aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-tidy1
-rw-r--r--CMakeLists.txt62
-rw-r--r--CODE_OWNERS.TXT4
-rw-r--r--bindings/python/clang/cindex.py265
-rw-r--r--bindings/python/tests/cindex/test_cursor.py58
-rw-r--r--cmake/modules/ClangConfig.cmake8
-rw-r--r--docs/AddressSanitizer.rst5
-rw-r--r--docs/ClangFormat.rst4
-rw-r--r--docs/ClangFormatStyleOptions.rst116
-rw-r--r--docs/CrossCompilation.rst1
-rw-r--r--docs/InternalsManual.rst37
-rw-r--r--docs/LanguageExtensions.rst236
-rw-r--r--docs/LibASTMatchersReference.html356
-rw-r--r--docs/MSVCCompatibility.rst16
-rw-r--r--docs/Modules.rst76
-rw-r--r--docs/RAVFrontendAction.rst15
-rw-r--r--docs/ReleaseNotes.rst225
-rw-r--r--docs/ThreadSafetyAnalysis.rst663
-rw-r--r--docs/UsersManual.rst72
-rw-r--r--docs/conf.py4
-rw-r--r--docs/tools/dump_format_style.py1
-rw-r--r--examples/PrintFunctionNames/PrintFunctionNames.cpp5
-rw-r--r--examples/clang-interpreter/CMakeLists.txt3
-rw-r--r--examples/clang-interpreter/Makefile6
-rw-r--r--examples/clang-interpreter/main.cpp40
-rw-r--r--include/clang-c/BuildSystem.h4
-rw-r--r--include/clang-c/CXCompilationDatabase.h4
-rw-r--r--include/clang-c/CXErrorCode.h4
-rw-r--r--include/clang-c/CXString.h4
-rw-r--r--include/clang-c/Documentation.h4
-rw-r--r--include/clang-c/Index.h201
-rw-r--r--include/clang-c/Platform.h4
-rw-r--r--include/clang/ARCMigrate/ARCMTActions.h12
-rw-r--r--include/clang/ARCMigrate/FileRemapper.h4
-rw-r--r--include/clang/AST/ASTContext.h111
-rw-r--r--include/clang/AST/ASTDiagnostic.h4
-rw-r--r--include/clang/AST/ASTFwd.h5
-rw-r--r--include/clang/AST/ASTLambda.h6
-rw-r--r--include/clang/AST/ASTMutationListener.h6
-rw-r--r--include/clang/AST/ASTTypeTraits.h111
-rw-r--r--include/clang/AST/ASTVector.h23
-rw-r--r--include/clang/AST/Attr.h1
-rw-r--r--include/clang/AST/CanonicalType.h6
-rw-r--r--include/clang/AST/Comment.h10
-rw-r--r--include/clang/AST/CommentBriefParser.h4
-rw-r--r--include/clang/AST/CommentCommandTraits.h10
-rw-r--r--include/clang/AST/CommentDiagnostic.h4
-rw-r--r--include/clang/AST/CommentLexer.h4
-rw-r--r--include/clang/AST/CommentParser.h4
-rw-r--r--include/clang/AST/CommentSema.h6
-rw-r--r--include/clang/AST/DataRecursiveASTVisitor.h103
-rw-r--r--include/clang/AST/Decl.h162
-rw-r--r--include/clang/AST/DeclBase.h21
-rw-r--r--include/clang/AST/DeclCXX.h109
-rw-r--r--include/clang/AST/DeclLookups.h10
-rw-r--r--include/clang/AST/DeclObjC.h9
-rw-r--r--include/clang/AST/DeclOpenMP.h10
-rw-r--r--include/clang/AST/DeclTemplate.h8
-rw-r--r--include/clang/AST/DeclarationName.h1
-rw-r--r--include/clang/AST/DependentDiagnostic.h7
-rw-r--r--include/clang/AST/EvaluatedExprVisitor.h11
-rw-r--r--include/clang/AST/Expr.h128
-rw-r--r--include/clang/AST/ExprCXX.h103
-rw-r--r--include/clang/AST/ExprObjC.h9
-rw-r--r--include/clang/AST/ExternalASTSource.h6
-rw-r--r--include/clang/AST/LambdaCapture.h12
-rw-r--r--include/clang/AST/Mangle.h5
-rw-r--r--include/clang/AST/MangleNumberingContext.h17
-rw-r--r--include/clang/AST/NSAPI.h10
-rw-r--r--include/clang/AST/NestedNameSpecifier.h34
-rw-r--r--include/clang/AST/OpenMPClause.h261
-rw-r--r--include/clang/AST/OperationKinds.h4
-rw-r--r--include/clang/AST/ParentMap.h4
-rw-r--r--include/clang/AST/PrettyPrinter.h4
-rw-r--r--include/clang/AST/RawCommentList.h4
-rw-r--r--include/clang/AST/RecordLayout.h4
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h103
-rw-r--r--include/clang/AST/Stmt.h99
-rw-r--r--include/clang/AST/StmtGraphTraits.h4
-rw-r--r--include/clang/AST/StmtIterator.h4
-rw-r--r--include/clang/AST/StmtOpenMP.h800
-rw-r--r--include/clang/AST/TemplateBase.h16
-rw-r--r--include/clang/AST/Type.h160
-rw-r--r--include/clang/AST/TypeLoc.h4
-rw-r--r--include/clang/AST/TypeOrdering.h4
-rw-r--r--include/clang/AST/UnresolvedSet.h2
-rw-r--r--include/clang/ASTMatchers/ASTMatchFinder.h69
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h337
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h636
-rw-r--r--include/clang/ASTMatchers/ASTMatchersMacros.h17
-rw-r--r--include/clang/ASTMatchers/Dynamic/Diagnostics.h4
-rw-r--r--include/clang/ASTMatchers/Dynamic/Parser.h130
-rw-r--r--include/clang/ASTMatchers/Dynamic/Registry.h51
-rw-r--r--include/clang/ASTMatchers/Dynamic/VariantValue.h184
-rw-r--r--include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h4
-rw-r--r--include/clang/Analysis/Analyses/Consumed.h4
-rw-r--r--include/clang/Analysis/Analyses/Dominators.h4
-rw-r--r--include/clang/Analysis/Analyses/FormatString.h10
-rw-r--r--include/clang/Analysis/Analyses/LiveVariables.h4
-rw-r--r--include/clang/Analysis/Analyses/PostOrderCFGView.h12
-rw-r--r--include/clang/Analysis/Analyses/PseudoConstantAnalysis.h4
-rw-r--r--include/clang/Analysis/Analyses/ReachableCode.h4
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafety.h33
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyCommon.h140
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyLogical.h12
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyOps.def3
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyTIL.h1107
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyTraverse.h450
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyUtil.h68
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h4
-rw-r--r--include/clang/Analysis/AnalysisContext.h16
-rw-r--r--include/clang/Analysis/AnalysisDiagnostic.h4
-rw-r--r--include/clang/Analysis/CFG.h11
-rw-r--r--include/clang/Analysis/CFGStmtMap.h4
-rw-r--r--include/clang/Analysis/CallGraph.h4
-rw-r--r--include/clang/Analysis/CodeInjector.h46
-rw-r--r--include/clang/Analysis/DomainSpecific/CocoaConventions.h4
-rw-r--r--include/clang/Analysis/DomainSpecific/ObjCNoReturn.h4
-rw-r--r--include/clang/Analysis/ProgramPoint.h4
-rw-r--r--include/clang/Analysis/Support/BumpVector.h6
-rw-r--r--include/clang/Basic/ABI.h11
-rw-r--r--include/clang/Basic/AddressSpaces.h1
-rw-r--r--include/clang/Basic/AllDiagnostics.h4
-rw-r--r--include/clang/Basic/Attr.td246
-rw-r--r--include/clang/Basic/AttrDocs.td338
-rw-r--r--include/clang/Basic/AttrKinds.h4
-rw-r--r--include/clang/Basic/Attributes.h14
-rw-r--r--include/clang/Basic/Builtins.def19
-rw-r--r--include/clang/Basic/Builtins.h4
-rw-r--r--include/clang/Basic/BuiltinsAArch64.def3
-rw-r--r--include/clang/Basic/BuiltinsARM.def6
-rw-r--r--include/clang/Basic/BuiltinsLe64.def19
-rw-r--r--include/clang/Basic/BuiltinsNVPTX.def30
-rw-r--r--include/clang/Basic/BuiltinsPPC.def19
-rw-r--r--include/clang/Basic/BuiltinsR600.def8
-rw-r--r--include/clang/Basic/BuiltinsX86.def207
-rw-r--r--include/clang/Basic/CharInfo.h4
-rw-r--r--include/clang/Basic/CommentOptions.h4
-rw-r--r--include/clang/Basic/Diagnostic.h16
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td7
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td14
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td18
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td34
-rw-r--r--include/clang/Basic/DiagnosticGroups.td75
-rw-r--r--include/clang/Basic/DiagnosticIDs.h6
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td25
-rw-r--r--include/clang/Basic/DiagnosticOptions.def3
-rw-r--r--include/clang/Basic/DiagnosticOptions.h3
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td115
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td444
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td10
-rw-r--r--include/clang/Basic/ExceptionSpecificationType.h3
-rw-r--r--include/clang/Basic/ExpressionTraits.h4
-rw-r--r--include/clang/Basic/FileManager.h25
-rw-r--r--include/clang/Basic/FileSystemStatCache.h12
-rw-r--r--include/clang/Basic/IdentifierTable.h65
-rw-r--r--include/clang/Basic/LLVM.h4
-rw-r--r--include/clang/Basic/Lambda.h3
-rw-r--r--include/clang/Basic/LangOptions.def68
-rw-r--r--include/clang/Basic/LangOptions.h26
-rw-r--r--include/clang/Basic/Module.h52
-rw-r--r--include/clang/Basic/ObjCRuntime.h4
-rw-r--r--include/clang/Basic/OpenMPKinds.def79
-rw-r--r--include/clang/Basic/OpenMPKinds.h6
-rw-r--r--include/clang/Basic/OperatorKinds.h4
-rw-r--r--include/clang/Basic/OperatorPrecedence.h4
-rw-r--r--include/clang/Basic/PartialDiagnostic.h4
-rw-r--r--include/clang/Basic/PlistSupport.h4
-rw-r--r--include/clang/Basic/PrettyStackTrace.h4
-rw-r--r--include/clang/Basic/SanitizerBlacklist.h45
-rw-r--r--include/clang/Basic/Sanitizers.def19
-rw-r--r--include/clang/Basic/Sanitizers.h47
-rw-r--r--include/clang/Basic/SourceLocation.h5
-rw-r--r--include/clang/Basic/SourceManager.h31
-rw-r--r--include/clang/Basic/SourceManagerInternals.h4
-rw-r--r--include/clang/Basic/Specifiers.h11
-rw-r--r--include/clang/Basic/StmtNodes.td15
-rw-r--r--include/clang/Basic/TargetBuiltins.h15
-rw-r--r--include/clang/Basic/TargetCXXABI.h4
-rw-r--r--include/clang/Basic/TargetInfo.h52
-rw-r--r--include/clang/Basic/TargetOptions.h4
-rw-r--r--include/clang/Basic/TemplateKinds.h4
-rw-r--r--include/clang/Basic/TokenKinds.def14
-rw-r--r--include/clang/Basic/TokenKinds.h10
-rw-r--r--include/clang/Basic/TypeTraits.h4
-rw-r--r--include/clang/Basic/VersionTuple.h29
-rw-r--r--include/clang/Basic/VirtualFileSystem.h36
-rw-r--r--include/clang/Basic/arm_neon.td49
-rw-r--r--include/clang/CodeGen/BackendUtil.h4
-rw-r--r--include/clang/CodeGen/CGFunctionInfo.h35
-rw-r--r--include/clang/CodeGen/CodeGenABITypes.h8
-rw-r--r--include/clang/CodeGen/CodeGenAction.h14
-rw-r--r--include/clang/CodeGen/ModuleBuilder.h4
-rw-r--r--include/clang/Config/config.h.cmake6
-rw-r--r--include/clang/Config/config.h.in9
-rw-r--r--include/clang/Driver/Action.h46
-rw-r--r--include/clang/Driver/CC1Options.td29
-rw-r--r--include/clang/Driver/CLCompatOptions.td30
-rw-r--r--include/clang/Driver/Compilation.h6
-rw-r--r--include/clang/Driver/Driver.h32
-rw-r--r--include/clang/Driver/DriverDiagnostic.h4
-rw-r--r--include/clang/Driver/Job.h70
-rw-r--r--include/clang/Driver/Multilib.h16
-rw-r--r--include/clang/Driver/Options.h4
-rw-r--r--include/clang/Driver/Options.td179
-rw-r--r--include/clang/Driver/Phases.h5
-rw-r--r--include/clang/Driver/SanitizerArgs.h126
-rw-r--r--include/clang/Driver/Tool.h62
-rw-r--r--include/clang/Driver/ToolChain.h14
-rw-r--r--include/clang/Driver/Types.h4
-rw-r--r--include/clang/Driver/Util.h4
-rw-r--r--include/clang/Format/Format.h99
-rw-r--r--include/clang/Frontend/ASTConsumers.h18
-rw-r--r--include/clang/Frontend/ASTUnit.h57
-rw-r--r--include/clang/Frontend/ChainedDiagnosticConsumer.h17
-rw-r--r--include/clang/Frontend/CodeGenOptions.def14
-rw-r--r--include/clang/Frontend/CodeGenOptions.h25
-rw-r--r--include/clang/Frontend/CompilerInstance.h38
-rw-r--r--include/clang/Frontend/DiagnosticRenderer.h4
-rw-r--r--include/clang/Frontend/FrontendAction.h41
-rw-r--r--include/clang/Frontend/FrontendActions.h51
-rw-r--r--include/clang/Frontend/FrontendDiagnostic.h4
-rw-r--r--include/clang/Frontend/FrontendOptions.h16
-rw-r--r--include/clang/Frontend/FrontendPluginRegistry.h4
-rw-r--r--include/clang/Frontend/LangStandard.h6
-rw-r--r--include/clang/Frontend/LangStandards.def15
-rw-r--r--include/clang/Frontend/LogDiagnosticPrinter.h15
-rw-r--r--include/clang/Frontend/MigratorOptions.h4
-rw-r--r--include/clang/Frontend/MultiplexConsumer.h8
-rw-r--r--include/clang/Frontend/SerializedDiagnosticPrinter.h45
-rw-r--r--include/clang/Frontend/SerializedDiagnosticReader.h131
-rw-r--r--include/clang/Frontend/SerializedDiagnostics.h59
-rw-r--r--include/clang/Frontend/TextDiagnostic.h4
-rw-r--r--include/clang/Frontend/TextDiagnosticBuffer.h4
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h4
-rw-r--r--include/clang/Frontend/Utils.h5
-rw-r--r--include/clang/Frontend/VerifyDiagnosticConsumer.h27
-rw-r--r--include/clang/Lex/ExternalPreprocessorSource.h6
-rw-r--r--include/clang/Lex/HeaderMap.h10
-rw-r--r--include/clang/Lex/HeaderSearch.h29
-rw-r--r--include/clang/Lex/HeaderSearchOptions.h13
-rw-r--r--include/clang/Lex/LexDiagnostic.h4
-rw-r--r--include/clang/Lex/Lexer.h10
-rw-r--r--include/clang/Lex/LiteralSupport.h4
-rw-r--r--include/clang/Lex/MacroArgs.h4
-rw-r--r--include/clang/Lex/MacroInfo.h119
-rw-r--r--include/clang/Lex/ModuleLoader.h4
-rw-r--r--include/clang/Lex/ModuleMap.h116
-rw-r--r--include/clang/Lex/MultipleIncludeOpt.h4
-rw-r--r--include/clang/Lex/PPCallbacks.h11
-rw-r--r--include/clang/Lex/PTHLexer.h4
-rw-r--r--include/clang/Lex/PTHManager.h32
-rw-r--r--include/clang/Lex/Pragma.h4
-rw-r--r--include/clang/Lex/Preprocessor.h103
-rw-r--r--include/clang/Lex/PreprocessorLexer.h4
-rw-r--r--include/clang/Lex/ScratchBuffer.h4
-rw-r--r--include/clang/Lex/Token.h29
-rw-r--r--include/clang/Lex/TokenConcatenation.h4
-rw-r--r--include/clang/Lex/TokenLexer.h4
-rw-r--r--include/clang/Parse/ParseDiagnostic.h4
-rw-r--r--include/clang/Parse/Parser.h103
-rw-r--r--include/clang/Rewrite/Core/DeltaTree.h4
-rw-r--r--include/clang/Rewrite/Core/HTMLRewrite.h4
-rw-r--r--include/clang/Rewrite/Core/RewriteRope.h52
-rw-r--r--include/clang/Rewrite/Core/Rewriter.h14
-rw-r--r--include/clang/Rewrite/Core/TokenRewriter.h4
-rw-r--r--include/clang/Rewrite/Frontend/ASTConsumers.h31
-rw-r--r--include/clang/Rewrite/Frontend/FixItRewriter.h8
-rw-r--r--include/clang/Rewrite/Frontend/FrontendActions.h16
-rw-r--r--include/clang/Rewrite/Frontend/Rewriters.h4
-rw-r--r--include/clang/Sema/AnalysisBasedWarnings.h4
-rw-r--r--include/clang/Sema/AttributeList.h15
-rw-r--r--include/clang/Sema/DeclSpec.h58
-rw-r--r--include/clang/Sema/DelayedDiagnostic.h4
-rw-r--r--include/clang/Sema/ExternalSemaSource.h17
-rw-r--r--include/clang/Sema/IdentifierResolver.h4
-rw-r--r--include/clang/Sema/Lookup.h27
-rw-r--r--include/clang/Sema/LoopHint.h13
-rw-r--r--include/clang/Sema/MultiplexExternalSemaSource.h15
-rw-r--r--include/clang/Sema/ObjCMethodList.h31
-rw-r--r--include/clang/Sema/Overload.h36
-rw-r--r--include/clang/Sema/PrettyDeclStackTrace.h4
-rw-r--r--include/clang/Sema/Scope.h20
-rw-r--r--include/clang/Sema/ScopeInfo.h41
-rw-r--r--include/clang/Sema/Sema.h485
-rw-r--r--include/clang/Sema/SemaDiagnostic.h4
-rw-r--r--include/clang/Sema/SemaFixItUtils.h6
-rw-r--r--include/clang/Sema/SemaInternal.h212
-rw-r--r--include/clang/Sema/SemaLambda.h6
-rw-r--r--include/clang/Sema/TemplateDeduction.h4
-rw-r--r--include/clang/Sema/TypoCorrection.h42
-rw-r--r--include/clang/Serialization/ASTBitCodes.h41
-rw-r--r--include/clang/Serialization/ASTDeserializationListener.h4
-rw-r--r--include/clang/Serialization/ASTReader.h133
-rw-r--r--include/clang/Serialization/ASTWriter.h67
-rw-r--r--include/clang/Serialization/ContinuousRangeMap.h12
-rw-r--r--include/clang/Serialization/GlobalModuleIndex.h6
-rw-r--r--include/clang/Serialization/Module.h18
-rw-r--r--include/clang/Serialization/ModuleManager.h23
-rw-r--r--include/clang/Serialization/SerializationDiagnostic.h4
-rw-r--r--include/clang/StaticAnalyzer/Checkers/LocalCheckers.h4
-rw-r--r--include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h21
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h30
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h23
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h15
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h19
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h11
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h4
-rw-r--r--include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h12
-rw-r--r--include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h12
-rw-r--r--include/clang/StaticAnalyzer/Frontend/FrontendActions.h33
-rw-r--r--include/clang/StaticAnalyzer/Frontend/ModelConsumer.h44
-rw-r--r--include/clang/Tooling/ArgumentsAdjusters.h68
-rw-r--r--include/clang/Tooling/CommonOptionsParser.h6
-rw-r--r--include/clang/Tooling/CompilationDatabase.h22
-rw-r--r--include/clang/Tooling/CompilationDatabasePluginRegistry.h6
-rw-r--r--include/clang/Tooling/Core/Replacement.h229
-rw-r--r--include/clang/Tooling/FileMatchTrie.h6
-rw-r--r--include/clang/Tooling/JSONCompilationDatabase.h19
-rw-r--r--include/clang/Tooling/Refactoring.h176
-rw-r--r--include/clang/Tooling/RefactoringCallbacks.h6
-rw-r--r--include/clang/Tooling/ReplacementsYaml.h6
-rw-r--r--include/clang/Tooling/Tooling.h42
-rw-r--r--include/clang/module.modulemap25
-rw-r--r--lib/ARCMigrate/ARCMT.cpp15
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp34
-rw-r--r--lib/ARCMigrate/Internals.h2
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp286
-rw-r--r--lib/ARCMigrate/PlistReporter.cpp6
-rw-r--r--lib/ARCMigrate/TransformActions.cpp3
-rw-r--r--lib/AST/APValue.cpp4
-rw-r--r--lib/AST/ASTContext.cpp419
-rw-r--r--lib/AST/ASTDiagnostic.cpp431
-rw-r--r--lib/AST/ASTDumper.cpp1144
-rw-r--r--lib/AST/ASTImporter.cpp124
-rw-r--r--lib/AST/ASTTypeTraits.cpp47
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/CXXABI.h4
-rw-r--r--lib/AST/Comment.cpp17
-rw-r--r--lib/AST/CommentCommandTraits.cpp4
-rw-r--r--lib/AST/CommentLexer.cpp4
-rw-r--r--lib/AST/Decl.cpp159
-rw-r--r--lib/AST/DeclBase.cpp28
-rw-r--r--lib/AST/DeclCXX.cpp94
-rw-r--r--lib/AST/DeclObjC.cpp66
-rw-r--r--lib/AST/DeclPrinter.cpp57
-rw-r--r--lib/AST/Expr.cpp205
-rw-r--r--lib/AST/ExprCXX.cpp16
-rw-r--r--lib/AST/ExprClassification.cpp11
-rw-r--r--lib/AST/ExprConstant.cpp579
-rw-r--r--lib/AST/ItaniumCXXABI.cpp54
-rw-r--r--lib/AST/ItaniumMangle.cpp187
-rw-r--r--lib/AST/Mangle.cpp92
-rw-r--r--lib/AST/MangleNumberingContext.cpp45
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp21
-rw-r--r--lib/AST/MicrosoftMangle.cpp174
-rw-r--r--lib/AST/NSAPI.cpp31
-rw-r--r--lib/AST/NestedNameSpecifier.cpp71
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp120
-rw-r--r--lib/AST/Stmt.cpp454
-rw-r--r--lib/AST/StmtPrinter.cpp91
-rw-r--r--lib/AST/StmtProfile.cpp76
-rw-r--r--lib/AST/TemplateBase.cpp28
-rw-r--r--lib/AST/Type.cpp143
-rw-r--r--lib/AST/TypeLoc.cpp8
-rw-r--r--lib/AST/TypePrinter.cpp19
-rw-r--r--lib/AST/VTTBuilder.cpp4
-rw-r--r--lib/AST/VTableBuilder.cpp334
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp289
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp268
-rw-r--r--lib/ASTMatchers/Dynamic/Marshallers.h105
-rw-r--r--lib/ASTMatchers/Dynamic/Parser.cpp105
-rw-r--r--lib/ASTMatchers/Dynamic/Registry.cpp171
-rw-r--r--lib/ASTMatchers/Dynamic/VariantValue.cpp164
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp29
-rw-r--r--lib/Analysis/BodyFarm.cpp12
-rw-r--r--lib/Analysis/BodyFarm.h8
-rw-r--r--lib/Analysis/CFG.cpp354
-rw-r--r--lib/Analysis/CMakeLists.txt1
-rw-r--r--lib/Analysis/CallGraph.cpp13
-rw-r--r--lib/Analysis/CodeInjector.cpp15
-rw-r--r--lib/Analysis/FormatString.cpp38
-rw-r--r--lib/Analysis/FormatStringParsing.h4
-rw-r--r--lib/Analysis/LiveVariables.cpp1
-rw-r--r--lib/Analysis/PrintfFormatString.cpp78
-rw-r--r--lib/Analysis/ReachableCode.cpp4
-rw-r--r--lib/Analysis/ScanfFormatString.cpp11
-rw-r--r--lib/Analysis/ThreadSafety.cpp1436
-rw-r--r--lib/Analysis/ThreadSafetyCommon.cpp335
-rw-r--r--lib/Analysis/ThreadSafetyTIL.cpp280
-rw-r--r--lib/Analysis/UninitializedValues.cpp32
-rw-r--r--lib/Basic/Attributes.cpp4
-rw-r--r--lib/Basic/CMakeLists.txt80
-rw-r--r--lib/Basic/Diagnostic.cpp42
-rw-r--r--lib/Basic/DiagnosticIDs.cpp31
-rw-r--r--lib/Basic/FileManager.cpp192
-rw-r--r--lib/Basic/FileSystemStatCache.cpp9
-rw-r--r--lib/Basic/IdentifierTable.cpp119
-rw-r--r--lib/Basic/LangOptions.cpp8
-rw-r--r--lib/Basic/Module.cpp58
-rw-r--r--lib/Basic/OpenMPKinds.cpp82
-rw-r--r--lib/Basic/SanitizerBlacklist.cpp46
-rw-r--r--lib/Basic/Sanitizers.cpp35
-rw-r--r--lib/Basic/SourceLocation.cpp8
-rw-r--r--lib/Basic/SourceManager.cpp67
-rw-r--r--lib/Basic/TargetInfo.cpp37
-rw-r--r--lib/Basic/Targets.cpp1116
-rw-r--r--lib/Basic/Version.cpp2
-rw-r--r--lib/Basic/VersionTuple.cpp4
-rw-r--r--lib/Basic/VirtualFileSystem.cpp100
-rw-r--r--lib/CodeGen/ABIInfo.h23
-rw-r--r--lib/CodeGen/BackendUtil.cpp88
-rw-r--r--lib/CodeGen/CGAtomic.cpp328
-rw-r--r--lib/CodeGen/CGBlocks.cpp48
-rw-r--r--lib/CodeGen/CGBlocks.h4
-rw-r--r--lib/CodeGen/CGBuilder.h6
-rw-r--r--lib/CodeGen/CGBuiltin.cpp530
-rw-r--r--lib/CodeGen/CGCUDARuntime.cpp3
-rw-r--r--lib/CodeGen/CGCUDARuntime.h4
-rw-r--r--lib/CodeGen/CGCXX.cpp157
-rw-r--r--lib/CodeGen/CGCXXABI.cpp23
-rw-r--r--lib/CodeGen/CGCXXABI.h102
-rw-r--r--lib/CodeGen/CGCall.cpp1512
-rw-r--r--lib/CodeGen/CGCall.h4
-rw-r--r--lib/CodeGen/CGClass.cpp263
-rw-r--r--lib/CodeGen/CGCleanup.cpp12
-rw-r--r--lib/CodeGen/CGCleanup.h12
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp1569
-rw-r--r--lib/CodeGen/CGDebugInfo.h136
-rw-r--r--lib/CodeGen/CGDecl.cpp141
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp154
-rw-r--r--lib/CodeGen/CGException.cpp106
-rw-r--r--lib/CodeGen/CGExpr.cpp547
-rw-r--r--lib/CodeGen/CGExprCXX.cpp301
-rw-r--r--lib/CodeGen/CGExprComplex.cpp271
-rw-r--r--lib/CodeGen/CGExprConstant.cpp202
-rw-r--r--lib/CodeGen/CGExprScalar.cpp240
-rw-r--r--lib/CodeGen/CGLoopInfo.cpp27
-rw-r--r--lib/CodeGen/CGLoopInfo.h6
-rw-r--r--lib/CodeGen/CGObjC.cpp43
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp31
-rw-r--r--lib/CodeGen/CGObjCMac.cpp424
-rw-r--r--lib/CodeGen/CGObjCRuntime.h4
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.h4
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.cpp794
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.h315
-rw-r--r--lib/CodeGen/CGRecordLayout.h4
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp59
-rw-r--r--lib/CodeGen/CGStmt.cpp196
-rw-r--r--lib/CodeGen/CGStmtOpenMP.cpp639
-rw-r--r--lib/CodeGen/CGVTables.cpp126
-rw-r--r--lib/CodeGen/CGVTables.h4
-rw-r--r--lib/CodeGen/CGValue.h4
-rw-r--r--lib/CodeGen/CMakeLists.txt15
-rw-r--r--lib/CodeGen/CodeGenABITypes.cpp9
-rw-r--r--lib/CodeGen/CodeGenAction.cpp89
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp232
-rw-r--r--lib/CodeGen/CodeGenFunction.h396
-rw-r--r--lib/CodeGen/CodeGenModule.cpp668
-rw-r--r--lib/CodeGen/CodeGenModule.h194
-rw-r--r--lib/CodeGen/CodeGenPGO.cpp364
-rw-r--r--lib/CodeGen/CodeGenPGO.h48
-rw-r--r--lib/CodeGen/CodeGenTBAA.h4
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp30
-rw-r--r--lib/CodeGen/CodeGenTypes.h140
-rw-r--r--lib/CodeGen/CoverageMappingGen.cpp1174
-rw-r--r--lib/CodeGen/CoverageMappingGen.h114
-rw-r--r--lib/CodeGen/EHScopeStack.h6
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp400
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp457
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp66
-rw-r--r--lib/CodeGen/SanitizerBlacklist.cpp52
-rw-r--r--lib/CodeGen/SanitizerBlacklist.h46
-rw-r--r--lib/CodeGen/SanitizerMetadata.cpp92
-rw-r--r--lib/CodeGen/SanitizerMetadata.h53
-rw-r--r--lib/CodeGen/TargetInfo.cpp1110
-rw-r--r--lib/CodeGen/TargetInfo.h22
-rw-r--r--lib/Driver/Action.cpp74
-rw-r--r--lib/Driver/CMakeLists.txt3
-rw-r--r--lib/Driver/Compilation.cpp19
-rw-r--r--lib/Driver/CrossWindowsToolChain.cpp117
-rw-r--r--lib/Driver/Driver.cpp506
-rw-r--r--lib/Driver/InputInfo.h4
-rw-r--r--lib/Driver/Job.cpp187
-rw-r--r--lib/Driver/MSVCToolChain.cpp496
-rw-r--r--lib/Driver/Multilib.cpp2
-rw-r--r--lib/Driver/Phases.cpp1
-rw-r--r--lib/Driver/SanitizerArgs.cpp524
-rw-r--r--lib/Driver/Tool.cpp12
-rw-r--r--lib/Driver/ToolChain.cpp36
-rw-r--r--lib/Driver/ToolChains.cpp594
-rw-r--r--lib/Driver/ToolChains.h93
-rw-r--r--lib/Driver/Tools.cpp1590
-rw-r--r--lib/Driver/Tools.h180
-rw-r--r--lib/Driver/Types.cpp2
-rw-r--r--lib/Driver/WindowsToolChain.cpp338
-rw-r--r--lib/Edit/EditedSource.cpp6
-rw-r--r--lib/Edit/RewriteObjCFoundationAPI.cpp3
-rw-r--r--lib/Format/BreakableToken.cpp3
-rw-r--r--lib/Format/BreakableToken.h11
-rw-r--r--lib/Format/CMakeLists.txt3
-rw-r--r--lib/Format/ContinuationIndenter.cpp465
-rw-r--r--lib/Format/ContinuationIndenter.h34
-rw-r--r--lib/Format/Encoding.h6
-rw-r--r--lib/Format/Format.cpp975
-rw-r--r--lib/Format/FormatToken.cpp24
-rw-r--r--lib/Format/FormatToken.h150
-rw-r--r--lib/Format/TokenAnnotator.cpp1041
-rw-r--r--lib/Format/TokenAnnotator.h22
-rw-r--r--lib/Format/UnwrappedLineFormatter.cpp706
-rw-r--r--lib/Format/UnwrappedLineFormatter.h168
-rw-r--r--lib/Format/UnwrappedLineParser.cpp244
-rw-r--r--lib/Format/UnwrappedLineParser.h14
-rw-r--r--lib/Format/WhitespaceManager.cpp12
-rw-r--r--lib/Format/WhitespaceManager.h6
-rw-r--r--lib/Frontend/ASTConsumers.cpp40
-rw-r--r--lib/Frontend/ASTMerge.cpp10
-rw-r--r--lib/Frontend/ASTUnit.cpp355
-rw-r--r--lib/Frontend/CMakeLists.txt3
-rw-r--r--lib/Frontend/CacheTokens.cpp16
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp33
-rw-r--r--lib/Frontend/CodeGenOptions.cpp24
-rw-r--r--lib/Frontend/CompilerInstance.cpp268
-rw-r--r--lib/Frontend/CompilerInvocation.cpp207
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp6
-rw-r--r--lib/Frontend/DependencyFile.cpp36
-rw-r--r--lib/Frontend/DependencyGraph.cpp13
-rw-r--r--lib/Frontend/DiagnosticRenderer.cpp4
-rw-r--r--lib/Frontend/FrontendAction.cpp80
-rw-r--r--lib/Frontend/FrontendActions.cpp168
-rw-r--r--lib/Frontend/HeaderIncludeGen.cpp20
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp16
-rw-r--r--lib/Frontend/InitPreprocessor.cpp166
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp26
-rw-r--r--lib/Frontend/ModuleDependencyCollector.cpp43
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp117
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp5
-rw-r--r--lib/Frontend/Rewrite/FixItRewriter.cpp26
-rw-r--r--lib/Frontend/Rewrite/FrontendActions.cpp14
-rw-r--r--lib/Frontend/Rewrite/HTMLPrint.cpp11
-rw-r--r--lib/Frontend/Rewrite/InclusionRewriter.cpp153
-rw-r--r--lib/Frontend/Rewrite/RewriteModernObjC.cpp102
-rw-r--r--lib/Frontend/Rewrite/RewriteObjC.cpp102
-rw-r--r--lib/Frontend/SerializedDiagnosticPrinter.cpp257
-rw-r--r--lib/Frontend/SerializedDiagnosticReader.cpp295
-rw-r--r--lib/Frontend/TextDiagnostic.cpp24
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp69
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp2
-rw-r--r--lib/Headers/CMakeLists.txt23
-rw-r--r--lib/Headers/Intrin.h88
-rw-r--r--lib/Headers/__stddef_max_align_t.h40
-rw-r--r--lib/Headers/adxintrin.h83
-rw-r--r--lib/Headers/altivec.h411
-rw-r--r--lib/Headers/arm_acle.h113
-rw-r--r--lib/Headers/avx512bwintrin.h60
-rw-r--r--lib/Headers/avx512erintrin.h112
-rw-r--r--lib/Headers/avx512fintrin.h1036
-rw-r--r--lib/Headers/avx512vlbwintrin.h83
-rw-r--r--lib/Headers/avx512vlintrin.h83
-rw-r--r--lib/Headers/bmiintrin.h6
-rw-r--r--lib/Headers/cpuid.h84
-rw-r--r--lib/Headers/emmintrin.h48
-rw-r--r--lib/Headers/float.h2
-rw-r--r--lib/Headers/immintrin.h76
-rw-r--r--lib/Headers/lzcntintrin.h18
-rw-r--r--lib/Headers/module.modulemap22
-rw-r--r--lib/Headers/shaintrin.h12
-rw-r--r--lib/Headers/stdatomic.h190
-rw-r--r--lib/Headers/stddef.h29
-rw-r--r--lib/Headers/unwind.h6
-rw-r--r--lib/Headers/vadefs.h65
-rw-r--r--lib/Headers/xmmintrin.h48
-rw-r--r--lib/Index/CMakeLists.txt3
-rw-r--r--lib/Index/CommentToXML.cpp10
-rw-r--r--lib/Index/SimpleFormatContext.h9
-rw-r--r--lib/Index/USRGeneration.cpp54
-rw-r--r--lib/Lex/HeaderMap.cpp10
-rw-r--r--lib/Lex/HeaderSearch.cpp302
-rw-r--r--lib/Lex/Lexer.cpp48
-rw-r--r--lib/Lex/LiteralSupport.cpp16
-rw-r--r--lib/Lex/MacroArgs.cpp5
-rw-r--r--lib/Lex/ModuleMap.cpp408
-rw-r--r--lib/Lex/PPDirectives.cpp339
-rw-r--r--lib/Lex/PPExpressions.cpp22
-rw-r--r--lib/Lex/PPLexerChange.cpp68
-rw-r--r--lib/Lex/PPMacroExpansion.cpp357
-rw-r--r--lib/Lex/PTHLexer.cpp74
-rw-r--r--lib/Lex/Pragma.cpp23
-rw-r--r--lib/Lex/Preprocessor.cpp114
-rw-r--r--lib/Lex/ScratchBuffer.cpp9
-rw-r--r--lib/Lex/TokenConcatenation.cpp20
-rw-r--r--lib/Lex/TokenLexer.cpp29
-rw-r--r--lib/Lex/UnicodeCharSets.h4
-rw-r--r--lib/Parse/ParseAST.cpp7
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp203
-rw-r--r--lib/Parse/ParseDecl.cpp460
-rw-r--r--lib/Parse/ParseDeclCXX.cpp362
-rw-r--r--lib/Parse/ParseExpr.cpp260
-rw-r--r--lib/Parse/ParseExprCXX.cpp198
-rw-r--r--lib/Parse/ParseInit.cpp6
-rw-r--r--lib/Parse/ParseObjc.cpp164
-rw-r--r--lib/Parse/ParseOpenMP.cpp71
-rw-r--r--lib/Parse/ParsePragma.cpp313
-rw-r--r--lib/Parse/ParseStmt.cpp83
-rw-r--r--lib/Parse/ParseStmtAsm.cpp61
-rw-r--r--lib/Parse/ParseTemplate.cpp25
-rw-r--r--lib/Parse/ParseTentative.cpp37
-rw-r--r--lib/Parse/Parser.cpp127
-rw-r--r--lib/Parse/RAIIObjectsForParser.h4
-rw-r--r--lib/Rewrite/CMakeLists.txt1
-rw-r--r--lib/Rewrite/RewriteRope.cpp14
-rw-r--r--lib/Rewrite/Rewriter.cpp33
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp191
-rw-r--r--lib/Sema/AttributeList.cpp8
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/DeclSpec.cpp49
-rw-r--r--lib/Sema/IdentifierResolver.cpp3
-rw-r--r--lib/Sema/JumpDiagnostics.cpp22
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp6
-rw-r--r--lib/Sema/Scope.cpp9
-rw-r--r--lib/Sema/ScopeInfo.cpp19
-rw-r--r--lib/Sema/Sema.cpp52
-rw-r--r--lib/Sema/SemaAccess.cpp4
-rw-r--r--lib/Sema/SemaAttr.cpp26
-rw-r--r--lib/Sema/SemaCUDA.cpp263
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp65
-rw-r--r--lib/Sema/SemaCast.cpp54
-rw-r--r--lib/Sema/SemaChecking.cpp716
-rw-r--r--lib/Sema/SemaCodeComplete.cpp111
-rw-r--r--lib/Sema/SemaDecl.cpp784
-rw-r--r--lib/Sema/SemaDeclAttr.cpp823
-rw-r--r--lib/Sema/SemaDeclCXX.cpp1207
-rw-r--r--lib/Sema/SemaDeclObjC.cpp184
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp117
-rw-r--r--lib/Sema/SemaExpr.cpp798
-rw-r--r--lib/Sema/SemaExprCXX.cpp411
-rw-r--r--lib/Sema/SemaExprMember.cpp132
-rw-r--r--lib/Sema/SemaExprObjC.cpp172
-rw-r--r--lib/Sema/SemaInit.cpp198
-rw-r--r--lib/Sema/SemaLambda.cpp27
-rw-r--r--lib/Sema/SemaLookup.cpp759
-rw-r--r--lib/Sema/SemaObjCProperty.cpp52
-rw-r--r--lib/Sema/SemaOpenMP.cpp1694
-rw-r--r--lib/Sema/SemaOverload.cpp616
-rw-r--r--lib/Sema/SemaPseudoObject.cpp9
-rw-r--r--lib/Sema/SemaStmt.cpp448
-rw-r--r--lib/Sema/SemaStmtAsm.cpp200
-rw-r--r--lib/Sema/SemaStmtAttr.cpp128
-rw-r--r--lib/Sema/SemaTemplate.cpp244
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp65
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp248
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp470
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp167
-rw-r--r--lib/Sema/SemaType.cpp215
-rw-r--r--lib/Sema/TreeTransform.h662
-rw-r--r--lib/Sema/TypeLocBuilder.h4
-rw-r--r--lib/Serialization/ASTCommon.cpp18
-rw-r--r--lib/Serialization/ASTCommon.h13
-rw-r--r--lib/Serialization/ASTReader.cpp1341
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp630
-rw-r--r--lib/Serialization/ASTReaderInternals.h11
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp195
-rw-r--r--lib/Serialization/ASTWriter.cpp883
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp160
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp140
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp25
-rw-r--r--lib/Serialization/Module.cpp2
-rw-r--r--lib/Serialization/ModuleManager.cpp84
-rw-r--r--lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h4
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp13
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp39
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td8
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckers.h4
-rw-r--r--lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/InterCheckerAPI.h4
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp186
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp19
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp49
-rw-r--r--lib/StaticAnalyzer/Checkers/SelectorExtras.h8
-rw-r--r--lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp66
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp26
-rw-r--r--lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp13
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp19
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp135
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp74
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp67
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp125
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp11
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp10
-rw-r--r--lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h4
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp11
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h4
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp13
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp62
-rw-r--r--lib/StaticAnalyzer/Frontend/CMakeLists.txt3
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp16
-rw-r--r--lib/StaticAnalyzer/Frontend/FrontendActions.cpp19
-rw-r--r--lib/StaticAnalyzer/Frontend/ModelConsumer.cpp42
-rw-r--r--lib/StaticAnalyzer/Frontend/ModelInjector.cpp117
-rw-r--r--lib/StaticAnalyzer/Frontend/ModelInjector.h74
-rw-r--r--lib/Tooling/ArgumentsAdjusters.cpp83
-rw-r--r--lib/Tooling/CMakeLists.txt3
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp63
-rw-r--r--lib/Tooling/CompilationDatabase.cpp38
-rw-r--r--lib/Tooling/Core/CMakeLists.txt10
-rw-r--r--lib/Tooling/Core/Makefile13
-rw-r--r--lib/Tooling/Core/Replacement.cpp289
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp18
-rw-r--r--lib/Tooling/Makefile1
-rw-r--r--lib/Tooling/Refactoring.cpp246
-rw-r--r--lib/Tooling/Tooling.cpp162
-rw-r--r--runtime/CMakeLists.txt4
-rw-r--r--runtime/compiler-rt/Makefile42
-rw-r--r--test/ARCMT/checking.m4
-rw-r--r--test/ARCMT/objcmt-boxing.m7
-rw-r--r--test/ARCMT/objcmt-boxing.m.result7
-rw-r--r--test/ARCMT/objcmt-ns-macros.m69
-rw-r--r--test/ARCMT/objcmt-ns-macros.m.result109
-rw-r--r--test/ARCMT/objcmt-property-dot-syntax.m61
-rw-r--r--test/ARCMT/objcmt-property-dot-syntax.m.result61
-rw-r--r--test/ARCMT/objcmt-undefined-ns-macros.m24
-rw-r--r--test/ARCMT/objcmt-undefined-ns-macros.m.result26
-rw-r--r--test/Analysis/Inputs/Models/modeledFunction.model3
-rw-r--r--test/Analysis/Inputs/Models/notzero.model3
-rw-r--r--test/Analysis/Inputs/system-header-simulator-for-pthread-lock.h28
-rw-r--r--test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp2
-rw-r--r--test/Analysis/Malloc+NewDelete_intersections.cpp2
-rw-r--r--test/Analysis/NSContainers.m2
-rw-r--r--test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp2
-rw-r--r--test/Analysis/NewDelete-checker-test.cpp2
-rw-r--r--test/Analysis/NewDelete-custom.cpp2
-rw-r--r--test/Analysis/NewDelete-intersections.mm2
-rw-r--r--test/Analysis/NewDelete-variadic.cpp2
-rw-r--r--test/Analysis/NewDeleteLeaks-PR18394.cpp2
-rw-r--r--test/Analysis/NewDeleteLeaks-PR19102.cpp43
-rw-r--r--test/Analysis/bstring.c39
-rw-r--r--test/Analysis/builtin-functions.cpp28
-rw-r--r--test/Analysis/cfg.cpp57
-rw-r--r--test/Analysis/debug-CallGraph.c23
-rw-r--r--test/Analysis/disable-all-checks.c11
-rw-r--r--test/Analysis/identical-expressions.cpp21
-rw-r--r--test/Analysis/logical-ops.c2
-rw-r--r--test/Analysis/malloc-protoype.c17
-rw-r--r--test/Analysis/malloc-sizeof.cpp26
-rw-r--r--test/Analysis/misc-ps.m13
-rw-r--r--test/Analysis/model-file.cpp288
-rw-r--r--test/Analysis/nonnull.m118
-rw-r--r--test/Analysis/objc-boxing.m2
-rw-r--r--test/Analysis/pthreadlock.c40
-rw-r--r--test/Analysis/temp-obj-dtors-cfg-output.cpp103
-rw-r--r--test/Analysis/temporaries.cpp207
-rw-r--r--test/Analysis/unix-api.c75
-rw-r--r--test/Analysis/virtualcall.cpp23
-rw-r--r--test/Analysis/vla.c86
-rw-r--r--test/CXX/basic/basic.types/p10.cpp11
-rw-r--r--test/CXX/class.access/class.friend/p11.cpp10
-rw-r--r--test/CXX/class/class.mem/p2.cpp30
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp5
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp3
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp4
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp32
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp12
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp16
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp4
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp4
-rw-r--r--test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.general/p8.cpp18
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp15
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/p6.cpp6
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp31
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp3
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/p1.cpp4
-rw-r--r--test/CXX/drs/dr0xx.cpp40
-rw-r--r--test/CXX/drs/dr10xx.cpp21
-rw-r--r--test/CXX/drs/dr13xx.cpp3
-rw-r--r--test/CXX/drs/dr14xx.cpp3
-rw-r--r--test/CXX/drs/dr15xx.cpp7
-rw-r--r--test/CXX/drs/dr16xx.cpp19
-rw-r--r--test/CXX/drs/dr18xx.cpp24
-rw-r--r--test/CXX/drs/dr1xx.cpp7
-rw-r--r--test/CXX/drs/dr2xx.cpp46
-rw-r--r--test/CXX/drs/dr3xx.cpp40
-rw-r--r--test/CXX/drs/dr412.cpp3
-rw-r--r--test/CXX/drs/dr4xx.cpp19
-rw-r--r--test/CXX/drs/dr5xx.cpp785
-rw-r--r--test/CXX/drs/dr6xx.cpp349
-rw-r--r--test/CXX/drs/dr9xx.cpp3
-rw-r--r--test/CXX/except/except.spec/p1.cpp9
-rw-r--r--test/CXX/except/except.spec/p5-delayed.cpp15
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp8
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp5
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp4
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp2
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp2
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp7
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp7
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp4
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp2
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p3.cpp2
-rw-r--r--test/CXX/lex/lex.trigraph/p1.cpp2
-rw-r--r--test/CXX/lex/lex.trigraph/p2.cpp2
-rw-r--r--test/CXX/lex/lex.trigraph/p3.cpp2
-rw-r--r--test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp4
-rw-r--r--test/CXX/stmt.stmt/stmt.dcl/p3.cpp4
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp8
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p5.cpp8
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p5.cpp15
-rw-r--r--test/CXX/temp/temp.param/p5.cpp8
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp2
-rw-r--r--test/CodeGen/2003-08-21-WideString.c4
-rw-r--r--test/CodeGen/2005-06-15-ExpandGotoInternalProblem.c2
-rw-r--r--test/CodeGen/2005-09-24-AsmUserPrefix.c2
-rw-r--r--test/CodeGen/2007-06-18-SextAttrAggregate.c4
-rw-r--r--test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c3
-rw-r--r--test/CodeGen/2009-07-15-pad-wchar_t-array.c4
-rw-r--r--test/CodeGen/2009-10-20-GlobalDebug.c4
-rw-r--r--test/CodeGen/2010-02-15-DbgStaticVar.c3
-rw-r--r--test/CodeGen/2010-07-08-DeclDebugLineNo.c4
-rw-r--r--test/CodeGen/24-bit.c14
-rw-r--r--test/CodeGen/Atomics.c43
-rw-r--r--test/CodeGen/aarch64-fix-cortex-a53-835769.c27
-rw-r--r--test/CodeGen/aarch64-poly64.c12
-rw-r--r--test/CodeGen/aarch64-type-sizes.c2
-rw-r--r--test/CodeGen/aarch64-varargs.c2
-rw-r--r--test/CodeGen/adc-builtins.c33
-rw-r--r--test/CodeGen/address-safety-attr.cpp70
-rw-r--r--test/CodeGen/address-sanitizer-and-array-cookie.cpp55
-rw-r--r--test/CodeGen/adx-builtins.c18
-rw-r--r--test/CodeGen/alias.c7
-rw-r--r--test/CodeGen/align_value.cpp103
-rw-r--r--test/CodeGen/arm-aapcs-vfp.c25
-rw-r--r--test/CodeGen/arm-arguments.c9
-rw-r--r--test/CodeGen/arm-homogenous.c20
-rw-r--r--test/CodeGen/arm-metadata.c12
-rw-r--r--test/CodeGen/arm-neon-directed-rounding.c75
-rw-r--r--test/CodeGen/arm-neon-numeric-maxmin.c27
-rw-r--r--test/CodeGen/arm64-aapcs-arguments.c15
-rw-r--r--test/CodeGen/arm64-arguments.c15
-rw-r--r--test/CodeGen/arm64-be-bitfield.c12
-rw-r--r--test/CodeGen/arm64-be-hfa-vararg.c2
-rw-r--r--test/CodeGen/arm64-lanes.c2
-rw-r--r--test/CodeGen/arm_acle.c155
-rw-r--r--test/CodeGen/arm_neon_intrinsics.c168
-rw-r--r--test/CodeGen/asan-globals.cpp45
-rw-r--r--test/CodeGen/asm.c14
-rw-r--r--test/CodeGen/atomic-ops-libcall.c10
-rw-r--r--test/CodeGen/atomic-ops.c178
-rw-r--r--test/CodeGen/atomic.c10
-rw-r--r--test/CodeGen/atomic_ops.c6
-rw-r--r--test/CodeGen/atomics-inlining.c24
-rw-r--r--test/CodeGen/attr-naked.c10
-rw-r--r--test/CodeGen/attr-optnone.c21
-rw-r--r--test/CodeGen/attributes.c2
-rw-r--r--test/CodeGen/avx2-builtins.c2
-rw-r--r--test/CodeGen/avx512bw-builtins.c27
-rw-r--r--test/CodeGen/avx512f-builtins.c212
-rw-r--r--test/CodeGen/avx512vl-builtins.c51
-rw-r--r--test/CodeGen/avx512vlbw-builtins.c51
-rw-r--r--test/CodeGen/block-with-perdefinedexpr.c14
-rw-r--r--test/CodeGen/bmi2-builtins.c6
-rw-r--r--test/CodeGen/bool_test.c2
-rw-r--r--test/CodeGen/builtin-assume-aligned.c67
-rw-r--r--test/CodeGen/builtin-assume.c23
-rw-r--r--test/CodeGen/builtin-recursive.cpp (renamed from test/CodeGen/builtin-recursive.cc)2
-rw-r--r--test/CodeGen/builtins-arm-msvc-compat-error.c6
-rw-r--r--test/CodeGen/builtins-arm-msvc-compat-only.c19
-rw-r--r--test/CodeGen/builtins-arm.c18
-rw-r--r--test/CodeGen/builtins-arm64.c14
-rw-r--r--test/CodeGen/builtins-nvptx.c2
-rw-r--r--test/CodeGen/builtins-ppc-altivec.c4
-rw-r--r--test/CodeGen/builtins-ppc-vsx.c116
-rw-r--r--test/CodeGen/builtins-x86.c2
-rw-r--r--test/CodeGen/builtins.c33
-rw-r--r--test/CodeGen/c11atomics-ios.c8
-rw-r--r--test/CodeGen/c11atomics.c14
-rw-r--r--test/CodeGen/captured-statements-nested.c74
-rw-r--r--test/CodeGen/captured-statements.c11
-rw-r--r--test/CodeGen/catch-undef-behavior.c417
-rw-r--r--test/CodeGen/complex-math.c481
-rw-r--r--test/CodeGen/complex.c16
-rw-r--r--test/CodeGen/compound-assign-overflow.c2
-rw-r--r--test/CodeGen/const-init.c22
-rw-r--r--test/CodeGen/debug-info-args.c4
-rw-r--r--test/CodeGen/debug-info-block-decl.c4
-rw-r--r--test/CodeGen/debug-info-block-out-return.c25
-rw-r--r--test/CodeGen/debug-info-enum.c6
-rw-r--r--test/CodeGen/debug-info-line3.c2
-rw-r--r--test/CodeGen/debug-info-line4.c2
-rw-r--r--test/CodeGen/debug-info-scope-file.c4
-rw-r--r--test/CodeGen/debug-info-scope.c12
-rw-r--r--test/CodeGen/debug-info-typedef.c4
-rw-r--r--test/CodeGen/debug-info-version.c4
-rw-r--r--test/CodeGen/debug-info-vla.c2
-rw-r--r--test/CodeGen/debug-info.c2
-rw-r--r--test/CodeGen/dependent-lib.c12
-rw-r--r--test/CodeGen/designated-initializers.c3
-rw-r--r--test/CodeGen/dllimport.c56
-rw-r--r--test/CodeGen/dwarf-version.c7
-rw-r--r--test/CodeGen/ext-vector-indexing.c14
-rw-r--r--test/CodeGen/fp128_complex.c9
-rw-r--r--test/CodeGen/fsgsbase-builtins.c54
-rw-r--r--test/CodeGen/lineno-dbginfo.c7
-rw-r--r--test/CodeGen/linetable-endscope.c4
-rw-r--r--test/CodeGen/link-bitcode-file.c2
-rw-r--r--test/CodeGen/lzcnt-builtins.c12
-rw-r--r--test/CodeGen/mangle-blocks.c23
-rw-r--r--test/CodeGen/mangle-windows.c39
-rw-r--r--test/CodeGen/may-alias.c24
-rw-r--r--test/CodeGen/merge-statics.c5
-rw-r--r--test/CodeGen/microsoft-call-conv.c12
-rw-r--r--test/CodeGen/mips-constraint-regs.c6
-rw-r--r--test/CodeGen/mips-constraints-mem.c2
-rw-r--r--test/CodeGen/mips-inline-asm-modifiers.c6
-rw-r--r--test/CodeGen/mips-transparent-union.c27
-rw-r--r--test/CodeGen/mips-varargs.c115
-rw-r--r--test/CodeGen/mmx-inline-asm-error.c6
-rw-r--r--test/CodeGen/mozilla-ms-inline-asm.c17
-rw-r--r--test/CodeGen/mrtd.c4
-rw-r--r--test/CodeGen/ms-align-tentative.c15
-rw-r--r--test/CodeGen/ms-declspecs.c4
-rw-r--r--test/CodeGen/ms-inline-asm-functions.c60
-rw-r--r--test/CodeGen/ms-inline-asm.c317
-rw-r--r--test/CodeGen/ms-inline-asm.cpp46
-rw-r--r--test/CodeGen/ms-intrinsics.c59
-rw-r--r--test/CodeGen/mult-alt-generic.c2
-rw-r--r--test/CodeGen/named_reg_global.c2
-rw-r--r--test/CodeGen/nonnull.c28
-rw-r--r--test/CodeGen/nvptx-abi.c34
-rw-r--r--test/CodeGen/piclevels.c7
-rw-r--r--test/CodeGen/ppc-signbit.c11
-rw-r--r--test/CodeGen/ppc-varargs-struct.c112
-rw-r--r--test/CodeGen/ppc64-elf-abi.c40
-rw-r--r--test/CodeGen/ppc64-varargs-struct.c30
-rw-r--r--test/CodeGen/ppc64le-aggregates.c6
-rw-r--r--test/CodeGen/pr5406.c2
-rw-r--r--test/CodeGen/pragma-comment.c20
-rw-r--r--test/CodeGen/pragma-detect_mismatch.c24
-rw-r--r--test/CodeGen/pragma-loop.cpp120
-rw-r--r--test/CodeGen/pragma-unroll.cpp24
-rw-r--r--test/CodeGen/pragma-weak.c20
-rw-r--r--test/CodeGen/predefined-expr.c4
-rw-r--r--test/CodeGen/sanitize-address-field-padding.cpp237
-rw-r--r--test/CodeGen/sanitize-init-order.cpp34
-rw-r--r--test/CodeGen/sanitize-recover.c28
-rw-r--r--test/CodeGen/sse-builtins.c288
-rw-r--r--test/CodeGen/target-data.c12
-rw-r--r--test/CodeGen/tbaa-class.cpp56
-rw-r--r--test/CodeGen/tbaa-for-vptr.cpp6
-rw-r--r--test/CodeGen/tbaa-ms-abi.cpp8
-rw-r--r--test/CodeGen/tbaa-struct.cpp18
-rw-r--r--test/CodeGen/tbaa.cpp66
-rw-r--r--test/CodeGen/transparent-union.c19
-rw-r--r--test/CodeGen/ubsan-type-blacklist.cpp6
-rw-r--r--test/CodeGen/variadic-null-win64.c17
-rw-r--r--test/CodeGen/vectorcall.c77
-rw-r--r--test/CodeGen/vlt_to_pointer.c30
-rw-r--r--test/CodeGen/wchar-const.c4
-rw-r--r--test/CodeGen/windows-struct-abi.c42
-rw-r--r--test/CodeGen/x86-atomic-long_double.c469
-rw-r--r--test/CodeGen/x86_32-inline-asm.c48
-rw-r--r--test/CodeGen/x86_64-arguments-win32.c16
-rw-r--r--test/CodeGen/xcore-stringtype.c102
-rw-r--r--test/CodeGenCUDA/launch-bounds.cu6
-rw-r--r--test/CodeGenCUDA/ptx-kernels.cu2
-rw-r--r--test/CodeGenCXX/2010-07-23-DeclLoc.cpp2
-rw-r--r--test/CodeGenCXX/PR20038.cpp8
-rw-r--r--test/CodeGenCXX/align-avx-complete-objects.cpp57
-rw-r--r--test/CodeGenCXX/atomicinit.cpp12
-rw-r--r--test/CodeGenCXX/attr-used.cpp10
-rw-r--r--test/CodeGenCXX/call-with-static-chain.cpp39
-rw-r--r--test/CodeGenCXX/catch-undef-behavior.cpp49
-rw-r--r--test/CodeGenCXX/class-layout.cpp2
-rw-r--r--test/CodeGenCXX/compound-literals.cpp15
-rw-r--r--test/CodeGenCXX/constructor-destructor-return-this.cpp14
-rw-r--r--test/CodeGenCXX/constructor-init.cpp12
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis-2.cpp2
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis.cpp4
-rw-r--r--test/CodeGenCXX/coverage.cpp4
-rw-r--r--test/CodeGenCXX/crash.cpp11
-rw-r--r--test/CodeGenCXX/ctor-dtor-alias.cpp107
-rw-r--r--test/CodeGenCXX/ctor-globalopt.cpp28
-rw-r--r--test/CodeGenCXX/cxx11-exception-spec.cpp21
-rw-r--r--test/CodeGenCXX/cxx11-special-members.cpp14
-rw-r--r--test/CodeGenCXX/cxx11-thread-local.cpp4
-rw-r--r--test/CodeGenCXX/cxx1y-initializer-aggregate.cpp11
-rw-r--r--test/CodeGenCXX/cxx1y-variable-template-linkage.cpp40
-rw-r--r--test/CodeGenCXX/cxx1z-fold-expression.cpp45
-rw-r--r--test/CodeGenCXX/debug-info-access.cpp39
-rw-r--r--test/CodeGenCXX/debug-info-alias.cpp6
-rw-r--r--test/CodeGenCXX/debug-info-artificial-arg.cpp8
-rw-r--r--test/CodeGenCXX/debug-info-class.cpp30
-rw-r--r--test/CodeGenCXX/debug-info-cxx1y.cpp17
-rw-r--r--test/CodeGenCXX/debug-info-decl-nested.cpp13
-rw-r--r--test/CodeGenCXX/debug-info-enum-class.cpp12
-rw-r--r--test/CodeGenCXX/debug-info-enum.cpp18
-rw-r--r--test/CodeGenCXX/debug-info-flex-member.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-function-context.cpp8
-rw-r--r--test/CodeGenCXX/debug-info-global.cpp6
-rw-r--r--test/CodeGenCXX/debug-info-globalinit.cpp4
-rw-r--r--test/CodeGenCXX/debug-info-line-if.cpp65
-rw-r--r--test/CodeGenCXX/debug-info-line.cpp187
-rw-r--r--test/CodeGenCXX/debug-info-method.cpp18
-rw-r--r--test/CodeGenCXX/debug-info-namespace.cpp78
-rw-r--r--test/CodeGenCXX/debug-info-ptr-to-member-function.cpp10
-rw-r--r--test/CodeGenCXX/debug-info-qualifiers.cpp18
-rw-r--r--test/CodeGenCXX/debug-info-rvalue-ref.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-scope.cpp67
-rw-r--r--test/CodeGenCXX/debug-info-static-fns.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-static-member.cpp81
-rw-r--r--test/CodeGenCXX/debug-info-template-explicit-specialization.cpp8
-rw-r--r--test/CodeGenCXX/debug-info-template-limit.cpp4
-rw-r--r--test/CodeGenCXX/debug-info-template-member.cpp42
-rw-r--r--test/CodeGenCXX/debug-info-template-partial-specialization.cpp4
-rw-r--r--test/CodeGenCXX/debug-info-template-quals.cpp14
-rw-r--r--test/CodeGenCXX/debug-info-template.cpp116
-rw-r--r--test/CodeGenCXX/debug-info-thunk.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-union-template.cpp6
-rw-r--r--test/CodeGenCXX/debug-info-uuid.cpp24
-rw-r--r--test/CodeGenCXX/debug-info-varargs.cpp18
-rw-r--r--test/CodeGenCXX/debug-info-wchar.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-windows-dtor.cpp22
-rw-r--r--test/CodeGenCXX/debug-info-zero-length-arrays.cpp8
-rw-r--r--test/CodeGenCXX/debug-info.cpp33
-rw-r--r--test/CodeGenCXX/debug-lambda-expressions.cpp44
-rw-r--r--test/CodeGenCXX/debug-lambda-this.cpp2
-rw-r--r--test/CodeGenCXX/destructor-debug-info.cpp2
-rw-r--r--test/CodeGenCXX/destructors.cpp362
-rw-r--r--test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp46
-rw-r--r--test/CodeGenCXX/dllexport-alias.cpp18
-rw-r--r--test/CodeGenCXX/dllexport-members.cpp32
-rw-r--r--test/CodeGenCXX/dllexport.cpp166
-rw-r--r--test/CodeGenCXX/dllimport-members.cpp408
-rw-r--r--test/CodeGenCXX/dllimport-rtti.cpp18
-rw-r--r--test/CodeGenCXX/dllimport.cpp164
-rw-r--r--test/CodeGenCXX/duplicate-mangled-name.cpp2
-rw-r--r--test/CodeGenCXX/explicit-instantiation.cpp13
-rw-r--r--test/CodeGenCXX/extern-c.cpp4
-rw-r--r--test/CodeGenCXX/field-access-debug-info.cpp4
-rw-r--r--test/CodeGenCXX/funcsig.cpp6
-rw-r--r--test/CodeGenCXX/function-template-specialization.cpp19
-rw-r--r--test/CodeGenCXX/globalinit-loc.cpp4
-rw-r--r--test/CodeGenCXX/homogeneous-aggregates.cpp106
-rw-r--r--test/CodeGenCXX/lambda-expressions.cpp14
-rw-r--r--test/CodeGenCXX/linetable-cleanup.cpp18
-rw-r--r--test/CodeGenCXX/linetable-eh.cpp12
-rw-r--r--test/CodeGenCXX/linetable-fnbegin.cpp6
-rw-r--r--test/CodeGenCXX/lpad-linetable.cpp2
-rw-r--r--test/CodeGenCXX/mangle-exprs.cpp101
-rw-r--r--test/CodeGenCXX/mangle-literal-suffix.cpp17
-rw-r--r--test/CodeGenCXX/mangle-local-anonymous-unions.cpp42
-rw-r--r--test/CodeGenCXX/mangle-ms-cxx11.cpp108
-rw-r--r--test/CodeGenCXX/mangle-ms-cxx14.cpp4
-rw-r--r--test/CodeGenCXX/mangle-ms-string-literals.cpp6
-rw-r--r--test/CodeGenCXX/mangle-ms-templates.cpp10
-rw-r--r--test/CodeGenCXX/mangle-ms.cpp15
-rw-r--r--test/CodeGenCXX/mangle.cpp22
-rw-r--r--test/CodeGenCXX/merge-functions.cpp14
-rw-r--r--test/CodeGenCXX/microsoft-abi-byval-sret.cpp61
-rw-r--r--test/CodeGenCXX/microsoft-abi-byval-thunks.cpp113
-rw-r--r--test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp54
-rwxr-xr-xtest/CodeGenCXX/microsoft-abi-member-pointers.cpp100
-rw-r--r--test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp20
-rw-r--r--test/CodeGenCXX/microsoft-abi-nontrivial-covariant-thunk.cpp2
-rw-r--r--test/CodeGenCXX/microsoft-abi-static-initializers.cpp34
-rw-r--r--test/CodeGenCXX/microsoft-abi-structors-delayed-template.cpp12
-rw-r--r--test/CodeGenCXX/microsoft-abi-structors.cpp70
-rw-r--r--test/CodeGenCXX/microsoft-abi-thunks.cpp11
-rw-r--r--test/CodeGenCXX/microsoft-abi-typeid.cpp9
-rw-r--r--test/CodeGenCXX/microsoft-abi-vftables.cpp8
-rw-r--r--test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp7
-rw-r--r--test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp89
-rw-r--r--test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp119
-rw-r--r--test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp101
-rw-r--r--test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp11
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp67
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp51
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-return-thunks.cpp24
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp10
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp20
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp45
-rw-r--r--test/CodeGenCXX/microsoft-interface.cpp4
-rw-r--r--test/CodeGenCXX/microsoft-no-rtti-data.cpp1
-rw-r--r--test/CodeGenCXX/microsoft-uuidof-mangling.cpp48
-rw-r--r--test/CodeGenCXX/mingw-w64-seh-exceptions.cpp24
-rw-r--r--test/CodeGenCXX/ms-inline-asm-return.cpp100
-rw-r--r--test/CodeGenCXX/ms-integer-static-data-members-exported.cpp4
-rw-r--r--test/CodeGenCXX/ms-integer-static-data-members.cpp2
-rw-r--r--test/CodeGenCXX/ms-thread_local.cpp28
-rw-r--r--test/CodeGenCXX/nrvo-noreturn.cpp (renamed from test/CodeGenCXX/nrvo-noreturn.cc)0
-rw-r--r--test/CodeGenCXX/optnone-def-decl.cpp94
-rw-r--r--test/CodeGenCXX/pod-member-memcpys.cpp13
-rw-r--r--test/CodeGenCXX/pointers-to-data-members.cpp24
-rw-r--r--test/CodeGenCXX/pr12251.cpp19
-rw-r--r--test/CodeGenCXX/pr18635.cpp22
-rw-r--r--test/CodeGenCXX/pr18962.cpp2
-rw-r--r--test/CodeGenCXX/pr20719.cpp35
-rw-r--r--test/CodeGenCXX/pr20897.cpp33
-rw-r--r--test/CodeGenCXX/pr21989.cpp9
-rw-r--r--test/CodeGenCXX/pragma-init_seg.cpp12
-rw-r--r--test/CodeGenCXX/predefined-expr-cxx14.cpp105
-rw-r--r--test/CodeGenCXX/predefined-expr.cpp32
-rw-r--r--test/CodeGenCXX/runtimecc.cpp22
-rw-r--r--test/CodeGenCXX/sections.cpp (renamed from test/CodeGen/sections.c)31
-rw-r--r--test/CodeGenCXX/skip-vtable-pointer-initialization.cpp16
-rw-r--r--test/CodeGenCXX/split-stacks.cpp4
-rw-r--r--test/CodeGenCXX/static-data-member.cpp14
-rw-r--r--test/CodeGenCXX/static-init.cpp8
-rw-r--r--test/CodeGenCXX/static-local-in-local-class.cpp133
-rw-r--r--test/CodeGenCXX/static-member-variable-explicit-specialization.cpp135
-rw-r--r--test/CodeGenCXX/temporaries.cpp7
-rw-r--r--test/CodeGenCXX/try-catch.cpp8
-rw-r--r--test/CodeGenCXX/unknown-anytype.cpp8
-rw-r--r--test/CodeGenCXX/vararg-non-pod-ms-compat.cpp28
-rw-r--r--test/CodeGenCXX/virtual-base-cast.cpp36
-rw-r--r--test/CodeGenCXX/virtual-destructor-calls.cpp2
-rw-r--r--test/CodeGenCXX/virtual-operator-call.cpp9
-rw-r--r--test/CodeGenCXX/vla-lambda-capturing.cpp171
-rw-r--r--test/CodeGenCXX/vlt_to_reference.cpp22
-rw-r--r--test/CodeGenCXX/vtable-align.cpp14
-rw-r--r--test/CodeGenCXX/vtable-holder-self-reference.cpp15
-rw-r--r--test/CodeGenCXX/vtable-pointer-initialization.cpp8
-rw-r--r--test/CodeGenCXX/x86_64-arguments-nacl-x32.cpp44
-rw-r--r--test/CodeGenCXX/x86_64-arguments.cpp15
-rw-r--r--test/CodeGenObjC/2010-02-09-DbgSelf.m2
-rw-r--r--test/CodeGenObjC/2010-02-15-Dbg-MethodStart.m3
-rw-r--r--test/CodeGenObjC/arc-foreach.m6
-rw-r--r--test/CodeGenObjC/arc-linetable-autorelease.m4
-rw-r--r--test/CodeGenObjC/arc-linetable.m34
-rw-r--r--test/CodeGenObjC/arc-literals.m14
-rw-r--r--test/CodeGenObjC/arc-loadweakretained-release.m2
-rw-r--r--test/CodeGenObjC/arc-precise-lifetime.m8
-rw-r--r--test/CodeGenObjC/arc-property.m4
-rw-r--r--test/CodeGenObjC/arc.m52
-rw-r--r--test/CodeGenObjC/arm-atomic-scalar-setter-getter.m4
-rw-r--r--test/CodeGenObjC/block-byref-debuginfo.m2
-rw-r--r--test/CodeGenObjC/block-over-align.m25
-rw-r--r--test/CodeGenObjC/boxing.m24
-rw-r--r--test/CodeGenObjC/catch-lexical-block.m2
-rw-r--r--test/CodeGenObjC/category-super-class-meth.m4
-rw-r--r--test/CodeGenObjC/debug-info-block-captured-self.m10
-rw-r--r--test/CodeGenObjC/debug-info-block-type.m18
-rw-r--r--test/CodeGenObjC/debug-info-blocks.m10
-rw-r--r--test/CodeGenObjC/debug-info-getter-name.m2
-rw-r--r--test/CodeGenObjC/debug-info-id-with-protocol.m7
-rw-r--r--test/CodeGenObjC/debug-info-instancetype.m10
-rw-r--r--test/CodeGenObjC/debug-info-ivars-extension.m4
-rw-r--r--test/CodeGenObjC/debug-info-lifetime-crash.m4
-rw-r--r--test/CodeGenObjC/debug-info-nested-blocks.m26
-rw-r--r--test/CodeGenObjC/debug-info-property-accessors.m2
-rw-r--r--test/CodeGenObjC/debug-info-property3.m2
-rw-r--r--test/CodeGenObjC/debug-info-self.m6
-rw-r--r--test/CodeGenObjC/debug-info-static-var.m2
-rw-r--r--test/CodeGenObjC/debug-info-synthesis.m2
-rw-r--r--test/CodeGenObjC/debug-info-variadic-method.m16
-rw-r--r--test/CodeGenObjC/debug-property-synth.m4
-rw-r--r--test/CodeGenObjC/encode-test.m2
-rw-r--r--test/CodeGenObjC/exceptions-asm-attribute.m8
-rw-r--r--test/CodeGenObjC/externally-initialized-selectors.m2
-rw-r--r--test/CodeGenObjC/forward-protocol-metadata-symbols.m2
-rw-r--r--test/CodeGenObjC/image-info.m16
-rw-r--r--test/CodeGenObjC/ivar-layout-64.m26
-rw-r--r--test/CodeGenObjC/mangle-blocks.m29
-rw-r--r--test/CodeGenObjC/metadata-symbols-32.m42
-rw-r--r--test/CodeGenObjC/metadata-symbols-64.m20
-rw-r--r--test/CodeGenObjC/metadata_symbols.m8
-rw-r--r--test/CodeGenObjC/non-lazy-classes.m7
-rw-r--r--test/CodeGenObjC/objc-align.m35
-rw-r--r--test/CodeGenObjC/objc-container-subscripting-1.m8
-rw-r--r--test/CodeGenObjC/objc-fixed-enum.m24
-rw-r--r--test/CodeGenObjC/optimize-ivar-offset-load.m4
-rw-r--r--test/CodeGenObjC/optimized-setter-ios-device.m8
-rw-r--r--test/CodeGenObjC/private-extern-selector-reference.m18
-rw-r--r--test/CodeGenObjC/property-array-type.m2
-rw-r--r--test/CodeGenObjC/property-type-mismatch.m2
-rw-r--r--test/CodeGenObjC/property.m12
-rw-r--r--test/CodeGenObjC/reorder-synthesized-ivars.m36
-rw-r--r--test/CodeGenObjC/selector-ref-invariance.m2
-rw-r--r--test/CodeGenObjC/super-message-fragileabi.m2
-rw-r--r--test/CodeGenObjC/tentative-cfconstantstring.m4
-rw-r--r--test/CodeGenObjC/undefined-protocol2.m17
-rw-r--r--test/CodeGenObjCXX/arc-cxx11-init-list.mm55
-rw-r--r--test/CodeGenObjCXX/arc-cxx11-member-init.mm17
-rw-r--r--test/CodeGenObjCXX/arc-references.mm2
-rw-r--r--test/CodeGenObjCXX/arc.mm2
-rw-r--r--test/CodeGenObjCXX/block-id.mm22
-rw-r--r--test/CodeGenObjCXX/debug-info-line.mm30
-rw-r--r--test/CodeGenObjCXX/destroy.mm50
-rw-r--r--test/CodeGenObjCXX/externally-initialized-selectors.mm2
-rw-r--r--test/CodeGenObjCXX/lambda-expressions.mm4
-rw-r--r--test/CodeGenObjCXX/lvalue-reference-getter.mm2
-rw-r--r--test/CodeGenObjCXX/mangle-blocks.mm13
-rw-r--r--test/CodeGenObjCXX/property-lvalue-capture.mm6
-rw-r--r--test/CodeGenObjCXX/property-object-reference.mm4
-rw-r--r--test/CodeGenObjCXX/property-objects.mm7
-rw-r--r--test/CodeGenObjCXX/subst-sel.mm4
-rw-r--r--test/CodeGenOpenCL/addr-space-struct-arg.cl46
-rw-r--r--test/CodeGenOpenCL/address-space-constant-initializers.cl2
-rw-r--r--test/CodeGenOpenCL/address-spaces-conversions.cl22
-rw-r--r--test/CodeGenOpenCL/amdgpu-num-gpr-attr.cl48
-rw-r--r--test/CodeGenOpenCL/builtins-r600.cl37
-rw-r--r--test/CodeGenOpenCL/const-str-array-decay.cl11
-rw-r--r--test/CodeGenOpenCL/constant-addr-space-globals.cl8
-rw-r--r--test/CodeGenOpenCL/denorms-are-zero.cl5
-rw-r--r--test/CodeGenOpenCL/fpmath.cl2
-rw-r--r--test/CodeGenOpenCL/kernel-arg-info.cl59
-rw-r--r--test/CodeGenOpenCL/kernel-attributes.cl12
-rw-r--r--test/CodeGenOpenCL/kernel-metadata.cl7
-rw-r--r--test/CodeGenOpenCL/local-initializer-undef.cl24
-rw-r--r--test/CodeGenOpenCL/local.cl6
-rw-r--r--test/CodeGenOpenCL/opencl_types.cl5
-rw-r--r--test/CodeGenOpenCL/ptx-calls.cl2
-rw-r--r--test/CodeGenOpenCL/ptx-kernels.cl2
-rw-r--r--test/CodeGenOpenCL/relaxed-fpmath.cl36
-rw-r--r--test/CodeGenOpenCL/str_literals.cl4
-rw-r--r--test/Coverage/html-diagnostics.c5
-rw-r--r--test/CoverageMapping/Inputs/code.h11
-rw-r--r--test/CoverageMapping/Inputs/header1.h31
-rw-r--r--test/CoverageMapping/break.c31
-rw-r--r--test/CoverageMapping/builtinmacro.c14
-rw-r--r--test/CoverageMapping/casts.c11
-rw-r--r--test/CoverageMapping/classtemplate.cpp54
-rw-r--r--test/CoverageMapping/continue.c24
-rw-r--r--test/CoverageMapping/header.cpp27
-rw-r--r--test/CoverageMapping/if.c24
-rw-r--r--test/CoverageMapping/includehell.cpp12
-rw-r--r--test/CoverageMapping/ir.c12
-rw-r--r--test/CoverageMapping/label.cpp63
-rw-r--r--test/CoverageMapping/logical.cpp13
-rw-r--r--test/CoverageMapping/loopmacro.c40
-rw-r--r--test/CoverageMapping/loops.cpp37
-rw-r--r--test/CoverageMapping/macroception.c40
-rw-r--r--test/CoverageMapping/macroparams.c12
-rw-r--r--test/CoverageMapping/macroparams2.c20
-rw-r--r--test/CoverageMapping/macros.c26
-rw-r--r--test/CoverageMapping/nestedclass.cpp28
-rw-r--r--test/CoverageMapping/objc.m29
-rw-r--r--test/CoverageMapping/preprocessor.c37
-rw-r--r--test/CoverageMapping/return.c35
-rw-r--r--test/CoverageMapping/switch.c48
-rw-r--r--test/CoverageMapping/templates.cpp21
-rw-r--r--test/CoverageMapping/test.c31
-rw-r--r--test/CoverageMapping/trycatch.cpp34
-rw-r--r--test/Driver/B-opt.c8
-rwxr-xr-xtest/Driver/Inputs/Windows/ARM/8.1/usr/bin/armv7-windows-itanium-ld0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/eabihf/crti.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/powerpc/crti.o0
-rw-r--r--test/Driver/Inputs/cc1-response.txt4
-rw-r--r--test/Driver/Inputs/gen-response.c8
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/el/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/nan2008/el/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/soft-float/el/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/el/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/nan2008/el/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/soft-float/el/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/lib/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/include/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/lib/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/lib/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/include/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/lib/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/include/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/lib/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/include/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/lib/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/include/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/include/.keep0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/nan2008/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/nan2008/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/sof/crtbegin.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/sof/crtend.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/nan2008/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/sof/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/el/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/el/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/nan2008/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/sof/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/include/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/include/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/include/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/include/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/include/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/include/bits/.keep0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crtn.o0
-rw-r--r--test/Driver/aarch64-cpus.c27
-rw-r--r--test/Driver/aarch64-fix-cortex-a53-835769.c13
-rw-r--r--test/Driver/arm-abi.c53
-rw-r--r--test/Driver/arm-alignment.c12
-rw-r--r--test/Driver/arm-cortex-cpus.c14
-rw-r--r--test/Driver/arm-fixed-r9.c2
-rw-r--r--test/Driver/arm-mfpu.c45
-rw-r--r--test/Driver/ast.c7
-rw-r--r--test/Driver/biarch.c41
-rw-r--r--test/Driver/cc1-response-files.c2
-rw-r--r--test/Driver/cl-inputs.c10
-rw-r--r--test/Driver/cl-link-at-file.c22
-rw-r--r--test/Driver/cl-link.c9
-rw-r--r--test/Driver/cl-options.c26
-rw-r--r--test/Driver/cl-outputs.c168
-rw-r--r--test/Driver/cl-zc.cpp59
-rw-r--r--test/Driver/clang-g-opts.c2
-rw-r--r--test/Driver/clang-s-opts.s4
-rw-r--r--test/Driver/clang_f_opts.c150
-rw-r--r--test/Driver/constructors.c10
-rw-r--r--test/Driver/coverage_no_integrated_as.c23
-rw-r--r--test/Driver/crash report spaces.c18
-rw-r--r--test/Driver/crash-report-modules.m10
-rw-r--r--test/Driver/crash-report-null.test7
-rw-r--r--test/Driver/crash-report.c36
-rw-r--r--test/Driver/cross-linux.c28
-rw-r--r--test/Driver/darwin-arch-default.c40
-rw-r--r--test/Driver/darwin-debug-flags.c8
-rw-r--r--test/Driver/darwin-dsymutil.c15
-rw-r--r--test/Driver/darwin-ld-demangle.c8
-rw-r--r--test/Driver/darwin-ld.c18
-rw-r--r--test/Driver/darwin-max-type-align.c15
-rw-r--r--test/Driver/darwin-sanitizer-ld.c8
-rw-r--r--test/Driver/darwin-sdkroot.c7
-rw-r--r--test/Driver/darwin-verify-debug.c5
-rw-r--r--test/Driver/debug-options.c4
-rw-r--r--test/Driver/default-image-name.c7
-rw-r--r--test/Driver/env.c28
-rw-r--r--test/Driver/fatal-warnings.c8
-rw-r--r--test/Driver/fortran.f959
-rw-r--r--test/Driver/freebsd.c12
-rw-r--r--test/Driver/freebsd.cpp (renamed from test/Driver/freebsd.cc)0
-rw-r--r--test/Driver/fsanitize.c87
-rw-r--r--test/Driver/gcc-version-debug.c1
-rw-r--r--test/Driver/gcc_forward.c4
-rw-r--r--test/Driver/hexagon-toolchain-elf.c137
-rw-r--r--test/Driver/hexagon-toolchain.c137
-rw-r--r--test/Driver/ident_md.c2
-rw-r--r--test/Driver/instrprof-ld.c6
-rw-r--r--test/Driver/le32-unknown-nacl.cpp6
-rw-r--r--test/Driver/le64-unknown-unknown.cpp137
-rw-r--r--test/Driver/linux-header-search.cpp18
-rw-r--r--test/Driver/linux-ld.c190
-rw-r--r--test/Driver/lto.c13
-rw-r--r--test/Driver/mips-as.c20
-rw-r--r--test/Driver/mips-cs.cpp174
-rw-r--r--test/Driver/mips-features.c10
-rw-r--r--test/Driver/mips-fsf.cpp162
-rw-r--r--test/Driver/mips-integrated-as.s10
-rw-r--r--test/Driver/mips-reduced-toolchain.cpp2
-rw-r--r--test/Driver/modules.m24
-rw-r--r--test/Driver/modules.mm6
-rw-r--r--test/Driver/msvc_forward.c4
-rw-r--r--test/Driver/netbsd.c141
-rw-r--r--test/Driver/netbsd.cpp96
-rw-r--r--test/Driver/no-canonical-prefixes.c10
-rw-r--r--test/Driver/openbsd.c17
-rw-r--r--test/Driver/parse-progname.c58
-rw-r--r--test/Driver/phases.c66
-rw-r--r--test/Driver/pic.c5
-rw-r--r--test/Driver/ppc-abi.c19
-rw-r--r--test/Driver/ppc-features.cpp16
-rw-r--r--test/Driver/prefixed-tools.c8
-rw-r--r--test/Driver/r600-mcpu.cl18
-rw-r--r--test/Driver/response-file.c23
-rw-r--r--test/Driver/rewrite-legacy-objc.m6
-rw-r--r--test/Driver/rewrite-map-in-diagnostics.c12
-rw-r--r--test/Driver/rewrite-objc.m2
-rw-r--r--test/Driver/sanitizer-ld.c63
-rw-r--r--test/Driver/save-temps.c11
-rw-r--r--test/Driver/sparc-float.c4
-rw-r--r--test/Driver/split-debug.c1
-rw-r--r--test/Driver/split-debug.s1
-rw-r--r--test/Driver/std.c16
-rw-r--r--test/Driver/symbol-rewriter.c21
-rw-r--r--test/Driver/systemz-as.s14
-rw-r--r--test/Driver/thread-model.c15
-rw-r--r--test/Driver/unknown-gcc-arch.c20
-rw-r--r--test/Driver/warning-options.cpp5
-rw-r--r--test/Driver/windows-cross.c40
-rw-r--r--test/Driver/x86-march.c105
-rw-r--r--test/FixIt/fixit-class-method-messaging.m30
-rw-r--r--test/FixIt/fixit-cxx1y-compat.cpp2
-rw-r--r--test/FixIt/fixit-errors.c10
-rw-r--r--test/FixIt/fixit-unrecoverable.cpp4
-rw-r--r--test/FixIt/fixit.cpp49
-rw-r--r--test/FixIt/multiarg-selector-fixit.m15
-rw-r--r--test/FixIt/property-access-fixit.m31
-rw-r--r--test/Frontend/Inputs/profile-sample-use-loc-tracking.prof2
-rw-r--r--test/Frontend/exceptions.c7
-rw-r--r--test/Frontend/invalid-o-level.c7
-rw-r--r--test/Frontend/output-failures.c2
-rw-r--r--test/Frontend/print-header-includes.c3
-rw-r--r--test/Frontend/profile-sample-use-loc-tracking.c19
-rw-r--r--test/Frontend/source-col-map.c37
-rw-r--r--test/Frontend/std.cl9
-rw-r--r--test/Frontend/trigraphs.cpp17
-rw-r--r--test/Frontend/verify-unknown-arg.c6
-rw-r--r--test/Frontend/x86-target-cpu.c30
-rw-r--r--test/Headers/altivec-header.c1
-rw-r--r--test/Headers/altivec-intrin.c18
-rw-r--r--test/Headers/c11.c2
-rw-r--r--test/Headers/cpuid.c18
-rw-r--r--test/Headers/cxx11.cpp3
-rw-r--r--test/Headers/ms-intrin.cpp5
-rw-r--r--test/Headers/x86intrin.c39
-rw-r--r--test/Index/Inputs/complete-at-EOF.c3
-rw-r--r--test/Index/Inputs/declare-objc-predef.h3
-rw-r--r--test/Index/Inputs/module-undef.h2
-rw-r--r--test/Index/Inputs/module.map2
-rw-r--r--test/Index/annotate-deep-statements.cpp4
-rw-r--r--test/Index/attributes-cuda.cu7
-rw-r--r--test/Index/comment-c-decls.c2
-rw-r--r--test/Index/comment-lots-of-unknown-commands.c295
-rw-r--r--test/Index/comment-to-html-xml-conversion.cpp52
-rw-r--r--test/Index/complete-at-EOF.c9
-rw-r--r--test/Index/complete-module-undef.m8
-rw-r--r--test/Index/cursor-dynamic-call.mm14
-rw-r--r--test/Index/cxx11-lambdas.cpp2
-rw-r--r--test/Index/format-comment-cdecls.c2
-rw-r--r--test/Index/get-cursor.cpp131
-rw-r--r--test/Index/index-many-call-ops.cpp3
-rw-r--r--test/Index/index-many-logical-ops.c3
-rw-r--r--test/Index/index-module.m4
-rw-r--r--test/Index/index-templates.cpp32
-rw-r--r--test/Index/overriding-ftemplate-comments.cpp20
-rw-r--r--test/Index/overriding-method-comments.mm4
-rw-r--r--test/Index/preamble_macro_template.cpp2
-rw-r--r--test/Index/print-mangled-name.cpp30
-rw-r--r--test/Index/reparse-predef-objc-protocol.m9
-rw-r--r--test/Index/skip-parsed-bodies/compile_commands.json2
-rw-r--r--test/Index/usrs-cxx0x.cpp10
-rw-r--r--test/Index/usrs.cpp82
-rw-r--r--test/Layout/itanium-union-bitfield.cpp29
-rw-r--r--test/Layout/ms-x86-basic-layout.cpp32
-rw-r--r--test/Layout/ms-x86-empty-layout.c88
-rw-r--r--test/Layout/ms-x86-pack-and-align.cpp154
-rw-r--r--test/Layout/ms-x86-vtordisp.cpp26
-rw-r--r--test/Lexer/bcpl-escaped-newline.c2
-rw-r--r--test/Lexer/block_cmt_end.c10
-rw-r--r--test/Lexer/constants.c6
-rw-r--r--test/Lexer/cxx-features.cpp36
-rw-r--r--test/Lexer/cxx1z-trigraphs.cpp2
-rw-r--r--test/Lexer/escape_newline.c8
-rw-r--r--test/Lexer/has_extension.c12
-rw-r--r--test/Lexer/has_feature_c1x.c22
-rw-r--r--test/Lexer/has_feature_cxx0x.cpp10
-rw-r--r--test/Lexer/ms-compatibility.c11
-rw-r--r--test/Lexer/string-literal-errors.cpp2
-rw-r--r--test/Lexer/utf8-char-literal.cpp9
-rw-r--r--test/Lexer/wchar-signedness.c1
-rw-r--r--test/Misc/ast-dump-arm-attr.c10
-rw-r--r--test/Misc/ast-dump-attr.cpp17
-rw-r--r--test/Misc/ast-dump-color.cpp24
-rw-r--r--test/Misc/ast-dump-decl.cpp5
-rw-r--r--test/Misc/ast-dump-invalid.cpp20
-rw-r--r--test/Misc/ast-dump-lookups.cpp38
-rw-r--r--test/Misc/ast-dump-msp430-attr.c10
-rw-r--r--test/Misc/ast-dump-templates.cpp12
-rw-r--r--test/Misc/ast-print-objectivec.m41
-rw-r--r--test/Misc/ast-print-pragmas.cpp15
-rw-r--r--test/Misc/attr-source-range.cpp16
-rw-r--r--test/Misc/diag-special-chars.c11
-rw-r--r--test/Misc/serialized-diags-driver.c20
-rw-r--r--test/Misc/serialized-diags.m2
-rw-r--r--test/Misc/warning-flags.c9
-rw-r--r--test/Modules/Inputs/AddRemovePrivate.framework/Headers/AddRemovePrivate.h1
-rw-r--r--test/Modules/Inputs/AddRemovePrivate.framework/Modules/module.modulemap1
-rw-r--r--test/Modules/Inputs/AddRemovePrivate.framework/Modules/module.private.modulemap1
-rw-r--r--test/Modules/Inputs/PR20399/FirstHeader.h14
-rw-r--r--test/Modules/Inputs/PR20399/SecondHeader.h13
-rw-r--r--test/Modules/Inputs/PR20399/module.modulemap18
-rw-r--r--test/Modules/Inputs/PR20399/stl_map.h13
-rw-r--r--test/Modules/Inputs/PR20399/vector17
-rw-r--r--test/Modules/Inputs/PR20786/TBranchProxy.h2
-rw-r--r--test/Modules/Inputs/PR20786/TFormula.h1
-rw-r--r--test/Modules/Inputs/PR20786/TMath.h1
-rw-r--r--test/Modules/Inputs/PR20786/module.modulemap3
-rw-r--r--test/Modules/Inputs/PR20786/random.h12
-rw-r--r--test/Modules/Inputs/StdDef/include_again.h2
-rw-r--r--test/Modules/Inputs/StdDef/module.map10
-rw-r--r--test/Modules/Inputs/StdDef/ptrdiff_t.h2
-rw-r--r--test/Modules/Inputs/attr-unavailable/module.modulemap4
-rw-r--r--test/Modules/Inputs/attr-unavailable/oneA.h4
-rw-r--r--test/Modules/Inputs/attr-unavailable/oneB.h5
-rw-r--r--test/Modules/Inputs/attr-unavailable/oneC.h3
-rw-r--r--test/Modules/Inputs/attr-unavailable/two.h6
-rw-r--r--test/Modules/Inputs/cxx-decls-imported.h24
-rw-r--r--test/Modules/Inputs/cxx-decls-merged.h26
-rw-r--r--test/Modules/Inputs/cxx-decls-premerged.h3
-rw-r--r--test/Modules/Inputs/cxx-irgen-left.h15
-rw-r--r--test/Modules/Inputs/cxx-irgen-right.h10
-rw-r--r--test/Modules/Inputs/cxx-irgen-top.h35
-rw-r--r--test/Modules/Inputs/cxx-lookup/a.h2
-rw-r--r--test/Modules/Inputs/cxx-lookup/b.h3
-rw-r--r--test/Modules/Inputs/cxx-lookup/c1.h3
-rw-r--r--test/Modules/Inputs/cxx-lookup/c2.h2
-rw-r--r--test/Modules/Inputs/cxx-lookup/module.modulemap8
-rw-r--r--test/Modules/Inputs/cxx-lookup/x.h2
-rw-r--r--test/Modules/Inputs/cxx-lookup/y.h5
-rw-r--r--test/Modules/Inputs/cxx-templates-a.h31
-rw-r--r--test/Modules/Inputs/cxx-templates-b.h21
-rw-r--r--test/Modules/Inputs/cxx-templates-c.h15
-rw-r--r--test/Modules/Inputs/cxx-templates-common.h18
-rw-r--r--test/Modules/Inputs/cxx-templates-d.h9
-rw-r--r--test/Modules/Inputs/cxx-templates-textual.h2
-rw-r--r--test/Modules/Inputs/declare-use/k.h8
-rw-r--r--test/Modules/Inputs/declare-use/l.h8
-rw-r--r--test/Modules/Inputs/declare-use/m.h8
-rw-r--r--test/Modules/Inputs/declare-use/m2.h1
-rw-r--r--test/Modules/Inputs/declare-use/module.map14
-rw-r--r--test/Modules/Inputs/dependency-gen-base.modulemap6
-rw-r--r--test/Modules/Inputs/dependency-gen-base2.modulemap4
-rw-r--r--test/Modules/Inputs/dependency-gen-included.h9
-rw-r--r--test/Modules/Inputs/dependency-gen-included2.h7
-rw-r--r--test/Modules/Inputs/dependency-gen.h11
-rw-r--r--test/Modules/Inputs/diamond_left.h2
-rw-r--r--test/Modules/Inputs/diamond_top.h1
-rw-r--r--test/Modules/Inputs/explicit-build/a.h5
-rw-r--r--test/Modules/Inputs/explicit-build/b.h7
-rw-r--r--test/Modules/Inputs/explicit-build/c.h7
-rw-r--r--test/Modules/Inputs/explicit-build/module.modulemap3
-rw-r--r--test/Modules/Inputs/filename/a.h1
-rw-r--r--test/Modules/Inputs/filename/module.map3
-rw-r--r--test/Modules/Inputs/include_next/x/a.h2
-rw-r--r--test/Modules/Inputs/include_next/x/module.modulemap2
-rw-r--r--test/Modules/Inputs/include_next/x/subdir/b.h2
-rw-r--r--test/Modules/Inputs/include_next/y/a.h1
-rw-r--r--test/Modules/Inputs/include_next/y/b.h1
-rw-r--r--test/Modules/Inputs/include_next/y/module.modulemap2
-rw-r--r--test/Modules/Inputs/inferred-attr/InferredExternC.framework/Headers/InferredExternC.h1
-rw-r--r--test/Modules/Inputs/inferred-attr/module.modulemap1
-rw-r--r--test/Modules/Inputs/macros_bottom.h3
-rw-r--r--test/Modules/Inputs/macros_right_undef.h1
-rw-r--r--test/Modules/Inputs/macros_top.h1
-rw-r--r--test/Modules/Inputs/malformed/c.h1
-rw-r--r--test/Modules/Inputs/malformed/module.map1
-rw-r--r--test/Modules/Inputs/merge-typedefs/a1.h11
-rw-r--r--test/Modules/Inputs/merge-typedefs/a2.h3
-rw-r--r--test/Modules/Inputs/merge-typedefs/b1.h11
-rw-r--r--test/Modules/Inputs/merge-typedefs/b2.h3
-rw-r--r--test/Modules/Inputs/merge-typedefs/module.modulemap9
-rw-r--r--test/Modules/Inputs/merge-using-decls/a.h43
-rw-r--r--test/Modules/Inputs/merge-using-decls/b.h50
-rw-r--r--test/Modules/Inputs/merge-using-decls/module.modulemap2
-rw-r--r--test/Modules/Inputs/modular_maps-moduleb-cwd.map4
-rw-r--r--test/Modules/Inputs/modular_maps/c.h4
-rw-r--r--test/Modules/Inputs/modular_maps/common.h2
-rw-r--r--test/Modules/Inputs/modular_maps/modulea-cwd.map7
-rw-r--r--test/Modules/Inputs/modular_maps/modulec-cwd.map3
-rw-r--r--test/Modules/Inputs/modular_maps/modulec.map3
-rw-r--r--test/Modules/Inputs/module.map16
-rw-r--r--test/Modules/Inputs/odr/a.h6
-rw-r--r--test/Modules/Inputs/odr/b.h8
-rw-r--r--test/Modules/Inputs/pch-used.h1
-rw-r--r--test/Modules/Inputs/pr19692/AIX.h2
-rw-r--r--test/Modules/Inputs/pr19692/Blah.h2
-rw-r--r--test/Modules/Inputs/pr19692/TBlah.h3
-rw-r--r--test/Modules/Inputs/pr19692/TFoo.h1
-rw-r--r--test/Modules/Inputs/pr19692/module.map3
-rw-r--r--test/Modules/Inputs/pr19692/stdint.h2
-rw-r--r--test/Modules/Inputs/preprocess-prefix.h2
-rw-r--r--test/Modules/Inputs/relative-dep-gen-1.h1
-rw-r--r--test/Modules/Inputs/relative-dep-gen-2.h1
-rw-r--r--test/Modules/Inputs/relative-dep-gen-cwd.modulemap4
-rw-r--r--test/Modules/Inputs/relative-dep-gen.modulemap4
-rw-r--r--test/Modules/Inputs/templates-left.h10
-rw-r--r--test/Modules/Inputs/templates-right.h4
-rw-r--r--test/Modules/Inputs/templates-top.h17
-rw-r--r--test/Modules/Inputs/va_list/module.modulemap2
-rw-r--r--test/Modules/Inputs/va_list/va_list_a.h1
-rw-r--r--test/Modules/Inputs/va_list/va_list_b.h2
-rw-r--r--test/Modules/Inputs/warn-unused-local-typedef.h1
-rw-r--r--test/Modules/Rmodule-build.m23
-rw-r--r--test/Modules/Werror-Wsystem-headers.m7
-rw-r--r--test/Modules/Werror.m1
-rw-r--r--test/Modules/add-remove-private.m28
-rw-r--r--test/Modules/attr-unavailable.m25
-rw-r--r--test/Modules/autolink.m16
-rw-r--r--test/Modules/cstd.m2
-rw-r--r--test/Modules/cxx-decls.cpp20
-rw-r--r--test/Modules/cxx-irgen.cpp56
-rw-r--r--test/Modules/cxx-lookup.cpp6
-rw-r--r--test/Modules/cxx-templates.cpp46
-rw-r--r--test/Modules/dependency-gen.m4
-rw-r--r--test/Modules/dependency-gen.modulemap.cpp18
-rw-r--r--test/Modules/explicit-build-flags.cpp49
-rw-r--r--test/Modules/explicit-build-relpath.cpp49
-rw-r--r--test/Modules/explicit-build.cpp175
-rw-r--r--test/Modules/filename.cpp9
-rw-r--r--test/Modules/fmodules-validate-once-per-build-session.c28
-rw-r--r--test/Modules/implementation-of-module.m29
-rw-r--r--test/Modules/include_next.c11
-rw-r--r--test/Modules/incomplete-module.m6
-rw-r--r--test/Modules/inferred-attributes.mm6
-rw-r--r--test/Modules/load-after-failure.m1
-rw-r--r--test/Modules/macro-reexport/c1.h2
-rw-r--r--test/Modules/macro-reexport/d1.h3
-rw-r--r--test/Modules/macro-reexport/e1.h2
-rw-r--r--test/Modules/macro-reexport/e2.h2
-rw-r--r--test/Modules/macro-reexport/f1.h3
-rw-r--r--test/Modules/macro-reexport/macro-reexport.cpp25
-rw-r--r--test/Modules/macro-reexport/module.modulemap8
-rw-r--r--test/Modules/macros.c6
-rw-r--r--test/Modules/malformed.cpp34
-rw-r--r--test/Modules/merge-typedefs.cpp10
-rw-r--r--test/Modules/merge-using-decls.cpp69
-rw-r--r--test/Modules/modular_maps.cpp20
-rw-r--r--test/Modules/module_file_info.m6
-rw-r--r--test/Modules/modules-with-same-name.m1
-rw-r--r--test/Modules/no-implicit-maps.cpp3
-rw-r--r--test/Modules/no-stale-modtime.m1
-rw-r--r--test/Modules/odr.cpp3
-rw-r--r--test/Modules/pch-used.m1
-rw-r--r--test/Modules/pr19692.cpp7
-rw-r--r--test/Modules/pr20399.cpp2
-rw-r--r--test/Modules/pr20786.cpp2
-rw-r--r--test/Modules/pr21217.cpp3
-rw-r--r--test/Modules/preprocess.m21
-rw-r--r--test/Modules/rebuild.m45
-rw-r--r--test/Modules/relative-dep-gen.cpp26
-rw-r--r--test/Modules/require-modular-includes.m1
-rw-r--r--test/Modules/resolution-change.m8
-rw-r--r--test/Modules/stddef.c13
-rw-r--r--test/Modules/system_headers.m7
-rw-r--r--test/Modules/system_version.m1
-rw-r--r--test/Modules/templates-2.mm36
-rw-r--r--test/Modules/templates.mm23
-rw-r--r--test/Modules/textual-headers.cpp18
-rw-r--r--test/Modules/va_list.m27
-rw-r--r--test/Modules/validate-system-headers.m14
-rw-r--r--test/Modules/warn-unused-local-typedef.cpp9
-rw-r--r--test/OpenMP/atomic_ast_print.cpp176
-rw-r--r--test/OpenMP/atomic_messages.c102
-rw-r--r--test/OpenMP/atomic_messages.cpp297
-rw-r--r--test/OpenMP/barrier_codegen.cpp41
-rw-r--r--test/OpenMP/critical_codegen.cpp38
-rw-r--r--test/OpenMP/flush_codegen.cpp34
-rw-r--r--test/OpenMP/for_codegen.cpp91
-rw-r--r--test/OpenMP/for_firstprivate_messages.cpp33
-rw-r--r--test/OpenMP/for_loop_messages.cpp39
-rw-r--r--test/OpenMP/for_misc_messages.c18
-rw-r--r--test/OpenMP/for_private_messages.cpp14
-rw-r--r--test/OpenMP/for_simd_aligned_messages.cpp202
-rw-r--r--test/OpenMP/for_simd_ast_print.cpp128
-rw-r--r--test/OpenMP/for_simd_collapse_messages.cpp83
-rw-r--r--test/OpenMP/for_simd_firstprivate_messages.cpp293
-rw-r--r--test/OpenMP/for_simd_lastprivate_messages.cpp266
-rw-r--r--test/OpenMP/for_simd_linear_messages.cpp206
-rw-r--r--test/OpenMP/for_simd_loop_messages.cpp734
-rw-r--r--test/OpenMP/for_simd_misc_messages.c659
-rw-r--r--test/OpenMP/for_simd_private_messages.cpp173
-rw-r--r--test/OpenMP/for_simd_reduction_messages.cpp350
-rw-r--r--test/OpenMP/for_simd_safelen_messages.cpp79
-rw-r--r--test/OpenMP/for_simd_schedule_messages.cpp91
-rw-r--r--test/OpenMP/master_codegen.cpp46
-rw-r--r--test/OpenMP/nesting_of_regions.cpp2237
-rw-r--r--test/OpenMP/ordered_ast_print.cpp59
-rw-r--r--test/OpenMP/ordered_messages.cpp54
-rw-r--r--test/OpenMP/parallel_codegen.cpp16
-rw-r--r--test/OpenMP/parallel_firstprivate_codegen.cpp255
-rw-r--r--test/OpenMP/parallel_firstprivate_messages.cpp18
-rw-r--r--test/OpenMP/parallel_for_firstprivate_messages.cpp28
-rw-r--r--test/OpenMP/parallel_for_loop_messages.cpp36
-rw-r--r--test/OpenMP/parallel_for_misc_messages.c11
-rw-r--r--test/OpenMP/parallel_for_private_messages.cpp14
-rw-r--r--test/OpenMP/parallel_for_simd_aligned_messages.cpp202
-rw-r--r--test/OpenMP/parallel_for_simd_ast_print.cpp128
-rw-r--r--test/OpenMP/parallel_for_simd_collapse_messages.cpp83
-rw-r--r--test/OpenMP/parallel_for_simd_copyin_messages.cpp93
-rw-r--r--test/OpenMP/parallel_for_simd_default_messages.cpp36
-rw-r--r--test/OpenMP/parallel_for_simd_firstprivate_messages.cpp250
-rw-r--r--test/OpenMP/parallel_for_simd_if_messages.cpp69
-rw-r--r--test/OpenMP/parallel_for_simd_lastprivate_messages.cpp226
-rw-r--r--test/OpenMP/parallel_for_simd_linear_messages.cpp206
-rw-r--r--test/OpenMP/parallel_for_simd_loop_messages.cpp644
-rw-r--r--test/OpenMP/parallel_for_simd_messages.cpp87
-rw-r--r--test/OpenMP/parallel_for_simd_misc_messages.c657
-rw-r--r--test/OpenMP/parallel_for_simd_num_threads_messages.cpp65
-rw-r--r--test/OpenMP/parallel_for_simd_private_messages.cpp173
-rw-r--r--test/OpenMP/parallel_for_simd_proc_bind_messages.cpp35
-rw-r--r--test/OpenMP/parallel_for_simd_reduction_messages.cpp295
-rw-r--r--test/OpenMP/parallel_for_simd_safelen_messages.cpp79
-rw-r--r--test/OpenMP/parallel_for_simd_schedule_messages.cpp91
-rw-r--r--test/OpenMP/parallel_if_codegen.cpp124
-rw-r--r--test/OpenMP/parallel_num_threads_codegen.cpp84
-rw-r--r--test/OpenMP/parallel_private_codegen.cpp181
-rw-r--r--test/OpenMP/parallel_private_messages.cpp14
-rw-r--r--test/OpenMP/parallel_sections_firstprivate_messages.cpp28
-rw-r--r--test/OpenMP/parallel_sections_private_messages.cpp14
-rw-r--r--test/OpenMP/sections_firstprivate_messages.cpp28
-rw-r--r--test/OpenMP/sections_private_messages.cpp14
-rw-r--r--test/OpenMP/simd_aligned_messages.cpp3
-rw-r--r--test/OpenMP/simd_codegen.cpp407
-rw-r--r--test/OpenMP/simd_loop_messages.cpp34
-rw-r--r--test/OpenMP/simd_metadata.c29
-rw-r--r--test/OpenMP/simd_misc_messages.c1039
-rw-r--r--test/OpenMP/simd_private_messages.cpp14
-rw-r--r--test/OpenMP/single_copyprivate_messages.cpp20
-rw-r--r--test/OpenMP/single_firstprivate_messages.cpp28
-rw-r--r--test/OpenMP/single_private_messages.cpp14
-rw-r--r--test/OpenMP/target_ast_print.cpp57
-rw-r--r--test/OpenMP/target_if_messages.cpp46
-rw-r--r--test/OpenMP/target_messages.cpp64
-rw-r--r--test/OpenMP/task_firstprivate_messages.cpp18
-rw-r--r--test/OpenMP/task_messages.cpp48
-rw-r--r--test/OpenMP/task_private_messages.cpp14
-rw-r--r--test/OpenMP/teams_ast_print.cpp112
-rw-r--r--test/OpenMP/teams_default_messages.cpp34
-rw-r--r--test/OpenMP/teams_firstprivate_messages.cpp124
-rw-r--r--test/OpenMP/teams_messages.cpp82
-rw-r--r--test/OpenMP/teams_private_messages.cpp119
-rw-r--r--test/OpenMP/teams_reduction_messages.cpp307
-rw-r--r--test/OpenMP/teams_shared_messages.cpp125
-rw-r--r--test/OpenMP/threadprivate_codegen.cpp707
-rw-r--r--test/OpenMP/threadprivate_messages.cpp3
-rw-r--r--test/PCH/chain-openmp-threadprivate.cpp26
-rw-r--r--test/PCH/cxx-namespaces.cpp4
-rw-r--r--test/PCH/cxx-traits.cpp65
-rw-r--r--test/PCH/cxx-traits.h53
-rw-r--r--test/PCH/cxx1y-lambdas.mm2
-rw-r--r--test/PCH/pragma-loop.cpp28
-rw-r--r--test/PCH/pragma-optimize.c6
-rw-r--r--test/PCH/stmt-attrs.cpp48
-rw-r--r--test/PCH/verify_pch.m14
-rw-r--r--test/Parser/MicrosoftExtensions.c8
-rw-r--r--test/Parser/MicrosoftExtensions.cpp20
-rw-r--r--test/Parser/PR21872.cpp4
-rw-r--r--test/Parser/access-spec-attrs.cpp1
-rw-r--r--test/Parser/altivec.c31
-rw-r--r--test/Parser/asm.cpp1
-rw-r--r--test/Parser/atomic.c3
-rw-r--r--test/Parser/attributes.c10
-rw-r--r--test/Parser/c11-noreturn.c4
-rw-r--r--test/Parser/c1x-alignas.c2
-rw-r--r--test/Parser/colon-colon-parentheses.cpp10
-rw-r--r--test/Parser/cxx-altivec.cpp17
-rw-r--r--test/Parser/cxx-ambig-init-templ.cpp6
-rw-r--r--test/Parser/cxx-attributes.cpp2
-rw-r--r--test/Parser/cxx-class.cpp48
-rw-r--r--test/Parser/cxx-default-args.cpp10
-rw-r--r--test/Parser/cxx-member-initializers.cpp30
-rw-r--r--test/Parser/cxx-template-argument.cpp5
-rw-r--r--test/Parser/cxx-template-decl.cpp28
-rw-r--r--test/Parser/cxx-variadic-func.cpp7
-rw-r--r--test/Parser/cxx0x-attributes.cpp16
-rw-r--r--test/Parser/cxx0x-decl.cpp10
-rw-r--r--test/Parser/cxx0x-in-cxx98.cpp4
-rw-r--r--test/Parser/cxx0x-lambda-expressions.cpp17
-rw-r--r--test/Parser/cxx11-templates.cpp46
-rw-r--r--test/Parser/cxx1z-attributes.cpp14
-rw-r--r--test/Parser/cxx1z-fold-expressions.cpp29
-rw-r--r--test/Parser/cxx1z-nested-namespace-definition.cpp38
-rw-r--r--test/Parser/debugger-import-module.m6
-rw-r--r--test/Parser/declarators.c4
-rw-r--r--test/Parser/eof2.cpp15
-rw-r--r--test/Parser/ms-if-exists.c87
-rw-r--r--test/Parser/ms-inline-asm.c5
-rw-r--r--test/Parser/namespaces.cpp6
-rw-r--r--test/Parser/nested-namespaces-recovery.cpp24
-rw-r--r--test/Parser/opencl-cl20.cl26
-rw-r--r--test/Parser/pragma-loop.cpp147
-rw-r--r--test/Parser/pragma-unroll.cpp72
-rw-r--r--test/Parser/switch-recovery.cpp9
-rw-r--r--test/Parser/vsx.c10
-rw-r--r--test/Preprocessor/_Pragma.c2
-rw-r--r--test/Preprocessor/aarch64-target-features.c6
-rw-r--r--test/Preprocessor/arm-acle-6.4.c6
-rw-r--r--test/Preprocessor/arm-acle-6.5.c22
-rw-r--r--test/Preprocessor/arm-target-features.c64
-rw-r--r--test/Preprocessor/cxx_oper_keyword_ms_compat.cpp2
-rw-r--r--test/Preprocessor/feature_tests.c9
-rw-r--r--test/Preprocessor/has_attribute.c5
-rw-r--r--test/Preprocessor/has_attribute.cpp68
-rw-r--r--test/Preprocessor/headermap-rel2.c4
-rw-r--r--test/Preprocessor/init.c227
-rw-r--r--test/Preprocessor/iwithprefix.c2
-rw-r--r--test/Preprocessor/line-directive.c2
-rw-r--r--test/Preprocessor/macro-reserved-cxx11.cpp7
-rw-r--r--test/Preprocessor/macro-reserved-ms.c7
-rw-r--r--test/Preprocessor/macro-reserved.c64
-rw-r--r--test/Preprocessor/macro-reserved.cpp63
-rw-r--r--test/Preprocessor/macro_arg_directive.c5
-rw-r--r--test/Preprocessor/macro_paste_bad.c8
-rw-r--r--test/Preprocessor/predefined-arch-macros.c153
-rw-r--r--test/Preprocessor/predefined-exceptions.m2
-rw-r--r--test/Preprocessor/predefined-macros.c102
-rw-r--r--test/Preprocessor/stdint.c107
-rw-r--r--test/Preprocessor/x86_target_features.c53
-rw-r--r--test/Profile/Inputs/c-general.profdata.v1bin0 -> 2000 bytes
-rw-r--r--test/Profile/c-captured.c14
-rw-r--r--test/Profile/c-counter-overflows.c6
-rw-r--r--test/Profile/c-general.c147
-rw-r--r--test/Profile/c-linkage-available_externally.c3
-rw-r--r--test/Profile/c-linkage.c17
-rw-r--r--test/Profile/c-unreachable-after-switch.c15
-rw-r--r--test/Profile/cxx-class.cpp8
-rw-r--r--test/Profile/cxx-lambda.cpp12
-rw-r--r--test/Profile/cxx-linkage.cpp13
-rw-r--r--test/Profile/cxx-templates.cpp4
-rw-r--r--test/Profile/cxx-throws.cpp12
-rw-r--r--test/Profile/objc-general.m10
-rw-r--r--test/Rewriter/rewrite-block-literal.mm2
-rw-r--r--test/Rewriter/rewrite-modern-block.mm3
-rw-r--r--test/Rewriter/rewrite-modern-captured-nested-bvar.mm2
-rw-r--r--test/Sema/128bitfloat.cpp (renamed from test/Sema/128bitfloat.cc)0
-rw-r--r--test/Sema/128bitint.c4
-rw-r--r--test/Sema/MicrosoftExtensions.c25
-rw-r--r--test/Sema/align_value.c32
-rw-r--r--test/Sema/anonymous-struct-union-c11.c4
-rw-r--r--test/Sema/anonymous-struct-union.c12
-rw-r--r--test/Sema/arm-darwin-aapcs.cpp1
-rw-r--r--test/Sema/arm64-inline-asm.c2
-rw-r--r--test/Sema/arm64-neon-args.c2
-rw-r--r--test/Sema/arm_acle.c16
-rw-r--r--test/Sema/array-init.c4
-rw-r--r--test/Sema/asm.c41
-rw-r--r--test/Sema/ast-print.c6
-rw-r--r--test/Sema/atomic-ops.c73
-rw-r--r--test/Sema/attr-bounded.c30
-rw-r--r--test/Sema/attr-deprecated.c4
-rw-r--r--test/Sema/attr-flag-enum.c73
-rw-r--r--test/Sema/attr-msp430.c12
-rw-r--r--test/Sema/attr-naked.c40
-rw-r--r--test/Sema/attr-nonnull.c7
-rw-r--r--test/Sema/attr-ownership.c5
-rw-r--r--test/Sema/big-endian-neon-initializers.c2
-rw-r--r--test/Sema/bitfield.c22
-rw-r--r--test/Sema/block-misc.c2
-rw-r--r--test/Sema/builtin-assume-aligned.c60
-rw-r--r--test/Sema/builtin-assume.c9
-rw-r--r--test/Sema/builtin-object-size.c28
-rw-r--r--test/Sema/builtins-arm.c10
-rw-r--r--test/Sema/builtins-arm64.c7
-rw-r--r--test/Sema/builtins-x86.c20
-rw-r--r--test/Sema/builtins.c56
-rw-r--r--test/Sema/call-with-static-chain.c11
-rw-r--r--test/Sema/callingconv.c2
-rw-r--r--test/Sema/constructor-attribute.c1
-rw-r--r--test/Sema/decl-microsoft-call-conv.c35
-rw-r--r--test/Sema/dllexport.c3
-rw-r--r--test/Sema/dllimport.c34
-rw-r--r--test/Sema/expr-comma-c99.c3
-rw-r--r--test/Sema/expr-comma.c3
-rw-r--r--test/Sema/exprs.c6
-rw-r--r--test/Sema/format-strings-gnu.c8
-rw-r--r--test/Sema/format-strings-ms.c89
-rw-r--r--test/Sema/format-strings.c2
-rw-r--r--test/Sema/gnu-attributes.c18
-rw-r--r--test/Sema/inline-asm-validate-aarch64.c38
-rw-r--r--test/Sema/inline-asm-validate-x86.c105
-rw-r--r--test/Sema/inline-asm-validate.c3
-rw-r--r--test/Sema/ms-inline-asm.c85
-rw-r--r--test/Sema/ms_bitfield_layout.c530
-rw-r--r--test/Sema/nonnull.c107
-rw-r--r--test/Sema/parentheses.cpp106
-rw-r--r--test/Sema/scope-check.c36
-rw-r--r--test/Sema/sentinel-attribute.c13
-rw-r--r--test/Sema/sizeof-struct-non-zero-as-member.cl18
-rw-r--r--test/Sema/statements.c2
-rw-r--r--test/Sema/static-array.c4
-rw-r--r--test/Sema/stdcall-fastcall.c2
-rw-r--r--test/Sema/string-plus-char.c15
-rw-r--r--test/Sema/struct-packed-align.c10
-rw-r--r--test/Sema/switch-1.c5
-rw-r--r--test/Sema/switch.c12
-rw-r--r--test/Sema/types.c18
-rw-r--r--test/Sema/typo-correction.c25
-rw-r--r--test/Sema/var-redecl.c12
-rw-r--r--test/Sema/warn-cast-qual.c29
-rw-r--r--test/Sema/warn-string-conversion.c17
-rw-r--r--test/Sema/warn-tautological-compare.c86
-rw-r--r--test/Sema/warn-thread-safety-analysis.c6
-rw-r--r--test/Sema/warn-unsequenced.c12
-rw-r--r--test/Sema/warn-unused-value.c25
-rw-r--r--test/Sema/wchar.c4
-rw-r--r--test/SemaCUDA/amdgpu-num-gpr-attr.cu14
-rw-r--r--test/SemaCUDA/function-target.cu35
-rw-r--r--test/SemaCUDA/implicit-copy.cu51
-rw-r--r--test/SemaCUDA/implicit-intrinsic.cu10
-rw-r--r--test/SemaCUDA/implicit-member-target-collision-cxx11.cu111
-rw-r--r--test/SemaCUDA/implicit-member-target-collision.cu57
-rw-r--r--test/SemaCUDA/implicit-member-target.cu186
-rw-r--r--test/SemaCUDA/launch_bounds.cu5
-rw-r--r--test/SemaCUDA/method-target.cu71
-rw-r--r--test/SemaCXX/Inputs/header-with-pragma-optimize-off.h5
-rw-r--r--test/SemaCXX/Inputs/override-system-header.h6
-rw-r--r--test/SemaCXX/MicrosoftCompatibility.cpp10
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp8
-rw-r--r--test/SemaCXX/MicrosoftSuper.cpp149
-rw-r--r--test/SemaCXX/PR10177.cpp31
-rw-r--r--test/SemaCXX/PR20705.cpp21
-rw-r--r--test/SemaCXX/align_value.cpp26
-rw-r--r--test/SemaCXX/anonymous-union.cpp6
-rw-r--r--test/SemaCXX/arrow-operator.cpp5
-rw-r--r--test/SemaCXX/ast-print.cpp5
-rw-r--r--test/SemaCXX/atomic-type.cpp4
-rw-r--r--test/SemaCXX/attr-cxx0x-fixit.cpp5
-rw-r--r--test/SemaCXX/attr-flag-enum-reject.cpp4
-rw-r--r--test/SemaCXX/attr-gnu.cpp29
-rw-r--r--test/SemaCXX/attr-nodebug.cpp4
-rw-r--r--test/SemaCXX/attr-nonnull.cpp4
-rw-r--r--test/SemaCXX/attr-optnone.cpp38
-rw-r--r--test/SemaCXX/attr-print.cpp9
-rw-r--r--test/SemaCXX/attributed-auto-deduction.cpp20
-rw-r--r--test/SemaCXX/bitfield.cpp32
-rw-r--r--test/SemaCXX/blocks.cpp45
-rw-r--r--test/SemaCXX/builtin-assume-aligned-tmpl.cpp87
-rw-r--r--test/SemaCXX/builtin-assume-aligned.cpp49
-rw-r--r--test/SemaCXX/call-with-static-chain.cpp15
-rw-r--r--test/SemaCXX/complex-folding.cpp90
-rw-r--r--test/SemaCXX/const-cast.cpp3
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp126
-rw-r--r--test/SemaCXX/constant-expression-cxx1y.cpp31
-rw-r--r--test/SemaCXX/constexpr-value-init.cpp6
-rw-r--r--test/SemaCXX/conversion-function.cpp12
-rw-r--r--test/SemaCXX/conversion.cpp20
-rw-r--r--test/SemaCXX/crashes.cpp6
-rw-r--r--test/SemaCXX/cxx-deprecated.cpp26
-rw-r--r--test/SemaCXX/cxx0x-compat.cpp8
-rw-r--r--test/SemaCXX/cxx0x-cursory-default-delete.cpp2
-rw-r--r--test/SemaCXX/cxx0x-initializer-references.cpp6
-rw-r--r--test/SemaCXX/cxx11-ast-print.cpp2
-rw-r--r--test/SemaCXX/cxx11-thread-unsupported.cpp5
-rw-r--r--test/SemaCXX/cxx1y-constexpr-not-const.cpp2
-rw-r--r--test/SemaCXX/cxx1y-deduced-return-type.cpp13
-rw-r--r--test/SemaCXX/cxx1y-generic-lambdas.cpp32
-rw-r--r--test/SemaCXX/cxx1y-variable-templates_in_class.cpp10
-rw-r--r--test/SemaCXX/cxx98-compat-flags.cpp4
-rw-r--r--test/SemaCXX/cxx98-compat-pedantic.cpp31
-rw-r--r--test/SemaCXX/cxx98-compat.cpp65
-rw-r--r--test/SemaCXX/decl-init-ref.cpp2
-rw-r--r--test/SemaCXX/decl-microsoft-call-conv.cpp13
-rw-r--r--test/SemaCXX/default1.cpp6
-rw-r--r--test/SemaCXX/default2.cpp6
-rw-r--r--test/SemaCXX/dependent-noexcept-unevaluated.cpp3
-rw-r--r--test/SemaCXX/deprecated.cpp8
-rw-r--r--test/SemaCXX/devirtualize-vtable-marking.cpp47
-rw-r--r--test/SemaCXX/dllexport.cpp58
-rw-r--r--test/SemaCXX/dllimport.cpp344
-rw-r--r--test/SemaCXX/enable_if.cpp41
-rw-r--r--test/SemaCXX/enum-scoped.cpp8
-rw-r--r--test/SemaCXX/exceptions.cpp24
-rw-r--r--test/SemaCXX/explicit.cpp2
-rw-r--r--test/SemaCXX/flexible-array-test.cpp6
-rw-r--r--test/SemaCXX/for-range-examples.cpp20
-rw-r--r--test/SemaCXX/friend.cpp55
-rw-r--r--test/SemaCXX/goto.cpp4
-rw-r--r--test/SemaCXX/implicit-exception-spec.cpp35
-rw-r--r--test/SemaCXX/issue547.cpp12
-rw-r--r--test/SemaCXX/lambda-expressions.cpp80
-rw-r--r--test/SemaCXX/libstdcxx_explicit_init_list_hack.cpp (renamed from test/SemaCXX/cxx0x-initializer-stdinitializerlist-system-header.cpp)0
-rw-r--r--test/SemaCXX/libstdcxx_is_pod_hack.cpp15
-rw-r--r--test/SemaCXX/libstdcxx_pair_swap_hack.cpp74
-rw-r--r--test/SemaCXX/member-init.cpp84
-rw-r--r--test/SemaCXX/member-pointer-ms.cpp19
-rw-r--r--test/SemaCXX/namespace-alias.cpp6
-rw-r--r--test/SemaCXX/nonnull.cpp5
-rw-r--r--test/SemaCXX/nullptr.cpp2
-rw-r--r--test/SemaCXX/overloaded-operator.cpp12
-rw-r--r--test/SemaCXX/override-in-system-header.cpp19
-rw-r--r--test/SemaCXX/pragma-optimize.cpp53
-rw-r--r--test/SemaCXX/predefined-expr.cpp16
-rw-r--r--test/SemaCXX/return-noreturn.cpp100
-rw-r--r--test/SemaCXX/return.cpp8
-rw-r--r--test/SemaCXX/runtimediag-ppe.cpp2
-rw-r--r--test/SemaCXX/scope-check.cpp38
-rw-r--r--test/SemaCXX/statements.cpp19
-rw-r--r--test/SemaCXX/string-plus-int.cpp5
-rw-r--r--test/SemaCXX/struct-class-redecl.cpp6
-rw-r--r--test/SemaCXX/trailing-return-0x.cpp10
-rw-r--r--test/SemaCXX/type-traits.cpp8
-rw-r--r--test/SemaCXX/typeid.cpp6
-rw-r--r--test/SemaCXX/typo-correction-delayed.cpp159
-rw-r--r--test/SemaCXX/typo-correction-pt2.cpp302
-rw-r--r--test/SemaCXX/typo-correction.cpp385
-rw-r--r--test/SemaCXX/undefined-internal.cpp4
-rw-r--r--test/SemaCXX/uninitialized.cpp713
-rw-r--r--test/SemaCXX/unknown-type-name.cpp6
-rw-r--r--test/SemaCXX/using-decl-1.cpp8
-rw-r--r--test/SemaCXX/vararg-non-pod.cpp5
-rw-r--r--test/SemaCXX/vtable-instantiation.cpp (renamed from test/SemaCXX/vtable-instantiation.cc)4
-rw-r--r--test/SemaCXX/warn-bool-conversion.cpp27
-rw-r--r--test/SemaCXX/warn-consumed-parsing.cpp1
-rw-r--r--test/SemaCXX/warn-global-constructors.cpp6
-rw-r--r--test/SemaCXX/warn-overloaded-virtual.cpp22
-rw-r--r--test/SemaCXX/warn-self-move.cpp55
-rw-r--r--test/SemaCXX/warn-tautological-compare.cpp40
-rw-r--r--test/SemaCXX/warn-tautological-undefined-compare.cpp28
-rw-r--r--test/SemaCXX/warn-thread-safety-analysis.cpp484
-rw-r--r--test/SemaCXX/warn-thread-safety-negative.cpp104
-rw-r--r--test/SemaCXX/warn-thread-safety-verbose.cpp86
-rw-r--r--test/SemaCXX/warn-undefined-bool-conversion.cpp24
-rw-r--r--test/SemaCXX/warn-unused-comparison.cpp2
-rw-r--r--test/SemaCXX/warn-unused-filescoped.cpp4
-rw-r--r--test/SemaCXX/warn-unused-local-typedef-serialize.cpp11
-rw-r--r--test/SemaCXX/warn-unused-local-typedef-x86asm.cpp16
-rw-r--r--test/SemaCXX/warn-unused-local-typedef.cpp242
-rw-r--r--test/SemaCXX/warn-unused-private-field-delayed-template.cpp11
-rw-r--r--test/SemaCXX/warn-unused-result.cpp47
-rw-r--r--test/SemaCXX/warn-unused-value-cxx11.cpp44
-rw-r--r--test/SemaCXX/warn-unused-value.cpp34
-rw-r--r--test/SemaObjC/access-property-getter.m17
-rw-r--r--test/SemaObjC/arc-jump-block.m8
-rw-r--r--test/SemaObjC/arc-repeated-weak.mm14
-rw-r--r--test/SemaObjC/arc.m2
-rw-r--r--test/SemaObjC/attr-availability-1.m116
-rw-r--r--test/SemaObjC/attr-availability.m27
-rw-r--r--test/SemaObjC/attr-deprecated-pch.m23
-rw-r--r--test/SemaObjC/attr-deprecated.m71
-rw-r--r--test/SemaObjC/autoreleasepool.m2
-rw-r--r--test/SemaObjC/compare-qualified-class.m35
-rw-r--r--test/SemaObjC/conditional-expr.m10
-rw-r--r--test/SemaObjC/debugger-support.m2
-rw-r--r--test/SemaObjC/default-synthesize-1.m17
-rw-r--r--test/SemaObjC/default-synthesize-3.m20
-rw-r--r--test/SemaObjC/default-synthesize.m40
-rw-r--r--test/SemaObjC/encode-typeof-test.m19
-rw-r--r--test/SemaObjC/format-cstrings-warning.m79
-rw-r--r--test/SemaObjC/format-strings-objc.m2
-rw-r--r--test/SemaObjC/iboutlet.m6
-rw-r--r--test/SemaObjC/ivar-lookup.m4
-rw-r--r--test/SemaObjC/method-lookup-3.m26
-rw-r--r--test/SemaObjC/nonnull.m30
-rw-r--r--test/SemaObjC/objc-cf-audited-warning.m24
-rw-r--r--test/SemaObjC/objc-dictionary-literal.m15
-rw-r--r--test/SemaObjC/objcbridge-attribute-arc.m16
-rw-r--r--test/SemaObjC/property-user-setter.m9
-rw-r--r--test/SemaObjC/protocol-expr-1.m2
-rw-r--r--test/SemaObjC/protocol-expr-neg-1.m19
-rw-r--r--test/SemaObjC/protocols-suppress-conformance.m10
-rw-r--r--test/SemaObjC/resolve-method-in-global-pool.m63
-rw-r--r--test/SemaObjC/scope-check.m28
-rw-r--r--test/SemaObjC/super-property-notation.m6
-rw-r--r--test/SemaObjC/warn-category-method-deprecated.m17
-rw-r--r--test/SemaObjC/warn-explicit-call-initialize.m25
-rw-r--r--test/SemaObjC/warn-strict-selector-match.m6
-rw-r--r--test/SemaObjCXX/arc-ppe.mm2
-rw-r--r--test/SemaObjCXX/synchronized.mm20
-rw-r--r--test/SemaOpenCL/address-spaces-conversions-cl2.0.cl227
-rw-r--r--test/SemaOpenCL/address-spaces.cl5
-rw-r--r--test/SemaOpenCL/amdgpu-num-register-attrs.cl40
-rw-r--r--test/SemaOpenCL/extern.cl4
-rw-r--r--test/SemaTemplate/canonical-expr-type.cpp8
-rw-r--r--test/SemaTemplate/class-template-decl.cpp2
-rw-r--r--test/SemaTemplate/constructor-template.cpp50
-rw-r--r--test/SemaTemplate/crash.cpp11
-rw-r--r--test/SemaTemplate/cxx1z-fold-expressions.cpp77
-rw-r--r--test/SemaTemplate/deduction.cpp12
-rw-r--r--test/SemaTemplate/dependent-type-identity.cpp23
-rw-r--r--test/SemaTemplate/derived.cpp4
-rw-r--r--test/SemaTemplate/enum-bool.cpp11
-rw-r--r--test/SemaTemplate/explicit-instantiation.cpp39
-rw-r--r--test/SemaTemplate/function-template-specialization-noreturn.cpp12
-rw-r--r--test/SemaTemplate/instantiate-exception-spec-cxx11.cpp41
-rw-r--r--test/SemaTemplate/instantiate-exception-spec.cpp21
-rw-r--r--test/SemaTemplate/instantiate-expr-1.cpp2
-rw-r--r--test/SemaTemplate/instantiate-init.cpp10
-rw-r--r--test/SemaTemplate/instantiate-method.cpp25
-rw-r--r--test/SemaTemplate/instantiate-non-dependent-types.cpp40
-rw-r--r--test/SemaTemplate/instantiate-scope.cpp30
-rw-r--r--test/SemaTemplate/instantiate-typeof.cpp7
-rw-r--r--test/SemaTemplate/lookup-dependent-bases.cpp63
-rw-r--r--test/SemaTemplate/ms-lookup-template-base-classes.cpp34
-rw-r--r--test/SemaTemplate/pack-deduction.cpp28
-rw-r--r--test/SemaTemplate/temp_arg_enum_printing.cpp24
-rw-r--r--test/SemaTemplate/temp_arg_nontype_cxx1z.cpp150
-rw-r--r--test/SemaTemplate/virtual-member-functions.cpp26
-rw-r--r--test/Tooling/auto-detect-from-source-parent-of-cwd.cpp3
-rw-r--r--test/Tooling/auto-detect-from-source-parent.cpp6
-rw-r--r--test/Tooling/auto-detect-from-source.cpp6
-rw-r--r--test/Tooling/clang-check-autodetect-dir.cpp6
-rw-r--r--test/Tooling/clang-check-pwd.cpp3
-rw-r--r--test/Tooling/pch.cpp1
-rw-r--r--test/VFS/external-names.c4
-rw-r--r--test/VFS/umbrella-mismatch.m3
-rw-r--r--test/lit.cfg27
-rw-r--r--tools/arcmt-test/arcmt-test.cpp7
-rw-r--r--tools/c-arcmt-test/CMakeLists.txt12
-rw-r--r--tools/c-arcmt-test/Makefile1
-rw-r--r--tools/c-index-test/CMakeLists.txt10
-rw-r--r--tools/c-index-test/Makefile1
-rw-r--r--tools/c-index-test/c-index-test.c48
-rw-r--r--tools/clang-check/ClangCheck.cpp74
-rw-r--r--tools/clang-format-vs/CMakeLists.txt7
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormat.csproj5
-rw-r--r--tools/clang-format-vs/README.txt11
-rw-r--r--tools/clang-format-vs/source.extension.vsixmanifest.in5
-rw-r--r--tools/clang-format/CMakeLists.txt3
-rw-r--r--tools/clang-format/ClangFormat.cpp12
-rw-r--r--tools/clang-format/Makefile4
-rwxr-xr-xtools/clang-format/clang-format-diff.py8
-rw-r--r--tools/clang-format/clang-format.el209
-rw-r--r--tools/clang-format/clang-format.py7
-rwxr-xr-xtools/clang-format/git-clang-format2
-rw-r--r--tools/diagtool/DiagTool.cpp2
-rw-r--r--tools/diagtool/DiagTool.h4
-rw-r--r--tools/diagtool/DiagnosticNames.h4
-rw-r--r--tools/diagtool/ListWarnings.cpp9
-rw-r--r--tools/diagtool/ShowEnabledWarnings.cpp2
-rw-r--r--tools/driver/cc1_main.cpp10
-rw-r--r--tools/driver/cc1as_main.cpp42
-rw-r--r--tools/driver/driver.cpp394
-rw-r--r--tools/libclang/ARCMigrate.cpp4
-rw-r--r--tools/libclang/CIndex.cpp203
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp4
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp29
-rw-r--r--tools/libclang/CIndexDiagnostic.h27
-rw-r--r--tools/libclang/CIndexUSRs.cpp2
-rw-r--r--tools/libclang/CIndexer.h4
-rw-r--r--tools/libclang/CLog.h4
-rw-r--r--tools/libclang/CMakeLists.txt2
-rw-r--r--tools/libclang/CXComment.cpp2
-rw-r--r--tools/libclang/CXComment.h6
-rw-r--r--tools/libclang/CXCompilationDatabase.cpp6
-rw-r--r--tools/libclang/CXCursor.cpp167
-rw-r--r--tools/libclang/CXCursor.h4
-rw-r--r--tools/libclang/CXLoadedDiagnostic.cpp591
-rw-r--r--tools/libclang/CXLoadedDiagnostic.h4
-rw-r--r--tools/libclang/CXSourceLocation.h4
-rw-r--r--tools/libclang/CXString.h4
-rw-r--r--tools/libclang/CXTranslationUnit.h4
-rw-r--r--tools/libclang/CXType.cpp1
-rw-r--r--tools/libclang/CXType.h4
-rw-r--r--tools/libclang/CursorVisitor.h4
-rw-r--r--tools/libclang/IndexBody.cpp2
-rw-r--r--tools/libclang/IndexTypeSourceInfo.cpp1
-rw-r--r--tools/libclang/Index_Internal.h4
-rw-r--r--tools/libclang/Indexing.cpp21
-rw-r--r--tools/libclang/IndexingContext.h5
-rw-r--r--tools/libclang/Makefile4
-rw-r--r--tools/libclang/libclang.exports8
-rw-r--r--tools/scan-build/c++-analyzer.bat1
-rwxr-xr-xtools/scan-build/ccc-analyzer24
-rw-r--r--tools/scan-build/ccc-analyzer.bat1
-rwxr-xr-xtools/scan-build/scan-build171
-rw-r--r--unittests/AST/ASTTypeTraitsTest.cpp39
-rw-r--r--unittests/AST/ASTVectorTest.cpp74
-rw-r--r--unittests/AST/CommentLexer.cpp4
-rw-r--r--unittests/AST/CommentParser.cpp4
-rw-r--r--unittests/AST/DeclPrinterTest.cpp35
-rw-r--r--unittests/AST/EvaluateAsRValueTest.cpp15
-rw-r--r--unittests/AST/ExternalASTSourceTest.cpp8
-rw-r--r--unittests/AST/MatchVerifier.h18
-rw-r--r--unittests/AST/NamedDeclPrinterTest.cpp4
-rw-r--r--unittests/AST/SourceLocationTest.cpp12
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp273
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h87
-rw-r--r--unittests/ASTMatchers/Dynamic/ParserTest.cpp75
-rw-r--r--unittests/ASTMatchers/Dynamic/RegistryTest.cpp60
-rw-r--r--unittests/Basic/CMakeLists.txt1
-rw-r--r--unittests/Basic/DiagnosticTest.cpp49
-rw-r--r--unittests/Basic/FileManagerTest.cpp37
-rw-r--r--unittests/Basic/SourceManagerTest.cpp30
-rw-r--r--unittests/Basic/VirtualFileSystemTest.cpp17
-rw-r--r--unittests/CMakeLists.txt1
-rw-r--r--unittests/CodeGen/BufferSourceTest.cpp78
-rw-r--r--unittests/CodeGen/CMakeLists.txt15
-rw-r--r--unittests/CodeGen/Makefile20
-rw-r--r--unittests/Format/CMakeLists.txt3
-rw-r--r--unittests/Format/FormatTest.cpp1116
-rw-r--r--unittests/Format/FormatTestJS.cpp202
-rw-r--r--unittests/Format/FormatTestJava.cpp492
-rw-r--r--unittests/Format/FormatTestProto.cpp53
-rw-r--r--unittests/Format/FormatTestUtils.h6
-rw-r--r--unittests/Format/Makefile4
-rw-r--r--unittests/Frontend/CMakeLists.txt2
-rw-r--r--unittests/Frontend/FrontendActionTest.cpp106
-rw-r--r--unittests/Lex/CMakeLists.txt1
-rw-r--r--unittests/Lex/LexerTest.cpp4
-rw-r--r--unittests/Lex/PPCallbacksTest.cpp18
-rw-r--r--unittests/Lex/PPConditionalDirectiveRecordTest.cpp6
-rw-r--r--unittests/Makefile5
-rw-r--r--unittests/Sema/ExternalSemaSourceTest.cpp6
-rw-r--r--unittests/Tooling/CMakeLists.txt5
-rw-r--r--unittests/Tooling/Makefile3
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTest.cpp525
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp121
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp141
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp224
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp93
-rw-r--r--unittests/Tooling/RefactoringTest.cpp23
-rw-r--r--unittests/Tooling/RewriterTestContext.h17
-rw-r--r--unittests/Tooling/TestVisitor.h12
-rw-r--r--unittests/Tooling/ToolingTest.cpp85
-rw-r--r--unittests/libclang/LibclangTest.cpp2
-rw-r--r--unittests/libclang/Makefile1
-rwxr-xr-xutils/ABITest/ABITestGen.py2
-rw-r--r--utils/ABITest/TypeGen.py6
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp248
-rw-r--r--utils/TableGen/NeonEmitter.cpp8
-rw-r--r--utils/TableGen/TableGenBackends.h5
-rw-r--r--utils/analyzer/SATestBuild.py2
-rw-r--r--www/analyzer/open_projects.html2
-rw-r--r--www/analyzer/potential_checkers.html44
-rw-r--r--www/analyzer/scan-build.html31
-rw-r--r--www/compatibility.html20
-rw-r--r--www/cxx_dr_status.html1962
-rw-r--r--www/cxx_status.html82
-rwxr-xr-xwww/make_cxx_dr_status4
2297 files changed, 104294 insertions, 33806 deletions
diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 000000000000..3186da43d43d
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1 @@
+Checks: '-*,clang-diagnostic-*,llvm-*,misc-*'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 02374e20f439..75b80757038d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -83,7 +83,13 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
# They are used as destination of target generators.
set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)
- set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib)
+ set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
+ if(WIN32 OR CYGWIN)
+ # DLL platform -- put DLLs into bin.
+ set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_RUNTIME_OUTPUT_INTDIR})
+ else()
+ set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
+ endif()
option(LLVM_INSTALL_TOOLCHAIN_ONLY
"Only include toolchain files in the 'install' target." OFF)
@@ -105,8 +111,8 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
link_directories("${LLVM_LIBRARY_DIR}")
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
- set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
- set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
+ set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX} )
+ set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX} )
if(LLVM_INCLUDE_TESTS)
# Check prebuilt llvm/utils.
@@ -193,6 +199,9 @@ endif()
set(CLANG_VENDOR_UTI "org.llvm.clang" CACHE STRING
"Vendor-specific uti.")
+# The libdir suffix must exactly match whatever LLVM's configuration used.
+set(CLANG_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}")
+
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
@@ -240,7 +249,7 @@ configure_file(
# Add appropriate flags for GCC
if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -fno-strict-aliasing")
# Enable -pedantic for Clang even if it's not enabled for LLVM.
if (NOT LLVM_ENABLE_PEDANTIC)
@@ -253,6 +262,26 @@ if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
endif()
endif ()
+# Determine HOST_LINK_VERSION on Darwin.
+set(HOST_LINK_VERSION)
+if (APPLE)
+ set(LD_V_OUTPUT)
+ execute_process(
+ COMMAND sh -c "${CMAKE_LINKER} -v 2>&1 | head -1"
+ RESULT_VARIABLE HAD_ERROR
+ OUTPUT_VARIABLE LD_V_OUTPUT
+ )
+ if (NOT HAD_ERROR)
+ if ("${LD_V_OUTPUT}" MATCHES ".*ld64-([0-9.]+).*")
+ string(REGEX REPLACE ".*ld64-([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT})
+ elseif ("${LD_V_OUTPUT}" MATCHES "[^0-9]*([0-9.]+).*")
+ string(REGEX REPLACE "[^0-9]*([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT})
+ endif()
+ else()
+ message(FATAL_ERROR "${CMAKE_LINKER} failed with status ${HAD_ERROR}")
+ endif()
+endif()
+
configure_file(
${CLANG_SOURCE_DIR}/include/clang/Config/config.h.cmake
${CLANG_BINARY_DIR}/include/clang/Config/config.h)
@@ -337,6 +366,7 @@ macro(add_clang_library name)
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
RUNTIME DESTINATION bin)
endif()
+ set_property(GLOBAL APPEND PROPERTY CLANG_EXPORTS ${name})
else()
# Add empty "phony" target
add_custom_target(${name})
@@ -478,3 +508,27 @@ endif()
set(CLANG_ORDER_FILE "" CACHE FILEPATH
"Order file to use when compiling clang in order to improve startup time.")
+
+if (CLANG_BUILT_STANDALONE)
+ # Generate a list of CMake library targets so that other CMake projects can
+ # link against them. LLVM calls its version of this file LLVMExports.cmake, but
+ # the usual CMake convention seems to be ${Project}Targets.cmake.
+ set(CLANG_INSTALL_PACKAGE_DIR share/clang/cmake)
+ set(clang_cmake_builddir "${CMAKE_BINARY_DIR}/${CLANG_INSTALL_PACKAGE_DIR}")
+ get_property(CLANG_EXPORTS GLOBAL PROPERTY CLANG_EXPORTS)
+ export(TARGETS ${CLANG_EXPORTS} FILE ${clang_cmake_builddir}/ClangTargets.cmake)
+
+ # Install a <prefix>/share/clang/cmake/ClangConfig.cmake file so that
+ # find_package(Clang) works. Install the target list with it.
+ install(FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/ClangConfig.cmake
+ ${CLANG_BINARY_DIR}/share/clang/cmake/ClangTargets.cmake
+ DESTINATION share/clang/cmake)
+
+ # Also copy ClangConfig.cmake to the build directory so that dependent projects
+ # can build against a build directory of Clang more easily.
+ configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/ClangConfig.cmake
+ ${CLANG_BINARY_DIR}/share/clang/cmake/ClangConfig.cmake
+ COPYONLY)
+endif ()
diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT
index bbd3142bc87c..b58014fee1aa 100644
--- a/CODE_OWNERS.TXT
+++ b/CODE_OWNERS.TXT
@@ -22,6 +22,7 @@ E: echristo@gmail.com
D: Debug Information, autotools/configure/make build, inline assembly
N: Doug Gregor
+E: dgregor@apple.com
D: All parts of Clang not covered by someone else
N: Anton Korobeynikov
@@ -29,6 +30,7 @@ E: anton@korobeynikov.info
D: Exception handling, Windows codegen, ARM EABI
N: Ted Kremenek
+E: kremenek@apple.com
D: Clang Static Analyzer
N: John McCall
@@ -37,7 +39,7 @@ D: Clang LLVM IR generation
N: Chad Rosier
E: mcrosier@codeaurora.org
-D: MS-inline asm, and the compiler driver
+D: Compiler driver
N: Richard Smith
E: richard@metafoo.co.uk
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 517b3c1bac6e..5792effea59b 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -496,24 +496,28 @@ class TokenKind(object):
setattr(TokenKind, name, kind)
### Cursor Kinds ###
-
-class CursorKind(object):
- """
- A CursorKind describes the kind of entity that a cursor points to.
+class BaseEnumeration(object):
"""
+ Common base class for named enumerations held in sync with Index.h values.
- # The unique kind objects, indexed by id.
+ Subclasses must define their own _kinds and _name_map members, as:
_kinds = []
_name_map = None
+ These values hold the per-subclass instances and value-to-name mappings,
+ respectively.
+
+ """
def __init__(self, value):
- if value >= len(CursorKind._kinds):
- CursorKind._kinds += [None] * (value - len(CursorKind._kinds) + 1)
- if CursorKind._kinds[value] is not None:
- raise ValueError,'CursorKind already loaded'
+ if value >= len(self.__class__._kinds):
+ self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1)
+ if self.__class__._kinds[value] is not None:
+ raise ValueError,'{0} value {1} already loaded'.format(
+ str(self.__class__), value)
self.value = value
- CursorKind._kinds[value] = self
- CursorKind._name_map = None
+ self.__class__._kinds[value] = self
+ self.__class__._name_map = None
+
def from_param(self):
return self.value
@@ -523,16 +527,29 @@ class CursorKind(object):
"""Get the enumeration name of this cursor kind."""
if self._name_map is None:
self._name_map = {}
- for key,value in CursorKind.__dict__.items():
- if isinstance(value,CursorKind):
+ for key, value in self.__class__.__dict__.items():
+ if isinstance(value, self.__class__):
self._name_map[value] = key
return self._name_map[self]
- @staticmethod
- def from_id(id):
- if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None:
- raise ValueError,'Unknown cursor kind %d' % id
- return CursorKind._kinds[id]
+ @classmethod
+ def from_id(cls, id):
+ if id >= len(cls._kinds) or cls._kinds[id] is None:
+ raise ValueError,'Unknown template argument kind %d' % id
+ return cls._kinds[id]
+
+ def __repr__(self):
+ return '%s.%s' % (self.__class__, self.name,)
+
+
+class CursorKind(BaseEnumeration):
+ """
+ A CursorKind describes the kind of entity that a cursor points to.
+ """
+
+ # The required BaseEnumeration declarations.
+ _kinds = []
+ _name_map = None
@staticmethod
def get_all_kinds():
@@ -578,11 +595,6 @@ class CursorKind(object):
def __repr__(self):
return 'CursorKind.%s' % (self.name,)
-# FIXME: Is there a nicer way to expose this enumeration? We could potentially
-# represent the nested structure, or even build a class hierarchy. The main
-# things we want for sure are (a) simple external access to kinds, (b) a place
-# to hang a description and name, (c) easy to keep in sync with Index.h.
-
###
# Declaration Kinds
@@ -1086,6 +1098,7 @@ CursorKind.CUDACONSTANT_ATTR = CursorKind(412)
CursorKind.CUDADEVICE_ATTR = CursorKind(413)
CursorKind.CUDAGLOBAL_ATTR = CursorKind(414)
CursorKind.CUDAHOST_ATTR = CursorKind(415)
+CursorKind.CUDASHARED_ATTR = CursorKind(416)
###
# Preprocessing
@@ -1100,6 +1113,24 @@ CursorKind.INCLUSION_DIRECTIVE = CursorKind(503)
# A module import declaration.
CursorKind.MODULE_IMPORT_DECL = CursorKind(600)
+
+### Template Argument Kinds ###
+class TemplateArgumentKind(BaseEnumeration):
+ """
+ A TemplateArgumentKind describes the kind of entity that a template argument
+ represents.
+ """
+
+ # The required BaseEnumeration declarations.
+ _kinds = []
+ _name_map = None
+
+TemplateArgumentKind.NULL = TemplateArgumentKind(0)
+TemplateArgumentKind.TYPE = TemplateArgumentKind(1)
+TemplateArgumentKind.DECLARATION = TemplateArgumentKind(2)
+TemplateArgumentKind.NULLPTR = TemplateArgumentKind(3)
+TemplateArgumentKind.INTEGRAL = TemplateArgumentKind(4)
+
### Cursors ###
class Cursor(Structure):
@@ -1176,9 +1207,9 @@ class Cursor(Structure):
"""
Return the display name for the entity referenced by this cursor.
- The display name contains extra information that helps identify the cursor,
- such as the parameters of a function or template or the arguments of a
- class template specialization.
+ The display name contains extra information that helps identify the
+ cursor, such as the parameters of a function or template or the
+ arguments of a class template specialization.
"""
if not hasattr(self, '_displayname'):
self._displayname = conf.lib.clang_getCursorDisplayName(self)
@@ -1186,6 +1217,14 @@ class Cursor(Structure):
return self._displayname
@property
+ def mangled_name(self):
+ """Return the mangled name for the entity referenced by this cursor."""
+ if not hasattr(self, '_mangled_name'):
+ self._mangled_name = conf.lib.clang_Cursor_getMangling(self)
+
+ return self._mangled_name
+
+ @property
def location(self):
"""
Return the source location (the starting character) of the entity
@@ -1208,6 +1247,17 @@ class Cursor(Structure):
return self._extent
@property
+ def storage_class(self):
+ """
+ Retrieves the storage class (if any) of the entity pointed at by the
+ cursor.
+ """
+ if not hasattr(self, '_storage_class'):
+ self._storage_class = conf.lib.clang_Cursor_getStorageClass(self)
+
+ return StorageClass.from_id(self._storage_class)
+
+ @property
def access_specifier(self):
"""
Retrieves the access specifier (if any) of the entity pointed at by the
@@ -1369,6 +1419,27 @@ class Cursor(Structure):
for i in range(0, num_args):
yield conf.lib.clang_Cursor_getArgument(self, i)
+ def get_num_template_arguments(self):
+ """Returns the number of template args associated with this cursor."""
+ return conf.lib.clang_Cursor_getNumTemplateArguments(self)
+
+ def get_template_argument_kind(self, num):
+ """Returns the TemplateArgumentKind for the indicated template
+ argument."""
+ return conf.lib.clang_Cursor_getTemplateArgumentKind(self, num)
+
+ def get_template_argument_type(self, num):
+ """Returns the CXType for the indicated template argument."""
+ return conf.lib.clang_Cursor_getTemplateArgumentType(self, num)
+
+ def get_template_argument_value(self, num):
+ """Returns the value of the indicated arg as a signed 64b integer."""
+ return conf.lib.clang_Cursor_getTemplateArgumentValue(self, num)
+
+ def get_template_argument_unsigned_value(self, num):
+ """Returns the value of the indicated arg as an unsigned 64b integer."""
+ return conf.lib.clang_Cursor_getTemplateArgumentUnsignedValue(self, num)
+
def get_children(self):
"""Return an iterator for accessing the children of this cursor."""
@@ -1450,11 +1521,9 @@ class Cursor(Structure):
res._tu = args[0]._tu
return res
-### C++ access specifiers ###
-
-class AccessSpecifier(object):
+class StorageClass(object):
"""
- Describes the access of a C++ class member
+ Describes the storage class of a declaration
"""
# The unique kind objects, index by id.
@@ -1462,32 +1531,59 @@ class AccessSpecifier(object):
_name_map = None
def __init__(self, value):
- if value >= len(AccessSpecifier._kinds):
- AccessSpecifier._kinds += [None] * (value - len(AccessSpecifier._kinds) + 1)
- if AccessSpecifier._kinds[value] is not None:
- raise ValueError,'AccessSpecifier already loaded'
+ if value >= len(StorageClass._kinds):
+ StorageClass._kinds += [None] * (value - len(StorageClass._kinds) + 1)
+ if StorageClass._kinds[value] is not None:
+ raise ValueError,'StorageClass already loaded'
self.value = value
- AccessSpecifier._kinds[value] = self
- AccessSpecifier._name_map = None
+ StorageClass._kinds[value] = self
+ StorageClass._name_map = None
def from_param(self):
return self.value
@property
def name(self):
- """Get the enumeration name of this access specifier."""
+ """Get the enumeration name of this storage class."""
if self._name_map is None:
self._name_map = {}
- for key,value in AccessSpecifier.__dict__.items():
- if isinstance(value,AccessSpecifier):
+ for key,value in StorageClass.__dict__.items():
+ if isinstance(value,StorageClass):
self._name_map[value] = key
return self._name_map[self]
@staticmethod
def from_id(id):
- if id >= len(AccessSpecifier._kinds) or not AccessSpecifier._kinds[id]:
- raise ValueError,'Unknown access specifier %d' % id
- return AccessSpecifier._kinds[id]
+ if id >= len(StorageClass._kinds) or not StorageClass._kinds[id]:
+ raise ValueError,'Unknown storage class %d' % id
+ return StorageClass._kinds[id]
+
+ def __repr__(self):
+ return 'StorageClass.%s' % (self.name,)
+
+StorageClass.INVALID = StorageClass(0)
+StorageClass.NONE = StorageClass(1)
+StorageClass.EXTERN = StorageClass(2)
+StorageClass.STATIC = StorageClass(3)
+StorageClass.PRIVATEEXTERN = StorageClass(4)
+StorageClass.OPENCLWORKGROUPLOCAL = StorageClass(5)
+StorageClass.AUTO = StorageClass(6)
+StorageClass.REGISTER = StorageClass(7)
+
+
+### C++ access specifiers ###
+
+class AccessSpecifier(BaseEnumeration):
+ """
+ Describes the access of a C++ class member
+ """
+
+ # The unique kind objects, index by id.
+ _kinds = []
+ _name_map = None
+
+ def from_param(self):
+ return self.value
def __repr__(self):
return 'AccessSpecifier.%s' % (self.name,)
@@ -1500,7 +1596,7 @@ AccessSpecifier.NONE = AccessSpecifier(4)
### Type Kinds ###
-class TypeKind(object):
+class TypeKind(BaseEnumeration):
"""
Describes the kind of type.
"""
@@ -1509,39 +1605,11 @@ class TypeKind(object):
_kinds = []
_name_map = None
- def __init__(self, value):
- if value >= len(TypeKind._kinds):
- TypeKind._kinds += [None] * (value - len(TypeKind._kinds) + 1)
- if TypeKind._kinds[value] is not None:
- raise ValueError,'TypeKind already loaded'
- self.value = value
- TypeKind._kinds[value] = self
- TypeKind._name_map = None
-
- def from_param(self):
- return self.value
-
- @property
- def name(self):
- """Get the enumeration name of this cursor kind."""
- if self._name_map is None:
- self._name_map = {}
- for key,value in TypeKind.__dict__.items():
- if isinstance(value,TypeKind):
- self._name_map[value] = key
- return self._name_map[self]
-
@property
def spelling(self):
"""Retrieve the spelling of this TypeKind."""
return conf.lib.clang_getTypeKindSpelling(self.value)
- @staticmethod
- def from_id(id):
- if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None:
- raise ValueError,'Unknown type kind %d' % id
- return TypeKind._kinds[id]
-
def __repr__(self):
return 'TypeKind.%s' % (self.name,)
@@ -1594,43 +1662,16 @@ TypeKind.VARIABLEARRAY = TypeKind(115)
TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
TypeKind.MEMBERPOINTER = TypeKind(117)
-class RefQualifierKind(object):
+class RefQualifierKind(BaseEnumeration):
"""Describes a specific ref-qualifier of a type."""
# The unique kind objects, indexed by id.
_kinds = []
_name_map = None
- def __init__(self, value):
- if value >= len(RefQualifierKind._kinds):
- num_kinds = value - len(RefQualifierKind._kinds) + 1
- RefQualifierKind._kinds += [None] * num_kinds
- if RefQualifierKind._kinds[value] is not None:
- raise ValueError, 'RefQualifierKind already loaded'
- self.value = value
- RefQualifierKind._kinds[value] = self
- RefQualifierKind._name_map = None
-
def from_param(self):
return self.value
- @property
- def name(self):
- """Get the enumeration name of this kind."""
- if self._name_map is None:
- self._name_map = {}
- for key, value in RefQualifierKind.__dict__.items():
- if isinstance(value, RefQualifierKind):
- self._name_map[value] = key
- return self._name_map[self]
-
- @staticmethod
- def from_id(id):
- if (id >= len(RefQualifierKind._kinds) or
- RefQualifierKind._kinds[id] is None):
- raise ValueError, 'Unknown type kind %d' % id
- return RefQualifierKind._kinds[id]
-
def __repr__(self):
return 'RefQualifierKind.%s' % (self.name,)
@@ -2973,6 +3014,11 @@ functionList = [
_CXString,
_CXString.from_result),
+ ("clang_Cursor_getMangling",
+ [Cursor],
+ _CXString,
+ _CXString.from_result),
+
# ("clang_getCXTUResourceUsage",
# [TranslationUnit],
# CXTUResourceUsage),
@@ -3300,6 +3346,27 @@ functionList = [
Cursor,
Cursor.from_result),
+ ("clang_Cursor_getNumTemplateArguments",
+ [Cursor],
+ c_int),
+
+ ("clang_Cursor_getTemplateArgumentKind",
+ [Cursor, c_uint],
+ TemplateArgumentKind.from_id),
+
+ ("clang_Cursor_getTemplateArgumentType",
+ [Cursor, c_uint],
+ Type,
+ Type.from_result),
+
+ ("clang_Cursor_getTemplateArgumentValue",
+ [Cursor, c_uint],
+ c_longlong),
+
+ ("clang_Cursor_getTemplateArgumentUnsignedValue",
+ [Cursor, c_uint],
+ c_ulonglong),
+
("clang_Cursor_isBitField",
[Cursor],
bool),
diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py
index 431504502245..a5224aafabc1 100644
--- a/bindings/python/tests/cindex/test_cursor.py
+++ b/bindings/python/tests/cindex/test_cursor.py
@@ -1,6 +1,8 @@
+import ctypes
import gc
from clang.cindex import CursorKind
+from clang.cindex import TemplateArgumentKind
from clang.cindex import TranslationUnit
from clang.cindex import TypeKind
from .util import get_cursor
@@ -244,6 +246,48 @@ def test_get_arguments():
assert arguments[0].spelling == "i"
assert arguments[1].spelling == "j"
+kTemplateArgTest = """\
+ template <int kInt, typename T, bool kBool>
+ void foo();
+
+ template<>
+ void foo<-7, float, true>();
+ """
+
+def test_get_num_template_arguments():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_num_template_arguments() == 3
+
+def test_get_template_argument_kind():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_kind(0) == TemplateArgumentKind.INTEGRAL
+ assert foos[1].get_template_argument_kind(1) == TemplateArgumentKind.TYPE
+ assert foos[1].get_template_argument_kind(2) == TemplateArgumentKind.INTEGRAL
+
+def test_get_template_argument_type():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_type(1).kind == TypeKind.FLOAT
+
+def test_get_template_argument_value():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_value(0) == -7
+ assert foos[1].get_template_argument_value(2) == True
+
+def test_get_template_argument_unsigned_value():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_unsigned_value(0) == 2 ** 32 - 7
+ assert foos[1].get_template_argument_unsigned_value(2) == True
+
def test_referenced():
tu = get_tu('void foo(); void bar() { foo(); }')
foo = get_cursor(tu, 'foo')
@@ -252,3 +296,17 @@ def test_referenced():
if c.kind == CursorKind.CALL_EXPR:
assert c.referenced.spelling == foo.spelling
break
+
+def test_mangled_name():
+ kInputForMangling = """\
+ int foo(int, int);
+ """
+ tu = get_tu(kInputForMangling, lang='cpp')
+ foo = get_cursor(tu, 'foo')
+
+ # Since libclang does not link in targets, we cannot pass a triple to it
+ # and force the target. To enable this test to pass on all platforms, accept
+ # all valid manglings.
+ # [c-index-test handles this by running the source through clang, emitting
+ # an AST file and running libclang on that AST file]
+ assert foo.mangled_name in ('_Z3fooii', '__Z3fooii', '?foo@@YAHHH')
diff --git a/cmake/modules/ClangConfig.cmake b/cmake/modules/ClangConfig.cmake
new file mode 100644
index 000000000000..f052bb9e8c8e
--- /dev/null
+++ b/cmake/modules/ClangConfig.cmake
@@ -0,0 +1,8 @@
+# This file allows users to call find_package(Clang) and pick up our targets.
+
+# Clang doesn't have any CMake configuration settings yet because it mostly
+# uses LLVM's. When it does, we should move this file to ClangConfig.cmake.in
+# and call configure_file() on it.
+
+# Provide all our library targets to users.
+include("${CMAKE_CURRENT_LIST_DIR}/ClangTargets.cmake")
diff --git a/docs/AddressSanitizer.rst b/docs/AddressSanitizer.rst
index 93a6a0ebaa50..cbdd7c65e847 100644
--- a/docs/AddressSanitizer.rst
+++ b/docs/AddressSanitizer.rst
@@ -165,9 +165,9 @@ problems happening in certain source files or with certain global variables.
# Disable out-of-bound checks for global:
global:bad_array
# Disable out-of-bound checks for global instances of a given class ...
- type:class.Namespace::BadClassName
+ type:Namespace::BadClassName
# ... or a given struct. Use wildcard to deal with anonymous namespace.
- type:struct.Namespace2::*::BadStructName
+ type:Namespace2::*::BadStructName
# Disable initialization-order checks for globals:
global:bad_init_global=init
type:*BadInitClassSubstring*=init
@@ -187,6 +187,7 @@ AddressSanitizer is supported on
* Linux i386/x86\_64 (tested on Ubuntu 12.04);
* MacOS 10.6 - 10.9 (i386/x86\_64).
* Android ARM
+* FreeBSD i386/x86\_64 (tested on FreeBSD 11-current)
Ports to various other platforms are in progress.
diff --git a/docs/ClangFormat.rst b/docs/ClangFormat.rst
index 86c5ec5e5873..45ea32717995 100644
--- a/docs/ClangFormat.rst
+++ b/docs/ClangFormat.rst
@@ -96,8 +96,8 @@ This can be integrated by adding the following to your `.vimrc`:
.. code-block:: vim
- map <C-K> :pyf <path-to-this-file>/clang-format.py<CR>
- imap <C-K> <ESC>:pyf <path-to-this-file>/clang-format.py<CR>i
+ map <C-K> :pyf <path-to-this-file>/clang-format.py<cr>
+ imap <C-K> <c-o>:pyf <path-to-this-file>/clang-format.py<cr>
The first line enables :program:`clang-format` for NORMAL and VISUAL mode, the
second line adds support for INSERT mode. Change "C-K" to another binding if
diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst
index 07febaf3898b..ce6fae19c09b 100644
--- a/docs/ClangFormatStyleOptions.rst
+++ b/docs/ClangFormatStyleOptions.rst
@@ -33,6 +33,43 @@ The ``.clang-format`` file uses YAML format:
# A comment.
...
+The configuration file can consist of several sections each having different
+``Language:`` parameter denoting the programming language this section of the
+configuration is targeted at. See the description of the **Language** option
+below for the list of supported languages. The first section may have no
+language set, it will set the default style options for all lanugages.
+Configuration sections for specific language will override options set in the
+default section.
+
+When :program:`clang-format` formats a file, it auto-detects the language using
+the file name. When formatting standard input or a file that doesn't have the
+extension corresponding to its language, ``-assume-filename=`` option can be
+used to override the file name :program:`clang-format` uses to detect the
+language.
+
+An example of a configuration file for multiple languages:
+
+.. code-block:: yaml
+
+ ---
+ # We'll use defaults from the LLVM style, but with 4 columns indentation.
+ BasedOnStyle: LLVM
+ IndentWidth: 4
+ ---
+ Language: Cpp
+ # Force pointers to the type for C++.
+ DerivePointerAlignment: false
+ PointerAlignment: Left
+ ---
+ Language: JavaScript
+ # Use 100 columns for JS.
+ ColumnLimit: 100
+ ---
+ Language: Proto
+ # Don't format .proto files.
+ DisableFormat: true
+ ...
+
An easy way to get a valid ``.clang-format`` file containing all configuration
options of a certain predefined style is:
@@ -48,6 +85,24 @@ is applied for all input files. The format of the configuration is:
-style='{key1: value1, key2: value2, ...}'
+Disabling Formatting on a Piece of Code
+=======================================
+
+Clang-format understands also special comments that switch formatting in a
+delimited range. The code between a comment ``// clang-format off`` or
+``/* clang-format off */`` up to a comment ``// clang-format on`` or
+``/* clang-format on */`` will not be formatted. The comments themselves
+will be formatted (aligned) normally.
+
+.. code-block:: c++
+
+ int formatted_code;
+ // clang-format off
+ void unformatted_code ;
+ // clang-format on
+ void formatted_code_again;
+
+
Configuring Style in Code
=========================
@@ -95,10 +150,24 @@ the configuration (without a prefix: ``Auto``).
**AccessModifierOffset** (``int``)
The extra indent or outdent of access modifiers, e.g. ``public:``.
+**AlignAfterOpenBracket** (``bool``)
+ If ``true``, horizontally aligns arguments after an open bracket.
+
+ This applies to round brackets (parentheses), angle brackets and square
+ brackets. This will result in formattings like
+ \code
+ someLongFunction(argument1,
+ argument2);
+ \endcode
+
**AlignEscapedNewlinesLeft** (``bool``)
If ``true``, aligns escaped newlines as far left as possible.
Otherwise puts them into the right-most column.
+**AlignOperands** (``bool``)
+ If ``true``, horizontally align operands of binary and ternary
+ expressions.
+
**AlignTrailingComments** (``bool``)
If ``true``, aligns trailing comments.
@@ -111,6 +180,9 @@ the configuration (without a prefix: ``Auto``).
E.g., this allows ``if (a) { return; }`` to be put on a single line.
+**AllowShortCaseLabelsOnASingleLine** (``bool``)
+ If ``true``, short case labels will be contracted to a single line.
+
**AllowShortFunctionsOnASingleLine** (``ShortFunctionStyle``)
Dependent on the value, ``int f() { return 0; }`` can be put
on a single line.
@@ -121,6 +193,8 @@ the configuration (without a prefix: ``Auto``).
Never merge functions into a single line.
* ``SFS_Inline`` (in configuration: ``Inline``)
Only merge functions defined inside a class.
+ * ``SFS_Empty`` (in configuration: ``Empty``)
+ Only merge empty functions.
* ``SFS_All`` (in configuration: ``All``)
Merge all functions fitting on a single line.
@@ -133,6 +207,13 @@ the configuration (without a prefix: ``Auto``).
If ``true``, ``while (true) continue;`` can be put on a
single line.
+**AlwaysBreakAfterDefinitionReturnType** (``bool``)
+ If ``true``, always break after function definition return types.
+
+ More truthfully called 'break before the identifier following the type
+ in a function definition'. PenaltyReturnTypeOnItsOwnLine becomes
+ irrelevant.
+
**AlwaysBreakBeforeMultilineStrings** (``bool``)
If ``true``, always break before multiline string literals.
@@ -140,12 +221,26 @@ the configuration (without a prefix: ``Auto``).
If ``true``, always break after the ``template<...>`` of a
template declaration.
+**BinPackArguments** (``bool``)
+ If ``false``, a function call's arguments will either be all on the
+ same line or will have one line each.
+
**BinPackParameters** (``bool``)
- If ``false``, a function call's or function definition's parameters
- will either all be on the same line or will have one line each.
+ If ``false``, a function declaration's or function definition's
+ parameters will either all be on the same line or will have one line each.
+
+**BreakBeforeBinaryOperators** (``BinaryOperatorStyle``)
+ The way to wrap binary operators.
+
+ Possible values:
+
+ * ``BOS_None`` (in configuration: ``None``)
+ Break after operators.
+ * ``BOS_NonAssignment`` (in configuration: ``NonAssignment``)
+ Break before operators that aren't assignments.
+ * ``BOS_All`` (in configuration: ``All``)
+ Break before operators.
-**BreakBeforeBinaryOperators** (``bool``)
- If ``true``, binary operators will be placed after line breaks.
**BreakBeforeBraces** (``BraceBreakingStyle``)
The brace breaking style to use.
@@ -158,7 +253,7 @@ the configuration (without a prefix: ``Auto``).
Like ``Attach``, but break before braces on function, namespace and
class definitions.
* ``BS_Stroustrup`` (in configuration: ``Stroustrup``)
- Like ``Attach``, but break before function definitions.
+ Like ``Attach``, but break before function definitions, and 'else'.
* ``BS_Allman`` (in configuration: ``Allman``)
Always break before braces.
* ``BS_GNU`` (in configuration: ``GNU``)
@@ -267,6 +362,8 @@ the configuration (without a prefix: ``Auto``).
Do not use.
* ``LK_Cpp`` (in configuration: ``Cpp``)
Should be used for C, C++, ObjectiveC, ObjectiveC++.
+ * ``LK_Java`` (in configuration: ``Java``)
+ Should be used for Java.
* ``LK_JavaScript`` (in configuration: ``JavaScript``)
Should be used for JavaScript.
* ``LK_Proto`` (in configuration: ``Proto``)
@@ -290,6 +387,9 @@ the configuration (without a prefix: ``Auto``).
Indent in all namespaces.
+**ObjCBlockIndentWidth** (``unsigned``)
+ The number of characters to use for indentation of ObjC blocks.
+
**ObjCSpaceAfterProperty** (``bool``)
Add a space after ``@property`` in Objective-C, i.e. use
``\@property (readonly)`` instead of ``\@property(readonly)``.
@@ -330,6 +430,9 @@ the configuration (without a prefix: ``Auto``).
Align pointer in the middle.
+**SpaceAfterCStyleCast** (``bool``)
+ If ``true``, a space may be inserted after C style casts.
+
**SpaceBeforeAssignmentOperators** (``bool``)
If ``false``, spaces will be removed before assignment operators.
@@ -374,6 +477,9 @@ the configuration (without a prefix: ``Auto``).
**SpacesInParentheses** (``bool``)
If ``true``, spaces will be inserted after '(' and before ')'.
+**SpacesInSquareBrackets** (``bool``)
+ If ``true``, spaces will be inserted after '[' and before ']'.
+
**Standard** (``LanguageStandard``)
Format compatible with this standard, e.g. use
``A<A<int> >`` instead of ``A<A<int>>`` for LS_Cpp03.
diff --git a/docs/CrossCompilation.rst b/docs/CrossCompilation.rst
index 89f8777ac074..fd42856ec3ad 100644
--- a/docs/CrossCompilation.rst
+++ b/docs/CrossCompilation.rst
@@ -201,4 +201,3 @@ uses hard-float), Clang will pick the ``armv7l-linux-gnueabi-ld``
The same is true if you're compiling for different ABIs, like ``gnueabi``
and ``androideabi``, and might even link and run, but produce run-time
errors, which are much harder to track down and fix.
-
diff --git a/docs/InternalsManual.rst b/docs/InternalsManual.rst
index 8e047dbdae7a..502cae44b336 100644
--- a/docs/InternalsManual.rst
+++ b/docs/InternalsManual.rst
@@ -784,9 +784,24 @@ buffer uses this idiom and is subsequently ``#include``'d, the preprocessor can
simply check to see whether the guarding condition is defined or not. If so,
the preprocessor can completely ignore the include of the header.
+.. _Parser:
+
The Parser Library
==================
+This library contains a recursive-descent parser that polls tokens from the
+preprocessor and notifies a client of the parsing progress.
+
+Historically, the parser used to talk to an abstract ``Action`` interface that
+had virtual methods for parse events, for example ``ActOnBinOp()``. When Clang
+grew C++ support, the parser stopped supporting general ``Action`` clients --
+it now always talks to the :ref:`Sema libray <Sema>`. However, the Parser
+still accesses AST objects only through opaque types like ``ExprResult`` and
+``StmtResult``. Only :ref:`Sema <Sema>` looks at the AST node contents of these
+wrappers.
+
+.. _AST:
+
The AST Library
===============
@@ -1396,10 +1411,7 @@ body by single call to a static class method:
.. code-block:: c++
Stmt *FooBody = ...
- CFG *FooCFG = CFG::buildCFG(FooBody);
-
-It is the responsibility of the caller of ``CFG::buildCFG`` to ``delete`` the
-returned ``CFG*`` when the CFG is no longer needed.
+ std::unique_ptr<CFG> FooCFG = CFG::buildCFG(FooBody);
Along with providing an interface to iterate over its ``CFGBlocks``, the
``CFG`` class also provides methods that are useful for debugging and
@@ -1585,6 +1597,23 @@ interacts with constant evaluation:
* ``__builtin_strlen`` and ``strlen``: These are constant folded as integer
constant expressions if the argument is a string literal.
+.. _Sema:
+
+The Sema Library
+================
+
+This library is called by the :ref:`Parser library <Parser>` during parsing to
+do semantic analysis of the input. For valid programs, Sema builds an AST for
+parsed constructs.
+
+.. _CodeGen:
+
+The CodeGen Library
+===================
+
+CodeGen takes an :ref:`AST <AST>` as input and produces `LLVM IR code
+<//llvm.org/docs/LangRef.html>`_ from it.
+
How to change Clang
===================
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index 35f759f4cf97..035b50d10824 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -109,12 +109,42 @@ following ``__`` (double underscore) to avoid interference from a macro with
the same name. For instance, ``__cxx_rvalue_references__`` can be used instead
of ``cxx_rvalue_references``.
+``__has_cpp_attribute``
+-----------------------
+
+This function-like macro takes a single argument that is the name of a
+C++11-style attribute. The argument can either be a single identifier, or a
+scoped identifier. If the attribute is supported, a nonzero value is returned.
+If the attribute is a standards-based attribute, this macro returns a nonzero
+value based on the year and month in which the attribute was voted into the
+working draft. If the attribute is not supported by the current compliation
+target, this macro evaluates to 0. It can be used like this:
+
+.. code-block:: c++
+
+ #ifndef __has_cpp_attribute // Optional of course.
+ #define __has_cpp_attribute(x) 0 // Compatibility with non-clang compilers.
+ #endif
+
+ ...
+ #if __has_cpp_attribute(clang::fallthrough)
+ #define FALLTHROUGH [[clang::fallthrough]]
+ #else
+ #define FALLTHROUGH
+ #endif
+ ...
+
+The attribute identifier (but not scope) can also be specified with a preceding
+and following ``__`` (double underscore) to avoid interference from a macro with
+the same name. For instance, ``gnu::__const__`` can be used instead of
+``gnu::const``.
+
``__has_attribute``
-------------------
This function-like macro takes a single identifier argument that is the name of
-an attribute. It evaluates to 1 if the attribute is supported by the current
-compilation target, or 0 if not. It can be used like this:
+a GNU-style attribute. It evaluates to 1 if the attribute is supported by the
+current compilation target, or 0 if not. It can be used like this:
.. code-block:: c++
@@ -134,6 +164,33 @@ The attribute name can also be specified with a preceding and following ``__``
(double underscore) to avoid interference from a macro with the same name. For
instance, ``__always_inline__`` can be used instead of ``always_inline``.
+
+``__has_declspec_attribute``
+----------------------------
+
+This function-like macro takes a single identifier argument that is the name of
+an attribute implemented as a Microsoft-style ``__declspec`` attribute. It
+evaluates to 1 if the attribute is supported by the current compilation target,
+or 0 if not. It can be used like this:
+
+.. code-block:: c++
+
+ #ifndef __has_declspec_attribute // Optional of course.
+ #define __has_declspec_attribute(x) 0 // Compatibility with non-clang compilers.
+ #endif
+
+ ...
+ #if __has_declspec_attribute(dllexport)
+ #define DLLEXPORT __declspec(dllexport)
+ #else
+ #define DLLEXPORT
+ #endif
+ ...
+
+The attribute name can also be specified with a preceding and following ``__``
+(double underscore) to avoid interference from a macro with the same name. For
+instance, ``__dllexport__`` can be used instead of ``dllexport``.
+
``__is_identifier``
-------------------
@@ -357,23 +414,27 @@ The table below shows the support for each operation by vector extension. A
dash indicates that an operation is not accepted according to a corresponding
specification.
-============================== ====== ======= === ====
- Opeator OpenCL AltiVec GCC NEON
-============================== ====== ======= === ====
-[] yes yes yes --
-unary operators +, -- yes yes yes --
-++, -- -- yes yes yes --
-+,--,*,/,% yes yes yes --
-bitwise operators &,|,^,~ yes yes yes --
->>,<< yes yes yes --
-!, &&, || no -- -- --
-==, !=, >, <, >=, <= yes yes -- --
-= yes yes yes yes
-:? yes -- -- --
-sizeof yes yes yes yes
-============================== ====== ======= === ====
-
-See also :ref:`langext-__builtin_shufflevector`.
+============================== ======= ======= ======= =======
+ Opeator OpenCL AltiVec GCC NEON
+============================== ======= ======= ======= =======
+[] yes yes yes --
+unary operators +, -- yes yes yes --
+++, -- -- yes yes yes --
++,--,*,/,% yes yes yes --
+bitwise operators &,|,^,~ yes yes yes --
+>>,<< yes yes yes --
+!, &&, || yes -- -- --
+==, !=, >, <, >=, <= yes yes -- --
+= yes yes yes yes
+:? yes -- -- --
+sizeof yes yes yes yes
+C-style cast yes yes yes no
+reinterpret_cast yes no yes no
+static_cast yes no yes no
+const_cast no no no no
+============================== ======= ======= ======= =======
+
+See also :ref:`langext-__builtin_shufflevector`, :ref:`langext-__builtin_convertvector`.
Messages on ``deprecated`` and ``unavailable`` Attributes
=========================================================
@@ -454,6 +515,13 @@ features are enabled. The ``__has_extension`` macro can be used to query if
language features are available as an extension when compiling for a standard
which does not provide them. The features which can be tested are listed here.
+Since Clang 3.4, the C++ SD-6 feature test macros are also supported.
+These are macros with names of the form ``__cpp_<feature_name>``, and are
+intended to be a portable way to query the supported features of the compiler.
+See `the C++ status page <http://clang.llvm.org/cxx_status.html#ts>`_ for
+information on the version of SD-6 supported by each Clang release, and the
+macros provided by that revision of the recommendations.
+
C++98
-----
@@ -502,6 +570,9 @@ C++11 alignment specifiers
Use ``__has_feature(cxx_alignas)`` or ``__has_extension(cxx_alignas)`` to
determine if support for alignment specifiers using ``alignas`` is enabled.
+Use ``__has_feature(cxx_alignof)`` or ``__has_extension(cxx_alignof)`` to
+determine if support for the ``alignof`` keyword is enabled.
+
C++11 attributes
^^^^^^^^^^^^^^^^
@@ -747,6 +818,13 @@ Use ``__has_feature(cxx_aggregate_nsdmi)`` or
``__has_extension(cxx_aggregate_nsdmi)`` to determine if support
for default initializers in aggregate members is enabled.
+C++1y digit separators
+^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__cpp_digit_separators`` to determine if support for digit separators
+using single quotes (for instance, ``10'000``) is enabled. At this time, there
+is no corresponding ``__has_feature`` name
+
C++1y generalized lambda capture
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -809,13 +887,25 @@ C11 alignment specifiers
Use ``__has_feature(c_alignas)`` or ``__has_extension(c_alignas)`` to determine
if support for alignment specifiers using ``_Alignas`` is enabled.
+Use ``__has_feature(c_alignof)`` or ``__has_extension(c_alignof)`` to determine
+if support for the ``_Alignof`` keyword is enabled.
+
C11 atomic operations
^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(c_atomic)`` or ``__has_extension(c_atomic)`` to determine
if support for atomic types using ``_Atomic`` is enabled. Clang also provides
:ref:`a set of builtins <langext-__c11_atomic>` which can be used to implement
-the ``<stdatomic.h>`` operations on ``_Atomic`` types.
+the ``<stdatomic.h>`` operations on ``_Atomic`` types. Use
+``__has_include(<stdatomic.h>)`` to determine if C11's ``<stdatomic.h>`` header
+is available.
+
+Clang will use the system's ``<stdatomic.h>`` header when one is available, and
+will otherwise use its own. When using its own, implementations of the atomic
+operations are provided as macros. In the cases where C11 also requires a real
+function, this header provides only the declaration of that function (along
+with a shadowing macro implementation), and you must link to a library which
+provides a definition of the function if you use it instead of the macro.
C11 generic selections
^^^^^^^^^^^^^^^^^^^^^^
@@ -1224,8 +1314,9 @@ Builtin Functions
Clang supports a number of builtin library functions with the same syntax as
GCC, including things like ``__builtin_nan``, ``__builtin_constant_p``,
``__builtin_choose_expr``, ``__builtin_types_compatible_p``,
-``__sync_fetch_and_add``, etc. In addition to the GCC builtins, Clang supports
-a number of builtins that GCC does not, which are listed here.
+``__builtin_assume_aligned``, ``__sync_fetch_and_add``, etc. In addition to
+the GCC builtins, Clang supports a number of builtins that GCC does not, which
+are listed here.
Please note that Clang does not and will not support all of the GCC builtins
for vector operations. Instead of using builtins, you should use the functions
@@ -1235,6 +1326,42 @@ implemented directly in terms of :ref:`extended vector support
<langext-vectors>` instead of builtins, in order to reduce the number of
builtins that we need to implement.
+``__builtin_assume``
+------------------------------
+
+``__builtin_assume`` is used to provide the optimizer with a boolean
+invariant that is defined to be true.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ __builtin_assume(bool)
+
+**Example of Use**:
+
+.. code-block:: c++
+
+ int foo(int x) {
+ __builtin_assume(x != 0);
+
+ // The optimizer may short-circuit this check using the invariant.
+ if (x == 0)
+ return do_something();
+
+ return do_something_else();
+ }
+
+**Description**:
+
+The boolean argument to this function is defined to be true. The optimizer may
+analyze the form of the expression provided as the argument and deduce from
+that information used to optimize the program. If the condition is violated
+during execution, the behavior is undefined. The argument itself is never
+evaluated, so any side effects of the expression will be discarded.
+
+Query for this feature with ``__has_builtin(__builtin_assume)``.
+
``__builtin_readcyclecounter``
------------------------------
@@ -1324,6 +1451,8 @@ indices specified.
Query for this feature with ``__has_builtin(__builtin_shufflevector)``.
+.. _langext-__builtin_convertvector:
+
``__builtin_convertvector``
---------------------------
@@ -1354,7 +1483,7 @@ type must have the same number of elements.
// convert from a vector of 4 shorts to a vector of 4 floats.
__builtin_convertvector(vs, vector4float)
// equivalent to:
- (vector4float) { (float) vf[0], (float) vf[1], (float) vf[2], (float) vf[3] }
+ (vector4float) { (float) vs[0], (float) vs[1], (float) vs[2], (float) vs[3] }
**Description**:
@@ -1554,12 +1683,14 @@ __c11_atomic builtins
Clang provides a set of builtins which are intended to be used to implement
C11's ``<stdatomic.h>`` header. These builtins provide the semantics of the
``_explicit`` form of the corresponding C11 operation, and are named with a
-``__c11_`` prefix. The supported operations are:
+``__c11_`` prefix. The supported operations, and the differences from
+the corresponding C11 operations, are:
* ``__c11_atomic_init``
* ``__c11_atomic_thread_fence``
* ``__c11_atomic_signal_fence``
-* ``__c11_atomic_is_lock_free``
+* ``__c11_atomic_is_lock_free`` (The argument is the size of the
+ ``_Atomic(...)`` object, instead of its address)
* ``__c11_atomic_store``
* ``__c11_atomic_load``
* ``__c11_atomic_exchange``
@@ -1571,6 +1702,11 @@ C11's ``<stdatomic.h>`` header. These builtins provide the semantics of the
* ``__c11_atomic_fetch_or``
* ``__c11_atomic_fetch_xor``
+The macros ``__ATOMIC_RELAXED``, ``__ATOMIC_CONSUME``, ``__ATOMIC_ACQUIRE``,
+``__ATOMIC_RELEASE``, ``__ATOMIC_ACQ_REL``, and ``__ATOMIC_SEQ_CST`` are
+provided, with values corresponding to the enumerators of C11's
+``memory_order`` enumeration.
+
Low-level ARM exclusive memory builtins
---------------------------------------
@@ -1780,15 +1916,17 @@ it causes the instantiation of ``twice`` and ``thrice`` with an ``int`` type; of
these two instantiations, ``twice`` will be optimized (because its definition
was outside the region) and ``thrice`` will not be optimized.
-.. _langext-pragma-loop:
-
Extensions for loop hint optimizations
======================================
The ``#pragma clang loop`` directive is used to specify hints for optimizing the
subsequent for, while, do-while, or c++11 range-based for loop. The directive
-provides options for vectorization and interleaving. Loop hints can be specified
-before any loop and will be ignored if the optimization is not safe to apply.
+provides options for vectorization, interleaving, and unrolling. Loop hints can
+be specified before any loop and will be ignored if the optimization is not safe
+to apply.
+
+Vectorization and Interleaving
+------------------------------
A vectorized loop performs multiple iterations of the original loop
in parallel using vector instructions. The instruction set of the target
@@ -1831,6 +1969,46 @@ width/count of the set of target architectures supported by your application.
Specifying a width/count of 1 disables the optimization, and is equivalent to
``vectorize(disable)`` or ``interleave(disable)``.
+Loop Unrolling
+--------------
+
+Unrolling a loop reduces the loop control overhead and exposes more
+opportunities for ILP. Loops can be fully or partially unrolled. Full unrolling
+eliminates the loop and replaces it with an enumerated sequence of loop
+iterations. Full unrolling is only possible if the loop trip count is known at
+compile time. Partial unrolling replicates the loop body within the loop and
+reduces the trip count.
+
+If ``unroll(full)`` is specified the unroller will attempt to fully unroll the
+loop if the trip count is known at compile time. If the loop count is not known
+or the fully unrolled code size is greater than the limit specified by the
+`-pragma-unroll-threshold` command line option the loop will be partially
+unrolled subject to the same limit.
+
+.. code-block:: c++
+
+ #pragma clang loop unroll(full)
+ for(...) {
+ ...
+ }
+
+The unroll count can be specified explicitly with ``unroll_count(_value_)`` where
+_value_ is a positive integer. If this value is greater than the trip count the
+loop will be fully unrolled. Otherwise the loop is partially unrolled subject
+to the `-pragma-unroll-threshold` limit.
+
+.. code-block:: c++
+
+ #pragma clang loop unroll_count(8)
+ for(...) {
+ ...
+ }
+
+Unrolling of a loop can be prevented by specifying ``unroll(disable)``.
+
+Additional Information
+----------------------
+
For convenience multiple loop hints can be specified on a single line.
.. code-block:: c++
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
index 49880539bc98..e70d1ec3fac7 100644
--- a/docs/LibASTMatchersReference.html
+++ b/docs/LibASTMatchersReference.html
@@ -246,6 +246,16 @@ Example matches f
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('linkageSpecDecl0')"><a name="linkageSpecDecl0Anchor">linkageSpecDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LinkageSpecDecl.html">LinkageSpecDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="linkageSpecDecl0"><pre>Matches a declaration of a linkage specification.
+
+Given
+ extern "C" {}
+linkageSpecDecl()
+ matches "extern "C" {}"
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('methodDecl0')"><a name="methodDecl0Anchor">methodDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="methodDecl0"><pre>Matches method declarations.
@@ -297,6 +307,16 @@ Example matches X, Z
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('typedefDecl0')"><a name="typedefDecl0Anchor">typedefDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefDecl.html">TypedefDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="typedefDecl0"><pre>Matches typedef declarations.
+
+Given
+ typedef int X;
+typedefDecl()
+ matches "typedef int X"
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('unresolvedUsingValueDecl0')"><a name="unresolvedUsingValueDecl0Anchor">unresolvedUsingValueDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingValueDecl.html">UnresolvedUsingValueDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="unresolvedUsingValueDecl0"><pre>Matches unresolved using value declarations.
@@ -319,6 +339,25 @@ usingDecl()
matches using X::x </pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('usingDirectiveDecl0')"><a name="usingDirectiveDecl0Anchor">usingDirectiveDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingDirectiveDecl.html">UsingDirectiveDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="usingDirectiveDecl0"><pre>Matches using namespace declarations.
+
+Given
+ namespace X { int x; }
+ using namespace X;
+usingDirectiveDecl()
+ matches using namespace X </pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('valueDecl0')"><a name="valueDecl0Anchor">valueDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="valueDecl0"><pre>Matches any value declaration.
+
+Example matches A, B, C and F
+ enum X { A, B, C };
+ void F();
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('varDecl0')"><a name="varDecl0Anchor">varDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="varDecl0"><pre>Matches variable declarations.
@@ -355,6 +394,14 @@ nestedNameSpecifier()
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('CUDAKernelCallExpr0')"><a name="CUDAKernelCallExpr0Anchor">CUDAKernelCallExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CUDAKernelCallExpr.html">CUDAKernelCallExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="CUDAKernelCallExpr0"><pre>Matches CUDA kernel call expression.
+
+Example matches,
+ kernel&lt;&lt;&lt;i,j&gt;&gt;&gt;();
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('arraySubscriptExpr0')"><a name="arraySubscriptExpr0Anchor">arraySubscriptExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="arraySubscriptExpr0"><pre>Matches array subscript expressions.
@@ -711,7 +758,7 @@ Given
int a[] = { 1, 2 };
struct B { int x, y; };
B b = { 5, 6 };
-initList()
+initListExpr()
matches "{ 1, 2 }" and "{ 5, 6 }"
</pre></td></tr>
@@ -876,6 +923,18 @@ Example matches "abcd", L"abcd"
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('substNonTypeTemplateParmExpr0')"><a name="substNonTypeTemplateParmExpr0Anchor">substNonTypeTemplateParmExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1SubstNonTypeTemplateParmExpr.html">SubstNonTypeTemplateParmExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="substNonTypeTemplateParmExpr0"><pre>Matches substitutions of non-type template parameters.
+
+Given
+ template &lt;int N&gt;
+ struct A { static const int n = N; };
+ struct B : public A&lt;42&gt; {};
+substNonTypeTemplateParmExpr()
+ matches "N" in the right-hand side of "static const int n = N;"
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('switchCase0')"><a name="switchCase0Anchor">switchCase</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchCase.html">SwitchCase</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="switchCase0"><pre>Matches case and default statements inside switch statements.
@@ -980,6 +1039,17 @@ whileStmt()
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt;</td><td class="name" onclick="toggle('templateArgument0')"><a name="templateArgument0Anchor">templateArgument</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="templateArgument0"><pre>Matches template arguments.
+
+Given
+ template &lt;typename T&gt; struct C {};
+ C&lt;int&gt; c;
+templateArgument()
+ matches 'int' in C&lt;int&gt;.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('typeLoc0')"><a name="typeLoc0Anchor">typeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="typeLoc0"><pre>Matches TypeLocs in the clang AST.
</pre></td></tr>
@@ -1269,6 +1339,7 @@ Given
int a[] = { 2, 3 }
int b[42];
int c[a[0]];
+ }
variableArrayType()
matches "int c[a[0]]"
</pre></td></tr>
@@ -1381,26 +1452,6 @@ constructorDecl(hasAnyConstructorInitializer(isWritten()))
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
-<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName0"><pre>Matches overloaded operator names.
-
-Matches overloaded operator names specified in strings without the
-"operator" prefix: e.g. "&lt;&lt;".
-
-Given:
- class A { int operator*(); };
- const A &amp;operator&lt;&lt;(const A &amp;a, const A &amp;b);
- A a;
- a &lt;&lt; a; &lt;-- This matches
-
-operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;"))) matches the specified
-line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
-the declaration of A.
-
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;
-</pre></td></tr>
-
-
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('isConst0')"><a name="isConst0Anchor">isConst</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isConst0"><pre>Matches if the given method declaration is const.
@@ -1470,7 +1521,7 @@ operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;"))) matches the specified
line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
the declaration of A.
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;
</pre></td></tr>
@@ -1541,6 +1592,17 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Charac
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;</td><td class="name" onclick="toggle('templateArgumentCountIs0')"><a name="templateArgumentCountIs0Anchor">templateArgumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="templateArgumentCountIs0"><pre>Matches if the number of template arguments equals N.
+
+Given
+ template&lt;typename T&gt; struct C {};
+ C&lt;int&gt; c;
+classTemplateSpecializationDecl(templateArgumentCountIs(1))
+ matches C&lt;int&gt;.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>&gt;</td><td class="name" onclick="toggle('statementCountIs0')"><a name="statementCountIs0Anchor">statementCountIs</a></td><td>unsigned N</td></tr>
<tr><td colspan="4" class="doc" id="statementCountIs0"><pre>Checks that a compound statement contains a specific number of
child statements.
@@ -1601,10 +1663,55 @@ and reference to that variable declaration within a compound statement.
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('equalsNode0')"><a name="equalsNode0Anchor">equalsNode</a></td><td>Decl *Node</td></tr>
-<tr><td colspan="4" class="doc" id="equalsNode0"><pre>Matches if a node equals another node.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('hasAttr0')"><a name="hasAttr0Anchor">hasAttr</a></td><td>attr::Kind AttrKind</td></tr>
+<tr><td colspan="4" class="doc" id="hasAttr0"><pre>Matches declaration that has a given attribute.
-Decl has pointer identity in the AST.
+Given
+ __attribute__((device)) void f() { ... }
+decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
+f.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('isExpansionInFileMatching0')"><a name="isExpansionInFileMatching0Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInFileMatching0"><pre>Matches AST nodes that were expanded within files whose name is
+partially matching a given regex.
+
+Example matches Y but not X
+ (matcher = recordDecl(isExpansionInFileMatching("AST.*"))
+ #include "ASTMatcher.h"
+ class X {};
+ASTMatcher.h:
+ class Y {};
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('isExpansionInMainFile0')"><a name="isExpansionInMainFile0Anchor">isExpansionInMainFile</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInMainFile0"><pre>Matches AST nodes that were expanded within the main-file.
+
+Example matches X but not Y (matcher = recordDecl(isExpansionInMainFile())
+ #include &lt;Y.h&gt;
+ class X {};
+Y.h:
+ class Y {};
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('isExpansionInSystemHeader0')"><a name="isExpansionInSystemHeader0Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader0"><pre>Matches AST nodes that were expanded within system-header-files.
+
+Example matches Y but not X
+ (matcher = recordDecl(isExpansionInSystemHeader())
+ #include &lt;SystemHeader.h&gt;
+ class X {};
+SystemHeader.h:
+ class Y {};
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;
</pre></td></tr>
@@ -1614,6 +1721,19 @@ by the compiler (eg. implicit defaultcopy constructors).
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('isInstantiated0')"><a name="isInstantiated0Anchor">isInstantiated</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isInstantiated0"><pre>Matches declarations that are template instantiations or are inside
+template instantiations.
+
+Given
+ template&lt;typename T&gt; void A(T t) { T i; }
+ A(0);
+ A(0U);
+functionDecl(isInstantiated())
+ matches 'A(int) {...};' and 'A(unsigned) {...}'.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('isPrivate0')"><a name="isPrivate0Anchor">isPrivate</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isPrivate0"><pre>Matches private C++ declarations.
@@ -1667,6 +1787,26 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Charac
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName0"><pre>Matches overloaded operator names.
+
+Matches overloaded operator names specified in strings without the
+"operator" prefix: e.g. "&lt;&lt;".
+
+Given:
+ class A { int operator*(); };
+ const A &amp;operator&lt;&lt;(const A &amp;a, const A &amp;b);
+ A a;
+ a &lt;&lt; a; &lt;-- This matches
+
+operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;"))) matches the specified
+line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
+the declaration of A.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition2')"><a name="isDefinition2Anchor">isDefinition</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isDefinition2"><pre>Matches if a declaration has a body attached.
@@ -1682,6 +1822,17 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDec
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isDeleted0')"><a name="isDeleted0Anchor">isDeleted</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDeleted0"><pre>Matches deleted function declarations.
+
+Given:
+ void Func();
+ void DeletedFunc() = delete;
+functionDecl(isDeleted())
+ matches the declaration of DeletedFunc, but not Func.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isExplicitTemplateSpecialization0')"><a name="isExplicitTemplateSpecialization0Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization0"><pre>Matches explicit template specializations of function, class, or
static member variable template instantiations.
@@ -1768,7 +1919,7 @@ memberExpr(isArrow())
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt;</td><td class="name" onclick="toggle('hasName0')"><a name="hasName0Anchor">hasName</a></td><td>std::string Name</td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt;</td><td class="name" onclick="toggle('hasName0')"><a name="hasName0Anchor">hasName</a></td><td>std::string Name</td></tr>
<tr><td colspan="4" class="doc" id="hasName0"><pre>Matches NamedDecl nodes that have the specified name.
Supports specifying enclosing namespaces or classes by prefixing the name
@@ -1900,11 +2051,61 @@ and reference to that variable declaration within a compound statement.
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('equalsNode1')"><a name="equalsNode1Anchor">equalsNode</a></td><td>Stmt *Node</td></tr>
-<tr><td colspan="4" class="doc" id="equalsNode1"><pre>Matches if a node equals another node.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('isExpansionInFileMatching1')"><a name="isExpansionInFileMatching1Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInFileMatching1"><pre>Matches AST nodes that were expanded within files whose name is
+partially matching a given regex.
-Stmt has pointer identity in the AST.
+Example matches Y but not X
+ (matcher = recordDecl(isExpansionInFileMatching("AST.*"))
+ #include "ASTMatcher.h"
+ class X {};
+ASTMatcher.h:
+ class Y {};
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('isExpansionInMainFile1')"><a name="isExpansionInMainFile1Anchor">isExpansionInMainFile</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInMainFile1"><pre>Matches AST nodes that were expanded within the main-file.
+
+Example matches X but not Y (matcher = recordDecl(isExpansionInMainFile())
+ #include &lt;Y.h&gt;
+ class X {};
+Y.h:
+ class Y {};
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;
+</pre></td></tr>
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('isExpansionInSystemHeader1')"><a name="isExpansionInSystemHeader1Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader1"><pre>Matches AST nodes that were expanded within system-header-files.
+
+Example matches Y but not X
+ (matcher = recordDecl(isExpansionInSystemHeader())
+ #include &lt;SystemHeader.h&gt;
+ class X {};
+SystemHeader.h:
+ class Y {};
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('isInTemplateInstantiation0')"><a name="isInTemplateInstantiation0Anchor">isInTemplateInstantiation</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isInTemplateInstantiation0"><pre>Matches statements inside of a template instantiation.
+
+Given
+ int j;
+ template&lt;typename T&gt; void A(T t) { T i; j += 42;}
+ A(0);
+ A(0U);
+declStmt(isInTemplateInstantiation())
+ matches 'int i;' and 'unsigned i'.
+unless(stmt(isInTemplateInstantiation()))
+ will NOT match j += 42; as it's shared between the template definition and
+ instantiation.
</pre></td></tr>
@@ -1923,6 +2124,88 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDec
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt;</td><td class="name" onclick="toggle('equalsIntegralValue0')"><a name="equalsIntegralValue0Anchor">equalsIntegralValue</a></td><td>std::string Value</td></tr>
+<tr><td colspan="4" class="doc" id="equalsIntegralValue0"><pre>Matches a TemplateArgument of integral type with a given value.
+
+Note that 'Value' is a string as the template argument's value is
+an arbitrary precision integer. 'Value' must be euqal to the canonical
+representation of that integral value in base 10.
+
+Given
+ template&lt;int T&gt; struct A {};
+ C&lt;42&gt; c;
+classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(equalsIntegralValue("42")))
+ matches the implicit instantiation of C in C&lt;42&gt;.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt;</td><td class="name" onclick="toggle('isIntegral0')"><a name="isIntegral0Anchor">isIntegral</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isIntegral0"><pre>Matches a TemplateArgument that is an integral value.
+
+Given
+ template&lt;int T&gt; struct A {};
+ C&lt;42&gt; c;
+classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(isIntegral()))
+ matches the implicit instantiation of C in C&lt;42&gt;
+ with isIntegral() matching 42.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;</td><td class="name" onclick="toggle('templateArgumentCountIs1')"><a name="templateArgumentCountIs1Anchor">templateArgumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="templateArgumentCountIs1"><pre>Matches if the number of template arguments equals N.
+
+Given
+ template&lt;typename T&gt; struct C {};
+ C&lt;int&gt; c;
+classTemplateSpecializationDecl(templateArgumentCountIs(1))
+ matches C&lt;int&gt;.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('isExpansionInFileMatching2')"><a name="isExpansionInFileMatching2Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInFileMatching2"><pre>Matches AST nodes that were expanded within files whose name is
+partially matching a given regex.
+
+Example matches Y but not X
+ (matcher = recordDecl(isExpansionInFileMatching("AST.*"))
+ #include "ASTMatcher.h"
+ class X {};
+ASTMatcher.h:
+ class Y {};
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('isExpansionInMainFile2')"><a name="isExpansionInMainFile2Anchor">isExpansionInMainFile</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInMainFile2"><pre>Matches AST nodes that were expanded within the main-file.
+
+Example matches X but not Y (matcher = recordDecl(isExpansionInMainFile())
+ #include &lt;Y.h&gt;
+ class X {};
+Y.h:
+ class Y {};
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('isExpansionInSystemHeader2')"><a name="isExpansionInSystemHeader2Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader2"><pre>Matches AST nodes that were expanded within system-header-files.
+
+Example matches Y but not X
+ (matcher = recordDecl(isExpansionInSystemHeader())
+ #include &lt;SystemHeader.h&gt;
+ class X {};
+SystemHeader.h:
+ class Y {};
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('equalsBoundNode2')"><a name="equalsBoundNode2Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
<tr><td colspan="4" class="doc" id="equalsBoundNode2"><pre>Matches if a node equals a previously bound node.
@@ -2550,7 +2833,7 @@ given matcher.
Example matches y.x() (matcher = callExpr(callee(methodDecl(hasName("x")))))
class Y { public: void x(); };
- void z() { Y y; y.x();
+ void z() { Y y; y.x(); }
</pre></td></tr>
@@ -3448,6 +3731,7 @@ Example matches X &amp;x and const X &amp;y
void a(X b) {
X &amp;x = b;
const X &amp;y = b;
+ }
};
</pre></td></tr>
@@ -3582,6 +3866,18 @@ classTemplateSpecializationDecl(hasAnyTemplateArgument(
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt;</td><td class="name" onclick="toggle('refersToIntegralType0')"><a name="refersToIntegralType0Anchor">refersToIntegralType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="refersToIntegralType0"><pre>Matches a TemplateArgument that referes to an integral type.
+
+Given
+ template&lt;int T&gt; struct A {};
+ C&lt;42&gt; c;
+classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(refersToIntegralType(asString("int"))))
+ matches the implicit instantiation of C in C&lt;42&gt;.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt;</td><td class="name" onclick="toggle('refersToType0')"><a name="refersToType0Anchor">refersToType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="refersToType0"><pre>Matches a TemplateArgument that refers to a certain type.
diff --git a/docs/MSVCCompatibility.rst b/docs/MSVCCompatibility.rst
index 32efb76db251..73f01fc2b080 100644
--- a/docs/MSVCCompatibility.rst
+++ b/docs/MSVCCompatibility.rst
@@ -72,17 +72,21 @@ The status of major ABI-impacting C++ features:
.. _/vm: http://msdn.microsoft.com/en-us/library/yad46a6z.aspx
.. _pointer to a member of a virtual base class: http://llvm.org/PR15713
-* Debug info: :partial:`Minimal`. Clang emits CodeView line tables into the
- object file, similar to what MSVC emits when given the ``/Z7`` flag.
- Microsoft's link.exe will read this information and use it to create a PDB,
+* Debug info: :partial:`Minimal`. Clang emits both CodeView line tables
+ (similar to what MSVC emits when given the ``/Z7`` flag) and DWARF debug
+ information into the object file.
+ Microsoft's link.exe will transform the CodeView line tables into a PDB,
enabling stack traces in all modern Windows debuggers. Clang does not emit
- any type info or description of variable layout.
+ any CodeView-compatible type info or description of variable layout.
+ Binaries linked with either binutils' ld or LLVM's lld should be usable with
+ GDB however sophisticated C++ expressions are likely to fail.
* RTTI: :good:`Complete`. Generation of RTTI data structures has been
finished, along with support for the ``/GR`` flag.
-* Exceptions and SEH: :none:`Unstarted`. Clang can parse both constructs, but
- does not know how to emit compatible handlers.
+* Exceptions and SEH: :partial:`Minimal`. Clang can parse both constructs, but
+ does not know how to emit compatible handlers. Clang cannot throw exceptions
+ but it can rethrow them.
* Thread-safe initialization of local statics: :none:`Unstarted`. We are ABI
compatible with MSVC 2013, which does not support thread-safe local statics.
diff --git a/docs/Modules.rst b/docs/Modules.rst
index ce1e717bc2a0..1575ce6964c8 100644
--- a/docs/Modules.rst
+++ b/docs/Modules.rst
@@ -2,10 +2,6 @@
Modules
=======
-.. warning::
- The functionality described on this page is supported for C and
- Objective-C. C++ support is experimental.
-
.. contents::
:local:
@@ -104,7 +100,7 @@ Many programming languages have a module or package system, and because of the v
Using Modules
=============
-To enable modules, pass the command-line flag ``-fmodules`` [#]_. This will make any modules-enabled software libraries available as modules as well as introducing any modules-specific syntax. Additional `command-line parameters`_ are described in a separate section later.
+To enable modules, pass the command-line flag ``-fmodules``. This will make any modules-enabled software libraries available as modules as well as introducing any modules-specific syntax. Additional `command-line parameters`_ are described in a separate section later.
Objective-C Import declaration
------------------------------
@@ -114,7 +110,7 @@ Objective-C provides syntax for importing a module via an *@import declaration*,
@import std;
-The @import declaration above imports the entire contents of the ``std`` module (which would contain, e.g., the entire C or C++ standard library) and make its API available within the current translation unit. To import only part of a module, one may use dot syntax to specific a particular submodule, e.g.,
+The ``@import`` declaration above imports the entire contents of the ``std`` module (which would contain, e.g., the entire C or C++ standard library) and make its API available within the current translation unit. To import only part of a module, one may use dot syntax to specific a particular submodule, e.g.,
.. parsed-literal::
@@ -140,6 +136,19 @@ will be automatically mapped to an import of the module ``std.io``. Even with sp
The automatic mapping of ``#include`` to ``import`` also solves an implementation problem: importing a module with a definition of some entity (say, a ``struct Point``) and then parsing a header containing another definition of ``struct Point`` would cause a redefinition error, even if it is the same ``struct Point``. By mapping ``#include`` to ``import``, the compiler can guarantee that it always sees just the already-parsed definition from the module.
+While building a module, ``#include_next`` is also supported, with one caveat.
+The usual behavior of ``#include_next`` is to search for the specified filename
+in the list of include paths, starting from the path *after* the one
+in which the current file was found.
+Because files listed in module maps are not found through include paths, a
+different strategy is used for ``#include_next`` directives in such files: the
+list of include paths is searched for the specified header name, to find the
+first include path that would refer to the current file. ``#include_next`` is
+interpreted as if the current file had been found in that path.
+If this search finds a file named by a module map, the ``#include_next``
+directive is translated into an import, just like for a ``#include``
+directive.``
+
Module maps
-----------
The crucial link between modules and headers is described by a *module map*, which describes how a collection of existing headers maps on to the (logical) structure of a module. For example, one could imagine a module ``std`` covering the C standard library. Each of the C standard library headers (``<stdio.h>``, ``<stdlib.h>``, ``<math.h>``, etc.) would contribute to the ``std`` module, by placing their respective APIs into the corresponding submodule (``std.io``, ``std.lib``, ``std.math``, etc.). Having a list of the headers that are part of the ``std`` module allows the compiler to build the ``std`` module as a standalone entity, and having the mapping from header names to (sub)modules allows the automatic translation of ``#include`` directives to module imports.
@@ -163,13 +172,10 @@ Modules maintain references to each of the headers that were part of the module
Command-line parameters
-----------------------
``-fmodules``
- Enable the modules feature (EXPERIMENTAL).
-
-``-fcxx-modules``
- Enable the modules feature for C++ (EXPERIMENTAL and VERY BROKEN).
+ Enable the modules feature.
``-fmodule-maps``
- Enable interpretation of module maps (EXPERIMENTAL). This option is implied by ``-fmodules``.
+ Enable interpretation of module maps. This option is implied by ``-fmodules``.
``-fmodules-cache-path=<directory>``
Specify the path to the modules cache. If not provided, Clang will select a system-appropriate default.
@@ -201,6 +207,9 @@ Command-line parameters
``-fmodules-search-all``
If a symbol is not found, search modules referenced in the current module maps but not imported for symbols, so the error message can reference the module by name. Note that if the global module index has not been built before, this might take some time as it needs to build all the modules. Note that this option doesn't apply in module builds, to avoid the recursion.
+``-fno-modules-implicit-maps``
+ Suppresses the implicit search for files called ``module.modulemap`` and similar. Instead, module files need to be explicitly specified via ``-fmodule-map-file`` or transitively used.
+
Module Semantics
================
@@ -208,7 +217,7 @@ Modules are modeled as if each submodule were a separate translation unit, and a
.. note::
- This behavior is currently only approximated when building a module. Entities within a submodule that has already been built are visible when building later submodules in that module. This can lead to fragile modules that depend on the build order used for the submodules of the module, and should not be relied upon.
+ This behavior is currently only approximated when building a module with submodules. Entities within a submodule that has already been built are visible when building later submodules in that module. This can lead to fragile modules that depend on the build order used for the submodules of the module, and should not be relied upon. This behavior is subject to change.
As an example, in C, this implies that if two structs are defined in different submodules with the same name, those two types are distinct types (but may be *compatible* types if their definitions match. In C++, two structs defined with the same name in different submodules are the *same* type, and must be equivalent under C++'s One Definition Rule.
@@ -216,6 +225,8 @@ As an example, in C, this implies that if two structs are defined in different s
Clang currently only performs minimal checking for violations of the One Definition Rule.
+If any submodule of a module is imported into any part of a program, the entire top-level module is considered to be part of the program. As a consequence of this, Clang may diagnose conflicts between an entity declared in an unimported submodule and an entity declared in the current translation unit, and Clang may inline or devirtualize based on knowledge from unimported submodules.
+
Macros
------
@@ -238,6 +249,10 @@ The ``#undef`` overrides the ``#define``, and a source file that imports both mo
Module Map Language
===================
+.. warning::
+
+ The module map language is not currently guaranteed to be stable between major revisions of Clang.
+
The module map language describes the mapping from header files to the
logical structure of modules. To enable support for using a library as
a module, one must write a ``module.modulemap`` file for that library. The
@@ -255,6 +270,12 @@ As an example, the module map file for the C standard library might look a bit l
.. parsed-literal::
module std [system] [extern_c] {
+ module assert {
+ textual header "assert.h"
+ header "bits/assert-decls.h"
+ export *
+ }
+
module complex {
header "complex.h"
export *
@@ -287,11 +308,11 @@ Module map files use a simplified form of the C99 lexer, with the same rules for
.. parsed-literal::
- ``config_macros`` ``export`` ``module``
+ ``config_macros`` ``export`` ``private``
``conflict`` ``framework`` ``requires``
- ``exclude`` ``header`` ``private``
+ ``exclude`` ``header`` ``textual``
``explicit`` ``link`` ``umbrella``
- ``extern`` ``use``
+ ``extern`` ``module`` ``use``
Module map file
---------------
@@ -319,7 +340,7 @@ A module declaration describes a module, including the headers that contribute t
``explicit``:sub:`opt` ``framework``:sub:`opt` ``module`` *module-id* *attributes*:sub:`opt` '{' *module-member** '}'
``extern`` ``module`` *module-id* *string-literal*
-The *module-id* should consist of only a single *identifier*, which provides the name of the module being defined. Each module shall have a single definition.
+The *module-id* should consist of only a single *identifier*, which provides the name of the module being defined. Each module shall have a single definition.
The ``explicit`` qualifier can only be applied to a submodule, i.e., a module that is nested within another module. The contents of explicit submodules are only made available when the submodule itself was explicitly named in an import declaration or was re-exported from an imported module.
@@ -427,11 +448,11 @@ A header declaration specifies that a particular header is associated with the e
.. parsed-literal::
*header-declaration*:
- ``umbrella``:sub:`opt` ``header`` *string-literal*
- ``private`` ``header`` *string-literal*
+ ``private``:sub:`opt` ``textual``:sub:`opt` ``header`` *string-literal*
+ ``umbrella`` ``header`` *string-literal*
``exclude`` ``header`` *string-literal*
-A header declaration that does not contain ``exclude`` specifies a header that contributes to the enclosing module. Specifically, when the module is built, the named header will be parsed and its declarations will be (logically) placed into the enclosing submodule.
+A header declaration that does not contain ``exclude`` nor ``textual`` specifies a header that contributes to the enclosing module. Specifically, when the module is built, the named header will be parsed and its declarations will be (logically) placed into the enclosing submodule.
A header with the ``umbrella`` specifier is called an umbrella header. An umbrella header includes all of the headers within its directory (and any subdirectories), and is typically used (in the ``#include`` world) to easily access the full API provided by a particular library. With modules, an umbrella header is a convenient shortcut that eliminates the need to write out ``header`` declarations for every library header. A given directory can only contain a single umbrella header.
@@ -443,14 +464,16 @@ A header with the ``umbrella`` specifier is called an umbrella header. An umbrel
A header with the ``private`` specifier may not be included from outside the module itself.
-A header with the ``exclude`` specifier is excluded from the module. It will not be included when the module is built, nor will it be considered to be part of the module.
+A header with the ``textual`` specifier will not be included when the module is built, and will be textually included if it is named by a ``#include`` directive. However, it is considered to be part of the module for the purpose of checking *use-declaration*\s.
-**Example**: The C header ``assert.h`` is an excellent candidate for an excluded header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings).
+A header with the ``exclude`` specifier is excluded from the module. It will not be included when the module is built, nor will it be considered to be part of the module, even if an ``umbrella`` header or directory would otherwise make it part of the module.
+
+**Example**: The C header ``assert.h`` is an excellent candidate for a textual header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings). However, declarations within it should typically be split into a separate modular header.
.. parsed-literal::
module std [system] {
- exclude header "assert.h"
+ textual header "assert.h"
}
A given header shall not be referenced by more than one *header-declaration*.
@@ -824,20 +847,17 @@ To detect and help address some of these problems, the ``clang-tools-extra`` rep
Future Directions
=================
-Modules is an experimental feature, and there is much work left to do to make it both real and useful. Here are a few ideas:
+Modules support is under active development, and there are many opportunities remaining to improve it. Here are a few ideas:
**Detect unused module imports**
Unlike with ``#include`` directives, it should be fairly simple to track whether a directly-imported module has ever been used. By doing so, Clang can emit ``unused import`` or ``unused #include`` diagnostics, including Fix-Its to remove the useless imports/includes.
**Fix-Its for missing imports**
- It's fairly common for one to make use of some API while writing code, only to get a compiler error about "unknown type" or "no function named" because the corresponding header has not been included. Clang should detect such cases and auto-import the required module (with a Fix-It!).
+ It's fairly common for one to make use of some API while writing code, only to get a compiler error about "unknown type" or "no function named" because the corresponding header has not been included. Clang can detect such cases and auto-import the required module, but should provide a Fix-It to add the import.
**Improve modularize**
The modularize tool is both extremely important (for deployment) and extremely crude. It needs better UI, better detection of problems (especially for C++), and perhaps an assistant mode to help write module maps for you.
-**C++ Support**
- Modules clearly has to work for C++, or we'll never get to use it for the Clang code base.
-
Where To Learn More About Modules
=================================
The Clang source code provides additional information about modules:
@@ -859,8 +879,6 @@ PCHInternals_
.. [#] Automatic linking against the libraries of modules requires specific linker support, which is not widely available.
-.. [#] Modules are only available in C and Objective-C; a separate flag ``-fcxx-modules`` enables modules support for C++, which is even more experimental and broken.
-
.. [#] There are certain anti-patterns that occur in headers, particularly system headers, that cause problems for modules. The section `Modularizing a Platform`_ describes some of them.
.. [#] The second instance is actually a new thread within the current process, not a separate process. However, the original compiler instance is blocked on the execution of this thread.
diff --git a/docs/RAVFrontendAction.rst b/docs/RAVFrontendAction.rst
index 2f60ce9e8279..ec5d5d54ff9b 100644
--- a/docs/RAVFrontendAction.rst
+++ b/docs/RAVFrontendAction.rst
@@ -25,9 +25,10 @@ unit.
class FindNamedClassAction : public clang::ASTFrontendAction {
public:
- virtual clang::ASTConsumer *CreateASTConsumer(
+ virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
- return new FindNamedClassConsumer;
+ return std::unique_ptr<clang::ASTConsumer>(
+ new FindNamedClassConsumer);
}
};
@@ -111,9 +112,10 @@ freshly created FindNamedClassConsumer:
::
- virtual clang::ASTConsumer *CreateASTConsumer(
+ virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
- return new FindNamedClassConsumer(&Compiler.getASTContext());
+ return std::unique_ptr<clang::ASTConsumer>(
+ new FindNamedClassConsumer(&Compiler.getASTContext()));
}
Now that the ASTContext is available in the RecursiveASTVisitor, we can
@@ -185,9 +187,10 @@ Now we can combine all of the above into a small example program:
class FindNamedClassAction : public clang::ASTFrontendAction {
public:
- virtual clang::ASTConsumer *CreateASTConsumer(
+ virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
- return new FindNamedClassConsumer(&Compiler.getASTContext());
+ return std::unique_ptr<clang::ASTConsumer>(
+ new FindNamedClassConsumer(&Compiler.getASTContext()));
}
};
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index 5ff136e5f6d7..8c47d693ed37 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -1,6 +1,6 @@
-=======================
-Clang 3.5 Release Notes
-=======================
+=====================================
+Clang 3.6 (In-Progress) Release Notes
+=====================================
.. contents::
:local:
@@ -8,11 +8,17 @@ Clang 3.5 Release Notes
Written by the `LLVM Team <http://llvm.org/>`_
+.. warning::
+
+ These are in-progress notes for the upcoming Clang 3.6 release. You may
+ prefer the `Clang 3.5 Release Notes
+ <http://llvm.org/releases/3.5/tools/clang/docs/ReleaseNotes.html>`_.
+
Introduction
============
This document contains the release notes for the Clang C/C++/Objective-C
-frontend, part of the LLVM Compiler Infrastructure, release 3.5. Here we
+frontend, part of the LLVM Compiler Infrastructure, release 3.6. Here we
describe the status of Clang in some detail, including major
improvements from the previous release and new feature work. For the
general LLVM release notes, see `the LLVM
@@ -30,7 +36,7 @@ main Clang web page, this document applies to the *next* release, not
the current one. To see the release notes for a specific release, please
see the `releases page <http://llvm.org/releases/>`_.
-What's New in Clang 3.5?
+What's New in Clang 3.6?
========================
Some of the major new features and improvements to Clang are listed
@@ -41,213 +47,104 @@ sections with improvements to Clang's support for those languages.
Major New Features
------------------
-- Clang uses the new MingW ABI
- GCC 4.7 changed the mingw ABI. Clang 3.4 and older use the GCC 4.6
- ABI. Clang 3.5 and newer use the GCC 4.7 abi.
-
-- The __has_attribute feature test is now target-aware. Older versions of Clang
- would return true when the attribute spelling was known, regardless of whether
- the attribute was available to the specific target. Clang now returns true
- only when the attribute pertains to the current compilation target.
-
-- Clang 3.5 now has parsing and semantic-analysis support for all OpenMP 3.1
- pragmas (except atomics and ordered). LLVM's OpenMP runtime library,
- originally developed by Intel, has been modified to work on ARM, PowerPC,
- as well as X86. Code generation support is minimal at this point and will
- continue to be developed for 3.6, along with the rest of OpenMP 3.1.
- Support for OpenMP 4.0 features, such as SIMD and target accelerator
- directives, is also in progress. Contributors to this work include AMD,
- Argonne National Lab., IBM, Intel, Texas Instruments, University of Houston
- and many others.
+- The __has_attribute built-in macro no longer queries for attributes across
+ multiple attribute syntaxes (GNU, C++11, __declspec, etc). Instead, it only
+ queries GNU-style attributes. With the addition of __has_cpp_attribute and
+ __has_declspec_attribute, this allows for more precise coverage of attribute
+ syntax querying.
+
Improvements to Clang's diagnostics
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Clang's diagnostics are constantly being improved to catch more issues,
explain them more clearly, and provide more accurate source information
-about them. The improvements since the 3.4 release include:
-
-- GCC compatibility: Clang displays a warning on unsupported gcc
- optimization flags instead of an error.
-
-- Remarks system: Clang supports `-R` flags for enabling remarks. These are
- diagnostic messages that provide information about the compilation process,
- but don't suggest that a problem has been detected. As such, they cannot
- be upgraded to errors with `-Werror` or `-Rerror`. A `-Reverything` flag
- is provided (paralleling `-Weverything`) to turn on all remarks.
-
-- New remark `-Rpass`: Clang provides information about decisions made by
- optimization passes during compilation. See :ref:`opt_rpass`.
-
-- New warning `-Wabsolute-value`: Clang warns about incorrect or useless usage
- of the absolute functions (`abs`, `fabsf`, etc).
-
- .. code-block:: c
-
- #include <stdlib.h>
- void foo() {
- unsigned int i=0;
- abs(i);
- }
-
- returns
- `warning: taking the absolute value of unsigned type 'unsigned int' has no effect [-Wabsolute-value]`
-
- or
-
- .. code-block:: c
-
- #include <stdlib.h>
- void plop() {
- long long i=0;
- abs(i);
- }
-
- returns
- `warning: absolute value function 'abs' given an argument of type 'long long' but has parameter of type 'int' which may cause truncation of value [-Wabsolute-value] use function 'llabs' instead`
-
-- New warning `-Wtautological-pointer-compare`:
-
- .. code-block:: c++
-
- #include <stddef.h>
- void foo() {
- int arr[5];
- int x;
- // warn on these conditionals
- if (foo);
- if (arr);
- if (&x);
- if (foo == NULL);
- if (arr == NULL);
- if (&x == NULL);
- }
-
- returns
- `warning: comparison of address of 'x' equal to a null pointer is always false [-Wtautological-pointer-compare]`
-
-- New warning `-Wtautological-undefined-compare`:
-
- .. code-block:: c++
-
- #include <stddef.h>
- void f(int &x) {
- if (&x == nullptr) { }
- }
-
- returns
- `warning: reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false [-Wtautological-undefined-compare]`
+about them. The improvements since the 3.5 release include:
- ...
New Compiler Flags
------------------
-The integrated assembler is now turned on by default on ARM (and Thumb),
-so the use of the option `-fintegrated-as` is now redundant on those
-architectures. This is an important move to both *eat our own dog food*
-and to ease cross-compilation tremendously.
+The option ....
-We are aware of the problems that this may cause for code bases that
-rely on specific GNU syntax or extensions, and we're working towards
-getting them all fixed. Please, report bugs or feature requests if
-you find anything. In the meantime, use `-fno-integrated-as` to revert
-back the call to GNU assembler.
-In order to provide better diagnostics, the integrated assembler validates
-inline assembly when the integrated assembler is enabled. Because this is
-considered a feature of the compiler, it is controlled via the `fintegrated-as`
-and `fno-integrated-as` flags which enable and disable the integrated assembler
-respectively. `-integrated-as` and `-no-integrated-as` are now considered
-legacy flags (but are available as an alias to prevent breaking existing users),
-and users are encouraged to switch to the equivalent new feature flag.
+New Pragmas in Clang
+-----------------------
-Deprecated flags `-faddress-sanitizer`, `-fthread-sanitizer`,
-`-fcatch-undefined-behavior` and `-fbounds-checking` were removed in favor of
-`-fsanitize=` family of flags.
+Clang now supports the ...
-It is now possible to get optimization reports from the major transformation
-passes via three new flags: `-Rpass`, `-Rpass-missed` and `-Rpass-analysis`.
-These flags take a POSIX regular expression which indicates the name
-of the pass (or passes) that should emit optimization remarks.
+Windows Support
+---------------
-Options `-u` and `-z` are forwarded to the linker on gnutools toolchains.
+Clang's support for building native Windows programs ...
-New Pragmas in Clang
------------------------
+C Language Changes in Clang
+---------------------------
+
+...
-Loop optimization hints can be specified using the new `#pragma clang loop`
-directive just prior to the desired loop. The directive allows vectorization and
-interleaving to be enabled or disabled. Vector width as well as interleave count
-can be manually specified. See :ref:`langext-pragma-loop` for details.
+C11 Feature Support
+^^^^^^^^^^^^^^^^^^^
+
+...
C++ Language Changes in Clang
-----------------------------
-- Reference parameters and return values from functions are more aggressively
- assumed to refer to valid objects when optimizing. Clang will attempt to
- issue a warning by default if it sees null checks being performed on
- references, and `-fsanitize=null` can be used to detect null references
- being formed at runtime.
+- ...
-C++17 Feature Support
+C++11 Feature Support
^^^^^^^^^^^^^^^^^^^^^
-Clang has experimental support for some proposed C++1z (tentatively, C++17)
-features. This support can be enabled using the `-std=c++1z` flag. The
-supported features are:
-
-- `static_assert(expr)` with no message
-
-- `for (identifier : range)` as a synonym for `for (auto &&identifier : range)`
+...
-- `template<template<...> typename>` as a synonym for `template<template<...> class>`
+Objective-C Language Changes in Clang
+-------------------------------------
-Additionally, trigraphs are not recognized by default in this mode.
-`-ftrigraphs` can be used if you need to parse legacy code that uses trigraphs.
-Note that these features may be changed or removed in future Clang releases
-without notice.
+...
-OpenMP C/C++ Language Changes in Clang
---------------------------------------
-
-- `Status of supported OpenMP constructs
- <https://github.com/clang-omp/clang/wiki/Status-of-supported-OpenMP-constructs>`_.
+OpenCL C Language Changes in Clang
+----------------------------------
+...
Internal API Changes
--------------------
-These are major API changes that have happened since the 3.4 release of
+These are major API changes that have happened since the 3.5 release of
Clang. If upgrading an external codebase that uses Clang as a library,
this section should help get you past the largest hurdles of upgrading.
-- Clang uses `std::unique_ptr<T>` in many places where it used to use
- raw `T *` pointers.
+...
+
+libclang
+--------
+
+...
Static Analyzer
---------------
-Check for code testing a variable for 0 after using it as a denominator.
-This new checker, alpha.core.TestAfterDivZero, catches issues like this:
+...
+
+Core Analysis Improvements
+==========================
-.. code-block:: c
+- ...
- int sum = ...
- int avg = sum / count; // potential division by zero...
- if (count == 0) { ... } // ...caught here
+New Issues Found
+================
+- ...
-The `-analyzer-config` options are now passed from scan-build through to
-ccc-analyzer and then to Clang.
+Python Binding Changes
+----------------------
-With the option `-analyzer-config stable-report-filename=true`,
-instead of `report-XXXXXX.html`, scan-build/clang analyzer generate
-`report-<filename>-<function, method name>-<function position>-<id>.html`.
-(id = i++ for several issues found in the same function/method).
+The following methods have been added:
-List the function/method name in the index page of scan-build.
+- ...
Significant Known Problems
==========================
diff --git a/docs/ThreadSafetyAnalysis.rst b/docs/ThreadSafetyAnalysis.rst
index dfef80b69fa2..0a1b8049e465 100644
--- a/docs/ThreadSafetyAnalysis.rst
+++ b/docs/ThreadSafetyAnalysis.rst
@@ -10,8 +10,8 @@ Clang Thread Safety Analysis is a C++ language extension which warns about
potential race conditions in code. The analysis is completely static (i.e.
compile-time); there is no run-time overhead. The analysis is still
under active development, but it is mature enough to be deployed in an
-industrial setting. It being developed by Google, and is used extensively
-on their internal code base.
+industrial setting. It is being developed by Google, in collaboration with
+CERT/SEI, and is used extensively in Google's internal code base.
Thread safety analysis works very much like a type system for multi-threaded
programs. In addition to declaring the *type* of data (e.g. ``int``, ``float``,
@@ -21,7 +21,7 @@ controlled in a multi-threaded environment. For example, if ``foo`` is
a piece of code reads or writes to ``foo`` without first locking ``mu``.
Similarly, if there are particular routines that should only be called by
the GUI thread, then the analysis will warn if other threads call those
-routines.
+routines.
Getting Started
----------------
@@ -34,21 +34,21 @@ Getting Started
private:
Mutex mu;
int balance GUARDED_BY(mu);
-
+
void depositImpl(int amount) {
balance += amount; // WARNING! Cannot write balance without locking mu.
}
-
- void withdrawImpl(int amount) EXCLUSIVE_LOCKS_REQUIRED(mu) {
+
+ void withdrawImpl(int amount) REQUIRES(mu) {
balance -= amount; // OK. Caller must have locked mu.
}
-
+
public:
void withdraw(int amount) {
mu.Lock();
withdrawImpl(amount); // OK. We've locked mu.
} // WARNING! Failed to unlock mu.
-
+
void transferFrom(BankAccount& b, int amount) {
mu.Lock();
b.withdrawImpl(amount); // WARNING! Calling withdrawImpl() requires locking b.mu.
@@ -60,23 +60,23 @@ Getting Started
This example demonstrates the basic concepts behind the analysis. The
``GUARDED_BY`` attribute declares that a thread must lock ``mu`` before it can
read or write to ``balance``, thus ensuring that the increment and decrement
-operations are atomic. Similarly, ``EXCLUSIVE_LOCKS_REQUIRED`` declares that
+operations are atomic. Similarly, ``REQUIRES`` declares that
the calling thread must lock ``mu`` before calling ``withdrawImpl``.
Because the caller is assumed to have locked ``mu``, it is safe to modify
``balance`` within the body of the method.
-The ``depositImpl()`` method does not have ``EXCLUSIVE_LOCKS_REQUIRED``, so the
+The ``depositImpl()`` method does not have ``REQUIRES``, so the
analysis issues a warning. Thread safety analysis is not inter-procedural, so
caller requirements must be explicitly declared.
There is also a warning in ``transferFrom()``, because although the method
locks ``this->mu``, it does not lock ``b.mu``. The analysis understands
-that these are two separate mutexes, in two different objects.
+that these are two separate mutexes, in two different objects.
Finally, there is a warning in the ``withdraw()`` method, because it fails to
unlock ``mu``. Every lock must have a corresponding unlock, and the analysis
will detect both double locks, and double unlocks. A function is allowed to
acquire a lock without releasing it, (or vice versa), but it must be annotated
-as such (using ``LOCK``/``UNLOCK_FUNCTION``).
+as such (using ``ACQUIRE``/``RELEASE``).
Running The Analysis
@@ -90,7 +90,7 @@ To run the analysis, simply compile with the ``-Wthread-safety`` flag, e.g.
Note that this example assumes the presence of a suitably annotated
:ref:`mutexheader` that declares which methods perform locking,
-unlocking, and so on.
+unlocking, and so on.
Basic Concepts: Capabilities
@@ -106,14 +106,14 @@ Capabilities are associated with named C++ objects which declare specific
methods to acquire and release the capability. The name of the object serves
to identify the capability. The most common example is a mutex. For example,
if ``mu`` is a mutex, then calling ``mu.Lock()`` causes the calling thread
-to acquire the capability to access data that is protected by ``mu``. Similarly,
+to acquire the capability to access data that is protected by ``mu``. Similarly,
calling ``mu.Unlock()`` releases that capability.
A thread may hold a capability either *exclusively* or *shared*. An exclusive
capability can be held by only one thread at a time, while a shared capability
can be held by many threads at the same time. This mechanism enforces a
multiple-reader, single-writer pattern. Write operations to protected data
-require exclusive access, while read operations require only shared access.
+require exclusive access, while read operations require only shared access.
At any given moment during program execution, a thread holds a specific set of
capabilities (e.g. the set of mutexes that it has locked.) These act like keys
@@ -121,7 +121,7 @@ or tokens that allow the thread to access a given resource. Just like physical
security keys, a thread cannot make copy of a capability, nor can it destroy
one. A thread can only release a capability to another thread, or acquire one
from another thread. The annotations are deliberately agnostic about the
-exact mechanism used to acquire and release capabilities; it assumes that the
+exact mechanism used to acquire and release capabilities; it assumes that the
underlying implementation (e.g. the Mutex implementation) does the handoff in
an appropriate manner.
@@ -144,6 +144,11 @@ and data members. Users are *strongly advised* to define macros for the various
attributes; example definitions can be found in :ref:`mutexheader`, below.
The following documentation assumes the use of macros.
+For historical reasons, prior versions of thread safety used macro names that
+were very lock-centric. These macros have since been renamed to fit a more
+general capability model. The prior names are still in use, and will be
+mentioned under the tag *previously* where appropriate.
+
GUARDED_BY(c) and PT_GUARDED_BY(c)
----------------------------------
@@ -154,47 +159,49 @@ require shared access, while write operations require exclusive access.
``PT_GUARDED_BY`` is similar, but is intended for use on pointers and smart
pointers. There is no constraint on the data member itself, but the *data that
-it points to* is protected by the given capability.
+it points to* is protected by the given capability.
.. code-block:: c++
Mutex mu;
- int *p1 GUARDED_BY(mu);
- int *p2 PT_GUARDED_BY(mu);
- unique_ptr<int> p3 PT_GUARDED_BY(mu);
-
+ int *p1 GUARDED_BY(mu);
+ int *p2 PT_GUARDED_BY(mu);
+ unique_ptr<int> p3 PT_GUARDED_BY(mu);
+
void test() {
p1 = 0; // Warning!
-
- p2 = new int; // OK.
+
*p2 = 42; // Warning!
-
- p3.reset(new int); // OK.
+ p2 = new int; // OK.
+
*p3 = 42; // Warning!
+ p3.reset(new int); // OK.
}
-EXCLUSIVE_LOCKS_REQUIRED(...), SHARED_LOCKS_REQUIRED(...)
----------------------------------------------------------
+REQUIRES(...), REQUIRES_SHARED(...)
+-----------------------------------
+
+*Previously*: ``EXCLUSIVE_LOCKS_REQUIRED``, ``SHARED_LOCKS_REQUIRED``
-``EXCLUSIVE_LOCKS_REQUIRED`` is an attribute on functions or methods, which
+``REQUIRES`` is an attribute on functions or methods, which
declares that the calling thread must have exclusive access to the given
capabilities. More than one capability may be specified. The capabilities
-must be held on entry to the function, *and must still be held on exit*.
+must be held on entry to the function, *and must still be held on exit*.
-``SHARED_LOCKS_REQUIRED`` is similar, but requires only shared access.
+``REQUIRES_SHARED`` is similar, but requires only shared access.
.. code-block:: c++
Mutex mu1, mu2;
int a GUARDED_BY(mu1);
int b GUARDED_BY(mu2);
-
- void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) {
+
+ void foo() REQUIRES(mu1, mu2) {
a = 0;
b = 0;
}
-
+
void test() {
mu1.Lock();
foo(); // Warning! Requires mu2.
@@ -202,32 +209,36 @@ must be held on entry to the function, *and must still be held on exit*.
}
-EXCLUSIVE_LOCK_FUNCTION(...), SHARED_LOCK_FUNCTION(...), UNLOCK_FUNCTION(...)
------------------------------------------------------------------------------
+ACQUIRE(...), ACQUIRE_SHARED(...), RELEASE(...), RELEASE_SHARED(...)
+--------------------------------------------------------------------
+
+*Previously*: ``EXCLUSIVE_LOCK_FUNCTION``, ``SHARED_LOCK_FUNCTION``,
+``UNLOCK_FUNCTION``
-``EXCLUSIVE_LOCK_FUNCTION`` is an attribute on functions or methods, which
+``ACQUIRE`` is an attribute on functions or methods, which
declares that the function acquires a capability, but does not release it. The
caller must not hold the given capability on entry, and it will hold the
-capability on exit. ``SHARED_LOCK_FUNCTION`` is similar.
+capability on exit. ``ACQUIRE_SHARED`` is similar.
-``UNLOCK_FUNCTION`` declares that the function releases the given capability.
-The caller must hold the capability on entry, and will no longer hold it on
-exit. It does not matter whether the given capability is shared or exclusive.
+``RELEASE`` and ``RELEASE_SHARED`` declare that the function releases the given
+capability. The caller must hold the capability on entry, and will no longer
+hold it on exit. It does not matter whether the given capability is shared or
+exclusive.
.. code-block:: c++
Mutex mu;
MyClass myObject GUARDED_BY(mu);
-
- void lockAndInit() EXCLUSIVE_LOCK_FUNCTION(mu) {
+
+ void lockAndInit() ACQUIRE(mu) {
mu.Lock();
myObject.init();
}
-
- void cleanupAndUnlock() UNLOCK_FUNCTION(mu) {
+
+ void cleanupAndUnlock() RELEASE(mu) {
myObject.cleanup();
- } // Warning! Need to unlock mu.
-
+ } // Warning! Need to unlock mu.
+
void test() {
lockAndInit();
myObject.doSomething();
@@ -235,27 +246,27 @@ exit. It does not matter whether the given capability is shared or exclusive.
myObject.doSomething(); // Warning, mu is not locked.
}
-If no argument is passed to ``(UN)LOCK_FUNCTION``, then the argument is assumed
-to be ``this``, and the analysis will not check the body of the function. This
-pattern is intended for use by classes which hide locking details behind an
-abstract interface. E.g.
+If no argument is passed to ``ACQUIRE`` or ``RELEASE``, then the argument is
+assumed to be ``this``, and the analysis will not check the body of the
+function. This pattern is intended for use by classes which hide locking
+details behind an abstract interface. For example:
.. code-block:: c++
template <class T>
- class LOCKABLE Container {
+ class CAPABILITY("mutex") Container {
private:
Mutex mu;
T* data;
-
+
public:
// Hide mu from public interface.
- void Lock() EXCLUSIVE_LOCK_FUNCTION() { mu.Lock(); }
- void Unlock() UNLOCK_FUNCTION() { mu.Unlock(); }
-
+ void Lock() ACQUIRE() { mu.Lock(); }
+ void Unlock() RELEASE() { mu.Unlock(); }
+
T& getElem(int i) { return data[i]; }
};
-
+
void test() {
Container<int> c;
c.Lock();
@@ -264,33 +275,36 @@ abstract interface. E.g.
}
-LOCKS_EXCLUDED(...)
--------------------
+EXCLUDES(...)
+-------------
+
+*Previously*: ``LOCKS_EXCLUDED``
-``LOCKS_EXCLUDED`` is an attribute on functions or methods, which declares that
+``EXCLUDES`` is an attribute on functions or methods, which declares that
the caller must *not* hold the given capabilities. This annotation is
used to prevent deadlock. Many mutex implementations are not re-entrant, so
-deadlock can occur if the function in question acquires the mutex a second time.
+deadlock can occur if the function acquires the mutex a second time.
.. code-block:: c++
Mutex mu;
int a GUARDED_BY(mu);
-
- void clear() LOCKS_EXCLUDED(mu) {
+
+ void clear() EXCLUDES(mu) {
mu.Lock();
a = 0;
mu.Unlock();
}
-
+
void reset() {
mu.Lock();
clear(); // Warning! Caller cannot hold 'mu'.
mu.Unlock();
}
-Unlike ``LOCKS_REQUIRED``, ``LOCKS_EXCLUDED`` is optional. The analysis will
-not issue a warning if the attribute is missing. See :ref:`limitations`.
+Unlike ``REQUIRES``, ``EXCLUDES`` is optional. The analysis will not issue a
+warning if the attribute is missing, which can lead to false negatives in some
+cases. This issue is discussed further in :ref:`negative`.
NO_THREAD_SAFETY_ANALYSIS
@@ -307,16 +321,23 @@ thread-safe, but too complicated for the analysis to understand. Reasons for
class Counter {
Mutex mu;
int a GUARDED_BY(mu);
-
+
void unsafeIncrement() NO_THREAD_SAFETY_ANALYSIS { a++; }
};
+Unlike the other attributes, NO_THREAD_SAFETY_ANALYSIS is not part of the
+interface of a function, and should thus be placed on the function definition
+(in the ``.cc`` or ``.cpp`` file) rather than on the function declaration
+(in the header).
-LOCK_RETURNED(c)
-----------------
-``LOCK_RETURNED`` is an attribute on functions or methods, which declares that
-the function returns a reference to the given capability. It is used to
+RETURN_CAPABILITY(c)
+--------------------
+
+*Previously*: ``LOCK_RETURNED``
+
+``RETURN_CAPABILITY`` is an attribute on functions or methods, which declares
+that the function returns a reference to the given capability. It is used to
annotate getter methods that return mutexes.
.. code-block:: c++
@@ -325,12 +346,12 @@ annotate getter methods that return mutexes.
private:
Mutex mu;
int a GUARDED_BY(mu);
-
+
public:
- Mutex* getMu() LOCK_RETURNED(mu) { return &mu; }
-
+ Mutex* getMu() RETURN_CAPABILITY(mu) { return &mu; }
+
// analysis knows that getMu() == mu
- void clear() EXCLUSIVE_LOCKS_REQUIRED(getMu()) { a = 0; }
+ void clear() REQUIRES(getMu()) { a = 0; }
};
@@ -346,11 +367,11 @@ acquired, in order to prevent deadlock.
Mutex m1;
Mutex m2 ACQUIRED_AFTER(m1);
-
+
// Alternative declaration
// Mutex m2;
// Mutex m1 ACQUIRED_BEFORE(m2);
-
+
void foo() {
m2.Lock();
m1.Lock(); // Warning! m2 must be acquired after m1.
@@ -359,36 +380,45 @@ acquired, in order to prevent deadlock.
}
-LOCKABLE
---------
+CAPABILITY(<string>)
+--------------------
-``LOCKABLE`` is an attribute on classes, which specifies that objects of the
-class can be used as a capability. See the ``Container`` example given above,
-or the ``Mutex`` class in :ref:`mutexheader`.
+*Previously*: ``LOCKABLE``
+``CAPABILITY`` is an attribute on classes, which specifies that objects of the
+class can be used as a capability. The string argument specifies the kind of
+capability in error messages, e.g. ``"mutex"``. See the ``Container`` example
+given above, or the ``Mutex`` class in :ref:`mutexheader`.
-SCOPED_LOCKABLE
----------------
-``SCOPED_LOCKABLE`` is an attribute on classes that implement RAII-style
+SCOPED_CAPABILITY
+-----------------
+
+*Previously*: ``SCOPED_LOCKABLE``
+
+``SCOPED_CAPABILITY`` is an attribute on classes that implement RAII-style
locking, in which a capability is acquired in the constructor, and released in
the destructor. Such classes require special handling because the constructor
and destructor refer to the capability via different names; see the
``MutexLocker`` class in :ref:`mutexheader`, below.
-EXCLUSIVE_TRYLOCK_FUNCTION(<bool>, ...), SHARED_TRYLOCK_FUNCTION(<bool>, ...)
------------------------------------------------------------------------------
+TRY_ACQUIRE(<bool>, ...), TRY_ACQUIRE_SHARED(<bool>, ...)
+---------------------------------------------------------
+
+*Previously:* ``EXCLUSIVE_TRYLOCK_FUNCTION``, ``SHARED_TRYLOCK_FUNCTION``
These are attributes on a function or method that tries to acquire the given
capability, and returns a boolean value indicating success or failure.
The first argument must be ``true`` or ``false``, to specify which return value
indicates success, and the remaining arguments are interpreted in the same way
-as ``(UN)LOCK_FUNCTION``. See :ref:`mutexheader`, below, for example uses.
+as ``ACQUIRE``. See :ref:`mutexheader`, below, for example uses.
-ASSERT_EXCLUSIVE_LOCK(...) and ASSERT_SHARED_LOCK(...)
-------------------------------------------------------
+ASSERT_CAPABILITY(...) and ASSERT_SHARED_CAPABILITY(...)
+--------------------------------------------------------
+
+*Previously:* ``ASSERT_EXCLUSIVE_LOCK``, ``ASSERT_SHARED_LOCK``
These are attributes on a function or method that does a run-time test to see
whether the calling thread holds the given capability. The function is assumed
@@ -410,13 +440,104 @@ Warning flags
+ ``-Wthread-safety-attributes``: Sanity checks on attribute syntax.
+ ``-Wthread-safety-analysis``: The core analysis.
+ ``-Wthread-safety-precise``: Requires that mutex expressions match precisely.
- This warning can be disabled for code which has a lot of aliases.
+ This warning can be disabled for code which has a lot of aliases.
+ + ``-Wthread-safety-reference``: Checks when guarded members are passed by reference.
+
+
+:ref:`negative` are an experimental feature, which are enabled with:
+
+* ``-Wthread-safety-negative``: Negative capabilities. Off by default.
When new features and checks are added to the analysis, they can often introduce
additional warnings. Those warnings are initially released as *beta* warnings
-for a period of time, after which they are migrated to the standard analysis.
+for a period of time, after which they are migrated into the standard analysis.
+
+* ``-Wthread-safety-beta``: New features. Off by default.
+
+
+.. _negative:
-* ``-Wthread-safety-beta``: New features. Off by default.
+Negative Capabilities
+=====================
+
+Thread Safety Analysis is designed to prevent both race conditions and
+deadlock. The GUARDED_BY and REQUIRES attributes prevent race conditions, by
+ensuring that a capability is held before reading or writing to guarded data,
+and the EXCLUDES attribute prevents deadlock, by making sure that a mutex is
+*not* held.
+
+However, EXCLUDES is an optional attribute, and does not provide the same
+safety guarantee as REQUIRES. In particular:
+
+ * A function which acquires a capability does not have to exclude it.
+ * A function which calls a function that excludes a capability does not
+ have transitively exclude that capability.
+
+As a result, EXCLUDES can easily produce false negatives:
+
+.. code-block:: c++
+
+ class Foo {
+ Mutex mu;
+
+ void foo() {
+ mu.Lock();
+ bar(); // No warning.
+ baz(); // No warning.
+ mu.Unlock();
+ }
+
+ void bar() { // No warning. (Should have EXCLUDES(mu)).
+ mu.Lock();
+ // ...
+ mu.Unlock();
+ }
+
+ void baz() {
+ bif(); // No warning. (Should have EXCLUDES(mu)).
+ }
+
+ void bif() EXCLUDES(mu);
+ };
+
+
+Negative requirements are an alternative EXCLUDES that provide
+a stronger safety guarantee. A negative requirement uses the REQUIRES
+attribute, in conjunction with the ``!`` operator, to indicate that a capability
+should *not* be held.
+
+For example, using ``REQUIRES(!mu)`` instead of ``EXCLUDES(mu)`` will produce
+the appropriate warnings:
+
+.. code-block:: c++
+
+ class FooNeg {
+ Mutex mu;
+
+ void foo() REQUIRES(!mu) { // foo() now requires !mu.
+ mu.Lock();
+ bar();
+ baz();
+ mu.Unlock();
+ }
+
+ void bar() {
+ mu.Lock(); // WARNING! Missing REQUIRES(!mu).
+ // ...
+ mu.Unlock();
+ }
+
+ void baz() {
+ bif(); // WARNING! Missing REQUIRES(!mu).
+ }
+
+ void bif() REQUIRES(!mu);
+ };
+
+
+Negative requirements are an experimental feature which is off by default,
+because it will produce many warnings in existing code. It can be enabled
+by passing ``-Wthread-safety-negative``.
.. _faq:
@@ -426,7 +547,10 @@ Frequently Asked Questions
(Q) Should I put attributes in the header file, or in the .cc/.cpp/.cxx file?
-(A) Attributes should always go in the header.
+(A) Attributes are part of the formal interface of a function, and should
+always go in the header, where they are visible to anything that includes
+the header. Attributes in the .cpp file are not visible outside of the
+immediate translation unit, which leads to false negatives and false positives.
(Q) "*Mutex is not locked on every path through here?*" What does that mean?
@@ -436,7 +560,7 @@ Frequently Asked Questions
.. _limitations:
-Known Limitations
+Known Limitations
=================
Lexical scope
@@ -448,14 +572,14 @@ capabilities must be declared before they can be used in an attribute.
Use-before-declaration is okay within a single class, because attributes are
parsed at the same time as method bodies. (C++ delays parsing of method bodies
until the end of the class.) However, use-before-declaration is not allowed
-between classes, as illustrated below.
+between classes, as illustrated below.
.. code-block:: c++
class Foo;
class Bar {
- void bar(Foo* f) EXCLUSIVE_LOCKS_REQUIRED(f->mu); // Error: mu undeclared.
+ void bar(Foo* f) REQUIRES(f->mu); // Error: mu undeclared.
};
class Foo {
@@ -474,9 +598,9 @@ Thread safety attributes follow normal C++ access restrictions, so if ``mu``
is a private member of ``c``, then it is an error to write ``c.mu`` in an
attribute.
-One workround is to (ab)use the ``LOCK_RETURNED`` attribute to provide a public
-*name* for a private mutex, without actually exposing the underlying mutex.
-For example:
+One workaround is to (ab)use the ``RETURN_CAPABILITY`` attribute to provide a
+public *name* for a private mutex, without actually exposing the underlying
+mutex. For example:
.. code-block:: c++
@@ -486,12 +610,12 @@ For example:
public:
// For thread safety analysis only. Does not actually return mu.
- Mutex* getMu() LOCK_RETURNED(mu) { return 0; }
+ Mutex* getMu() RETURN_CAPABILITY(mu) { return 0; }
- void doSomething() EXCLUSIVE_LOCKS_REQUIRED(mu);
+ void doSomething() REQUIRES(mu);
};
- void doSomethingTwice(MyClass& c) EXCLUSIVE_LOCKS_REQUIRED(c.getMu()) {
+ void doSomethingTwice(MyClass& c) REQUIRES(c.getMu()) {
// The analysis thinks that c.getMu() == c.mu
c.doSomething();
c.doSomething();
@@ -506,43 +630,6 @@ as a fake getter method, which is provided only for the benefit of thread
safety analysis.
-False negatives on pass by reference.
--------------------------------------
-
-The current version of the analysis only checks operations which refer to
-guarded data members directly by name. If the data members are accessed
-indirectly, via a pointer or reference, then no warning is generated. Thus,
-no warnings will be generated for the following code:
-
-.. code-block:: c++
-
- Mutex mu;
- int a GUARDED_BY(mu);
-
- void clear(int& ra) { ra = 0; }
-
- void test() {
- int *p = &a;
- *p = 0; // No warning. *p is an alias to a.
-
- clear(a); // No warning. 'a' is passed by reference.
- }
-
-This issue is by far the biggest source of false negatives in the current
-version of the analysis. At a fundamental level, the
-false negatives are caused by the fact that annotations are attached to data
-members, rather than types. The type of ``&a`` should really be
-``int GUARDED_BY(mu)*``, rather than ``int*``, and the statement ``p = &a``
-should thus generate a type error. However, attaching attributes to types
-would be an invasive change to the C++ type system, with potential
-ramifications with respect to template instantation, function overloading,
-and so on. Thus, a complete solution to this issue is simply not feasible.
-
-Future versions of the analysis will include better support for pointer
-alias analysis, along with limited checking of guarded types, in order to
-reduce the number of false negatives.
-
-
.. _conditional_locks:
No conditionally held locks.
@@ -557,7 +644,7 @@ generate spurious warnings (false positives). For example:
void foo() {
bool b = needsToLock();
if (b) mu.Lock();
- ... // Warning! Mutex 'mu' is not held on every path through here.
+ ... // Warning! Mutex 'mu' is not held on every path through here.
if (b) mu.Unlock();
}
@@ -567,7 +654,7 @@ No checking inside constructors and destructors.
The analysis currently does not do any checking inside constructors or
destructors. In other words, every constructor and destructor is treated as
-if it was annotated with ``NO_THREAD_SAFETY_ANALYSIS``.
+if it was annotated with ``NO_THREAD_SAFETY_ANALYSIS``.
The reason for this is that during initialization, only one thread typically
has access to the object which is being initialized, and it is thus safe (and
common practice) to initialize guarded members without acquiring any locks.
@@ -577,15 +664,15 @@ Ideally, the analysis would allow initialization of guarded members inside the
object being initialized or destroyed, while still enforcing the usual access
restrictions on everything else. However, this is difficult to enforce in
practice, because in complex pointer-based data structures, it is hard to
-determine what data is "owned by" the enclosing object.
+determine what data is owned by the enclosing object.
No inlining.
------------
Thread safety analysis is strictly intra-procedural, just like ordinary type
checking. It relies only on the declared attributes of a function, and will
-not attempt to "step inside", or inline any method calls. As a result, code
-such as the following will not work:
+not attempt to inline any method calls. As a result, code such as the
+following will not work:
.. code-block:: c++
@@ -593,7 +680,7 @@ such as the following will not work:
class AutoCleanup {
T* object;
void (T::*mp)();
-
+
public:
AutoCleanup(T* obj, void (T::*imp)()) : object(obj), mp(imp) { }
~AutoCleanup() { (object->*mp)(); }
@@ -602,8 +689,8 @@ such as the following will not work:
Mutex mu;
void foo() {
mu.Lock();
- AutoCleanup<Mutex>(&mu, &Mutex::Unlock);
- ...
+ AutoCleanup<Mutex>(&mu, &Mutex::Unlock);
+ // ...
} // Warning, mu is not unlocked.
In this case, the destructor of ``Autocleanup`` calls ``mu.Unlock()``, so
@@ -611,42 +698,14 @@ the warning is bogus. However,
thread safety analysis cannot see the unlock, because it does not attempt to
inline the destructor. Moreover, there is no way to annotate the destructor,
because the destructor is calling a function that is not statically known.
-This pattern is simply not supported.
-
-
-LOCKS_EXCLUDED is not transitive.
----------------------------------
-
-A function which calls a method marked with LOCKS_EXCLUDED is not required to
-put LOCKS_EXCLUDED in its own interface. LOCKS_EXCLUDED behaves differently
-from LOCKS_REQUIRED in this respect, and it can result in false negatives:
-
-.. code-block:: c++
-
- class Foo {
- Mutex mu;
-
- void foo() {
- mu.Lock();
- bar(); // No warning
- mu.Unlock();
- }
-
- void bar() { baz(); } // No warning. (Should have LOCKS_EXCLUDED(mu).)
-
- void baz() LOCKS_EXCLUDED(mu);
- };
-
-The lack of transitivity is due to the fact that LOCKS_EXCLUDED can easily
-break encapsulation; it would be a bad idea to require functions to list the
-names private locks which happen to be acquired internally.
+This pattern is simply not supported.
No alias analysis.
------------------
The analysis currently does not track pointer aliases. Thus, there can be
-false positives if two pointers both point to the same mutex.
+false positives if two pointers both point to the same mutex.
.. code-block:: c++
@@ -655,13 +714,13 @@ false positives if two pointers both point to the same mutex.
Mutex* mu;
public:
- MutexUnlocker(Mutex* m) UNLOCK_FUNCTION(m) : mu(m) { mu->Unlock(); }
- ~MutexUnlocker() EXCLUSIVE_LOCK_FUNCTION(mu) { mu->Lock(); }
+ MutexUnlocker(Mutex* m) RELEASE(m) : mu(m) { mu->Unlock(); }
+ ~MutexUnlocker() ACQUIRE(mu) { mu->Lock(); }
};
Mutex mutex;
- void test() EXCLUSIVE_LOCKS_REQUIRED(mutex) {
- {
+ void test() REQUIRES(mutex) {
+ {
MutexUnlocker munl(&mutex); // unlocks mutex
doSomeIO();
} // Warning: locks munl.mu
@@ -669,14 +728,14 @@ false positives if two pointers both point to the same mutex.
The MutexUnlocker class is intended to be the dual of the MutexLocker class,
defined in :ref:`mutexheader`. However, it doesn't work because the analysis
-doesn't know that munl.mu == mutex. The SCOPED_LOCKABLE attribute handles
-aliasing
+doesn't know that munl.mu == mutex. The SCOPED_CAPABILITY attribute handles
+aliasing for MutexLocker, but does so only for that particular pattern.
ACQUIRED_BEFORE(...) and ACQUIRED_AFTER(...) are currently unimplemented.
-------------------------------------------------------------------------
-To be fixed in a future update.
+To be fixed in a future update.
.. _mutexheader:
@@ -688,14 +747,15 @@ Thread safety analysis can be used with any threading library, but it does
require that the threading API be wrapped in classes and methods which have the
appropriate annotations. The following code provides ``mutex.h`` as an example;
these methods should be filled in to call the appropriate underlying
-implementation.
+implementation.
.. code-block:: c++
+
#ifndef THREAD_SAFETY_ANALYSIS_MUTEX_H
#define THREAD_SAFETY_ANALYSIS_MUTEX_H
-
+
// Enable thread safety attributes only with clang.
// The attributes can be safely erased when compiling with other compilers.
#if defined(__clang__) && (!defined(SWIG))
@@ -703,116 +763,185 @@ implementation.
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
-
+
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
-
+
+ #define CAPABILITY(x) \
+ THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+ #define SCOPED_CAPABILITY \
+ THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
#define GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
-
- #define GUARDED_VAR \
- THREAD_ANNOTATION_ATTRIBUTE__(guarded)
-
+
#define PT_GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
-
- #define PT_GUARDED_VAR \
- THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded)
-
- #define ACQUIRED_AFTER(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
-
+
#define ACQUIRED_BEFORE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
-
- #define EXCLUSIVE_LOCKS_REQUIRED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
-
- #define SHARED_LOCKS_REQUIRED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
-
- #define LOCKS_EXCLUDED(...) \
+
+ #define ACQUIRED_AFTER(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+ #define REQUIRES(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
+
+ #define REQUIRES_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
+
+ #define ACQUIRE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
+
+ #define ACQUIRE_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
+
+ #define RELEASE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
+
+ #define RELEASE_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
+
+ #define TRY_ACQUIRE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
+
+ #define TRY_ACQUIRE_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
+
+ #define EXCLUDES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
-
- #define LOCK_RETURNED(x) \
+
+ #define ASSERT_CAPABILITY(x) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
+
+ #define ASSERT_SHARED_CAPABILITY(x) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
+
+ #define RETURN_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
-
- #define LOCKABLE \
- THREAD_ANNOTATION_ATTRIBUTE__(lockable)
-
- #define SCOPED_LOCKABLE \
- THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
-
- #define EXCLUSIVE_LOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
-
- #define SHARED_LOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
-
- #define ASSERT_EXCLUSIVE_LOCK(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
-
- #define ASSERT_SHARED_LOCK(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
-
- #define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
-
- #define SHARED_TRYLOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
-
- #define UNLOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
-
+
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
-
-
+
+
// Defines an annotated interface for mutexes.
// These methods can be implemented to use any internal mutex implementation.
- class LOCKABLE Mutex {
+ class CAPABILITY("mutex") Mutex {
public:
// Acquire/lock this mutex exclusively. Only one thread can have exclusive
// access at any one time. Write operations to guarded data require an
// exclusive lock.
- void Lock() EXCLUSIVE_LOCK_FUNCTION();
-
+ void Lock() ACQUIRE();
+
// Acquire/lock this mutex for read operations, which require only a shared
// lock. This assumes a multiple-reader, single writer semantics. Multiple
- // threads may acquire the mutex simultaneously as readers, but a writer must
- // wait for all of them to release the mutex before it can acquire it
- // exclusively.
- void ReaderLock() SHARED_LOCK_FUNCTION();
-
- // Release/unlock the mutex, regardless of whether it is exclusive or shared.
- void Unlock() UNLOCK_FUNCTION();
-
+ // threads may acquire the mutex simultaneously as readers, but a writer
+ // must wait for all of them to release the mutex before it can acquire it
+ // exclusively.
+ void ReaderLock() ACQUIRE_SHARED();
+
+ // Release/unlock an exclusive mutex.
+ void Unlock() RELEASE();
+
+ // Release/unlock a shared mutex.
+ void ReaderUnlock() RELEASE_SHARED();
+
// Try to acquire the mutex. Returns true on success, and false on failure.
- bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true);
-
+ bool TryLock() TRY_ACQUIRE(true);
+
// Try to acquire the mutex for read operations.
- bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true);
-
+ bool ReaderTryLock() TRY_ACQUIRE_SHARED(true);
+
// Assert that this mutex is currently held by the calling thread.
- void AssertHeld() ASSERT_EXCLUSIVE_LOCK();
-
- // Assert that is mutex is currently held for read operations.
- void AssertReaderHeld() ASSERT_SHARED_LOCK();
+ void AssertHeld() ASSERT_CAPABILITY(this);
+
+ // Assert that is mutex is currently held for read operations.
+ void AssertReaderHeld() ASSERT_SHARED_CAPABILITY(this);
};
-
-
+
+
// MutexLocker is an RAII class that acquires a mutex in its constructor, and
- // releases it in its destructor.
- class SCOPED_LOCKABLE MutexLocker {
+ // releases it in its destructor.
+ class SCOPED_CAPABILITY MutexLocker {
private:
Mutex* mut;
-
+
public:
- MutexLocker(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mut(mu) {
+ MutexLocker(Mutex *mu) ACQUIRE(mu) : mut(mu) {
mu->Lock();
- }
- ~MutexLocker() UNLOCK_FUNCTION() {
+ }
+ ~MutexLocker() RELEASE() {
mut->Unlock();
}
};
-
+
+
+ #ifdef USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES
+ // The original version of thread safety analysis the following attribute
+ // definitions. These use a lock-based terminology. They are still in use
+ // by existing thread safety code, and will continue to be supported.
+
+ // Deprecated.
+ #define PT_GUARDED_VAR \
+ THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded)
+
+ // Deprecated.
+ #define GUARDED_VAR \
+ THREAD_ANNOTATION_ATTRIBUTE__(guarded)
+
+ // Replaced by REQUIRES
+ #define EXCLUSIVE_LOCKS_REQUIRED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+
+ // Replaced by REQUIRES_SHARED
+ #define SHARED_LOCKS_REQUIRED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+
+ // Replaced by CAPABILITY
+ #define LOCKABLE \
+ THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+
+ // Replaced by SCOPED_CAPABILITY
+ #define SCOPED_LOCKABLE \
+ THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+ // Replaced by ACQUIRE
+ #define EXCLUSIVE_LOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+
+ // Replaced by ACQUIRE_SHARED
+ #define SHARED_LOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+
+ // Replaced by RELEASE and RELEASE_SHARED
+ #define UNLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+
+ // Replaced by TRY_ACQUIRE
+ #define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+
+ // Replaced by TRY_ACQUIRE_SHARED
+ #define SHARED_TRYLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+
+ // Replaced by ASSERT_CAPABILITY
+ #define ASSERT_EXCLUSIVE_LOCK(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
+
+ // Replaced by ASSERT_SHARED_CAPABILITY
+ #define ASSERT_SHARED_LOCK(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
+
+ // Replaced by EXCLUDE_CAPABILITY.
+ #define LOCKS_EXCLUDED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+ // Replaced by RETURN_CAPABILITY
+ #define LOCK_RETURNED(x) \
+ THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+ #endif // USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES
+
#endif // THREAD_SAFETY_ANALYSIS_MUTEX_H
+
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index 90f16ee0d431..fc5af4ecd5b1 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -73,7 +73,7 @@ Basic Usage
Intro to how to use a C compiler for newbies.
compile + link compile then link debug info enabling optimizations
-picking a language to use, defaults to C99 by default. Autosenses based
+picking a language to use, defaults to C11 by default. Autosenses based
on extension. using a makefile
Command Line Options
@@ -481,7 +481,7 @@ TODO: Generate this from tblgen. Define one anchor per warning group.
Warn about an unusable copy constructor when binding a reference to a
temporary.
- This option, which defaults to on, enables warnings about binding a
+ This option enables warnings about binding a
reference to a temporary when the temporary doesn't have a usable
copy constructor. For example:
@@ -531,8 +531,6 @@ control the crash diagnostics.
The -fno-crash-diagnostics flag can be helpful for speeding the process
of generating a delta reduced test case.
-.. _opt_rpass:
-
Options to Emit Optimization Reports
------------------------------------
@@ -979,6 +977,8 @@ are listed below.
- ``-fsanitize=function``: Indirect call of a function through a
function pointer of the wrong type (Linux, C++ and x86/x86_64 only).
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
+ - ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
+ parameter which is declared to never be null.
- ``-fsanitize=null``: Use of a null pointer or creation of a null
reference.
- ``-fsanitize=object-size``: An attempt to use bytes which the
@@ -988,6 +988,8 @@ are listed below.
more problems at higher optimization levels.
- ``-fsanitize=return``: In C++, reaching the end of a
value-returning function without returning a value.
+ - ``-fsanitize=returns-nonnull-attribute``: Returning null pointer
+ from a function which is declared to never return null.
- ``-fsanitize=shift``: Shift operators where the amount shifted is
greater or equal to the promoted bit-width of the left hand side
or less than zero, or where the left hand side is negative. For a
@@ -1031,10 +1033,6 @@ are listed below.
Extra features of UndefinedBehaviorSanitizer:
- - ``-fno-sanitize-recover``: By default, after a sanitizer diagnoses
- an issue, it will attempt to continue executing the program if there
- is a reasonable behavior it can give to the faulting operation. This
- option causes the program to abort instead.
- ``-fsanitize-undefined-trap-on-error``: Causes traps to be emitted
rather than calls to runtime libraries when a problem is detected.
This option is intended for use in cases where the sanitizer runtime
@@ -1054,6 +1052,17 @@ are listed below.
program. The ``-fsanitize=undefined`` checks can be combined with other
sanitizers.
+**-f[no-]sanitize-recover=check1,check2,...**
+
+ Controls which checks enabled by ``-fsanitize=`` flag are non-fatal.
+ If the check is fatal, program will halt after the first error
+ of this kind is detected and error report is printed.
+
+ By default, non-fatal checks are those enabled by UndefinedBehaviorSanitizer,
+ except for ``-fsanitize=return`` and ``-fsanitize=unreachable``. Some
+ sanitizers (e.g. :doc:`AddressSanitizer`) may not support recovery,
+ and always crash the program after the issue is detected.
+
.. option:: -fno-assume-sane-operator-new
Don't assume that the C++'s new operator is sane.
@@ -1113,6 +1122,37 @@ are listed below.
This option restricts the generated code to use general registers
only. This only applies to the AArch64 architecture.
+**-f[no-]max-unknown-pointer-align=[number]**
+ Instruct the code generator to not enforce a higher alignment than the given
+ number (of bytes) when accessing memory via an opaque pointer or reference.
+ This cap is ignored when directly accessing a variable or when the pointee
+ type has an explicit “aligned” attribute.
+
+ The value should usually be determined by the properties of the system allocator.
+ Some builtin types, especially vector types, have very high natural alignments;
+ when working with values of those types, Clang usually wants to use instructions
+ that take advantage of that alignment. However, many system allocators do
+ not promise to return memory that is more than 8-byte or 16-byte-aligned. Use
+ this option to limit the alignment that the compiler can assume for an arbitrary
+ pointer, which may point onto the heap.
+
+ This option does not affect the ABI alignment of types; the layout of structs and
+ unions and the value returned by the alignof operator remain the same.
+
+ This option can be overridden on a case-by-case basis by putting an explicit
+ “aligned” alignment on a struct, union, or typedef. For example:
+
+ .. code-block:: console
+
+ #include <immintrin.h>
+ // Make an aligned typedef of the AVX-512 16-int vector type.
+ typedef __v16si __aligned_v16si __attribute__((aligned(64)));
+
+ void initialize_vector(__aligned_v16si *v) {
+ // The compiler may assume that ‘v’ is 64-byte aligned, regardless of the
+ // value of -fmax-unknown-pointer-align.
+ }
+
Profile Guided Optimization
---------------------------
@@ -1441,9 +1481,12 @@ Differences between various standard modes
------------------------------------------
clang supports the -std option, which changes what language mode clang
-uses. The supported modes for C are c89, gnu89, c94, c99, gnu99 and
-various aliases for those modes. If no -std option is specified, clang
-defaults to gnu99 mode.
+uses. The supported modes for C are c89, gnu89, c94, c99, gnu99, c11,
+gnu11, and various aliases for those modes. If no -std option is
+specified, clang defaults to gnu11 mode. Many C99 and C11 features are
+supported in earlier modes as a conforming extension, with a warning. Use
+``-pedantic-errors`` to request an error if a feature from a later standard
+revision is used in an earlier mode.
Differences between all ``c*`` and ``gnu*`` modes:
@@ -1481,6 +1524,11 @@ Differences between ``*89`` and ``*99`` modes:
in ``*89`` modes.
- Some warnings are different.
+Differences between ``*99`` and ``*11`` modes:
+
+- Warnings for use of C11 features are disabled.
+- ``__STDC_VERSION__`` is defined to ``201112L`` rather than ``199901L``.
+
c94 mode is identical to c89 mode except that digraphs are enabled in
c94 mode (FIXME: And ``__STDC_VERSION__`` should be defined!).
@@ -1874,6 +1922,8 @@ Execute ``clang-cl /?`` to see a list of supported options:
/WX Treat warnings as errors
/w Disable all warnings
/Zi Enable debug information
+ /Zp Set the default maximum struct packing alignment to 1
+ /Zp<value> Specify the default maximum struct packing alignment
/Zs Syntax-check only
OPTIONS:
diff --git a/docs/conf.py b/docs/conf.py
index 1963a05385e8..7c2ef2aed0f0 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -48,9 +48,9 @@ copyright = u'2007-2014, The Clang Team'
# built documents.
#
# The short X.Y version.
-version = '3.5'
+version = '3.6'
# The full version, including alpha/beta/rc tags.
-release = '3.5'
+release = '3.6'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/tools/dump_format_style.py b/docs/tools/dump_format_style.py
index 66bad8bb4e7e..fdf03c6244ce 100644
--- a/docs/tools/dump_format_style.py
+++ b/docs/tools/dump_format_style.py
@@ -17,6 +17,7 @@ def substitute(text, tag, contents):
return re.sub(pattern, '%s', text, flags=re.S) % replacement
def doxygen2rst(text):
+ text = re.sub(r'([^/\*])\*', r'\1\\*', text)
text = re.sub(r'<tt>\s*(.*?)\s*<\/tt>', r'``\1``', text)
text = re.sub(r'\\c ([^ ,;\.]+)', r'``\1``', text)
text = re.sub(r'\\\w+ ', '', text)
diff --git a/examples/PrintFunctionNames/PrintFunctionNames.cpp b/examples/PrintFunctionNames/PrintFunctionNames.cpp
index 3f18cd45e564..e8a361dbee9a 100644
--- a/examples/PrintFunctionNames/PrintFunctionNames.cpp
+++ b/examples/PrintFunctionNames/PrintFunctionNames.cpp
@@ -36,8 +36,9 @@ public:
class PrintFunctionNamesAction : public PluginASTAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef) {
- return new PrintFunctionsConsumer();
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef) {
+ return llvm::make_unique<PrintFunctionsConsumer>();
}
bool ParseArgs(const CompilerInstance &CI,
diff --git a/examples/clang-interpreter/CMakeLists.txt b/examples/clang-interpreter/CMakeLists.txt
index 3c66881d026b..4c6db12a4e43 100644
--- a/examples/clang-interpreter/CMakeLists.txt
+++ b/examples/clang-interpreter/CMakeLists.txt
@@ -1,7 +1,8 @@
set(LLVM_LINK_COMPONENTS
Core
ExecutionEngine
- JIT
+ MC
+ MCJIT
Support
native
)
diff --git a/examples/clang-interpreter/Makefile b/examples/clang-interpreter/Makefile
index d571337735ea..2eff90b32b05 100644
--- a/examples/clang-interpreter/Makefile
+++ b/examples/clang-interpreter/Makefile
@@ -15,12 +15,14 @@ NO_INSTALL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
-LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter irreader \
+LINK_COMPONENTS := mcjit interpreter nativecodegen bitreader bitwriter irreader \
ipo linker selectiondag asmparser instrumentation objcarcopts option
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
clangAnalysis.a clangRewrite.a clangRewriteFrontend.a \
- clangEdit.a clangAST.a clangLex.a clangBasic.a
+ clangEdit.a clangAST.a clangLex.a clangBasic.a LLVMCore.a \
+ LLVMExecutionEngine.a LLVMMC.a LLVMMCJIT.a LLVMRuntimeDyld.a \
+ LLVMObject.a LLVMSupport.a LLVMProfileData.a
include $(CLANG_LEVEL)/Makefile
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index 8b8ccfdf70a0..9b4a257bcba3 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -18,7 +18,7 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
-#include "llvm/ExecutionEngine/JIT.h"
+#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
@@ -42,18 +42,28 @@ std::string GetExecutablePath(const char *Argv0) {
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}
-static int Execute(llvm::Module *Mod, char * const *envp) {
+static llvm::ExecutionEngine *
+createExecutionEngine(std::unique_ptr<llvm::Module> M, std::string *ErrorStr) {
+ return llvm::EngineBuilder(std::move(M))
+ .setEngineKind(llvm::EngineKind::Either)
+ .setErrorStr(ErrorStr)
+ .create();
+}
+
+static int Execute(std::unique_ptr<llvm::Module> Mod, char *const *envp) {
llvm::InitializeNativeTarget();
+ llvm::InitializeNativeTargetAsmPrinter();
+ llvm::Module &M = *Mod;
std::string Error;
std::unique_ptr<llvm::ExecutionEngine> EE(
- llvm::ExecutionEngine::create(Mod, /*ForceInterpreter*/ false, &Error));
+ createExecutionEngine(std::move(Mod), &Error));
if (!EE) {
llvm::errs() << "unable to make execution engine: " << Error << "\n";
return 255;
}
- llvm::Function *EntryFn = Mod->getFunction("main");
+ llvm::Function *EntryFn = M.getFunction("main");
if (!EntryFn) {
llvm::errs() << "'main' function not found in module.\n";
return 255;
@@ -61,8 +71,9 @@ static int Execute(llvm::Module *Mod, char * const *envp) {
// FIXME: Support passing arguments.
std::vector<std::string> Args;
- Args.push_back(Mod->getModuleIdentifier());
+ Args.push_back(M.getModuleIdentifier());
+ EE->finalizeObject();
return EE->runFunctionAsMain(EntryFn, Args, envp);
}
@@ -75,7 +86,14 @@ int main(int argc, const char **argv, char * const *envp) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
- Driver TheDriver(Path, llvm::sys::getProcessTriple(), Diags);
+
+ // Use ELF on windows for now.
+ std::string TripleStr = llvm::sys::getProcessTriple();
+ llvm::Triple T(TripleStr);
+ if (T.isOSBinFormatCOFF())
+ T.setObjectFormat(llvm::Triple::ELF);
+
+ Driver TheDriver(Path, T.str(), Diags);
TheDriver.setTitle("clang interpreter");
TheDriver.setCheckInputsExist(false);
@@ -101,14 +119,14 @@ int main(int argc, const char **argv, char * const *envp) {
return 1;
}
- const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
- if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
+ const driver::Command &Cmd = cast<driver::Command>(*Jobs.begin());
+ if (llvm::StringRef(Cmd.getCreator().getName()) != "clang") {
Diags.Report(diag::err_fe_expected_clang_command);
return 1;
}
// Initialize a compiler invocation object from the clang (-cc1) arguments.
- const driver::ArgStringList &CCArgs = Cmd->getArguments();
+ const driver::ArgStringList &CCArgs = Cmd.getArguments();
std::unique_ptr<CompilerInvocation> CI(new CompilerInvocation);
CompilerInvocation::CreateFromArgs(*CI,
const_cast<const char **>(CCArgs.data()),
@@ -146,8 +164,8 @@ int main(int argc, const char **argv, char * const *envp) {
return 1;
int Res = 255;
- if (llvm::Module *Module = Act->takeModule())
- Res = Execute(Module, envp);
+ if (std::unique_ptr<llvm::Module> Module = Act->takeModule())
+ Res = Execute(std::move(Module), envp);
// Shutdown.
diff --git a/include/clang-c/BuildSystem.h b/include/clang-c/BuildSystem.h
index ed3e8d9a28b3..7aa01914cf24 100644
--- a/include/clang-c/BuildSystem.h
+++ b/include/clang-c/BuildSystem.h
@@ -11,8 +11,8 @@
|* *|
\*===----------------------------------------------------------------------===*/
-#ifndef CLANG_C_BUILD_SYSTEM_H
-#define CLANG_C_BUILD_SYSTEM_H
+#ifndef LLVM_CLANG_C_BUILDSYSTEM_H
+#define LLVM_CLANG_C_BUILDSYSTEM_H
#include "clang-c/Platform.h"
#include "clang-c/CXErrorCode.h"
diff --git a/include/clang-c/CXCompilationDatabase.h b/include/clang-c/CXCompilationDatabase.h
index fd65418f607c..068a677a95ed 100644
--- a/include/clang-c/CXCompilationDatabase.h
+++ b/include/clang-c/CXCompilationDatabase.h
@@ -12,8 +12,8 @@
|* *|
\*===----------------------------------------------------------------------===*/
-#ifndef CLANG_CXCOMPILATIONDATABASE_H
-#define CLANG_CXCOMPILATIONDATABASE_H
+#ifndef LLVM_CLANG_C_CXCOMPILATIONDATABASE_H
+#define LLVM_CLANG_C_CXCOMPILATIONDATABASE_H
#include "clang-c/Platform.h"
#include "clang-c/CXString.h"
diff --git a/include/clang-c/CXErrorCode.h b/include/clang-c/CXErrorCode.h
index a026c95a5bb9..aff73b746763 100644
--- a/include/clang-c/CXErrorCode.h
+++ b/include/clang-c/CXErrorCode.h
@@ -11,8 +11,8 @@
|* *|
\*===----------------------------------------------------------------------===*/
-#ifndef CLANG_C_CXERRORCODE_H
-#define CLANG_C_CXERRORCODE_H
+#ifndef LLVM_CLANG_C_CXERRORCODE_H
+#define LLVM_CLANG_C_CXERRORCODE_H
#include "clang-c/Platform.h"
diff --git a/include/clang-c/CXString.h b/include/clang-c/CXString.h
index cf198cbf5d0f..a649cdf82fc7 100644
--- a/include/clang-c/CXString.h
+++ b/include/clang-c/CXString.h
@@ -11,8 +11,8 @@
|* *|
\*===----------------------------------------------------------------------===*/
-#ifndef CLANG_CXSTRING_H
-#define CLANG_CXSTRING_H
+#ifndef LLVM_CLANG_C_CXSTRING_H
+#define LLVM_CLANG_C_CXSTRING_H
#include "clang-c/Platform.h"
diff --git a/include/clang-c/Documentation.h b/include/clang-c/Documentation.h
index ad2da0778315..89373b11457d 100644
--- a/include/clang-c/Documentation.h
+++ b/include/clang-c/Documentation.h
@@ -12,8 +12,8 @@
|* *|
\*===----------------------------------------------------------------------===*/
-#ifndef CLANG_C_DOCUMENTATION_H
-#define CLANG_C_DOCUMENTATION_H
+#ifndef LLVM_CLANG_C_DOCUMENTATION_H
+#define LLVM_CLANG_C_DOCUMENTATION_H
#include "clang-c/Index.h"
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index f69f567c2690..ed7bd169f6fc 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -13,8 +13,8 @@
|* *|
\*===----------------------------------------------------------------------===*/
-#ifndef CLANG_C_INDEX_H
-#define CLANG_C_INDEX_H
+#ifndef LLVM_CLANG_C_INDEX_H
+#define LLVM_CLANG_C_INDEX_H
#include <time.h>
@@ -32,7 +32,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 27
+#define CINDEX_VERSION_MINOR 29
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -336,6 +336,12 @@ CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
const char *file_name);
/**
+ * \brief Returns non-zero if the \c file1 and \c file2 point to the same file,
+ * or they are both NULL.
+ */
+CINDEX_LINKAGE int clang_File_isEqual(CXFile file1, CXFile file2);
+
+/**
* @}
*/
@@ -2120,7 +2126,7 @@ enum CXCursorKind {
*/
CXCursor_MSAsmStmt = 229,
- /** \brief The null satement ";": C99 6.8.3p3.
+ /** \brief The null statement ";": C99 6.8.3p3.
*
* This cursor kind is used to describe the null statement.
*/
@@ -2135,7 +2141,7 @@ enum CXCursorKind {
*/
CXCursor_OMPParallelDirective = 232,
- /** \brief OpenMP simd directive.
+ /** \brief OpenMP SIMD directive.
*/
CXCursor_OMPSimdDirective = 233,
@@ -2195,7 +2201,31 @@ enum CXCursorKind {
*/
CXCursor_SEHLeaveStmt = 247,
- CXCursor_LastStmt = CXCursor_SEHLeaveStmt,
+ /** \brief OpenMP ordered directive.
+ */
+ CXCursor_OMPOrderedDirective = 248,
+
+ /** \brief OpenMP atomic directive.
+ */
+ CXCursor_OMPAtomicDirective = 249,
+
+ /** \brief OpenMP for SIMD directive.
+ */
+ CXCursor_OMPForSimdDirective = 250,
+
+ /** \brief OpenMP parallel for SIMD directive.
+ */
+ CXCursor_OMPParallelForSimdDirective = 251,
+
+ /** \brief OpenMP target directive.
+ */
+ CXCursor_OMPTargetDirective = 252,
+
+ /** \brief OpenMP teams directive.
+ */
+ CXCursor_OMPTeamsDirective = 253,
+
+ CXCursor_LastStmt = CXCursor_OMPTeamsDirective,
/**
* \brief Cursor that represents the translation unit itself.
@@ -2228,7 +2258,8 @@ enum CXCursorKind {
CXCursor_CUDADeviceAttr = 413,
CXCursor_CUDAGlobalAttr = 414,
CXCursor_CUDAHostAttr = 415,
- CXCursor_LastAttr = CXCursor_CUDAHostAttr,
+ CXCursor_CUDASharedAttr = 416,
+ CXCursor_LastAttr = CXCursor_CUDASharedAttr,
/* Preprocessing */
CXCursor_PreprocessingDirective = 500,
@@ -2822,6 +2853,7 @@ enum CXCallingConv {
CXCallingConv_IntelOclBicc = 9,
CXCallingConv_X86_64Win64 = 10,
CXCallingConv_X86_64SysV = 11,
+ CXCallingConv_X86VectorCall = 12,
CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200
@@ -2912,6 +2944,124 @@ CINDEX_LINKAGE int clang_Cursor_getNumArguments(CXCursor C);
CINDEX_LINKAGE CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i);
/**
+ * \brief Describes the kind of a template argument.
+ *
+ * See the definition of llvm::clang::TemplateArgument::ArgKind for full
+ * element descriptions.
+ */
+enum CXTemplateArgumentKind {
+ CXTemplateArgumentKind_Null,
+ CXTemplateArgumentKind_Type,
+ CXTemplateArgumentKind_Declaration,
+ CXTemplateArgumentKind_NullPtr,
+ CXTemplateArgumentKind_Integral,
+ CXTemplateArgumentKind_Template,
+ CXTemplateArgumentKind_TemplateExpansion,
+ CXTemplateArgumentKind_Expression,
+ CXTemplateArgumentKind_Pack,
+ /* Indicates an error case, preventing the kind from being deduced. */
+ CXTemplateArgumentKind_Invalid
+};
+
+/**
+ *\brief Returns the number of template args of a function decl representing a
+ * template specialization.
+ *
+ * If the argument cursor cannot be converted into a template function
+ * declaration, -1 is returned.
+ *
+ * For example, for the following declaration and specialization:
+ * template <typename T, int kInt, bool kBool>
+ * void foo() { ... }
+ *
+ * template <>
+ * void foo<float, -7, true>();
+ *
+ * The value 3 would be returned from this call.
+ */
+CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C);
+
+/**
+ * \brief Retrieve the kind of the I'th template argument of the CXCursor C.
+ *
+ * If the argument CXCursor does not represent a FunctionDecl, an invalid
+ * template argument kind is returned.
+ *
+ * For example, for the following declaration and specialization:
+ * template <typename T, int kInt, bool kBool>
+ * void foo() { ... }
+ *
+ * template <>
+ * void foo<float, -7, true>();
+ *
+ * For I = 0, 1, and 2, Type, Integral, and Integral will be returned,
+ * respectively.
+ */
+CINDEX_LINKAGE enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(
+ CXCursor C, unsigned I);
+
+/**
+ * \brief Retrieve a CXType representing the type of a TemplateArgument of a
+ * function decl representing a template specialization.
+ *
+ * If the argument CXCursor does not represent a FunctionDecl whose I'th
+ * template argument has a kind of CXTemplateArgKind_Integral, an invalid type
+ * is returned.
+ *
+ * For example, for the following declaration and specialization:
+ * template <typename T, int kInt, bool kBool>
+ * void foo() { ... }
+ *
+ * template <>
+ * void foo<float, -7, true>();
+ *
+ * If called with I = 0, "float", will be returned.
+ * Invalid types will be returned for I == 1 or 2.
+ */
+CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentType(CXCursor C,
+ unsigned I);
+
+/**
+ * \brief Retrieve the value of an Integral TemplateArgument (of a function
+ * decl representing a template specialization) as a signed long long.
+ *
+ * It is undefined to call this function on a CXCursor that does not represent a
+ * FunctionDecl or whose I'th template argument is not an integral value.
+ *
+ * For example, for the following declaration and specialization:
+ * template <typename T, int kInt, bool kBool>
+ * void foo() { ... }
+ *
+ * template <>
+ * void foo<float, -7, true>();
+ *
+ * If called with I = 1 or 2, -7 or true will be returned, respectively.
+ * For I == 0, this function's behavior is undefined.
+ */
+CINDEX_LINKAGE long long clang_Cursor_getTemplateArgumentValue(CXCursor C,
+ unsigned I);
+
+/**
+ * \brief Retrieve the value of an Integral TemplateArgument (of a function
+ * decl representing a template specialization) as an unsigned long long.
+ *
+ * It is undefined to call this function on a CXCursor that does not represent a
+ * FunctionDecl or whose I'th template argument is not an integral value.
+ *
+ * For example, for the following declaration and specialization:
+ * template <typename T, int kInt, bool kBool>
+ * void foo() { ... }
+ *
+ * template <>
+ * void foo<float, 2147483649, true>();
+ *
+ * If called with I = 1 or 2, 2147483649 or true will be returned, respectively.
+ * For I == 0, this function's behavior is undefined.
+ */
+CINDEX_LINKAGE unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(
+ CXCursor C, unsigned I);
+
+/**
* \brief Determine whether two CXTypes represent the same type.
*
* \returns non-zero if the CXTypes represent the same type and
@@ -3194,6 +3344,29 @@ enum CX_CXXAccessSpecifier {
CINDEX_LINKAGE enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor);
/**
+ * \brief Represents the storage classes as declared in the source. CX_SC_Invalid
+ * was added for the case that the passed cursor in not a declaration.
+ */
+enum CX_StorageClass {
+ CX_SC_Invalid,
+ CX_SC_None,
+ CX_SC_Extern,
+ CX_SC_Static,
+ CX_SC_PrivateExtern,
+ CX_SC_OpenCLWorkGroupLocal,
+ CX_SC_Auto,
+ CX_SC_Register
+};
+
+/**
+ * \brief Returns the storage class for a function or variable declaration.
+ *
+ * If the passed in Cursor is not a function or variable declaration,
+ * CX_SC_Invalid is returned else the storage class.
+ */
+CINDEX_LINKAGE enum CX_StorageClass clang_Cursor_getStorageClass(CXCursor);
+
+/**
* \brief Determine the number of overloaded declarations referenced by a
* \c CXCursor_OverloadedDeclRef cursor.
*
@@ -3631,6 +3804,20 @@ CINDEX_LINKAGE CXString clang_Cursor_getBriefCommentText(CXCursor C);
* @}
*/
+/** \defgroup CINDEX_MANGLE Name Mangling API Functions
+ *
+ * @{
+ */
+
+/**
+ * \brief Retrieve the CXString representing the mangled name of the cursor.
+ */
+CINDEX_LINKAGE CXString clang_Cursor_getMangling(CXCursor);
+
+/**
+ * @}
+ */
+
/**
* \defgroup CINDEX_MODULE Module introspection
*
diff --git a/include/clang-c/Platform.h b/include/clang-c/Platform.h
index 0f866c64563c..e2a4dccbdaf0 100644
--- a/include/clang-c/Platform.h
+++ b/include/clang-c/Platform.h
@@ -11,8 +11,8 @@
|* *|
\*===----------------------------------------------------------------------===*/
-#ifndef CLANG_C_PLATFORM_H
-#define CLANG_C_PLATFORM_H
+#ifndef LLVM_CLANG_C_PLATFORM_H
+#define LLVM_CLANG_C_PLATFORM_H
#ifdef __cplusplus
extern "C" {
diff --git a/include/clang/ARCMigrate/ARCMTActions.h b/include/clang/ARCMigrate/ARCMTActions.h
index b3e74b996678..c830aa3d7874 100644
--- a/include/clang/ARCMigrate/ARCMTActions.h
+++ b/include/clang/ARCMigrate/ARCMTActions.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H
-#define LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H
+#ifndef LLVM_CLANG_ARCMIGRATE_ARCMTACTIONS_H
+#define LLVM_CLANG_ARCMIGRATE_ARCMTACTIONS_H
#include "clang/ARCMigrate/FileRemapper.h"
#include "clang/Frontend/FrontendAction.h"
@@ -37,8 +37,8 @@ class MigrateSourceAction : public ASTFrontendAction {
FileRemapper Remapper;
protected:
bool BeginInvocation(CompilerInstance &CI) override;
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
};
class MigrateAction : public WrapperFrontendAction {
@@ -65,8 +65,8 @@ public:
unsigned migrateAction);
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
bool BeginInvocation(CompilerInstance &CI) override;
};
diff --git a/include/clang/ARCMigrate/FileRemapper.h b/include/clang/ARCMigrate/FileRemapper.h
index e094301ae6c4..53b88e9eb5e5 100644
--- a/include/clang/ARCMigrate/FileRemapper.h
+++ b/include/clang/ARCMigrate/FileRemapper.h
@@ -52,14 +52,14 @@ public:
bool overwriteOriginal(DiagnosticsEngine &Diag,
StringRef outputDir = StringRef());
- void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
+ void remap(StringRef filePath, std::unique_ptr<llvm::MemoryBuffer> memBuf);
void applyMappings(PreprocessorOptions &PPOpts) const;
void clear(StringRef outputDir = StringRef());
private:
- void remap(const FileEntry *file, llvm::MemoryBuffer *memBuf);
+ void remap(const FileEntry *file, std::unique_ptr<llvm::MemoryBuffer> memBuf);
void remap(const FileEntry *file, const FileEntry *newfile);
const FileEntry *getOriginalFile(StringRef filePath);
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 8134f6b080b7..195d748b5be8 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -30,6 +30,7 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SanitizerBlacklist.h"
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
@@ -74,6 +75,15 @@ namespace clang {
class FullComment;
}
+ struct TypeInfo {
+ uint64_t Width;
+ unsigned Align;
+ bool AlignIsRequired : 1;
+ TypeInfo() : Width(0), Align(0), AlignIsRequired(false) {}
+ TypeInfo(uint64_t Width, unsigned Align, bool AlignIsRequired)
+ : Width(Width), Align(Align), AlignIsRequired(AlignIsRequired) {}
+ };
+
/// \brief Holds long-lived AST nodes (such as types and decls) that can be
/// referred to throughout the semantic analysis of a file.
class ASTContext : public RefCountedBase<ASTContext> {
@@ -144,8 +154,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
ObjCLayouts;
/// \brief A cache from types to size and alignment information.
- typedef llvm::DenseMap<const Type*,
- std::pair<uint64_t, unsigned> > TypeInfoMap;
+ typedef llvm::DenseMap<const Type *, struct TypeInfo> TypeInfoMap;
mutable TypeInfoMap MemoizedTypeInfo;
/// \brief A cache mapping from CXXRecordDecls to key functions.
@@ -264,8 +273,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief Declaration for the CUDA cudaConfigureCall function.
FunctionDecl *cudaConfigureCallDecl;
- TypeSourceInfo NullTypeSourceInfo;
-
/// \brief Keeps track of all declaration attributes.
///
/// Since so few decls have attrs, we keep them in a hash map instead of
@@ -384,6 +391,10 @@ private:
/// this ASTContext object.
LangOptions &LangOpts;
+ /// \brief Blacklist object that is used by sanitizers to decide which
+ /// entities should not be instrumented.
+ std::unique_ptr<SanitizerBlacklist> SanitizerBL;
+
/// \brief The allocator used to create AST objects.
///
/// AST objects are never destructed; rather, all memory associated with the
@@ -453,11 +464,12 @@ public:
/// 'NodeT' can be one of Decl, Stmt, Type, TypeLoc,
/// NestedNameSpecifier or NestedNameSpecifierLoc.
template <typename NodeT>
- ParentVector getParents(const NodeT &Node) {
+ ArrayRef<ast_type_traits::DynTypedNode> getParents(const NodeT &Node) {
return getParents(ast_type_traits::DynTypedNode::create(Node));
}
- ParentVector getParents(const ast_type_traits::DynTypedNode &Node);
+ ArrayRef<ast_type_traits::DynTypedNode>
+ getParents(const ast_type_traits::DynTypedNode &Node);
const clang::PrintingPolicy &getPrintingPolicy() const {
return PrintingPolicy;
@@ -508,6 +520,10 @@ public:
const LangOptions& getLangOpts() const { return LangOpts; }
+ const SanitizerBlacklist &getSanitizerBlacklist() const {
+ return *SanitizerBL;
+ }
+
DiagnosticsEngine &getDiagnostics() const;
FullSourceLoc getFullLoc(SourceLocation Loc) const {
@@ -912,6 +928,12 @@ public:
/// \brief Change the result type of a function type once it is deduced.
void adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType);
+ /// \brief Change the exception specification on a function once it is
+ /// delay-parsed, instantiated, or computed.
+ void adjustExceptionSpec(FunctionDecl *FD,
+ const FunctionProtoType::ExceptionSpecInfo &ESI,
+ bool AsWritten = false);
+
/// \brief Return the uniqued reference to the type for a complex
/// number with the specified element type.
QualType getComplexType(QualType T) const;
@@ -1371,7 +1393,8 @@ public:
///
/// If \p Field is specified then record field names are also encoded.
void getObjCEncodingForType(QualType T, std::string &S,
- const FieldDecl *Field=nullptr) const;
+ const FieldDecl *Field=nullptr,
+ QualType *NotEncodedT=nullptr) const;
/// \brief Emit the Objective-C property type encoding for the given
/// type \p T into \p S.
@@ -1581,7 +1604,7 @@ public:
private:
CanQualType getFromTargetType(unsigned Type) const;
- std::pair<uint64_t, unsigned> getTypeInfoImpl(const Type *T) const;
+ TypeInfo getTypeInfoImpl(const Type *T) const;
//===--------------------------------------------------------------------===//
// Type Predicates.
@@ -1614,18 +1637,12 @@ public:
const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const;
/// \brief Get the size and alignment of the specified complete type in bits.
- std::pair<uint64_t, unsigned> getTypeInfo(const Type *T) const;
- std::pair<uint64_t, unsigned> getTypeInfo(QualType T) const {
- return getTypeInfo(T.getTypePtr());
- }
+ TypeInfo getTypeInfo(const Type *T) const;
+ TypeInfo getTypeInfo(QualType T) const { return getTypeInfo(T.getTypePtr()); }
/// \brief Return the size of the specified (complete) type \p T, in bits.
- uint64_t getTypeSize(QualType T) const {
- return getTypeInfo(T).first;
- }
- uint64_t getTypeSize(const Type *T) const {
- return getTypeInfo(T).first;
- }
+ uint64_t getTypeSize(QualType T) const { return getTypeInfo(T).Width; }
+ uint64_t getTypeSize(const Type *T) const { return getTypeInfo(T).Width; }
/// \brief Return the size of the character type, in bits.
uint64_t getCharWidth() const {
@@ -1645,12 +1662,8 @@ public:
/// \brief Return the ABI-specified alignment of a (complete) type \p T, in
/// bits.
- unsigned getTypeAlign(QualType T) const {
- return getTypeInfo(T).second;
- }
- unsigned getTypeAlign(const Type *T) const {
- return getTypeInfo(T).second;
- }
+ unsigned getTypeAlign(QualType T) const { return getTypeInfo(T).Align; }
+ unsigned getTypeAlign(const Type *T) const { return getTypeInfo(T).Align; }
/// \brief Return the ABI-specified alignment of a (complete) type \p T, in
/// characters.
@@ -1664,6 +1677,11 @@ public:
std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T) const;
std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T) const;
+ /// \brief Determine if the alignment the type has was required using an
+ /// alignment attribute.
+ bool isAlignmentRequired(const Type *T) const;
+ bool isAlignmentRequired(QualType T) const;
+
/// \brief Return the "preferred" alignment of the specified type \p T for
/// the current target, in bits.
///
@@ -2153,8 +2171,6 @@ public:
getTrivialTypeSourceInfo(QualType T,
SourceLocation Loc = SourceLocation()) const;
- TypeSourceInfo *getNullTypeSourceInfo() { return &NullTypeSourceInfo; }
-
/// \brief Add a deallocation callback that will be invoked when the
/// ASTContext is destroyed.
///
@@ -2272,12 +2288,14 @@ private:
bool StructField = false,
bool EncodeBlockParameters = false,
bool EncodeClassNames = false,
- bool EncodePointerToObjCTypedef = false) const;
+ bool EncodePointerToObjCTypedef = false,
+ QualType *NotEncodedT=nullptr) const;
// Adds the encoding of the structure's members.
void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S,
const FieldDecl *Field,
- bool includeVBases = true) const;
+ bool includeVBases = true,
+ QualType *NotEncodedT=nullptr) const;
public:
// Adds the encoding of a method parameter or return type.
void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT,
@@ -2312,6 +2330,31 @@ private:
std::unique_ptr<ParentMap> AllParents;
std::unique_ptr<VTableContextBase> VTContext;
+
+public:
+ enum PragmaSectionFlag : unsigned {
+ PSF_None = 0,
+ PSF_Read = 0x1,
+ PSF_Write = 0x2,
+ PSF_Execute = 0x4,
+ PSF_Implicit = 0x8,
+ PSF_Invalid = 0x80000000U,
+ };
+
+ struct SectionInfo {
+ DeclaratorDecl *Decl;
+ SourceLocation PragmaSectionLocation;
+ int SectionFlags;
+ SectionInfo() {}
+ SectionInfo(DeclaratorDecl *Decl,
+ SourceLocation PragmaSectionLocation,
+ int SectionFlags)
+ : Decl(Decl),
+ PragmaSectionLocation(PragmaSectionLocation),
+ SectionFlags(SectionFlags) {}
+ };
+
+ llvm::StringMap<SectionInfo> SectionInfos;
};
/// \brief Utility function for constructing a nullary selector.
@@ -2349,9 +2392,9 @@ static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
/// // Specific alignment
/// IntegerLiteral *Ex2 = new (Context, 4) IntegerLiteral(arguments);
/// @endcode
-/// Please note that you cannot use delete on the pointer; it must be
-/// deallocated using an explicit destructor call followed by
-/// @c Context.Deallocate(Ptr).
+/// Memory allocated through this placement new operator does not need to be
+/// explicitly freed, as ASTContext will free all of this memory when it gets
+/// destroyed. Please note that you cannot use delete on the pointer.
///
/// @param Bytes The number of bytes to allocate. Calculated by the compiler.
/// @param C The ASTContext that provides the allocator.
@@ -2386,9 +2429,9 @@ inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t) {
/// // Specific alignment
/// char *data = new (Context, 4) char[10];
/// @endcode
-/// Please note that you cannot use delete on the pointer; it must be
-/// deallocated using an explicit destructor call followed by
-/// @c Context.Deallocate(Ptr).
+/// Memory allocated through this placement new[] operator does not need to be
+/// explicitly freed, as ASTContext will free all of this memory when it gets
+/// destroyed. Please note that you cannot use delete on the pointer.
///
/// @param Bytes The number of bytes to allocate. Calculated by the compiler.
/// @param C The ASTContext that provides the allocator.
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
index 484ca4cb8632..27c85e65f2c1 100644
--- a/include/clang/AST/ASTDiagnostic.h
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_DIAGNOSTICAST_H
-#define LLVM_CLANG_DIAGNOSTICAST_H
+#ifndef LLVM_CLANG_AST_ASTDIAGNOSTIC_H
+#define LLVM_CLANG_AST_ASTDIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
diff --git a/include/clang/AST/ASTFwd.h b/include/clang/AST/ASTFwd.h
index 4f3279874b16..003d489c1ca4 100644
--- a/include/clang/AST/ASTFwd.h
+++ b/include/clang/AST/ASTFwd.h
@@ -12,6 +12,9 @@
///
//===-------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_ASTFWD_H
+#define LLVM_CLANG_AST_ASTFWD_H
+
namespace clang {
class Decl;
@@ -26,3 +29,5 @@ class Type;
class CXXCtorInitializer;
} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/ASTLambda.h b/include/clang/AST/ASTLambda.h
index 9af016b13d45..69df2d8c0113 100644
--- a/include/clang/AST/ASTLambda.h
+++ b/include/clang/AST/ASTLambda.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_LAMBDA_H
-#define LLVM_CLANG_AST_LAMBDA_H
+#ifndef LLVM_CLANG_AST_ASTLAMBDA_H
+#define LLVM_CLANG_AST_ASTLAMBDA_H
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
@@ -77,4 +77,4 @@ inline DeclContext *getLambdaAwareParentOfDeclContext(DeclContext *DC) {
} // clang
-#endif // LLVM_CLANG_AST_LAMBDA_H
+#endif
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index a89bfed53fbd..48eb6292772c 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -102,6 +102,12 @@ public:
/// \param D the declaration marked used
virtual void DeclarationMarkedUsed(const Decl *D) {}
+ /// \brief A declaration is marked as OpenMP threadprivate which was not
+ /// previously marked as threadprivate.
+ ///
+ /// \param D the declaration marked OpenMP threadprivate.
+ virtual void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {}
+
// NOTE: If new methods are added they should also be added to
// MultiplexASTMutationListener.
};
diff --git a/include/clang/AST/ASTTypeTraits.h b/include/clang/AST/ASTTypeTraits.h
index 0e06e26e6d80..dc3c34f28d94 100644
--- a/include/clang/AST/ASTTypeTraits.h
+++ b/include/clang/AST/ASTTypeTraits.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
-#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
+#ifndef LLVM_CLANG_AST_ASTTYPETRAITS_H
+#define LLVM_CLANG_AST_ASTTYPETRAITS_H
#include "clang/AST/ASTFwd.h"
#include "clang/AST/Decl.h"
@@ -23,6 +23,7 @@
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/Support/AlignOf.h"
namespace llvm {
@@ -53,9 +54,19 @@ public:
return ASTNodeKind(KindToKindId<T>::Id);
}
+ /// \{
+ /// \brief Construct an identifier for the dynamic type of the node
+ static ASTNodeKind getFromNode(const Decl &D);
+ static ASTNodeKind getFromNode(const Stmt &S);
+ static ASTNodeKind getFromNode(const Type &T);
+ /// \}
+
/// \brief Returns \c true if \c this and \c Other represent the same kind.
bool isSame(ASTNodeKind Other) const;
+ /// \brief Returns \c true only for the default \c ASTNodeKind()
+ bool isNone() const { return KindId == NKI_None; }
+
/// \brief Returns \c true if \c this is a base kind of (or same as) \c Other.
/// \param Distance If non-null, used to return the distance between \c this
/// and \c Other in the class hierarchy.
@@ -69,6 +80,32 @@ public:
return KindId < Other.KindId;
}
+ /// \brief Return the most derived type between \p Kind1 and \p Kind2.
+ ///
+ /// Return ASTNodeKind() if they are not related.
+ static ASTNodeKind getMostDerivedType(ASTNodeKind Kind1, ASTNodeKind Kind2);
+
+ /// \brief Return the most derived common ancestor between Kind1 and Kind2.
+ ///
+ /// Return ASTNodeKind() if they are not related.
+ static ASTNodeKind getMostDerivedCommonAncestor(ASTNodeKind Kind1,
+ ASTNodeKind Kind2);
+
+ /// \brief Hooks for using ASTNodeKind as a key in a DenseMap.
+ struct DenseMapInfo {
+ // ASTNodeKind() is a good empty key because it is represented as a 0.
+ static inline ASTNodeKind getEmptyKey() { return ASTNodeKind(); }
+ // NKI_NumberOfKinds is not a valid value, so it is good for a
+ // tombstone key.
+ static inline ASTNodeKind getTombstoneKey() {
+ return ASTNodeKind(NKI_NumberOfKinds);
+ }
+ static unsigned getHashValue(const ASTNodeKind &Val) { return Val.KindId; }
+ static bool isEqual(const ASTNodeKind &LHS, const ASTNodeKind &RHS) {
+ return LHS.KindId == RHS.KindId;
+ }
+ };
+
private:
/// \brief Kind ids.
///
@@ -108,6 +145,8 @@ private:
template <class T> struct KindToKindId {
static const NodeKindId Id = NKI_None;
};
+ template <class T>
+ struct KindToKindId<const T> : KindToKindId<T> {};
/// \brief Per kind info.
struct KindInfo {
@@ -184,12 +223,22 @@ public:
return BaseConverter<T>::get(NodeKind, Storage.buffer);
}
+ /// \brief Retrieve the stored node as type \c T.
+ ///
+ /// Similar to \c get(), but asserts that the type is what we are expecting.
+ template <typename T>
+ const T &getUnchecked() const {
+ return BaseConverter<T>::getUnchecked(NodeKind, Storage.buffer);
+ }
+
+ ASTNodeKind getNodeKind() const { return NodeKind; }
+
/// \brief Returns a pointer that identifies the stored AST node.
///
/// Note that this is not supported by all AST nodes. For AST nodes
/// that don't have a pointer-defined identity inside the AST, this
/// method returns NULL.
- const void *getMemoizationData() const;
+ const void *getMemoizationData() const { return MemoizationData; }
/// \brief Prints the node to the given output stream.
void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const;
@@ -212,14 +261,15 @@ public:
return getMemoizationData() < Other.getMemoizationData();
}
bool operator==(const DynTypedNode &Other) const {
- if (!NodeKind.isBaseOf(Other.NodeKind) &&
- !Other.NodeKind.isBaseOf(NodeKind))
+ // DynTypedNode::create() stores the exact kind of the node in NodeKind.
+ // If they contain the same node, their NodeKind must be the same.
+ if (!NodeKind.isSame(Other.NodeKind))
return false;
// FIXME: Implement for other types.
- if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) {
- return *get<QualType>() == *Other.get<QualType>();
- }
+ if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
+ return getUnchecked<QualType>() == Other.getUnchecked<QualType>();
+
assert(getMemoizationData() && Other.getMemoizationData());
return getMemoizationData() == Other.getMemoizationData();
}
@@ -235,13 +285,18 @@ private:
/// \brief Converter that uses dyn_cast<T> from a stored BaseT*.
template <typename T, typename BaseT> struct DynCastPtrConverter {
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
- if (ASTNodeKind::getFromNodeKind<BaseT>().isBaseOf(NodeKind))
- return dyn_cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
+ if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind))
+ return cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
return nullptr;
}
+ static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) {
+ assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind));
+ return *cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
+ }
static DynTypedNode create(const BaseT &Node) {
DynTypedNode Result;
- Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
+ Result.NodeKind = ASTNodeKind::getFromNode(Node);
+ Result.MemoizationData = &Node;
new (Result.Storage.buffer) const BaseT * (&Node);
return Result;
}
@@ -254,9 +309,14 @@ private:
return *reinterpret_cast<T *const *>(Storage);
return nullptr;
}
+ static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) {
+ assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind));
+ return **reinterpret_cast<T *const *>(Storage);
+ }
static DynTypedNode create(const T &Node) {
DynTypedNode Result;
Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
+ Result.MemoizationData = &Node;
new (Result.Storage.buffer) const T * (&Node);
return Result;
}
@@ -269,15 +329,21 @@ private:
return reinterpret_cast<const T *>(Storage);
return nullptr;
}
+ static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) {
+ assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind));
+ return *reinterpret_cast<const T *>(Storage);
+ }
static DynTypedNode create(const T &Node) {
DynTypedNode Result;
Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
+ Result.MemoizationData = nullptr;
new (Result.Storage.buffer) T(Node);
return Result;
}
};
ASTNodeKind NodeKind;
+ const void *MemoizationData;
/// \brief Stores the data of the node.
///
@@ -345,20 +411,15 @@ template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
}
};
-inline const void *DynTypedNode::getMemoizationData() const {
- if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) {
- return BaseConverter<Decl>::get(NodeKind, Storage.buffer);
- } else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) {
- return BaseConverter<Stmt>::get(NodeKind, Storage.buffer);
- } else if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind)) {
- return BaseConverter<Type>::get(NodeKind, Storage.buffer);
- } else if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) {
- return BaseConverter<NestedNameSpecifier>::get(NodeKind, Storage.buffer);
- }
- return nullptr;
-}
-
} // end namespace ast_type_traits
} // end namespace clang
-#endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H
+namespace llvm {
+
+template <>
+struct DenseMapInfo<clang::ast_type_traits::ASTNodeKind>
+ : clang::ast_type_traits::ASTNodeKind::DenseMapInfo {};
+
+} // end namespace llvm
+
+#endif
diff --git a/include/clang/AST/ASTVector.h b/include/clang/AST/ASTVector.h
index d92167e95992..6ec054582e26 100644
--- a/include/clang/AST/ASTVector.h
+++ b/include/clang/AST/ASTVector.h
@@ -15,8 +15,8 @@
// FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h.
// We can refactor this core logic into something common.
-#ifndef LLVM_CLANG_AST_VECTOR
-#define LLVM_CLANG_AST_VECTOR
+#ifndef LLVM_CLANG_AST_ASTVECTOR_H
+#define LLVM_CLANG_AST_ASTVECTOR_H
#include "clang/AST/AttrIterator.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -236,14 +236,14 @@ public:
iterator insert(const ASTContext &C, iterator I, size_type NumToInsert,
const T &Elt) {
- if (I == this->end()) { // Important special case for empty vector.
- append(C, NumToInsert, Elt);
- return this->end()-1;
- }
-
// Convert iterator to elt# to avoid invalidating iterator when we reserve()
size_t InsertElt = I - this->begin();
+ if (I == this->end()) { // Important special case for empty vector.
+ append(C, NumToInsert, Elt);
+ return this->begin() + InsertElt;
+ }
+
// Ensure there is enough space.
reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
@@ -284,14 +284,15 @@ public:
template<typename ItTy>
iterator insert(const ASTContext &C, iterator I, ItTy From, ItTy To) {
- if (I == this->end()) { // Important special case for empty vector.
+ // Convert iterator to elt# to avoid invalidating iterator when we reserve()
+ size_t InsertElt = I - this->begin();
+
+ if (I == this->end()) { // Important special case for empty vector.
append(C, From, To);
- return this->end()-1;
+ return this->begin() + InsertElt;
}
size_t NumToInsert = std::distance(From, To);
- // Convert iterator to elt# to avoid invalidating iterator when we reserve()
- size_t InsertElt = I - this->begin();
// Ensure there is enough space.
reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index fc4881619bce..787843e64f56 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -16,6 +16,7 @@
#include "clang/AST/AttrIterator.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/LLVM.h"
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 7cccef69ddf8..aa3c84682983 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_CANONICAL_TYPE_H
-#define LLVM_CLANG_AST_CANONICAL_TYPE_H
+#ifndef LLVM_CLANG_AST_CANONICALTYPE_H
+#define LLVM_CLANG_AST_CANONICALTYPE_H
#include "clang/AST/Type.h"
#include "llvm/Support/Casting.h"
@@ -736,4 +736,4 @@ CanTypeIterator<InputIterator>::operator->() const {
}
-#endif // LLVM_CLANG_AST_CANONICAL_TYPE_H
+#endif
diff --git a/include/clang/AST/Comment.h b/include/clang/AST/Comment.h
index e18fe9ab86a0..94470cbf305f 100644
--- a/include/clang/AST/Comment.h
+++ b/include/clang/AST/Comment.h
@@ -96,9 +96,10 @@ protected:
unsigned : NumInlineContentCommentBits;
unsigned RenderKind : 2;
- unsigned CommandID : 8;
+ unsigned CommandID : CommandInfo::NumCommandIDBits;
};
- enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 10 };
+ enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 2 +
+ CommandInfo::NumCommandIDBits };
class HTMLTagCommentBitfields {
friend class HTMLTagComment;
@@ -139,13 +140,14 @@ protected:
unsigned : NumCommentBits;
- unsigned CommandID : 8;
+ unsigned CommandID : CommandInfo::NumCommandIDBits;
/// Describes the syntax that was used in a documentation command.
/// Contains values from CommandMarkerKind enum.
unsigned CommandMarker : 1;
};
- enum { NumBlockCommandCommentBits = NumCommentBits + 9 };
+ enum { NumBlockCommandCommentBits = NumCommentBits +
+ CommandInfo::NumCommandIDBits + 1 };
class ParamCommandCommentBitfields {
friend class ParamCommandComment;
diff --git a/include/clang/AST/CommentBriefParser.h b/include/clang/AST/CommentBriefParser.h
index 5d508860635d..be5b8eeb80c3 100644
--- a/include/clang/AST/CommentBriefParser.h
+++ b/include/clang/AST/CommentBriefParser.h
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_BRIEF_COMMENT_PARSER_H
-#define LLVM_CLANG_AST_BRIEF_COMMENT_PARSER_H
+#ifndef LLVM_CLANG_AST_COMMENTBRIEFPARSER_H
+#define LLVM_CLANG_AST_COMMENTBRIEFPARSER_H
#include "clang/AST/CommentLexer.h"
diff --git a/include/clang/AST/CommentCommandTraits.h b/include/clang/AST/CommentCommandTraits.h
index dde7a1442fe1..ec6d83c03021 100644
--- a/include/clang/AST/CommentCommandTraits.h
+++ b/include/clang/AST/CommentCommandTraits.h
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_COMMENT_COMMAND_TRAITS_H
-#define LLVM_CLANG_AST_COMMENT_COMMAND_TRAITS_H
+#ifndef LLVM_CLANG_AST_COMMENTCOMMANDTRAITS_H
+#define LLVM_CLANG_AST_COMMENTCOMMANDTRAITS_H
#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/LLVM.h"
@@ -40,7 +40,11 @@ struct CommandInfo {
/// Name of the command that ends the verbatim block.
const char *EndCommandName;
- unsigned ID : 8;
+ /// DRY definition of the number of bits used for a command ID.
+ enum { NumCommandIDBits = 20 };
+
+ /// The ID of the command.
+ unsigned ID : NumCommandIDBits;
/// Number of word-like arguments for a given block command, except for
/// \\param and \\tparam commands -- these have special argument parsers.
diff --git a/include/clang/AST/CommentDiagnostic.h b/include/clang/AST/CommentDiagnostic.h
index 312da065ff59..f3a209bf6e7c 100644
--- a/include/clang/AST/CommentDiagnostic.h
+++ b/include/clang/AST/CommentDiagnostic.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_COMMENTDIAGNOSTIC_H
-#define LLVM_CLANG_COMMENTDIAGNOSTIC_H
+#ifndef LLVM_CLANG_AST_COMMENTDIAGNOSTIC_H
+#define LLVM_CLANG_AST_COMMENTDIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
diff --git a/include/clang/AST/CommentLexer.h b/include/clang/AST/CommentLexer.h
index a6e3ed89b27e..d995df921282 100644
--- a/include/clang/AST/CommentLexer.h
+++ b/include/clang/AST/CommentLexer.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_COMMENT_LEXER_H
-#define LLVM_CLANG_AST_COMMENT_LEXER_H
+#ifndef LLVM_CLANG_AST_COMMENTLEXER_H
+#define LLVM_CLANG_AST_COMMENTLEXER_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
diff --git a/include/clang/AST/CommentParser.h b/include/clang/AST/CommentParser.h
index 7e008131d205..2c444f0dc3a6 100644
--- a/include/clang/AST/CommentParser.h
+++ b/include/clang/AST/CommentParser.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_COMMENT_PARSER_H
-#define LLVM_CLANG_AST_COMMENT_PARSER_H
+#ifndef LLVM_CLANG_AST_COMMENTPARSER_H
+#define LLVM_CLANG_AST_COMMENTPARSER_H
#include "clang/AST/Comment.h"
#include "clang/AST/CommentLexer.h"
diff --git a/include/clang/AST/CommentSema.h b/include/clang/AST/CommentSema.h
index 027c3b929df6..4ae6fe0c613d 100644
--- a/include/clang/AST/CommentSema.h
+++ b/include/clang/AST/CommentSema.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_COMMENT_SEMA_H
-#define LLVM_CLANG_AST_COMMENT_SEMA_H
+#ifndef LLVM_CLANG_AST_COMMENTSEMA_H
+#define LLVM_CLANG_AST_COMMENTSEMA_H
#include "clang/AST/Comment.h"
#include "clang/Basic/Diagnostic.h"
@@ -85,7 +85,7 @@ public:
std::uninitialized_copy(Source.begin(), Source.end(), Mem);
return llvm::makeArrayRef(Mem, Size);
}
- return ArrayRef<T>();
+ return None;
}
ParagraphComment *actOnParagraphComment(
diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
index 9ef008717b1b..c0526e1cfd45 100644
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ b/include/clang/AST/DataRecursiveASTVisitor.h
@@ -424,6 +424,7 @@ private:
bool TraverseFunctionHelper(FunctionDecl *D);
bool TraverseVarHelper(VarDecl *D);
bool TraverseOMPExecutableDirective(OMPExecutableDirective *S);
+ bool TraverseOMPLoopDirective(OMPLoopDirective *S);
bool TraverseOMPClause(OMPClause *C);
#define OPENMP_CLAUSE(Name, Class) bool Visit##Class(Class *C);
#include "clang/Basic/OpenMPKinds.def"
@@ -623,6 +624,7 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier(
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
return true;
case NestedNameSpecifier::TypeSpec:
@@ -647,6 +649,7 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
return true;
case NestedNameSpecifier::TypeSpec:
@@ -875,6 +878,9 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, {
for (const auto &E : T->exceptions()) {
TRY_TO(TraverseType(E));
}
+
+ if (Expr *NE = T->getNoexceptExpr())
+ TRY_TO(TraverseStmt(NE));
})
DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
@@ -1083,6 +1089,9 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, {
for (const auto &E : T->exceptions()) {
TRY_TO(TraverseType(E));
}
+
+ if (Expr *NE = T->getNoexceptExpr())
+ TRY_TO(TraverseStmt(NE));
})
DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
@@ -2122,21 +2131,29 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
TRY_TO(TraverseLambdaCapture(S, C));
}
- if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
- TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
- if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
- // Visit the whole type.
- TRY_TO(TraverseTypeLoc(TL));
- } else if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) {
- if (S->hasExplicitParameters()) {
- // Visit parameters.
- for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) {
- TRY_TO(TraverseDecl(Proto.getParam(I)));
- }
- } else {
- TRY_TO(TraverseTypeLoc(Proto.getReturnLoc()));
+ TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+ FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>();
+
+ if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
+ // Visit the whole type.
+ TRY_TO(TraverseTypeLoc(TL));
+ } else {
+ if (S->hasExplicitParameters()) {
+ // Visit parameters.
+ for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) {
+ TRY_TO(TraverseDecl(Proto.getParam(I)));
}
+ } else if (S->hasExplicitResultType()) {
+ TRY_TO(TraverseTypeLoc(Proto.getReturnLoc()));
+ }
+
+ auto *T = Proto.getTypePtr();
+ for (const auto &E : T->exceptions()) {
+ TRY_TO(TraverseType(E));
}
+
+ if (Expr *NE = T->getNoexceptExpr())
+ TRY_TO(TraverseStmt(NE));
}
TRY_TO(TraverseLambdaBody(S));
@@ -2237,6 +2254,7 @@ DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); })
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {})
DEF_TRAVERSE_STMT(OpaqueValueExpr, {})
+DEF_TRAVERSE_STMT(TypoExpr, {})
DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {})
// These operators (all of them) do not need any action except
@@ -2253,6 +2271,7 @@ DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {})
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {})
+DEF_TRAVERSE_STMT(CXXFoldExpr, {})
DEF_TRAVERSE_STMT(AtomicExpr, {})
// These literals (all of them) do not need any action.
@@ -2279,6 +2298,12 @@ bool RecursiveASTVisitor<Derived>::TraverseOMPExecutableDirective(
return true;
}
+template <typename Derived>
+bool
+RecursiveASTVisitor<Derived>::TraverseOMPLoopDirective(OMPLoopDirective *S) {
+ return TraverseOMPExecutableDirective(S);
+}
+
DEF_TRAVERSE_STMT(OMPParallelDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
@@ -2288,6 +2313,9 @@ DEF_TRAVERSE_STMT(OMPSimdDirective,
DEF_TRAVERSE_STMT(OMPForDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPForSimdDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
DEF_TRAVERSE_STMT(OMPSectionsDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
@@ -2308,6 +2336,9 @@ DEF_TRAVERSE_STMT(OMPCriticalDirective, {
DEF_TRAVERSE_STMT(OMPParallelForDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPParallelForSimdDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
DEF_TRAVERSE_STMT(OMPParallelSectionsDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
@@ -2326,6 +2357,18 @@ DEF_TRAVERSE_STMT(OMPTaskwaitDirective,
DEF_TRAVERSE_STMT(OMPFlushDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPOrderedDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
+DEF_TRAVERSE_STMT(OMPAtomicDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
+DEF_TRAVERSE_STMT(OMPTargetDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
+DEF_TRAVERSE_STMT(OMPTeamsDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
// OpenMP clauses.
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
@@ -2415,6 +2458,31 @@ RecursiveASTVisitor<Derived>::VisitOMPMergeableClause(OMPMergeableClause *) {
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPReadClause(OMPReadClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPWriteClause(OMPWriteClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPUpdateClause(OMPUpdateClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPCaptureClause(OMPCaptureClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPSeqCstClause(OMPSeqCstClause *) {
+ return true;
+}
+
+template <typename Derived>
template <typename T>
bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
for (auto *E : Node->varlists()) {
@@ -2426,6 +2494,9 @@ bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->private_copies()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
@@ -2433,6 +2504,12 @@ template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
OMPFirstprivateClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->private_copies()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->inits()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index ce8b8b7dbcd6..a39888f9e1f0 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -43,6 +43,7 @@ class Stmt;
class StringLiteral;
class TemplateArgumentList;
class TemplateParameterList;
+class TypeAliasTemplateDecl;
class TypeLoc;
class UnresolvedSetImpl;
class VarTemplateDecl;
@@ -67,6 +68,9 @@ public:
/// \brief Return the TypeLoc wrapper for the type source info.
TypeLoc getTypeLoc() const; // implemented in TypeLoc.h
+
+ /// \brief Override the type stored in this TypeSourceInfo. Use with caution!
+ void overrideType(QualType T) { Ty = T; }
};
/// TranslationUnitDecl - The top declaration context.
@@ -288,6 +292,8 @@ public:
return const_cast<NamedDecl*>(this)->getMostRecentDecl();
}
+ ObjCStringFormatFamily getObjCFStringFormattingFamily() const;
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
};
@@ -305,6 +311,8 @@ inline raw_ostream &operator<<(raw_ostream &OS, const NamedDecl &ND) {
class LabelDecl : public NamedDecl {
void anchor() override;
LabelStmt *TheStmt;
+ StringRef MSAsmName;
+ bool MSAsmNameResolved;
/// LocStart - For normal labels, this is the same as the main declaration
/// label, i.e., the location of the identifier; for GNU local labels,
/// this is the location of the __label__ keyword.
@@ -312,7 +320,10 @@ class LabelDecl : public NamedDecl {
LabelDecl(DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II,
LabelStmt *S, SourceLocation StartL)
- : NamedDecl(Label, DC, IdentL, II), TheStmt(S), LocStart(StartL) {}
+ : NamedDecl(Label, DC, IdentL, II),
+ TheStmt(S),
+ MSAsmNameResolved(false),
+ LocStart(StartL) {}
public:
static LabelDecl *Create(ASTContext &C, DeclContext *DC,
@@ -332,6 +343,12 @@ public:
return SourceRange(LocStart, getLocation());
}
+ bool isMSAsmLabel() const { return MSAsmName.size() != 0; }
+ bool isResolvedMSAsmLabel() const { return isMSAsmLabel() && MSAsmNameResolved; }
+ void setMSAsmLabel(StringRef Name);
+ StringRef getMSAsmLabel() const { return MSAsmName; }
+ void setMSAsmLabelResolved() { MSAsmNameResolved = true; }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Label; }
@@ -648,8 +665,6 @@ struct EvaluatedStmt {
/// declaration or definition.
class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
public:
- typedef clang::StorageClass StorageClass;
-
/// getStorageClassSpecifierString - Return the string used to
/// specify the storage class \p SC.
///
@@ -891,6 +906,11 @@ public:
return false;
}
+ /// \brief Similar to isLocalVarDecl but also includes parameters.
+ bool isLocalVarDeclOrParm() const {
+ return isLocalVarDecl() || getKind() == Decl::ParmVar;
+ }
+
/// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but
/// excludes variables declared in blocks.
bool isFunctionOrMethodVarDecl() const {
@@ -1423,8 +1443,6 @@ private:
class FunctionDecl : public DeclaratorDecl, public DeclContext,
public Redeclarable<FunctionDecl> {
public:
- typedef clang::StorageClass StorageClass;
-
/// \brief The kind of templated function a FunctionDecl can be.
enum TemplatedKind {
TK_NonTemplate,
@@ -1650,7 +1668,7 @@ public:
/// unnecessary AST de-serialization of the body.
Stmt *getBody(const FunctionDecl *&Definition) const;
- Stmt *getBody() const override {
+ Stmt *getBody() const override {
const FunctionDecl* Definition;
return getBody(Definition);
}
@@ -1880,7 +1898,7 @@ public:
return llvm::makeArrayRef(ParamInfo, getNumParams());
}
- const ArrayRef<NamedDecl *> &getDeclsInPrototypeScope() const {
+ ArrayRef<NamedDecl *> getDeclsInPrototypeScope() const {
return DeclsInPrototypeScope;
}
void setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls);
@@ -2154,17 +2172,41 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
bool Mutable : 1;
mutable unsigned CachedFieldIndex : 31;
- /// \brief An InClassInitStyle value, and either a bit width expression (if
- /// the InClassInitStyle value is ICIS_NoInit), or a pointer to the in-class
- /// initializer for this field (otherwise).
+ /// The kinds of value we can store in InitializerOrBitWidth.
///
- /// We can safely combine these two because in-class initializers are not
- /// permitted for bit-fields.
+ /// Note that this is compatible with InClassInitStyle except for
+ /// ISK_CapturedVLAType.
+ enum InitStorageKind {
+ /// If the pointer is null, there's nothing special. Otherwise,
+ /// this is a bitfield and the pointer is the Expr* storing the
+ /// bit-width.
+ ISK_BitWidthOrNothing = (unsigned) ICIS_NoInit,
+
+ /// The pointer is an (optional due to delayed parsing) Expr*
+ /// holding the copy-initializer.
+ ISK_InClassCopyInit = (unsigned) ICIS_CopyInit,
+
+ /// The pointer is an (optional due to delayed parsing) Expr*
+ /// holding the list-initializer.
+ ISK_InClassListInit = (unsigned) ICIS_ListInit,
+
+ /// The pointer is a VariableArrayType* that's been captured;
+ /// the enclosing context is a lambda or captured statement.
+ ISK_CapturedVLAType,
+ };
+
+ /// \brief Storage for either the bit-width, the in-class
+ /// initializer, or the captured variable length array bound.
+ ///
+ /// We can safely combine these because in-class initializers are
+ /// not permitted for bit-fields, and both are exclusive with VLA
+ /// captures.
///
- /// If the InClassInitStyle is not ICIS_NoInit and the initializer is null,
- /// then this field has an in-class initializer which has not yet been parsed
+ /// If the storage kind is ISK_InClassCopyInit or
+ /// ISK_InClassListInit, but the initializer is null, then this
+ /// field has an in-class initializer which has not yet been parsed
/// and attached.
- llvm::PointerIntPair<Expr *, 2, unsigned> InitializerOrBitWidth;
+ llvm::PointerIntPair<void *, 2, InitStorageKind> InitStorage;
protected:
FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
@@ -2172,7 +2214,7 @@ protected:
InClassInitStyle InitStyle)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
Mutable(Mutable), CachedFieldIndex(0),
- InitializerOrBitWidth(BW, InitStyle) {
+ InitStorage(BW, (InitStorageKind) InitStyle) {
assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield");
}
@@ -2192,10 +2234,10 @@ public:
/// isMutable - Determines whether this field is mutable (C++ only).
bool isMutable() const { return Mutable; }
- /// isBitfield - Determines whether this field is a bitfield.
+ /// \brief Determines whether this field is a bitfield.
bool isBitField() const {
- return getInClassInitStyle() == ICIS_NoInit &&
- InitializerOrBitWidth.getPointer();
+ return InitStorage.getInt() == ISK_BitWidthOrNothing &&
+ InitStorage.getPointer() != nullptr;
}
/// @brief Determines whether this is an unnamed bitfield.
@@ -2208,24 +2250,34 @@ public:
bool isAnonymousStructOrUnion() const;
Expr *getBitWidth() const {
- return isBitField() ? InitializerOrBitWidth.getPointer() : nullptr;
+ return isBitField()
+ ? static_cast<Expr *>(InitStorage.getPointer())
+ : nullptr;
}
unsigned getBitWidthValue(const ASTContext &Ctx) const;
/// setBitWidth - Set the bit-field width for this member.
// Note: used by some clients (i.e., do not remove it).
- void setBitWidth(Expr *Width);
+ void setBitWidth(Expr *Width) {
+ assert(InitStorage.getInt() == ISK_BitWidthOrNothing &&
+ InitStorage.getPointer() == nullptr &&
+ "bit width, initializer or captured type already set");
+ InitStorage.setPointerAndInt(Width, ISK_BitWidthOrNothing);
+ }
+
/// removeBitWidth - Remove the bit-field width from this member.
// Note: used by some clients (i.e., do not remove it).
void removeBitWidth() {
assert(isBitField() && "no bitfield width to remove");
- InitializerOrBitWidth.setPointer(nullptr);
+ InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing);
}
/// getInClassInitStyle - Get the kind of (C++11) in-class initializer which
/// this field has.
InClassInitStyle getInClassInitStyle() const {
- return static_cast<InClassInitStyle>(InitializerOrBitWidth.getInt());
+ InitStorageKind storageKind = InitStorage.getInt();
+ return (storageKind == ISK_CapturedVLAType
+ ? ICIS_NoInit : (InClassInitStyle) storageKind);
}
/// hasInClassInitializer - Determine whether this member has a C++11 in-class
@@ -2233,24 +2285,47 @@ public:
bool hasInClassInitializer() const {
return getInClassInitStyle() != ICIS_NoInit;
}
+
/// getInClassInitializer - Get the C++11 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()
- : nullptr;
+ return hasInClassInitializer()
+ ? static_cast<Expr *>(InitStorage.getPointer())
+ : nullptr;
}
+
/// setInClassInitializer - Set the C++11 in-class initializer for this
/// member.
- void setInClassInitializer(Expr *Init);
+ void setInClassInitializer(Expr *Init) {
+ assert(hasInClassInitializer() &&
+ InitStorage.getPointer() == nullptr &&
+ "bit width, initializer or captured type already set");
+ InitStorage.setPointer(Init);
+ }
+
/// removeInClassInitializer - Remove the C++11 in-class initializer from this
/// member.
void removeInClassInitializer() {
assert(hasInClassInitializer() && "no initializer to remove");
- InitializerOrBitWidth.setPointer(nullptr);
- InitializerOrBitWidth.setInt(ICIS_NoInit);
+ InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing);
+ }
+
+ /// \brief Determine whether this member captures the variable length array
+ /// type.
+ bool hasCapturedVLAType() const {
+ return InitStorage.getInt() == ISK_CapturedVLAType;
+ }
+
+ /// \brief Get the captured variable length array type.
+ const VariableArrayType *getCapturedVLAType() const {
+ return hasCapturedVLAType() ? static_cast<const VariableArrayType *>(
+ InitStorage.getPointer())
+ : nullptr;
}
+ /// \brief Set the captured variable length array type for this field.
+ void setCapturedVLAType(const VariableArrayType *VLAType);
/// getParent - Returns the parent of this field declaration, which
/// is the struct in which this method is defined.
@@ -2492,9 +2567,13 @@ public:
/// TypeAliasDecl - Represents the declaration of a typedef-name via a C++0x
/// alias-declaration.
class TypeAliasDecl : public TypedefNameDecl {
+ /// The template for which this is the pattern, if any.
+ TypeAliasTemplateDecl *Template;
+
TypeAliasDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo)
- : TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo) {}
+ : TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo),
+ Template(nullptr) {}
public:
static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC,
@@ -2504,6 +2583,9 @@ public:
SourceRange getSourceRange() const override LLVM_READONLY;
+ TypeAliasTemplateDecl *getDescribedAliasTemplate() const { return Template; }
+ void setDescribedAliasTemplate(TypeAliasTemplateDecl *TAT) { Template = TAT; }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == TypeAlias; }
@@ -2647,7 +2729,7 @@ public:
}
/// isThisDeclarationADefinition() - Return true if this declaration
- /// is a completion definintion of the type. Provided for consistency.
+ /// is a completion definition of the type. Provided for consistency.
bool isThisDeclarationADefinition() const {
return isCompleteDefinition();
}
@@ -3136,6 +3218,17 @@ public:
/// \endcode
bool isInjectedClassName() const;
+ /// \brief Determine whether this record is a class describing a lambda
+ /// function object.
+ bool isLambda() const;
+
+ /// \brief Determine whether this record is a record for captured variables in
+ /// CapturedStmt construct.
+ bool isCapturedRecord() const;
+ /// \brief Mark the record as a record for captured variables in CapturedStmt
+ /// construct.
+ void setCapturedRecord();
+
/// getDefinition - Returns the RecordDecl that actually defines
/// this struct/union/class. When determining whether or not a
/// struct/union/class is completely defined, one should use this
@@ -3181,6 +3274,15 @@ public:
/// commandline option.
bool isMsStruct(const ASTContext &C) const;
+ /// \brief Whether we are allowed to insert extra padding between fields.
+ /// These padding are added to help AddressSanitizer detect
+ /// intra-object-overflow bugs.
+ bool mayInsertExtraPadding(bool EmitRemark = false) const;
+
+ /// Finds the first data member which has a name.
+ /// nullptr is returned if no named data member exists.
+ const FieldDecl *findFirstNamedDataMember() const;
+
private:
/// \brief Deserialize just the fields.
void LoadFieldsFromExternalStorage() const;
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 607ca4ec27c6..984ab13df426 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -48,6 +48,7 @@ class ObjCInterfaceDecl;
class ObjCMethodDecl;
class ObjCProtocolDecl;
struct PrintingPolicy;
+class RecordDecl;
class Stmt;
class StoredDeclsMap;
class TranslationUnitDecl;
@@ -515,9 +516,13 @@ public:
/// indicating the declaration is used.
void markUsed(ASTContext &C);
- /// \brief Whether this declaration was referenced.
+ /// \brief Whether any declaration of this entity was referenced.
bool isReferenced() const;
+ /// \brief Whether this declaration was referenced. This should not be relied
+ /// upon for anything other than debugging.
+ bool isThisDeclarationReferenced() const { return Referenced; }
+
void setReferenced(bool R = true) { Referenced = R; }
/// \brief Whether this declaration is a top-level declaration (function,
@@ -675,9 +680,9 @@ public:
return const_cast<Decl*>(this)->getLexicalDeclContext();
}
- virtual bool isOutOfLine() const {
- return getLexicalDeclContext() != getDeclContext();
- }
+ /// Determine whether this declaration is declared out of line (outside its
+ /// semantic context).
+ virtual bool isOutOfLine() const;
/// setDeclContext - Set both the semantic and lexical DeclContext
/// to DC.
@@ -1234,6 +1239,12 @@ public:
return const_cast<DeclContext *>(this)->getEnclosingNamespaceContext();
}
+ /// \brief Retrieve the outermost lexically enclosing record context.
+ RecordDecl *getOuterLexicalRecordContext();
+ const RecordDecl *getOuterLexicalRecordContext() const {
+ return const_cast<DeclContext *>(this)->getOuterLexicalRecordContext();
+ }
+
/// \brief Test if this context is part of the enclosing namespace set of
/// the context NS, as defined in C++0x [namespace.def]p9. If either context
/// isn't a namespace, this is equivalent to Equals().
@@ -1642,7 +1653,7 @@ public:
void dumpDeclContext() const;
void dumpLookups() const;
- void dumpLookups(llvm::raw_ostream &OS) const;
+ void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false) const;
private:
void reconcileExternalVisibleStorage() const;
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 72fad7c28e49..027b41e27da3 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -538,6 +538,12 @@ class CXXRecordDecl : public RecordDecl {
ManglingNumber(0), ContextDecl(nullptr), Captures(nullptr),
MethodTyInfo(Info) {
IsLambda = true;
+
+ // C++11 [expr.prim.lambda]p3:
+ // This class type is neither an aggregate nor a literal type.
+ Aggregate = false;
+ PlainOldData = false;
+ HasNonLiteralTypeFieldsOrBases = true;
}
/// \brief Whether this lambda is known to be dependent, even if its
@@ -820,7 +826,11 @@ public:
/// This value is used for lazy creation of default constructors.
bool needsImplicitDefaultConstructor() const {
return !data().UserDeclaredConstructor &&
- !(data().DeclaredSpecialMembers & SMF_DefaultConstructor);
+ !(data().DeclaredSpecialMembers & SMF_DefaultConstructor) &&
+ // C++14 [expr.prim.lambda]p20:
+ // The closure type associated with a lambda-expression has no
+ // default constructor.
+ !isLambda();
}
/// \brief Determine whether this class has any user-declared constructors.
@@ -1371,6 +1381,15 @@ public:
/// \brief Set the kind of specialization or template instantiation this is.
void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
+ /// \brief Retrieve the record declaration from which this record could be
+ /// instantiated. Returns null if this class is not a template instantiation.
+ const CXXRecordDecl *getTemplateInstantiationPattern() const;
+
+ CXXRecordDecl *getTemplateInstantiationPattern() {
+ return const_cast<CXXRecordDecl *>(const_cast<const CXXRecordDecl *>(this)
+ ->getTemplateInstantiationPattern());
+ }
+
/// \brief Returns the destructor decl for this class.
CXXDestructorDecl *getDestructor() const;
@@ -2104,8 +2123,8 @@ public:
}
ArrayRef<VarDecl *> getArrayIndexes() {
assert(getNumArrayIndices() != 0 && "Getting indexes for non-array init");
- return ArrayRef<VarDecl *>(reinterpret_cast<VarDecl **>(this + 1),
- getNumArrayIndices());
+ return llvm::makeArrayRef(reinterpret_cast<VarDecl **>(this + 1),
+ getNumArrayIndices());
}
/// \brief Get the initializer.
@@ -2636,7 +2655,8 @@ public:
/// \code
/// namespace Foo = Bar;
/// \endcode
-class NamespaceAliasDecl : public NamedDecl {
+class NamespaceAliasDecl : public NamedDecl,
+ public Redeclarable<NamespaceAliasDecl> {
void anchor() override;
/// \brief The location of the \c namespace keyword.
@@ -2654,17 +2674,47 @@ class NamespaceAliasDecl : public NamedDecl {
/// a NamespaceAliasDecl.
NamedDecl *Namespace;
- NamespaceAliasDecl(DeclContext *DC, SourceLocation NamespaceLoc,
- SourceLocation AliasLoc, IdentifierInfo *Alias,
- NestedNameSpecifierLoc QualifierLoc,
+ NamespaceAliasDecl(ASTContext &C, DeclContext *DC,
+ SourceLocation NamespaceLoc, SourceLocation AliasLoc,
+ IdentifierInfo *Alias, NestedNameSpecifierLoc QualifierLoc,
SourceLocation IdentLoc, NamedDecl *Namespace)
- : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias),
- NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc),
- QualifierLoc(QualifierLoc), Namespace(Namespace) { }
+ : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias), redeclarable_base(C),
+ NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc),
+ QualifierLoc(QualifierLoc), Namespace(Namespace) {}
+
+ typedef Redeclarable<NamespaceAliasDecl> redeclarable_base;
+ NamespaceAliasDecl *getNextRedeclarationImpl() override;
+ NamespaceAliasDecl *getPreviousDeclImpl() override;
+ NamespaceAliasDecl *getMostRecentDeclImpl() override;
friend class ASTDeclReader;
public:
+ static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation NamespaceLoc,
+ SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation IdentLoc,
+ NamedDecl *Namespace);
+
+ static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ typedef redeclarable_base::redecl_range redecl_range;
+ typedef redeclarable_base::redecl_iterator redecl_iterator;
+ using redeclarable_base::redecls_begin;
+ using redeclarable_base::redecls_end;
+ using redeclarable_base::redecls;
+ using redeclarable_base::getPreviousDecl;
+ using redeclarable_base::getMostRecentDecl;
+
+ NamespaceAliasDecl *getCanonicalDecl() override {
+ return getFirstDecl();
+ }
+ const NamespaceAliasDecl *getCanonicalDecl() const {
+ return getFirstDecl();
+ }
+
/// \brief Retrieve the nested-name-specifier that qualifies the
/// name of the namespace, with source-location information.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
@@ -2701,16 +2751,6 @@ public:
/// may either be a NamespaceDecl or a NamespaceAliasDecl.
NamedDecl *getAliasedNamespace() const { return Namespace; }
- static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation NamespaceLoc,
- SourceLocation AliasLoc,
- IdentifierInfo *Alias,
- NestedNameSpecifierLoc QualifierLoc,
- SourceLocation IdentLoc,
- NamedDecl *Namespace);
-
- static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID);
-
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(NamespaceLoc, IdentLoc);
}
@@ -2824,7 +2864,7 @@ public:
/// \code
/// using someNameSpace::someIdentifier;
/// \endcode
-class UsingDecl : public NamedDecl {
+class UsingDecl : public NamedDecl, public Mergeable<UsingDecl> {
void anchor() override;
/// \brief The source location of the 'using' keyword itself.
@@ -2948,6 +2988,10 @@ public:
SourceRange getSourceRange() const override LLVM_READONLY;
+ /// Retrieves the canonical declaration of this declaration.
+ UsingDecl *getCanonicalDecl() override { return getFirstDecl(); }
+ const UsingDecl *getCanonicalDecl() const { return getFirstDecl(); }
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Using; }
@@ -2966,7 +3010,8 @@ public:
/// using Base<T>::foo;
/// };
/// \endcode
-class UnresolvedUsingValueDecl : public ValueDecl {
+class UnresolvedUsingValueDecl : public ValueDecl,
+ public Mergeable<UnresolvedUsingValueDecl> {
void anchor() override;
/// \brief The source location of the 'using' keyword
@@ -3022,6 +3067,14 @@ public:
SourceRange getSourceRange() const override LLVM_READONLY;
+ /// Retrieves the canonical declaration of this declaration.
+ UnresolvedUsingValueDecl *getCanonicalDecl() override {
+ return getFirstDecl();
+ }
+ const UnresolvedUsingValueDecl *getCanonicalDecl() const {
+ return getFirstDecl();
+ }
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == UnresolvedUsingValue; }
@@ -3040,7 +3093,9 @@ public:
///
/// The type associated with an unresolved using typename decl is
/// currently always a typename type.
-class UnresolvedUsingTypenameDecl : public TypeDecl {
+class UnresolvedUsingTypenameDecl
+ : public TypeDecl,
+ public Mergeable<UnresolvedUsingTypenameDecl> {
void anchor() override;
/// \brief The source location of the 'typename' keyword
@@ -3084,6 +3139,14 @@ public:
static UnresolvedUsingTypenameDecl *
CreateDeserialized(ASTContext &C, unsigned ID);
+ /// Retrieves the canonical declaration of this declaration.
+ UnresolvedUsingTypenameDecl *getCanonicalDecl() override {
+ return getFirstDecl();
+ }
+ const UnresolvedUsingTypenameDecl *getCanonicalDecl() const {
+ return getFirstDecl();
+ }
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; }
};
diff --git a/include/clang/AST/DeclLookups.h b/include/clang/AST/DeclLookups.h
index d2016af89f13..eba2266724fd 100644
--- a/include/clang/AST/DeclLookups.h
+++ b/include/clang/AST/DeclLookups.h
@@ -75,7 +75,10 @@ inline DeclContext::lookups_range DeclContext::lookups() const {
if (StoredDeclsMap *Map = Primary->buildLookup())
return lookups_range(all_lookups_iterator(Map->begin(), Map->end()),
all_lookups_iterator(Map->end(), Map->end()));
- return lookups_range();
+
+ // Synthesize an empty range. This requires that two default constructed
+ // versions of these iterators form a valid empty range.
+ return lookups_range(all_lookups_iterator(), all_lookups_iterator());
}
inline DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
@@ -91,7 +94,10 @@ inline DeclContext::lookups_range DeclContext::noload_lookups() const {
if (StoredDeclsMap *Map = Primary->getLookupPtr())
return lookups_range(all_lookups_iterator(Map->begin(), Map->end()),
all_lookups_iterator(Map->end(), Map->end()));
- return lookups_range();
+
+ // Synthesize an empty range. This requires that two default constructed
+ // versions of these iterators form a valid empty range.
+ return lookups_range(all_lookups_iterator(), all_lookups_iterator());
}
inline
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index db3b0849382a..55d4b0f16953 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -329,6 +329,7 @@ public:
QualType getReturnType() const { return MethodDeclType; }
void setReturnType(QualType T) { MethodDeclType = T; }
+ SourceRange getReturnTypeSourceRange() const;
/// \brief Determine the type of an expression that sends a message to this
/// function.
@@ -378,8 +379,7 @@ public:
/// ignored.
void setMethodParams(ASTContext &C,
ArrayRef<ParmVarDecl*> Params,
- ArrayRef<SourceLocation> SelLocs =
- ArrayRef<SourceLocation>());
+ ArrayRef<SourceLocation> SelLocs = llvm::None);
// Iterator access to parameter types.
typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun;
@@ -591,7 +591,8 @@ public:
bool HasUserDeclaredSetterMethod(const ObjCPropertyDecl *P) const;
ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const;
- ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const;
+ ObjCPropertyDecl *
+ FindPropertyDeclaration(const IdentifierInfo *PropertyId) const;
typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
@@ -2354,7 +2355,7 @@ public:
/// Lookup a property by name in the specified DeclContext.
static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC,
- IdentifierInfo *propertyID);
+ const IdentifierInfo *propertyID);
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCProperty; }
diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h
index 1b329dcd0052..7f0616f1e603 100644
--- a/include/clang/AST/DeclOpenMP.h
+++ b/include/clang/AST/DeclOpenMP.h
@@ -12,13 +12,14 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_OPENMP_H
-#define LLVM_CLANG_AST_OPENMP_H
+#ifndef LLVM_CLANG_AST_DECLOPENMP_H
+#define LLVM_CLANG_AST_DECLOPENMP_H
#include "clang/AST/DeclBase.h"
#include "llvm/ADT/ArrayRef.h"
namespace clang {
+class Expr;
/// \brief This represents '#pragma omp threadprivate ...' directive.
/// For example, in the following, both 'a' and 'A::b' are threadprivate:
@@ -42,9 +43,8 @@ class OMPThreadPrivateDecl : public Decl {
Decl(DK, DC, L), NumVars(0) { }
ArrayRef<const Expr *> getVars() const {
- return ArrayRef<const Expr *>(
- reinterpret_cast<const Expr * const *>(this + 1),
- NumVars);
+ return llvm::makeArrayRef(reinterpret_cast<const Expr * const *>(this + 1),
+ NumVars);
}
MutableArrayRef<Expr *> getVars() {
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 980a06e35b70..9283d2dc4350 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -87,10 +87,10 @@ public:
unsigned size() const { return NumParams; }
ArrayRef<NamedDecl*> asArray() {
- return ArrayRef<NamedDecl*>(begin(), size());
+ return llvm::makeArrayRef(begin(), end());
}
ArrayRef<const NamedDecl*> asArray() const {
- return ArrayRef<const NamedDecl*>(begin(), size());
+ return llvm::makeArrayRef(begin(), size());
}
NamedDecl* getParam(unsigned Idx) {
@@ -204,7 +204,7 @@ public:
/// \brief Produce this as an array ref.
ArrayRef<TemplateArgument> asArray() const {
- return ArrayRef<TemplateArgument>(data(), size());
+ return llvm::makeArrayRef(data(), size());
}
/// \brief Retrieve the number of template arguments in this
@@ -236,7 +236,7 @@ protected:
TemplateParams(nullptr) {}
// Construct a template decl with the given name and parameters.
- // Used when there is not templated element (tt-params, alias?).
+ // Used when there is not templated element (tt-params).
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
DeclarationName Name, TemplateParameterList *Params)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr),
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index 3076b30cd377..49e51e09b830 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -59,6 +59,7 @@ public:
CXXLiteralOperatorName,
CXXUsingDirective
};
+ static const unsigned NumNameKinds = CXXUsingDirective + 1;
private:
/// StoredNameKind - The kind of name that is actually stored in the
diff --git a/include/clang/AST/DependentDiagnostic.h b/include/clang/AST/DependentDiagnostic.h
index 63047ec4db84..8e038c83c989 100644
--- a/include/clang/AST/DependentDiagnostic.h
+++ b/include/clang/AST/DependentDiagnostic.h
@@ -15,8 +15,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
-#define LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
+#ifndef LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
+#define LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclContextInternals.h"
@@ -178,7 +178,8 @@ inline DeclContext::ddiag_range DeclContext::ddiags() const {
= static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr());
if (!Map)
- return ddiag_range();
+ // Return an empty range using the always-end default constructor.
+ return ddiag_range(ddiag_iterator(), ddiag_iterator());
return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator());
}
diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h
index 12c4fcc49b01..59de104b83f9 100644
--- a/include/clang/AST/EvaluatedExprVisitor.h
+++ b/include/clang/AST/EvaluatedExprVisitor.h
@@ -56,6 +56,17 @@ public:
return this->Visit(E->getChosenSubExpr());
}
+ void VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ // The controlling expression of a generic selection is not evaluated.
+
+ // Don't visit either child expression if the condition is type-dependent.
+ if (E->isResultDependent())
+ return;
+ // Only the selected subexpression matters; the other subexpressions and the
+ // controlling expression are not evaluated.
+ return this->Visit(E->getResultExpr());
+ }
+
void VisitDesignatedInitExpr(DesignatedInitExpr *E) {
// Only the actual initializer matters; the designators are all constant
// expressions.
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index b4bb0b6b6440..c410f2358bc7 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -45,6 +45,7 @@ namespace clang {
class ObjCPropertyRefExpr;
class OpaqueValueExpr;
class ParmVarDecl;
+ class StringLiteral;
class TargetInfo;
class ValueDecl;
@@ -124,8 +125,7 @@ public:
QualType getType() const { return TR; }
void setType(QualType t) {
// In C++, the type of an expression is always adjusted so that it
- // will not have reference type an expression will never have
- // reference type (C++ [expr]p6). Use
+ // will not have reference type (C++ [expr]p6). Use
// QualType::getNonReferenceType() to retrieve the non-reference
// type. Additionally, inspect Expr::isLvalue to determine whether
// an expression that is adjusted in this manner should be
@@ -586,8 +586,13 @@ public:
/// HasSideEffects - This routine returns true for all those expressions
/// which have any effect other than producing a value. Example is a function
- /// call, volatile variable read, or throwing an exception.
- bool HasSideEffects(const ASTContext &Ctx) const;
+ /// call, volatile variable read, or throwing an exception. If
+ /// IncludePossibleEffects is false, this call treats certain expressions with
+ /// potential side effects (such as function call-like expressions,
+ /// instantiation-dependent expressions, or invocations from a macro) as not
+ /// having side effects.
+ bool HasSideEffects(const ASTContext &Ctx,
+ bool IncludePossibleEffects = true) const;
/// \brief Determine whether this expression involves a call to any function
/// that is not trivial.
@@ -886,9 +891,9 @@ public:
/// DeclRefExprBits.HasTemplateKWAndArgsInfo:
/// Specifies when this declaration reference expression has an explicit
/// C++ template keyword and/or template argument list.
-/// DeclRefExprBits.RefersToEnclosingLocal
+/// DeclRefExprBits.RefersToEnclosingVariableOrCapture
/// Specifies when this declaration reference expression (validly)
-/// refers to a local variable from a different function.
+/// refers to an enclosed local or a captured variable.
class DeclRefExpr : public Expr {
/// \brief The declaration that we are referencing.
ValueDecl *D;
@@ -933,7 +938,7 @@ class DeclRefExpr : public Expr {
DeclRefExpr(const ASTContext &Ctx,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
- ValueDecl *D, bool refersToEnclosingLocal,
+ ValueDecl *D, bool RefersToEnlosingVariableOrCapture,
const DeclarationNameInfo &NameInfo,
NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs,
@@ -948,7 +953,7 @@ class DeclRefExpr : public Expr {
void computeDependence(const ASTContext &C);
public:
- DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T,
+ DeclRefExpr(ValueDecl *D, bool RefersToEnclosingVariableOrCapture, QualType T,
ExprValueKind VK, SourceLocation L,
const DeclarationNameLoc &LocInfo = DeclarationNameLoc())
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
@@ -957,20 +962,22 @@ public:
DeclRefExprBits.HasTemplateKWAndArgsInfo = 0;
DeclRefExprBits.HasFoundDecl = 0;
DeclRefExprBits.HadMultipleCandidates = 0;
- DeclRefExprBits.RefersToEnclosingLocal = refersToEnclosingLocal;
+ DeclRefExprBits.RefersToEnclosingVariableOrCapture =
+ RefersToEnclosingVariableOrCapture;
computeDependence(D->getASTContext());
}
static DeclRefExpr *
Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc, ValueDecl *D, bool isEnclosingLocal,
- SourceLocation NameLoc, QualType T, ExprValueKind VK,
- NamedDecl *FoundD = nullptr,
+ SourceLocation TemplateKWLoc, ValueDecl *D,
+ bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc,
+ QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr,
const TemplateArgumentListInfo *TemplateArgs = nullptr);
static DeclRefExpr *
Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc, ValueDecl *D, bool isEnclosingLocal,
+ SourceLocation TemplateKWLoc, ValueDecl *D,
+ bool RefersToEnclosingVariableOrCapture,
const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK,
NamedDecl *FoundD = nullptr,
const TemplateArgumentListInfo *TemplateArgs = nullptr);
@@ -1144,10 +1151,10 @@ public:
DeclRefExprBits.HadMultipleCandidates = V;
}
- /// Does this DeclRefExpr refer to a local declaration from an
- /// enclosing function scope?
- bool refersToEnclosingLocal() const {
- return DeclRefExprBits.RefersToEnclosingLocal;
+ /// \brief Does this DeclRefExpr refer to an enclosing local or a captured
+ /// variable?
+ bool refersToEnclosingVariableOrCapture() const {
+ return DeclRefExprBits.RefersToEnclosingVariableOrCapture;
}
static bool classof(const Stmt *T) {
@@ -1161,7 +1168,7 @@ public:
friend class ASTStmtWriter;
};
-/// PredefinedExpr - [C99 6.4.2.2] - A predefined identifier such as __func__.
+/// \brief [C99 6.4.2.2] - A predefined identifier such as __func__.
class PredefinedExpr : public Expr {
public:
enum IdentType {
@@ -1171,7 +1178,7 @@ public:
FuncDName,
FuncSig,
PrettyFunction,
- /// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
+ /// \brief The same as PrettyFunction, except that the
/// 'virtual' keyword is omitted for virtual member functions.
PrettyFunctionNoVirtual
};
@@ -1179,24 +1186,27 @@ public:
private:
SourceLocation Loc;
IdentType Type;
+ Stmt *FnName;
+
public:
- PredefinedExpr(SourceLocation l, QualType type, IdentType IT)
- : Expr(PredefinedExprClass, type, VK_LValue, OK_Ordinary,
- type->isDependentType(), type->isDependentType(),
- type->isInstantiationDependentType(),
- /*ContainsUnexpandedParameterPack=*/false),
- Loc(l), Type(IT) {}
+ PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT,
+ StringLiteral *SL);
/// \brief Construct an empty predefined expression.
explicit PredefinedExpr(EmptyShell Empty)
- : Expr(PredefinedExprClass, Empty) { }
+ : Expr(PredefinedExprClass, Empty), Loc(), Type(Func), FnName(nullptr) {}
IdentType getIdentType() const { return Type; }
- void setIdentType(IdentType IT) { Type = IT; }
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
+ StringLiteral *getFunctionName();
+ const StringLiteral *getFunctionName() const {
+ return const_cast<PredefinedExpr *>(this)->getFunctionName();
+ }
+
+ static StringRef getIdentTypeName(IdentType IT);
static std::string ComputeName(IdentType IT, const Decl *CurrentDecl);
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
@@ -1207,7 +1217,9 @@ public:
}
// Iterators
- child_range children() { return child_range(); }
+ child_range children() { return child_range(&FnName, &FnName + 1); }
+
+ friend class ASTStmtReader;
};
/// \brief Used by IntegerLiteral/FloatingLiteral to store the numeric without
@@ -2212,11 +2224,11 @@ public:
/// getArg - Return the specified argument.
Expr *getArg(unsigned Arg) {
assert(Arg < NumArgs && "Arg access out of range!");
- return cast<Expr>(SubExprs[Arg+getNumPreArgs()+PREARGS_START]);
+ return cast_or_null<Expr>(SubExprs[Arg + getNumPreArgs() + PREARGS_START]);
}
const Expr *getArg(unsigned Arg) const {
assert(Arg < NumArgs && "Arg access out of range!");
- return cast<Expr>(SubExprs[Arg+getNumPreArgs()+PREARGS_START]);
+ return cast_or_null<Expr>(SubExprs[Arg + getNumPreArgs() + PREARGS_START]);
}
/// setArg - Set the specified argument.
@@ -2256,8 +2268,8 @@ public:
/// interface. This provides efficient reverse iteration of the
/// subexpressions. This is currently used for CFG construction.
ArrayRef<Stmt*> getRawSubExprs() {
- return ArrayRef<Stmt*>(SubExprs,
- getNumPreArgs() + PREARGS_START + getNumArgs());
+ return llvm::makeArrayRef(SubExprs,
+ getNumPreArgs() + PREARGS_START + getNumArgs());
}
/// getNumCommas - Return the number of commas that must have been present in
@@ -2653,9 +2665,6 @@ public:
/// representation in the source code (ExplicitCastExpr's derived
/// classes).
class CastExpr : public Expr {
-public:
- typedef clang::CastKind CastKind;
-
private:
Stmt *Op;
@@ -2673,20 +2682,23 @@ private:
}
protected:
- CastExpr(StmtClass SC, QualType ty, ExprValueKind VK,
- const CastKind kind, Expr *op, unsigned BasePathSize) :
- Expr(SC, ty, VK, OK_Ordinary,
- // Cast expressions are type-dependent if the type is
- // dependent (C++ [temp.dep.expr]p3).
- ty->isDependentType(),
- // Cast expressions are value-dependent if the type is
- // dependent or if the subexpression is value-dependent.
- ty->isDependentType() || (op && op->isValueDependent()),
- (ty->isInstantiationDependentType() ||
- (op && op->isInstantiationDependent())),
- (ty->containsUnexpandedParameterPack() ||
- (op && op->containsUnexpandedParameterPack()))),
- Op(op) {
+ CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, const CastKind kind,
+ Expr *op, unsigned BasePathSize)
+ : Expr(SC, ty, VK, OK_Ordinary,
+ // Cast expressions are type-dependent if the type is
+ // dependent (C++ [temp.dep.expr]p3).
+ ty->isDependentType(),
+ // Cast expressions are value-dependent if the type is
+ // dependent or if the subexpression is value-dependent.
+ ty->isDependentType() || (op && op->isValueDependent()),
+ (ty->isInstantiationDependentType() ||
+ (op && op->isInstantiationDependent())),
+ // An implicit cast expression doesn't (lexically) contain an
+ // unexpanded pack, even if its target type does.
+ ((SC != ImplicitCastExprClass &&
+ ty->containsUnexpandedParameterPack()) ||
+ (op && op->containsUnexpandedParameterPack()))),
+ Op(op) {
assert(kind != CK_Invalid && "creating cast with invalid cast kind");
CastExprBits.Kind = kind;
setBasePathSize(BasePathSize);
@@ -4841,6 +4853,24 @@ public:
return child_range(SubExprs, SubExprs+NumSubExprs);
}
};
+
+/// TypoExpr - Internal placeholder for expressions where typo correction
+/// still needs to be performed and/or an error diagnostic emitted.
+class TypoExpr : public Expr {
+public:
+ TypoExpr(QualType T)
+ : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary,
+ /*isTypeDependent*/ true,
+ /*isValueDependent*/ true,
+ /*isInstantiationDependent*/ true,
+ /*containsUnexpandedParameterPack*/ false) {
+ assert(T->isDependentType() && "TypoExpr given a non-dependent type");
+ }
+
+ child_range children() { return child_range(); }
+ SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
+};
} // end namespace clang
#endif
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 3a43d6dac140..176817823ea9 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -17,10 +17,10 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/LambdaCapture.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/ExpressionTraits.h"
-#include "clang/AST/LambdaCapture.h"
#include "clang/Basic/TypeTraits.h"
#include "llvm/Support/Compiler.h"
@@ -967,8 +967,14 @@ public:
const FieldDecl *getField() const { return Field; }
/// \brief Get the initialization expression that will be used.
- const Expr *getExpr() const { return Field->getInClassInitializer(); }
- Expr *getExpr() { return Field->getInClassInitializer(); }
+ const Expr *getExpr() const {
+ assert(Field->getInClassInitializer() && "initializer hasn't been parsed");
+ return Field->getInClassInitializer();
+ }
+ Expr *getExpr() {
+ assert(Field->getInClassInitializer() && "initializer hasn't been parsed");
+ return Field->getInClassInitializer();
+ }
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
@@ -1165,6 +1171,13 @@ public:
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
+ typedef llvm::iterator_range<arg_iterator> arg_range;
+ typedef llvm::iterator_range<const_arg_iterator> arg_const_range;
+
+ arg_range arguments() { return arg_range(arg_begin(), arg_end()); }
+ arg_const_range arguments() const {
+ return arg_const_range(arg_begin(), arg_end());
+ }
arg_iterator arg_begin() { return Args; }
arg_iterator arg_end() { return Args + NumArgs; }
@@ -1569,12 +1582,12 @@ class CXXScalarValueInitExpr : public Expr {
public:
/// \brief Create an explicitly-written scalar-value initialization
/// expression.
- CXXScalarValueInitExpr(QualType Type,
- TypeSourceInfo *TypeInfo,
- SourceLocation rParenLoc ) :
- Expr(CXXScalarValueInitExprClass, Type, VK_RValue, OK_Ordinary,
- false, false, Type->isInstantiationDependentType(), false),
- RParenLoc(rParenLoc), TypeInfo(TypeInfo) {}
+ CXXScalarValueInitExpr(QualType Type, TypeSourceInfo *TypeInfo,
+ SourceLocation rParenLoc)
+ : Expr(CXXScalarValueInitExprClass, Type, VK_RValue, OK_Ordinary,
+ false, false, Type->isInstantiationDependentType(),
+ Type->containsUnexpandedParameterPack()),
+ RParenLoc(rParenLoc), TypeInfo(TypeInfo) {}
explicit CXXScalarValueInitExpr(EmptyShell Shell)
: Expr(CXXScalarValueInitExprClass, Shell) { }
@@ -2113,7 +2126,7 @@ public:
/// \brief Retrieve the argument types.
ArrayRef<TypeSourceInfo *> getArgs() const {
- return ArrayRef<TypeSourceInfo *>(getTypeSourceInfos(), getNumArgs());
+ return llvm::makeArrayRef(getTypeSourceInfos(), getNumArgs());
}
typedef TypeSourceInfo **arg_iterator;
@@ -2767,7 +2780,7 @@ public:
ArrayRef<CleanupObject> objects);
ArrayRef<CleanupObject> getObjects() const {
- return ArrayRef<CleanupObject>(getObjectsBuffer(), getNumObjects());
+ return llvm::makeArrayRef(getObjectsBuffer(), getNumObjects());
}
unsigned getNumObjects() const { return ExprWithCleanupsBits.NumObjects; }
@@ -2902,8 +2915,9 @@ public:
SourceLocation getLocStart() const LLVM_READONLY;
SourceLocation getLocEnd() const LLVM_READONLY {
- assert(RParenLoc.isValid() || NumArgs == 1);
- return RParenLoc.isValid() ? RParenLoc : getArg(0)->getLocEnd();
+ if (!RParenLoc.isValid() && NumArgs > 0)
+ return getArg(NumArgs - 1)->getLocEnd();
+ return RParenLoc;
}
static bool classof(const Stmt *T) {
@@ -3811,6 +3825,69 @@ public:
}
};
+/// \brief Represents a folding of a pack over an operator.
+///
+/// This expression is always dependent and represents a pack expansion of the
+/// forms:
+///
+/// ( expr op ... )
+/// ( ... op expr )
+/// ( expr op ... op expr )
+class CXXFoldExpr : public Expr {
+ SourceLocation LParenLoc;
+ SourceLocation EllipsisLoc;
+ SourceLocation RParenLoc;
+ Stmt *SubExprs[2];
+ BinaryOperatorKind Opcode;
+
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+public:
+ CXXFoldExpr(QualType T, SourceLocation LParenLoc, Expr *LHS,
+ BinaryOperatorKind Opcode, SourceLocation EllipsisLoc, Expr *RHS,
+ SourceLocation RParenLoc)
+ : Expr(CXXFoldExprClass, T, VK_RValue, OK_Ordinary,
+ /*Dependent*/ true, true, true,
+ /*ContainsUnexpandedParameterPack*/ false),
+ LParenLoc(LParenLoc), EllipsisLoc(EllipsisLoc), RParenLoc(RParenLoc),
+ Opcode(Opcode) {
+ SubExprs[0] = LHS;
+ SubExprs[1] = RHS;
+ }
+ CXXFoldExpr(EmptyShell Empty) : Expr(CXXFoldExprClass, Empty) {}
+
+ Expr *getLHS() const { return static_cast<Expr*>(SubExprs[0]); }
+ Expr *getRHS() const { return static_cast<Expr*>(SubExprs[1]); }
+
+ /// Does this produce a right-associated sequence of operators?
+ bool isRightFold() const {
+ return getLHS() && getLHS()->containsUnexpandedParameterPack();
+ }
+ /// Does this produce a left-associated sequence of operators?
+ bool isLeftFold() const { return !isRightFold(); }
+ /// Get the pattern, that is, the operand that contains an unexpanded pack.
+ Expr *getPattern() const { return isLeftFold() ? getRHS() : getLHS(); }
+ /// Get the operand that doesn't contain a pack, for a binary fold.
+ Expr *getInit() const { return isLeftFold() ? getLHS() : getRHS(); }
+
+ SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
+ BinaryOperatorKind getOperator() const { return Opcode; }
+
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return LParenLoc;
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return RParenLoc;
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXFoldExprClass;
+ }
+
+ // Iterators
+ child_range children() { return child_range(SubExprs, SubExprs + 2); }
+};
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 817c0cc43131..f296e8f71d30 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -124,6 +124,15 @@ public:
// Iterators
child_range children() { return child_range(&SubExpr, &SubExpr+1); }
+
+ typedef ConstExprIterator const_arg_iterator;
+
+ const_arg_iterator arg_begin() const {
+ return reinterpret_cast<Stmt const * const*>(&SubExpr);
+ }
+ const_arg_iterator arg_end() const {
+ return reinterpret_cast<Stmt const * const*>(&SubExpr + 1);
+ }
friend class ASTStmtReader;
};
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index 1e8eff38d3ec..ff1d180ee8c6 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -11,8 +11,8 @@
// construction of AST nodes from some external source.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
-#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+#ifndef LLVM_CLANG_AST_EXTERNALASTSOURCE_H
+#define LLVM_CLANG_AST_EXTERNALASTSOURCE_H
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclBase.h"
@@ -650,4 +650,4 @@ typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
} // end namespace clang
-#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+#endif
diff --git a/include/clang/AST/LambdaCapture.h b/include/clang/AST/LambdaCapture.h
index 8633c9796523..a7468a0fd53f 100644
--- a/include/clang/AST/LambdaCapture.h
+++ b/include/clang/AST/LambdaCapture.h
@@ -68,13 +68,23 @@ public:
/// \brief Determine whether this capture handles the C++ \c this
/// pointer.
- bool capturesThis() const { return DeclAndBits.getPointer() == nullptr; }
+ bool capturesThis() const {
+ return (DeclAndBits.getPointer() == nullptr) &&
+ !(DeclAndBits.getInt() & Capture_ByCopy);
+ }
/// \brief Determine whether this capture handles a variable.
bool capturesVariable() const {
return dyn_cast_or_null<VarDecl>(DeclAndBits.getPointer());
}
+ /// \brief Determine whether this captures a variable length array bound
+ /// expression.
+ bool capturesVLAType() const {
+ return (DeclAndBits.getPointer() == nullptr) &&
+ (DeclAndBits.getInt() & Capture_ByCopy);
+ }
+
/// \brief Determine whether this is an init-capture.
bool isInitCapture() const {
return capturesVariable() && getCapturedVar()->isInitCapture();
diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h
index a8d119971b33..cbe08a1a765e 100644
--- a/include/clang/AST/Mangle.h
+++ b/include/clang/AST/Mangle.h
@@ -156,6 +156,11 @@ public:
virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D,
raw_ostream &) = 0;
+ virtual void mangleCXXCtorComdat(const CXXConstructorDecl *D,
+ raw_ostream &) = 0;
+ virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D,
+ raw_ostream &) = 0;
+
static bool classof(const MangleContext *C) {
return C->getKind() == MK_Itanium;
}
diff --git a/include/clang/AST/MangleNumberingContext.h b/include/clang/AST/MangleNumberingContext.h
index 56c995264b32..7a818557fdb7 100644
--- a/include/clang/AST/MangleNumberingContext.h
+++ b/include/clang/AST/MangleNumberingContext.h
@@ -12,8 +12,8 @@
// literals.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_MANGLENUMBERINGCONTEXT_H
-#define LLVM_CLANG_MANGLENUMBERINGCONTEXT_H
+#ifndef LLVM_CLANG_AST_MANGLENUMBERINGCONTEXT_H
+#define LLVM_CLANG_AST_MANGLENUMBERINGCONTEXT_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
@@ -30,23 +30,20 @@ class VarDecl;
/// \brief Keeps track of the mangled names of lambda expressions and block
/// literals within a particular context.
-class MangleNumberingContext
- : public RefCountedBase<MangleNumberingContext> {
- llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
-
+class MangleNumberingContext : public RefCountedBase<MangleNumberingContext> {
public:
virtual ~MangleNumberingContext() {}
/// \brief Retrieve the mangling number of a new lambda expression with the
/// given call operator within this context.
- unsigned getManglingNumber(const CXXMethodDecl *CallOperator);
+ virtual unsigned getManglingNumber(const CXXMethodDecl *CallOperator) = 0;
/// \brief Retrieve the mangling number of a new block literal within this
/// context.
- unsigned getManglingNumber(const BlockDecl *BD);
+ virtual unsigned getManglingNumber(const BlockDecl *BD) = 0;
/// Static locals are numbered by source order.
- unsigned getStaticLocalNumber(const VarDecl *VD);
+ virtual unsigned getStaticLocalNumber(const VarDecl *VD) = 0;
/// \brief Retrieve the mangling number of a static local variable within
/// this context.
@@ -58,6 +55,6 @@ public:
virtual unsigned getManglingNumber(const TagDecl *TD,
unsigned MSLocalManglingNumber) = 0;
};
-
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h
index 0b21b0334812..33fcce2109aa 100644
--- a/include/clang/AST/NSAPI.h
+++ b/include/clang/AST/NSAPI.h
@@ -42,7 +42,8 @@ public:
NSStr_stringWithUTF8String,
NSStr_stringWithCStringEncoding,
NSStr_stringWithCString,
- NSStr_initWithString
+ NSStr_initWithString,
+ NSStr_initWithUTF8String
};
static const unsigned NumNSStringMethods = 5;
@@ -100,8 +101,8 @@ public:
NSDict_objectForKey,
NSMutableDict_setObjectForKey
};
- static const unsigned NumNSDictionaryMethods = 11;
-
+ static const unsigned NumNSDictionaryMethods = 12;
+
/// \brief The Objective-C NSDictionary selectors.
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
@@ -184,6 +185,9 @@ public:
bool isObjCNSIntegerType(QualType T) const;
/// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c.
bool isObjCNSUIntegerType(QualType T) const;
+ /// \brief Returns one of NSIntegral typedef names if \param T is a typedef
+ /// of that name in objective-c.
+ StringRef GetNSIntegralKind(QualType T) const;
private:
bool isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const;
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index fc719bdc16c3..518f1232fe8f 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -22,6 +22,7 @@
namespace clang {
class ASTContext;
+class CXXRecordDecl;
class NamespaceAliasDecl;
class NamespaceDecl;
class IdentifierInfo;
@@ -45,7 +46,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
/// \brief Enumeration describing
enum StoredSpecifierKind {
StoredIdentifier = 0,
- StoredNamespaceOrAlias = 1,
+ StoredDecl = 1,
StoredTypeSpec = 2,
StoredTypeSpecWithTemplate = 3
};
@@ -83,7 +84,10 @@ public:
/// stored as a Type*.
TypeSpecWithTemplate,
/// \brief The global specifier '::'. There is no stored value.
- Global
+ Global,
+ /// \brief Microsoft's '__super' specifier, stored as a CXXRecordDecl* of
+ /// the class it appeared in.
+ Super
};
private:
@@ -143,6 +147,11 @@ public:
/// scope.
static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context);
+ /// \brief Returns the nested name specifier representing the __super scope
+ /// for the given CXXRecordDecl.
+ static NestedNameSpecifier *SuperSpecifier(const ASTContext &Context,
+ CXXRecordDecl *RD);
+
/// \brief Return the prefix of this nested name specifier.
///
/// The prefix contains all of the parts of the nested name
@@ -172,6 +181,10 @@ public:
/// specifier.
NamespaceAliasDecl *getAsNamespaceAlias() const;
+ /// \brief Retrieve the record declaration stored in this nested name
+ /// specifier.
+ CXXRecordDecl *getAsRecordDecl() const;
+
/// \brief Retrieve the type stored in this nested name specifier.
const Type *getAsType() const {
if (Prefix.getInt() == StoredTypeSpec ||
@@ -421,7 +434,22 @@ public:
/// \brief Turn this (empty) nested-name-specifier into the global
/// nested-name-specifier '::'.
void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
-
+
+ /// \brief Turns this (empty) nested-name-specifier into '__super'
+ /// nested-name-specifier.
+ ///
+ /// \param Context The AST context in which this nested-name-specifier
+ /// resides.
+ ///
+ /// \param RD The declaration of the class in which nested-name-specifier
+ /// appeared.
+ ///
+ /// \param SuperLoc The location of the '__super' keyword.
+ /// name.
+ ///
+ /// \param ColonColonLoc The location of the trailing '::'.
+ void MakeSuper(ASTContext &Context, CXXRecordDecl *RD,
+ SourceLocation SuperLoc, SourceLocation ColonColonLoc);
/// \brief Make a new nested-name-specifier from incomplete source-location
/// information.
///
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 3345959653a6..0c3002c103e2 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -61,7 +61,7 @@ public:
ConstStmtRange children() const {
return const_cast<OMPClause *>(this)->children();
}
- static bool classof(const OMPClause *T) { return true; }
+ static bool classof(const OMPClause *) { return true; }
};
/// \brief This represents clauses with the list of variables like 'private',
@@ -135,10 +135,10 @@ public:
/// \brief Fetches list of all variables in the clause.
ArrayRef<const Expr *> getVarRefs() const {
- return ArrayRef<const Expr *>(
+ return llvm::makeArrayRef(
reinterpret_cast<const Expr *const *>(
reinterpret_cast<const char *>(this) +
- llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf<Expr *>())),
+ llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf<const Expr *>())),
NumVars);
}
};
@@ -770,6 +770,153 @@ public:
StmtRange children() { return StmtRange(); }
};
+/// \brief This represents 'read' clause in the '#pragma omp atomic' directive.
+///
+/// \code
+/// #pragma omp atomic read
+/// \endcode
+/// In this example directive '#pragma omp atomic' has 'read' clause.
+///
+class OMPReadClause : public OMPClause {
+public:
+ /// \brief Build 'read' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_read, StartLoc, EndLoc) {}
+
+ /// \brief Build an empty clause.
+ ///
+ OMPReadClause() : OMPClause(OMPC_read, SourceLocation(), SourceLocation()) {}
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_read;
+ }
+
+ StmtRange children() { return StmtRange(); }
+};
+
+/// \brief This represents 'write' clause in the '#pragma omp atomic' directive.
+///
+/// \code
+/// #pragma omp atomic write
+/// \endcode
+/// In this example directive '#pragma omp atomic' has 'write' clause.
+///
+class OMPWriteClause : public OMPClause {
+public:
+ /// \brief Build 'write' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPWriteClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_write, StartLoc, EndLoc) {}
+
+ /// \brief Build an empty clause.
+ ///
+ OMPWriteClause()
+ : OMPClause(OMPC_write, SourceLocation(), SourceLocation()) {}
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_write;
+ }
+
+ StmtRange children() { return StmtRange(); }
+};
+
+/// \brief This represents 'update' clause in the '#pragma omp atomic'
+/// directive.
+///
+/// \code
+/// #pragma omp atomic update
+/// \endcode
+/// In this example directive '#pragma omp atomic' has 'update' clause.
+///
+class OMPUpdateClause : public OMPClause {
+public:
+ /// \brief Build 'update' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_update, StartLoc, EndLoc) {}
+
+ /// \brief Build an empty clause.
+ ///
+ OMPUpdateClause()
+ : OMPClause(OMPC_update, SourceLocation(), SourceLocation()) {}
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_update;
+ }
+
+ StmtRange children() { return StmtRange(); }
+};
+
+/// \brief This represents 'capture' clause in the '#pragma omp atomic'
+/// directive.
+///
+/// \code
+/// #pragma omp atomic capture
+/// \endcode
+/// In this example directive '#pragma omp atomic' has 'capture' clause.
+///
+class OMPCaptureClause : public OMPClause {
+public:
+ /// \brief Build 'capture' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_capture, StartLoc, EndLoc) {}
+
+ /// \brief Build an empty clause.
+ ///
+ OMPCaptureClause()
+ : OMPClause(OMPC_capture, SourceLocation(), SourceLocation()) {}
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_capture;
+ }
+
+ StmtRange children() { return StmtRange(); }
+};
+
+/// \brief This represents 'seq_cst' clause in the '#pragma omp atomic'
+/// directive.
+///
+/// \code
+/// #pragma omp atomic seq_cst
+/// \endcode
+/// In this example directive '#pragma omp atomic' has 'seq_cst' clause.
+///
+class OMPSeqCstClause : public OMPClause {
+public:
+ /// \brief Build 'seq_cst' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_seq_cst, StartLoc, EndLoc) {}
+
+ /// \brief Build an empty clause.
+ ///
+ OMPSeqCstClause()
+ : OMPClause(OMPC_seq_cst, SourceLocation(), SourceLocation()) {}
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_seq_cst;
+ }
+
+ StmtRange children() { return StmtRange(); }
+};
+
/// \brief This represents clause 'private' in the '#pragma omp ...' directives.
///
/// \code
@@ -779,6 +926,7 @@ public:
/// with the variables 'a' and 'b'.
///
class OMPPrivateClause : public OMPVarListClause<OMPPrivateClause> {
+ friend class OMPClauseReader;
/// \brief Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
@@ -800,6 +948,20 @@ class OMPPrivateClause : public OMPVarListClause<OMPPrivateClause> {
SourceLocation(), SourceLocation(),
N) {}
+ /// \brief Sets the list of references to private copies with initializers for
+ /// new private variables.
+ /// \param VL List of references.
+ void setPrivateCopies(ArrayRef<Expr *> VL);
+
+ /// \brief Gets the list of references to private copies with initializers for
+ /// new private variables.
+ MutableArrayRef<Expr *> getPrivateCopies() {
+ return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getPrivateCopies() const {
+ return llvm::makeArrayRef(varlist_end(), varlist_size());
+ }
+
public:
/// \brief Creates clause with a list of variables \a VL.
///
@@ -808,10 +970,12 @@ public:
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param VL List of references to the variables.
+ /// \param PrivateVL List of references to private copies with initializers.
///
static OMPPrivateClause *Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc,
- SourceLocation EndLoc, ArrayRef<Expr *> VL);
+ SourceLocation EndLoc, ArrayRef<Expr *> VL,
+ ArrayRef<Expr *> PrivateVL);
/// \brief Creates an empty clause with the place for \a N variables.
///
/// \param C AST context.
@@ -819,6 +983,21 @@ public:
///
static OMPPrivateClause *CreateEmpty(const ASTContext &C, unsigned N);
+ typedef MutableArrayRef<Expr *>::iterator private_copies_iterator;
+ typedef ArrayRef<const Expr *>::iterator private_copies_const_iterator;
+ typedef llvm::iterator_range<private_copies_iterator> private_copies_range;
+ typedef llvm::iterator_range<private_copies_const_iterator>
+ private_copies_const_range;
+
+ private_copies_range private_copies() {
+ return private_copies_range(getPrivateCopies().begin(),
+ getPrivateCopies().end());
+ }
+ private_copies_const_range private_copies() const {
+ return private_copies_const_range(getPrivateCopies().begin(),
+ getPrivateCopies().end());
+ }
+
StmtRange children() {
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
@@ -839,6 +1018,8 @@ public:
/// with the variables 'a' and 'b'.
///
class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> {
+ friend class OMPClauseReader;
+
/// \brief Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
@@ -859,6 +1040,33 @@ class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> {
: OMPVarListClause<OMPFirstprivateClause>(
OMPC_firstprivate, SourceLocation(), SourceLocation(),
SourceLocation(), N) {}
+ /// \brief Sets the list of references to private copies with initializers for
+ /// new private variables.
+ /// \param VL List of references.
+ void setPrivateCopies(ArrayRef<Expr *> VL);
+
+ /// \brief Gets the list of references to private copies with initializers for
+ /// new private variables.
+ MutableArrayRef<Expr *> getPrivateCopies() {
+ return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getPrivateCopies() const {
+ return llvm::makeArrayRef(varlist_end(), varlist_size());
+ }
+
+ /// \brief Sets the list of references to initializer variables for new
+ /// private variables.
+ /// \param VL List of references.
+ void setInits(ArrayRef<Expr *> VL);
+
+ /// \brief Gets the list of references to initializer variables for new
+ /// private variables.
+ MutableArrayRef<Expr *> getInits() {
+ return MutableArrayRef<Expr *>(getPrivateCopies().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getInits() const {
+ return llvm::makeArrayRef(getPrivateCopies().end(), varlist_size());
+ }
public:
/// \brief Creates clause with a list of variables \a VL.
@@ -867,11 +1075,16 @@ public:
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
- /// \param VL List of references to the variables.
+ /// \param VL List of references to the original variables.
+ /// \param PrivateVL List of references to private copies with initializers.
+ /// \param InitVL List of references to auto generated variables used for
+ /// initialization of a single array element. Used if firstprivate variable is
+ /// of array type.
///
static OMPFirstprivateClause *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation EndLoc, ArrayRef<Expr *> VL);
+ SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
+ ArrayRef<Expr *> InitVL);
/// \brief Creates an empty clause with the place for \a N variables.
///
/// \param C AST context.
@@ -879,6 +1092,33 @@ public:
///
static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
+ typedef MutableArrayRef<Expr *>::iterator private_copies_iterator;
+ typedef ArrayRef<const Expr *>::iterator private_copies_const_iterator;
+ typedef llvm::iterator_range<private_copies_iterator> private_copies_range;
+ typedef llvm::iterator_range<private_copies_const_iterator>
+ private_copies_const_range;
+
+ private_copies_range private_copies() {
+ return private_copies_range(getPrivateCopies().begin(),
+ getPrivateCopies().end());
+ }
+ private_copies_const_range private_copies() const {
+ return private_copies_const_range(getPrivateCopies().begin(),
+ getPrivateCopies().end());
+ }
+
+ typedef MutableArrayRef<Expr *>::iterator inits_iterator;
+ typedef ArrayRef<const Expr *>::iterator inits_const_iterator;
+ typedef llvm::iterator_range<inits_iterator> inits_range;
+ typedef llvm::iterator_range<inits_const_iterator> inits_const_range;
+
+ inits_range inits() {
+ return inits_range(getInits().begin(), getInits().end());
+ }
+ inits_const_range inits() const {
+ return inits_const_range(getInits().begin(), getInits().end());
+ }
+
StmtRange children() {
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
@@ -1390,13 +1630,17 @@ public:
}
};
-/// \brief This represents pseudo clause 'flush' for the '#pragma omp flush'
+/// \brief This represents implicit clause 'flush' for the '#pragma omp flush'
/// directive.
+/// This clause does not exist by itself, it can be only as a part of 'omp
+/// flush' directive. This clause is introduced to keep the original structure
+/// of \a OMPExecutableDirective class and its derivatives and to use the
+/// existing infrastructure of clauses with the list of variables.
///
/// \code
/// #pragma omp flush(a,b)
/// \endcode
-/// In this example directive '#pragma omp flush' has pseudo clause 'flush'
+/// In this example directive '#pragma omp flush' has implicit clause 'flush'
/// with the variables 'a' and 'b'.
///
class OMPFlushClause : public OMPVarListClause<OMPFlushClause> {
@@ -1453,3 +1697,4 @@ public:
} // end namespace clang
#endif
+
diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h
index aba88d6c5419..e3f012667727 100644
--- a/include/clang/AST/OperationKinds.h
+++ b/include/clang/AST/OperationKinds.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_OPERATION_KINDS_H
-#define LLVM_CLANG_AST_OPERATION_KINDS_H
+#ifndef LLVM_CLANG_AST_OPERATIONKINDS_H
+#define LLVM_CLANG_AST_OPERATIONKINDS_H
namespace clang {
diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h
index eece8510e9c4..8945c413d268 100644
--- a/include/clang/AST/ParentMap.h
+++ b/include/clang/AST/ParentMap.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PARENTMAP_H
-#define LLVM_CLANG_PARENTMAP_H
+#ifndef LLVM_CLANG_AST_PARENTMAP_H
+#define LLVM_CLANG_AST_PARENTMAP_H
namespace clang {
class Stmt;
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index 349f4c44a4e0..35ceabbd6b71 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H
-#define LLVM_CLANG_AST_PRETTY_PRINTER_H
+#ifndef LLVM_CLANG_AST_PRETTYPRINTER_H
+#define LLVM_CLANG_AST_PRETTYPRINTER_H
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
diff --git a/include/clang/AST/RawCommentList.h b/include/clang/AST/RawCommentList.h
index 8ba85c43f657..2e005ddbd027 100644
--- a/include/clang/AST/RawCommentList.h
+++ b/include/clang/AST/RawCommentList.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_RAW_COMMENT_LIST_H
-#define LLVM_CLANG_AST_RAW_COMMENT_LIST_H
+#ifndef LLVM_CLANG_AST_RAWCOMMENTLIST_H
+#define LLVM_CLANG_AST_RAWCOMMENTLIST_H
#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/SourceManager.h"
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
index 4befb4506212..7b7799884a3d 100644
--- a/include/clang/AST/RecordLayout.h
+++ b/include/clang/AST/RecordLayout.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_LAYOUTINFO_H
-#define LLVM_CLANG_AST_LAYOUTINFO_H
+#ifndef LLVM_CLANG_AST_RECORDLAYOUT_H
+#define LLVM_CLANG_AST_RECORDLAYOUT_H
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index ff46ffb94e70..a1d36180d737 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -429,6 +429,7 @@ private:
bool TraverseFunctionHelper(FunctionDecl *D);
bool TraverseVarHelper(VarDecl *D);
bool TraverseOMPExecutableDirective(OMPExecutableDirective *S);
+ bool TraverseOMPLoopDirective(OMPLoopDirective *S);
bool TraverseOMPClause(OMPClause *C);
#define OPENMP_CLAUSE(Name, Class) bool Visit##Class(Class *C);
#include "clang/Basic/OpenMPKinds.def"
@@ -689,6 +690,7 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier(
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
return true;
case NestedNameSpecifier::TypeSpec:
@@ -713,6 +715,7 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
return true;
case NestedNameSpecifier::TypeSpec:
@@ -940,6 +943,9 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, {
for (const auto &E : T->exceptions()) {
TRY_TO(TraverseType(E));
}
+
+ if (Expr *NE = T->getNoexceptExpr())
+ TRY_TO(TraverseStmt(NE));
})
DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
@@ -1148,6 +1154,9 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, {
for (const auto &E : T->exceptions()) {
TRY_TO(TraverseType(E));
}
+
+ if (Expr *NE = T->getNoexceptExpr())
+ TRY_TO(TraverseStmt(NE));
})
DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
@@ -2144,21 +2153,29 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
TRY_TO(TraverseLambdaCapture(S, C));
}
- if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
- TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
- if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
- // Visit the whole type.
- TRY_TO(TraverseTypeLoc(TL));
- } else if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) {
- if (S->hasExplicitParameters()) {
- // Visit parameters.
- for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) {
- TRY_TO(TraverseDecl(Proto.getParam(I)));
- }
- } else {
- TRY_TO(TraverseTypeLoc(Proto.getReturnLoc()));
+ TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+ FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>();
+
+ if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
+ // Visit the whole type.
+ TRY_TO(TraverseTypeLoc(TL));
+ } else {
+ if (S->hasExplicitParameters()) {
+ // Visit parameters.
+ for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) {
+ TRY_TO(TraverseDecl(Proto.getParam(I)));
}
+ } else if (S->hasExplicitResultType()) {
+ TRY_TO(TraverseTypeLoc(Proto.getReturnLoc()));
+ }
+
+ auto *T = Proto.getTypePtr();
+ for (const auto &E : T->exceptions()) {
+ TRY_TO(TraverseType(E));
}
+
+ if (Expr *NE = T->getNoexceptExpr())
+ TRY_TO(TraverseStmt(NE));
}
TRY_TO(TraverseLambdaBody(S));
@@ -2259,6 +2276,7 @@ DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); })
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {})
DEF_TRAVERSE_STMT(OpaqueValueExpr, {})
+DEF_TRAVERSE_STMT(TypoExpr, {})
DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {})
// These operators (all of them) do not need any action except
@@ -2275,6 +2293,7 @@ DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {})
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {})
+DEF_TRAVERSE_STMT(CXXFoldExpr, {})
DEF_TRAVERSE_STMT(AtomicExpr, {})
// These literals (all of them) do not need any action.
@@ -2301,6 +2320,12 @@ bool RecursiveASTVisitor<Derived>::TraverseOMPExecutableDirective(
return true;
}
+template <typename Derived>
+bool
+RecursiveASTVisitor<Derived>::TraverseOMPLoopDirective(OMPLoopDirective *S) {
+ return TraverseOMPExecutableDirective(S);
+}
+
DEF_TRAVERSE_STMT(OMPParallelDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
@@ -2310,6 +2335,9 @@ DEF_TRAVERSE_STMT(OMPSimdDirective,
DEF_TRAVERSE_STMT(OMPForDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPForSimdDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
DEF_TRAVERSE_STMT(OMPSectionsDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
@@ -2330,6 +2358,9 @@ DEF_TRAVERSE_STMT(OMPCriticalDirective, {
DEF_TRAVERSE_STMT(OMPParallelForDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPParallelForSimdDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
DEF_TRAVERSE_STMT(OMPParallelSectionsDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
@@ -2348,6 +2379,18 @@ DEF_TRAVERSE_STMT(OMPTaskwaitDirective,
DEF_TRAVERSE_STMT(OMPFlushDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPOrderedDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
+DEF_TRAVERSE_STMT(OMPAtomicDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
+DEF_TRAVERSE_STMT(OMPTargetDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
+DEF_TRAVERSE_STMT(OMPTeamsDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
// OpenMP clauses.
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
@@ -2437,6 +2480,31 @@ RecursiveASTVisitor<Derived>::VisitOMPMergeableClause(OMPMergeableClause *) {
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPReadClause(OMPReadClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPWriteClause(OMPWriteClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPUpdateClause(OMPUpdateClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPCaptureClause(OMPCaptureClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPSeqCstClause(OMPSeqCstClause *) {
+ return true;
+}
+
+template <typename Derived>
template <typename T>
bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
for (auto *E : Node->varlists()) {
@@ -2448,6 +2516,9 @@ bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->private_copies()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
@@ -2455,6 +2526,12 @@ template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
OMPFirstprivateClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->private_copies()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->inits()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index fb94097cfac7..eb6836f88699 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -212,7 +212,7 @@ protected:
unsigned HasTemplateKWAndArgsInfo : 1;
unsigned HasFoundDecl : 1;
unsigned HadMultipleCandidates : 1;
- unsigned RefersToEnclosingLocal : 1;
+ unsigned RefersToEnclosingVariableOrCapture : 1;
};
class CastExprBitfields {
@@ -393,6 +393,10 @@ public:
/// statement, such as ExprWithCleanups or ImplicitCastExpr nodes.
Stmt *IgnoreImplicit();
+ /// \brief Skip no-op (attributed, compound) container stmts and skip captured
+ /// stmt at the top, if \a IgnoreCaptured is true.
+ Stmt *IgnoreContainers(bool IgnoreCaptured = false);
+
const Stmt *stripLabelLikeStatements() const;
Stmt *stripLabelLikeStatements() {
return const_cast<Stmt*>(
@@ -548,14 +552,17 @@ public:
///
class CompoundStmt : public Stmt {
Stmt** Body;
- SourceLocation LBracLoc, RBracLoc;
+ SourceLocation LBraceLoc, RBraceLoc;
+
+ friend class ASTStmtReader;
+
public:
CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts,
SourceLocation LB, SourceLocation RB);
// \brief Build an empty compound statement with a location.
explicit CompoundStmt(SourceLocation Loc)
- : Stmt(CompoundStmtClass), Body(nullptr), LBracLoc(Loc), RBracLoc(Loc) {
+ : Stmt(CompoundStmtClass), Body(nullptr), LBraceLoc(Loc), RBraceLoc(Loc) {
CompoundStmtBits.NumStmts = 0;
}
@@ -614,13 +621,11 @@ public:
return const_reverse_body_iterator(body_begin());
}
- SourceLocation getLocStart() const LLVM_READONLY { return LBracLoc; }
- SourceLocation getLocEnd() const LLVM_READONLY { return RBracLoc; }
+ SourceLocation getLocStart() const LLVM_READONLY { return LBraceLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RBraceLoc; }
- SourceLocation getLBracLoc() const { return LBracLoc; }
- void setLBracLoc(SourceLocation L) { LBracLoc = L; }
- SourceLocation getRBracLoc() const { return RBracLoc; }
- void setRBracLoc(SourceLocation L) { RBracLoc = L; }
+ SourceLocation getLBracLoc() const { return LBraceLoc; }
+ SourceLocation getRBracLoc() const { return RBraceLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CompoundStmtClass;
@@ -846,7 +851,7 @@ public:
SourceLocation getAttrLoc() const { return AttrLoc; }
ArrayRef<const Attr*> getAttrs() const {
- return ArrayRef<const Attr*>(getAttrArrayPtr(), NumAttrs);
+ return llvm::makeArrayRef(getAttrArrayPtr(), NumAttrs);
}
Stmt *getSubStmt() { return SubStmt; }
const Stmt *getSubStmt() const { return SubStmt; }
@@ -1010,7 +1015,7 @@ public:
SourceLocation getLocStart() const LLVM_READONLY { return SwitchLoc; }
SourceLocation getLocEnd() const LLVM_READONLY {
- return SubExprs[BODY]->getLocEnd();
+ return SubExprs[BODY] ? SubExprs[BODY]->getLocEnd() : SubExprs[COND]->getLocEnd();
}
// Iterators
@@ -1580,18 +1585,21 @@ public:
Kind MyKind;
std::string Str;
unsigned OperandNo;
+
+ // Source range for operand references.
+ CharSourceRange Range;
public:
AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {}
- AsmStringPiece(unsigned OpNo, char Modifier)
- : MyKind(Operand), Str(), OperandNo(OpNo) {
- Str += Modifier;
+ AsmStringPiece(unsigned OpNo, const std::string &S, SourceLocation Begin,
+ SourceLocation End)
+ : MyKind(Operand), Str(S), OperandNo(OpNo),
+ Range(CharSourceRange::getCharRange(Begin, End)) {
}
bool isString() const { return MyKind == String; }
bool isOperand() const { return MyKind == Operand; }
const std::string &getString() const {
- assert(isString());
return Str;
}
@@ -1600,12 +1608,14 @@ public:
return OperandNo;
}
+ CharSourceRange getRange() const {
+ assert(isOperand() && "Range is currently used only for Operands.");
+ return Range;
+ }
+
/// getModifier - Get the modifier for this operand, if present. This
/// returns '\0' if there was no modifier.
- char getModifier() const {
- assert(isOperand());
- return Str[0];
- }
+ char getModifier() const;
};
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
@@ -1780,14 +1790,14 @@ public:
//===--- Other ---===//
ArrayRef<StringRef> getAllConstraints() const {
- return ArrayRef<StringRef>(Constraints, NumInputs + NumOutputs);
+ return llvm::makeArrayRef(Constraints, NumInputs + NumOutputs);
}
ArrayRef<StringRef> getClobbers() const {
- return ArrayRef<StringRef>(Clobbers, NumClobbers);
+ return llvm::makeArrayRef(Clobbers, NumClobbers);
}
ArrayRef<Expr*> getAllExprs() const {
- return ArrayRef<Expr*>(reinterpret_cast<Expr**>(Exprs),
- NumInputs + NumOutputs);
+ return llvm::makeArrayRef(reinterpret_cast<Expr**>(Exprs),
+ NumInputs + NumOutputs);
}
StringRef getClobber(unsigned i) const { return getClobbers()[i]; }
@@ -1892,24 +1902,22 @@ class SEHTryStmt : public Stmt {
bool IsCXXTry;
SourceLocation TryLoc;
Stmt *Children[2];
- int HandlerIndex;
- int HandlerParentIndex;
enum { TRY = 0, HANDLER = 1 };
SEHTryStmt(bool isCXXTry, // true if 'try' otherwise '__try'
- SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler,
- int HandlerIndex, int HandlerParentIndex);
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler);
friend class ASTReader;
friend class ASTStmtReader;
explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { }
public:
- static SEHTryStmt *Create(const ASTContext &C, bool isCXXTry,
+ static SEHTryStmt* Create(const ASTContext &C, bool isCXXTry,
SourceLocation TryLoc, Stmt *TryBlock,
- Stmt *Handler, int HandlerIndex,
- int HandlerParentIndex);
+ Stmt *Handler);
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); }
@@ -1936,9 +1944,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == SEHTryStmtClass;
}
-
- int getHandlerIndex() const { return HandlerIndex; }
- int getHandlerParentIndex() const { return HandlerParentIndex; }
};
/// Represents a __leave statement.
@@ -1977,15 +1982,18 @@ public:
/// @endcode
class CapturedStmt : public Stmt {
public:
- /// \brief The different capture forms: by 'this' or by reference, etc.
+ /// \brief The different capture forms: by 'this', by reference, capture for
+ /// variable-length array type etc.
enum VariableCaptureKind {
VCK_This,
- VCK_ByRef
+ VCK_ByRef,
+ VCK_VLAType,
};
- /// \brief Describes the capture of either a variable or 'this'.
+ /// \brief Describes the capture of either a variable, or 'this', or
+ /// variable-length array type.
class Capture {
- llvm::PointerIntPair<VarDecl *, 1, VariableCaptureKind> VarAndKind;
+ llvm::PointerIntPair<VarDecl *, 2, VariableCaptureKind> VarAndKind;
SourceLocation Loc;
public:
@@ -2007,6 +2015,10 @@ public:
case VCK_ByRef:
assert(Var && "capturing by reference must have a variable!");
break;
+ case VCK_VLAType:
+ assert(!Var &&
+ "Variable-length array type capture cannot have a variable!");
+ break;
}
}
@@ -2021,13 +2033,20 @@ public:
bool capturesThis() const { return getCaptureKind() == VCK_This; }
/// \brief Determine whether this capture handles a variable.
- bool capturesVariable() const { return getCaptureKind() != VCK_This; }
+ bool capturesVariable() const { return getCaptureKind() == VCK_ByRef; }
+
+ /// \brief Determine whether this capture handles a variable-length array
+ /// type.
+ bool capturesVariableArrayType() const {
+ return getCaptureKind() == VCK_VLAType;
+ }
/// \brief Retrieve the declaration of the variable being captured.
///
- /// This operation is only valid if this capture does not capture 'this'.
+ /// This operation is only valid if this capture captures a variable.
VarDecl *getCapturedVar() const {
- assert(!capturesThis() && "No variable available for 'this' capture");
+ assert(capturesVariable() &&
+ "No variable available for 'this' or VAT capture");
return VarAndKind.getPointer();
}
friend class ASTStmtReader;
diff --git a/include/clang/AST/StmtGraphTraits.h b/include/clang/AST/StmtGraphTraits.h
index a3e9e1e093f6..ab636a5ddc48 100644
--- a/include/clang/AST/StmtGraphTraits.h
+++ b/include/clang/AST/StmtGraphTraits.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_STMT_GRAPHTRAITS_H
-#define LLVM_CLANG_AST_STMT_GRAPHTRAITS_H
+#ifndef LLVM_CLANG_AST_STMTGRAPHTRAITS_H
+#define LLVM_CLANG_AST_STMTGRAPHTRAITS_H
#include "clang/AST/Stmt.h"
#include "llvm/ADT/DepthFirstIterator.h"
diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h
index 18c55166beba..6ffe74f2d7fb 100644
--- a/include/clang/AST/StmtIterator.h
+++ b/include/clang/AST/StmtIterator.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_STMT_ITR_H
-#define LLVM_CLANG_AST_STMT_ITR_H
+#ifndef LLVM_CLANG_AST_STMTITERATOR_H
+#define LLVM_CLANG_AST_STMTITERATOR_H
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataTypes.h"
diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h
index db02afe0568b..aed7691cf73a 100644
--- a/include/clang/AST/StmtOpenMP.h
+++ b/include/clang/AST/StmtOpenMP.h
@@ -128,6 +128,13 @@ public:
operator bool() { return Current != End; }
};
+ /// \brief Gets a single clause of the specified kind \a K associated with the
+ /// current directive iff there is only one clause of this kind (and assertion
+ /// is fired if there is more than one clause is associated with the
+ /// directive). Returns nullptr if no clause of kind \a K is associated with
+ /// the directive.
+ const OMPClause *getSingleClause(OpenMPClauseKind K) const;
+
/// \brief Returns starting location of directive kind.
SourceLocation getLocStart() const { return StartLoc; }
/// \brief Returns ending location of directive.
@@ -238,6 +245,353 @@ public:
}
};
+/// \brief This is a common base class for loop directives ('omp simd', 'omp
+/// for', 'omp for simd' etc.). It is responsible for the loop code generation.
+///
+class OMPLoopDirective : public OMPExecutableDirective {
+ friend class ASTStmtReader;
+ /// \brief Number of collapsed loops as specified by 'collapse' clause.
+ unsigned CollapsedNum;
+
+ /// \brief Offsets to the stored exprs.
+ /// This enumeration contains offsets to all the pointers to children
+ /// expressions stored in OMPLoopDirective.
+ /// The first 9 children are nesessary for all the loop directives, and
+ /// the next 7 are specific to the worksharing ones.
+ /// After the fixed children, three arrays of length CollapsedNum are
+ /// allocated: loop counters, their updates and final values.
+ ///
+ enum {
+ AssociatedStmtOffset = 0,
+ IterationVariableOffset = 1,
+ LastIterationOffset = 2,
+ CalcLastIterationOffset = 3,
+ PreConditionOffset = 4,
+ CondOffset = 5,
+ SeparatedCondOffset = 6,
+ InitOffset = 7,
+ IncOffset = 8,
+ // The '...End' enumerators do not correspond to child expressions - they
+ // specify the offset to the end (and start of the following counters/
+ // updates/finals arrays).
+ DefaultEnd = 9,
+ // The following 7 exprs are used by worksharing loops only.
+ IsLastIterVariableOffset = 9,
+ LowerBoundVariableOffset = 10,
+ UpperBoundVariableOffset = 11,
+ StrideVariableOffset = 12,
+ EnsureUpperBoundOffset = 13,
+ NextLowerBoundOffset = 14,
+ NextUpperBoundOffset = 15,
+ // Offset to the end (and start of the following counters/updates/finals
+ // arrays) for worksharing loop directives.
+ WorksharingEnd = 16,
+ };
+
+ /// \brief Get the counters storage.
+ MutableArrayRef<Expr *> getCounters() {
+ Expr **Storage = reinterpret_cast<Expr **>(
+ &(*(std::next(child_begin(), getArraysOffset(getDirectiveKind())))));
+ return MutableArrayRef<Expr *>(Storage, CollapsedNum);
+ }
+
+ /// \brief Get the updates storage.
+ MutableArrayRef<Expr *> getUpdates() {
+ Expr **Storage = reinterpret_cast<Expr **>(
+ &*std::next(child_begin(),
+ getArraysOffset(getDirectiveKind()) + CollapsedNum));
+ return MutableArrayRef<Expr *>(Storage, CollapsedNum);
+ }
+
+ /// \brief Get the final counter updates storage.
+ MutableArrayRef<Expr *> getFinals() {
+ Expr **Storage = reinterpret_cast<Expr **>(
+ &*std::next(child_begin(),
+ getArraysOffset(getDirectiveKind()) + 2 * CollapsedNum));
+ return MutableArrayRef<Expr *>(Storage, CollapsedNum);
+ }
+
+protected:
+ /// \brief Build instance of loop directive of class \a Kind.
+ ///
+ /// \param SC Statement class.
+ /// \param Kind Kind of OpenMP directive.
+ /// \param StartLoc Starting location of the directive (directive keyword).
+ /// \param EndLoc Ending location of the directive.
+ /// \param CollapsedNum Number of collapsed loops from 'collapse' clause.
+ /// \param NumClauses Number of clauses.
+ /// \param NumSpecialChildren Number of additional directive-specific stmts.
+ ///
+ template <typename T>
+ OMPLoopDirective(const T *That, StmtClass SC, OpenMPDirectiveKind Kind,
+ SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, unsigned NumClauses,
+ unsigned NumSpecialChildren = 0)
+ : OMPExecutableDirective(That, SC, Kind, StartLoc, EndLoc, NumClauses,
+ numLoopChildren(CollapsedNum, Kind) +
+ NumSpecialChildren),
+ CollapsedNum(CollapsedNum) {}
+
+ /// \brief Offset to the start of children expression arrays.
+ static unsigned getArraysOffset(OpenMPDirectiveKind Kind) {
+ return isOpenMPWorksharingDirective(Kind) ? WorksharingEnd
+ : DefaultEnd;
+ }
+
+ /// \brief Children number.
+ static unsigned numLoopChildren(unsigned CollapsedNum,
+ OpenMPDirectiveKind Kind) {
+ return getArraysOffset(Kind) +
+ 3 * CollapsedNum; // Counters, Updates and Finals
+ }
+
+ void setIterationVariable(Expr *IV) {
+ *std::next(child_begin(), IterationVariableOffset) = IV;
+ }
+ void setLastIteration(Expr *LI) {
+ *std::next(child_begin(), LastIterationOffset) = LI;
+ }
+ void setCalcLastIteration(Expr *CLI) {
+ *std::next(child_begin(), CalcLastIterationOffset) = CLI;
+ }
+ void setPreCond(Expr *PC) {
+ *std::next(child_begin(), PreConditionOffset) = PC;
+ }
+ void setCond(Expr *Cond, Expr *SeparatedCond) {
+ *std::next(child_begin(), CondOffset) = Cond;
+ *std::next(child_begin(), SeparatedCondOffset) = SeparatedCond;
+ }
+ void setInit(Expr *Init) { *std::next(child_begin(), InitOffset) = Init; }
+ void setInc(Expr *Inc) { *std::next(child_begin(), IncOffset) = Inc; }
+ void setIsLastIterVariable(Expr *IL) {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ *std::next(child_begin(), IsLastIterVariableOffset) = IL;
+ }
+ void setLowerBoundVariable(Expr *LB) {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ *std::next(child_begin(), LowerBoundVariableOffset) = LB;
+ }
+ void setUpperBoundVariable(Expr *UB) {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ *std::next(child_begin(), UpperBoundVariableOffset) = UB;
+ }
+ void setStrideVariable(Expr *ST) {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ *std::next(child_begin(), StrideVariableOffset) = ST;
+ }
+ void setEnsureUpperBound(Expr *EUB) {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ *std::next(child_begin(), EnsureUpperBoundOffset) = EUB;
+ }
+ void setNextLowerBound(Expr *NLB) {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ *std::next(child_begin(), NextLowerBoundOffset) = NLB;
+ }
+ void setNextUpperBound(Expr *NUB) {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ *std::next(child_begin(), NextUpperBoundOffset) = NUB;
+ }
+ void setCounters(ArrayRef<Expr *> A);
+ void setUpdates(ArrayRef<Expr *> A);
+ void setFinals(ArrayRef<Expr *> A);
+
+public:
+ /// \brief The expressions built for the OpenMP loop CodeGen for the
+ /// whole collapsed loop nest.
+ struct HelperExprs {
+ /// \brief Loop iteration variable.
+ Expr *IterationVarRef;
+ /// \brief Loop last iteration number.
+ Expr *LastIteration;
+ /// \brief Calculation of last iteration.
+ Expr *CalcLastIteration;
+ /// \brief Loop pre-condition.
+ Expr *PreCond;
+ /// \brief Loop condition.
+ Expr *Cond;
+ /// \brief A condition with 1 iteration separated.
+ Expr *SeparatedCond;
+ /// \brief Loop iteration variable init.
+ Expr *Init;
+ /// \brief Loop increment.
+ Expr *Inc;
+ /// \brief IsLastIteration - local flag variable passed to runtime.
+ Expr *IL;
+ /// \brief LowerBound - local variable passed to runtime.
+ Expr *LB;
+ /// \brief UpperBound - local variable passed to runtime.
+ Expr *UB;
+ /// \brief Stride - local variable passed to runtime.
+ Expr *ST;
+ /// \brief EnsureUpperBound -- expression LB = min(LB, NumIterations).
+ Expr *EUB;
+ /// \brief Update of LowerBound for statically sheduled 'omp for' loops.
+ Expr *NLB;
+ /// \brief Update of UpperBound for statically sheduled 'omp for' loops.
+ Expr *NUB;
+ /// \brief Counters Loop counters.
+ SmallVector<Expr *, 4> Counters;
+ /// \brief Expressions for loop counters update for CodeGen.
+ SmallVector<Expr *, 4> Updates;
+ /// \brief Final loop counter values for GodeGen.
+ SmallVector<Expr *, 4> Finals;
+
+ /// \brief Check if all the expressions are built (does not check the
+ /// worksharing ones).
+ bool builtAll() {
+ return IterationVarRef != nullptr && LastIteration != nullptr &&
+ PreCond != nullptr && Cond != nullptr &&
+ SeparatedCond != nullptr && Init != nullptr && Inc != nullptr;
+ }
+
+ /// \brief Initialize all the fields to null.
+ /// \param Size Number of elements in the counters/finals/updates arrays.
+ void clear(unsigned Size) {
+ IterationVarRef = nullptr;
+ LastIteration = nullptr;
+ CalcLastIteration = nullptr;
+ PreCond = nullptr;
+ Cond = nullptr;
+ SeparatedCond = nullptr;
+ Init = nullptr;
+ Inc = nullptr;
+ IL = nullptr;
+ LB = nullptr;
+ UB = nullptr;
+ ST = nullptr;
+ EUB = nullptr;
+ NLB = nullptr;
+ NUB = nullptr;
+ Counters.resize(Size);
+ Updates.resize(Size);
+ Finals.resize(Size);
+ for (unsigned i = 0; i < Size; ++i) {
+ Counters[i] = nullptr;
+ Updates[i] = nullptr;
+ Finals[i] = nullptr;
+ }
+ }
+ };
+
+ /// \brief Get number of collapsed loops.
+ unsigned getCollapsedNumber() const { return CollapsedNum; }
+
+ Expr *getIterationVariable() const {
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), IterationVariableOffset)));
+ }
+ Expr *getLastIteration() const {
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), LastIterationOffset)));
+ }
+ Expr *getCalcLastIteration() const {
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CalcLastIterationOffset)));
+ }
+ Expr *getPreCond() const {
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), PreConditionOffset)));
+ }
+ Expr *getCond(bool SeparateIter) const {
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(),
+ (SeparateIter ? SeparatedCondOffset : CondOffset))));
+ }
+ Expr *getInit() const {
+ return const_cast<Expr *>(
+ reinterpret_cast<const Expr *>(*std::next(child_begin(), InitOffset)));
+ }
+ Expr *getInc() const {
+ return const_cast<Expr *>(
+ reinterpret_cast<const Expr *>(*std::next(child_begin(), IncOffset)));
+ }
+ Expr *getIsLastIterVariable() const {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), IsLastIterVariableOffset)));
+ }
+ Expr *getLowerBoundVariable() const {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), LowerBoundVariableOffset)));
+ }
+ Expr *getUpperBoundVariable() const {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), UpperBoundVariableOffset)));
+ }
+ Expr *getStrideVariable() const {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), StrideVariableOffset)));
+ }
+ Expr *getEnsureUpperBound() const {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), EnsureUpperBoundOffset)));
+ }
+ Expr *getNextLowerBound() const {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), NextLowerBoundOffset)));
+ }
+ Expr *getNextUpperBound() const {
+ assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ "expected worksharing loop directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), NextUpperBoundOffset)));
+ }
+ const Stmt *getBody() const {
+ // This relies on the loop form is already checked by Sema.
+ Stmt *Body = getAssociatedStmt()->IgnoreContainers(true);
+ Body = cast<ForStmt>(Body)->getBody();
+ for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) {
+ Body = Body->IgnoreContainers();
+ Body = cast<ForStmt>(Body)->getBody();
+ }
+ return Body;
+ }
+
+ ArrayRef<Expr *> counters() { return getCounters(); }
+
+ ArrayRef<Expr *> counters() const {
+ return const_cast<OMPLoopDirective *>(this)->getCounters();
+ }
+
+ ArrayRef<Expr *> updates() { return getUpdates(); }
+
+ ArrayRef<Expr *> updates() const {
+ return const_cast<OMPLoopDirective *>(this)->getUpdates();
+ }
+
+ ArrayRef<Expr *> finals() { return getFinals(); }
+
+ ArrayRef<Expr *> finals() const {
+ return const_cast<OMPLoopDirective *>(this)->getFinals();
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPSimdDirectiveClass ||
+ T->getStmtClass() == OMPForDirectiveClass ||
+ T->getStmtClass() == OMPForSimdDirectiveClass ||
+ T->getStmtClass() == OMPParallelForDirectiveClass ||
+ T->getStmtClass() == OMPParallelForSimdDirectiveClass;
+ }
+};
+
/// \brief This represents '#pragma omp simd' directive.
///
/// \code
@@ -247,10 +601,8 @@ public:
/// with the variables 'a' and 'b', 'linear' with variables 'i', 'j' and
/// linear step 's', 'reduction' with operator '+' and variables 'c' and 'd'.
///
-class OMPSimdDirective : public OMPExecutableDirective {
+class OMPSimdDirective : public OMPLoopDirective {
friend class ASTStmtReader;
- /// \brief Number of collapsed loops as specified by 'collapse' clause.
- unsigned CollapsedNum;
/// \brief Build directive with the given start and end location.
///
/// \param StartLoc Starting location of the directive kind.
@@ -260,9 +612,8 @@ class OMPSimdDirective : public OMPExecutableDirective {
///
OMPSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, unsigned NumClauses)
- : OMPExecutableDirective(this, OMPSimdDirectiveClass, OMPD_simd, StartLoc,
- EndLoc, NumClauses, 1),
- CollapsedNum(CollapsedNum) {}
+ : OMPLoopDirective(this, OMPSimdDirectiveClass, OMPD_simd, StartLoc,
+ EndLoc, CollapsedNum, NumClauses) {}
/// \brief Build an empty directive.
///
@@ -270,10 +621,9 @@ class OMPSimdDirective : public OMPExecutableDirective {
/// \param NumClauses Number of clauses.
///
explicit OMPSimdDirective(unsigned CollapsedNum, unsigned NumClauses)
- : OMPExecutableDirective(this, OMPSimdDirectiveClass, OMPD_simd,
- SourceLocation(), SourceLocation(), NumClauses,
- 1),
- CollapsedNum(CollapsedNum) {}
+ : OMPLoopDirective(this, OMPSimdDirectiveClass, OMPD_simd,
+ SourceLocation(), SourceLocation(), CollapsedNum,
+ NumClauses) {}
public:
/// \brief Creates directive with a list of \a Clauses.
@@ -284,11 +634,13 @@ public:
/// \param CollapsedNum Number of collapsed loops.
/// \param Clauses List of clauses.
/// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
///
static OMPSimdDirective *Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses,
- Stmt *AssociatedStmt);
+ Stmt *AssociatedStmt,
+ const HelperExprs &Exprs);
/// \brief Creates an empty directive with the place
/// for \a NumClauses clauses.
@@ -300,8 +652,6 @@ public:
static OMPSimdDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses,
unsigned CollapsedNum, EmptyShell);
- unsigned getCollapsedNumber() const { return CollapsedNum; }
-
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPSimdDirectiveClass;
}
@@ -316,10 +666,8 @@ public:
/// variables 'a' and 'b' and 'reduction' with operator '+' and variables 'c'
/// and 'd'.
///
-class OMPForDirective : public OMPExecutableDirective {
+class OMPForDirective : public OMPLoopDirective {
friend class ASTStmtReader;
- /// \brief Number of collapsed loops as specified by 'collapse' clause.
- unsigned CollapsedNum;
/// \brief Build directive with the given start and end location.
///
/// \param StartLoc Starting location of the directive kind.
@@ -329,9 +677,8 @@ class OMPForDirective : public OMPExecutableDirective {
///
OMPForDirective(SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, unsigned NumClauses)
- : OMPExecutableDirective(this, OMPForDirectiveClass, OMPD_for, StartLoc,
- EndLoc, NumClauses, 1),
- CollapsedNum(CollapsedNum) {}
+ : OMPLoopDirective(this, OMPForDirectiveClass, OMPD_for, StartLoc, EndLoc,
+ CollapsedNum, NumClauses) {}
/// \brief Build an empty directive.
///
@@ -339,10 +686,8 @@ class OMPForDirective : public OMPExecutableDirective {
/// \param NumClauses Number of clauses.
///
explicit OMPForDirective(unsigned CollapsedNum, unsigned NumClauses)
- : OMPExecutableDirective(this, OMPForDirectiveClass, OMPD_for,
- SourceLocation(), SourceLocation(), NumClauses,
- 1),
- CollapsedNum(CollapsedNum) {}
+ : OMPLoopDirective(this, OMPForDirectiveClass, OMPD_for, SourceLocation(),
+ SourceLocation(), CollapsedNum, NumClauses) {}
public:
/// \brief Creates directive with a list of \a Clauses.
@@ -353,11 +698,13 @@ public:
/// \param CollapsedNum Number of collapsed loops.
/// \param Clauses List of clauses.
/// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
///
static OMPForDirective *Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses,
- Stmt *AssociatedStmt);
+ Stmt *AssociatedStmt,
+ const HelperExprs &Exprs);
/// \brief Creates an empty directive with the place
/// for \a NumClauses clauses.
@@ -369,13 +716,76 @@ public:
static OMPForDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses,
unsigned CollapsedNum, EmptyShell);
- unsigned getCollapsedNumber() const { return CollapsedNum; }
-
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPForDirectiveClass;
}
};
+/// \brief This represents '#pragma omp for simd' directive.
+///
+/// \code
+/// #pragma omp for simd private(a,b) linear(i,j:s) reduction(+:c,d)
+/// \endcode
+/// In this example directive '#pragma omp for simd' has clauses 'private'
+/// with the variables 'a' and 'b', 'linear' with variables 'i', 'j' and
+/// linear step 's', 'reduction' with operator '+' and variables 'c' and 'd'.
+///
+class OMPForSimdDirective : public OMPLoopDirective {
+ friend class ASTStmtReader;
+ /// \brief Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPForSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPForSimdDirectiveClass, OMPD_for_simd,
+ StartLoc, EndLoc, CollapsedNum, NumClauses) {}
+
+ /// \brief Build an empty directive.
+ ///
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPForSimdDirective(unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPForSimdDirectiveClass, OMPD_for_simd,
+ SourceLocation(), SourceLocation(), CollapsedNum,
+ NumClauses) {}
+
+public:
+ /// \brief Creates directive with a list of \a Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param CollapsedNum Number of collapsed loops.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
+ ///
+ static OMPForSimdDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt, const HelperExprs &Exprs);
+
+ /// \brief Creates an empty directive with the place
+ /// for \a NumClauses clauses.
+ ///
+ /// \param C AST context.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPForSimdDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPForSimdDirectiveClass;
+ }
+};
+
/// \brief This represents '#pragma omp sections' directive.
///
/// \code
@@ -657,10 +1067,8 @@ public:
/// with the variables 'a' and 'b' and 'reduction' with operator '+' and
/// variables 'c' and 'd'.
///
-class OMPParallelForDirective : public OMPExecutableDirective {
+class OMPParallelForDirective : public OMPLoopDirective {
friend class ASTStmtReader;
- /// \brief Number of collapsed loops as specified by 'collapse' clause.
- unsigned CollapsedNum;
/// \brief Build directive with the given start and end location.
///
/// \param StartLoc Starting location of the directive kind.
@@ -670,10 +1078,8 @@ class OMPParallelForDirective : public OMPExecutableDirective {
///
OMPParallelForDirective(SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, unsigned NumClauses)
- : OMPExecutableDirective(this, OMPParallelForDirectiveClass,
- OMPD_parallel_for, StartLoc, EndLoc, NumClauses,
- 1),
- CollapsedNum(CollapsedNum) {}
+ : OMPLoopDirective(this, OMPParallelForDirectiveClass, OMPD_parallel_for,
+ StartLoc, EndLoc, CollapsedNum, NumClauses) {}
/// \brief Build an empty directive.
///
@@ -681,10 +1087,9 @@ class OMPParallelForDirective : public OMPExecutableDirective {
/// \param NumClauses Number of clauses.
///
explicit OMPParallelForDirective(unsigned CollapsedNum, unsigned NumClauses)
- : OMPExecutableDirective(this, OMPParallelForDirectiveClass,
- OMPD_parallel_for, SourceLocation(),
- SourceLocation(), NumClauses, 1),
- CollapsedNum(CollapsedNum) {}
+ : OMPLoopDirective(this, OMPParallelForDirectiveClass, OMPD_parallel_for,
+ SourceLocation(), SourceLocation(), CollapsedNum,
+ NumClauses) {}
public:
/// \brief Creates directive with a list of \a Clauses.
@@ -695,11 +1100,12 @@ public:
/// \param CollapsedNum Number of collapsed loops.
/// \param Clauses List of clauses.
/// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
///
static OMPParallelForDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
- Stmt *AssociatedStmt);
+ Stmt *AssociatedStmt, const HelperExprs &Exprs);
/// \brief Creates an empty directive with the place
/// for \a NumClauses clauses.
@@ -713,13 +1119,80 @@ public:
unsigned CollapsedNum,
EmptyShell);
- unsigned getCollapsedNumber() const { return CollapsedNum; }
-
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPParallelForDirectiveClass;
}
};
+/// \brief This represents '#pragma omp parallel for simd' directive.
+///
+/// \code
+/// #pragma omp parallel for simd private(a,b) linear(i,j:s) reduction(+:c,d)
+/// \endcode
+/// In this example directive '#pragma omp parallel for simd' has clauses
+/// 'private' with the variables 'a' and 'b', 'linear' with variables 'i', 'j'
+/// and linear step 's', 'reduction' with operator '+' and variables 'c' and
+/// 'd'.
+///
+class OMPParallelForSimdDirective : public OMPLoopDirective {
+ friend class ASTStmtReader;
+ /// \brief Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPParallelForSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPParallelForSimdDirectiveClass,
+ OMPD_parallel_for_simd, StartLoc, EndLoc, CollapsedNum,
+ NumClauses) {}
+
+ /// \brief Build an empty directive.
+ ///
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPParallelForSimdDirective(unsigned CollapsedNum,
+ unsigned NumClauses)
+ : OMPLoopDirective(this, OMPParallelForSimdDirectiveClass,
+ OMPD_parallel_for_simd, SourceLocation(),
+ SourceLocation(), CollapsedNum, NumClauses) {}
+
+public:
+ /// \brief Creates directive with a list of \a Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param CollapsedNum Number of collapsed loops.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
+ ///
+ static OMPParallelForSimdDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt, const HelperExprs &Exprs);
+
+ /// \brief Creates an empty directive with the place
+ /// for \a NumClauses clauses.
+ ///
+ /// \param C AST context.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPParallelForSimdDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPParallelForSimdDirectiveClass;
+ }
+};
+
/// \brief This represents '#pragma omp parallel sections' directive.
///
/// \code
@@ -1028,6 +1501,253 @@ public:
}
};
+/// \brief This represents '#pragma omp ordered' directive.
+///
+/// \code
+/// #pragma omp ordered
+/// \endcode
+///
+class OMPOrderedDirective : public OMPExecutableDirective {
+ friend class ASTStmtReader;
+ /// \brief Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ ///
+ OMPOrderedDirective(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPExecutableDirective(this, OMPOrderedDirectiveClass, OMPD_ordered,
+ StartLoc, EndLoc, 0, 1) {}
+
+ /// \brief Build an empty directive.
+ ///
+ explicit OMPOrderedDirective()
+ : OMPExecutableDirective(this, OMPOrderedDirectiveClass, OMPD_ordered,
+ SourceLocation(), SourceLocation(), 0, 1) {}
+
+public:
+ /// \brief Creates directive.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ ///
+ static OMPOrderedDirective *Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ Stmt *AssociatedStmt);
+
+ /// \brief Creates an empty directive.
+ ///
+ /// \param C AST context.
+ ///
+ static OMPOrderedDirective *CreateEmpty(const ASTContext &C, EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPOrderedDirectiveClass;
+ }
+};
+
+/// \brief This represents '#pragma omp atomic' directive.
+///
+/// \code
+/// #pragma omp atomic capture
+/// \endcode
+/// In this example directive '#pragma omp atomic' has clause 'capture'.
+///
+class OMPAtomicDirective : public OMPExecutableDirective {
+ friend class ASTStmtReader;
+ /// \brief Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPAtomicDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned NumClauses)
+ : OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic,
+ StartLoc, EndLoc, NumClauses, 4) {}
+
+ /// \brief Build an empty directive.
+ ///
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPAtomicDirective(unsigned NumClauses)
+ : OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic,
+ SourceLocation(), SourceLocation(), NumClauses,
+ 4) {}
+
+ /// \brief Set 'x' part of the associated expression/statement.
+ void setX(Expr *X) { *std::next(child_begin()) = X; }
+ /// \brief Set 'v' part of the associated expression/statement.
+ void setV(Expr *V) { *std::next(child_begin(), 2) = V; }
+ /// \brief Set 'expr' part of the associated expression/statement.
+ void setExpr(Expr *E) { *std::next(child_begin(), 3) = E; }
+
+public:
+ /// \brief Creates directive with a list of \a Clauses and 'x', 'v' and 'expr'
+ /// parts of the atomic construct (see Section 2.12.6, atomic Construct, for
+ /// detailed description of 'x', 'v' and 'expr').
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ /// \param X 'x' part of the associated expression/statement.
+ /// \param V 'v' part of the associated expression/statement.
+ /// \param E 'expr' part of the associated expression/statement.
+ ///
+ static OMPAtomicDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V,
+ Expr *E);
+
+ /// \brief Creates an empty directive with the place for \a NumClauses
+ /// clauses.
+ ///
+ /// \param C AST context.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPAtomicDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses, EmptyShell);
+
+ /// \brief Get 'x' part of the associated expression/statement.
+ Expr *getX() { return cast_or_null<Expr>(*std::next(child_begin())); }
+ const Expr *getX() const {
+ return cast_or_null<Expr>(*std::next(child_begin()));
+ }
+ /// \brief Get 'v' part of the associated expression/statement.
+ Expr *getV() { return cast_or_null<Expr>(*std::next(child_begin(), 2)); }
+ const Expr *getV() const {
+ return cast_or_null<Expr>(*std::next(child_begin(), 2));
+ }
+ /// \brief Get 'expr' part of the associated expression/statement.
+ Expr *getExpr() { return cast_or_null<Expr>(*std::next(child_begin(), 3)); }
+ const Expr *getExpr() const {
+ return cast_or_null<Expr>(*std::next(child_begin(), 3));
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPAtomicDirectiveClass;
+ }
+};
+
+/// \brief This represents '#pragma omp target' directive.
+///
+/// \code
+/// #pragma omp target if(a)
+/// \endcode
+/// In this example directive '#pragma omp target' has clause 'if' with
+/// condition 'a'.
+///
+class OMPTargetDirective : public OMPExecutableDirective {
+ friend class ASTStmtReader;
+ /// \brief Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPTargetDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned NumClauses)
+ : OMPExecutableDirective(this, OMPTargetDirectiveClass, OMPD_target,
+ StartLoc, EndLoc, NumClauses, 1) {}
+
+ /// \brief Build an empty directive.
+ ///
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPTargetDirective(unsigned NumClauses)
+ : OMPExecutableDirective(this, OMPTargetDirectiveClass, OMPD_target,
+ SourceLocation(), SourceLocation(), NumClauses,
+ 1) {}
+
+public:
+ /// \brief Creates directive with a list of \a Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ ///
+ static OMPTargetDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt);
+
+ /// \brief Creates an empty directive with the place for \a NumClauses
+ /// clauses.
+ ///
+ /// \param C AST context.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPTargetDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses, EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPTargetDirectiveClass;
+ }
+};
+
+/// \brief This represents '#pragma omp teams' directive.
+///
+/// \code
+/// #pragma omp teams if(a)
+/// \endcode
+/// In this example directive '#pragma omp teams' has clause 'if' with
+/// condition 'a'.
+///
+class OMPTeamsDirective : public OMPExecutableDirective {
+ friend class ASTStmtReader;
+ /// \brief Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPTeamsDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned NumClauses)
+ : OMPExecutableDirective(this, OMPTeamsDirectiveClass, OMPD_teams,
+ StartLoc, EndLoc, NumClauses, 1) {}
+
+ /// \brief Build an empty directive.
+ ///
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPTeamsDirective(unsigned NumClauses)
+ : OMPExecutableDirective(this, OMPTeamsDirectiveClass, OMPD_teams,
+ SourceLocation(), SourceLocation(), NumClauses,
+ 1) {}
+
+public:
+ /// \brief Creates directive with a list of \a Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ ///
+ static OMPTeamsDirective *Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt);
+
+ /// \brief Creates an empty directive with the place for \a NumClauses
+ /// clauses.
+ ///
+ /// \param C AST context.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPTeamsDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses, EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPTeamsDirectiveClass;
+ }
+};
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 1026a7807a60..80b68bc0569b 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -18,8 +18,8 @@
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
@@ -76,7 +76,7 @@ private:
struct DA {
unsigned Kind;
- bool ForRefParam;
+ void *QT;
ValueDecl *D;
};
struct I {
@@ -132,11 +132,11 @@ public:
/// \brief Construct a template argument that refers to a
/// declaration, which is either an external declaration or a
/// template declaration.
- TemplateArgument(ValueDecl *D, bool ForRefParam) {
+ TemplateArgument(ValueDecl *D, QualType QT) {
assert(D && "Expected decl");
DeclArg.Kind = Declaration;
+ DeclArg.QT = QT.getAsOpaquePtr();
DeclArg.D = D;
- DeclArg.ForRefParam = ForRefParam;
}
/// \brief Construct an integral constant template argument. The memory to
@@ -249,11 +249,9 @@ public:
return DeclArg.D;
}
- /// \brief Retrieve whether a declaration is binding to a
- /// reference parameter in a declaration non-type template argument.
- bool isDeclForReferenceParam() const {
+ QualType getParamTypeForDecl() const {
assert(getKind() == Declaration && "Unexpected kind");
- return DeclArg.ForRefParam;
+ return QualType::getFromOpaquePtr(DeclArg.QT);
}
/// \brief Retrieve the type for null non-type template argument.
@@ -344,7 +342,7 @@ public:
/// \brief Return the array of arguments in this template argument pack.
ArrayRef<TemplateArgument> getPackAsArray() const {
assert(getKind() == Pack);
- return ArrayRef<TemplateArgument>(Args.Args, Args.NumArgs);
+ return llvm::makeArrayRef(Args.Args, Args.NumArgs);
}
/// \brief Determines whether two template arguments are superficially the
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 09862e4fb7f7..1bda01fee8ad 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -16,6 +16,7 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
+#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/LLVM.h"
@@ -25,11 +26,11 @@
#include "clang/Basic/Visibility.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
@@ -400,21 +401,36 @@ public:
Mask |= qs.Mask;
}
+ /// \brief Returns true if this address space is a superset of the other one.
+ /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of
+ /// overlapping address spaces.
+ /// CL1.1 or CL1.2:
+ /// every address space is a superset of itself.
+ /// CL2.0 adds:
+ /// __generic is a superset of any address space except for __constant.
+ bool isAddressSpaceSupersetOf(Qualifiers other) const {
+ return
+ // Address spaces must match exactly.
+ getAddressSpace() == other.getAddressSpace() ||
+ // Otherwise in OpenCLC v2.0 s6.5.5: every address space except
+ // for __constant can be used as __generic.
+ (getAddressSpace() == LangAS::opencl_generic &&
+ other.getAddressSpace() != LangAS::opencl_constant);
+ }
+
/// \brief Determines if these qualifiers compatibly include another set.
/// 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 {
- 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()) &&
- // ObjC lifetime qualifiers must match exactly.
- getObjCLifetime() == other.getObjCLifetime() &&
- // CVR qualifiers may subset.
- (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask));
+ return isAddressSpaceSupersetOf(other) &&
+ // ObjC GC qualifiers can match, be added, or be removed, but can't
+ // be changed.
+ (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() ||
+ !other.hasObjCGCAttr()) &&
+ // ObjC lifetime qualifiers must match exactly.
+ getObjCLifetime() == other.getObjCLifetime() &&
+ // CVR qualifiers may subset.
+ (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask));
}
/// \brief Determines if these qualifiers compatibly include another set of
@@ -1245,6 +1261,7 @@ protected:
class FunctionTypeBitfields {
friend class FunctionType;
+ friend class FunctionProtoType;
unsigned : NumTypeBits;
@@ -1259,6 +1276,11 @@ protected:
/// C++ 8.3.5p4: The return type, the parameter type list and the
/// cv-qualifier-seq, [...], are part of the function type.
unsigned TypeQuals : 3;
+
+ /// \brief The ref-qualifier associated with a \c FunctionProtoType.
+ ///
+ /// This is a value of type \c RefQualifierKind.
+ unsigned RefQualifier : 2;
};
class ObjCObjectTypeBitfields {
@@ -1685,6 +1707,11 @@ public:
/// type of a class template or class template partial specialization.
CXXRecordDecl *getAsCXXRecordDecl() const;
+ /// \brief Retrieves the TagDecl that this type refers to, either
+ /// because the type is a TagType or because it is the injected-class-name
+ /// type of a class template or class template partial specialization.
+ TagDecl *getAsTagDecl() const;
+
/// If this is a pointer or reference to a RecordType, return the
/// CXXRecordDecl that that type refers to.
///
@@ -1982,6 +2009,22 @@ public:
QualType getPointeeType() const { return PointeeType; }
+ /// \brief Returns true if address spaces of pointers overlap.
+ /// OpenCL v2.0 defines conversion rules for pointers to different
+ /// address spaces (OpenCLC v2.0 s6.5.5) and notion of overlapping
+ /// address spaces.
+ /// CL1.1 or CL1.2:
+ /// address spaces overlap iff they are they same.
+ /// CL2.0 adds:
+ /// __generic overlaps with any address space except for __constant.
+ bool isAddressSpaceOverlapping(const PointerType &other) const {
+ Qualifiers thisQuals = PointeeType.getQualifiers();
+ Qualifiers otherQuals = other.getPointeeType().getQualifiers();
+ // Address spaces overlap if at least one of them is a superset of another
+ return thisQuals.isAddressSpaceSupersetOf(otherQuals) ||
+ otherQuals.isAddressSpaceSupersetOf(thisQuals);
+ }
+
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@@ -2765,7 +2808,7 @@ class FunctionType : public Type {
protected:
FunctionType(TypeClass tc, QualType res,
- unsigned typeQuals, QualType Canonical, bool Dependent,
+ QualType Canonical, bool Dependent,
bool InstantiationDependent,
bool VariablyModified, bool ContainsUnexpandedParameterPack,
ExtInfo Info)
@@ -2773,7 +2816,6 @@ protected:
ContainsUnexpandedParameterPack),
ResultType(res) {
FunctionTypeBits.ExtInfo = Info.Bits;
- FunctionTypeBits.TypeQuals = typeQuals;
}
unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; }
@@ -2810,7 +2852,7 @@ public:
/// no information available about its arguments.
class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info)
- : FunctionType(FunctionNoProto, Result, 0, Canonical,
+ : FunctionType(FunctionNoProto, Result, Canonical,
/*Dependent=*/false, /*InstantiationDependent=*/false,
Result->isVariablyModifiedType(),
/*ContainsUnexpandedParameterPack=*/false, Info) {}
@@ -2844,33 +2886,51 @@ public:
/// type.
class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
public:
+ struct ExceptionSpecInfo {
+ ExceptionSpecInfo()
+ : Type(EST_None), NoexceptExpr(nullptr),
+ SourceDecl(nullptr), SourceTemplate(nullptr) {}
+
+ ExceptionSpecInfo(ExceptionSpecificationType EST)
+ : Type(EST), NoexceptExpr(nullptr), SourceDecl(nullptr),
+ SourceTemplate(nullptr) {}
+
+ /// The kind of exception specification this is.
+ ExceptionSpecificationType Type;
+ /// Explicitly-specified list of exception types.
+ ArrayRef<QualType> Exceptions;
+ /// Noexcept expression, if this is EST_ComputedNoexcept.
+ Expr *NoexceptExpr;
+ /// The function whose exception specification this is, for
+ /// EST_Unevaluated and EST_Uninstantiated.
+ FunctionDecl *SourceDecl;
+ /// The function template whose exception specification this is instantiated
+ /// from, for EST_Uninstantiated.
+ FunctionDecl *SourceTemplate;
+ };
+
/// ExtProtoInfo - Extra information about a function prototype.
struct ExtProtoInfo {
ExtProtoInfo()
: Variadic(false), HasTrailingReturn(false), TypeQuals(0),
- ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0),
- Exceptions(nullptr), NoexceptExpr(nullptr),
- ExceptionSpecDecl(nullptr), ExceptionSpecTemplate(nullptr),
- ConsumedParameters(nullptr) {}
+ RefQualifier(RQ_None), ConsumedParameters(nullptr) {}
ExtProtoInfo(CallingConv CC)
: ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0),
- ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0),
- Exceptions(nullptr), NoexceptExpr(nullptr),
- ExceptionSpecDecl(nullptr), ExceptionSpecTemplate(nullptr),
- ConsumedParameters(nullptr) {}
+ RefQualifier(RQ_None), ConsumedParameters(nullptr) {}
+
+ ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &O) {
+ ExtProtoInfo Result(*this);
+ Result.ExceptionSpec = O;
+ return Result;
+ }
FunctionType::ExtInfo ExtInfo;
bool Variadic : 1;
bool HasTrailingReturn : 1;
unsigned char TypeQuals;
- ExceptionSpecificationType ExceptionSpecType;
RefQualifierKind RefQualifier;
- unsigned NumExceptions;
- const QualType *Exceptions;
- Expr *NoexceptExpr;
- FunctionDecl *ExceptionSpecDecl;
- FunctionDecl *ExceptionSpecTemplate;
+ ExceptionSpecInfo ExceptionSpec;
const bool *ConsumedParameters;
};
@@ -2896,7 +2956,7 @@ private:
unsigned NumExceptions : 9;
/// ExceptionSpecType - The type of exception specification this function has.
- unsigned ExceptionSpecType : 3;
+ unsigned ExceptionSpecType : 4;
/// HasAnyConsumedParams - Whether this function has any consumed parameters.
unsigned HasAnyConsumedParams : 1;
@@ -2907,11 +2967,6 @@ private:
/// HasTrailingReturn - Whether this function has a trailing return type.
unsigned HasTrailingReturn : 1;
- /// \brief The ref-qualifier associated with a \c FunctionProtoType.
- ///
- /// This is a value of type \c RefQualifierKind.
- unsigned RefQualifier : 2;
-
// ParamInfo - There is an variable size array after the class in memory that
// holds the parameter types.
@@ -2952,7 +3007,7 @@ public:
return param_type_begin()[i];
}
ArrayRef<QualType> getParamTypes() const {
- return ArrayRef<QualType>(param_type_begin(), param_type_end());
+ return llvm::makeArrayRef(param_type_begin(), param_type_end());
}
ExtProtoInfo getExtProtoInfo() const {
@@ -2960,19 +3015,18 @@ public:
EPI.ExtInfo = getExtInfo();
EPI.Variadic = isVariadic();
EPI.HasTrailingReturn = hasTrailingReturn();
- EPI.ExceptionSpecType = getExceptionSpecType();
+ EPI.ExceptionSpec.Type = getExceptionSpecType();
EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals());
EPI.RefQualifier = getRefQualifier();
- if (EPI.ExceptionSpecType == EST_Dynamic) {
- EPI.NumExceptions = NumExceptions;
- EPI.Exceptions = exception_begin();
- } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
- EPI.NoexceptExpr = getNoexceptExpr();
- } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
- EPI.ExceptionSpecDecl = getExceptionSpecDecl();
- EPI.ExceptionSpecTemplate = getExceptionSpecTemplate();
- } else if (EPI.ExceptionSpecType == EST_Unevaluated) {
- EPI.ExceptionSpecDecl = getExceptionSpecDecl();
+ if (EPI.ExceptionSpec.Type == EST_Dynamic) {
+ EPI.ExceptionSpec.Exceptions = exceptions();
+ } else if (EPI.ExceptionSpec.Type == EST_ComputedNoexcept) {
+ EPI.ExceptionSpec.NoexceptExpr = getNoexceptExpr();
+ } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) {
+ EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl();
+ EPI.ExceptionSpec.SourceTemplate = getExceptionSpecTemplate();
+ } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) {
+ EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl();
}
if (hasAnyConsumedParams())
EPI.ConsumedParameters = getConsumedParamsBuffer();
@@ -2995,6 +3049,8 @@ public:
bool hasNoexceptExceptionSpec() const {
return isNoexceptExceptionSpec(getExceptionSpecType());
}
+ /// \brief Return whether this function has a dependent exception spec.
+ bool hasDependentExceptionSpec() const;
/// \brief Result type of getNoexceptSpec().
enum NoexceptResult {
NR_NoNoexcept, ///< There is no noexcept specifier.
@@ -3057,7 +3113,7 @@ public:
/// \brief Retrieve the ref-qualifier associated with this function type.
RefQualifierKind getRefQualifier() const {
- return static_cast<RefQualifierKind>(RefQualifier);
+ return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier);
}
typedef const QualType *param_type_iterator;
@@ -3074,10 +3130,9 @@ public:
}
typedef const QualType *exception_iterator;
- typedef llvm::iterator_range<exception_iterator> exception_range;
- exception_range exceptions() const {
- return exception_range(exception_begin(), exception_end());
+ ArrayRef<QualType> exceptions() const {
+ return llvm::makeArrayRef(exception_begin(), exception_end());
}
exception_iterator exception_begin() const {
// exceptions begin where arguments end
@@ -3416,6 +3471,7 @@ public:
attr_stdcall,
attr_thiscall,
attr_pascal,
+ attr_vectorcall,
attr_pnaclcall,
attr_inteloclbicc,
attr_ms_abi,
@@ -5231,8 +5287,8 @@ template <typename T> const T *Type::castAs() const {
ArrayType_cannot_be_used_with_getAs<T> at;
(void) at;
- assert(isa<T>(CanonicalType));
if (const T *ty = dyn_cast<T>(this)) return ty;
+ assert(isa<T>(CanonicalType));
return cast<T>(getUnqualifiedDesugaredType());
}
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 3648d2a5c259..4f3c811ce275 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -1208,7 +1208,7 @@ public:
}
ArrayRef<ParmVarDecl *> getParams() const {
- return ArrayRef<ParmVarDecl *>(getParmArray(), getNumParams());
+ return llvm::makeArrayRef(getParmArray(), getNumParams());
}
// ParmVarDecls* are stored after Info, one for each parameter.
@@ -1567,6 +1567,8 @@ public:
void setUnderlyingTInfo(TypeSourceInfo* TI) const {
this->getLocalData()->UnderlyingTInfo = TI;
}
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc);
};
// FIXME: location of the 'decltype' and parens.
diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h
index 9c9f15e95323..392e544d90c1 100644
--- a/include/clang/AST/TypeOrdering.h
+++ b/include/clang/AST/TypeOrdering.h
@@ -16,8 +16,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TYPE_ORDERING_H
-#define LLVM_CLANG_TYPE_ORDERING_H
+#ifndef LLVM_CLANG_AST_TYPEORDERING_H
+#define LLVM_CLANG_AST_TYPEORDERING_H
#include "clang/AST/CanonicalType.h"
#include "clang/AST/Type.h"
diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h
index 2ef5800c305f..a11f22d201b7 100644
--- a/include/clang/AST/UnresolvedSet.h
+++ b/include/clang/AST/UnresolvedSet.h
@@ -98,7 +98,7 @@ class UnresolvedSetImpl {
private:
template <unsigned N> friend class UnresolvedSet;
UnresolvedSetImpl() {}
- UnresolvedSetImpl(const UnresolvedSetImpl &) LLVM_DELETED_FUNCTION;
+ UnresolvedSetImpl(const UnresolvedSetImpl &) {}
public:
// We don't currently support assignment through this iterator, so we might
diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h
index 8af0546db57b..ce2674e442da 100644
--- a/include/clang/ASTMatchers/ASTMatchFinder.h
+++ b/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -38,10 +38,12 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
-#define LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
+#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
+#define LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
#include "clang/ASTMatchers/ASTMatchers.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Timer.h"
namespace clang {
@@ -102,6 +104,12 @@ public:
///
/// Optionally override to do per translation unit tasks.
virtual void onEndOfTranslationUnit() {}
+
+ /// \brief An id used to group the matchers.
+ ///
+ /// This id is used, for example, for the profiling output.
+ /// It defaults to "<unknown>".
+ virtual StringRef getID() const;
};
/// \brief Called when parsing is finished. Intended for testing only.
@@ -111,7 +119,22 @@ public:
virtual void run() = 0;
};
- MatchFinder();
+ struct MatchFinderOptions {
+ struct Profiling {
+ Profiling(llvm::StringMap<llvm::TimeRecord> &Records)
+ : Records(Records) {}
+
+ /// \brief Per bucket timing information.
+ llvm::StringMap<llvm::TimeRecord> &Records;
+ };
+
+ /// \brief Enables per-check timers.
+ ///
+ /// It prints a report after match.
+ llvm::Optional<Profiling> CheckProfiling;
+ };
+
+ MatchFinder(MatchFinderOptions Options = MatchFinderOptions());
~MatchFinder();
/// \brief Adds a matcher to execute when running over the AST.
@@ -148,7 +171,7 @@ public:
MatchCallback *Action);
/// \brief Creates a clang ASTConsumer that finds all matches.
- clang::ASTConsumer *newASTConsumer();
+ std::unique_ptr<clang::ASTConsumer> newASTConsumer();
/// \brief Calls the registered callbacks on all matches on the given \p Node.
///
@@ -173,11 +196,25 @@ public:
/// Each call to FindAll(...) will call the closure once.
void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
-private:
- /// \brief For each \c DynTypedMatcher a \c MatchCallback that will be called
+ /// \brief For each \c Matcher<> a \c MatchCallback that will be called
/// when it matches.
- std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> >
- MatcherCallbackPairs;
+ struct MatchersByType {
+ std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *>>
+ DeclOrStmt;
+ std::vector<std::pair<TypeMatcher, MatchCallback *>> Type;
+ std::vector<std::pair<NestedNameSpecifierMatcher, MatchCallback *>>
+ NestedNameSpecifier;
+ std::vector<std::pair<NestedNameSpecifierLocMatcher, MatchCallback *>>
+ NestedNameSpecifierLoc;
+ std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc;
+ /// \brief All the callbacks in one container to simplify iteration.
+ std::vector<MatchCallback *> AllCallbacks;
+ };
+
+private:
+ MatchersByType Matchers;
+
+ MatchFinderOptions Options;
/// \brief Called when parsing is done.
ParsingDoneTestCallback *ParsingDone;
@@ -210,16 +247,14 @@ match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
///
/// This is useful in combanation with \c match():
/// \code
-/// Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
-/// Node, Context));
+/// const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
+/// Node, Context));
/// \endcode
template <typename NodeT>
-NodeT *
+const NodeT *
selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
- for (SmallVectorImpl<BoundNodes>::const_iterator I = Results.begin(),
- E = Results.end();
- I != E; ++I) {
- if (NodeT *Node = I->getNodeAs<NodeT>(BoundTo))
+ for (const BoundNodes &N : Results) {
+ if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo))
return Node;
}
return nullptr;
@@ -243,7 +278,7 @@ match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
MatchFinder Finder;
Finder.addMatcher(Matcher, &Callback);
Finder.match(Node, Context);
- return Callback.Nodes;
+ return std::move(Callback.Nodes);
}
template <typename MatcherT, typename NodeT>
@@ -255,4 +290,4 @@ match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
} // end namespace ast_matchers
} // end namespace clang
-#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
+#endif
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 1ff4ab367fd5..f002cb9cbaba 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -42,9 +42,10 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H
-#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H
+#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H
+#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
@@ -140,9 +141,97 @@ typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher;
/// \endcode
///
/// Usable as: Any Matcher
-inline internal::PolymorphicMatcherWithParam0<internal::TrueMatcher>
-anything() {
- return internal::PolymorphicMatcherWithParam0<internal::TrueMatcher>();
+inline internal::TrueMatcher anything() { return internal::TrueMatcher(); }
+
+/// \brief Matches typedef declarations.
+///
+/// Given
+/// \code
+/// typedef int X;
+/// \endcode
+/// typedefDecl()
+/// matches "typedef int X"
+const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl;
+
+/// \brief Matches AST nodes that were expanded within the main-file.
+///
+/// Example matches X but not Y (matcher = recordDecl(isExpansionInMainFile())
+/// \code
+/// #include <Y.h>
+/// class X {};
+/// \endcode
+/// Y.h:
+/// \code
+/// class Y {};
+/// \endcode
+///
+/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
+AST_POLYMORPHIC_MATCHER(isExpansionInMainFile,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
+ TypeLoc)) {
+ auto &SourceManager = Finder->getASTContext().getSourceManager();
+ return SourceManager.isInMainFile(
+ SourceManager.getExpansionLoc(Node.getLocStart()));
+}
+
+/// \brief Matches AST nodes that were expanded within system-header-files.
+///
+/// Example matches Y but not X
+/// (matcher = recordDecl(isExpansionInSystemHeader())
+/// \code
+/// #include <SystemHeader.h>
+/// class X {};
+/// \endcode
+/// SystemHeader.h:
+/// \code
+/// class Y {};
+/// \endcode
+///
+/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
+AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
+ TypeLoc)) {
+ auto &SourceManager = Finder->getASTContext().getSourceManager();
+ auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
+ if (ExpansionLoc.isInvalid()) {
+ return false;
+ }
+ return SourceManager.isInSystemHeader(ExpansionLoc);
+}
+
+/// \brief Matches AST nodes that were expanded within files whose name is
+/// partially matching a given regex.
+///
+/// Example matches Y but not X
+/// (matcher = recordDecl(isExpansionInFileMatching("AST.*"))
+/// \code
+/// #include "ASTMatcher.h"
+/// class X {};
+/// \endcode
+/// ASTMatcher.h:
+/// \code
+/// class Y {};
+/// \endcode
+///
+/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
+AST_POLYMORPHIC_MATCHER_P(isExpansionInFileMatching,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
+ TypeLoc),
+ std::string, RegExp) {
+ auto &SourceManager = Finder->getASTContext().getSourceManager();
+ auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
+ if (ExpansionLoc.isInvalid()) {
+ return false;
+ }
+ auto FileEntry =
+ SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
+ if (!FileEntry) {
+ return false;
+ }
+
+ auto Filename = FileEntry->getName();
+ llvm::Regex RE(RegExp);
+ return RE.match(Filename);
}
/// \brief Matches declarations.
@@ -156,6 +245,17 @@ anything() {
/// \endcode
const internal::VariadicAllOfMatcher<Decl> decl;
+/// \brief Matches a declaration of a linkage specification.
+///
+/// Given
+/// \code
+/// extern "C" {}
+/// \endcode
+/// linkageSpecDecl()
+/// matches "extern "C" {}"
+const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl>
+ linkageSpecDecl;
+
/// \brief Matches a declaration of anything that could have a name.
///
/// Example matches \c X, \c S, the anonymous union type, \c i, and \c U;
@@ -263,6 +363,17 @@ const internal::VariadicDynCastAllOfMatcher<
/// \endcode
const internal::VariadicAllOfMatcher<CXXCtorInitializer> ctorInitializer;
+/// \brief Matches template arguments.
+///
+/// Given
+/// \code
+/// template <typename T> struct C {};
+/// C<int> c;
+/// \endcode
+/// templateArgument()
+/// matches 'int' in C<int>.
+const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument;
+
/// \brief Matches public C++ declarations.
///
/// Given
@@ -441,6 +552,23 @@ AST_POLYMORPHIC_MATCHER_P2(
return InnerMatcher.matches(List[N], Finder, Builder);
}
+/// \brief Matches if the number of template arguments equals \p N.
+///
+/// Given
+/// \code
+/// template<typename T> struct C {};
+/// C<int> c;
+/// \endcode
+/// classTemplateSpecializationDecl(templateArgumentCountIs(1))
+/// matches C<int>.
+AST_POLYMORPHIC_MATCHER_P(
+ templateArgumentCountIs,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
+ TemplateSpecializationType),
+ unsigned, N) {
+ return internal::getTemplateSpecializationArgs(Node).size() == N;
+}
+
/// \brief Matches a TemplateArgument that refers to a certain type.
///
/// Given
@@ -497,6 +625,68 @@ AST_MATCHER_P(TemplateArgument, isExpr, internal::Matcher<Expr>, InnerMatcher) {
return false;
}
+/// \brief Matches a TemplateArgument that is an integral value.
+///
+/// Given
+/// \code
+/// template<int T> struct A {};
+/// C<42> c;
+/// \endcode
+/// classTemplateSpecializationDecl(
+/// hasAnyTemplateArgument(isIntegral()))
+/// matches the implicit instantiation of C in C<42>
+/// with isIntegral() matching 42.
+AST_MATCHER(TemplateArgument, isIntegral) {
+ return Node.getKind() == TemplateArgument::Integral;
+}
+
+/// \brief Matches a TemplateArgument that referes to an integral type.
+///
+/// Given
+/// \code
+/// template<int T> struct A {};
+/// C<42> c;
+/// \endcode
+/// classTemplateSpecializationDecl(
+/// hasAnyTemplateArgument(refersToIntegralType(asString("int"))))
+/// matches the implicit instantiation of C in C<42>.
+AST_MATCHER_P(TemplateArgument, refersToIntegralType,
+ internal::Matcher<QualType>, InnerMatcher) {
+ if (Node.getKind() != TemplateArgument::Integral)
+ return false;
+ return InnerMatcher.matches(Node.getIntegralType(), Finder, Builder);
+}
+
+/// \brief Matches a TemplateArgument of integral type with a given value.
+///
+/// Note that 'Value' is a string as the template argument's value is
+/// an arbitrary precision integer. 'Value' must be euqal to the canonical
+/// representation of that integral value in base 10.
+///
+/// Given
+/// \code
+/// template<int T> struct A {};
+/// C<42> c;
+/// \endcode
+/// classTemplateSpecializationDecl(
+/// hasAnyTemplateArgument(equalsIntegralValue("42")))
+/// matches the implicit instantiation of C in C<42>.
+AST_MATCHER_P(TemplateArgument, equalsIntegralValue,
+ std::string, Value) {
+ if (Node.getKind() != TemplateArgument::Integral)
+ return false;
+ return Node.getAsIntegral().toString(10) == Value;
+}
+
+/// \brief Matches any value declaration.
+///
+/// Example matches A, B, C and F
+/// \code
+/// enum X { A, B, C };
+/// void F();
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl;
+
/// \brief Matches C++ constructor declarations.
///
/// Example matches Foo::Foo() and Foo::Foo(int)
@@ -1414,21 +1604,21 @@ const internal::VariadicAllOfMatcher<TypeLoc> typeLoc;
///
/// Usable as: Any Matcher
const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = {
- internal::EachOfVariadicOperator
+ internal::DynTypedMatcher::VO_EachOf
};
/// \brief Matches if any of the given matchers matches.
///
/// Usable as: Any Matcher
const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> anyOf = {
- internal::AnyOfVariadicOperator
+ internal::DynTypedMatcher::VO_AnyOf
};
/// \brief Matches if all given matchers match.
///
/// Usable as: Any Matcher
const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = {
- internal::AllOfVariadicOperator
+ internal::DynTypedMatcher::VO_AllOf
};
/// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
@@ -1502,16 +1692,8 @@ inline internal::Matcher<Stmt> sizeOfExpr(
/// \code
/// namespace a { namespace b { class X; } }
/// \endcode
-AST_MATCHER_P(NamedDecl, hasName, std::string, Name) {
- assert(!Name.empty());
- const std::string FullNameString = "::" + Node.getQualifiedNameAsString();
- const StringRef FullName = FullNameString;
- const StringRef Pattern = Name;
- if (Pattern.startswith("::")) {
- return FullName == Pattern;
- } else {
- return FullName.endswith(("::" + Pattern).str());
- }
+inline internal::Matcher<NamedDecl> hasName(const std::string &Name) {
+ return internal::Matcher<NamedDecl>(new internal::HasNameMatcher(Name));
}
/// \brief Matches NamedDecl nodes whose fully qualified names contain
@@ -1558,7 +1740,7 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) {
inline internal::PolymorphicMatcherWithParam1<
internal::HasOverloadedOperatorNameMatcher, StringRef,
AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, FunctionDecl)>
-hasOverloadedOperatorName(const StringRef Name) {
+hasOverloadedOperatorName(StringRef Name) {
return internal::PolymorphicMatcherWithParam1<
internal::HasOverloadedOperatorNameMatcher, StringRef,
AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, FunctionDecl)>(
@@ -1592,7 +1774,7 @@ AST_MATCHER_P(CXXRecordDecl, isDerivedFrom,
}
/// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
-AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, StringRef, BaseName, 1) {
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, std::string, BaseName, 1) {
assert(!BaseName.empty());
return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
}
@@ -1607,8 +1789,8 @@ AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom,
/// \brief Overloaded method as shortcut for
/// \c isSameOrDerivedFrom(hasName(...)).
-AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, StringRef, BaseName,
- 1) {
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, std::string,
+ BaseName, 1) {
assert(!BaseName.empty());
return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
}
@@ -1768,7 +1950,7 @@ const internal::ArgumentAdaptingMatcherFunc<
///
/// Usable as: Any Matcher
const internal::VariadicOperatorMatcherFunc<1, 1> unless = {
- internal::NotUnaryOperator
+ internal::DynTypedMatcher::VO_UnaryNot
};
/// \brief Matches a node if the declaration associated with that node
@@ -1844,7 +2026,7 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>,
/// Example matches y.x() (matcher = callExpr(callee(methodDecl(hasName("x")))))
/// \code
/// class Y { public: void x(); };
-/// void z() { Y y; y.x();
+/// void z() { Y y; y.x(); }
/// \endcode
AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher,
1) {
@@ -1952,6 +2134,7 @@ AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>,
/// void a(X b) {
/// X &x = b;
/// const X &y = b;
+/// }
/// };
/// \endcode
AST_MATCHER_P(QualType, references, internal::Matcher<QualType>,
@@ -2280,11 +2463,10 @@ AST_MATCHER(CXXCtorInitializer, isWritten) {
AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
CallExpr, CXXConstructExpr),
internal::Matcher<Expr>, InnerMatcher) {
- for (unsigned I = 0; I < Node.getNumArgs(); ++I) {
+ for (const Expr *Arg : Node.arguments()) {
BoundNodesTreeBuilder Result(*Builder);
- if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(), Finder,
- &Result)) {
- *Builder = Result;
+ if (InnerMatcher.matches(*Arg->IgnoreParenImpCasts(), Finder, &Result)) {
+ *Builder = std::move(Result);
return true;
}
}
@@ -2372,6 +2554,19 @@ AST_MATCHER(FunctionDecl, isExternC) {
return Node.isExternC();
}
+/// \brief Matches deleted function declarations.
+///
+/// Given:
+/// \code
+/// void Func();
+/// void DeletedFunc() = delete;
+/// \endcode
+/// functionDecl(isDeleted())
+/// matches the declaration of DeletedFunc, but not Func.
+AST_MATCHER(FunctionDecl, isDeleted) {
+ return Node.isDeleted();
+}
+
/// \brief Matches the condition expression of an if statement, for loop,
/// or conditional operator.
///
@@ -2953,6 +3148,43 @@ AST_POLYMORPHIC_MATCHER(
TSK_ExplicitInstantiationDefinition);
}
+/// \brief Matches declarations that are template instantiations or are inside
+/// template instantiations.
+///
+/// Given
+/// \code
+/// template<typename T> void A(T t) { T i; }
+/// A(0);
+/// A(0U);
+/// \endcode
+/// functionDecl(isInstantiated())
+/// matches 'A(int) {...};' and 'A(unsigned) {...}'.
+AST_MATCHER_FUNCTION(internal::Matcher<Decl>, isInstantiated) {
+ auto IsInstantiation = decl(anyOf(recordDecl(isTemplateInstantiation()),
+ functionDecl(isTemplateInstantiation())));
+ return decl(anyOf(IsInstantiation, hasAncestor(IsInstantiation)));
+}
+
+/// \brief Matches statements inside of a template instantiation.
+///
+/// Given
+/// \code
+/// int j;
+/// template<typename T> void A(T t) { T i; j += 42;}
+/// A(0);
+/// A(0U);
+/// \endcode
+/// declStmt(isInTemplateInstantiation())
+/// matches 'int i;' and 'unsigned i'.
+/// unless(stmt(isInTemplateInstantiation()))
+/// will NOT match j += 42; as it's shared between the template definition and
+/// instantiation.
+AST_MATCHER_FUNCTION(internal::Matcher<Stmt>, isInTemplateInstantiation) {
+ return stmt(
+ hasAncestor(decl(anyOf(recordDecl(isTemplateInstantiation()),
+ functionDecl(isTemplateInstantiation())))));
+}
+
/// \brief Matches explicit template specializations of function, class, or
/// static member variable template instantiations.
///
@@ -2979,6 +3211,18 @@ AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher<TypeLoc>, loc,
new internal::TypeLocTypeMatcher(InnerMatcher));
}
+/// \brief Matches type \c void.
+///
+/// Given
+/// \code
+/// struct S { void func(); };
+/// \endcode
+/// functionDecl(returns(voidType()))
+/// matches "void func();"
+AST_MATCHER(Type, voidType) {
+ return Node.isVoidType();
+}
+
/// \brief Matches builtin Types.
///
/// Given
@@ -3094,6 +3338,7 @@ AST_TYPE_MATCHER(IncompleteArrayType, incompleteArrayType);
/// int a[] = { 2, 3 }
/// int b[42];
/// int c[a[0]];
+/// }
/// \endcode
/// variableArrayType()
/// matches "int c[a[0]]"
@@ -3432,8 +3677,9 @@ AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>,
/// \c recordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
/// declaration of \c class \c D.
AST_MATCHER_P(Decl, hasDeclContext, internal::Matcher<Decl>, InnerMatcher) {
- return InnerMatcher.matches(*Decl::castFromDeclContext(Node.getDeclContext()),
- Finder, Builder);
+ const DeclContext *DC = Node.getDeclContext();
+ if (!DC) return false;
+ return InnerMatcher.matches(*Decl::castFromDeclContext(DC), Finder, Builder);
}
/// \brief Matches nested name specifiers.
@@ -3599,7 +3845,7 @@ AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>,
Result.addMatch(CaseBuilder);
}
}
- *Builder = Result;
+ *Builder = std::move(Result);
return Matched;
}
@@ -3622,7 +3868,7 @@ AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer,
Result.addMatch(InitBuilder);
}
}
- *Builder = Result;
+ *Builder = std::move(Result);
return Matched;
}
@@ -3643,7 +3889,32 @@ AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>,
return InnerMatcher.matches(*Node.getLHS(), Finder, Builder);
}
+/// \brief Matches declaration that has a given attribute.
+///
+/// Given
+/// \code
+/// __attribute__((device)) void f() { ... }
+/// \endcode
+/// decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
+/// f.
+AST_MATCHER_P(Decl, hasAttr, attr::Kind, AttrKind) {
+ for (const auto *Attr : Node.attrs()) {
+ if (Attr->getKind() == AttrKind)
+ return true;
+ }
+ return false;
+}
+
+/// \brief Matches CUDA kernel call expression.
+///
+/// Example matches,
+/// \code
+/// kernel<<<i,j>>>();
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr>
+ CUDAKernelCallExpr;
+
} // end namespace ast_matchers
} // end namespace clang
-#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H
+#endif
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 94435fd274eb..ebe5cddb622a 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -32,8 +32,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
-#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
+#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H
+#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Decl.h"
@@ -44,6 +44,7 @@
#include "clang/AST/Type.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/VariadicFunction.h"
+#include "llvm/Support/ManagedStatic.h"
#include <map>
#include <string>
#include <vector>
@@ -61,9 +62,8 @@ public:
/// \brief Adds \c Node to the map with key \c ID.
///
/// The node's base type should be in NodeBaseType or it will be unaccessible.
- template <typename T>
- void addNode(StringRef ID, const T* Node) {
- NodeMap[ID] = ast_type_traits::DynTypedNode::create(*Node);
+ void addNode(StringRef ID, const ast_type_traits::DynTypedNode& DynNode) {
+ NodeMap[ID] = DynNode;
}
/// \brief Returns the AST node bound to \c ID.
@@ -103,6 +103,16 @@ public:
return NodeMap;
}
+ /// \brief Returns \c true if this \c BoundNodesMap can be compared, i.e. all
+ /// stored nodes have memoization data.
+ bool isComparable() const {
+ for (const auto &IDAndNode : NodeMap) {
+ if (!IDAndNode.second.getMemoizationData())
+ return false;
+ }
+ return true;
+ }
+
private:
IDToNodeMap NodeMap;
};
@@ -126,11 +136,12 @@ public:
};
/// \brief Add a binding from an id to a node.
- template <typename T> void setBinding(const std::string &Id, const T *Node) {
+ void setBinding(const std::string &Id,
+ const ast_type_traits::DynTypedNode &DynNode) {
if (Bindings.empty())
Bindings.push_back(BoundNodesMap());
- for (unsigned i = 0, e = Bindings.size(); i != e; ++i)
- Bindings[i].addNode(Id, Node);
+ for (BoundNodesMap &Binding : Bindings)
+ Binding.addNode(Id, DynNode);
}
/// \brief Adds a branch in the tree.
@@ -153,12 +164,38 @@ public:
return Bindings < Other.Bindings;
}
+ /// \brief Returns \c true if this \c BoundNodesTreeBuilder can be compared,
+ /// i.e. all stored node maps have memoization data.
+ bool isComparable() const {
+ for (const BoundNodesMap &NodesMap : Bindings) {
+ if (!NodesMap.isComparable())
+ return false;
+ }
+ return true;
+ }
+
private:
SmallVector<BoundNodesMap, 16> Bindings;
};
class ASTMatchFinder;
+/// \brief Generic interface for all matchers.
+///
+/// Used by the implementation of Matcher<T> and DynTypedMatcher.
+/// In general, implement MatcherInterface<T> or SingleNodeMatcherInterface<T>
+/// instead.
+class DynMatcherInterface : public RefCountedBaseVPTR {
+public:
+ /// \brief Returns true if \p DynNode can be matched.
+ ///
+ /// May bind \p DynNode to an ID via \p Builder, or recurse into
+ /// the AST via \p Finder.
+ virtual bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const = 0;
+};
+
/// \brief Generic interface for matchers on an AST node of type T.
///
/// Implement this if your matcher may need to inspect the children or
@@ -167,7 +204,7 @@ class ASTMatchFinder;
/// current node and doesn't care about its children or descendants,
/// implement SingleNodeMatcherInterface instead.
template <typename T>
-class MatcherInterface : public RefCountedBaseVPTR {
+class MatcherInterface : public DynMatcherInterface {
public:
virtual ~MatcherInterface() {}
@@ -178,6 +215,12 @@ public:
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const = 0;
+
+ bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const override {
+ return matches(DynNode.getUnchecked<T>(), Finder, Builder);
+ }
};
/// \brief Interface for matchers that only evaluate properties on a single
@@ -199,6 +242,145 @@ private:
}
};
+template <typename> class Matcher;
+
+/// \brief Matcher that works on a \c DynTypedNode.
+///
+/// It is constructed from a \c Matcher<T> object and redirects most calls to
+/// underlying matcher.
+/// It checks whether the \c DynTypedNode is convertible into the type of the
+/// underlying matcher and then do the actual match on the actual node, or
+/// return false if it is not convertible.
+class DynTypedMatcher {
+public:
+ /// \brief Takes ownership of the provided implementation pointer.
+ template <typename T>
+ DynTypedMatcher(MatcherInterface<T> *Implementation)
+ : AllowBind(false),
+ SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()),
+ RestrictKind(SupportedKind), Implementation(Implementation) {}
+
+ /// \brief Construct from a variadic function.
+ enum VariadicOperator {
+ /// \brief Matches nodes for which all provided matchers match.
+ VO_AllOf,
+ /// \brief Matches nodes for which at least one of the provided matchers
+ /// matches.
+ VO_AnyOf,
+ /// \brief Matches nodes for which at least one of the provided matchers
+ /// matches, but doesn't stop at the first match.
+ VO_EachOf,
+ /// \brief Matches nodes that do not match the provided matcher.
+ ///
+ /// Uses the variadic matcher interface, but fails if
+ /// InnerMatchers.size() != 1.
+ VO_UnaryNot
+ };
+ static DynTypedMatcher
+ constructVariadic(VariadicOperator Op,
+ std::vector<DynTypedMatcher> InnerMatchers);
+
+ /// \brief Get a "true" matcher for \p NodeKind.
+ ///
+ /// It only checks that the node is of the right kind.
+ static DynTypedMatcher trueMatcher(ast_type_traits::ASTNodeKind NodeKind);
+
+ void setAllowBind(bool AB) { AllowBind = AB; }
+
+ /// \brief Check whether this matcher could ever match a node of kind \p Kind.
+ /// \return \c false if this matcher will never match such a node. Otherwise,
+ /// return \c true.
+ bool canMatchNodesOfKind(ast_type_traits::ASTNodeKind Kind) const;
+
+ /// \brief Return a matcher that points to the same implementation, but
+ /// restricts the node types for \p Kind.
+ DynTypedMatcher dynCastTo(const ast_type_traits::ASTNodeKind Kind) const;
+
+ /// \brief Returns true if the matcher matches the given \c DynNode.
+ bool matches(const ast_type_traits::DynTypedNode &DynNode,
+ ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const;
+
+ /// \brief Same as matches(), but skips the kind check.
+ ///
+ /// It is faster, but the caller must ensure the node is valid for the
+ /// kind of this matcher.
+ bool matchesNoKindCheck(const ast_type_traits::DynTypedNode &DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const;
+
+ /// \brief Bind the specified \p ID to the matcher.
+ /// \return A new matcher with the \p ID bound to it if this matcher supports
+ /// binding. Otherwise, returns an empty \c Optional<>.
+ llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const;
+
+ /// \brief Returns a unique \p ID for the matcher.
+ ///
+ /// Casting a Matcher<T> to Matcher<U> creates a matcher that has the
+ /// same \c Implementation pointer, but different \c RestrictKind. We need to
+ /// include both in the ID to make it unique.
+ ///
+ /// \c MatcherIDType supports operator< and provides strict weak ordering.
+ typedef std::pair<ast_type_traits::ASTNodeKind, uint64_t> MatcherIDType;
+ MatcherIDType getID() const {
+ /// FIXME: Document the requirements this imposes on matcher
+ /// implementations (no new() implementation_ during a Matches()).
+ return std::make_pair(RestrictKind,
+ reinterpret_cast<uint64_t>(Implementation.get()));
+ }
+
+ /// \brief Returns the type this matcher works on.
+ ///
+ /// \c matches() will always return false unless the node passed is of this
+ /// or a derived type.
+ ast_type_traits::ASTNodeKind getSupportedKind() const {
+ return SupportedKind;
+ }
+
+ /// \brief Returns \c true if the passed \c DynTypedMatcher can be converted
+ /// to a \c Matcher<T>.
+ ///
+ /// This method verifies that the underlying matcher in \c Other can process
+ /// nodes of types T.
+ template <typename T> bool canConvertTo() const {
+ return canConvertTo(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+ }
+ bool canConvertTo(ast_type_traits::ASTNodeKind To) const;
+
+ /// \brief Construct a \c Matcher<T> interface around the dynamic matcher.
+ ///
+ /// This method asserts that \c canConvertTo() is \c true. Callers
+ /// should call \c canConvertTo() first to make sure that \c this is
+ /// compatible with T.
+ template <typename T> Matcher<T> convertTo() const {
+ assert(canConvertTo<T>());
+ return unconditionalConvertTo<T>();
+ }
+
+ /// \brief Same as \c convertTo(), but does not check that the underlying
+ /// matcher can handle a value of T.
+ ///
+ /// If it is not compatible, then this matcher will never match anything.
+ template <typename T> Matcher<T> unconditionalConvertTo() const;
+
+private:
+ DynTypedMatcher(ast_type_traits::ASTNodeKind SupportedKind,
+ ast_type_traits::ASTNodeKind RestrictKind,
+ IntrusiveRefCntPtr<DynMatcherInterface> Implementation)
+ : AllowBind(false),
+ SupportedKind(SupportedKind),
+ RestrictKind(RestrictKind),
+ Implementation(std::move(Implementation)) {}
+
+ bool AllowBind;
+ ast_type_traits::ASTNodeKind SupportedKind;
+ /// \brief A potentially stricter node kind.
+ ///
+ /// It allows to perform implicit and dynamic cast of matchers without
+ /// needing to change \c Implementation.
+ ast_type_traits::ASTNodeKind RestrictKind;
+ IntrusiveRefCntPtr<DynMatcherInterface> Implementation;
+};
+
/// \brief Wrapper of a MatcherInterface<T> *that allows copying.
///
/// A Matcher<Base> can be used anywhere a Matcher<Derived> is
@@ -221,7 +403,10 @@ public:
Matcher(const Matcher<From> &Other,
typename std::enable_if<std::is_base_of<From, T>::value &&
!std::is_same<From, T>::value>::type * = 0)
- : Implementation(new ImplicitCastMatcher<From>(Other)) {}
+ : Implementation(restrictMatcher(Other.Implementation)) {
+ assert(Implementation.getSupportedKind().isSame(
+ ast_type_traits::ASTNodeKind::getFromNodeKind<T>()));
+ }
/// \brief Implicitly converts \c Matcher<Type> to \c Matcher<QualType>.
///
@@ -233,26 +418,34 @@ public:
std::is_same<TypeT, Type>::value>::type* = 0)
: Implementation(new TypeToQualType<TypeT>(Other)) {}
+ /// \brief Convert \c this into a \c Matcher<T> by applying dyn_cast<> to the
+ /// argument.
+ /// \c To must be a base class of \c T.
+ template <typename To>
+ Matcher<To> dynCastTo() const {
+ static_assert(std::is_base_of<To, T>::value, "Invalid dynCast call.");
+ return Matcher<To>(Implementation);
+ }
+
/// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- if (Implementation->matches(Node, Finder, Builder))
- return true;
- // Delete all bindings when a matcher does not match.
- // This prevents unexpected exposure of bound nodes in unmatches
- // branches of the match tree.
- *Builder = BoundNodesTreeBuilder();
- return false;
+ return Implementation.matches(ast_type_traits::DynTypedNode::create(Node),
+ Finder, Builder);
}
/// \brief Returns an ID that uniquely identifies the matcher.
- uint64_t getID() const {
- /// FIXME: Document the requirements this imposes on matcher
- /// implementations (no new() implementation_ during a Matches()).
- return reinterpret_cast<uint64_t>(Implementation.get());
+ DynTypedMatcher::MatcherIDType getID() const {
+ return Implementation.getID();
}
+ /// \brief Extract the dynamic matcher.
+ ///
+ /// The returned matcher keeps the same restrictions as \c this and remembers
+ /// that it is meant to support nodes of type \c T.
+ operator DynTypedMatcher() const { return Implementation; }
+
/// \brief Allows the conversion of a \c Matcher<Type> to a \c
/// Matcher<QualType>.
///
@@ -276,24 +469,22 @@ public:
};
private:
- /// \brief Allows conversion from Matcher<Base> to Matcher<T> if T
- /// is derived from Base.
- template <typename Base>
- class ImplicitCastMatcher : public MatcherInterface<T> {
- public:
- explicit ImplicitCastMatcher(const Matcher<Base> &From)
- : From(From) {}
+ // For Matcher<T> <=> Matcher<U> conversions.
+ template <typename U> friend class Matcher;
+ // For DynTypedMatcher::unconditionalConvertTo<T>.
+ friend class DynTypedMatcher;
- bool matches(const T &Node, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const override {
- return From.matches(Node, Finder, Builder);
- }
+ static DynTypedMatcher restrictMatcher(const DynTypedMatcher &Other) {
+ return Other.dynCastTo(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+ }
- private:
- const Matcher<Base> From;
- };
+ explicit Matcher(const DynTypedMatcher &Implementation)
+ : Implementation(restrictMatcher(Implementation)) {
+ assert(this->Implementation.getSupportedKind()
+ .isSame(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()));
+ }
- IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
+ DynTypedMatcher Implementation;
}; // class Matcher
/// \brief A convenient helper for creating a Matcher<T> without specifying
@@ -303,153 +494,10 @@ inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) {
return Matcher<T>(Implementation);
}
-template <typename T> class BindableMatcher;
-
-/// \brief Matcher that works on a \c DynTypedNode.
-///
-/// It is constructed from a \c Matcher<T> object and redirects most calls to
-/// underlying matcher.
-/// It checks whether the \c DynTypedNode is convertible into the type of the
-/// underlying matcher and then do the actual match on the actual node, or
-/// return false if it is not convertible.
-class DynTypedMatcher {
-public:
- /// \brief Construct from a \c Matcher<T>. Copies the matcher.
- template <typename T> inline DynTypedMatcher(const Matcher<T> &M);
-
- /// \brief Construct from a bindable \c Matcher<T>. Copies the matcher.
- ///
- /// This version enables \c tryBind() on the \c DynTypedMatcher.
- template <typename T> inline DynTypedMatcher(const BindableMatcher<T> &M);
-
- /// \brief Returns true if the matcher matches the given \c DynNode.
- bool matches(const ast_type_traits::DynTypedNode DynNode,
- ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const {
- return Storage->matches(DynNode, Finder, Builder);
- }
-
- /// \brief Bind the specified \p ID to the matcher.
- /// \return A new matcher with the \p ID bound to it if this matcher supports
- /// binding. Otherwise, returns an empty \c Optional<>.
- llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const {
- return Storage->tryBind(ID);
- }
-
- /// \brief Returns a unique \p ID for the matcher.
- uint64_t getID() const { return Storage->getID(); }
-
- /// \brief Returns the type this matcher works on.
- ///
- /// \c matches() will always return false unless the node passed is of this
- /// or a derived type.
- ast_type_traits::ASTNodeKind getSupportedKind() const {
- return Storage->getSupportedKind();
- }
-
- /// \brief Returns \c true if the passed \c DynTypedMatcher can be converted
- /// to a \c Matcher<T>.
- ///
- /// This method verifies that the underlying matcher in \c Other can process
- /// nodes of types T.
- template <typename T> bool canConvertTo() const {
- return getSupportedKind().isBaseOf(
- ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
- }
-
- /// \brief Construct a \c Matcher<T> interface around the dynamic matcher.
- ///
- /// This method asserts that \c canConvertTo() is \c true. Callers
- /// should call \c canConvertTo() first to make sure that \c this is
- /// compatible with T.
- template <typename T> Matcher<T> convertTo() const {
- assert(canConvertTo<T>());
- return unconditionalConvertTo<T>();
- }
-
- /// \brief Same as \c convertTo(), but does not check that the underlying
- /// matcher can handle a value of T.
- ///
- /// If it is not compatible, then this matcher will never match anything.
- template <typename T> Matcher<T> unconditionalConvertTo() const;
-
-private:
- class MatcherStorage : public RefCountedBaseVPTR {
- public:
- MatcherStorage(ast_type_traits::ASTNodeKind SupportedKind, uint64_t ID)
- : SupportedKind(SupportedKind), ID(ID) {}
- virtual ~MatcherStorage();
-
- virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const = 0;
-
- virtual llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const = 0;
-
- ast_type_traits::ASTNodeKind getSupportedKind() const {
- return SupportedKind;
- }
-
- uint64_t getID() const { return ID; }
-
- private:
- const ast_type_traits::ASTNodeKind SupportedKind;
- const uint64_t ID;
- };
-
- /// \brief Typed implementation of \c MatcherStorage.
- template <typename T> class TypedMatcherStorage;
-
- IntrusiveRefCntPtr<const MatcherStorage> Storage;
-};
-
-template <typename T>
-class DynTypedMatcher::TypedMatcherStorage : public MatcherStorage {
-public:
- TypedMatcherStorage(const Matcher<T> &Other, bool AllowBind)
- : MatcherStorage(ast_type_traits::ASTNodeKind::getFromNodeKind<T>(),
- Other.getID()),
- InnerMatcher(Other), AllowBind(AllowBind) {}
-
- bool matches(const ast_type_traits::DynTypedNode DynNode,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const override {
- if (const T *Node = DynNode.get<T>()) {
- return InnerMatcher.matches(*Node, Finder, Builder);
- }
- return false;
- }
-
- llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const override {
- if (!AllowBind)
- return llvm::Optional<DynTypedMatcher>();
- return DynTypedMatcher(BindableMatcher<T>(InnerMatcher).bind(ID));
- }
-
-private:
- const Matcher<T> InnerMatcher;
- const bool AllowBind;
-};
-
-template <typename T>
-inline DynTypedMatcher::DynTypedMatcher(const Matcher<T> &M)
- : Storage(new TypedMatcherStorage<T>(M, false)) {}
-
-template <typename T>
-inline DynTypedMatcher::DynTypedMatcher(const BindableMatcher<T> &M)
- : Storage(new TypedMatcherStorage<T>(M, true)) {}
-
/// \brief Specialization of the conversion functions for QualType.
///
-/// These specializations provide the Matcher<Type>->Matcher<QualType>
+/// This specialization provides the Matcher<Type>->Matcher<QualType>
/// conversion that the static API does.
-template <> inline bool DynTypedMatcher::canConvertTo<QualType>() const {
- const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind();
- return SourceKind.isSame(
- ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) ||
- SourceKind.isSame(
- ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>());
-}
-
template <>
inline Matcher<QualType> DynTypedMatcher::convertTo<QualType>() const {
assert(canConvertTo<QualType>());
@@ -470,7 +518,7 @@ bool matchesFirstInRange(const MatcherT &Matcher, IteratorT Start,
for (IteratorT I = Start; I != End; ++I) {
BoundNodesTreeBuilder Result(*Builder);
if (Matcher.matches(*I, Finder, &Result)) {
- *Builder = Result;
+ *Builder = std::move(Result);
return true;
}
}
@@ -486,7 +534,7 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start,
for (IteratorT I = Start; I != End; ++I) {
BoundNodesTreeBuilder Result(*Builder);
if (Matcher.matches(**I, Finder, &Result)) {
- *Builder = Result;
+ *Builder = std::move(Result);
return true;
}
}
@@ -549,6 +597,33 @@ private:
std::string Name;
};
+/// \brief Matches named declarations with a specific name.
+///
+/// See \c hasName() in ASTMatchers.h for details.
+class HasNameMatcher : public SingleNodeMatcherInterface<NamedDecl> {
+ public:
+ explicit HasNameMatcher(StringRef Name);
+
+ bool matchesNode(const NamedDecl &Node) const override;
+
+ private:
+ /// \brief Unqualified match routine.
+ ///
+ /// It is much faster than the full match, but it only works for unqualified
+ /// matches.
+ bool matchesNodeUnqualified(const NamedDecl &Node) const;
+
+ /// \brief Full match routine
+ ///
+ /// It generates the fully qualified name of the declaration (which is
+ /// expensive) before trying to match.
+ /// It is slower but simple and works on all cases.
+ bool matchesNodeFull(const NamedDecl &Node) const;
+
+ const bool UseUnqualifiedMatch;
+ const std::string Name;
+};
+
/// \brief Matches declarations for QualType and CallExpr.
///
/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
@@ -973,46 +1048,16 @@ private:
///
/// This is useful when a matcher syntactically requires a child matcher,
/// but the context doesn't care. See for example: anything().
-///
-/// FIXME: Alternatively we could also create a IsAMatcher or something
-/// that checks that a dyn_cast is possible. This is purely needed for the
-/// difference between calling for example:
-/// record()
-/// and
-/// record(SomeMatcher)
-/// In the second case we need the correct type we were dyn_cast'ed to in order
-/// to get the right type for the inner matcher. In the first case we don't need
-/// that, but we use the type conversion anyway and insert a TrueMatcher.
-template <typename T>
-class TrueMatcher : public SingleNodeMatcherInterface<T> {
-public:
- bool matchesNode(const T &Node) const override {
- return true;
- }
-};
-
-/// \brief Matcher<T> that wraps an inner Matcher<T> and binds the matched node
-/// to an ID if the inner matcher matches on the node.
-template <typename T>
-class IdMatcher : public MatcherInterface<T> {
-public:
- /// \brief Creates an IdMatcher that binds to 'ID' if 'InnerMatcher' matches
- /// the node.
- IdMatcher(StringRef ID, const Matcher<T> &InnerMatcher)
- : ID(ID), InnerMatcher(InnerMatcher) {}
+class TrueMatcher {
+ public:
+ typedef AllNodeBaseTypes ReturnTypes;
- bool matches(const T &Node, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const override {
- bool Result = InnerMatcher.matches(Node, Finder, Builder);
- if (Result) {
- Builder->setBinding(ID, &Node);
- }
- return Result;
+ template <typename T>
+ operator Matcher<T>() const {
+ return DynTypedMatcher::trueMatcher(
+ ast_type_traits::ASTNodeKind::getFromNodeKind<T>())
+ .template unconditionalConvertTo<T>();
}
-
-private:
- const std::string ID;
- const Matcher<T> InnerMatcher;
};
/// \brief A Matcher that allows binding the node it matches to an id.
@@ -1031,7 +1076,17 @@ public:
/// The returned matcher is equivalent to this matcher, but will
/// bind the matched node on a match.
Matcher<T> bind(StringRef ID) const {
- return Matcher<T>(new IdMatcher<T>(ID, *this));
+ return DynTypedMatcher(*this)
+ .tryBind(ID)
+ ->template unconditionalConvertTo<T>();
+ }
+
+ /// \brief Same as Matcher<T>'s conversion operator, but enables binding on
+ /// the returned matcher.
+ operator DynTypedMatcher() const {
+ DynTypedMatcher Result = static_cast<const Matcher<T>&>(*this);
+ Result.setAllowBind(true);
+ return Result;
}
};
@@ -1089,36 +1144,11 @@ private:
/// \brief VariadicOperatorMatcher related types.
/// @{
-/// \brief Function signature for any variadic operator. It takes the inner
-/// matchers as an array of DynTypedMatcher.
-typedef bool (*VariadicOperatorFunction)(
- const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers);
-
-/// \brief \c MatcherInterface<T> implementation for an variadic operator.
-template <typename T>
-class VariadicOperatorMatcherInterface : public MatcherInterface<T> {
-public:
- VariadicOperatorMatcherInterface(VariadicOperatorFunction Func,
- std::vector<DynTypedMatcher> InnerMatchers)
- : Func(Func), InnerMatchers(std::move(InnerMatchers)) {}
-
- bool matches(const T &Node, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const override {
- return Func(ast_type_traits::DynTypedNode::create(Node), Finder, Builder,
- InnerMatchers);
- }
-
-private:
- const VariadicOperatorFunction Func;
- const std::vector<DynTypedMatcher> InnerMatchers;
-};
-
/// \brief "No argument" placeholder to use as template paratemers.
struct VariadicOperatorNoArg {};
-/// \brief Polymorphic matcher object that uses a \c VariadicOperatorFunction
-/// operator.
+/// \brief Polymorphic matcher object that uses a \c
+/// DynTypedMatcher::VariadicOperator operator.
///
/// Input matchers can have any type (including other polymorphic matcher
/// types), and the actual Matcher<T> is generated on demand with an implicit
@@ -1133,7 +1163,8 @@ template <typename P1, typename P2 = VariadicOperatorNoArg,
typename P9 = VariadicOperatorNoArg>
class VariadicOperatorMatcher {
public:
- VariadicOperatorMatcher(VariadicOperatorFunction Func, const P1 &Param1,
+ VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op,
+ const P1 &Param1,
const P2 &Param2 = VariadicOperatorNoArg(),
const P3 &Param3 = VariadicOperatorNoArg(),
const P4 &Param4 = VariadicOperatorNoArg(),
@@ -1142,7 +1173,7 @@ public:
const P7 &Param7 = VariadicOperatorNoArg(),
const P8 &Param8 = VariadicOperatorNoArg(),
const P9 &Param9 = VariadicOperatorNoArg())
- : Func(Func), Param1(Param1), Param2(Param2), Param3(Param3),
+ : Op(Op), Param1(Param1), Param2(Param2), Param3(Param3),
Param4(Param4), Param5(Param5), Param6(Param6), Param7(Param7),
Param8(Param8), Param9(Param9) {}
@@ -1157,8 +1188,8 @@ public:
addMatcher<T>(Param7, Matchers);
addMatcher<T>(Param8, Matchers);
addMatcher<T>(Param9, Matchers);
- return Matcher<T>(
- new VariadicOperatorMatcherInterface<T>(Func, std::move(Matchers)));
+ return DynTypedMatcher::constructVariadic(Op, std::move(Matchers))
+ .template unconditionalConvertTo<T>();
}
private:
@@ -1173,7 +1204,7 @@ private:
static void addMatcher(VariadicOperatorNoArg,
std::vector<DynTypedMatcher> &Matchers) {}
- const VariadicOperatorFunction Func;
+ const DynTypedMatcher::VariadicOperator Op;
const P1 Param1;
const P2 Param2;
const P3 Param3;
@@ -1191,7 +1222,7 @@ private:
/// It supports 1-9 argument overloaded operator(). More can be added if needed.
template <unsigned MinCount, unsigned MaxCount>
struct VariadicOperatorMatcherFunc {
- VariadicOperatorFunction Func;
+ DynTypedMatcher::VariadicOperator Op;
template <unsigned Count, typename T>
struct EnableIfValidArity
@@ -1200,30 +1231,29 @@ struct VariadicOperatorMatcherFunc {
template <typename M1>
typename EnableIfValidArity<1, VariadicOperatorMatcher<M1> >::type
operator()(const M1 &P1) const {
- return VariadicOperatorMatcher<M1>(Func, P1);
+ return VariadicOperatorMatcher<M1>(Op, P1);
}
template <typename M1, typename M2>
typename EnableIfValidArity<2, VariadicOperatorMatcher<M1, M2> >::type
operator()(const M1 &P1, const M2 &P2) const {
- return VariadicOperatorMatcher<M1, M2>(Func, P1, P2);
+ return VariadicOperatorMatcher<M1, M2>(Op, P1, P2);
}
template <typename M1, typename M2, typename M3>
typename EnableIfValidArity<3, VariadicOperatorMatcher<M1, M2, M3> >::type
operator()(const M1 &P1, const M2 &P2, const M3 &P3) const {
- return VariadicOperatorMatcher<M1, M2, M3>(Func, P1, P2, P3);
+ return VariadicOperatorMatcher<M1, M2, M3>(Op, P1, P2, P3);
}
template <typename M1, typename M2, typename M3, typename M4>
typename EnableIfValidArity<4, VariadicOperatorMatcher<M1, M2, M3, M4> >::type
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) const {
- return VariadicOperatorMatcher<M1, M2, M3, M4>(Func, P1, P2, P3, P4);
+ return VariadicOperatorMatcher<M1, M2, M3, M4>(Op, P1, P2, P3, P4);
}
template <typename M1, typename M2, typename M3, typename M4, typename M5>
typename EnableIfValidArity<
5, VariadicOperatorMatcher<M1, M2, M3, M4, M5> >::type
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
const M5 &P5) const {
- return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Func, P1, P2, P3, P4,
- P5);
+ return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Op, P1, P2, P3, P4, P5);
}
template <typename M1, typename M2, typename M3, typename M4, typename M5,
typename M6>
@@ -1232,7 +1262,7 @@ struct VariadicOperatorMatcherFunc {
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
const M5 &P5, const M6 &P6) const {
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6>(
- Func, P1, P2, P3, P4, P5, P6);
+ Op, P1, P2, P3, P4, P5, P6);
}
template <typename M1, typename M2, typename M3, typename M4, typename M5,
typename M6, typename M7>
@@ -1241,7 +1271,7 @@ struct VariadicOperatorMatcherFunc {
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
const M5 &P5, const M6 &P6, const M7 &P7) const {
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7>(
- Func, P1, P2, P3, P4, P5, P6, P7);
+ Op, P1, P2, P3, P4, P5, P6, P7);
}
template <typename M1, typename M2, typename M3, typename M4, typename M5,
typename M6, typename M7, typename M8>
@@ -1250,7 +1280,7 @@ struct VariadicOperatorMatcherFunc {
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
const M5 &P5, const M6 &P6, const M7 &P7, const M8 &P8) const {
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8>(
- Func, P1, P2, P3, P4, P5, P6, P7, P8);
+ Op, P1, P2, P3, P4, P5, P6, P7, P8);
}
template <typename M1, typename M2, typename M3, typename M4, typename M5,
typename M6, typename M7, typename M8, typename M9>
@@ -1260,55 +1290,40 @@ struct VariadicOperatorMatcherFunc {
const M5 &P5, const M6 &P6, const M7 &P7, const M8 &P8,
const M9 &P9) const {
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8, M9>(
- Func, P1, P2, P3, P4, P5, P6, P7, P8, P9);
+ Op, P1, P2, P3, P4, P5, P6, P7, P8, P9);
}
};
/// @}
-/// \brief Matches nodes that do not match the provided matcher.
-///
-/// Uses the variadic matcher interface, but fails if InnerMatchers.size()!=1.
-bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
- ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
- ArrayRef<DynTypedMatcher> InnerMatchers);
-
-/// \brief Matches nodes for which all provided matchers match.
-bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder,
- ArrayRef<DynTypedMatcher> InnerMatchers);
-
-/// \brief Matches nodes for which at least one of the provided matchers
-/// matches, but doesn't stop at the first match.
-bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder,
- ArrayRef<DynTypedMatcher> InnerMatchers);
-
-/// \brief Matches nodes for which at least one of the provided matchers
-/// matches.
-bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder,
- ArrayRef<DynTypedMatcher> InnerMatchers);
-
template <typename T>
inline Matcher<T> DynTypedMatcher::unconditionalConvertTo() const {
- return Matcher<T>(new VariadicOperatorMatcherInterface<T>(
- AllOfVariadicOperator, llvm::makeArrayRef(*this)));
+ return Matcher<T>(*this);
}
/// \brief Creates a Matcher<T> that matches if all inner matchers match.
template<typename T>
BindableMatcher<T> makeAllOfComposite(
ArrayRef<const Matcher<T> *> InnerMatchers) {
- std::vector<DynTypedMatcher> DynMatchers;
- for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
- DynMatchers.push_back(*InnerMatchers[i]);
+ // For the size() == 0 case, we return a "true" matcher.
+ if (InnerMatchers.size() == 0) {
+ return BindableMatcher<T>(TrueMatcher());
+ }
+ // For the size() == 1 case, we simply return that one matcher.
+ // No need to wrap it in a variadic operation.
+ if (InnerMatchers.size() == 1) {
+ return BindableMatcher<T>(*InnerMatchers[0]);
}
- return BindableMatcher<T>(new VariadicOperatorMatcherInterface<T>(
- AllOfVariadicOperator, std::move(DynMatchers)));
+
+ std::vector<DynTypedMatcher> DynMatchers;
+ DynMatchers.reserve(InnerMatchers.size());
+ for (const auto *InnerMatcher : InnerMatchers) {
+ DynMatchers.push_back(*InnerMatcher);
+ }
+ return BindableMatcher<T>(
+ DynTypedMatcher::constructVariadic(DynTypedMatcher::VO_AllOf,
+ std::move(DynMatchers))
+ .template unconditionalConvertTo<T>());
}
/// \brief Creates a Matcher<T> that matches if
@@ -1320,8 +1335,8 @@ BindableMatcher<T> makeAllOfComposite(
template<typename T, typename InnerT>
BindableMatcher<T> makeDynCastAllOfComposite(
ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
- return BindableMatcher<T>(DynTypedMatcher(makeAllOfComposite(InnerMatchers))
- .unconditionalConvertTo<T>());
+ return BindableMatcher<T>(
+ makeAllOfComposite(InnerMatchers).template dynCastTo<T>());
}
/// \brief Matches nodes of type T that have at least one descendant node of
@@ -1606,6 +1621,23 @@ private:
const Matcher<InnerTBase> InnerMatcher;
};
+/// \brief A simple memoizer of T(*)() functions.
+///
+/// It will call the passed 'Func' template parameter at most once.
+/// Used to support AST_MATCHER_FUNCTION() macro.
+template <typename Matcher, Matcher (*Func)()> class MemoizedMatcher {
+ struct Wrapper {
+ Wrapper() : M(Func()) {}
+ Matcher M;
+ };
+
+public:
+ static const Matcher &getInstance() {
+ static llvm::ManagedStatic<Wrapper> Instance;
+ return Instance->M;
+ }
+};
+
// Define the create() method out of line to silence a GCC warning about
// the struct "Func" having greater visibility than its base, which comes from
// using the flag -fvisibility-inlines-hidden.
@@ -1627,7 +1659,7 @@ getTemplateSpecializationArgs(const ClassTemplateSpecializationDecl &D) {
inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const TemplateSpecializationType &T) {
- return ArrayRef<TemplateArgument>(T.getArgs(), T.getNumArgs());
+ return llvm::makeArrayRef(T.getArgs(), T.getNumArgs());
}
struct NotEqualsBoundNodePredicate {
@@ -1642,4 +1674,4 @@ struct NotEqualsBoundNodePredicate {
} // end namespace ast_matchers
} // end namespace clang
-#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
+#endif
diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h
index 563372a50609..b7888be7c176 100644
--- a/include/clang/ASTMatchers/ASTMatchersMacros.h
+++ b/include/clang/ASTMatchers/ASTMatchersMacros.h
@@ -34,8 +34,19 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
-#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
+#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H
+#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H
+
+/// \brief AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) {
+/// defines a zero parameter function named DefineMatcher() that returns a
+/// ReturnType object.
+#define AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) \
+ inline ReturnType DefineMatcher##_getInstance(); \
+ inline ReturnType DefineMatcher() { \
+ return internal::MemoizedMatcher< \
+ ReturnType, DefineMatcher##_getInstance>::getInstance(); \
+ } \
+ inline ReturnType DefineMatcher##_getInstance()
/// \brief AST_MATCHER_FUNCTION_P(ReturnType, DefineMatcher, ParamType, Param) {
/// defines a single-parameter function named DefineMatcher() that returns a
@@ -352,4 +363,4 @@
internal::TypeLocTraverseMatcher, ReturnTypesF>::Func MatcherName##Loc; \
AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type, ReturnTypesF)
-#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
+#endif
diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
index 82a14f1929be..ef93ac54508d 100644
--- a/include/clang/ASTMatchers/Dynamic/Diagnostics.h
+++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
-#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
+#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H
+#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
#include "clang/Basic/LLVM.h"
diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h
index 4045f57d1b36..bd006b6e1290 100644
--- a/include/clang/ASTMatchers/Dynamic/Parser.h
+++ b/include/clang/ASTMatchers/Dynamic/Parser.h
@@ -31,8 +31,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
-#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
+#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H
+#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
#include "clang/ASTMatchers/Dynamic/Registry.h"
@@ -63,17 +63,6 @@ public:
public:
virtual ~Sema();
- /// \brief Lookup a value by name.
- ///
- /// This can be used in the Sema layer to declare known constants or to
- /// allow to split an expression in pieces.
- ///
- /// \param Name The name of the value to lookup.
- ///
- /// \return The named value. It could be any type that VariantValue
- /// supports. An empty value means that the name is not recognized.
- virtual VariantValue getNamedValue(StringRef Name);
-
/// \brief Process a matcher expression.
///
/// All the arguments passed here have already been processed.
@@ -105,6 +94,29 @@ public:
/// found.
virtual llvm::Optional<MatcherCtor>
lookupMatcherCtor(StringRef MatcherName) = 0;
+
+ /// \brief Compute the list of completion types for \p Context.
+ ///
+ /// Each element of \p Context represents a matcher invocation, going from
+ /// outermost to innermost. Elements are pairs consisting of a reference to
+ /// the matcher constructor and the index of the next element in the
+ /// argument list of that matcher (or for the last element, the index of
+ /// the completion point in the argument list). An empty list requests
+ /// completion for the root matcher.
+ virtual std::vector<ArgKind> getAcceptedCompletionTypes(
+ llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context);
+
+ /// \brief Compute the list of completions that match any of
+ /// \p AcceptedTypes.
+ ///
+ /// \param AcceptedTypes All types accepted for this completion.
+ ///
+ /// \return All completions for the specified types.
+ /// Completions should be valid when used in \c lookupMatcherCtor().
+ /// The matcher constructed from the return of \c lookupMatcherCtor()
+ /// should be convertible to some type in \p AcceptedTypes.
+ virtual std::vector<MatcherCompletion>
+ getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes);
};
/// \brief Sema implementation that uses the matcher registry to process the
@@ -121,58 +133,91 @@ public:
StringRef BindID,
ArrayRef<ParserValue> Args,
Diagnostics *Error) override;
+
+ std::vector<ArgKind> getAcceptedCompletionTypes(
+ llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) override;
+
+ std::vector<MatcherCompletion>
+ getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) override;
};
- /// \brief Parse a matcher expression, creating matchers from the registry.
- ///
- /// This overload creates matchers calling directly into the registry. If the
- /// caller needs more control over how the matchers are created, then it can
- /// use the overload below that takes a Sema.
- ///
- /// \param MatcherCode The matcher expression to parse.
- ///
- /// \return The matcher object constructed, or an empty Optional if an error
- /// occurred.
- /// In that case, \c Error will contain a description of the error.
- /// The caller takes ownership of the DynTypedMatcher object returned.
- static llvm::Optional<DynTypedMatcher>
- parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error);
+ typedef llvm::StringMap<VariantValue> NamedValueMap;
/// \brief Parse a matcher expression.
///
/// \param MatcherCode The matcher expression to parse.
///
/// \param S The Sema instance that will help the parser
- /// construct the matchers.
+ /// construct the matchers. If null, it uses the default registry.
+ ///
+ /// \param NamedValues A map of precomputed named values. This provides
+ /// the dictionary for the <NamedValue> rule of the grammar.
+ /// If null, it is ignored.
+ ///
/// \return The matcher object constructed by the processor, or an empty
/// Optional if an error occurred. In that case, \c Error will contain a
/// description of the error.
/// The caller takes ownership of the DynTypedMatcher object returned.
static llvm::Optional<DynTypedMatcher>
- parseMatcherExpression(StringRef MatcherCode, Sema *S, Diagnostics *Error);
-
- /// \brief Parse an expression, creating matchers from the registry.
- ///
- /// Parses any expression supported by this parser. In general, the
- /// \c parseMatcherExpression function is a better approach to get a matcher
- /// object.
- static bool parseExpression(StringRef Code, VariantValue *Value,
- Diagnostics *Error);
+ parseMatcherExpression(StringRef MatcherCode, Sema *S,
+ const NamedValueMap *NamedValues,
+ Diagnostics *Error);
+ static llvm::Optional<DynTypedMatcher>
+ parseMatcherExpression(StringRef MatcherCode, Sema *S,
+ Diagnostics *Error) {
+ return parseMatcherExpression(MatcherCode, S, nullptr, Error);
+ }
+ static llvm::Optional<DynTypedMatcher>
+ parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error) {
+ return parseMatcherExpression(MatcherCode, nullptr, Error);
+ }
/// \brief Parse an expression.
///
/// Parses any expression supported by this parser. In general, the
/// \c parseMatcherExpression function is a better approach to get a matcher
/// object.
+ ///
+ /// \param S The Sema instance that will help the parser
+ /// construct the matchers. If null, it uses the default registry.
+ ///
+ /// \param NamedValues A map of precomputed named values. This provides
+ /// the dictionary for the <NamedValue> rule of the grammar.
+ /// If null, it is ignored.
static bool parseExpression(StringRef Code, Sema *S,
+ const NamedValueMap *NamedValues,
VariantValue *Value, Diagnostics *Error);
+ static bool parseExpression(StringRef Code, Sema *S,
+ VariantValue *Value, Diagnostics *Error) {
+ return parseExpression(Code, S, nullptr, Value, Error);
+ }
+ static bool parseExpression(StringRef Code, VariantValue *Value,
+ Diagnostics *Error) {
+ return parseExpression(Code, nullptr, Value, Error);
+ }
/// \brief Complete an expression at the given offset.
///
+ /// \param S The Sema instance that will help the parser
+ /// construct the matchers. If null, it uses the default registry.
+ ///
+ /// \param NamedValues A map of precomputed named values. This provides
+ /// the dictionary for the <NamedValue> rule of the grammar.
+ /// If null, it is ignored.
+ ///
/// \return The list of completions, which may be empty if there are no
/// available completions or if an error occurred.
static std::vector<MatcherCompletion>
- completeExpression(StringRef Code, unsigned CompletionOffset);
+ completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S,
+ const NamedValueMap *NamedValues);
+ static std::vector<MatcherCompletion>
+ completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S) {
+ return completeExpression(Code, CompletionOffset, S, nullptr);
+ }
+ static std::vector<MatcherCompletion>
+ completeExpression(StringRef Code, unsigned CompletionOffset) {
+ return completeExpression(Code, CompletionOffset, nullptr);
+ }
private:
class CodeTokenizer;
@@ -180,6 +225,7 @@ private:
struct TokenInfo;
Parser(CodeTokenizer *Tokenizer, Sema *S,
+ const NamedValueMap *NamedValues,
Diagnostics *Error);
bool parseExpressionImpl(VariantValue *Value);
@@ -187,12 +233,16 @@ private:
VariantValue *Value);
bool parseIdentifierPrefixImpl(VariantValue *Value);
- void addCompletion(const TokenInfo &CompToken, StringRef TypedText,
- StringRef Decl);
+ void addCompletion(const TokenInfo &CompToken,
+ const MatcherCompletion &Completion);
void addExpressionCompletions();
+ std::vector<MatcherCompletion>
+ getNamedValueCompletions(ArrayRef<ArgKind> AcceptedTypes);
+
CodeTokenizer *const Tokenizer;
Sema *const S;
+ const NamedValueMap *const NamedValues;
Diagnostics *const Error;
typedef std::vector<std::pair<MatcherCtor, unsigned> > ContextStackTy;
diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h
index faa9254bc2e7..ad24a8d1b794 100644
--- a/include/clang/ASTMatchers/Dynamic/Registry.h
+++ b/include/clang/ASTMatchers/Dynamic/Registry.h
@@ -14,8 +14,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H
-#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H
+#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H
+#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
@@ -36,8 +36,10 @@ typedef const internal::MatcherDescriptor *MatcherCtor;
struct MatcherCompletion {
MatcherCompletion() {}
- MatcherCompletion(StringRef TypedText, StringRef MatcherDecl)
- : TypedText(TypedText), MatcherDecl(MatcherDecl) {}
+ MatcherCompletion(StringRef TypedText, StringRef MatcherDecl,
+ unsigned Specificity)
+ : TypedText(TypedText), MatcherDecl(MatcherDecl),
+ Specificity(Specificity) {}
/// \brief The text to type to select this matcher.
std::string TypedText;
@@ -45,6 +47,13 @@ struct MatcherCompletion {
/// \brief The "declaration" of the matcher, with type information.
std::string MatcherDecl;
+ /// \brief Value corresponding to the "specificity" of the converted matcher.
+ ///
+ /// Zero specificity indicates that this conversion would produce a trivial
+ /// matcher that will either always or never match.
+ /// Such matchers are excluded from code completion results.
+ unsigned Specificity;
+
bool operator==(const MatcherCompletion &Other) const {
return TypedText == Other.TypedText && MatcherDecl == Other.MatcherDecl;
}
@@ -58,28 +67,28 @@ public:
/// constructor, or Optional<MatcherCtor>() if not found.
static llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName);
- /// \brief Compute the list of completions for \p Context.
+ /// \brief Compute the list of completion types for \p Context.
///
/// Each element of \p Context represents a matcher invocation, going from
- /// outermost to innermost. Elements are pairs consisting of a reference to the
- /// matcher constructor and the index of the next element in the argument list
- /// of that matcher (or for the last element, the index of the completion
- /// point in the argument list). An empty list requests completion for the
- /// root matcher.
+ /// outermost to innermost. Elements are pairs consisting of a reference to
+ /// the matcher constructor and the index of the next element in the
+ /// argument list of that matcher (or for the last element, the index of
+ /// the completion point in the argument list). An empty list requests
+ /// completion for the root matcher.
+ static std::vector<ArgKind> getAcceptedCompletionTypes(
+ llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context);
+
+ /// \brief Compute the list of completions that match any of
+ /// \p AcceptedTypes.
///
- /// The completions are ordered first by decreasing relevance, then
- /// alphabetically. Relevance is determined by how closely the matcher's
- /// type matches that of the context. For example, if the innermost matcher
- /// takes a FunctionDecl matcher, the FunctionDecl matchers are returned
- /// first, followed by the ValueDecl matchers, then NamedDecl, then Decl, then
- /// polymorphic matchers.
+ /// \param AcceptedTypes All types accepted for this completion.
///
- /// Matchers which are technically convertible to the innermost context but
- /// which would match either all or no nodes are excluded. For example,
- /// namedDecl and varDecl are excluded in a FunctionDecl context, because
- /// those matchers would match respectively all or no nodes in such a context.
+ /// \return All completions for the specified types.
+ /// Completions should be valid when used in \c lookupMatcherCtor().
+ /// The matcher constructed from the return of \c lookupMatcherCtor()
+ /// should be convertible to some type in \p AcceptedTypes.
static std::vector<MatcherCompletion>
- getCompletions(ArrayRef<std::pair<MatcherCtor, unsigned> > Context);
+ getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes);
/// \brief Construct a matcher from the registry.
///
diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h
index b25267b1c54b..a9bd3d50115a 100644
--- a/include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -14,8 +14,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
-#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
+#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
+#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
@@ -29,6 +29,51 @@ namespace clang {
namespace ast_matchers {
namespace dynamic {
+/// \brief Kind identifier.
+///
+/// It supports all types that VariantValue can contain.
+class ArgKind {
+ public:
+ enum Kind {
+ AK_Matcher,
+ AK_Unsigned,
+ AK_String
+ };
+ /// \brief Constructor for non-matcher types.
+ ArgKind(Kind K) : K(K) { assert(K != AK_Matcher); }
+
+ /// \brief Constructor for matcher types.
+ ArgKind(ast_type_traits::ASTNodeKind MatcherKind)
+ : K(AK_Matcher), MatcherKind(MatcherKind) {}
+
+ Kind getArgKind() const { return K; }
+ ast_type_traits::ASTNodeKind getMatcherKind() const {
+ assert(K == AK_Matcher);
+ return MatcherKind;
+ }
+
+ /// \brief Determines if this type can be converted to \p To.
+ ///
+ /// \param To the requested destination type.
+ ///
+ /// \param Specificity value corresponding to the "specificity" of the
+ /// convertion.
+ bool isConvertibleTo(ArgKind To, unsigned *Specificity) const;
+
+ bool operator<(const ArgKind &Other) const {
+ if (K == AK_Matcher && Other.K == AK_Matcher)
+ return MatcherKind < Other.MatcherKind;
+ return K < Other.K;
+ }
+
+ /// \brief String representation of the type.
+ std::string asString() const;
+
+private:
+ Kind K;
+ ast_type_traits::ASTNodeKind MatcherKind;
+};
+
using ast_matchers::internal::DynTypedMatcher;
/// \brief A variant matcher object.
@@ -48,13 +93,28 @@ class VariantMatcher {
/// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher.
class MatcherOps {
public:
- virtual ~MatcherOps();
- virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
- bool &IsExactMatch) const = 0;
- virtual void constructFrom(const DynTypedMatcher &Matcher) = 0;
- virtual void constructVariadicOperator(
- ast_matchers::internal::VariadicOperatorFunction Func,
- ArrayRef<VariantMatcher> InnerMatchers) = 0;
+ MatcherOps(ast_type_traits::ASTNodeKind NodeKind) : NodeKind(NodeKind) {}
+
+ bool canConstructFrom(const DynTypedMatcher &Matcher,
+ bool &IsExactMatch) const;
+
+ /// \brief Convert \p Matcher the destination type and return it as a new
+ /// DynTypedMatcher.
+ virtual DynTypedMatcher
+ convertMatcher(const DynTypedMatcher &Matcher) const = 0;
+
+ /// \brief Constructs a variadic typed matcher from \p InnerMatchers.
+ /// Will try to convert each inner matcher to the destination type and
+ /// return llvm::None if it fails to do so.
+ llvm::Optional<DynTypedMatcher>
+ constructVariadicOperator(DynTypedMatcher::VariadicOperator Op,
+ ArrayRef<VariantMatcher> InnerMatchers) const;
+
+ protected:
+ ~MatcherOps() {}
+
+ private:
+ ast_type_traits::ASTNodeKind NodeKind;
};
/// \brief Payload interface to be specialized by each matcher type.
@@ -65,7 +125,10 @@ class VariantMatcher {
virtual ~Payload();
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
virtual std::string getTypeAsString() const = 0;
- virtual void makeTypedMatcher(MatcherOps &Ops) const = 0;
+ virtual llvm::Optional<DynTypedMatcher>
+ getTypedMatcher(const MatcherOps &Ops) const = 0;
+ virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
+ unsigned *Specificity) const = 0;
};
public:
@@ -84,9 +147,9 @@ public:
/// \brief Creates a 'variadic' operator matcher.
///
/// It will bind to the appropriate type on getTypedMatcher<T>().
- static VariantMatcher VariadicOperatorMatcher(
- ast_matchers::internal::VariadicOperatorFunction Func,
- std::vector<VariantMatcher> Args);
+ static VariantMatcher
+ VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op,
+ std::vector<VariantMatcher> Args);
/// \brief Makes the matcher the "null" matcher.
void reset();
@@ -111,9 +174,21 @@ public:
/// that can, the result would be ambiguous and false is returned.
template <class T>
bool hasTypedMatcher() const {
- TypedMatcherOps<T> Ops;
- if (Value) Value->makeTypedMatcher(Ops);
- return Ops.hasMatcher();
+ if (!Value) return false;
+ return Value->getTypedMatcher(TypedMatcherOps<T>()).hasValue();
+ }
+
+ /// \brief Determines if the contained matcher can be converted to \p Kind.
+ ///
+ /// \param Kind the requested destination type.
+ ///
+ /// \param Specificity value corresponding to the "specificity" of the
+ /// convertion.
+ bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
+ unsigned *Specificity) const {
+ if (Value)
+ return Value->isConvertibleTo(Kind, Specificity);
+ return false;
}
/// \brief Return this matcher as a \c Matcher<T>.
@@ -122,10 +197,9 @@ public:
/// Asserts that \c hasTypedMatcher<T>() is true.
template <class T>
ast_matchers::internal::Matcher<T> getTypedMatcher() const {
- TypedMatcherOps<T> Ops;
- Value->makeTypedMatcher(Ops);
- assert(Ops.hasMatcher() && "hasTypedMatcher<T>() == false");
- return Ops.matcher();
+ assert(hasTypedMatcher<T>() && "hasTypedMatcher<T>() == false");
+ return Value->getTypedMatcher(TypedMatcherOps<T>())
+ ->template convertTo<T>();
}
/// \brief String representation of the type of the value.
@@ -137,51 +211,25 @@ public:
private:
explicit VariantMatcher(Payload *Value) : Value(Value) {}
+ template <typename T> struct TypedMatcherOps;
+
class SinglePayload;
class PolymorphicPayload;
class VariadicOpPayload;
- template <typename T>
- class TypedMatcherOps : public MatcherOps {
- public:
- typedef ast_matchers::internal::Matcher<T> MatcherT;
-
- virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
- bool &IsExactMatch) const {
- IsExactMatch = Matcher.getSupportedKind().isSame(
- ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
- return Matcher.canConvertTo<T>();
- }
-
- virtual void constructFrom(const DynTypedMatcher& Matcher) {
- Out.reset(new MatcherT(Matcher.convertTo<T>()));
- }
-
- virtual void constructVariadicOperator(
- ast_matchers::internal::VariadicOperatorFunction Func,
- ArrayRef<VariantMatcher> InnerMatchers) {
- std::vector<DynTypedMatcher> DynMatchers;
- for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
- // Abort if any of the inner matchers can't be converted to
- // Matcher<T>.
- if (!InnerMatchers[i].hasTypedMatcher<T>()) {
- return;
- }
- DynMatchers.push_back(InnerMatchers[i].getTypedMatcher<T>());
- }
- Out.reset(new MatcherT(
- new ast_matchers::internal::VariadicOperatorMatcherInterface<T>(
- Func, DynMatchers)));
- }
-
- bool hasMatcher() const { return Out.get() != nullptr; }
- const MatcherT &matcher() const { return *Out; }
+ IntrusiveRefCntPtr<const Payload> Value;
+};
- private:
- std::unique_ptr<MatcherT> Out;
- };
+template <typename T>
+struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps {
+ TypedMatcherOps()
+ : MatcherOps(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) {}
+ typedef ast_matchers::internal::Matcher<T> MatcherT;
- IntrusiveRefCntPtr<const Payload> Value;
+ DynTypedMatcher
+ convertMatcher(const DynTypedMatcher &Matcher) const override {
+ return DynTypedMatcher(Matcher.convertTo<T>());
+ }
};
/// \brief Variant value class.
@@ -228,6 +276,24 @@ public:
const VariantMatcher &getMatcher() const;
void setMatcher(const VariantMatcher &Matcher);
+ /// \brief Determines if the contained value can be converted to \p Kind.
+ ///
+ /// \param Kind the requested destination type.
+ ///
+ /// \param Specificity value corresponding to the "specificity" of the
+ /// convertion.
+ bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const;
+
+ /// \brief Determines if the contained value can be converted to any kind
+ /// in \p Kinds.
+ ///
+ /// \param Kinds the requested destination types.
+ ///
+ /// \param Specificity value corresponding to the "specificity" of the
+ /// convertion. It is the maximum specificity of all the possible
+ /// conversions.
+ bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const;
+
/// \brief String representation of the type of the value.
std::string getTypeAsString() const;
diff --git a/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h b/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h
index a61d9e47881d..cc14c7bd33db 100644
--- a/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h
+++ b/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_ANALYSIS_CFG_REACHABILITY
-#define CLANG_ANALYSIS_CFG_REACHABILITY
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CFGREACHABILITYANALYSIS_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_CFGREACHABILITYANALYSIS_H
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/include/clang/Analysis/Analyses/Consumed.h b/include/clang/Analysis/Analyses/Consumed.h
index 36e07c21907b..a7109233987c 100644
--- a/include/clang/Analysis/Analyses/Consumed.h
+++ b/include/clang/Analysis/Analyses/Consumed.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CONSUMED_H
-#define LLVM_CLANG_CONSUMED_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
diff --git a/include/clang/Analysis/Analyses/Dominators.h b/include/clang/Analysis/Analyses/Dominators.h
index 6c6d9238e5a9..fcef0fc10ac8 100644
--- a/include/clang/Analysis/Analyses/Dominators.h
+++ b/include/clang/Analysis/Analyses/Dominators.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_DOMINATORS_H
-#define LLVM_CLANG_DOMINATORS_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index 76fe9ddca6f8..174cce4f363c 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -16,8 +16,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FORMAT_H
-#define LLVM_CLANG_FORMAT_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
#include "clang/AST/CanonicalType.h"
@@ -79,6 +79,7 @@ public:
AsLongDouble, // 'L'
AsAllocate, // for '%as', GNU extension to C90 scanf
AsMAllocate, // for '%ms', GNU extension to scanf
+ AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
AsWideChar = AsLong // for '%ls', only makes sense for printf
};
@@ -154,6 +155,8 @@ public:
// ** Printf-specific **
+ ZArg, // MS extension
+
// Objective-C specific specifiers.
ObjCObjArg, // '@'
ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
@@ -644,6 +647,9 @@ public:
bool ParsePrintfString(FormatStringHandler &H,
const char *beg, const char *end, const LangOptions &LO,
const TargetInfo &Target);
+
+bool ParseFormatStringHasSArg(const char *beg, const char *end, const LangOptions &LO,
+ const TargetInfo &Target);
bool ParseScanfString(FormatStringHandler &H,
const char *beg, const char *end, const LangOptions &LO,
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h
index 784227108ead..c29dd409e56c 100644
--- a/include/clang/Analysis/Analyses/LiveVariables.h
+++ b/include/clang/Analysis/Analyses/LiveVariables.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LIVEVARIABLES_H
-#define LLVM_CLANG_LIVEVARIABLES_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H
#include "clang/AST/Decl.h"
#include "clang/Analysis/AnalysisContext.h"
diff --git a/include/clang/Analysis/Analyses/PostOrderCFGView.h b/include/clang/Analysis/Analyses/PostOrderCFGView.h
index 91bf51cd613f..a1c650427588 100644
--- a/include/clang/Analysis/Analyses/PostOrderCFGView.h
+++ b/include/clang/Analysis/Analyses/PostOrderCFGView.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_POSTORDER_CFGVIEW
-#define LLVM_CLANG_POSTORDER_CFGVIEW
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H
#include <vector>
//#include <algorithm>
@@ -47,17 +47,17 @@ public:
/// \brief Set the bit associated with a particular CFGBlock.
/// This is the important method for the SetType template parameter.
- bool insert(const CFGBlock *Block) {
+ std::pair<llvm::NoneType, bool> insert(const CFGBlock *Block) {
// Note that insert() is called by po_iterator, which doesn't check to
// make sure that Block is non-null. Moreover, the CFGBlock iterator will
// occasionally hand out null pointers for pruned edges, so we catch those
// here.
if (!Block)
- return false; // if an edge is trivially false.
+ return std::make_pair(None, false); // if an edge is trivially false.
if (VisitedBlockIDs.test(Block->getBlockID()))
- return false;
+ return std::make_pair(None, false);
VisitedBlockIDs.set(Block->getBlockID());
- return true;
+ return std::make_pair(None, true);
}
/// \brief Check if the bit for a CFGBlock has been already set.
diff --git a/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h b/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h
index cb73850b08c7..c4ec2f22eca0 100644
--- a/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h
+++ b/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ANALYSIS_PSEUDOCONSTANTANALYSIS
-#define LLVM_CLANG_ANALYSIS_PSEUDOCONSTANTANALYSIS
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_PSEUDOCONSTANTANALYSIS_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_PSEUDOCONSTANTANALYSIS_H
#include "clang/AST/Stmt.h"
diff --git a/include/clang/Analysis/Analyses/ReachableCode.h b/include/clang/Analysis/Analyses/ReachableCode.h
index 90a6d014f58d..4c523bfc8b56 100644
--- a/include/clang/Analysis/Analyses/ReachableCode.h
+++ b/include/clang/Analysis/Analyses/ReachableCode.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_REACHABLECODE_H
-#define LLVM_CLANG_REACHABLECODE_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_REACHABLECODE_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_REACHABLECODE_H
#include "clang/Basic/SourceLocation.h"
diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h
index b533c1db492e..458bb576f459 100644
--- a/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -16,31 +16,33 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_THREADSAFETY_H
-#define LLVM_CLANG_THREADSAFETY_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/StringRef.h"
namespace clang {
-namespace thread_safety {
+namespace threadSafety {
/// This enum distinguishes between different kinds of operations that may
/// need to be protected by locks. We use this enum in error handling.
enum ProtectedOperationKind {
POK_VarDereference, ///< Dereferencing a variable (e.g. p in *p = 5;)
POK_VarAccess, ///< Reading or writing a variable (e.g. x in x = 5;)
- POK_FunctionCall ///< Making a function call (e.g. fool())
+ POK_FunctionCall, ///< Making a function call (e.g. fool())
+ POK_PassByRef, ///< Passing a guarded variable by reference.
+ POK_PtPassByRef, ///< Passing a pt-guarded variable by reference.
};
/// This enum distinguishes between different kinds of lock actions. For
/// example, it is an error to write a variable protected by shared version of a
/// mutex.
enum LockKind {
- LK_Shared, ///< Shared/reader lock of a mutex.
+ LK_Shared, ///< Shared/reader lock of a mutex.
LK_Exclusive, ///< Exclusive/writer lock of a mutex.
- LK_Generic ///< Can be either Shared or Exclusive
+ LK_Generic ///< Can be either Shared or Exclusive
};
/// This enum distinguishes between different ways to access (read or write) a
@@ -161,6 +163,16 @@ public:
LockKind LK, SourceLocation Loc,
Name *PossibleMatch = nullptr) {}
+ /// Warn when acquiring a lock that the negative capability is not held.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param LockName -- The name for the lock expression, to be printed in the
+ /// diagnostic.
+ /// \param Neg -- The name of the negative capability to be printed in the
+ /// diagnostic.
+ /// \param Loc -- The location of the protected operation.
+ virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
+ SourceLocation Loc) {}
+
/// Warn when a function is called while an excluded mutex is locked. For
/// example, the mutex may be locked inside the function.
/// \param Kind -- the capability's name parameter (role, mutex, etc).
@@ -171,6 +183,13 @@ public:
virtual void handleFunExcludesLock(StringRef Kind, Name FunName,
Name LockName, SourceLocation Loc) {}
+ /// Called by the analysis when starting analysis of a function.
+ /// Used to issue suggestions for changes to annotations.
+ virtual void enterFunction(const FunctionDecl *FD) {}
+
+ /// Called by the analysis when finishing analysis of a function.
+ virtual void leaveFunction(const FunctionDecl *FD) {}
+
bool issueBetaWarnings() { return IssueBetaWarnings; }
void setIssueBetaWarnings(bool b) { IssueBetaWarnings = b; }
@@ -190,5 +209,5 @@ void runThreadSafetyAnalysis(AnalysisDeclContext &AC,
/// of access.
LockKind getLockKindFromAccessKind(AccessKind AK);
-}} // end namespace clang::thread_safety
+}} // end namespace clang::threadSafety
#endif
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
index 09c614ca3e36..be81121c102b 100644
--- a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
+++ b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
@@ -19,21 +19,63 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_THREAD_SAFETY_COMMON_H
-#define LLVM_CLANG_THREAD_SAFETY_COMMON_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/OperatorKinds.h"
-
#include <memory>
+#include <ostream>
+#include <sstream>
#include <vector>
namespace clang {
namespace threadSafety {
+
+// Various helper functions on til::SExpr
+namespace sx {
+
+inline bool equals(const til::SExpr *E1, const til::SExpr *E2) {
+ return til::EqualsComparator::compareExprs(E1, E2);
+}
+
+inline bool matches(const til::SExpr *E1, const til::SExpr *E2) {
+ // We treat a top-level wildcard as the "univsersal" lock.
+ // It matches everything for the purpose of checking locks, but not
+ // for unlocking them.
+ if (isa<til::Wildcard>(E1))
+ return isa<til::Wildcard>(E2);
+ if (isa<til::Wildcard>(E2))
+ return isa<til::Wildcard>(E1);
+
+ return til::MatchComparator::compareExprs(E1, E2);
+}
+
+inline bool partiallyMatches(const til::SExpr *E1, const til::SExpr *E2) {
+ const auto *PE1 = dyn_cast_or_null<til::Project>(E1);
+ if (!PE1)
+ return false;
+ const auto *PE2 = dyn_cast_or_null<til::Project>(E2);
+ if (!PE2)
+ return false;
+ return PE1->clangDecl() == PE2->clangDecl();
+}
+
+inline std::string toString(const til::SExpr *E) {
+ std::stringstream ss;
+ til::StdPrinter::print(E, ss);
+ return ss.str();
+}
+
+} // end namespace sx
+
+
+
// This class defines the interface of a clang CFG Visitor.
// CFGWalker will invoke the following methods.
// Note that methods are not virtual; the visitor is templatized.
@@ -206,6 +248,59 @@ private:
};
+
+
+class CapabilityExpr {
+ // TODO: move this back into ThreadSafety.cpp
+ // This is specific to thread safety. It is here because
+ // translateAttrExpr needs it, but that should be moved too.
+
+private:
+ const til::SExpr* CapExpr; ///< The capability expression.
+ bool Negated; ///< True if this is a negative capability
+
+public:
+ CapabilityExpr(const til::SExpr *E, bool Neg) : CapExpr(E), Negated(Neg) {}
+
+ const til::SExpr* sexpr() const { return CapExpr; }
+ bool negative() const { return Negated; }
+
+ CapabilityExpr operator!() const {
+ return CapabilityExpr(CapExpr, !Negated);
+ }
+
+ bool equals(const CapabilityExpr &other) const {
+ return (Negated == other.Negated) && sx::equals(CapExpr, other.CapExpr);
+ }
+
+ bool matches(const CapabilityExpr &other) const {
+ return (Negated == other.Negated) && sx::matches(CapExpr, other.CapExpr);
+ }
+
+ bool matchesUniv(const CapabilityExpr &CapE) const {
+ return isUniversal() || matches(CapE);
+ }
+
+ bool partiallyMatches(const CapabilityExpr &other) const {
+ return (Negated == other.Negated) &&
+ sx::partiallyMatches(CapExpr, other.CapExpr);
+ }
+
+ std::string toString() const {
+ if (Negated)
+ return "!" + sx::toString(CapExpr);
+ return sx::toString(CapExpr);
+ }
+
+ bool shouldIgnore() const { return CapExpr == nullptr; }
+
+ bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); }
+
+ bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); }
+};
+
+
+
// Translate clang::Expr to til::SExpr.
class SExprBuilder {
public:
@@ -219,18 +314,16 @@ public:
/// should be evaluated; multiple calling contexts can be chained together
/// by the lock_returned attribute.
struct CallingContext {
+ CallingContext *Prev; // The previous context; or 0 if none.
const NamedDecl *AttrDecl; // The decl to which the attr is attached.
const Expr *SelfArg; // Implicit object argument -- e.g. 'this'
unsigned NumArgs; // Number of funArgs
const Expr *const *FunArgs; // Function arguments
- CallingContext *Prev; // The previous context; or 0 if none.
bool SelfArrow; // is Self referred to with -> or .?
- CallingContext(const NamedDecl *D = nullptr, const Expr *S = nullptr,
- unsigned N = 0, const Expr *const *A = nullptr,
- CallingContext *P = nullptr)
- : AttrDecl(D), SelfArg(S), NumArgs(N), FunArgs(A), Prev(P),
- SelfArrow(false)
+ CallingContext(CallingContext *P, const NamedDecl *D = nullptr)
+ : Prev(P), AttrDecl(D), SelfArg(nullptr),
+ NumArgs(0), FunArgs(nullptr), SelfArrow(false)
{}
};
@@ -242,6 +335,13 @@ public:
SelfVar->setKind(til::Variable::VK_SFun);
}
+ // Translate a clang expression in an attribute to a til::SExpr.
+ // Constructs the context from D, DeclExp, and SelfDecl.
+ CapabilityExpr translateAttrExpr(const Expr *AttrExp, const NamedDecl *D,
+ const Expr *DeclExp, VarDecl *SelfD=nullptr);
+
+ CapabilityExpr translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx);
+
// Translate a clang statement or expression to a TIL expression.
// Also performs substitution of variables; Ctx provides the context.
// Dispatches on the type of S.
@@ -262,7 +362,8 @@ private:
CallingContext *Ctx) ;
til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx);
til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx);
- til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx);
+ til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx,
+ const Expr *SelfE = nullptr);
til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME,
CallingContext *Ctx);
til::SExpr *translateCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE,
@@ -280,10 +381,8 @@ private:
til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx);
til::SExpr *translateArraySubscriptExpr(const ArraySubscriptExpr *E,
CallingContext *Ctx);
- til::SExpr *translateConditionalOperator(const ConditionalOperator *C,
- CallingContext *Ctx);
- til::SExpr *translateBinaryConditionalOperator(
- const BinaryConditionalOperator *C, CallingContext *Ctx);
+ til::SExpr *translateAbstractConditionalOperator(
+ const AbstractConditionalOperator *C, CallingContext *Ctx);
til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx);
@@ -362,21 +461,24 @@ private:
void mergePhiNodesBackEdge(const CFGBlock *Blk);
private:
+ // Set to true when parsing capability expressions, which get translated
+ // inaccurately in order to hack around smart pointers etc.
+ static const bool CapabilityExprMode = true;
+
til::MemRegionRef Arena;
til::Variable *SelfVar; // Variable to use for 'this'. May be null.
- til::SCFG *Scfg;
+ til::SCFG *Scfg;
StatementMap SMap; // Map from Stmt to TIL Variables
LVarIndexMap LVarIdxMap; // Indices of clang local vars.
std::vector<til::BasicBlock *> BlockMap; // Map from clang to til BBs.
std::vector<BlockInfo> BBInfo; // Extra information per BB.
// Indexed by clang BlockID.
- std::unique_ptr<SExprBuilder::CallingContext> CallCtx; // Root calling context
LVarDefinitionMap CurrentLVarMap;
- std::vector<til::Variable*> CurrentArguments;
- std::vector<til::Variable*> CurrentInstructions;
- std::vector<til::Variable*> IncompleteArgs;
+ std::vector<til::Phi*> CurrentArguments;
+ std::vector<til::SExpr*> CurrentInstructions;
+ std::vector<til::Phi*> IncompleteArgs;
til::BasicBlock *CurrentBB;
BlockInfo *CurrentBlockInfo;
};
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyLogical.h b/include/clang/Analysis/Analyses/ThreadSafetyLogical.h
index c4f4b21aab12..bc78021343a4 100644
--- a/include/clang/Analysis/Analyses/ThreadSafetyLogical.h
+++ b/include/clang/Analysis/Analyses/ThreadSafetyLogical.h
@@ -10,8 +10,8 @@
// that are used as part of fact-checking capability expressions.
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_THREAD_SAFETY_LOGICAL_H
-#define LLVM_CLANG_THREAD_SAFETY_LOGICAL_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYLOGICAL_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYLOGICAL_H
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
@@ -41,13 +41,13 @@ private:
};
class Terminal : public LExpr {
- til::SExprRef Expr;
+ til::SExpr *Expr;
public:
Terminal(til::SExpr *Expr) : LExpr(LExpr::Terminal), Expr(Expr) {}
- const til::SExpr *expr() const { return Expr.get(); }
- til::SExpr *expr() { return Expr.get(); }
+ const til::SExpr *expr() const { return Expr; }
+ til::SExpr *expr() { return Expr; }
static bool classof(const LExpr *E) { return E->kind() == LExpr::Terminal; }
};
@@ -104,5 +104,5 @@ bool LExpr::implies(const LExpr *RHS) const {
}
}
-#endif // LLVM_CLANG_THREAD_SAFETY_LOGICAL_H
+#endif
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyOps.def b/include/clang/Analysis/Analyses/ThreadSafetyOps.def
index 6ebc95dbe9a7..0d2458b0c893 100644
--- a/include/clang/Analysis/Analyses/ThreadSafetyOps.def
+++ b/include/clang/Analysis/Analyses/ThreadSafetyOps.def
@@ -44,8 +44,11 @@ TIL_OPCODE_DEF(Cast)
TIL_OPCODE_DEF(SCFG)
TIL_OPCODE_DEF(BasicBlock)
TIL_OPCODE_DEF(Phi)
+
+// Terminator instructions
TIL_OPCODE_DEF(Goto)
TIL_OPCODE_DEF(Branch)
+TIL_OPCODE_DEF(Return)
// pseudo-terms
TIL_OPCODE_DEF(Identifier)
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
index 8e4299ea70e8..2cd8c6d6d2d6 100644
--- a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
+++ b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
@@ -44,17 +44,16 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_THREAD_SAFETY_TIL_H
-#define LLVM_CLANG_THREAD_SAFETY_TIL_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H
// All clang include dependencies for this file must be put in
// ThreadSafetyUtil.h.
#include "ThreadSafetyUtil.h"
-
-#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <cstddef>
+#include <stdint.h>
#include <utility>
@@ -63,24 +62,27 @@ namespace threadSafety {
namespace til {
+/// Enum for the different distinct classes of SExpr
enum TIL_Opcode {
#define TIL_OPCODE_DEF(X) COP_##X,
#include "ThreadSafetyOps.def"
#undef TIL_OPCODE_DEF
};
+/// Opcode for unary arithmetic operations.
enum TIL_UnaryOpcode : unsigned char {
UOP_Minus, // -
UOP_BitNot, // ~
UOP_LogicNot // !
};
+/// Opcode for binary arithmetic operations.
enum TIL_BinaryOpcode : unsigned char {
+ BOP_Add, // +
+ BOP_Sub, // -
BOP_Mul, // *
BOP_Div, // /
BOP_Rem, // %
- BOP_Add, // +
- BOP_Sub, // -
BOP_Shl, // <<
BOP_Shr, // >>
BOP_BitAnd, // &
@@ -90,37 +92,42 @@ enum TIL_BinaryOpcode : unsigned char {
BOP_Neq, // !=
BOP_Lt, // <
BOP_Leq, // <=
- BOP_LogicAnd, // &&
- BOP_LogicOr // ||
+ BOP_LogicAnd, // && (no short-circuit)
+ BOP_LogicOr // || (no short-circuit)
};
+/// Opcode for cast operations.
enum TIL_CastOpcode : unsigned char {
CAST_none = 0,
CAST_extendNum, // extend precision of numeric type
CAST_truncNum, // truncate precision of numeric type
CAST_toFloat, // convert to floating point type
CAST_toInt, // convert to integer type
+ CAST_objToPtr // convert smart pointer to pointer (C++ only)
};
const TIL_Opcode COP_Min = COP_Future;
const TIL_Opcode COP_Max = COP_Branch;
const TIL_UnaryOpcode UOP_Min = UOP_Minus;
const TIL_UnaryOpcode UOP_Max = UOP_LogicNot;
-const TIL_BinaryOpcode BOP_Min = BOP_Mul;
+const TIL_BinaryOpcode BOP_Min = BOP_Add;
const TIL_BinaryOpcode BOP_Max = BOP_LogicOr;
const TIL_CastOpcode CAST_Min = CAST_none;
const TIL_CastOpcode CAST_Max = CAST_toInt;
+/// Return the name of a unary opcode.
StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op);
+
+/// Return the name of a binary opcode.
StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op);
-// ValueTypes are data types that can actually be held in registers.
-// All variables and expressions must have a vBNF_Nonealue type.
-// Pointer types are further subdivided into the various heap-allocated
-// types, such as functions, records, etc.
-// Structured types that are passed by value (e.g. complex numbers)
-// require special handling; they use BT_ValueRef, and size ST_0.
+/// ValueTypes are data types that can actually be held in registers.
+/// All variables and expressions must have a value type.
+/// Pointer types are further subdivided into the various heap-allocated
+/// types, such as functions, records, etc.
+/// Structured types that are passed by value (e.g. complex numbers)
+/// require special handling; they use BT_ValueRef, and size ST_0.
struct ValueType {
enum BaseType : unsigned char {
BT_Void = 0,
@@ -246,8 +253,10 @@ inline ValueType ValueType::getValueType<void*>() {
}
+class BasicBlock;
+
-// Base class for AST nodes in the typed intermediate language.
+/// Base class for AST nodes in the typed intermediate language.
class SExpr {
public:
TIL_Opcode opcode() const { return static_cast<TIL_Opcode>(Opcode); }
@@ -266,71 +275,47 @@ public:
// template <class C> typename C::CType compare(CType* E, C& Cmp) {
// compare all subexpressions, following the comparator interface
// }
-
void *operator new(size_t S, MemRegionRef &R) {
return ::operator new(S, R);
}
- // SExpr objects cannot be deleted.
+ /// SExpr objects cannot be deleted.
// This declaration is public to workaround a gcc bug that breaks building
// with REQUIRES_EH=1.
void operator delete(void *) LLVM_DELETED_FUNCTION;
+ /// Returns the instruction ID for this expression.
+ /// All basic block instructions have a unique ID (i.e. virtual register).
+ unsigned id() const { return SExprID; }
+
+ /// Returns the block, if this is an instruction in a basic block,
+ /// otherwise returns null.
+ BasicBlock* block() const { return Block; }
+
+ /// Set the basic block and instruction ID for this expression.
+ void setID(BasicBlock *B, unsigned id) { Block = B; SExprID = id; }
+
protected:
- SExpr(TIL_Opcode Op) : Opcode(Op), Reserved(0), Flags(0) {}
- SExpr(const SExpr &E) : Opcode(E.Opcode), Reserved(0), Flags(E.Flags) {}
+ SExpr(TIL_Opcode Op)
+ : Opcode(Op), Reserved(0), Flags(0), SExprID(0), Block(nullptr) {}
+ SExpr(const SExpr &E)
+ : Opcode(E.Opcode), Reserved(0), Flags(E.Flags), SExprID(0),
+ Block(nullptr) {}
const unsigned char Opcode;
unsigned char Reserved;
unsigned short Flags;
+ unsigned SExprID;
+ BasicBlock* Block;
private:
SExpr() LLVM_DELETED_FUNCTION;
- // SExpr objects must be created in an arena.
+ /// SExpr objects must be created in an arena.
void *operator new(size_t) LLVM_DELETED_FUNCTION;
};
-// Class for owning references to SExprs.
-// Includes attach/detach logic for counting variable references and lazy
-// rewriting strategies.
-class SExprRef {
-public:
- SExprRef() : Ptr(nullptr) { }
- SExprRef(std::nullptr_t P) : Ptr(nullptr) { }
- SExprRef(SExprRef &&R) : Ptr(R.Ptr) { R.Ptr = nullptr; }
-
- // Defined after Variable and Future, below.
- inline SExprRef(SExpr *P);
- inline ~SExprRef();
-
- SExpr *get() { return Ptr; }
- const SExpr *get() const { return Ptr; }
-
- SExpr *operator->() { return get(); }
- const SExpr *operator->() const { return get(); }
-
- SExpr &operator*() { return *Ptr; }
- const SExpr &operator*() const { return *Ptr; }
-
- bool operator==(const SExprRef &R) const { return Ptr == R.Ptr; }
- bool operator!=(const SExprRef &R) const { return !operator==(R); }
- bool operator==(const SExpr *P) const { return Ptr == P; }
- bool operator!=(const SExpr *P) const { return !operator==(P); }
- bool operator==(std::nullptr_t) const { return Ptr == nullptr; }
- bool operator!=(std::nullptr_t) const { return Ptr != nullptr; }
-
- inline void reset(SExpr *E);
-
-private:
- inline void attach();
- inline void detach();
-
- SExpr *Ptr;
-};
-
-
// Contains various helper functions for SExprs.
namespace ThreadSafetyTIL {
inline bool isTrivial(const SExpr *E) {
@@ -342,62 +327,64 @@ namespace ThreadSafetyTIL {
// Nodes which declare variables
class Function;
class SFunction;
-class BasicBlock;
class Let;
-// A named variable, e.g. "x".
-//
-// There are two distinct places in which a Variable can appear in the AST.
-// A variable declaration introduces a new variable, and can occur in 3 places:
-// Let-expressions: (Let (x = t) u)
-// Functions: (Function (x : t) u)
-// Self-applicable functions (SFunction (x) t)
-//
-// If a variable occurs in any other location, it is a reference to an existing
-// variable declaration -- e.g. 'x' in (x * y + z). To save space, we don't
-// allocate a separate AST node for variable references; a reference is just a
-// pointer to the original declaration.
+/// A named variable, e.g. "x".
+///
+/// There are two distinct places in which a Variable can appear in the AST.
+/// A variable declaration introduces a new variable, and can occur in 3 places:
+/// Let-expressions: (Let (x = t) u)
+/// Functions: (Function (x : t) u)
+/// Self-applicable functions (SFunction (x) t)
+///
+/// If a variable occurs in any other location, it is a reference to an existing
+/// variable declaration -- e.g. 'x' in (x * y + z). To save space, we don't
+/// allocate a separate AST node for variable references; a reference is just a
+/// pointer to the original declaration.
class Variable : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Variable; }
- // Let-variable, function parameter, or self-variable
enum VariableKind {
- VK_Let,
- VK_LetBB,
- VK_Fun,
- VK_SFun
+ VK_Let, ///< Let-variable
+ VK_Fun, ///< Function parameter
+ VK_SFun ///< SFunction (self) parameter
};
- // These are defined after SExprRef contructor, below
- inline Variable(SExpr *D, const clang::ValueDecl *Cvd = nullptr);
- inline Variable(StringRef s, SExpr *D = nullptr);
- inline Variable(const Variable &Vd, SExpr *D);
+ Variable(StringRef s, SExpr *D = nullptr)
+ : SExpr(COP_Variable), Name(s), Definition(D), Cvdecl(nullptr) {
+ Flags = VK_Let;
+ }
+ Variable(SExpr *D, const clang::ValueDecl *Cvd = nullptr)
+ : SExpr(COP_Variable), Name(Cvd ? Cvd->getName() : "_x"),
+ Definition(D), Cvdecl(Cvd) {
+ Flags = VK_Let;
+ }
+ Variable(const Variable &Vd, SExpr *D) // rewrite constructor
+ : SExpr(Vd), Name(Vd.Name), Definition(D), Cvdecl(Vd.Cvdecl) {
+ Flags = Vd.kind();
+ }
+ /// Return the kind of variable (let, function param, or self)
VariableKind kind() const { return static_cast<VariableKind>(Flags); }
- const StringRef name() const { return Name; }
- const clang::ValueDecl *clangDecl() const { return Cvdecl; }
-
- // Returns the definition (for let vars) or type (for parameter & self vars)
- SExpr *definition() { return Definition.get(); }
- const SExpr *definition() const { return Definition.get(); }
+ /// Return the name of the variable, if any.
+ StringRef name() const { return Name; }
- void attachVar() const { ++NumUses; }
- void detachVar() const { assert(NumUses > 0); --NumUses; }
+ /// Return the clang declaration for this variable, if any.
+ const clang::ValueDecl *clangDecl() const { return Cvdecl; }
- unsigned getID() const { return Id; }
- unsigned getBlockID() const { return BlockID; }
+ /// Return the definition of the variable.
+ /// For let-vars, this is the setting expression.
+ /// For function and self parameters, it is the type of the variable.
+ SExpr *definition() { return Definition; }
+ const SExpr *definition() const { return Definition; }
- void setName(StringRef S) { Name = S; }
- void setID(unsigned Bid, unsigned I) {
- BlockID = static_cast<unsigned short>(Bid);
- Id = static_cast<unsigned short>(I);
- }
- void setClangDecl(const clang::ValueDecl *VD) { Cvdecl = VD; }
- void setDefinition(SExpr *E);
+ void setName(StringRef S) { Name = S; }
void setKind(VariableKind K) { Flags = K; }
+ void setDefinition(SExpr *E) { Definition = E; }
+ void setClangDecl(const clang::ValueDecl *VD) { Cvdecl = VD; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -405,7 +392,8 @@ public:
return Vs.reduceVariableRef(this);
}
- template <class C> typename C::CType compare(Variable* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Variable* E, C& Cmp) const {
return Cmp.compareVariableRefs(this, E);
}
@@ -416,17 +404,13 @@ private:
friend class Let;
StringRef Name; // The name of the variable.
- SExprRef Definition; // The TIL type or definition
+ SExpr* Definition; // The TIL type or definition
const clang::ValueDecl *Cvdecl; // The clang declaration for this variable.
-
- unsigned short BlockID;
- unsigned short Id;
- mutable unsigned NumUses;
};
-// Placeholder for an expression that has not yet been created.
-// Used to implement lazy copy and rewriting strategies.
+/// Placeholder for an expression that has not yet been created.
+/// Used to implement lazy copy and rewriting strategies.
class Future : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Future; }
@@ -437,25 +421,17 @@ public:
FS_done
};
- Future() :
- SExpr(COP_Future), Status(FS_pending), Result(nullptr), Location(nullptr)
- {}
+ Future() : SExpr(COP_Future), Status(FS_pending), Result(nullptr) {}
+
private:
virtual ~Future() LLVM_DELETED_FUNCTION;
-public:
-
- // Registers the location in the AST where this future is stored.
- // Forcing the future will automatically update the AST.
- static inline void registerLocation(SExprRef *Member) {
- if (Future *F = dyn_cast_or_null<Future>(Member->get()))
- F->Location = Member;
- }
+public:
// A lazy rewriting strategy should subclass Future and override this method.
- virtual SExpr *create() { return nullptr; }
+ virtual SExpr *compute() { return nullptr; }
// Return the result of this future if it exists, otherwise return null.
- SExpr *maybeGetResult() {
+ SExpr *maybeGetResult() const {
return Result;
}
@@ -463,8 +439,7 @@ public:
SExpr *result() {
switch (Status) {
case FS_pending:
- force();
- return Result;
+ return force();
case FS_evaluating:
return nullptr; // infinite loop; illegal recursion.
case FS_done:
@@ -478,88 +453,22 @@ public:
return Vs.traverse(Result, Ctx);
}
- template <class C> typename C::CType compare(Future* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Future* E, C& Cmp) const {
if (!Result || !E->Result)
return Cmp.comparePointers(this, E);
return Cmp.compare(Result, E->Result);
}
private:
- // Force the future.
- inline void force();
+ SExpr* force();
FutureStatus Status;
SExpr *Result;
- SExprRef *Location;
};
-inline void SExprRef::attach() {
- if (!Ptr)
- return;
-
- TIL_Opcode Op = Ptr->opcode();
- if (Op == COP_Variable) {
- cast<Variable>(Ptr)->attachVar();
- } else if (Op == COP_Future) {
- cast<Future>(Ptr)->registerLocation(this);
- }
-}
-
-inline void SExprRef::detach() {
- if (Ptr && Ptr->opcode() == COP_Variable) {
- cast<Variable>(Ptr)->detachVar();
- }
-}
-
-inline SExprRef::SExprRef(SExpr *P) : Ptr(P) {
- attach();
-}
-
-inline SExprRef::~SExprRef() {
- detach();
-}
-
-inline void SExprRef::reset(SExpr *P) {
- detach();
- Ptr = P;
- attach();
-}
-
-
-inline Variable::Variable(StringRef s, SExpr *D)
- : SExpr(COP_Variable), Name(s), Definition(D), Cvdecl(nullptr),
- BlockID(0), Id(0), NumUses(0) {
- Flags = VK_Let;
-}
-
-inline Variable::Variable(SExpr *D, const clang::ValueDecl *Cvd)
- : SExpr(COP_Variable), Name(Cvd ? Cvd->getName() : "_x"),
- Definition(D), Cvdecl(Cvd), BlockID(0), Id(0), NumUses(0) {
- Flags = VK_Let;
-}
-
-inline Variable::Variable(const Variable &Vd, SExpr *D) // rewrite constructor
- : SExpr(Vd), Name(Vd.Name), Definition(D), Cvdecl(Vd.Cvdecl),
- BlockID(0), Id(0), NumUses(0) {
- Flags = Vd.kind();
-}
-
-inline void Variable::setDefinition(SExpr *E) {
- Definition.reset(E);
-}
-
-void Future::force() {
- Status = FS_evaluating;
- SExpr *R = create();
- Result = R;
- if (Location)
- Location->reset(R);
- Status = FS_done;
-}
-
-
-// Placeholder for C++ expressions that cannot be represented in the TIL.
+/// Placeholder for expressions that cannot be represented in the TIL.
class Undefined : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; }
@@ -572,8 +481,9 @@ public:
return Vs.reduceUndefined(*this);
}
- template <class C> typename C::CType compare(Undefined* E, C& Cmp) {
- return Cmp.comparePointers(Cstmt, E->Cstmt);
+ template <class C>
+ typename C::CType compare(const Undefined* E, C& Cmp) const {
+ return Cmp.trueResult();
}
private:
@@ -581,7 +491,7 @@ private:
};
-// Placeholder for a wildcard that matches any other expression.
+/// Placeholder for a wildcard that matches any other expression.
class Wildcard : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Wildcard; }
@@ -593,7 +503,8 @@ public:
return Vs.reduceWildcard(*this);
}
- template <class C> typename C::CType compare(Wildcard* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Wildcard* E, C& Cmp) const {
return Cmp.trueResult();
}
};
@@ -626,9 +537,10 @@ public:
template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx);
- template <class C> typename C::CType compare(Literal* E, C& Cmp) {
- // TODO -- use value, not pointer equality
- return Cmp.comparePointers(Cexpr, E->Cexpr);
+ template <class C>
+ typename C::CType compare(const Literal* E, C& Cmp) const {
+ // TODO: defer actual comparison to LiteralT
+ return Cmp.trueResult();
}
private:
@@ -710,8 +622,8 @@ typename V::R_SExpr Literal::traverse(V &Vs, typename V::R_Ctx Ctx) {
}
-// Literal pointer to an object allocated in memory.
-// At compile time, pointer literals are represented by symbolic names.
+/// A Literal pointer to an object allocated in memory.
+/// At compile time, pointer literals are represented by symbolic names.
class LiteralPtr : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_LiteralPtr; }
@@ -727,7 +639,8 @@ public:
return Vs.reduceLiteralPtr(*this);
}
- template <class C> typename C::CType compare(LiteralPtr* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const LiteralPtr* E, C& Cmp) const {
return Cmp.comparePointers(Cvdecl, E->Cvdecl);
}
@@ -736,9 +649,9 @@ private:
};
-// A function -- a.k.a. lambda abstraction.
-// Functions with multiple arguments are created by currying,
-// e.g. (function (x: Int) (function (y: Int) (add x y)))
+/// A function -- a.k.a. lambda abstraction.
+/// Functions with multiple arguments are created by currying,
+/// e.g. (Function (x: Int) (Function (y: Int) (Code { return x + y })))
class Function : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Function; }
@@ -755,8 +668,8 @@ public:
Variable *variableDecl() { return VarDecl; }
const Variable *variableDecl() const { return VarDecl; }
- SExpr *body() { return Body.get(); }
- const SExpr *body() const { return Body.get(); }
+ SExpr *body() { return Body; }
+ const SExpr *body() const { return Body; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -769,7 +682,8 @@ public:
return Vs.reduceFunction(*this, Nvd, E1);
}
- template <class C> typename C::CType compare(Function* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Function* E, C& Cmp) const {
typename C::CType Ct =
Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
if (Cmp.notTrue(Ct))
@@ -782,13 +696,13 @@ public:
private:
Variable *VarDecl;
- SExprRef Body;
+ SExpr* Body;
};
-// A self-applicable function.
-// A self-applicable function can be applied to itself. It's useful for
-// implementing objects and late binding
+/// A self-applicable function.
+/// A self-applicable function can be applied to itself. It's useful for
+/// implementing objects and late binding.
class SFunction : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_SFunction; }
@@ -797,20 +711,20 @@ public:
: SExpr(COP_SFunction), VarDecl(Vd), Body(B) {
assert(Vd->Definition == nullptr);
Vd->setKind(Variable::VK_SFun);
- Vd->Definition.reset(this);
+ Vd->Definition = this;
}
SFunction(const SFunction &F, Variable *Vd, SExpr *B) // rewrite constructor
: SExpr(F), VarDecl(Vd), Body(B) {
assert(Vd->Definition == nullptr);
Vd->setKind(Variable::VK_SFun);
- Vd->Definition.reset(this);
+ Vd->Definition = this;
}
Variable *variableDecl() { return VarDecl; }
const Variable *variableDecl() const { return VarDecl; }
- SExpr *body() { return Body.get(); }
- const SExpr *body() const { return Body.get(); }
+ SExpr *body() { return Body; }
+ const SExpr *body() const { return Body; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -824,7 +738,8 @@ public:
return Vs.reduceSFunction(*this, Nvd, E1);
}
- template <class C> typename C::CType compare(SFunction* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const SFunction* E, C& Cmp) const {
Cmp.enterScope(variableDecl(), E->variableDecl());
typename C::CType Ct = Cmp.compare(body(), E->body());
Cmp.leaveScope();
@@ -833,11 +748,11 @@ public:
private:
Variable *VarDecl;
- SExprRef Body;
+ SExpr* Body;
};
-// A block of code -- e.g. the body of a function.
+/// A block of code -- e.g. the body of a function.
class Code : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Code; }
@@ -846,11 +761,11 @@ public:
Code(const Code &C, SExpr *T, SExpr *B) // rewrite constructor
: SExpr(C), ReturnType(T), Body(B) {}
- SExpr *returnType() { return ReturnType.get(); }
- const SExpr *returnType() const { return ReturnType.get(); }
+ SExpr *returnType() { return ReturnType; }
+ const SExpr *returnType() const { return ReturnType; }
- SExpr *body() { return Body.get(); }
- const SExpr *body() const { return Body.get(); }
+ SExpr *body() { return Body; }
+ const SExpr *body() const { return Body; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -859,7 +774,8 @@ public:
return Vs.reduceCode(*this, Nt, Nb);
}
- template <class C> typename C::CType compare(Code* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Code* E, C& Cmp) const {
typename C::CType Ct = Cmp.compare(returnType(), E->returnType());
if (Cmp.notTrue(Ct))
return Ct;
@@ -867,12 +783,12 @@ public:
}
private:
- SExprRef ReturnType;
- SExprRef Body;
+ SExpr* ReturnType;
+ SExpr* Body;
};
-// A typed, writable location in memory
+/// A typed, writable location in memory
class Field : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Field; }
@@ -881,11 +797,11 @@ public:
Field(const Field &C, SExpr *R, SExpr *B) // rewrite constructor
: SExpr(C), Range(R), Body(B) {}
- SExpr *range() { return Range.get(); }
- const SExpr *range() const { return Range.get(); }
+ SExpr *range() { return Range; }
+ const SExpr *range() const { return Range; }
- SExpr *body() { return Body.get(); }
- const SExpr *body() const { return Body.get(); }
+ SExpr *body() { return Body; }
+ const SExpr *body() const { return Body; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -894,7 +810,8 @@ public:
return Vs.reduceField(*this, Nr, Nb);
}
- template <class C> typename C::CType compare(Field* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Field* E, C& Cmp) const {
typename C::CType Ct = Cmp.compare(range(), E->range());
if (Cmp.notTrue(Ct))
return Ct;
@@ -902,12 +819,16 @@ public:
}
private:
- SExprRef Range;
- SExprRef Body;
+ SExpr* Range;
+ SExpr* Body;
};
-// Apply an argument to a function
+/// Apply an argument to a function.
+/// Note that this does not actually call the function. Functions are curried,
+/// so this returns a closure in which the first parameter has been applied.
+/// Once all parameters have been applied, Call can be used to invoke the
+/// function.
class Apply : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Apply; }
@@ -917,11 +838,11 @@ public:
: SExpr(A), Fun(F), Arg(Ar)
{}
- SExpr *fun() { return Fun.get(); }
- const SExpr *fun() const { return Fun.get(); }
+ SExpr *fun() { return Fun; }
+ const SExpr *fun() const { return Fun; }
- SExpr *arg() { return Arg.get(); }
- const SExpr *arg() const { return Arg.get(); }
+ SExpr *arg() { return Arg; }
+ const SExpr *arg() const { return Arg; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -930,7 +851,8 @@ public:
return Vs.reduceApply(*this, Nf, Na);
}
- template <class C> typename C::CType compare(Apply* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Apply* E, C& Cmp) const {
typename C::CType Ct = Cmp.compare(fun(), E->fun());
if (Cmp.notTrue(Ct))
return Ct;
@@ -938,12 +860,12 @@ public:
}
private:
- SExprRef Fun;
- SExprRef Arg;
+ SExpr* Fun;
+ SExpr* Arg;
};
-// Apply a self-argument to a self-applicable function
+/// Apply a self-argument to a self-applicable function.
class SApply : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_SApply; }
@@ -952,23 +874,24 @@ public:
SApply(SApply &A, SExpr *Sf, SExpr *Ar = nullptr) // rewrite constructor
: SExpr(A), Sfun(Sf), Arg(Ar) {}
- SExpr *sfun() { return Sfun.get(); }
- const SExpr *sfun() const { return Sfun.get(); }
+ SExpr *sfun() { return Sfun; }
+ const SExpr *sfun() const { return Sfun; }
- SExpr *arg() { return Arg.get() ? Arg.get() : Sfun.get(); }
- const SExpr *arg() const { return Arg.get() ? Arg.get() : Sfun.get(); }
+ SExpr *arg() { return Arg ? Arg : Sfun; }
+ const SExpr *arg() const { return Arg ? Arg : Sfun; }
- bool isDelegation() const { return Arg == nullptr; }
+ bool isDelegation() const { return Arg != nullptr; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
auto Nf = Vs.traverse(Sfun, Vs.subExprCtx(Ctx));
- typename V::R_SExpr Na = Arg.get() ? Vs.traverse(Arg, Vs.subExprCtx(Ctx))
+ typename V::R_SExpr Na = Arg ? Vs.traverse(Arg, Vs.subExprCtx(Ctx))
: nullptr;
return Vs.reduceSApply(*this, Nf, Na);
}
- template <class C> typename C::CType compare(SApply* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const SApply* E, C& Cmp) const {
typename C::CType Ct = Cmp.compare(sfun(), E->sfun());
if (Cmp.notTrue(Ct) || (!arg() && !E->arg()))
return Ct;
@@ -976,12 +899,12 @@ public:
}
private:
- SExprRef Sfun;
- SExprRef Arg;
+ SExpr* Sfun;
+ SExpr* Arg;
};
-// Project a named slot from a C++ struct or class.
+/// Project a named slot from a C++ struct or class.
class Project : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Project; }
@@ -989,17 +912,23 @@ public:
Project(SExpr *R, StringRef SName)
: SExpr(COP_Project), Rec(R), SlotName(SName), Cvdecl(nullptr)
{ }
- Project(SExpr *R, clang::ValueDecl *Cvd)
+ Project(SExpr *R, const clang::ValueDecl *Cvd)
: SExpr(COP_Project), Rec(R), SlotName(Cvd->getName()), Cvdecl(Cvd)
{ }
Project(const Project &P, SExpr *R)
: SExpr(P), Rec(R), SlotName(P.SlotName), Cvdecl(P.Cvdecl)
{ }
- SExpr *record() { return Rec.get(); }
- const SExpr *record() const { return Rec.get(); }
+ SExpr *record() { return Rec; }
+ const SExpr *record() const { return Rec; }
+
+ const clang::ValueDecl *clangDecl() const { return Cvdecl; }
- const clang::ValueDecl *clangValueDecl() const { return Cvdecl; }
+ bool isArrow() const { return (Flags & 0x01) != 0; }
+ void setArrow(bool b) {
+ if (b) Flags |= 0x01;
+ else Flags &= 0xFFFE;
+ }
StringRef slotName() const {
if (Cvdecl)
@@ -1014,7 +943,8 @@ public:
return Vs.reduceProject(*this, Nr);
}
- template <class C> typename C::CType compare(Project* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Project* E, C& Cmp) const {
typename C::CType Ct = Cmp.compare(record(), E->record());
if (Cmp.notTrue(Ct))
return Ct;
@@ -1022,13 +952,13 @@ public:
}
private:
- SExprRef Rec;
+ SExpr* Rec;
StringRef SlotName;
- clang::ValueDecl *Cvdecl;
+ const clang::ValueDecl *Cvdecl;
};
-// Call a function (after all arguments have been applied).
+/// Call a function (after all arguments have been applied).
class Call : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
@@ -1037,8 +967,8 @@ public:
: SExpr(COP_Call), Target(T), Cexpr(Ce) {}
Call(const Call &C, SExpr *T) : SExpr(C), Target(T), Cexpr(C.Cexpr) {}
- SExpr *target() { return Target.get(); }
- const SExpr *target() const { return Target.get(); }
+ SExpr *target() { return Target; }
+ const SExpr *target() const { return Target; }
const clang::CallExpr *clangCallExpr() const { return Cexpr; }
@@ -1048,17 +978,18 @@ public:
return Vs.reduceCall(*this, Nt);
}
- template <class C> typename C::CType compare(Call* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Call* E, C& Cmp) const {
return Cmp.compare(target(), E->target());
}
private:
- SExprRef Target;
+ SExpr* Target;
const clang::CallExpr *Cexpr;
};
-// Allocate memory for a new value on the heap or stack.
+/// Allocate memory for a new value on the heap or stack.
class Alloc : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
@@ -1073,8 +1004,8 @@ public:
AllocKind kind() const { return static_cast<AllocKind>(Flags); }
- SExpr *dataType() { return Dtype.get(); }
- const SExpr *dataType() const { return Dtype.get(); }
+ SExpr *dataType() { return Dtype; }
+ const SExpr *dataType() const { return Dtype; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -1082,7 +1013,8 @@ public:
return Vs.reduceAlloc(*this, Nd);
}
- template <class C> typename C::CType compare(Alloc* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Alloc* E, C& Cmp) const {
typename C::CType Ct = Cmp.compareIntegers(kind(), E->kind());
if (Cmp.notTrue(Ct))
return Ct;
@@ -1090,11 +1022,11 @@ public:
}
private:
- SExprRef Dtype;
+ SExpr* Dtype;
};
-// Load a value from memory.
+/// Load a value from memory.
class Load : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Load; }
@@ -1102,8 +1034,8 @@ public:
Load(SExpr *P) : SExpr(COP_Load), Ptr(P) {}
Load(const Load &L, SExpr *P) : SExpr(L), Ptr(P) {}
- SExpr *pointer() { return Ptr.get(); }
- const SExpr *pointer() const { return Ptr.get(); }
+ SExpr *pointer() { return Ptr; }
+ const SExpr *pointer() const { return Ptr; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -1111,17 +1043,18 @@ public:
return Vs.reduceLoad(*this, Np);
}
- template <class C> typename C::CType compare(Load* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Load* E, C& Cmp) const {
return Cmp.compare(pointer(), E->pointer());
}
private:
- SExprRef Ptr;
+ SExpr* Ptr;
};
-// Store a value to memory.
-// Source is a pointer, destination is the value to store.
+/// Store a value to memory.
+/// The destination is a pointer to a field, the source is the value to store.
class Store : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Store; }
@@ -1129,11 +1062,11 @@ public:
Store(SExpr *P, SExpr *V) : SExpr(COP_Store), Dest(P), Source(V) {}
Store(const Store &S, SExpr *P, SExpr *V) : SExpr(S), Dest(P), Source(V) {}
- SExpr *destination() { return Dest.get(); } // Address to store to
- const SExpr *destination() const { return Dest.get(); }
+ SExpr *destination() { return Dest; } // Address to store to
+ const SExpr *destination() const { return Dest; }
- SExpr *source() { return Source.get(); } // Value to store
- const SExpr *source() const { return Source.get(); }
+ SExpr *source() { return Source; } // Value to store
+ const SExpr *source() const { return Source; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -1142,7 +1075,8 @@ public:
return Vs.reduceStore(*this, Np, Nv);
}
- template <class C> typename C::CType compare(Store* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Store* E, C& Cmp) const {
typename C::CType Ct = Cmp.compare(destination(), E->destination());
if (Cmp.notTrue(Ct))
return Ct;
@@ -1150,13 +1084,13 @@ public:
}
private:
- SExprRef Dest;
- SExprRef Source;
+ SExpr* Dest;
+ SExpr* Source;
};
-// If p is a reference to an array, then first(p) is a reference to the first
-// element. The usual array notation p[i] becomes first(p + i).
+/// If p is a reference to an array, then p[i] is a reference to the i'th
+/// element of the array.
class ArrayIndex : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayIndex; }
@@ -1165,11 +1099,11 @@ public:
ArrayIndex(const ArrayIndex &E, SExpr *A, SExpr *N)
: SExpr(E), Array(A), Index(N) {}
- SExpr *array() { return Array.get(); }
- const SExpr *array() const { return Array.get(); }
+ SExpr *array() { return Array; }
+ const SExpr *array() const { return Array; }
- SExpr *index() { return Index.get(); }
- const SExpr *index() const { return Index.get(); }
+ SExpr *index() { return Index; }
+ const SExpr *index() const { return Index; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -1178,7 +1112,8 @@ public:
return Vs.reduceArrayIndex(*this, Na, Ni);
}
- template <class C> typename C::CType compare(ArrayIndex* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const ArrayIndex* E, C& Cmp) const {
typename C::CType Ct = Cmp.compare(array(), E->array());
if (Cmp.notTrue(Ct))
return Ct;
@@ -1186,14 +1121,14 @@ public:
}
private:
- SExprRef Array;
- SExprRef Index;
+ SExpr* Array;
+ SExpr* Index;
};
-// Pointer arithmetic, restricted to arrays only.
-// If p is a reference to an array, then p + n, where n is an integer, is
-// a reference to a subarray.
+/// Pointer arithmetic, restricted to arrays only.
+/// If p is a reference to an array, then p + n, where n is an integer, is
+/// a reference to a subarray.
class ArrayAdd : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; }
@@ -1202,11 +1137,11 @@ public:
ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N)
: SExpr(E), Array(A), Index(N) {}
- SExpr *array() { return Array.get(); }
- const SExpr *array() const { return Array.get(); }
+ SExpr *array() { return Array; }
+ const SExpr *array() const { return Array; }
- SExpr *index() { return Index.get(); }
- const SExpr *index() const { return Index.get(); }
+ SExpr *index() { return Index; }
+ const SExpr *index() const { return Index; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -1215,7 +1150,8 @@ public:
return Vs.reduceArrayAdd(*this, Na, Ni);
}
- template <class C> typename C::CType compare(ArrayAdd* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const ArrayAdd* E, C& Cmp) const {
typename C::CType Ct = Cmp.compare(array(), E->array());
if (Cmp.notTrue(Ct))
return Ct;
@@ -1223,12 +1159,13 @@ public:
}
private:
- SExprRef Array;
- SExprRef Index;
+ SExpr* Array;
+ SExpr* Index;
};
-// Simple unary operation -- e.g. !, ~, etc.
+/// Simple arithmetic unary operations, e.g. negate and not.
+/// These operations have no side-effects.
class UnaryOp : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; }
@@ -1242,8 +1179,8 @@ public:
return static_cast<TIL_UnaryOpcode>(Flags);
}
- SExpr *expr() { return Expr0.get(); }
- const SExpr *expr() const { return Expr0.get(); }
+ SExpr *expr() { return Expr0; }
+ const SExpr *expr() const { return Expr0; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -1251,7 +1188,8 @@ public:
return Vs.reduceUnaryOp(*this, Ne);
}
- template <class C> typename C::CType compare(UnaryOp* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const UnaryOp* E, C& Cmp) const {
typename C::CType Ct =
Cmp.compareIntegers(unaryOpcode(), E->unaryOpcode());
if (Cmp.notTrue(Ct))
@@ -1260,11 +1198,12 @@ public:
}
private:
- SExprRef Expr0;
+ SExpr* Expr0;
};
-// Simple binary operation -- e.g. +, -, etc.
+/// Simple arithmetic binary operations, e.g. +, -, etc.
+/// These operations have no side effects.
class BinaryOp : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; }
@@ -1282,11 +1221,11 @@ public:
return static_cast<TIL_BinaryOpcode>(Flags);
}
- SExpr *expr0() { return Expr0.get(); }
- const SExpr *expr0() const { return Expr0.get(); }
+ SExpr *expr0() { return Expr0; }
+ const SExpr *expr0() const { return Expr0; }
- SExpr *expr1() { return Expr1.get(); }
- const SExpr *expr1() const { return Expr1.get(); }
+ SExpr *expr1() { return Expr1; }
+ const SExpr *expr1() const { return Expr1; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -1295,7 +1234,8 @@ public:
return Vs.reduceBinaryOp(*this, Ne0, Ne1);
}
- template <class C> typename C::CType compare(BinaryOp* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const BinaryOp* E, C& Cmp) const {
typename C::CType Ct =
Cmp.compareIntegers(binaryOpcode(), E->binaryOpcode());
if (Cmp.notTrue(Ct))
@@ -1307,12 +1247,14 @@ public:
}
private:
- SExprRef Expr0;
- SExprRef Expr1;
+ SExpr* Expr0;
+ SExpr* Expr1;
};
-// Cast expression
+/// Cast expressions.
+/// Cast expressions are essentially unary operations, but we treat them
+/// as a distinct AST node because they only change the type of the result.
class Cast : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; }
@@ -1324,8 +1266,8 @@ public:
return static_cast<TIL_CastOpcode>(Flags);
}
- SExpr *expr() { return Expr0.get(); }
- const SExpr *expr() const { return Expr0.get(); }
+ SExpr *expr() { return Expr0; }
+ const SExpr *expr() const { return Expr0; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -1333,7 +1275,8 @@ public:
return Vs.reduceCast(*this, Ne);
}
- template <class C> typename C::CType compare(Cast* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Cast* E, C& Cmp) const {
typename C::CType Ct =
Cmp.compareIntegers(castOpcode(), E->castOpcode());
if (Cmp.notTrue(Ct))
@@ -1342,16 +1285,18 @@ public:
}
private:
- SExprRef Expr0;
+ SExpr* Expr0;
};
class SCFG;
+/// Phi Node, for code in SSA form.
+/// Each Phi node has an array of possible values that it can take,
+/// depending on where control flow comes from.
class Phi : public SExpr {
public:
- // TODO: change to SExprRef
typedef SimpleArray<SExpr *> ValArray;
// In minimal SSA form, all Phi nodes are MultiVal.
@@ -1365,9 +1310,12 @@ public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; }
- Phi() : SExpr(COP_Phi) {}
- Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {}
- Phi(const Phi &P, ValArray &&Vs) : SExpr(P), Values(std::move(Vs)) {}
+ Phi()
+ : SExpr(COP_Phi), Cvdecl(nullptr) {}
+ Phi(MemRegionRef A, unsigned Nvals)
+ : SExpr(COP_Phi), Values(A, Nvals), Cvdecl(nullptr) {}
+ Phi(const Phi &P, ValArray &&Vs)
+ : SExpr(P), Values(std::move(Vs)), Cvdecl(nullptr) {}
const ValArray &values() const { return Values; }
ValArray &values() { return Values; }
@@ -1375,6 +1323,12 @@ public:
Status status() const { return static_cast<Status>(Flags); }
void setStatus(Status s) { Flags = s; }
+ /// Return the clang declaration of the variable for this Phi node, if any.
+ const clang::ValueDecl *clangDecl() const { return Cvdecl; }
+
+ /// Set the clang variable associated with this Phi node.
+ void setClangDecl(const clang::ValueDecl *Cvd) { Cvdecl = Cvd; }
+
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
typename V::template Container<typename V::R_SExpr>
@@ -1386,72 +1340,268 @@ public:
return Vs.reducePhi(*this, Nvs);
}
- template <class C> typename C::CType compare(Phi *E, C &Cmp) {
+ template <class C>
+ typename C::CType compare(const Phi *E, C &Cmp) const {
// TODO: implement CFG comparisons
return Cmp.comparePointers(this, E);
}
private:
ValArray Values;
+ const clang::ValueDecl* Cvdecl;
+};
+
+
+/// Base class for basic block terminators: Branch, Goto, and Return.
+class Terminator : public SExpr {
+public:
+ static bool classof(const SExpr *E) {
+ return E->opcode() >= COP_Goto && E->opcode() <= COP_Return;
+ }
+
+protected:
+ Terminator(TIL_Opcode Op) : SExpr(Op) {}
+ Terminator(const SExpr &E) : SExpr(E) {}
+
+public:
+ /// Return the list of basic blocks that this terminator can branch to.
+ ArrayRef<BasicBlock*> successors();
+
+ ArrayRef<BasicBlock*> successors() const {
+ return const_cast<Terminator*>(this)->successors();
+ }
};
-// A basic block is part of an SCFG, and can be treated as a function in
-// continuation passing style. It consists of a sequence of phi nodes, which
-// are "arguments" to the function, followed by a sequence of instructions.
-// Both arguments and instructions define new variables. It ends with a
-// branch or goto to another basic block in the same SCFG.
+/// Jump to another basic block.
+/// A goto instruction is essentially a tail-recursive call into another
+/// block. In addition to the block pointer, it specifies an index into the
+/// phi nodes of that block. The index can be used to retrieve the "arguments"
+/// of the call.
+class Goto : public Terminator {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; }
+
+ Goto(BasicBlock *B, unsigned I)
+ : Terminator(COP_Goto), TargetBlock(B), Index(I) {}
+ Goto(const Goto &G, BasicBlock *B, unsigned I)
+ : Terminator(COP_Goto), TargetBlock(B), Index(I) {}
+
+ const BasicBlock *targetBlock() const { return TargetBlock; }
+ BasicBlock *targetBlock() { return TargetBlock; }
+
+ /// Returns the index into the
+ unsigned index() const { return Index; }
+
+ /// Return the list of basic blocks that this terminator can branch to.
+ ArrayRef<BasicBlock*> successors() {
+ return ArrayRef<BasicBlock*>(&TargetBlock, 1);
+ }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ BasicBlock *Ntb = Vs.reduceBasicBlockRef(TargetBlock);
+ return Vs.reduceGoto(*this, Ntb);
+ }
+
+ template <class C>
+ typename C::CType compare(const Goto *E, C &Cmp) const {
+ // TODO: implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ BasicBlock *TargetBlock;
+ unsigned Index;
+};
+
+
+/// A conditional branch to two other blocks.
+/// Note that unlike Goto, Branch does not have an index. The target blocks
+/// must be child-blocks, and cannot have Phi nodes.
+class Branch : public Terminator {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; }
+
+ Branch(SExpr *C, BasicBlock *T, BasicBlock *E)
+ : Terminator(COP_Branch), Condition(C) {
+ Branches[0] = T;
+ Branches[1] = E;
+ }
+ Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E)
+ : Terminator(Br), Condition(C) {
+ Branches[0] = T;
+ Branches[1] = E;
+ }
+
+ const SExpr *condition() const { return Condition; }
+ SExpr *condition() { return Condition; }
+
+ const BasicBlock *thenBlock() const { return Branches[0]; }
+ BasicBlock *thenBlock() { return Branches[0]; }
+
+ const BasicBlock *elseBlock() const { return Branches[1]; }
+ BasicBlock *elseBlock() { return Branches[1]; }
+
+ /// Return the list of basic blocks that this terminator can branch to.
+ ArrayRef<BasicBlock*> successors() {
+ return ArrayRef<BasicBlock*>(Branches, 2);
+ }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx));
+ BasicBlock *Ntb = Vs.reduceBasicBlockRef(Branches[0]);
+ BasicBlock *Nte = Vs.reduceBasicBlockRef(Branches[1]);
+ return Vs.reduceBranch(*this, Nc, Ntb, Nte);
+ }
+
+ template <class C>
+ typename C::CType compare(const Branch *E, C &Cmp) const {
+ // TODO: implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ SExpr* Condition;
+ BasicBlock *Branches[2];
+};
+
+
+/// Return from the enclosing function, passing the return value to the caller.
+/// Only the exit block should end with a return statement.
+class Return : public Terminator {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Return; }
+
+ Return(SExpr* Rval) : Terminator(COP_Return), Retval(Rval) {}
+ Return(const Return &R, SExpr* Rval) : Terminator(R), Retval(Rval) {}
+
+ /// Return an empty list.
+ ArrayRef<BasicBlock*> successors() {
+ return ArrayRef<BasicBlock*>();
+ }
+
+ SExpr *returnValue() { return Retval; }
+ const SExpr *returnValue() const { return Retval; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Ne = Vs.traverse(Retval, Vs.subExprCtx(Ctx));
+ return Vs.reduceReturn(*this, Ne);
+ }
+
+ template <class C>
+ typename C::CType compare(const Return *E, C &Cmp) const {
+ return Cmp.compare(Retval, E->Retval);
+ }
+
+private:
+ SExpr* Retval;
+};
+
+
+inline ArrayRef<BasicBlock*> Terminator::successors() {
+ switch (opcode()) {
+ case COP_Goto: return cast<Goto>(this)->successors();
+ case COP_Branch: return cast<Branch>(this)->successors();
+ case COP_Return: return cast<Return>(this)->successors();
+ default:
+ return ArrayRef<BasicBlock*>();
+ }
+}
+
+
+/// A basic block is part of an SCFG. It can be treated as a function in
+/// continuation passing style. A block consists of a sequence of phi nodes,
+/// which are "arguments" to the function, followed by a sequence of
+/// instructions. It ends with a Terminator, which is a Branch or Goto to
+/// another basic block in the same SCFG.
class BasicBlock : public SExpr {
public:
- typedef SimpleArray<Variable*> VarArray;
+ typedef SimpleArray<SExpr*> InstrArray;
typedef SimpleArray<BasicBlock*> BlockArray;
+ // TopologyNodes are used to overlay tree structures on top of the CFG,
+ // such as dominator and postdominator trees. Each block is assigned an
+ // ID in the tree according to a depth-first search. Tree traversals are
+ // always up, towards the parents.
+ struct TopologyNode {
+ TopologyNode() : NodeID(0), SizeOfSubTree(0), Parent(nullptr) {}
+
+ bool isParentOf(const TopologyNode& OtherNode) {
+ return OtherNode.NodeID > NodeID &&
+ OtherNode.NodeID < NodeID + SizeOfSubTree;
+ }
+
+ bool isParentOfOrEqual(const TopologyNode& OtherNode) {
+ return OtherNode.NodeID >= NodeID &&
+ OtherNode.NodeID < NodeID + SizeOfSubTree;
+ }
+
+ int NodeID;
+ int SizeOfSubTree; // Includes this node, so must be > 1.
+ BasicBlock *Parent; // Pointer to parent.
+ };
+
static bool classof(const SExpr *E) { return E->opcode() == COP_BasicBlock; }
- explicit BasicBlock(MemRegionRef A, BasicBlock* P = nullptr)
+ explicit BasicBlock(MemRegionRef A)
: SExpr(COP_BasicBlock), Arena(A), CFGPtr(nullptr), BlockID(0),
- Parent(P), Terminator(nullptr)
- { }
- BasicBlock(BasicBlock &B, VarArray &&As, VarArray &&Is, SExpr *T)
- : SExpr(COP_BasicBlock), Arena(B.Arena), CFGPtr(nullptr), BlockID(0),
- Parent(nullptr), Args(std::move(As)), Instrs(std::move(Is)),
- Terminator(T)
- { }
+ Visited(0), TermInstr(nullptr) {}
+ BasicBlock(BasicBlock &B, MemRegionRef A, InstrArray &&As, InstrArray &&Is,
+ Terminator *T)
+ : SExpr(COP_BasicBlock), Arena(A), CFGPtr(nullptr), BlockID(0),Visited(0),
+ Args(std::move(As)), Instrs(std::move(Is)), TermInstr(T) {}
+
+ /// Returns the block ID. Every block has a unique ID in the CFG.
+ int blockID() const { return BlockID; }
- unsigned blockID() const { return BlockID; }
- unsigned numPredecessors() const { return Predecessors.size(); }
+ /// Returns the number of predecessors.
+ size_t numPredecessors() const { return Predecessors.size(); }
+ size_t numSuccessors() const { return successors().size(); }
const SCFG* cfg() const { return CFGPtr; }
SCFG* cfg() { return CFGPtr; }
- const BasicBlock *parent() const { return Parent; }
- BasicBlock *parent() { return Parent; }
+ const BasicBlock *parent() const { return DominatorNode.Parent; }
+ BasicBlock *parent() { return DominatorNode.Parent; }
- const VarArray &arguments() const { return Args; }
- VarArray &arguments() { return Args; }
+ const InstrArray &arguments() const { return Args; }
+ InstrArray &arguments() { return Args; }
- const VarArray &instructions() const { return Instrs; }
- VarArray &instructions() { return Instrs; }
+ InstrArray &instructions() { return Instrs; }
+ const InstrArray &instructions() const { return Instrs; }
- const BlockArray &predecessors() const { return Predecessors; }
+ /// Returns a list of predecessors.
+ /// The order of predecessors in the list is important; each phi node has
+ /// exactly one argument for each precessor, in the same order.
BlockArray &predecessors() { return Predecessors; }
+ const BlockArray &predecessors() const { return Predecessors; }
+
+ ArrayRef<BasicBlock*> successors() { return TermInstr->successors(); }
+ ArrayRef<BasicBlock*> successors() const { return TermInstr->successors(); }
+
+ const Terminator *terminator() const { return TermInstr; }
+ Terminator *terminator() { return TermInstr; }
- const SExpr *terminator() const { return Terminator.get(); }
- SExpr *terminator() { return Terminator.get(); }
+ void setTerminator(Terminator *E) { TermInstr = E; }
- void setBlockID(unsigned i) { BlockID = i; }
- void setParent(BasicBlock *P) { Parent = P; }
- void setTerminator(SExpr *E) { Terminator.reset(E); }
+ bool Dominates(const BasicBlock &Other) {
+ return DominatorNode.isParentOfOrEqual(Other.DominatorNode);
+ }
+
+ bool PostDominates(const BasicBlock &Other) {
+ return PostDominatorNode.isParentOfOrEqual(Other.PostDominatorNode);
+ }
- // Add a new argument. V must define a phi-node.
- void addArgument(Variable *V) {
- V->setKind(Variable::VK_LetBB);
+ /// Add a new argument.
+ void addArgument(Phi *V) {
Args.reserveCheck(1, Arena);
Args.push_back(V);
}
- // Add a new instruction.
- void addInstruction(Variable *V) {
- V->setKind(Variable::VK_LetBB);
+ /// Add a new instruction.
+ void addInstruction(SExpr *V) {
Instrs.reserveCheck(1, Arena);
Instrs.push_back(V);
}
@@ -1468,34 +1618,29 @@ public:
// Reserve space for NumPreds predecessors, including space in phi nodes.
void reservePredecessors(unsigned NumPreds);
- // Return the index of BB, or Predecessors.size if BB is not a predecessor.
+ /// Return the index of BB, or Predecessors.size if BB is not a predecessor.
unsigned findPredecessorIndex(const BasicBlock *BB) const {
auto I = std::find(Predecessors.cbegin(), Predecessors.cend(), BB);
return std::distance(Predecessors.cbegin(), I);
}
- // Set id numbers for variables.
- void renumberVars();
-
template <class V>
typename V::R_BasicBlock traverse(V &Vs, typename V::R_Ctx Ctx) {
- typename V::template Container<Variable*> Nas(Vs, Args.size());
- typename V::template Container<Variable*> Nis(Vs, Instrs.size());
+ typename V::template Container<SExpr*> Nas(Vs, Args.size());
+ typename V::template Container<SExpr*> Nis(Vs, Instrs.size());
// Entering the basic block should do any scope initialization.
Vs.enterBasicBlock(*this);
- for (auto *A : Args) {
- auto Ne = Vs.traverse(A->Definition, Vs.subExprCtx(Ctx));
- Variable *Nvd = Vs.enterScope(*A, Ne);
- Nas.push_back(Nvd);
+ for (auto *E : Args) {
+ auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx));
+ Nas.push_back(Ne);
}
- for (auto *I : Instrs) {
- auto Ne = Vs.traverse(I->Definition, Vs.subExprCtx(Ctx));
- Variable *Nvd = Vs.enterScope(*I, Ne);
- Nis.push_back(Nvd);
+ for (auto *E : Instrs) {
+ auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx));
+ Nis.push_back(Ne);
}
- auto Nt = Vs.traverse(Terminator, Ctx);
+ auto Nt = Vs.traverse(TermInstr, Ctx);
// Exiting the basic block should handle any scope cleanup.
Vs.exitBasicBlock(*this);
@@ -1503,7 +1648,8 @@ public:
return Vs.reduceBasicBlock(*this, Nas, Nis, Nt);
}
- template <class C> typename C::CType compare(BasicBlock *E, C &Cmp) {
+ template <class C>
+ typename C::CType compare(const BasicBlock *E, C &Cmp) const {
// TODO: implement CFG comparisons
return Cmp.comparePointers(this, E);
}
@@ -1511,22 +1657,32 @@ public:
private:
friend class SCFG;
- MemRegionRef Arena;
+ int renumberInstrs(int id); // assign unique ids to all instructions
+ int topologicalSort(SimpleArray<BasicBlock*>& Blocks, int ID);
+ int topologicalFinalSort(SimpleArray<BasicBlock*>& Blocks, int ID);
+ void computeDominator();
+ void computePostDominator();
- SCFG *CFGPtr; // The CFG that contains this block.
- unsigned BlockID; // unique id for this BB in the containing CFG
- BasicBlock *Parent; // The parent block is the enclosing lexical scope.
- // The parent dominates this block.
- BlockArray Predecessors; // Predecessor blocks in the CFG.
- VarArray Args; // Phi nodes. One argument per predecessor.
- VarArray Instrs; // Instructions.
- SExprRef Terminator; // Branch or Goto
+private:
+ MemRegionRef Arena; // The arena used to allocate this block.
+ SCFG *CFGPtr; // The CFG that contains this block.
+ int BlockID : 31; // unique id for this BB in the containing CFG.
+ // IDs are in topological order.
+ bool Visited : 1; // Bit to determine if a block has been visited
+ // during a traversal.
+ BlockArray Predecessors; // Predecessor blocks in the CFG.
+ InstrArray Args; // Phi nodes. One argument per predecessor.
+ InstrArray Instrs; // Instructions.
+ Terminator* TermInstr; // Terminating instruction
+
+ TopologyNode DominatorNode; // The dominator tree
+ TopologyNode PostDominatorNode; // The post-dominator tree
};
-// An SCFG is a control-flow graph. It consists of a set of basic blocks, each
-// of which terminates in a branch to another basic block. There is one
-// entry point, and one exit point.
+/// An SCFG is a control-flow graph. It consists of a set of basic blocks,
+/// each of which terminates in a branch to another basic block. There is one
+/// entry point, and one exit point.
class SCFG : public SExpr {
public:
typedef SimpleArray<BasicBlock *> BlockArray;
@@ -1537,20 +1693,29 @@ public:
SCFG(MemRegionRef A, unsigned Nblocks)
: SExpr(COP_SCFG), Arena(A), Blocks(A, Nblocks),
- Entry(nullptr), Exit(nullptr) {
- Entry = new (A) BasicBlock(A, nullptr);
- Exit = new (A) BasicBlock(A, Entry);
- auto *V = new (A) Variable(new (A) Phi());
+ Entry(nullptr), Exit(nullptr), NumInstructions(0), Normal(false) {
+ Entry = new (A) BasicBlock(A);
+ Exit = new (A) BasicBlock(A);
+ auto *V = new (A) Phi();
Exit->addArgument(V);
+ Exit->setTerminator(new (A) Return(V));
add(Entry);
add(Exit);
}
SCFG(const SCFG &Cfg, BlockArray &&Ba) // steals memory from Ba
: SExpr(COP_SCFG), Arena(Cfg.Arena), Blocks(std::move(Ba)),
- Entry(nullptr), Exit(nullptr) {
+ Entry(nullptr), Exit(nullptr), NumInstructions(0), Normal(false) {
// TODO: set entry and exit!
}
+ /// Return true if this CFG is valid.
+ bool valid() const { return Entry && Exit && Blocks.size() > 0; }
+
+ /// Return true if this CFG has been normalized.
+ /// After normalization, blocks are in topological order, and block and
+ /// instruction IDs have been assigned.
+ bool normal() const { return Normal; }
+
iterator begin() { return Blocks.begin(); }
iterator end() { return Blocks.end(); }
@@ -1565,9 +1730,17 @@ public:
const BasicBlock *exit() const { return Exit; }
BasicBlock *exit() { return Exit; }
+ /// Return the number of blocks in the CFG.
+ /// Block::blockID() will return a number less than numBlocks();
+ size_t numBlocks() const { return Blocks.size(); }
+
+ /// Return the total number of instructions in the CFG.
+ /// This is useful for building instruction side-tables;
+ /// A call to SExpr::id() will return a number less than numInstructions().
+ unsigned numInstructions() { return NumInstructions; }
+
inline void add(BasicBlock *BB) {
- assert(BB->CFGPtr == nullptr || BB->CFGPtr == this);
- BB->setBlockID(Blocks.size());
+ assert(BB->CFGPtr == nullptr);
BB->CFGPtr = this;
Blocks.reserveCheck(1, Arena);
Blocks.push_back(BB);
@@ -1576,13 +1749,13 @@ public:
void setEntry(BasicBlock *BB) { Entry = BB; }
void setExit(BasicBlock *BB) { Exit = BB; }
- // Set varable ids in all blocks.
- void renumberVars();
+ void computeNormalForm();
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
Vs.enterCFG(*this);
typename V::template Container<BasicBlock *> Bbs(Vs, Blocks.size());
+
for (auto *B : Blocks) {
Bbs.push_back( B->traverse(Vs, Vs.subExprCtx(Ctx)) );
}
@@ -1590,100 +1763,28 @@ public:
return Vs.reduceSCFG(*this, Bbs);
}
- template <class C> typename C::CType compare(SCFG *E, C &Cmp) {
- // TODO -- implement CFG comparisons
+ template <class C>
+ typename C::CType compare(const SCFG *E, C &Cmp) const {
+ // TODO: implement CFG comparisons
return Cmp.comparePointers(this, E);
}
private:
+ void renumberInstrs(); // assign unique ids to all instructions
+
+private:
MemRegionRef Arena;
BlockArray Blocks;
BasicBlock *Entry;
BasicBlock *Exit;
+ unsigned NumInstructions;
+ bool Normal;
};
-class Goto : public SExpr {
-public:
- static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; }
-
- Goto(BasicBlock *B, unsigned I)
- : SExpr(COP_Goto), TargetBlock(B), Index(I) {}
- Goto(const Goto &G, BasicBlock *B, unsigned I)
- : SExpr(COP_Goto), TargetBlock(B), Index(I) {}
- const BasicBlock *targetBlock() const { return TargetBlock; }
- BasicBlock *targetBlock() { return TargetBlock; }
-
- unsigned index() const { return Index; }
-
- template <class V>
- typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
- BasicBlock *Ntb = Vs.reduceBasicBlockRef(TargetBlock);
- return Vs.reduceGoto(*this, Ntb);
- }
-
- template <class C> typename C::CType compare(Goto *E, C &Cmp) {
- // TODO -- implement CFG comparisons
- return Cmp.comparePointers(this, E);
- }
-
-private:
- BasicBlock *TargetBlock;
- unsigned Index; // Index into Phi nodes of target block.
-};
-
-
-class Branch : public SExpr {
-public:
- static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; }
-
- Branch(SExpr *C, BasicBlock *T, BasicBlock *E, unsigned TI, unsigned EI)
- : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E),
- ThenIndex(TI), ElseIndex(EI)
- {}
- Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E,
- unsigned TI, unsigned EI)
- : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E),
- ThenIndex(TI), ElseIndex(EI)
- {}
-
- const SExpr *condition() const { return Condition; }
- SExpr *condition() { return Condition; }
-
- const BasicBlock *thenBlock() const { return ThenBlock; }
- BasicBlock *thenBlock() { return ThenBlock; }
-
- const BasicBlock *elseBlock() const { return ElseBlock; }
- BasicBlock *elseBlock() { return ElseBlock; }
-
- unsigned thenIndex() const { return ThenIndex; }
- unsigned elseIndex() const { return ElseIndex; }
-
- template <class V>
- typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
- auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx));
- BasicBlock *Ntb = Vs.reduceBasicBlockRef(ThenBlock);
- BasicBlock *Nte = Vs.reduceBasicBlockRef(ElseBlock);
- return Vs.reduceBranch(*this, Nc, Ntb, Nte);
- }
-
- template <class C> typename C::CType compare(Branch *E, C &Cmp) {
- // TODO -- implement CFG comparisons
- return Cmp.comparePointers(this, E);
- }
-
-private:
- SExpr *Condition;
- BasicBlock *ThenBlock;
- BasicBlock *ElseBlock;
- unsigned ThenIndex;
- unsigned ElseIndex;
-};
-
-
-// An identifier, e.g. 'foo' or 'x'.
-// This is a pseduo-term; it will be lowered to a variable or projection.
+/// An identifier, e.g. 'foo' or 'x'.
+/// This is a pseduo-term; it will be lowered to a variable or projection.
class Identifier : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Identifier; }
@@ -1698,7 +1799,8 @@ public:
return Vs.reduceIdentifier(*this);
}
- template <class C> typename C::CType compare(Identifier* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Identifier* E, C& Cmp) const {
return Cmp.compareStrings(name(), E->name());
}
@@ -1707,8 +1809,8 @@ private:
};
-// An if-then-else expression.
-// This is a pseduo-term; it will be lowered to a branch in a CFG.
+/// An if-then-else expression.
+/// This is a pseduo-term; it will be lowered to a branch in a CFG.
class IfThenElse : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_IfThenElse; }
@@ -1720,14 +1822,14 @@ public:
: SExpr(I), Condition(C), ThenExpr(T), ElseExpr(E)
{ }
- SExpr *condition() { return Condition.get(); } // Address to store to
- const SExpr *condition() const { return Condition.get(); }
+ SExpr *condition() { return Condition; } // Address to store to
+ const SExpr *condition() const { return Condition; }
- SExpr *thenExpr() { return ThenExpr.get(); } // Value to store
- const SExpr *thenExpr() const { return ThenExpr.get(); }
+ SExpr *thenExpr() { return ThenExpr; } // Value to store
+ const SExpr *thenExpr() const { return ThenExpr; }
- SExpr *elseExpr() { return ElseExpr.get(); } // Value to store
- const SExpr *elseExpr() const { return ElseExpr.get(); }
+ SExpr *elseExpr() { return ElseExpr; } // Value to store
+ const SExpr *elseExpr() const { return ElseExpr; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -1737,7 +1839,8 @@ public:
return Vs.reduceIfThenElse(*this, Nc, Nt, Ne);
}
- template <class C> typename C::CType compare(IfThenElse* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const IfThenElse* E, C& Cmp) const {
typename C::CType Ct = Cmp.compare(condition(), E->condition());
if (Cmp.notTrue(Ct))
return Ct;
@@ -1748,14 +1851,14 @@ public:
}
private:
- SExprRef Condition;
- SExprRef ThenExpr;
- SExprRef ElseExpr;
+ SExpr* Condition;
+ SExpr* ThenExpr;
+ SExpr* ElseExpr;
};
-// A let-expression, e.g. let x=t; u.
-// This is a pseduo-term; it will be lowered to instructions in a CFG.
+/// A let-expression, e.g. let x=t; u.
+/// This is a pseduo-term; it will be lowered to instructions in a CFG.
class Let : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Let; }
@@ -1770,8 +1873,8 @@ public:
Variable *variableDecl() { return VarDecl; }
const Variable *variableDecl() const { return VarDecl; }
- SExpr *body() { return Body.get(); }
- const SExpr *body() const { return Body.get(); }
+ SExpr *body() { return Body; }
+ const SExpr *body() const { return Body; }
template <class V>
typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
@@ -1784,7 +1887,8 @@ public:
return Vs.reduceLet(*this, Nvd, E1);
}
- template <class C> typename C::CType compare(Let* E, C& Cmp) {
+ template <class C>
+ typename C::CType compare(const Let* E, C& Cmp) const {
typename C::CType Ct =
Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
if (Cmp.notTrue(Ct))
@@ -1797,17 +1901,18 @@ public:
private:
Variable *VarDecl;
- SExprRef Body;
+ SExpr* Body;
};
-SExpr *getCanonicalVal(SExpr *E);
-void simplifyIncompleteArg(Variable *V, til::Phi *Ph);
+const SExpr *getCanonicalVal(const SExpr *E);
+SExpr* simplifyToCanonicalVal(SExpr *E);
+void simplifyIncompleteArg(til::Phi *Ph);
} // end namespace til
} // end namespace threadSafety
} // end namespace clang
-#endif // LLVM_CLANG_THREAD_SAFETY_TIL_H
+#endif
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
index bc1490b4a448..705fe910d092 100644
--- a/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
+++ b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
@@ -14,10 +14,11 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H
-#define LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
#include "ThreadSafetyTIL.h"
+#include <ostream>
namespace clang {
namespace threadSafety {
@@ -56,11 +57,16 @@ public:
// Traverse an expression -- returning a result of type R_SExpr.
// Override this method to do something for every expression, regardless
// of which kind it is.
- typename R::R_SExpr traverse(SExprRef &E, typename R::R_Ctx Ctx) {
- return traverse(E.get(), Ctx);
+ // E is a reference, so this can be use for in-place updates.
+ // The type T must be a subclass of SExpr.
+ template <class T>
+ typename R::R_SExpr traverse(T* &E, typename R::R_Ctx Ctx) {
+ return traverseSExpr(E, Ctx);
}
- typename R::R_SExpr traverse(SExpr *E, typename R::R_Ctx Ctx) {
+ // Override this method to do something for every expression.
+ // Does not allow in-place updates.
+ typename R::R_SExpr traverseSExpr(SExpr *E, typename R::R_Ctx Ctx) {
return traverseByCase(E, Ctx);
}
@@ -73,6 +79,7 @@ public:
#include "ThreadSafetyOps.def"
#undef TIL_OPCODE_DEF
}
+ return self()->reduceNull();
}
// Traverse e, by static dispatch on the type "X" of e.
@@ -90,10 +97,10 @@ public:
class SimpleReducerBase {
public:
enum TraversalKind {
- TRV_Normal,
- TRV_Decl,
- TRV_Lazy,
- TRV_Type
+ TRV_Normal, // ordinary subexpressions
+ TRV_Decl, // declarations (e.g. function bodies)
+ TRV_Lazy, // expressions that require lazy evaluation
+ TRV_Type // type expressions
};
// R_Ctx defines a "context" for the traversal, which encodes information
@@ -145,153 +152,6 @@ protected:
};
-// Implements a traversal that makes a deep copy of an SExpr.
-// The default behavior of reduce##X(...) is to create a copy of the original.
-// Subclasses can override reduce##X to implement non-destructive rewriting
-// passes.
-template<class Self>
-class CopyReducer : public Traversal<Self, CopyReducerBase>,
- public CopyReducerBase {
-public:
- CopyReducer(MemRegionRef A) : CopyReducerBase(A) {}
-
-public:
- R_SExpr reduceNull() {
- return nullptr;
- }
- // R_SExpr reduceFuture(...) is never used.
-
- R_SExpr reduceUndefined(Undefined &Orig) {
- return new (Arena) Undefined(Orig);
- }
- R_SExpr reduceWildcard(Wildcard &Orig) {
- return new (Arena) Wildcard(Orig);
- }
-
- R_SExpr reduceLiteral(Literal &Orig) {
- return new (Arena) Literal(Orig);
- }
- template<class T>
- R_SExpr reduceLiteralT(LiteralT<T> &Orig) {
- return new (Arena) LiteralT<T>(Orig);
- }
- R_SExpr reduceLiteralPtr(LiteralPtr &Orig) {
- return new (Arena) LiteralPtr(Orig);
- }
-
- R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) {
- return new (Arena) Function(Orig, Nvd, E0);
- }
- R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) {
- return new (Arena) SFunction(Orig, Nvd, E0);
- }
- R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) {
- return new (Arena) Code(Orig, E0, E1);
- }
- R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1) {
- return new (Arena) Field(Orig, E0, E1);
- }
-
- R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) {
- return new (Arena) Apply(Orig, E0, E1);
- }
- R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) {
- return new (Arena) SApply(Orig, E0, E1);
- }
- R_SExpr reduceProject(Project &Orig, R_SExpr E0) {
- return new (Arena) Project(Orig, E0);
- }
- R_SExpr reduceCall(Call &Orig, R_SExpr E0) {
- return new (Arena) Call(Orig, E0);
- }
-
- R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) {
- return new (Arena) Alloc(Orig, E0);
- }
- R_SExpr reduceLoad(Load &Orig, R_SExpr E0) {
- return new (Arena) Load(Orig, E0);
- }
- R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) {
- return new (Arena) Store(Orig, E0, E1);
- }
- R_SExpr reduceArrayIndex(ArrayIndex &Orig, R_SExpr E0, R_SExpr E1) {
- return new (Arena) ArrayIndex(Orig, E0, E1);
- }
- R_SExpr reduceArrayAdd(ArrayAdd &Orig, R_SExpr E0, R_SExpr E1) {
- return new (Arena) ArrayAdd(Orig, E0, E1);
- }
- R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) {
- return new (Arena) UnaryOp(Orig, E0);
- }
- R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) {
- return new (Arena) BinaryOp(Orig, E0, E1);
- }
- R_SExpr reduceCast(Cast &Orig, R_SExpr E0) {
- return new (Arena) Cast(Orig, E0);
- }
-
- R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> &Bbs) {
- return nullptr; // FIXME: implement CFG rewriting
- }
- R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<Variable *> &As,
- Container<Variable *> &Is, R_SExpr T) {
- return nullptr; // FIXME: implement CFG rewriting
- }
- R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) {
- return new (Arena) Phi(Orig, std::move(As.Elems));
- }
- R_SExpr reduceGoto(Goto &Orig, BasicBlock *B) {
- return new (Arena) Goto(Orig, B, 0); // FIXME: set index
- }
- R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) {
- return new (Arena) Branch(O, C, B0, B1, 0, 0); // FIXME: set indices
- }
-
- R_SExpr reduceIdentifier(Identifier &Orig) {
- return new (Arena) Identifier(Orig);
- }
- R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E) {
- return new (Arena) IfThenElse(Orig, C, T, E);
- }
- R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B) {
- return new (Arena) Let(Orig, Nvd, B);
- }
-
- // Create a new variable from orig, and push it onto the lexical scope.
- Variable *enterScope(Variable &Orig, R_SExpr E0) {
- return new (Arena) Variable(Orig, E0);
- }
- // Exit the lexical scope of orig.
- void exitScope(const Variable &Orig) {}
-
- void enterCFG(SCFG &Cfg) {}
- void exitCFG(SCFG &Cfg) {}
- void enterBasicBlock(BasicBlock &BB) {}
- void exitBasicBlock(BasicBlock &BB) {}
-
- // Map Variable references to their rewritten definitions.
- Variable *reduceVariableRef(Variable *Ovd) { return Ovd; }
-
- // Map BasicBlock references to their rewritten definitions.
- BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; }
-};
-
-
-class SExprCopier : public CopyReducer<SExprCopier> {
-public:
- typedef SExpr *R_SExpr;
-
- SExprCopier(MemRegionRef A) : CopyReducer(A) { }
-
- // Create a copy of e in region a.
- static SExpr *copy(SExpr *E, MemRegionRef A) {
- SExprCopier Copier(A);
- return Copier.traverse(E, TRV_Normal);
- }
-};
-
-
-
// Base class for visit traversals.
class VisitReducerBase : public SimpleReducerBase {
public:
@@ -366,8 +226,8 @@ public:
R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> Bbs) {
return Bbs.Success;
}
- R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<Variable *> &As,
- Container<Variable *> &Is, R_SExpr T) {
+ R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<R_SExpr> &As,
+ Container<R_SExpr> &Is, R_SExpr T) {
return (As.Success && Is.Success && T);
}
R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) {
@@ -379,6 +239,9 @@ public:
R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) {
return C;
}
+ R_SExpr reduceReturn(Return &O, R_SExpr E) {
+ return E;
+ }
R_SExpr reduceIdentifier(Identifier &Orig) {
return true;
@@ -423,7 +286,7 @@ protected:
Self *self() { return reinterpret_cast<Self *>(this); }
public:
- bool compareByCase(SExpr *E1, SExpr* E2) {
+ bool compareByCase(const SExpr *E1, const SExpr* E2) {
switch (E1->opcode()) {
#define TIL_OPCODE_DEF(X) \
case COP_##X: \
@@ -431,6 +294,7 @@ public:
#include "ThreadSafetyOps.def"
#undef TIL_OPCODE_DEF
}
+ return false;
}
};
@@ -449,38 +313,86 @@ public:
bool compareStrings (StringRef s, StringRef r) { return s == r; }
bool comparePointers(const void* P, const void* Q) { return P == Q; }
- bool compare(SExpr *E1, SExpr* E2) {
+ bool compare(const SExpr *E1, const SExpr* E2) {
if (E1->opcode() != E2->opcode())
return false;
return compareByCase(E1, E2);
}
// TODO -- handle alpha-renaming of variables
- void enterScope(Variable* V1, Variable* V2) { }
+ void enterScope(const Variable* V1, const Variable* V2) { }
void leaveScope() { }
- bool compareVariableRefs(Variable* V1, Variable* V2) {
+ bool compareVariableRefs(const Variable* V1, const Variable* V2) {
return V1 == V2;
}
- static bool compareExprs(SExpr *E1, SExpr* E2) {
+ static bool compareExprs(const SExpr *E1, const SExpr* E2) {
EqualsComparator Eq;
return Eq.compare(E1, E2);
}
};
+
+class MatchComparator : public Comparator<MatchComparator> {
+public:
+ // Result type for the comparison, e.g. bool for simple equality,
+ // or int for lexigraphic comparison (-1, 0, 1). Must have one value which
+ // denotes "true".
+ typedef bool CType;
+
+ CType trueResult() { return true; }
+ bool notTrue(CType ct) { return !ct; }
+
+ bool compareIntegers(unsigned i, unsigned j) { return i == j; }
+ bool compareStrings (StringRef s, StringRef r) { return s == r; }
+ bool comparePointers(const void* P, const void* Q) { return P == Q; }
+
+ bool compare(const SExpr *E1, const SExpr* E2) {
+ // Wildcards match anything.
+ if (E1->opcode() == COP_Wildcard || E2->opcode() == COP_Wildcard)
+ return true;
+ // otherwise normal equality.
+ if (E1->opcode() != E2->opcode())
+ return false;
+ return compareByCase(E1, E2);
+ }
+
+ // TODO -- handle alpha-renaming of variables
+ void enterScope(const Variable* V1, const Variable* V2) { }
+ void leaveScope() { }
+
+ bool compareVariableRefs(const Variable* V1, const Variable* V2) {
+ return V1 == V2;
+ }
+
+ static bool compareExprs(const SExpr *E1, const SExpr* E2) {
+ MatchComparator Matcher;
+ return Matcher.compare(E1, E2);
+ }
+};
+
+
+
+// inline std::ostream& operator<<(std::ostream& SS, StringRef R) {
+// return SS.write(R.data(), R.size());
+// }
+
// Pretty printer for TIL expressions
template <typename Self, typename StreamType>
class PrettyPrinter {
private:
bool Verbose; // Print out additional information
bool Cleanup; // Omit redundant decls.
+ bool CStyle; // Print exprs in C-like syntax.
public:
- PrettyPrinter(bool V = false, bool C = true) : Verbose(V), Cleanup(C) { }
+ PrettyPrinter(bool V = false, bool C = true, bool CS = true)
+ : Verbose(V), Cleanup(C), CStyle(CS)
+ {}
- static void print(SExpr *E, StreamType &SS) {
+ static void print(const SExpr *E, StreamType &SS) {
Self printer;
printer.printSExpr(E, SS, Prec_MAX);
}
@@ -502,7 +414,7 @@ protected:
static const unsigned Prec_MAX = 6;
// Return the precedence of a given node, for use in pretty printing.
- unsigned precedence(SExpr *E) {
+ unsigned precedence(const SExpr *E) {
switch (E->opcode()) {
case COP_Future: return Prec_Atom;
case COP_Undefined: return Prec_Atom;
@@ -529,13 +441,14 @@ protected:
case COP_UnaryOp: return Prec_Unary;
case COP_BinaryOp: return Prec_Binary;
- case COP_Cast: return Prec_Unary;
+ case COP_Cast: return Prec_Atom;
case COP_SCFG: return Prec_Decl;
case COP_BasicBlock: return Prec_MAX;
case COP_Phi: return Prec_Atom;
case COP_Goto: return Prec_Atom;
case COP_Branch: return Prec_Atom;
+ case COP_Return: return Prec_Other;
case COP_Identifier: return Prec_Atom;
case COP_IfThenElse: return Prec_Other;
@@ -544,22 +457,29 @@ protected:
return Prec_MAX;
}
- void printBlockLabel(StreamType & SS, BasicBlock *BB, unsigned index) {
+ void printBlockLabel(StreamType & SS, const BasicBlock *BB, int index) {
if (!BB) {
SS << "BB_null";
return;
}
SS << "BB_";
SS << BB->blockID();
- SS << ":";
- SS << index;
+ if (index >= 0) {
+ SS << ":";
+ SS << index;
+ }
}
- void printSExpr(SExpr *E, StreamType &SS, unsigned P) {
+
+ void printSExpr(const SExpr *E, StreamType &SS, unsigned P, bool Sub=true) {
if (!E) {
self()->printNull(SS);
return;
}
+ if (Sub && E->block() && E->opcode() != COP_Variable) {
+ SS << "_x" << E->id();
+ return;
+ }
if (self()->precedence(E) > P) {
// Wrap expr in () if necessary.
SS << "(";
@@ -582,28 +502,28 @@ protected:
SS << "#null";
}
- void printFuture(Future *E, StreamType &SS) {
+ void printFuture(const Future *E, StreamType &SS) {
self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom);
}
- void printUndefined(Undefined *E, StreamType &SS) {
+ void printUndefined(const Undefined *E, StreamType &SS) {
SS << "#undefined";
}
- void printWildcard(Wildcard *E, StreamType &SS) {
- SS << "_";
+ void printWildcard(const Wildcard *E, StreamType &SS) {
+ SS << "*";
}
template<class T>
- void printLiteralT(LiteralT<T> *E, StreamType &SS) {
+ void printLiteralT(const LiteralT<T> *E, StreamType &SS) {
SS << E->value();
}
- void printLiteralT(LiteralT<uint8_t> *E, StreamType &SS) {
+ void printLiteralT(const LiteralT<uint8_t> *E, StreamType &SS) {
SS << "'" << E->value() << "'";
}
- void printLiteral(Literal *E, StreamType &SS) {
+ void printLiteral(const Literal *E, StreamType &SS) {
if (E->clangExpr()) {
SS << getSourceLiteralString(E->clangExpr());
return;
@@ -685,25 +605,18 @@ protected:
SS << "#lit";
}
- void printLiteralPtr(LiteralPtr *E, StreamType &SS) {
+ void printLiteralPtr(const LiteralPtr *E, StreamType &SS) {
SS << E->clangDecl()->getNameAsString();
}
- void printVariable(Variable *V, StreamType &SS, bool IsVarDecl = false) {
- if (!IsVarDecl && Cleanup) {
- SExpr* E = getCanonicalVal(V);
- if (E != V) {
- printSExpr(E, SS, Prec_Atom);
- return;
- }
- }
- if (V->kind() == Variable::VK_LetBB)
- SS << V->name() << V->getBlockID() << "_" << V->getID();
+ void printVariable(const Variable *V, StreamType &SS, bool IsVarDecl=false) {
+ if (CStyle && V->kind() == Variable::VK_SFun)
+ SS << "this";
else
- SS << V->name() << V->getID();
+ SS << V->name() << V->id();
}
- void printFunction(Function *E, StreamType &SS, unsigned sugared = 0) {
+ void printFunction(const Function *E, StreamType &SS, unsigned sugared = 0) {
switch (sugared) {
default:
SS << "\\("; // Lambda
@@ -719,7 +632,7 @@ protected:
SS << ": ";
self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX);
- SExpr *B = E->body();
+ const SExpr *B = E->body();
if (B && B->opcode() == COP_Function)
self()->printFunction(cast<Function>(B), SS, 2);
else {
@@ -728,29 +641,29 @@ protected:
}
}
- void printSFunction(SFunction *E, StreamType &SS) {
+ void printSFunction(const SFunction *E, StreamType &SS) {
SS << "@";
self()->printVariable(E->variableDecl(), SS, true);
SS << " ";
self()->printSExpr(E->body(), SS, Prec_Decl);
}
- void printCode(Code *E, StreamType &SS) {
+ void printCode(const Code *E, StreamType &SS) {
SS << ": ";
self()->printSExpr(E->returnType(), SS, Prec_Decl-1);
SS << " -> ";
self()->printSExpr(E->body(), SS, Prec_Decl);
}
- void printField(Field *E, StreamType &SS) {
+ void printField(const Field *E, StreamType &SS) {
SS << ": ";
self()->printSExpr(E->range(), SS, Prec_Decl-1);
SS << " = ";
self()->printSExpr(E->body(), SS, Prec_Decl);
}
- void printApply(Apply *E, StreamType &SS, bool sugared = false) {
- SExpr *F = E->fun();
+ void printApply(const Apply *E, StreamType &SS, bool sugared = false) {
+ const SExpr *F = E->fun();
if (F->opcode() == COP_Apply) {
printApply(cast<Apply>(F), SS, true);
SS << ", ";
@@ -763,7 +676,7 @@ protected:
SS << ")$";
}
- void printSApply(SApply *E, StreamType &SS) {
+ void printSApply(const SApply *E, StreamType &SS) {
self()->printSExpr(E->sfun(), SS, Prec_Postfix);
if (E->isDelegation()) {
SS << "@(";
@@ -772,14 +685,36 @@ protected:
}
}
- void printProject(Project *E, StreamType &SS) {
+ void printProject(const Project *E, StreamType &SS) {
+ if (CStyle) {
+ // Omit the this->
+ if (const SApply *SAP = dyn_cast<SApply>(E->record())) {
+ if (const Variable *V = dyn_cast<Variable>(SAP->sfun())) {
+ if (!SAP->isDelegation() && V->kind() == Variable::VK_SFun) {
+ SS << E->slotName();
+ return;
+ }
+ }
+ }
+ if (isa<Wildcard>(E->record())) {
+ // handle existentials
+ SS << "&";
+ SS << E->clangDecl()->getQualifiedNameAsString();
+ return;
+ }
+ }
self()->printSExpr(E->record(), SS, Prec_Postfix);
- SS << ".";
+ if (CStyle && E->isArrow()) {
+ SS << "->";
+ }
+ else {
+ SS << ".";
+ }
SS << E->slotName();
}
- void printCall(Call *E, StreamType &SS) {
- SExpr *T = E->target();
+ void printCall(const Call *E, StreamType &SS) {
+ const SExpr *T = E->target();
if (T->opcode() == COP_Apply) {
self()->printApply(cast<Apply>(T), SS, true);
SS << ")";
@@ -790,52 +725,60 @@ protected:
}
}
- void printAlloc(Alloc *E, StreamType &SS) {
+ void printAlloc(const Alloc *E, StreamType &SS) {
SS << "new ";
self()->printSExpr(E->dataType(), SS, Prec_Other-1);
}
- void printLoad(Load *E, StreamType &SS) {
+ void printLoad(const Load *E, StreamType &SS) {
self()->printSExpr(E->pointer(), SS, Prec_Postfix);
- SS << "^";
+ if (!CStyle)
+ SS << "^";
}
- void printStore(Store *E, StreamType &SS) {
+ void printStore(const Store *E, StreamType &SS) {
self()->printSExpr(E->destination(), SS, Prec_Other-1);
SS << " := ";
self()->printSExpr(E->source(), SS, Prec_Other-1);
}
- void printArrayIndex(ArrayIndex *E, StreamType &SS) {
+ void printArrayIndex(const ArrayIndex *E, StreamType &SS) {
self()->printSExpr(E->array(), SS, Prec_Postfix);
SS << "[";
self()->printSExpr(E->index(), SS, Prec_MAX);
SS << "]";
}
- void printArrayAdd(ArrayAdd *E, StreamType &SS) {
+ void printArrayAdd(const ArrayAdd *E, StreamType &SS) {
self()->printSExpr(E->array(), SS, Prec_Postfix);
SS << " + ";
self()->printSExpr(E->index(), SS, Prec_Atom);
}
- void printUnaryOp(UnaryOp *E, StreamType &SS) {
+ void printUnaryOp(const UnaryOp *E, StreamType &SS) {
SS << getUnaryOpcodeString(E->unaryOpcode());
self()->printSExpr(E->expr(), SS, Prec_Unary);
}
- void printBinaryOp(BinaryOp *E, StreamType &SS) {
+ void printBinaryOp(const BinaryOp *E, StreamType &SS) {
self()->printSExpr(E->expr0(), SS, Prec_Binary-1);
SS << " " << getBinaryOpcodeString(E->binaryOpcode()) << " ";
self()->printSExpr(E->expr1(), SS, Prec_Binary-1);
}
- void printCast(Cast *E, StreamType &SS) {
- SS << "%";
+ void printCast(const Cast *E, StreamType &SS) {
+ if (!CStyle) {
+ SS << "cast[";
+ SS << E->castOpcode();
+ SS << "](";
+ self()->printSExpr(E->expr(), SS, Prec_Unary);
+ SS << ")";
+ return;
+ }
self()->printSExpr(E->expr(), SS, Prec_Unary);
}
- void printSCFG(SCFG *E, StreamType &SS) {
+ void printSCFG(const SCFG *E, StreamType &SS) {
SS << "CFG {\n";
for (auto BBI : *E) {
printBasicBlock(BBI, SS);
@@ -844,39 +787,45 @@ protected:
newline(SS);
}
- void printBasicBlock(BasicBlock *E, StreamType &SS) {
+
+ void printBBInstr(const SExpr *E, StreamType &SS) {
+ bool Sub = false;
+ if (E->opcode() == COP_Variable) {
+ auto *V = cast<Variable>(E);
+ SS << "let " << V->name() << V->id() << " = ";
+ E = V->definition();
+ Sub = true;
+ }
+ else if (E->opcode() != COP_Store) {
+ SS << "let _x" << E->id() << " = ";
+ }
+ self()->printSExpr(E, SS, Prec_MAX, Sub);
+ SS << ";";
+ newline(SS);
+ }
+
+ void printBasicBlock(const BasicBlock *E, StreamType &SS) {
SS << "BB_" << E->blockID() << ":";
if (E->parent())
SS << " BB_" << E->parent()->blockID();
newline(SS);
- for (auto *A : E->arguments()) {
- SS << "let ";
- self()->printVariable(A, SS, true);
- SS << " = ";
- self()->printSExpr(A->definition(), SS, Prec_MAX);
- SS << ";";
- newline(SS);
- }
- for (auto *I : E->instructions()) {
- if (I->definition()->opcode() != COP_Store) {
- SS << "let ";
- self()->printVariable(I, SS, true);
- SS << " = ";
- }
- self()->printSExpr(I->definition(), SS, Prec_MAX);
- SS << ";";
- newline(SS);
- }
- SExpr *T = E->terminator();
+
+ for (auto *A : E->arguments())
+ printBBInstr(A, SS);
+
+ for (auto *I : E->instructions())
+ printBBInstr(I, SS);
+
+ const SExpr *T = E->terminator();
if (T) {
- self()->printSExpr(T, SS, Prec_MAX);
+ self()->printSExpr(T, SS, Prec_MAX, false);
SS << ";";
newline(SS);
}
newline(SS);
}
- void printPhi(Phi *E, StreamType &SS) {
+ void printPhi(const Phi *E, StreamType &SS) {
SS << "phi(";
if (E->status() == Phi::PH_SingleVal)
self()->printSExpr(E->values()[0], SS, Prec_MAX);
@@ -891,25 +840,38 @@ protected:
SS << ")";
}
- void printGoto(Goto *E, StreamType &SS) {
+ void printGoto(const Goto *E, StreamType &SS) {
SS << "goto ";
printBlockLabel(SS, E->targetBlock(), E->index());
}
- void printBranch(Branch *E, StreamType &SS) {
+ void printBranch(const Branch *E, StreamType &SS) {
SS << "branch (";
self()->printSExpr(E->condition(), SS, Prec_MAX);
SS << ") ";
- printBlockLabel(SS, E->thenBlock(), E->thenIndex());
+ printBlockLabel(SS, E->thenBlock(), -1);
SS << " ";
- printBlockLabel(SS, E->elseBlock(), E->elseIndex());
+ printBlockLabel(SS, E->elseBlock(), -1);
}
- void printIdentifier(Identifier *E, StreamType &SS) {
+ void printReturn(const Return *E, StreamType &SS) {
+ SS << "return ";
+ self()->printSExpr(E->returnValue(), SS, Prec_Other);
+ }
+
+ void printIdentifier(const Identifier *E, StreamType &SS) {
SS << E->name();
}
- void printIfThenElse(IfThenElse *E, StreamType &SS) {
+ void printIfThenElse(const IfThenElse *E, StreamType &SS) {
+ if (CStyle) {
+ printSExpr(E->condition(), SS, Prec_Unary);
+ SS << " ? ";
+ printSExpr(E->thenExpr(), SS, Prec_Unary);
+ SS << " : ";
+ printSExpr(E->elseExpr(), SS, Prec_Unary);
+ return;
+ }
SS << "if (";
printSExpr(E->condition(), SS, Prec_MAX);
SS << ") then ";
@@ -918,7 +880,7 @@ protected:
printSExpr(E->elseExpr(), SS, Prec_Other);
}
- void printLet(Let *E, StreamType &SS) {
+ void printLet(const Let *E, StreamType &SS) {
SS << "let ";
printVariable(E->variableDecl(), SS, true);
SS << " = ";
@@ -929,6 +891,10 @@ protected:
};
+class StdPrinter : public PrettyPrinter<StdPrinter, std::ostream> { };
+
+
+
} // end namespace til
} // end namespace threadSafety
} // end namespace clang
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyUtil.h b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
index 31200a3a7253..ba3e0e519b09 100644
--- a/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
+++ b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
@@ -11,19 +11,19 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_THREAD_SAFETY_UTIL_H
-#define LLVM_CLANG_THREAD_SAFETY_UTIL_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H
+#include "clang/AST/ExprCXX.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
-#include "clang/AST/ExprCXX.h"
-
#include <cassert>
#include <cstddef>
-#include <vector>
+#include <ostream>
#include <utility>
+#include <vector>
namespace clang {
namespace threadSafety {
@@ -142,18 +142,35 @@ public:
assert(i < Size && "Array index out of bounds.");
return Data[i];
}
+ T &back() {
+ assert(Size && "No elements in the array.");
+ return Data[Size - 1];
+ }
+ const T &back() const {
+ assert(Size && "No elements in the array.");
+ return Data[Size - 1];
+ }
iterator begin() { return Data; }
- iterator end() { return Data + Size; }
+ iterator end() { return Data + Size; }
+
+ const_iterator begin() const { return Data; }
+ const_iterator end() const { return Data + Size; }
const_iterator cbegin() const { return Data; }
- const_iterator cend() const { return Data + Size; }
+ const_iterator cend() const { return Data + Size; }
void push_back(const T &Elem) {
assert(Size < Capacity);
Data[Size++] = Elem;
}
+ // drop last n elements from array
+ void drop(unsigned n = 0) {
+ assert(Size > n);
+ Size -= n;
+ }
+
void setValues(unsigned Sz, const T& C) {
assert(Sz <= Capacity);
Size = Sz;
@@ -171,6 +188,37 @@ public:
return J - Osz;
}
+ // An adaptor to reverse a simple array
+ class ReverseAdaptor {
+ public:
+ ReverseAdaptor(SimpleArray &Array) : Array(Array) {}
+ // A reverse iterator used by the reverse adaptor
+ class Iterator {
+ public:
+ Iterator(T *Data) : Data(Data) {}
+ T &operator*() { return *Data; }
+ const T &operator*() const { return *Data; }
+ Iterator &operator++() {
+ --Data;
+ return *this;
+ }
+ bool operator!=(Iterator Other) { return Data != Other.Data; }
+
+ private:
+ T *Data;
+ };
+ Iterator begin() { return Array.end() - 1; }
+ Iterator end() { return Array.begin() - 1; }
+ const Iterator begin() const { return Array.end() - 1; }
+ const Iterator end() const { return Array.begin() - 1; }
+
+ private:
+ SimpleArray &Array;
+ };
+
+ const ReverseAdaptor reverse() const { return ReverseAdaptor(*this); }
+ ReverseAdaptor reverse() { return ReverseAdaptor(*this); }
+
private:
// std::max is annoying here, because it requires a reference,
// thus forcing InitialCapacity to be initialized outside the .h file.
@@ -185,6 +233,7 @@ private:
size_t Capacity;
};
+
} // end namespace til
@@ -310,6 +359,11 @@ private:
};
+inline std::ostream& operator<<(std::ostream& ss, const StringRef str) {
+ return ss.write(str.data(), str.size());
+}
+
+
} // end namespace threadSafety
} // end namespace clang
diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h
index 188722d94b3a..53ff20c23560 100644
--- a/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_UNINIT_VALS_H
-#define LLVM_CLANG_UNINIT_VALS_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
#include "clang/AST/Stmt.h"
#include "llvm/ADT/SmallVector.h"
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index 08e335418ab7..0ebdf15f2c4e 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -17,6 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CodeInjector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/Allocator.h"
@@ -143,6 +144,14 @@ public:
/// \sa getBody
bool isBodyAutosynthesized() const;
+ /// \brief Checks if the body of the Decl is generated by the BodyFarm from a
+ /// model file.
+ ///
+ /// Note, the lookup is not free. We are going to call getBody behind
+ /// the scenes.
+ /// \sa getBody
+ bool isBodyAutosynthesizedFromModelFile() const;
+
CFG *getCFG();
CFGStmtMap *getCFGStmtMap();
@@ -398,6 +407,10 @@ class AnalysisDeclContextManager {
ContextMap Contexts;
LocationContextManager LocContexts;
CFG::BuildOptions cfgBuildOptions;
+
+ /// Pointer to an interface that can provide function bodies for
+ /// declarations from external source.
+ std::unique_ptr<CodeInjector> Injector;
/// Flag to indicate whether or not bodies should be synthesized
/// for well-known functions.
@@ -410,7 +423,8 @@ public:
bool addTemporaryDtors = false,
bool synthesizeBodies = false,
bool addStaticInitBranches = false,
- bool addCXXNewAllocator = true);
+ bool addCXXNewAllocator = true,
+ CodeInjector* injector = nullptr);
~AnalysisDeclContextManager();
diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h
index 33c940e7bbf0..8d28971cfe5c 100644
--- a/include/clang/Analysis/AnalysisDiagnostic.h
+++ b/include/clang/Analysis/AnalysisDiagnostic.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_DIAGNOSTICANALYSIS_H
-#define LLVM_CLANG_DIAGNOSTICANALYSIS_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSISDIAGNOSTIC_H
+#define LLVM_CLANG_ANALYSIS_ANALYSISDIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index 891fb90691f3..beea867228d6 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CFG_H
-#define LLVM_CLANG_CFG_H
+#ifndef LLVM_CLANG_ANALYSIS_CFG_H
+#define LLVM_CLANG_ANALYSIS_CFG_H
#include "clang/AST/Stmt.h"
#include "clang/Analysis/Support/BumpVector.h"
@@ -811,10 +811,9 @@ public:
ImplTy I;
};
- /// buildCFG - Builds a CFG from an AST. The responsibility to free the
- /// constructed CFG belongs to the caller.
- static CFG* buildCFG(const Decl *D, Stmt *AST, ASTContext *C,
- const BuildOptions &BO);
+ /// buildCFG - Builds a CFG from an AST.
+ static std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *AST, ASTContext *C,
+ const BuildOptions &BO);
/// createBlock - Create a new block in the CFG. The CFG owns the block;
/// the caller should not directly free it.
diff --git a/include/clang/Analysis/CFGStmtMap.h b/include/clang/Analysis/CFGStmtMap.h
index 6e8e140afb23..4dfa91df0f42 100644
--- a/include/clang/Analysis/CFGStmtMap.h
+++ b/include/clang/Analysis/CFGStmtMap.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CFGSTMTMAP_H
-#define LLVM_CLANG_CFGSTMTMAP_H
+#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTMAP_H
+#define LLVM_CLANG_ANALYSIS_CFGSTMTMAP_H
#include "clang/Analysis/CFG.h"
diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h
index 593ba575c78e..eda22a57e8a5 100644
--- a/include/clang/Analysis/CallGraph.h
+++ b/include/clang/Analysis/CallGraph.h
@@ -14,8 +14,8 @@
// edges to all externally available functions.
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH
-#define LLVM_CLANG_ANALYSIS_CALLGRAPH
+#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH_H
+#define LLVM_CLANG_ANALYSIS_CALLGRAPH_H
#include "clang/AST/DeclBase.h"
#include "clang/AST/RecursiveASTVisitor.h"
diff --git a/include/clang/Analysis/CodeInjector.h b/include/clang/Analysis/CodeInjector.h
new file mode 100644
index 000000000000..413a55b05b07
--- /dev/null
+++ b/include/clang/Analysis/CodeInjector.h
@@ -0,0 +1,46 @@
+//===-- CodeInjector.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the clang::CodeInjector interface which is responsible for
+/// injecting AST of function definitions that may not be available in the
+/// original source.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CODEINJECTOR_H
+#define LLVM_CLANG_ANALYSIS_CODEINJECTOR_H
+
+namespace clang {
+
+class Stmt;
+class FunctionDecl;
+class ObjCMethodDecl;
+
+/// \brief CodeInjector is an interface which is responsible for injecting AST
+/// of function definitions that may not be available in the original source.
+///
+/// The getBody function will be called each time the static analyzer examines a
+/// function call that has no definition available in the current translation
+/// unit. If the returned statement is not a null pointer, it is assumed to be
+/// the body of a function which will be used for the analysis. The source of
+/// the body can be arbitrary, but it is advised to use memoization to avoid
+/// unnecessary reparsing of the external source that provides the body of the
+/// functions.
+class CodeInjector {
+public:
+ CodeInjector();
+ virtual ~CodeInjector();
+
+ virtual Stmt *getBody(const FunctionDecl *D) = 0;
+ virtual Stmt *getBody(const ObjCMethodDecl *D) = 0;
+};
+}
+
+#endif
diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h
index e6a2f13a0b80..8b3fcff52d08 100644
--- a/include/clang/Analysis/DomainSpecific/CocoaConventions.h
+++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA
-#define LLVM_CLANG_ANALYSIS_DS_COCOA
+#ifndef LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_COCOACONVENTIONS_H
+#define LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_COCOACONVENTIONS_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
diff --git a/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h b/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h
index 930c2bd0925b..f9e800a4a412 100644
--- a/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h
+++ b/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN
-#define LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN
+#ifndef LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_OBJCNORETURN_H
+#define LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_OBJCNORETURN_H
#include "clang/Basic/IdentifierTable.h"
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index 57324d042908..f87271550c20 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT
-#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT
+#ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H
+#define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h
index 6d0427ba92b5..841adf64557d 100644
--- a/include/clang/Analysis/Support/BumpVector.h
+++ b/include/clang/Analysis/Support/BumpVector.h
@@ -16,8 +16,8 @@
// refactor this core logic into something common that is shared between
// the two. The main thing that is different is the allocation strategy.
-#ifndef LLVM_CLANG_BUMP_VECTOR
-#define LLVM_CLANG_BUMP_VECTOR
+#ifndef LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H
+#define LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/Allocator.h"
@@ -241,4 +241,4 @@ void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) {
}
} // end: clang namespace
-#endif // end: LLVM_CLANG_BUMP_VECTOR
+#endif
diff --git a/include/clang/Basic/ABI.h b/include/clang/Basic/ABI.h
index 9e8ef2e3ee8e..bd246792fe24 100644
--- a/include/clang/Basic/ABI.h
+++ b/include/clang/Basic/ABI.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef CLANG_BASIC_ABI_H
-#define CLANG_BASIC_ABI_H
+#ifndef LLVM_CLANG_BASIC_ABI_H
+#define LLVM_CLANG_BASIC_ABI_H
#include "llvm/Support/DataTypes.h"
@@ -24,14 +24,15 @@ namespace clang {
enum CXXCtorType {
Ctor_Complete, ///< Complete object ctor
Ctor_Base, ///< Base object ctor
- Ctor_CompleteAllocating ///< Complete object allocating ctor
+ Ctor_Comdat ///< The COMDAT used for ctors
};
/// \brief C++ destructor types.
enum CXXDtorType {
Dtor_Deleting, ///< Deleting dtor
Dtor_Complete, ///< Complete object dtor
- Dtor_Base ///< Base object dtor
+ Dtor_Base, ///< Base object dtor
+ Dtor_Comdat ///< The COMDAT used for dtors
};
/// \brief A return adjustment.
@@ -204,4 +205,4 @@ struct ThunkInfo {
} // end namespace clang
-#endif // CLANG_BASIC_ABI_H
+#endif
diff --git a/include/clang/Basic/AddressSpaces.h b/include/clang/Basic/AddressSpaces.h
index 4b1cea50f884..8dd75660c672 100644
--- a/include/clang/Basic/AddressSpaces.h
+++ b/include/clang/Basic/AddressSpaces.h
@@ -30,6 +30,7 @@ enum ID {
opencl_global = Offset,
opencl_local,
opencl_constant,
+ opencl_generic,
cuda_device,
cuda_constant,
diff --git a/include/clang/Basic/AllDiagnostics.h b/include/clang/Basic/AllDiagnostics.h
index 7304c8f673e6..18a2b8a31871 100644
--- a/include/clang/Basic/AllDiagnostics.h
+++ b/include/clang/Basic/AllDiagnostics.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ALL_DIAGNOSTICS_H
-#define LLVM_CLANG_ALL_DIAGNOSTICS_H
+#ifndef LLVM_CLANG_BASIC_ALLDIAGNOSTICS_H
+#define LLVM_CLANG_BASIC_ALLDIAGNOSTICS_H
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/CommentDiagnostic.h"
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 704a375ba291..843746111463 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -115,6 +115,10 @@ def DeclBase : AttrSubject;
def FunctionLike : SubsetSubject<DeclBase,
[{S->getFunctionType(false) != NULL}]>;
+def OpenCLKernelFunction : SubsetSubject<Function, [{
+ S->hasAttr<OpenCLKernelAttr>()
+}]>;
+
// HasFunctionProto is a more strict version of FunctionLike, so it should
// never be specified in a Subjects list along with FunctionLike (due to the
// inclusive nature of subject testing).
@@ -186,10 +190,11 @@ class Spelling<string name, string variety> {
class GNU<string name> : Spelling<name, "GNU">;
class Declspec<string name> : Spelling<name, "Declspec">;
-class CXX11<string namespace, string name> : Spelling<name, "CXX11"> {
+class CXX11<string namespace, string name, int version = 1>
+ : Spelling<name, "CXX11"> {
string Namespace = namespace;
-}
-class Keyword<string name> : Spelling<name, "Keyword">;
+ int Version = version;
+} class Keyword<string name> : Spelling<name, "Keyword">;
class Pragma<string namespace, string name> : Spelling<name, "Pragma"> {
string Namespace = namespace;
}
@@ -219,12 +224,14 @@ class SubjectList<list<AttrSubject> subjects, SubjectDiag diag = WarnDiag,
string CustomDiag = customDiag;
}
-class LangOpt<string name> {
+class LangOpt<string name, bit negated = 0> {
string Name = name;
+ bit Negated = negated;
}
def MicrosoftExt : LangOpt<"MicrosoftExt">;
def Borland : LangOpt<"Borland">;
def CUDA : LangOpt<"CUDA">;
+def COnly : LangOpt<"CPlusPlus", 1>;
// Defines targets for target-specific attributes. The list of strings should
// specify architectures for which the target applies, based off the ArchType
@@ -354,6 +361,24 @@ def Aligned : InheritableAttr {
let Documentation = [Undocumented];
}
+def AlignValue : Attr {
+ let Spellings = [
+ // Unfortunately, this is semantically an assertion, not a directive
+ // (something else must ensure the alignment), so aligned_value is a
+ // probably a better name. We might want to add an aligned_value spelling in
+ // the future (and a corresponding C++ attribute), but this can be done
+ // later once we decide if we also want them to have slightly-different
+ // semantics than Intel's align_value.
+ GNU<"align_value">
+ // Intel's compiler on Windows also supports:
+ // , Declspec<"align_value">
+ ];
+ let Args = [ExprArgument<"Alignment">];
+ let Subjects = SubjectList<[Var, TypedefName], WarnDiag,
+ "ExpectedVariableOrTypedef">;
+ let Documentation = [AlignValueDocs];
+}
+
def AlignMac68k : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
@@ -434,7 +459,8 @@ def Bounded : IgnoredAttr {
}
def CarriesDependency : InheritableParamAttr {
- let Spellings = [GNU<"carries_dependency">, CXX11<"","carries_dependency">];
+ let Spellings = [GNU<"carries_dependency">,
+ CXX11<"","carries_dependency", 200809>];
let Subjects = SubjectList<[ParmVar, ObjCMethod, Function], ErrorDiag>;
let Documentation = [CarriesDependencyDocs];
}
@@ -541,6 +567,13 @@ def CUDAHost : InheritableAttr {
let Documentation = [Undocumented];
}
+def CUDAInvalidTarget : InheritableAttr {
+ let Spellings = [];
+ let Subjects = SubjectList<[Function]>;
+ let LangOpts = [CUDA];
+ let Documentation = [Undocumented];
+}
+
def CUDALaunchBounds : InheritableAttr {
let Spellings = [GNU<"launch_bounds">];
let Args = [IntArgument<"MaxThreads">, DefaultIntArgument<"MinBlocks", 0>];
@@ -568,7 +601,7 @@ def C11NoReturn : InheritableAttr {
}
def CXX11NoReturn : InheritableAttr {
- let Spellings = [CXX11<"","noreturn">];
+ let Spellings = [CXX11<"","noreturn", 200809>];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [CXX11NoReturnDocs];
}
@@ -597,27 +630,32 @@ def OpenCLImageAccess : Attr {
def OpenCLPrivateAddressSpace : TypeAttr {
let Spellings = [Keyword<"__private">, Keyword<"private">];
- let Documentation = [Undocumented];
+ let Documentation = [OpenCLAddressSpacePrivateDocs];
}
def OpenCLGlobalAddressSpace : TypeAttr {
let Spellings = [Keyword<"__global">, Keyword<"global">];
- let Documentation = [Undocumented];
+ let Documentation = [OpenCLAddressSpaceGlobalDocs];
}
def OpenCLLocalAddressSpace : TypeAttr {
let Spellings = [Keyword<"__local">, Keyword<"local">];
- let Documentation = [Undocumented];
+ let Documentation = [OpenCLAddressSpaceLocalDocs];
}
def OpenCLConstantAddressSpace : TypeAttr {
let Spellings = [Keyword<"__constant">, Keyword<"constant">];
- let Documentation = [Undocumented];
+ let Documentation = [OpenCLAddressSpaceConstantDocs];
+}
+
+def OpenCLGenericAddressSpace : TypeAttr {
+ let Spellings = [Keyword<"__generic">, Keyword<"generic">];
+ let Documentation = [OpenCLAddressSpaceGenericDocs];
}
def Deprecated : InheritableAttr {
let Spellings = [GCC<"deprecated">, Declspec<"deprecated">,
- CXX11<"","deprecated">];
+ CXX11<"","deprecated", 201309>];
let Args = [StringArgument<"Message", 1>];
let Documentation = [Undocumented];
}
@@ -655,7 +693,7 @@ def FastCall : InheritableAttr {
let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">,
Keyword<"_fastcall">];
// let Subjects = [Function, ObjCMethod];
- let Documentation = [Undocumented];
+ let Documentation = [FastCallDocs];
}
def Final : InheritableAttr {
@@ -671,6 +709,25 @@ def MinSize : InheritableAttr {
let Documentation = [Undocumented];
}
+def FlagEnum : InheritableAttr {
+ let Spellings = [GNU<"flag_enum">];
+ let Subjects = SubjectList<[Enum]>;
+ let Documentation = [FlagEnumDocs];
+ let LangOpts = [COnly];
+ let AdditionalMembers = [{
+private:
+ llvm::APInt FlagBits;
+public:
+ llvm::APInt &getFlagBits() {
+ return FlagBits;
+ }
+
+ const llvm::APInt &getFlagBits() const {
+ return FlagBits;
+ }
+}];
+}
+
def Flatten : InheritableAttr {
let Spellings = [GCC<"flatten">];
let Subjects = SubjectList<[Function], ErrorDiag>;
@@ -754,7 +811,7 @@ def MayAlias : InheritableAttr {
def MSABI : InheritableAttr {
let Spellings = [GCC<"ms_abi">];
// let Subjects = [Function, ObjCMethod];
- let Documentation = [Undocumented];
+ let Documentation = [MSABIDocs];
}
def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> {
@@ -810,7 +867,7 @@ def NoCommon : InheritableAttr {
}
def NoDebug : InheritableAttr {
- let Spellings = [GNU<"nodebug">];
+ let Spellings = [GCC<"nodebug">];
let Documentation = [Undocumented];
}
@@ -832,6 +889,38 @@ def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
let Documentation = [Undocumented];
}
+// This is not a TargetSpecificAttr so that is silently accepted and
+// ignored on other targets as encouraged by the OpenCL spec.
+//
+// See OpenCL 1.2 6.11.5: "It is our intention that a particular
+// implementation of OpenCL be free to ignore all attributes and the
+// resulting executable binary will produce the same result."
+//
+// However, only AMD GPU targets will emit the corresponding IR
+// attribute.
+//
+// FIXME: This provides a sub-optimal error message if you attempt to
+// use this in CUDA, since CUDA does not use the same terminology.
+def AMDGPUNumVGPR : InheritableAttr {
+ let Spellings = [GNU<"amdgpu_num_vgpr">];
+ let Args = [UnsignedArgument<"NumVGPR">];
+ let Documentation = [AMDGPUNumVGPRDocs];
+
+// FIXME: This should be for OpenCLKernelFunction, but is not to
+// workaround needing to see kernel attribute before others to know if
+// this should be rejected on non-kernels.
+ let Subjects = SubjectList<[Function], ErrorDiag,
+ "ExpectedKernelFunction">;
+}
+
+def AMDGPUNumSGPR : InheritableAttr {
+ let Spellings = [GNU<"amdgpu_num_sgpr">];
+ let Args = [UnsignedArgument<"NumSGPR">];
+ let Documentation = [AMDGPUNumSGPRDocs];
+ let Subjects = SubjectList<[Function], ErrorDiag,
+ "ExpectedKernelFunction">;
+}
+
def NoSplitStack : InheritableAttr {
let Spellings = [GCC<"no_split_stack">];
let Subjects = SubjectList<[Function], ErrorDiag>;
@@ -845,11 +934,15 @@ def NonNull : InheritableAttr {
let Args = [VariadicUnsignedArgument<"Args">];
let AdditionalMembers =
[{bool isNonNull(unsigned idx) const {
+ if (!args_size())
+ return true;
for (const auto &V : args())
if (V == idx)
return true;
return false;
} }];
+ // FIXME: We should merge duplicates into a single nonnull attribute.
+ let DuplicatesAllowedWhileMerging = 1;
let Documentation = [Undocumented];
}
@@ -860,6 +953,13 @@ def ReturnsNonNull : InheritableAttr {
let Documentation = [Undocumented];
}
+def AssumeAligned : InheritableAttr {
+ let Spellings = [GCC<"assume_aligned">];
+ let Subjects = SubjectList<[ObjCMethod, Function]>;
+ let Args = [ExprArgument<"Alignment">, ExprArgument<"Offset", 1>];
+ let Documentation = [AssumeAlignedDocs];
+}
+
def NoReturn : InheritableAttr {
let Spellings = [GCC<"noreturn">, Declspec<"noreturn">];
// FIXME: Does GCC allow this on the function instead?
@@ -1068,7 +1168,7 @@ def Pure : InheritableAttr {
def Regparm : TypeAttr {
let Spellings = [GCC<"regparm">];
let Args = [UnsignedArgument<"NumParams">];
- let Documentation = [Undocumented];
+ let Documentation = [RegparmDocs];
}
def ReqdWorkGroupSize : InheritableAttr {
@@ -1115,7 +1215,7 @@ def Sentinel : InheritableAttr {
def StdCall : InheritableAttr {
let Spellings = [GCC<"stdcall">, Keyword<"__stdcall">, Keyword<"_stdcall">];
// let Subjects = [Function, ObjCMethod];
- let Documentation = [Undocumented];
+ let Documentation = [StdCallDocs];
}
def SysVABI : InheritableAttr {
@@ -1128,7 +1228,14 @@ def ThisCall : InheritableAttr {
let Spellings = [GCC<"thiscall">, Keyword<"__thiscall">,
Keyword<"_thiscall">];
// let Subjects = [Function, ObjCMethod];
- let Documentation = [Undocumented];
+ let Documentation = [ThisCallDocs];
+}
+
+def VectorCall : InheritableAttr {
+ let Spellings = [GNU<"vectorcall">, Keyword<"__vectorcall">,
+ Keyword<"_vectorcall">];
+// let Subjects = [Function, ObjCMethod];
+ let Documentation = [VectorCallDocs];
}
def Pascal : InheritableAttr {
@@ -1784,14 +1891,21 @@ def Unaligned : IgnoredAttr {
}
def LoopHint : Attr {
- /// vectorize: vectorizes loop operations if 'value != 0'.
- /// vectorize_width: vectorize loop operations with width 'value'.
- /// interleave: interleave multiple loop iterations if 'value != 0'.
- /// interleave_count: interleaves 'value' loop interations.
- /// unroll: unroll loop if 'value != 0'.
- /// unroll_count: unrolls loop 'value' times.
-
- let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">];
+ /// #pragma clang loop <option> directive
+ /// vectorize: vectorizes loop operations if State == Enable.
+ /// vectorize_width: vectorize loop operations with width 'Value'.
+ /// interleave: interleave multiple loop iterations if State == Enable.
+ /// interleave_count: interleaves 'Value' loop interations.
+ /// unroll: fully unroll loop if State == Enable.
+ /// unroll_count: unrolls loop 'Value' times.
+
+ /// #pragma unroll <argument> directive
+ /// <no arg>: fully unrolls loop.
+ /// boolean: fully unrolls loop if State == Enable.
+ /// expression: unrolls loop 'Value' times.
+
+ let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">,
+ Pragma<"", "nounroll">];
/// State of the loop optimization specified by the spelling.
let Args = [EnumArgument<"Option", "OptionType",
@@ -1799,10 +1913,13 @@ def LoopHint : Attr {
"unroll", "unroll_count"],
["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount",
"Unroll", "UnrollCount"]>,
- DefaultIntArgument<"Value", 1>];
+ EnumArgument<"State", "LoopHintState",
+ ["default", "enable", "disable"],
+ ["Default", "Enable", "Disable"]>,
+ ExprArgument<"Value">];
let AdditionalMembers = [{
- static StringRef getOptionName(int Option) {
+ static const char *getOptionName(int Option) {
switch(Option) {
case Vectorize: return "vectorize";
case VectorizeWidth: return "vectorize_width";
@@ -1814,59 +1931,68 @@ def LoopHint : Attr {
llvm_unreachable("Unhandled LoopHint option.");
}
- static StringRef getValueName(int Value) {
- if (Value)
- return "enable";
- return "disable";
- }
-
void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {
unsigned SpellingIndex = getSpellingListIndex();
- if (SpellingIndex == Pragma_unroll) {
- // String "unroll" of "#pragma unroll" is already emitted as the
- // pragma name.
- if (option == UnrollCount)
- printArgument(OS);
+ // For "#pragma unroll" and "#pragma nounroll" the string "unroll" or
+ // "nounroll" is already emitted as the pragma name.
+ if (SpellingIndex == Pragma_nounroll) {
OS << "\n";
return;
}
+ else if (SpellingIndex == Pragma_unroll) {
+ OS << getValueString(Policy) << "\n";
+ return;
+ }
+
assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
- OS << getOptionName(option);
- printArgument(OS);
- OS << "\n";
+ OS << getOptionName(option) << getValueString(Policy) << "\n";
}
- // Prints the loop hint argument including the enclosing parentheses to OS.
- void printArgument(raw_ostream &OS) const {
+ // Return a string containing the loop hint argument including the
+ // enclosing parentheses.
+ std::string getValueString(const PrintingPolicy &Policy) const {
+ std::string ValueName;
+ llvm::raw_string_ostream OS(ValueName);
OS << "(";
if (option == VectorizeWidth || option == InterleaveCount ||
option == UnrollCount)
- OS << value;
- else if (value)
- OS << "enable";
+ value->printPretty(OS, nullptr, Policy);
+ else if (state == Default)
+ return "";
+ else if (state == Enable)
+ OS << (option == Unroll ? "full" : "enable");
else
OS << "disable";
OS << ")";
+ return OS.str();
}
// Return a string suitable for identifying this attribute in diagnostics.
- std::string getDiagnosticName() const {
- std::string DiagnosticName;
- llvm::raw_string_ostream OS(DiagnosticName);
+ std::string getDiagnosticName(const PrintingPolicy &Policy) const {
unsigned SpellingIndex = getSpellingListIndex();
- if (SpellingIndex == Pragma_unroll && option == Unroll)
- OS << "#pragma unroll";
- else if (SpellingIndex == Pragma_unroll && option == UnrollCount) {
- OS << "#pragma unroll";
- printArgument(OS);
- } else {
- assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
- OS << getOptionName(option);
- printArgument(OS);
- }
- return OS.str();
+ if (SpellingIndex == Pragma_nounroll)
+ return "#pragma nounroll";
+ else if (SpellingIndex == Pragma_unroll)
+ return "#pragma unroll" + getValueString(Policy);
+
+ assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
+ return getOptionName(option) + getValueString(Policy);
}
}];
let Documentation = [LoopHintDocs, UnrollHintDocs];
}
+
+def CapturedRecord : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let SemaHandler = 0;
+ let Documentation = [Undocumented];
+}
+
+def OMPThreadPrivateDecl : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let SemaHandler = 0;
+ let Documentation = [Undocumented];
+}
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index e6d6a33d3b5d..918abb6072ea 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -72,9 +72,9 @@ def ThreadDocs : Documentation {
let Content = [{
The ``__declspec(thread)`` attribute declares a variable with thread local
storage. It is available under the ``-fms-extensions`` flag for MSVC
-compatibility. Documentation for the Visual C++ attribute is available on MSDN_.
+compatibility. See the documentation for `__declspec(thread)`_ on MSDN.
-.. _MSDN: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx
+.. _`__declspec(thread)`: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx
In Clang, ``__declspec(thread)`` is generally equivalent in functionality to the
GNU ``__thread`` keyword. The variable must not have a destructor and must have
@@ -154,6 +154,30 @@ def ReleaseCapabilityDocs : Documentation {
Marks a function as releasing a capability.
}];
}
+
+def AssumeAlignedDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Use ``__attribute__((assume_aligned(<alignment>[,<offset>]))`` on a function
+declaration to specify that the return value of the function (which must be a
+pointer type) has the specified offset, in bytes, from an address with the
+specified alignment. The offset is taken to be zero if omitted.
+
+.. code-block:: c++
+
+ // The returned pointer value has 32-byte alignment.
+ void *a() __attribute__((assume_aligned (32)));
+
+ // The returned pointer value is 4 bytes greater than an address having
+ // 32-byte alignment.
+ void *b() __attribute__((assume_aligned (32, 4)));
+
+Note that this attribute provides information to the compiler regarding a
+condition that the code already ensures is true. It does not cause the compiler
+to enforce the provided alignment assumption.
+ }];
+}
+
def EnableIfDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -649,15 +673,180 @@ The semantics are as follows:
}];
}
+def DocCatAMDGPURegisterAttributes :
+ DocumentationCategory<"AMD GPU Register Attributes"> {
+ let Content = [{
+Clang supports attributes for controlling register usage on AMD GPU
+targets. These attributes may be attached to a kernel function
+definition and is an optimization hint to the backend for the maximum
+number of registers to use. This is useful in cases where register
+limited occupancy is known to be an important factor for the
+performance for the kernel.
+
+The semantics are as follows:
+
+- The backend will attempt to limit the number of used registers to
+ the specified value, but the exact number used is not
+ guaranteed. The number used may be rounded up to satisfy the
+ allocation requirements or ABI constraints of the subtarget. For
+ example, on Southern Islands VGPRs may only be allocated in
+ increments of 4, so requesting a limit of 39 VGPRs will really
+ attempt to use up to 40. Requesting more registers than the
+ subtarget supports will truncate to the maximum allowed. The backend
+ may also use fewer registers than requested whenever possible.
+
+- 0 implies the default no limit on register usage.
+
+- Ignored on older VLIW subtargets which did not have separate scalar
+ and vector registers, R600 through Northern Islands.
+
+}];
+}
+
+
+def AMDGPUNumVGPRDocs : Documentation {
+ let Category = DocCatAMDGPURegisterAttributes;
+ let Content = [{
+Clang supports the
+``__attribute__((amdgpu_num_vgpr(<num_registers>)))`` attribute on AMD
+Southern Islands GPUs and later for controlling the number of vector
+registers. A typical value would be between 4 and 256 in increments
+of 4.
+}];
+}
+
+def AMDGPUNumSGPRDocs : Documentation {
+ let Category = DocCatAMDGPURegisterAttributes;
+ let Content = [{
+
+Clang supports the
+``__attribute__((amdgpu_num_sgpr(<num_registers>)))`` attribute on AMD
+Southern Islands GPUs and later for controlling the number of scalar
+registers. A typical value would be between 8 and 104 in increments of
+8.
+
+Due to common instruction constraints, an additional 2-4 SGPRs are
+typically required for internal use depending on features used. This
+value is a hint for the total number of SGPRs to use, and not the
+number of user SGPRs, so no special consideration needs to be given
+for these.
+}];
+}
+
+def DocCatCallingConvs : DocumentationCategory<"Calling Conventions"> {
+ let Content = [{
+Clang supports several different calling conventions, depending on the target
+platform and architecture. The calling convention used for a function determines
+how parameters are passed, how results are returned to the caller, and other
+low-level details of calling a function.
+ }];
+}
+
def PcsDocs : Documentation {
- let Category = DocCatFunction;
+ let Category = DocCatCallingConvs;
let Content = [{
-On ARM targets, this can attribute can be used to select calling conventions,
+On ARM targets, this attribute can be used to select calling conventions
similar to ``stdcall`` on x86. Valid parameter values are "aapcs" and
"aapcs-vfp".
}];
}
+def RegparmDocs : Documentation {
+ let Category = DocCatCallingConvs;
+ let Content = [{
+On 32-bit x86 targets, the regparm attribute causes the compiler to pass
+the first three integer parameters in EAX, EDX, and ECX instead of on the
+stack. This attribute has no effect on variadic functions, and all parameters
+are passed via the stack as normal.
+ }];
+}
+
+def SysVABIDocs : Documentation {
+ let Category = DocCatCallingConvs;
+ let Content = [{
+On Windows x86_64 targets, this attribute changes the calling convention of a
+function to match the default convention used on Sys V targets such as Linux,
+Mac, and BSD. This attribute has no effect on other targets.
+ }];
+}
+
+def MSABIDocs : Documentation {
+ let Category = DocCatCallingConvs;
+ let Content = [{
+On non-Windows x86_64 targets, this attribute changes the calling convention of
+a function to match the default convention used on Windows x86_64. This
+attribute has no effect on Windows targets or non-x86_64 targets.
+ }];
+}
+
+def StdCallDocs : Documentation {
+ let Category = DocCatCallingConvs;
+ let Content = [{
+On 32-bit x86 targets, this attribute changes the calling convention of a
+function to clear parameters off of the stack on return. This convention does
+not support variadic calls or unprototyped functions in C, and has no effect on
+x86_64 targets. This calling convention is used widely by the Windows API and
+COM applications. See the documentation for `__stdcall`_ on MSDN.
+
+.. _`__stdcall`: http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx
+ }];
+}
+
+def FastCallDocs : Documentation {
+ let Category = DocCatCallingConvs;
+ let Content = [{
+On 32-bit x86 targets, this attribute changes the calling convention of a
+function to use ECX and EDX as register parameters and clear parameters off of
+the stack on return. This convention does not support variadic calls or
+unprototyped functions in C, and has no effect on x86_64 targets. This calling
+convention is supported primarily for compatibility with existing code. Users
+seeking register parameters should use the ``regparm`` attribute, which does
+not require callee-cleanup. See the documentation for `__fastcall`_ on MSDN.
+
+.. _`__fastcall`: http://msdn.microsoft.com/en-us/library/6xa169sk.aspx
+ }];
+}
+
+def ThisCallDocs : Documentation {
+ let Category = DocCatCallingConvs;
+ let Content = [{
+On 32-bit x86 targets, this attribute changes the calling convention of a
+function to use ECX for the first parameter (typically the implicit ``this``
+parameter of C++ methods) and clear parameters off of the stack on return. This
+convention does not support variadic calls or unprototyped functions in C, and
+has no effect on x86_64 targets. See the documentation for `__thiscall`_ on
+MSDN.
+
+.. _`__thiscall`: http://msdn.microsoft.com/en-us/library/ek8tkfbw.aspx
+ }];
+}
+
+def VectorCallDocs : Documentation {
+ let Category = DocCatCallingConvs;
+ let Content = [{
+On 32-bit x86 *and* x86_64 targets, this attribute changes the calling
+convention of a function to pass vector parameters in SSE registers.
+
+On 32-bit x86 targets, this calling convention is similar to ``__fastcall``.
+The first two integer parameters are passed in ECX and EDX. Subsequent integer
+parameters are passed in memory, and callee clears the stack. On x86_64
+targets, the callee does *not* clear the stack, and integer parameters are
+passed in RCX, RDX, R8, and R9 as is done for the default Windows x64 calling
+convention.
+
+On both 32-bit x86 and x86_64 targets, vector and floating point arguments are
+passed in XMM0-XMM5. Homogenous vector aggregates of up to four elements are
+passed in sequential SSE registers if enough are available. If AVX is enabled,
+256 bit vectors are passed in YMM0-YMM5. Any vector or aggregate type that
+cannot be passed in registers for any reason is passed by reference, which
+allows the caller to align the parameter memory.
+
+See the documentation for `__vectorcall`_ on MSDN for more details.
+
+.. _`__vectorcall`: http://msdn.microsoft.com/en-us/library/dn375768.aspx
+ }];
+}
+
def DocCatConsumed : DocumentationCategory<"Consumed Annotation Checking"> {
let Content = [{
Clang supports additional attributes for checking basic resource management
@@ -987,6 +1176,36 @@ Clang implements two kinds of checks with this attribute.
}];
}
+def AlignValueDocs : Documentation {
+ let Category = DocCatType;
+ let Content = [{
+The align_value attribute can be added to the typedef of a pointer type or the
+declaration of a variable of pointer or reference type. It specifies that the
+pointer will point to, or the reference will bind to, only objects with at
+least the provided alignment. This alignment value must be some positive power
+of 2.
+
+ .. code-block:: c
+
+ typedef double * aligned_double_ptr __attribute__((align_value(64)));
+ void foo(double & x __attribute__((align_value(128)),
+ aligned_double_ptr y) { ... }
+
+If the pointer value does not have the specified alignment at runtime, the
+behavior of the program is undefined.
+ }];
+}
+
+def FlagEnumDocs : Documentation {
+ let Category = DocCatType;
+ let Content = [{
+This attribute can be added to an enumerator to signal to the compiler that it
+is intended to be used as a flag type. This will cause the compiler to assume
+that the range of the type includes all of the values that you can get by
+manipulating bits of the enumerator when issuing warnings.
+ }];
+}
+
def MSInheritanceDocs : Documentation {
let Category = DocCatType;
let Heading = "__single_inhertiance, __multiple_inheritance, __virtual_inheritance";
@@ -1045,12 +1264,14 @@ entire application without optimization. Avoiding optimization on the
specified function can improve the quality of the debugging information
for that function.
-This attribute is incompatible with the ``always_inline`` attribute.
+This attribute is incompatible with the ``always_inline`` and ``minsize``
+attributes.
}];
}
def LoopHintDocs : Documentation {
let Category = DocCatStmt;
+ let Heading = "#pragma clang loop";
let Content = [{
The ``#pragma clang loop`` directive allows loop optimization hints to be
specified for the subsequent loop. The directive allows vectorization,
@@ -1064,10 +1285,11 @@ for details.
def UnrollHintDocs : Documentation {
let Category = DocCatStmt;
+ let Heading = "#pragma unroll, #pragma nounroll";
let Content = [{
-Loop unrolling optimization hints can be specified with ``#pragma unroll``. The
-pragma is placed immediately before a for, while, do-while, or c++11 range-based
-for loop.
+Loop unrolling optimization hints can be specified with ``#pragma unroll`` and
+``#pragma nounroll``. The pragma is placed immediately before a for, while,
+do-while, or c++11 range-based for loop.
Specifying ``#pragma unroll`` without a parameter directs the loop unroller to
attempt to fully unroll the loop if the trip count is known at compile time:
@@ -1095,11 +1317,107 @@ enclosed in parentheses:
...
}
+Specifying ``#pragma nounroll`` indicates that the loop should not be unrolled:
+
+.. code-block:: c++
+
+ #pragma nounroll
+ for (...) {
+ ...
+ }
+
``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to
-``#pragma clang loop unroll(enable)`` and ``#pragma clang loop
-unroll_count(_value_)`` respectively. See `language extensions
+``#pragma clang loop unroll(full)`` and
+``#pragma clang loop unroll_count(_value_)`` respectively. ``#pragma nounroll``
+is equivalent to ``#pragma clang loop unroll(disable)``. See
+`language extensions
<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_
for further details including limitations of the unroll hints.
}];
}
+def DocOpenCLAddressSpaces : DocumentationCategory<"OpenCL Address Spaces"> {
+ let Content = [{
+The address space qualifier may be used to specify the region of memory that is
+used to allocate the object. OpenCL supports the following address spaces:
+__generic(generic), __global(global), __local(local), __private(private),
+__constant(constant).
+
+ .. code-block:: c
+
+ __constant int c = ...;
+
+ __generic int* foo(global int* g) {
+ __local int* l;
+ private int p;
+ ...
+ return l;
+ }
+
+More details can be found in the OpenCL C language Spec v2.0, Section 6.5.
+ }];
+}
+
+def OpenCLAddressSpaceGenericDocs : Documentation {
+ let Category = DocOpenCLAddressSpaces;
+ let Heading = "__generic(generic)";
+ let Content = [{
+The generic address space attribute is only available with OpenCL v2.0 and later.
+It can be used with pointer types. Variables in global and local scope and
+function parameters in non-kernel functions can have the generic address space
+type attribute. It is intended to be a placeholder for any other address space
+except for '__constant' in OpenCL code which can be used with multiple address
+spaces.
+ }];
+}
+
+def OpenCLAddressSpaceConstantDocs : Documentation {
+ let Category = DocOpenCLAddressSpaces;
+ let Heading = "__constant(constant)";
+ let Content = [{
+The constant address space attribute signals that an object is located in
+a constant (non-modifiable) memory region. It is available to all work items.
+Any type can be annotated with the constant address space attribute. Objects
+with the constant address space qualifier can be declared in any scope and must
+have an initializer.
+ }];
+}
+
+def OpenCLAddressSpaceGlobalDocs : Documentation {
+ let Category = DocOpenCLAddressSpaces;
+ let Heading = "__global(global)";
+ let Content = [{
+The global address space attribute specifies that an object is allocated in
+global memory, which is accessible by all work items. The content stored in this
+memory area persists between kernel executions. Pointer types to the global
+address space are allowed as function parameters or local variables. Starting
+with OpenCL v2.0, the global address space can be used with global (program
+scope) variables and static local variable as well.
+ }];
+}
+
+def OpenCLAddressSpaceLocalDocs : Documentation {
+ let Category = DocOpenCLAddressSpaces;
+ let Heading = "__local(local)";
+ let Content = [{
+The local address space specifies that an object is allocated in the local (work
+group) memory area, which is accessible to all work items in the same work
+group. The content stored in this memory region is not accessible after
+the kernel execution ends. In a kernel function scope, any variable can be in
+the local address space. In other scopes, only pointer types to the local address
+space are allowed. Local address space variables cannot have an initializer.
+ }];
+}
+
+def OpenCLAddressSpacePrivateDocs : Documentation {
+ let Category = DocOpenCLAddressSpaces;
+ let Heading = "__private(private)";
+ let Content = [{
+The private address space specifies that an object is allocated in the private
+(work item) memory. Other work items cannot access the same memory area and its
+content is destroyed after work item execution ends. Local variables can be
+declared in the private address space. Function arguments are always in the
+private address space. Kernel function arguments of a pointer or an array type
+cannot point to the private address space.
+ }];
+}
diff --git a/include/clang/Basic/AttrKinds.h b/include/clang/Basic/AttrKinds.h
index 150a30e73d3f..f0b0a6445d40 100644
--- a/include/clang/Basic/AttrKinds.h
+++ b/include/clang/Basic/AttrKinds.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ATTRKINDS_H
-#define LLVM_CLANG_ATTRKINDS_H
+#ifndef LLVM_CLANG_BASIC_ATTRKINDS_H
+#define LLVM_CLANG_BASIC_ATTRKINDS_H
namespace clang {
diff --git a/include/clang/Basic/Attributes.h b/include/clang/Basic/Attributes.h
index 5783b3bff510..a64dd5666b73 100644
--- a/include/clang/Basic/Attributes.h
+++ b/include/clang/Basic/Attributes.h
@@ -10,16 +10,14 @@
#ifndef LLVM_CLANG_BASIC_ATTRIBUTES_H
#define LLVM_CLANG_BASIC_ATTRIBUTES_H
-#include "llvm/ADT/Triple.h"
#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/Triple.h"
namespace clang {
class IdentifierInfo;
enum class AttrSyntax {
- /// Is the attribute identifier generally known for any syntax?
- Generic,
/// Is the identifier known as a GNU-style attribute?
GNU,
/// Is the identifier known as a __declspec-style attribute?
@@ -30,11 +28,11 @@ enum class AttrSyntax {
Pragma
};
-/// \brief Return true if we recognize and implement the attribute specified by
-/// the given information.
-bool hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
- const IdentifierInfo *Attr, const llvm::Triple &T,
- const LangOptions &LangOpts);
+/// \brief Return the version number associated with the attribute if we
+/// recognize and implement the attribute specified by the given information.
+int hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
+ const IdentifierInfo *Attr, const llvm::Triple &T,
+ const LangOptions &LangOpts);
} // end namespace clang
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index e705382e11ca..098f5dacacbd 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -412,6 +412,7 @@ BUILTIN(__builtin_va_start, "vA.", "nt")
BUILTIN(__builtin_va_end, "vA", "n")
BUILTIN(__builtin_va_copy, "vAA", "n")
BUILTIN(__builtin_stdarg_start, "vA.", "n")
+BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nc")
BUILTIN(__builtin_bcmp, "iv*v*z", "n")
BUILTIN(__builtin_bcopy, "vv*v*z", "n")
BUILTIN(__builtin_bzero, "vv*z", "nF")
@@ -496,6 +497,7 @@ BUILTIN(__builtin_unreachable, "v", "nr")
BUILTIN(__builtin_shufflevector, "v." , "nc")
BUILTIN(__builtin_convertvector, "v." , "nct")
BUILTIN(__builtin_alloca, "v*z" , "n")
+BUILTIN(__builtin_call_with_static_chain, "v.", "nt")
// "Overloaded" Atomic operator builtins. These are overloaded to support data
// types of i8, i16, i32, i64, and i128. The front-end sees calls to the
@@ -540,6 +542,12 @@ BUILTIN(__sync_fetch_and_xor_4, "iiD*i.", "tn")
BUILTIN(__sync_fetch_and_xor_8, "LLiLLiD*LLi.", "tn")
BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLiD*LLLi.", "tn")
+BUILTIN(__sync_fetch_and_nand, "v.", "t")
+BUILTIN(__sync_fetch_and_nand_1, "ccD*c.", "tn")
+BUILTIN(__sync_fetch_and_nand_2, "ssD*s.", "tn")
+BUILTIN(__sync_fetch_and_nand_4, "iiD*i.", "tn")
+BUILTIN(__sync_fetch_and_nand_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_fetch_and_nand_16, "LLLiLLLiD*LLLi.", "tn")
BUILTIN(__sync_add_and_fetch, "v.", "t")
BUILTIN(__sync_add_and_fetch_1, "ccD*c.", "tn")
@@ -576,6 +584,13 @@ BUILTIN(__sync_xor_and_fetch_4, "iiD*i.", "tn")
BUILTIN(__sync_xor_and_fetch_8, "LLiLLiD*LLi.", "tn")
BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLiD*LLLi.", "tn")
+BUILTIN(__sync_nand_and_fetch, "v.", "t")
+BUILTIN(__sync_nand_and_fetch_1, "ccD*c.", "tn")
+BUILTIN(__sync_nand_and_fetch_2, "ssD*s.", "tn")
+BUILTIN(__sync_nand_and_fetch_4, "iiD*i.", "tn")
+BUILTIN(__sync_nand_and_fetch_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLiD*LLLi.", "tn")
+
BUILTIN(__sync_bool_compare_and_swap, "v.", "t")
BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "tn")
BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "tn")
@@ -689,6 +704,7 @@ LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES)
// C99 library functions
// C99 stdlib.h
@@ -1173,6 +1189,9 @@ LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
// Annotation function
BUILTIN(__builtin_annotation, "v.", "tn")
+// Invariants
+BUILTIN(__builtin_assume, "vb", "n")
+
// Multiprecision Arithmetic Builtins.
BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n")
BUILTIN(__builtin_addcs, "UsUsCUsCUsCUs*", "n")
diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h
index f9d30e40560a..3ce2255c8646 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -29,7 +29,7 @@ namespace clang {
class ASTContext;
class QualType;
class LangOptions;
-
+
enum LanguageID {
GNU_LANG = 0x1, // builtin requires GNU mode.
C_LANG = 0x2, // builtin for c only.
@@ -40,7 +40,7 @@ namespace clang {
ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode.
ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode.
};
-
+
namespace Builtin {
enum ID {
NotBuiltin = 0, // This is not a builtin function.
diff --git a/include/clang/Basic/BuiltinsAArch64.def b/include/clang/Basic/BuiltinsAArch64.def
index 695ecf9da5f8..9d223c3e8516 100644
--- a/include/clang/Basic/BuiltinsAArch64.def
+++ b/include/clang/Basic/BuiltinsAArch64.def
@@ -50,4 +50,7 @@ BUILTIN(__builtin_arm_dmb, "vUi", "nc")
BUILTIN(__builtin_arm_dsb, "vUi", "nc")
BUILTIN(__builtin_arm_isb, "vUi", "nc")
+// Prefetch
+BUILTIN(__builtin_arm_prefetch, "vvC*UiUiUiUi", "nc")
+
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def
index 2e5eac694fc2..9091ad4d7581 100644
--- a/include/clang/Basic/BuiltinsARM.def
+++ b/include/clang/Basic/BuiltinsARM.def
@@ -74,13 +74,19 @@ BUILTIN(__builtin_arm_wfe, "v", "")
BUILTIN(__builtin_arm_wfi, "v", "")
BUILTIN(__builtin_arm_sev, "v", "")
BUILTIN(__builtin_arm_sevl, "v", "")
+BUILTIN(__builtin_arm_dbg, "vUi", "")
// Data barrier
BUILTIN(__builtin_arm_dmb, "vUi", "nc")
BUILTIN(__builtin_arm_dsb, "vUi", "nc")
BUILTIN(__builtin_arm_isb, "vUi", "nc")
+// Prefetch
+BUILTIN(__builtin_arm_prefetch, "vvC*UiUi", "nc")
+
// MSVC
+LANGBUILTIN(__emit, "vIUiC", "", ALL_MS_LANGUAGES)
+
LANGBUILTIN(__yield, "v", "", ALL_MS_LANGUAGES)
LANGBUILTIN(__wfe, "v", "", ALL_MS_LANGUAGES)
LANGBUILTIN(__wfi, "v", "", ALL_MS_LANGUAGES)
diff --git a/include/clang/Basic/BuiltinsLe64.def b/include/clang/Basic/BuiltinsLe64.def
new file mode 100644
index 000000000000..532860603c29
--- /dev/null
+++ b/include/clang/Basic/BuiltinsLe64.def
@@ -0,0 +1,19 @@
+//==- BuiltinsLe64.def - Le64 Builtin function 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 defines the Le64-specific builtin function database. Users of this
+// file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// The format of this database matches clang/Basic/Builtins.def.
+
+BUILTIN(__clear_cache, "vv*v*", "i")
+
+#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsNVPTX.def b/include/clang/Basic/BuiltinsNVPTX.def
index 7e9b5eea8325..9c920dce5cab 100644
--- a/include/clang/Basic/BuiltinsNVPTX.def
+++ b/include/clang/Basic/BuiltinsNVPTX.def
@@ -139,8 +139,8 @@ BUILTIN(__nvvm_brev64, "ULLiULLi", "")
// Sad
-BUILTIN(__nvvm_sad_i, "iii", "")
-BUILTIN(__nvvm_sad_ui, "UiUiUi", "")
+BUILTIN(__nvvm_sad_i, "iiii", "")
+BUILTIN(__nvvm_sad_ui, "UiUiUiUi", "")
// Floor, Ceil
@@ -255,19 +255,19 @@ BUILTIN(__nvvm_rsqrt_approx_d, "dd", "")
// Add
-BUILTIN(__nvvm_add_rn_ftz_f, "ff", "")
-BUILTIN(__nvvm_add_rn_f, "ff", "")
-BUILTIN(__nvvm_add_rz_ftz_f, "ff", "")
-BUILTIN(__nvvm_add_rz_f, "ff", "")
-BUILTIN(__nvvm_add_rm_ftz_f, "ff", "")
-BUILTIN(__nvvm_add_rm_f, "ff", "")
-BUILTIN(__nvvm_add_rp_ftz_f, "ff", "")
-BUILTIN(__nvvm_add_rp_f, "ff", "")
-
-BUILTIN(__nvvm_add_rn_d, "dd", "")
-BUILTIN(__nvvm_add_rz_d, "dd", "")
-BUILTIN(__nvvm_add_rm_d, "dd", "")
-BUILTIN(__nvvm_add_rp_d, "dd", "")
+BUILTIN(__nvvm_add_rn_ftz_f, "fff", "")
+BUILTIN(__nvvm_add_rn_f, "fff", "")
+BUILTIN(__nvvm_add_rz_ftz_f, "fff", "")
+BUILTIN(__nvvm_add_rz_f, "fff", "")
+BUILTIN(__nvvm_add_rm_ftz_f, "fff", "")
+BUILTIN(__nvvm_add_rm_f, "fff", "")
+BUILTIN(__nvvm_add_rp_ftz_f, "fff", "")
+BUILTIN(__nvvm_add_rp_f, "fff", "")
+
+BUILTIN(__nvvm_add_rn_d, "ddd", "")
+BUILTIN(__nvvm_add_rz_d, "ddd", "")
+BUILTIN(__nvvm_add_rm_d, "ddd", "")
+BUILTIN(__nvvm_add_rp_d, "ddd", "")
// Convert
diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def
index 8a751e4ce846..e42af4244160 100644
--- a/include/clang/Basic/BuiltinsPPC.def
+++ b/include/clang/Basic/BuiltinsPPC.def
@@ -204,6 +204,25 @@ BUILTIN(__builtin_altivec_vcmpgtsw_p, "iiV4SiV4Si", "")
BUILTIN(__builtin_altivec_vcmpgtuw_p, "iiV4UiV4Ui", "")
BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "")
+// VSX built-ins.
+
+BUILTIN(__builtin_vsx_lxvd2x, "V2divC*", "")
+BUILTIN(__builtin_vsx_lxvw4x, "V4iivC*", "")
+
+BUILTIN(__builtin_vsx_stxvd2x, "vV2div*", "")
+BUILTIN(__builtin_vsx_stxvw4x, "vV4iiv*", "")
+
+BUILTIN(__builtin_vsx_xvmaxdp, "V2dV2dV2d", "")
+BUILTIN(__builtin_vsx_xvmaxsp, "V4fV4fV4f", "")
+BUILTIN(__builtin_vsx_xsmaxdp, "ddd", "")
+
+BUILTIN(__builtin_vsx_xvmindp, "V2dV2dV2d", "")
+BUILTIN(__builtin_vsx_xvminsp, "V4fV4fV4f", "")
+BUILTIN(__builtin_vsx_xsmindp, "ddd", "")
+
+BUILTIN(__builtin_vsx_xvdivdp, "V2dV2dV2d", "")
+BUILTIN(__builtin_vsx_xvdivsp, "V4fV4fV4f", "")
+
// FIXME: Obviously incomplete.
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsR600.def b/include/clang/Basic/BuiltinsR600.def
index 49135ccb056d..84fc4fae4eab 100644
--- a/include/clang/Basic/BuiltinsR600.def
+++ b/include/clang/Basic/BuiltinsR600.def
@@ -16,8 +16,8 @@
BUILTIN(__builtin_amdgpu_div_scale, "dddbb*", "n")
BUILTIN(__builtin_amdgpu_div_scalef, "fffbb*", "n")
-BUILTIN(__builtin_amdgpu_div_fmas, "dddd", "nc")
-BUILTIN(__builtin_amdgpu_div_fmasf, "ffff", "nc")
+BUILTIN(__builtin_amdgpu_div_fmas, "ddddb", "nc")
+BUILTIN(__builtin_amdgpu_div_fmasf, "ffffb", "nc")
BUILTIN(__builtin_amdgpu_div_fixup, "dddd", "nc")
BUILTIN(__builtin_amdgpu_div_fixupf, "ffff", "nc")
BUILTIN(__builtin_amdgpu_trig_preop, "ddi", "nc")
@@ -28,5 +28,9 @@ BUILTIN(__builtin_amdgpu_rsq, "dd", "nc")
BUILTIN(__builtin_amdgpu_rsqf, "ff", "nc")
BUILTIN(__builtin_amdgpu_rsq_clamped, "dd", "nc")
BUILTIN(__builtin_amdgpu_rsq_clampedf, "ff", "nc")
+BUILTIN(__builtin_amdgpu_ldexp, "ddi", "nc")
+BUILTIN(__builtin_amdgpu_ldexpf, "ffi", "nc")
+BUILTIN(__builtin_amdgpu_class, "bdi", "nc")
+BUILTIN(__builtin_amdgpu_classf, "bfi", "nc")
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 1f377a8ab1de..eb6803b141b7 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -187,13 +187,45 @@ BUILTIN(__builtin_ia32_ucomisdgt, "iV2dV2d", "")
BUILTIN(__builtin_ia32_ucomisdge, "iV2dV2d", "")
BUILTIN(__builtin_ia32_ucomisdneq, "iV2dV2d", "")
BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fIc", "")
+BUILTIN(__builtin_ia32_cmpeqps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpltps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpleps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpunordps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpneqps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpnltps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpnleps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpordps, "V4fV4fV4f", "")
BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fIc", "")
+BUILTIN(__builtin_ia32_cmpeqss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpltss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpless, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpunordss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpneqss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpnltss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpnless, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpordss, "V4fV4fV4f", "")
BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "")
BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "")
BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "")
BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "")
BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dIc", "")
+BUILTIN(__builtin_ia32_cmpeqpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpltpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmplepd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpunordpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpneqpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpnltpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpnlepd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpordpd, "V2dV2dV2d", "")
BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dIc", "")
+BUILTIN(__builtin_ia32_cmpeqsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpltsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmplesd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpunordsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpneqsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpnltsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpnlesd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmpordsd, "V2dV2dV2d", "")
BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "")
BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "")
BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "")
@@ -303,12 +335,12 @@ BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "")
BUILTIN(__builtin_ia32_mwait, "vUiUi", "")
BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "")
BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cIc", "")
-BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "")
+BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fIc", "")
BUILTIN(__builtin_ia32_pblendvb128, "V16cV16cV16cV16c", "")
-BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8sIi", "")
-BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2dIi", "")
-BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fIi", "")
+BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8sIc", "")
+BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2dIc", "")
+BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fIc", "")
BUILTIN(__builtin_ia32_blendvpd, "V2dV2dV2dV2d", "")
BUILTIN(__builtin_ia32_blendvps, "V4fV4fV4fV4f", "")
@@ -339,13 +371,13 @@ BUILTIN(__builtin_ia32_roundps, "V4fV4fi", "")
BUILTIN(__builtin_ia32_roundss, "V4fV4fV4fi", "")
BUILTIN(__builtin_ia32_roundsd, "V2dV2dV2di", "")
BUILTIN(__builtin_ia32_roundpd, "V2dV2di", "")
-BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fi", "")
-BUILTIN(__builtin_ia32_dppd, "V2dV2dV2di", "")
+BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fIc", "")
+BUILTIN(__builtin_ia32_dppd, "V2dV2dV2dIc", "")
BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLi*", "")
BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "")
-BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16ci", "")
+BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16cIc", "")
BUILTIN(__builtin_ia32_phminposuw128, "V8sV8s", "")
// SSE 4.2
@@ -404,13 +436,13 @@ BUILTIN(__builtin_ia32_vpermilvarpd, "V2dV2dV2LLi", "")
BUILTIN(__builtin_ia32_vpermilvarps, "V4fV4fV4i", "")
BUILTIN(__builtin_ia32_vpermilvarpd256, "V4dV4dV4LLi", "")
BUILTIN(__builtin_ia32_vpermilvarps256, "V8fV8fV8i", "")
-BUILTIN(__builtin_ia32_blendpd256, "V4dV4dV4dIi", "")
-BUILTIN(__builtin_ia32_blendps256, "V8fV8fV8fIi", "")
+BUILTIN(__builtin_ia32_blendpd256, "V4dV4dV4dIc", "")
+BUILTIN(__builtin_ia32_blendps256, "V8fV8fV8fIc", "")
BUILTIN(__builtin_ia32_blendvpd256, "V4dV4dV4dV4d", "")
BUILTIN(__builtin_ia32_blendvps256, "V8fV8fV8fV8f", "")
-BUILTIN(__builtin_ia32_dpps256, "V8fV8fV8fIi", "")
-BUILTIN(__builtin_ia32_cmppd256, "V4dV4dV4dc", "")
-BUILTIN(__builtin_ia32_cmpps256, "V8fV8fV8fc", "")
+BUILTIN(__builtin_ia32_dpps256, "V8fV8fV8fIc", "")
+BUILTIN(__builtin_ia32_cmppd256, "V4dV4dV4dIc", "")
+BUILTIN(__builtin_ia32_cmpps256, "V8fV8fV8fIc", "")
BUILTIN(__builtin_ia32_vextractf128_pd256, "V2dV4dIc", "")
BUILTIN(__builtin_ia32_vextractf128_ps256, "V4fV8fIc", "")
BUILTIN(__builtin_ia32_vextractf128_si256, "V4iV8iIc", "")
@@ -472,7 +504,7 @@ BUILTIN(__builtin_ia32_maskstorepd256, "vV4d*V4dV4d", "")
BUILTIN(__builtin_ia32_maskstoreps256, "vV8f*V8fV8f", "")
// AVX2
-BUILTIN(__builtin_ia32_mpsadbw256, "V32cV32cV32ci", "")
+BUILTIN(__builtin_ia32_mpsadbw256, "V32cV32cV32cIc", "")
BUILTIN(__builtin_ia32_pabsb256, "V32cV32c", "")
BUILTIN(__builtin_ia32_pabsw256, "V16sV16s", "")
BUILTIN(__builtin_ia32_pabsd256, "V8iV8i", "")
@@ -492,7 +524,7 @@ BUILTIN(__builtin_ia32_palignr256, "V32cV32cV32cIc", "")
BUILTIN(__builtin_ia32_pavgb256, "V32cV32cV32c", "")
BUILTIN(__builtin_ia32_pavgw256, "V16sV16sV16s", "")
BUILTIN(__builtin_ia32_pblendvb256, "V32cV32cV32cV32c", "")
-BUILTIN(__builtin_ia32_pblendw256, "V16sV16sV16sIi", "")
+BUILTIN(__builtin_ia32_pblendw256, "V16sV16sV16sIc", "")
BUILTIN(__builtin_ia32_phaddw256, "V16sV16sV16s", "")
BUILTIN(__builtin_ia32_phaddd256, "V8iV8iV8i", "")
BUILTIN(__builtin_ia32_phaddsw256, "V16sV16sV16s", "")
@@ -559,8 +591,8 @@ BUILTIN(__builtin_ia32_vbroadcastss_ps, "V4fV4f", "")
BUILTIN(__builtin_ia32_vbroadcastss_ps256, "V8fV4f", "")
BUILTIN(__builtin_ia32_vbroadcastsd_pd256, "V4dV2d", "")
BUILTIN(__builtin_ia32_vbroadcastsi256, "V4LLiV2LLi", "")
-BUILTIN(__builtin_ia32_pblendd128, "V4iV4iV4iIi", "")
-BUILTIN(__builtin_ia32_pblendd256, "V8iV8iV8iIi", "")
+BUILTIN(__builtin_ia32_pblendd128, "V4iV4iV4iIc", "")
+BUILTIN(__builtin_ia32_pblendd256, "V8iV8iV8iIc", "")
BUILTIN(__builtin_ia32_pbroadcastb256, "V32cV16c", "")
BUILTIN(__builtin_ia32_pbroadcastw256, "V16sV8s", "")
BUILTIN(__builtin_ia32_pbroadcastd256, "V8iV4i", "")
@@ -615,14 +647,34 @@ BUILTIN(__builtin_ia32_gatherq_d256, "V4iV4iV4iC*V4LLiV4iIc", "")
// F16C
BUILTIN(__builtin_ia32_vcvtps2ph, "V8sV4fIi", "")
BUILTIN(__builtin_ia32_vcvtps2ph256, "V8sV8fIi", "")
+BUILTIN(__builtin_ia32_vcvtps2ph512, "V16sV16fIi", "")
BUILTIN(__builtin_ia32_vcvtph2ps, "V4fV8s", "")
BUILTIN(__builtin_ia32_vcvtph2ps256, "V8fV8s", "")
+BUILTIN(__builtin_ia32_vcvtph2ps512, "V16fV16s", "")
// RDRAND
BUILTIN(__builtin_ia32_rdrand16_step, "UiUs*", "")
BUILTIN(__builtin_ia32_rdrand32_step, "UiUi*", "")
BUILTIN(__builtin_ia32_rdrand64_step, "UiULLi*", "")
+// FSGSBASE
+BUILTIN(__builtin_ia32_rdfsbase32, "Ui", "")
+BUILTIN(__builtin_ia32_rdfsbase64, "ULLi", "")
+BUILTIN(__builtin_ia32_rdgsbase32, "Ui", "")
+BUILTIN(__builtin_ia32_rdgsbase64, "ULLi", "")
+BUILTIN(__builtin_ia32_wrfsbase32, "vUi", "")
+BUILTIN(__builtin_ia32_wrfsbase64, "vULLi", "")
+BUILTIN(__builtin_ia32_wrgsbase32, "vUi", "")
+BUILTIN(__builtin_ia32_wrgsbase64, "vULLi", "")
+
+// ADX
+BUILTIN(__builtin_ia32_addcarryx_u32, "UcUcUiUiUi*", "")
+BUILTIN(__builtin_ia32_addcarryx_u64, "UcUcULLiULLiULLi*", "")
+BUILTIN(__builtin_ia32_addcarry_u32, "UcUcUiUiUi*", "")
+BUILTIN(__builtin_ia32_addcarry_u64, "UcUcULLiULLiULLi*", "")
+BUILTIN(__builtin_ia32_subborrow_u32, "UcUcUiUiUi*", "")
+BUILTIN(__builtin_ia32_subborrow_u64, "UcUcULLiULLiULLi*", "")
+
// RDSEED
BUILTIN(__builtin_ia32_rdseed16_step, "UiUs*", "")
BUILTIN(__builtin_ia32_rdseed32_step, "UiUi*", "")
@@ -653,7 +705,7 @@ BUILTIN(__builtin_ia32_sha256rnds2, "V4iV4iV4iV4i", "")
BUILTIN(__builtin_ia32_sha256msg1, "V4iV4iV4i", "")
BUILTIN(__builtin_ia32_sha256msg2, "V4iV4iV4i", "")
-// FMA4
+// FMA
BUILTIN(__builtin_ia32_vfmaddps, "V4fV4fV4fV4f", "")
BUILTIN(__builtin_ia32_vfmaddpd, "V2dV2dV2dV2d", "")
BUILTIN(__builtin_ia32_vfmaddss, "V4fV4fV4fV4f", "")
@@ -686,6 +738,12 @@ BUILTIN(__builtin_ia32_vfmaddsubps256, "V8fV8fV8fV8f", "")
BUILTIN(__builtin_ia32_vfmaddsubpd256, "V4dV4dV4dV4d", "")
BUILTIN(__builtin_ia32_vfmsubaddps256, "V8fV8fV8fV8f", "")
BUILTIN(__builtin_ia32_vfmsubaddpd256, "V4dV4dV4dV4d", "")
+BUILTIN(__builtin_ia32_vfmaddpd512_mask, "V8dV8dV8dV8dUci", "")
+BUILTIN(__builtin_ia32_vfmsubpd512_mask, "V8dV8dV8dV8dUci", "")
+BUILTIN(__builtin_ia32_vfnmaddpd512_mask, "V8dV8dV8dV8dUci", "")
+BUILTIN(__builtin_ia32_vfmaddps512_mask, "V16fV16fV16fV16fUsi", "")
+BUILTIN(__builtin_ia32_vfmsubps512_mask, "V16fV16fV16fV16fUsi", "")
+BUILTIN(__builtin_ia32_vfnmaddps512_mask, "V16fV16fV16fV16fUsi", "")
// XOP
BUILTIN(__builtin_ia32_vpmacssww, "V8sV8sV8sV8s", "")
@@ -761,4 +819,119 @@ BUILTIN(__builtin_ia32_rdpmc, "ULLii", "")
BUILTIN(__builtin_ia32_rdtsc, "ULLi", "")
BUILTIN(__builtin_ia32_rdtscp, "ULLiUi*", "")
+// AVX-512
+BUILTIN(__builtin_ia32_sqrtpd512_mask, "V8dV8dV8dUciC", "")
+BUILTIN(__builtin_ia32_sqrtps512_mask, "V16fV16fV16fUsiC", "")
+BUILTIN(__builtin_ia32_rsqrt14sd_mask, "V2dV2dV2dV2dUc", "")
+BUILTIN(__builtin_ia32_rsqrt14ss_mask, "V4fV4fV4fV4fUc", "")
+BUILTIN(__builtin_ia32_rsqrt14pd512_mask, "V8dV8dV8dUc", "")
+BUILTIN(__builtin_ia32_rsqrt14ps512_mask, "V16fV16fV16fUs", "")
+BUILTIN(__builtin_ia32_rsqrt28sd_mask, "V2dV2dV2dV2dUciC", "")
+BUILTIN(__builtin_ia32_rsqrt28ss_mask, "V4fV4fV4fV4fUciC", "")
+BUILTIN(__builtin_ia32_rsqrt28pd_mask, "V8dV8dV8dUciC", "")
+BUILTIN(__builtin_ia32_rsqrt28ps_mask, "V16fV16fV16fUsiC", "")
+BUILTIN(__builtin_ia32_rcp14sd_mask, "V2dV2dV2dV2dUc", "")
+BUILTIN(__builtin_ia32_rcp14ss_mask, "V4fV4fV4fV4fUc", "")
+BUILTIN(__builtin_ia32_rcp14pd512_mask, "V8dV8dV8dUc", "")
+BUILTIN(__builtin_ia32_rcp14ps512_mask, "V16fV16fV16fUs", "")
+BUILTIN(__builtin_ia32_rcp28sd_mask, "V2dV2dV2dV2dUciC", "")
+BUILTIN(__builtin_ia32_rcp28ss_mask, "V4fV4fV4fV4fUciC", "")
+BUILTIN(__builtin_ia32_rcp28pd_mask, "V8dV8dV8dUciC", "")
+BUILTIN(__builtin_ia32_rcp28ps_mask, "V16fV16fV16fUsiC", "")
+BUILTIN(__builtin_ia32_cvttps2dq512_mask, "V16iV16fV16iUsiC", "")
+BUILTIN(__builtin_ia32_cvttps2udq512_mask, "V16iV16fV16iUsiC", "")
+BUILTIN(__builtin_ia32_cvttpd2dq512_mask, "V8iV8dV8iUciC", "")
+BUILTIN(__builtin_ia32_cvttpd2udq512_mask, "V8iV8dV8iUciC", "")
+BUILTIN(__builtin_ia32_cmpps512_mask, "UsV16fV16fiCUsi", "")
+BUILTIN(__builtin_ia32_pcmpeqb512_mask, "LLiV64cV64cLLi", "")
+BUILTIN(__builtin_ia32_pcmpeqd512_mask, "sV16iV16is", "")
+BUILTIN(__builtin_ia32_pcmpeqq512_mask, "cV8LLiV8LLic", "")
+BUILTIN(__builtin_ia32_pcmpeqw512_mask, "iV32sV32si", "")
+BUILTIN(__builtin_ia32_pcmpeqb256_mask, "iV32cV32ci", "")
+BUILTIN(__builtin_ia32_pcmpeqd256_mask, "cV8iV8ic", "")
+BUILTIN(__builtin_ia32_pcmpeqq256_mask, "cV4LLiV4LLic", "")
+BUILTIN(__builtin_ia32_pcmpeqw256_mask, "sV16sV16ss", "")
+BUILTIN(__builtin_ia32_pcmpeqb128_mask, "sV16cV16cs", "")
+BUILTIN(__builtin_ia32_pcmpeqd128_mask, "cV4iV4ic", "")
+BUILTIN(__builtin_ia32_pcmpeqq128_mask, "cV2LLiV2LLic", "")
+BUILTIN(__builtin_ia32_pcmpeqw128_mask, "cV8sV8sc", "")
+BUILTIN(__builtin_ia32_cmppd512_mask, "UcV8dV8diCUci", "")
+BUILTIN(__builtin_ia32_rndscaleps_mask, "V16fV16fiCV16fUsiC", "")
+BUILTIN(__builtin_ia32_rndscalepd_mask, "V8dV8diCV8dUciC", "")
+BUILTIN(__builtin_ia32_cvtps2dq512_mask, "V16iV16fV16iUsiC", "")
+BUILTIN(__builtin_ia32_cvtpd2dq512_mask, "V8iV8dV8iUciC", "")
+BUILTIN(__builtin_ia32_cvtps2udq512_mask, "V16iV16fV16iUsiC", "")
+BUILTIN(__builtin_ia32_cvtpd2udq512_mask, "V8iV8dV8iUciC", "")
+BUILTIN(__builtin_ia32_minps512_mask, "V16fV16fV16fV16fUsiC", "")
+BUILTIN(__builtin_ia32_minpd512_mask, "V8dV8dV8dV8dUciC", "")
+BUILTIN(__builtin_ia32_maxps512_mask, "V16fV16fV16fV16fUsiC", "")
+BUILTIN(__builtin_ia32_maxpd512_mask, "V8dV8dV8dV8dUciC", "")
+BUILTIN(__builtin_ia32_cvtdq2ps512_mask, "V16fV16iV16fUsiC", "")
+BUILTIN(__builtin_ia32_cvtudq2ps512_mask, "V16fV16iV16fUsiC", "")
+BUILTIN(__builtin_ia32_cvtdq2pd512_mask, "V8dV8iV8dUc", "")
+BUILTIN(__builtin_ia32_cvtudq2pd512_mask, "V8dV8iV8dUc", "")
+BUILTIN(__builtin_ia32_cvtpd2ps512_mask, "V8fV8dV8fUciC", "")
+BUILTIN(__builtin_ia32_vcvtps2ph512_mask, "V16sV16fiCV16sUs", "")
+BUILTIN(__builtin_ia32_vcvtph2ps512_mask, "V16fV16sV16fUsiC", "")
+BUILTIN(__builtin_ia32_pabsd512_mask, "V16iV16iV16iUs", "")
+BUILTIN(__builtin_ia32_pabsq512_mask, "V8LLiV8LLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_pmaxsd512_mask, "V16iV16iV16iV16iUs", "")
+BUILTIN(__builtin_ia32_pmaxsq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_pmaxud512_mask, "V16iV16iV16iV16iUs", "")
+BUILTIN(__builtin_ia32_pmaxuq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_pminsd512_mask, "V16iV16iV16iV16iUs", "")
+BUILTIN(__builtin_ia32_pminsq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_pminud512_mask, "V16iV16iV16iV16iUs", "")
+BUILTIN(__builtin_ia32_pminuq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_pmuldq512_mask, "V8LLiV16iV16iV8LLiUc", "")
+BUILTIN(__builtin_ia32_pmuludq512_mask, "V8LLiV16iV16iV8LLiUc", "")
+BUILTIN(__builtin_ia32_blendmd_512_mask, "V16iV16iV16iUs", "")
+BUILTIN(__builtin_ia32_blendmq_512_mask, "V8LLiV8LLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_blendmps_512_mask, "V16fV16fV16fUs", "")
+BUILTIN(__builtin_ia32_blendmpd_512_mask, "V8dV8dV8dUc", "")
+BUILTIN(__builtin_ia32_ptestmd512, "UsV16iV16iUs", "")
+BUILTIN(__builtin_ia32_ptestmq512, "UcV8LLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_pbroadcastd512_gpr_mask, "V16iiV16iUs", "")
+BUILTIN(__builtin_ia32_pbroadcastq512_gpr_mask, "V8LLiLLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_pbroadcastq512_mem_mask, "V8LLiLLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_loaddqusi512_mask, "V16ivC*V16iUs", "")
+BUILTIN(__builtin_ia32_loaddqudi512_mask, "V8LLivC*V8LLiUc", "")
+BUILTIN(__builtin_ia32_loadups512_mask, "V16fvC*V16fUs", "")
+BUILTIN(__builtin_ia32_loadupd512_mask, "V8dvC*V8dUc", "")
+BUILTIN(__builtin_ia32_storedqudi512_mask, "vv*V8LLiUc", "")
+BUILTIN(__builtin_ia32_storedqusi512_mask, "vv*V16iUs", "")
+BUILTIN(__builtin_ia32_storeupd512_mask, "vv*V8dUc", "")
+BUILTIN(__builtin_ia32_storeups512_mask, "vv*V16fUs", "")
+BUILTIN(__builtin_ia32_vpermt2vard512_mask, "V16iV16iV16iV16iUs", "")
+BUILTIN(__builtin_ia32_vpermt2varq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_vpermt2varps512_mask, "V16fV16iV16fV16fUs", "")
+BUILTIN(__builtin_ia32_vpermt2varpd512_mask, "V8dV8LLiV8dV8dUc", "")
+BUILTIN(__builtin_ia32_alignq512_mask, "V8LLiV8LLiV8LLiUcV8LLiUc", "")
+BUILTIN(__builtin_ia32_alignd512_mask, "V16iV16iV16iUcV16iUc", "")
+BUILTIN(__builtin_ia32_gathersiv8df, "V8dV8dvC*V8iUciC", "")
+BUILTIN(__builtin_ia32_gathersiv16sf, "V16fV16fvC*UsiC", "")
+BUILTIN(__builtin_ia32_gatherdiv8df, "V8dV8dvC*V8LLiUciC", "")
+BUILTIN(__builtin_ia32_gatherdiv16sf, "V8fV8fvC*V8LLiUciC", "")
+BUILTIN(__builtin_ia32_gathersiv8di, "V8LLiV8LLivC*V8iUciC", "")
+BUILTIN(__builtin_ia32_gathersiv16si, "V16iV16ivC*UsiC", "")
+BUILTIN(__builtin_ia32_gatherdiv8di, "V8LLiV8LLivC*V8LLiUciC", "")
+BUILTIN(__builtin_ia32_gatherdiv16si, "V8iV8ivC*V8LLiUciC", "")
+BUILTIN(__builtin_ia32_scattersiv8df, "vv*UcV8iV8diC", "")
+BUILTIN(__builtin_ia32_scattersiv16sf, "vv*UsV16iV16fiC", "")
+BUILTIN(__builtin_ia32_scatterdiv8df, "vv*UcV8LLiV8diC", "")
+BUILTIN(__builtin_ia32_scatterdiv16sf, "vv*UcV8LLiV8fiC", "")
+BUILTIN(__builtin_ia32_scattersiv8di, "vv*UcV8iV8LLiiC", "")
+BUILTIN(__builtin_ia32_scattersiv16si, "vv*UsV16iV16iiC", "")
+BUILTIN(__builtin_ia32_scatterdiv8di, "vv*UcV8LLiV8LLiiC", "")
+BUILTIN(__builtin_ia32_scatterdiv16si, "vv*UcV8LLiV8iiC", "")
+BUILTIN(__builtin_ia32_gatherpfdpd, "vUcV8ivC*iCiC", "")
+BUILTIN(__builtin_ia32_gatherpfdps, "vUsV16ivC*iCiC", "")
+BUILTIN(__builtin_ia32_gatherpfqpd, "vUcV8LLivC*iCiC", "")
+BUILTIN(__builtin_ia32_gatherpfqps, "vUcV8LLivC*iCiC", "")
+BUILTIN(__builtin_ia32_scatterpfdpd, "vUcV8iv*iCiC", "")
+BUILTIN(__builtin_ia32_scatterpfdps, "vUsV16iv*iCiC", "")
+BUILTIN(__builtin_ia32_scatterpfqpd, "vUcV8LLiv*iCiC", "")
+BUILTIN(__builtin_ia32_scatterpfqps, "vUcV8LLiv*iCiC", "")
+BUILTIN(__builtin_ia32_knothi, "UsUs", "")
+
#undef BUILTIN
diff --git a/include/clang/Basic/CharInfo.h b/include/clang/Basic/CharInfo.h
index d0afda43709a..dd9c55431e01 100644
--- a/include/clang/Basic/CharInfo.h
+++ b/include/clang/Basic/CharInfo.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_BASIC_CHARINFO_H
-#define CLANG_BASIC_CHARINFO_H
+#ifndef LLVM_CLANG_BASIC_CHARINFO_H
+#define LLVM_CLANG_BASIC_CHARINFO_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
diff --git a/include/clang/Basic/CommentOptions.h b/include/clang/Basic/CommentOptions.h
index 7991875838a4..92419f91b741 100644
--- a/include/clang/Basic/CommentOptions.h
+++ b/include/clang/Basic/CommentOptions.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_COMMENTOPTIONS_H
-#define LLVM_CLANG_COMMENTOPTIONS_H
+#ifndef LLVM_CLANG_BASIC_COMMENTOPTIONS_H
+#define LLVM_CLANG_BASIC_COMMENTOPTIONS_H
#include <string>
#include <vector>
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index a7b2ba270d46..91e94db802b1 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_DIAGNOSTIC_H
-#define LLVM_CLANG_DIAGNOSTIC_H
+#ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_H
+#define LLVM_CLANG_BASIC_DIAGNOSTIC_H
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticOptions.h"
@@ -187,7 +187,7 @@ private:
IntrusiveRefCntPtr<DiagnosticIDs> Diags;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticConsumer *Client;
- bool OwnsDiagClient;
+ std::unique_ptr<DiagnosticConsumer> Owner;
SourceManager *SourceMgr;
/// \brief Mapping information for diagnostics.
@@ -302,7 +302,6 @@ private:
unsigned NumWarnings; ///< Number of warnings reported
unsigned NumErrors; ///< Number of errors reported
- unsigned NumErrorsSuppressed; ///< Number of errors suppressed
/// \brief A function pointer that converts an opaque diagnostic
/// argument to a strings.
@@ -369,14 +368,11 @@ public:
const DiagnosticConsumer *getClient() const { return Client; }
/// \brief Determine whether this \c DiagnosticsEngine object own its client.
- bool ownsClient() const { return OwnsDiagClient; }
-
+ bool ownsClient() const { return Owner != nullptr; }
+
/// \brief Return the current diagnostic client along with ownership of that
/// client.
- DiagnosticConsumer *takeClient() {
- OwnsDiagClient = false;
- return Client;
- }
+ std::unique_ptr<DiagnosticConsumer> takeClient() { return std::move(Owner); }
bool hasSourceManager() const { return SourceMgr != nullptr; }
SourceManager &getSourceManager() const {
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 8d5a1c77233b..d353b451aaa7 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -141,6 +141,13 @@ def note_constexpr_calls_suppressed : Note<
"(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to "
"see all)">;
def note_constexpr_call_here : Note<"in call to '%0'">;
+def note_constexpr_baa_insufficient_alignment : Note<
+ "%select{alignment of|offset of the aligned pointer from}0 the base pointee "
+ "object (%1 %plural{1:byte|:bytes}1) is %select{less than|not a multiple of}0 the "
+ "asserted %2 %plural{1:byte|:bytes}2">;
+def note_constexpr_baa_value_insufficient_alignment : Note<
+ "value of the aligned pointer (%0) is not a multiple of the asserted %1 "
+ "%plural{1:byte|:bytes}1">;
def warn_integer_constant_overflow : Warning<
"overflow in expression; result is %0 with type %1">,
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index b3c77b8f5f36..ff9ed69022ec 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -81,6 +81,8 @@ def err_deleted_non_function : Error<
"only functions can have deleted definitions">;
def err_module_not_found : Error<"module '%0' not found">, DefaultFatal;
def err_module_not_built : Error<"could not build module '%0'">, DefaultFatal;
+def err_module_lock_failure : Error<
+ "could not acquire lock file for module '%0'">, DefaultFatal;
def err_module_cycle : Error<"cyclic dependency in module '%0': %1">,
DefaultFatal;
def note_pragma_entered_here : Note<"#pragma entered here">;
@@ -102,10 +104,12 @@ def ext_cxx11_longlong : Extension<
def warn_cxx98_compat_longlong : Warning<
"'long long' is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;
-def err_integer_too_large : Error<
- "integer constant is larger than the largest unsigned integer type">;
-def ext_integer_too_large_for_signed : ExtWarn<
- "integer constant is larger than the largest signed integer type">,
+def err_integer_literal_too_large : Error<
+ "integer literal is too large to be represented in any %select{signed |}0"
+ "integer type">;
+def ext_integer_literal_too_large_for_signed : ExtWarn<
+ "integer literal is too large to be represented in a signed integer type, "
+ "interpreting as unsigned">,
InGroup<DiagGroup<"implicitly-unsigned-literal">>;
// Sema && AST
@@ -121,6 +125,8 @@ def err_target_unknown_abi : Error<"unknown target ABI '%0'">;
def err_target_unknown_fpmath : Error<"unknown FP unit '%0'">;
def err_target_unsupported_fpmath : Error<
"the '%0' unit is not supported with this instruction set">;
+def err_target_unsupported_unaligned : Error<
+ "the %0 sub-architecture does not support unaligned accesses">;
// Source manager
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index cd26a6a4dd70..41c78ee669dc 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -22,6 +22,8 @@ def err_drv_unknown_stdin_type_clang_cl : Error<
def err_drv_unknown_language : Error<"language not recognized: '%0'">;
def err_drv_invalid_arch_name : Error<
"invalid arch name '%0'">;
+def err_drv_invalid_thread_model_for_target : Error<
+ "invalid thread model '%0' in '%1' for this target">;
def err_drv_invalid_linker_name : Error<
"invalid linker name in argument '%0'">;
def err_drv_invalid_rtlib_name : Error<
@@ -100,10 +102,6 @@ def err_drv_cc_print_options_failure : Error<
"unable to open CC_PRINT_OPTIONS file: %0">;
def err_drv_preamble_format : Error<
"incorrect format for -preamble-bytes=N,END">;
-def err_drv_conflicting_deployment_targets : Error<
- "conflicting deployment targets, both '%0' and '%1' are present in environment">;
-def err_drv_invalid_arch_for_deployment_target : Error<
- "invalid architecture '%0' for deployment target '%1'">;
def err_drv_objc_gc_arr : Error<
"cannot specify both '-fobjc-arc' and '%0'">;
def err_arc_unsupported_on_runtime : Error<
@@ -124,7 +122,7 @@ def warn_O4_is_O3 : Warning<"-O4 is equivalent to -O3">, InGroup<Deprecated>;
def warn_drv_optimization_value : Warning<"optimization level '%0' is not supported; using '%1%2' instead">,
InGroup<InvalidCommandLineArgument>;
def warn_ignored_gcc_optimization : Warning<"optimization flag '%0' is not supported">,
- InGroup<InvalidCommandLineArgument>;
+ InGroup<IgnoredOptimizationArgument>;
def warn_c_kext : Warning<
"ignoring -fapple-kext which is valid for C++ and Objective-C++ only">;
def warn_drv_input_file_unused : Warning<
@@ -165,9 +163,11 @@ def warn_debug_compression_unavailable : Warning<"cannot compress debug sections
def note_drv_command_failed_diag_msg : Note<
"diagnostic msg: %0">;
-def note_drv_t_option_is_global :
- Note<"The last /TC or /TP option takes precedence over earlier instances">;
-
+def note_drv_t_option_is_global : Note<
+ "The last /TC or /TP option takes precedence over earlier instances">;
+def note_drv_address_sanitizer_debug_runtime : Note<
+ "AddressSanitizer doesn't support linking with debug runtime libraries yet">;
+
def err_analyzer_config_no_value : Error<
"analyzer-config option '%0' has a key but no value">;
def err_analyzer_config_multiple_values : Error<
@@ -175,7 +175,7 @@ def err_analyzer_config_multiple_values : Error<
def err_drv_modules_validate_once_requires_timestamp : Error<
"option '-fmodules-validate-once-per-build-session' requires "
- "'-fbuild-session-timestamp=<seconds since Epoch>'">;
+ "'-fbuild-session-timestamp=<seconds since Epoch>' or '-fbuild-session-file=<file>'">;
def warn_drv_invoking_fallback : Warning<"falling back to %0">,
InGroup<Fallback>;
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index ae704c49150b..15f74b11698f 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -46,6 +46,16 @@ def warn_fe_backend_optimization_failure : Warning<"%0">, BackendInfo,
def note_fe_backend_optimization_remark_invalid_loc : Note<"could "
"not determine the original source location for %0:%1:%2">;
+def remark_sanitize_address_insert_extra_padding_accepted : Remark<
+ "-fsanitize-address-field-padding applied to %0">, ShowInSystemHeader,
+ InGroup<SanitizeAddressRemarks>;
+def remark_sanitize_address_insert_extra_padding_rejected : Remark<
+ "-fsanitize-address-field-padding ignored for %0 because it "
+ "%select{is not C++|is packed|is a union|is trivially copyable|"
+ "has trivial destructor|is standard layout|is in a blacklisted file|"
+ "is blacklisted}1">, ShowInSystemHeader,
+ InGroup<SanitizeAddressRemarks>;
+
def err_fe_invalid_code_complete_file : Error<
"cannot locate code-completion file %0">, DefaultFatal;
def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
@@ -85,9 +95,12 @@ def err_fe_no_pch_in_dir : Error<
def err_fe_action_not_available : Error<
"action %0 not compiled in">;
+def warn_fe_serialized_diag_merge_failure : Warning<
+ "unable to merge a subprocess's serialized diagnostics">,
+ InGroup<SerializedDiagnostics>;
def warn_fe_serialized_diag_failure : Warning<
"unable to open file %0 for serializing diagnostics (%1)">,
- InGroup<DiagGroup<"serialized-diagnostics">>;
+ InGroup<SerializedDiagnostics>;
def err_verify_missing_line : Error<
"missing or invalid line number following '@' in expected %0">;
@@ -135,12 +148,15 @@ def warn_unknown_warning_specifier : Warning<
def err_unknown_analyzer_checker : Error<
"no analyzer checkers are associated with '%0'">;
+def note_suggest_disabling_all_checkers : Note<
+ "use -analyzer-disable-all-checks to disable all static analyzer checkers">;
+
def warn_incompatible_analyzer_plugin_api : Warning<
"checker plugin '%0' is not compatible with this version of the analyzer">,
InGroup<DiagGroup<"analyzer-incompatible-plugin"> >;
def note_incompatible_analyzer_plugin_api : Note<
"current API version is '%0', but plugin was compiled with version '%1'">;
-
+
def err_module_map_not_found : Error<"module map file '%0' not found">,
DefaultFatal;
def err_missing_module_name : Error<
@@ -167,7 +183,19 @@ def warn_module_config_macro_undef : Warning<
def note_module_def_undef_here : Note<
"macro was %select{defined|#undef'd}0 here">;
def remark_module_build : Remark<"building module '%0' as '%1'">,
- InGroup<DiagGroup<"module-build">>;
+ InGroup<ModuleBuild>;
+def remark_module_build_done : Remark<"finished building module '%0'">,
+ InGroup<ModuleBuild>;
+
+def err_conflicting_module_names : Error<
+ "conflicting module names specified: '-fmodule-name=%0' and "
+ "'-fmodule-implementation-of %1'">;
+def err_conflicting_module_files : Error<
+ "module '%0' is defined in both '%1' and '%2'">;
+def err_module_file_not_found : Error<
+ "file '%0' is not a precompiled module file">, DefaultFatal;
+def err_module_file_not_module : Error<
+ "AST file '%0' was not built as a module">, DefaultFatal;
def err_missing_vfs_overlay_file : Error<
"virtual filesystem overlay file '%0' not found">, DefaultFatal;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 58dee482b627..75d40b17a67c 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -60,7 +60,7 @@ def ExternCCompat : DiagGroup<"extern-c-compat">;
def KeywordCompat : DiagGroup<"keyword-compat">;
def GNUCaseRange : DiagGroup<"gnu-case-range">;
def CastAlign : DiagGroup<"cast-align">;
-def : DiagGroup<"cast-qual">;
+def CastQual : DiagGroup<"cast-qual">;
def : DiagGroup<"char-align">;
def Comment : DiagGroup<"comment">;
def GNUComplexInteger : DiagGroup<"gnu-complex-integer">;
@@ -71,6 +71,7 @@ def GNUDesignator : DiagGroup<"gnu-designator">;
def GNUStringLiteralOperatorTemplate :
DiagGroup<"gnu-string-literal-operator-template">;
+def DeleteIncomplete : DiagGroup<"delete-incomplete">;
def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">;
def AbstractFinalClass : DiagGroup<"abstract-final-class">;
@@ -118,9 +119,9 @@ def FormatExtraArgs : DiagGroup<"format-extra-args">;
def FormatZeroLength : DiagGroup<"format-zero-length">;
// Warnings for C++1y code which is not compatible with prior C++ standards.
-def CXXPre1yCompat : DiagGroup<"c++98-c++11-compat">;
-def CXXPre1yCompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic",
- [CXXPre1yCompat]>;
+def CXXPre14Compat : DiagGroup<"c++98-c++11-compat">;
+def CXXPre14CompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic",
+ [CXXPre14Compat]>;
def CXXPre1zCompat : DiagGroup<"c++98-c++11-c++14-compat">;
def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic",
[CXXPre1zCompat]>;
@@ -133,19 +134,21 @@ def CXX98CompatUnnamedTypeTemplateArgs :
DiagGroup<"c++98-compat-unnamed-type-template-args">;
def CXX98Compat : DiagGroup<"c++98-compat",
- [CXX98CompatBindToTemporaryCopy,
- CXX98CompatLocalTypeTemplateArgs,
+ [CXX98CompatLocalTypeTemplateArgs,
CXX98CompatUnnamedTypeTemplateArgs,
- CXXPre1yCompat,
+ CXXPre14Compat,
CXXPre1zCompat]>;
// Warnings for C++11 features which are Extensions in C++98 mode.
def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic",
[CXX98Compat,
- CXXPre1yCompatPedantic,
+ CXX98CompatBindToTemporaryCopy,
+ CXXPre14CompatPedantic,
CXXPre1zCompatPedantic]>;
def CXX11Narrowing : DiagGroup<"c++11-narrowing">;
+def CXX11WarnOverrideMethod : DiagGroup<"inconsistent-missing-override">;
+
// Original name of this warning in Clang
def : DiagGroup<"c++0x-narrowing", [CXX11Narrowing]>;
@@ -162,11 +165,11 @@ def CXX11Compat : DiagGroup<"c++11-compat",
[CXX11Narrowing,
CXX11CompatReservedUserDefinedLiteral,
CXX11CompatDeprecatedWritableStr,
- CXXPre1yCompat,
+ CXXPre14Compat,
CXXPre1zCompat]>;
def : DiagGroup<"c++0x-compat", [CXX11Compat]>;
def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic",
- [CXXPre1yCompatPedantic,
+ [CXXPre14CompatPedantic,
CXXPre1zCompatPedantic]>;
def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre1zCompat]>;
@@ -187,6 +190,7 @@ def OverloadedShiftOpParentheses: DiagGroup<"overloaded-shift-op-parentheses">;
def DanglingElse: DiagGroup<"dangling-else">;
def DanglingField : DiagGroup<"dangling-field">;
def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
+def FlagEnum : DiagGroup<"flag-enum">;
def InfiniteRecursion : DiagGroup<"infinite-recursion">;
def GNUImaginaryConstant : DiagGroup<"gnu-imaginary-constant">;
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
@@ -198,11 +202,13 @@ def IncompatiblePointerTypes
: DiagGroup<"incompatible-pointer-types",
[IncompatiblePointerTypesDiscardsQualifiers]>;
def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">;
-def IncompleteModule : DiagGroup<"incomplete-module", [IncompleteUmbrella]>;
def NonModularIncludeInFrameworkModule
: DiagGroup<"non-modular-include-in-framework-module">;
def NonModularIncludeInModule : DiagGroup<"non-modular-include-in-module",
[NonModularIncludeInFrameworkModule]>;
+def IncompleteModule : DiagGroup<"incomplete-module",
+ [IncompleteUmbrella, NonModularIncludeInModule]>;
+
def InvalidNoreturn : DiagGroup<"invalid-noreturn">;
def InvalidSourceEncoding : DiagGroup<"invalid-source-encoding">;
def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">;
@@ -231,6 +237,7 @@ def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">;
def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">;
def MismatchedTags : DiagGroup<"mismatched-tags">;
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
+def ModuleBuild : DiagGroup<"module-build">;
def ModuleConflict : DiagGroup<"module-conflict">;
def NewlineEOF : DiagGroup<"newline-eof">;
def NullArithmetic : DiagGroup<"null-arithmetic">;
@@ -267,7 +274,9 @@ def ObjCInvalidIBOutletProperty : DiagGroup<"invalid-iboutlet">;
def ObjCRootClass : DiagGroup<"objc-root-class">;
def ObjCPointerIntrospectPerformSelector : DiagGroup<"deprecated-objc-pointer-introspection-performSelector">;
def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>;
+def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">;
def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">;
+def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">;
def Packed : DiagGroup<"packed">;
def Padded : DiagGroup<"padded">;
def PointerArith : DiagGroup<"pointer-arith">;
@@ -285,6 +294,7 @@ def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy",
[CXX98CompatBindToTemporaryCopy]>;
def SelfAssignmentField : DiagGroup<"self-assign-field">;
def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentField]>;
+def SelfMove : DiagGroup<"self-move">;
def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
def Sentinel : DiagGroup<"sentinel">;
def MissingMethodReturnType : DiagGroup<"missing-method-return-type">;
@@ -329,6 +339,8 @@ def : DiagGroup<"sequence-point", [Unsequenced]>;
// Preprocessor warnings.
def AmbiguousMacro : DiagGroup<"ambiguous-macro">;
+def KeywordAsMacro : DiagGroup<"keyword-macro">;
+def ReservedIdAsMacro : DiagGroup<"reserved-id-macro">;
// Just silence warnings about -Wstrict-aliasing for now.
def : DiagGroup<"strict-aliasing=0">;
@@ -349,6 +361,7 @@ def InvalidOffsetof : DiagGroup<"invalid-offsetof">;
def : DiagGroup<"strict-prototypes">;
def StrictSelector : DiagGroup<"strict-selector-match">;
def MethodDuplicate : DiagGroup<"duplicate-method-match">;
+def ObjCCStringFormat : DiagGroup<"cstring-format-directive">;
def CoveredSwitchDefault : DiagGroup<"covered-switch-default">;
def SwitchBool : DiagGroup<"switch-bool">;
def SwitchEnum : DiagGroup<"switch-enum">;
@@ -383,7 +396,9 @@ def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args",
def UnsupportedFriend : DiagGroup<"unsupported-friend">;
def UnusedArgument : DiagGroup<"unused-argument">;
def UnusedCommandLineArgument : DiagGroup<"unused-command-line-argument">;
-def InvalidCommandLineArgument : DiagGroup<"invalid-command-line-argument">;
+def IgnoredOptimizationArgument : DiagGroup<"ignored-optimization-argument">;
+def InvalidCommandLineArgument : DiagGroup<"invalid-command-line-argument",
+ [IgnoredOptimizationArgument]>;
def UnusedComparison : DiagGroup<"unused-comparison">;
def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">;
def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">;
@@ -395,11 +410,17 @@ def UnusedMemberFunction : DiagGroup<"unused-member-function",
def UnusedLabel : DiagGroup<"unused-label">;
def UnusedParameter : DiagGroup<"unused-parameter">;
def UnusedResult : DiagGroup<"unused-result">;
-def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult]>;
+def PotentiallyEvaluatedExpression : DiagGroup<"potentially-evaluated-expression">;
+def UnevaluatedExpression : DiagGroup<"unevaluated-expression",
+ [PotentiallyEvaluatedExpression]>;
+def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult,
+ UnevaluatedExpression]>;
def UnusedConstVariable : DiagGroup<"unused-const-variable">;
def UnusedVariable : DiagGroup<"unused-variable",
[UnusedConstVariable]>;
+def UnusedLocalTypedef : DiagGroup<"unused-local-typedef">;
def UnusedPropertyIvar : DiagGroup<"unused-property-ivar">;
+def UnusedGetterReturnValue : DiagGroup<"unused-getter-return-value">;
def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">;
def UserDefinedLiterals : DiagGroup<"user-defined-literals">;
def Reorder : DiagGroup<"reorder">;
@@ -408,8 +429,6 @@ def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">;
def CustomAtomic : DiagGroup<"custom-atomic-properties">;
def AtomicProperties : DiagGroup<"atomic-properties",
[ImplicitAtomic, CustomAtomic]>;
-// FIXME: Remove arc-abi once an Xcode is released that doesn't pass this flag.
-def : DiagGroup<"arc-abi">;
def ARCUnsafeRetainedAssign : DiagGroup<"arc-unsafe-retained-assign">;
def ARCRetainCycles : DiagGroup<"arc-retain-cycles">;
def ARCNonPodMemAccess : DiagGroup<"arc-non-pod-memaccess">;
@@ -426,6 +445,9 @@ def DeallocInCategory:DiagGroup<"dealloc-in-category">;
def SelectorTypeMismatch : DiagGroup<"selector-type-mismatch">;
def Selector : DiagGroup<"selector", [SelectorTypeMismatch]>;
def Protocol : DiagGroup<"protocol">;
+def AtProtocol : DiagGroup<"at-protocol">;
+def PropertyAccessDotSyntax: DiagGroup<"property-access-dot-syntax">;
+def PropertyAttr : DiagGroup<"property-attribute-mismatch">;
def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">;
def VariadicMacros : DiagGroup<"variadic-macros">;
@@ -520,7 +542,7 @@ def Unused : DiagGroup<"unused",
[UnusedArgument, UnusedFunction, UnusedLabel,
// UnusedParameter, (matches GCC's behavior)
// UnusedMemberFunction, (clean-up llvm before enabling)
- UnusedPrivateField,
+ UnusedPrivateField, UnusedLocalTypedef,
UnusedValue, UnusedVariable, UnusedPropertyIvar]>,
DiagCategory<"Unused Entity Issue">;
@@ -565,6 +587,7 @@ def Most : DiagGroup<"most", [
Reorder,
ReturnType,
SelfAssignment,
+ SelfMove,
SizeofArrayArgument,
SizeofArrayDecay,
StringPlusInt,
@@ -585,10 +608,14 @@ def Most : DiagGroup<"most", [
def ThreadSafetyAttributes : DiagGroup<"thread-safety-attributes">;
def ThreadSafetyAnalysis : DiagGroup<"thread-safety-analysis">;
def ThreadSafetyPrecise : DiagGroup<"thread-safety-precise">;
+def ThreadSafetyReference : DiagGroup<"thread-safety-reference">;
+def ThreadSafetyNegative : DiagGroup<"thread-safety-negative">;
def ThreadSafety : DiagGroup<"thread-safety",
[ThreadSafetyAttributes,
ThreadSafetyAnalysis,
- ThreadSafetyPrecise]>;
+ ThreadSafetyPrecise,
+ ThreadSafetyReference]>;
+def ThreadSafetyVerbose : DiagGroup<"thread-safety-verbose">;
def ThreadSafetyBeta : DiagGroup<"thread-safety-beta">;
// Uniqueness Analysis warnings
@@ -614,6 +641,8 @@ def : DiagGroup<"int-conversions",
[IntConversion]>; // -Wint-conversions = -Wint-conversion
def : DiagGroup<"vector-conversions",
[VectorConversion]>; // -Wvector-conversions = -Wvector-conversion
+def : DiagGroup<"unused-local-typedefs", [UnusedLocalTypedef]>;
+ // -Wunused-local-typedefs = -Wunused-local-typedef
// A warning group for warnings that we want to have on by default in clang,
// but which aren't on by default in GCC.
@@ -624,15 +653,17 @@ def NonGCC : DiagGroup<"non-gcc",
// earlier C++ versions.
def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11LongLong]>;
-// A warning group for warnings about using C++1y features as extensions in
+// A warning group for warnings about using C++14 features as extensions in
// earlier C++ versions.
-def CXX1y : DiagGroup<"c++1y-extensions">;
+def CXX14 : DiagGroup<"c++14-extensions">;
// A warning group for warnings about using C++1z features as extensions in
// earlier C++ versions.
def CXX1z : DiagGroup<"c++1z-extensions">;
def : DiagGroup<"c++0x-extensions", [CXX11]>;
+def : DiagGroup<"c++1y-extensions", [CXX14]>;
+
def DelegatingCtorCycles :
DiagGroup<"delegating-ctor-cycles">;
@@ -710,6 +741,12 @@ def BackendOptimizationFailure : DiagGroup<"pass-failed">;
def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">;
+// AddressSanitizer frontent instrumentation remarks.
+def SanitizeAddressRemarks : DiagGroup<"sanitize-address">;
+
+// Issues with serialized diagnostics.
+def SerializedDiagnostics : DiagGroup<"serialized-diagnostics">;
+
// A warning group for warnings about code that clang accepts when
// compiling CUDA C/C++ but which is not compatible with the CUDA spec.
def CudaCompat : DiagGroup<"cuda-compat">;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index bfb0f0d1ee5d..99b469d70e78 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_DIAGNOSTICIDS_H
-#define LLVM_CLANG_DIAGNOSTICIDS_H
+#ifndef LLVM_CLANG_BASIC_DIAGNOSTICIDS_H
+#define LLVM_CLANG_BASIC_DIAGNOSTICIDS_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -33,7 +33,7 @@ namespace clang {
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100,
DIAG_START_LEX = DIAG_START_SERIALIZATION + 120,
DIAG_START_PARSE = DIAG_START_LEX + 300,
- DIAG_START_AST = DIAG_START_PARSE + 400,
+ DIAG_START_AST = DIAG_START_PARSE + 500,
DIAG_START_COMMENT = DIAG_START_AST + 100,
DIAG_START_SEMA = DIAG_START_COMMENT + 100,
DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000,
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 86def878834f..93cc7c297813 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -161,8 +161,8 @@ def err_invalid_suffix_integer_constant : Error<
def err_invalid_suffix_float_constant : Error<
"invalid suffix '%0' on floating constant">;
def warn_cxx11_compat_digit_separator : Warning<
- "digit separators are incompatible with C++ standards before C++1y">,
- InGroup<CXXPre1yCompat>, DefaultIgnore;
+ "digit separators are incompatible with C++ standards before C++14">,
+ InGroup<CXXPre14Compat>, DefaultIgnore;
def err_digit_separator_not_between_digits : Error<
"digit separator cannot appear at %select{start|end}0 of digit sequence">;
def warn_extraneous_char_constant : Warning<
@@ -182,11 +182,11 @@ def ext_hexconstant_invalid : Extension<
"hexadecimal floating constants are a C99 feature">, InGroup<C99>;
def ext_binary_literal : Extension<
"binary integer literals are a GNU extension">, InGroup<GNUBinaryLiteral>;
-def ext_binary_literal_cxx1y : Extension<
- "binary integer literals are a C++1y extension">, InGroup<CXX1y>;
+def ext_binary_literal_cxx14 : Extension<
+ "binary integer literals are a C++14 extension">, InGroup<CXX14>;
def warn_cxx11_compat_binary_literal : Warning<
- "binary integer literals are incompatible with C++ standards before C++1y">,
- InGroup<CXXPre1yCompatPedantic>, DefaultIgnore;
+ "binary integer literals are incompatible with C++ standards before C++14">,
+ InGroup<CXXPre14CompatPedantic>, DefaultIgnore;
def err_pascal_string_too_long : Error<"Pascal string is too long">;
def err_octal_escape_too_large : Error<"octal escape sequence out of range">;
def err_hex_escape_too_large : Error<"hex escape sequence out of range">;
@@ -201,6 +201,9 @@ def warn_c99_compat_unicode_literal : Warning<
def warn_cxx98_compat_unicode_literal : Warning<
"unicode literals are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
+def warn_cxx14_compat_u8_character_literal : Warning<
+ "unicode literals are incompatible with C++ standards before C++1z">,
+ InGroup<CXXPre1zCompat>, DefaultIgnore;
def warn_cxx11_compat_user_defined_literal : Warning<
"identifier after literal will be treated as a user-defined literal suffix "
"in C++11">, InGroup<CXX11Compat>, DefaultIgnore;
@@ -287,6 +290,11 @@ def note_pp_ambiguous_macro_chosen : Note<
"expanding this definition of %0">;
def note_pp_ambiguous_macro_other : Note<
"other definition of %0">;
+def warn_pp_macro_hides_keyword : Extension<
+ "keyword is hidden by macro definition">, InGroup<KeywordAsMacro>;
+def warn_pp_macro_is_reserved_id : Warning<
+ "macro name is a reserved identifier">, DefaultIgnore,
+ InGroup<ReservedIdAsMacro>;
def pp_invalid_string_literal : Warning<
"invalid string literal, ignoring final '\\'">;
@@ -324,7 +332,7 @@ def warn_cxx98_compat_variadic_macro : Warning<
InGroup<CXX98CompatPedantic>, DefaultIgnore;
def ext_named_variadic_macro : Extension<
"named variadic macros are a GNU extension">, InGroup<VariadicMacros>;
-def err_embedded_include : Error<
+def err_embedded_directive : Error<
"embedding a #%0 directive within macro arguments is not supported">;
def ext_embedded_directive : Extension<
"embedding a directive within macro arguments has undefined behavior">,
@@ -615,9 +623,6 @@ def warn_auto_module_import : Warning<
def warn_uncovered_module_header : Warning<
"umbrella header for module '%0' does not include header '%1'">,
InGroup<IncompleteUmbrella>;
-def warn_forgotten_module_header : Warning<
- "header '%0' is included in module '%1' but not listed in module map">,
- InGroup<IncompleteModule>, DefaultIgnore;
def err_expected_id_building_module : Error<
"expected a module name in '__building_module' expression">;
def error_use_of_private_header_outside_module : Error<
diff --git a/include/clang/Basic/DiagnosticOptions.def b/include/clang/Basic/DiagnosticOptions.def
index a360a5a84e98..fdd325446e27 100644
--- a/include/clang/Basic/DiagnosticOptions.def
+++ b/include/clang/Basic/DiagnosticOptions.def
@@ -81,6 +81,8 @@ VALUE_DIAGOPT(MacroBacktraceLimit, 32, DefaultMacroBacktraceLimit)
VALUE_DIAGOPT(TemplateBacktraceLimit, 32, DefaultTemplateBacktraceLimit)
/// Limit depth of constexpr backtrace.
VALUE_DIAGOPT(ConstexprBacktraceLimit, 32, DefaultConstexprBacktraceLimit)
+/// Limit number of times to perform spell checking.
+VALUE_DIAGOPT(SpellCheckingLimit, 32, DefaultSpellCheckingLimit)
VALUE_DIAGOPT(TabStop, 32, DefaultTabStop) /// The distance between tab stops.
/// Column limit for formatting message diagnostics, or 0 if unused.
@@ -92,4 +94,3 @@ VALUE_DIAGOPT(MessageLength, 32, 0)
#undef SEMANTIC_DIAGOPT
#undef SEMANTIC_ENUM_DIAGOPT
#undef SEMANTIC_VALUE_DIAGOPT
-
diff --git a/include/clang/Basic/DiagnosticOptions.h b/include/clang/Basic/DiagnosticOptions.h
index 3e4d0eefbcf9..058e00f73e77 100644
--- a/include/clang/Basic/DiagnosticOptions.h
+++ b/include/clang/Basic/DiagnosticOptions.h
@@ -33,7 +33,8 @@ public:
enum { DefaultTabStop = 8, MaxTabStop = 100,
DefaultMacroBacktraceLimit = 6,
DefaultTemplateBacktraceLimit = 10,
- DefaultConstexprBacktraceLimit = 10 };
+ DefaultConstexprBacktraceLimit = 10,
+ DefaultSpellCheckingLimit = 50 };
// Define simple diagnostic options (with no accessors).
#define DIAGOPT(Name, Bits, Default) unsigned Name : Bits;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index b1305e182f0b..239d4d20bb72 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -108,6 +108,9 @@ def ext_alignof_expr : ExtWarn<
def warn_microsoft_dependent_exists : Warning<
"dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">,
InGroup<DiagGroup<"microsoft-exists">>;
+def warn_microsoft_qualifiers_ignored : Warning<
+ "qualifiers after comma in declarator list are ignored">,
+ InGroup<IgnoredAttributes>;
def ext_c11_generic_selection : Extension<
"generic selections are a C11-specific feature">, InGroup<C11>;
@@ -121,11 +124,15 @@ def ext_c11_alignment : Extension<
def ext_c11_noreturn : Extension<
"_Noreturn functions are a C11-specific feature">, InGroup<C11>;
+def err_c11_noreturn_misplaced : Error<
+ "'_Noreturn' keyword must precede function declarator">;
def ext_gnu_indirect_goto : Extension<
"use of GNU indirect-goto extension">, InGroup<GNULabelsAsValue>;
def ext_gnu_address_of_label : Extension<
"use of GNU address-of-label extension">, InGroup<GNULabelsAsValue>;
+def err_stmtexpr_file_scope : Error<
+ "statement expression not allowed at file scope">;
def ext_gnu_statement_expr : Extension<
"use of GNU statement expression extension">, InGroup<GNUStatementExpression>;
def ext_gnu_conditional_expr : Extension<
@@ -167,6 +174,9 @@ def err_expected_fn_body : Error<
def warn_attribute_on_function_definition : Warning<
"GCC does not allow %0 attribute in this position on a function definition">,
InGroup<GccCompat>;
+def warn_gcc_attribute_location : Warning<
+ "GCC does not allow an attribute in this position on a function declaration">,
+ InGroup<GccCompat>;
def warn_attribute_no_decl : Warning<
"attribute %0 ignored, because it is not attached to a declaration">,
InGroup<IgnoredAttributes>;
@@ -194,11 +204,19 @@ def err_expected_semi_after_namespace_name : Error<
"expected ';' after namespace name">;
def err_unexpected_namespace_attributes_alias : Error<
"attributes cannot be specified on namespace alias">;
+def err_unexpected_nested_namespace_attribute : Error<
+ "attributes cannot be specified on a nested namespace definition">;
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 ext_nested_namespace_definition : ExtWarn<
+ "nested namespace definition is a C++1z extension; "
+ "define each namespace separately">, InGroup<CXX1z>;
+def warn_cxx14_compat_nested_namespace_definition : Warning<
+ "nested namespace definition is incompatible with C++ standards before C++1z">,
+ InGroup<CXXPre1zCompat>, DefaultIgnore;
+def err_inline_nested_namespace_definition : Error<
+ "nested namespace definition cannot be 'inline'">;
def err_expected_semi_after_attribute_list : Error<
"expected ';' after attribute list">;
def err_expected_semi_after_static_assert : Error<
@@ -268,22 +286,17 @@ def ext_auto_storage_class : ExtWarn<
"'auto' storage class specifier is not permitted in C++11, and will not "
"be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>;
def ext_decltype_auto_type_specifier : ExtWarn<
- "'decltype(auto)' type specifier is a C++1y extension">, InGroup<CXX1y>;
+ "'decltype(auto)' type specifier is a C++14 extension">, InGroup<CXX14>;
def warn_cxx11_compat_decltype_auto_type_specifier : Warning<
"'decltype(auto)' type specifier is incompatible with C++ standards before "
- "C++1y">, InGroup<CXXPre1yCompat>, DefaultIgnore;
+ "C++14">, InGroup<CXXPre14Compat>, DefaultIgnore;
def ext_for_range : ExtWarn<
"range-based for loop is a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_for_range : Warning<
"range-based for loop is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
-def ext_for_range_identifier : ExtWarn<
- "range-based for loop with implicit deduced type is a C++1z extension">,
- InGroup<CXX1z>;
-def warn_cxx1y_compat_for_range_identifier : Warning<
- "range-based for loop with implicit deduced type is incompatible with "
- "C++ standards before C++1z">,
- InGroup<CXXPre1zCompat>, DefaultIgnore;
+def err_for_range_identifier : Error<
+ "range-based for loop requires type for loop variable">;
def err_for_range_expected_decl : Error<
"for range declaration must declare a variable">;
def err_argument_required_after_attribute : Error<
@@ -303,6 +316,8 @@ def err_expected_class_name_not_template :
Error<"'typename' is redundant; base classes are implicitly types">;
def err_unspecified_vla_size_with_static : Error<
"'static' may not be used with an unspecified variable length array size">;
+def err_unspecified_size_with_static : Error<
+ "'static' may not be used without an array size">;
def warn_deprecated_register : Warning<
"'register' storage class specifier is deprecated">,
InGroup<DeprecatedRegister>;
@@ -332,10 +347,12 @@ def err_invalid_vector_decl_spec_combination : Error<
def err_invalid_pixel_decl_spec_combination : Error<
"'__pixel' must be preceded by '__vector'. "
"'%0' declaration specifier not allowed here">;
-def err_invalid_vector_decl_spec : Error<
- "cannot use '%0' with '__vector'">;
def err_invalid_vector_bool_decl_spec : Error<
"cannot use '%0' with '__vector bool'">;
+def err_invalid_vector_double_decl_spec : Error <
+ "use of 'double' with '__vector' requires VSX support to be enabled (available on the POWER7 or later)">;
+def err_invalid_vector_long_double_decl_spec : Error<
+ "cannot use 'long double' with '__vector'">;
def warn_vector_long_decl_spec_combination : Warning<
"Use of 'long' with '__vector' is deprecated">, InGroup<Deprecated>;
def err_friend_invalid_in_context : Error<
@@ -363,6 +380,8 @@ def err_function_definition_not_allowed : Error<
"function definition is not allowed here">;
def err_expected_end_of_enumerator : Error<
"expected '= constant-expression' or end of enumerator definition">;
+def err_expected_coloncolon_after_super : Error<
+ "expected '::' after '__super'">;
/// Objective-C parser diagnostics
def err_expected_minus_or_plus : Error<
@@ -477,6 +496,8 @@ def ext_ellipsis_exception_spec : Extension<
InGroup<Microsoft>;
def err_dynamic_and_noexcept_specification : Error<
"cannot have both throw() and noexcept() clause on the same function">;
+def err_except_spec_unparsed : Error<
+ "unexpected end of exception specification">;
def warn_cxx98_compat_noexcept_decl : Warning<
"noexcept specifications are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
@@ -487,6 +508,8 @@ def err_constructor_bad_name : Error<
"missing return type for function %0; did you mean the constructor name %1?">;
def err_destructor_tilde_identifier : Error<
"expected a class name after '~' to name a destructor">;
+def err_destructor_tilde_scope : Error<
+ "'~' in destructor name should be after nested name specifier">;
def err_destructor_template_id : Error<
"destructor name %0 does not refer to a template">;
def err_default_arg_unparsed : Error<
@@ -498,11 +521,24 @@ def note_bracket_depth : Note<
def err_misplaced_ellipsis_in_declaration : Error<
"'...' must %select{immediately precede declared identifier|"
"be innermost component of anonymous pack declaration}0">;
+def warn_misplaced_ellipsis_vararg : Warning<
+ "'...' in this location creates a C-style varargs function"
+ "%select{, not a function parameter pack|}0">,
+ InGroup<DiagGroup<"ambiguous-ellipsis">>;
+def note_misplaced_ellipsis_vararg_existing_ellipsis : Note<
+ "preceding '...' declares a function parameter pack">;
+def note_misplaced_ellipsis_vararg_add_ellipsis : Note<
+ "place '...' %select{immediately before declared identifier|here}0 "
+ "to declare a function parameter pack">;
+def note_misplaced_ellipsis_vararg_add_comma : Note<
+ "insert ',' before '...' to silence this warning">;
def ext_abstract_pack_declarator_parens : ExtWarn<
"ISO C++11 requires a parenthesized pack declaration to have a name">,
InGroup<DiagGroup<"anonymous-pack-parens">>;
def err_function_is_not_record : Error<
"unexpected %0 in function call; perhaps remove the %0?">;
+def err_super_in_using_declaration : Error<
+ "'__super' cannot be used with a using declaration">;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
@@ -529,6 +565,10 @@ def warn_cxx98_compat_noexcept_expr : Warning<
def warn_cxx98_compat_nullptr : Warning<
"'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
+def warn_cxx14_compat_attribute : Warning<
+ "attributes on %select{a namespace|an enumerator}0 declaration are "
+ "incompatible with C++ standards before C++1z">,
+ InGroup<CXXPre1zCompat>, DefaultIgnore;
def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx98_compat_attribute : Warning<
@@ -564,6 +604,8 @@ def err_ms_property_expected_accessor_name : Error<
"expected name of accessor method">;
def err_ms_property_expected_comma_or_rparen : Error<
"expected ',' or ')' at end of property accessor list">;
+def err_ms_property_initializer : Error<
+ "property declaration cannot have an in-class initializer">;
/// C++ Templates
def err_expected_template : Error<"expected template">;
@@ -576,7 +618,7 @@ def err_class_on_template_template_param : Error<
def ext_template_template_param_typename : ExtWarn<
"template template parameter using 'typename' is a C++1z extension">,
InGroup<CXX1z>;
-def warn_cxx1y_compat_template_template_param_typename : Warning<
+def warn_cxx14_compat_template_template_param_typename : Warning<
"template template parameter using 'typename' is "
"incompatible with C++ standards before C++1z">,
InGroup<CXXPre1zCompat>, DefaultIgnore;
@@ -597,14 +639,16 @@ def warn_cxx11_right_shift_in_template_arg : Warning<
def warn_cxx98_compat_two_right_angle_brackets : Warning<
"consecutive right angle brackets are incompatible with C++98 (use '> >')">,
InGroup<CXX98Compat>, DefaultIgnore;
+def err_templated_invalid_declaration : Error<
+ "a static_assert declaration cannot be a template">;
def err_multiple_template_declarators : Error<
- "%select{|a template declaration|an explicit template specialization|"
- "an explicit template instantiation}0 can "
- "only %select{|declare|declare|instantiate}0 a single entity">;
+ "%select{|a template declaration|an explicit template specialization|"
+ "an explicit template instantiation}0 can "
+ "only %select{|declare|declare|instantiate}0 a single entity">;
def err_explicit_instantiation_with_definition : Error<
- "explicit template instantiation cannot have a definition; if this "
- "definition is meant to be an explicit specialization, add '<>' after the "
- "'template' keyword">;
+ "explicit template instantiation cannot have a definition; if this "
+ "definition is meant to be an explicit specialization, add '<>' after the "
+ "'template' keyword">;
def err_template_defn_explicit_instantiation : Error<
"%select{function|class|variable}0 cannot be defined in an explicit instantiation; if this "
"declaration is meant to be a %select{function|class|variable}0 definition, remove the 'template' keyword">;
@@ -612,7 +656,7 @@ def err_friend_explicit_instantiation : Error<
"friend cannot be declared in an explicit instantiation; if this "
"declaration is meant to be a friend declaration, remove the 'template' keyword">;
def err_explicit_instantiation_enum : Error<
- "enumerations cannot be explicitly instantiated">;
+ "enumerations cannot be explicitly instantiated">;
def err_expected_template_parameter : Error<"expected template parameter">;
def err_missing_dependent_template_keyword : Error<
@@ -654,7 +698,18 @@ def err_explicit_spec_non_template : Error<
def err_default_template_template_parameter_not_template : Error<
"default template argument for a template template parameter must be a class "
"template">;
-
+
+def ext_fold_expression : ExtWarn<
+ "pack fold expression is a C++1z extension">,
+ InGroup<CXX1z>;
+def warn_cxx14_compat_fold_expression : Warning<
+ "pack fold expression is incompatible with C++ standards before C++1z">,
+ InGroup<CXXPre1zCompat>, DefaultIgnore;
+def err_expected_fold_operator : Error<
+ "expected a foldable binary operator in fold expression">;
+def err_fold_operator_mismatch : Error<
+ "operators in fold expression must be the same">;
+
def err_ctor_init_missing_comma : Error<
"missing ',' between base or member initializers">;
@@ -699,7 +754,7 @@ 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++11 override control
def ext_override_control_keyword : ExtWarn<
"'%0' keyword is a C++11 extension">, InGroup<CXX11>;
@@ -751,6 +806,9 @@ def err_lambda_missing_parens : Error<
// Availability attribute
def err_expected_version : Error<
"expected a version of the form 'major[.minor[.subminor]]'">;
+def warn_expected_consistent_version_separator : Warning<
+ "use same version number separators '_' or '.'; as in "
+ "'major[.minor[.subminor]]'">, InGroup<Availability>;
def err_zero_version : Error<
"version number must have non-zero major, minor, or sub-minor version">;
def err_availability_expected_platform : Error<
@@ -818,7 +876,7 @@ def warn_pragma_expected_non_wide_string : Warning<
"expected non-wide string literal in '#pragma %0'">, InGroup<IgnoredPragmas>;
// - Generic errors
def err_pragma_missing_argument : Error<
- "missing argument to '#pragma %0'; expected %1">;
+ "missing argument to '#pragma %0'%select{|; expected %2}1">;
// - #pragma options
def warn_pragma_options_expected_align : Warning<
"expected 'align' following '#pragma options' - ignored">,
@@ -878,8 +936,8 @@ def err_pragma_optimize_extra_argument : Error<
"unexpected extra argument '%0' to '#pragma clang optimize'">;
// OpenCL Section 6.8.g
-def err_not_opencl_storage_class_specifier : Error<
- "OpenCL does not support the '%0' storage class specifier">;
+def err_opencl_unknown_type_specifier : Error<
+ "OpenCL does not support the '%0' %select{type qualifier|storage class specifier}1">;
// OpenCL EXTENSION pragma (OpenCL 1.1 [9.1])
def warn_pragma_expected_colon : Warning<
@@ -923,9 +981,14 @@ def err_omp_expected_identifier_for_critical : Error<
"expected identifier specifying the name of the 'omp critical' directive">;
// Pragma loop support.
+def err_pragma_loop_missing_argument : Error<
+ "missing argument; expected %select{an integer value|"
+ "'%select{enable|full}1' or 'disable'}0">;
def err_pragma_loop_invalid_option : Error<
"%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
"vectorize_width, interleave, interleave_count, unroll, or unroll_count">;
+def err_pragma_invalid_keyword : Error<
+ "invalid argument; expected '%select{enable|full}0' or 'disable'">;
// Pragma unroll support.
def warn_pragma_unroll_cuda_value_in_parens : Warning<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 1665a45e2cbf..8966c55d0963 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -64,6 +64,9 @@ def err_typecheck_converted_constant_expression : Error<
"value of type %0 is not implicitly convertible to %1">;
def err_typecheck_converted_constant_expression_disallowed : Error<
"conversion from %0 to %1 is not allowed in a converted constant expression">;
+def err_typecheck_converted_constant_expression_indirect : Error<
+ "conversion from %0 to %1 in converted constant expression would "
+ "bind reference to a temporary">;
def err_expr_not_cce : Error<
"%select{case value|enumerator value|non-type template argument|array size}0 "
"is not a constant expression">;
@@ -84,6 +87,9 @@ def note_ice_conversion_here : Note<
def err_ice_ambiguous_conversion : Error<
"ambiguous conversion from type %0 to an integral or unscoped "
"enumeration type">;
+def err_ice_too_large : Error<
+ "integer constant expression evaluates to value %0 that cannot be "
+ "represented in a %1-bit %select{signed|unsigned}2 integer type">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
@@ -172,6 +178,9 @@ def warn_unused_parameter : Warning<"unused parameter %0">,
InGroup<UnusedParameter>, DefaultIgnore;
def warn_unused_variable : Warning<"unused variable %0">,
InGroup<UnusedVariable>, DefaultIgnore;
+def warn_unused_local_typedef : Warning<
+ "unused %select{typedef|type alias}0 %1">,
+ InGroup<UnusedLocalTypedef>, DefaultIgnore;
def warn_unused_property_backing_ivar :
Warning<"ivar %0 which backs the property is not "
"referenced in this property's accessor">,
@@ -445,9 +454,13 @@ def note_strncat_wrong_size : Note<
"the terminating null byte">;
def warn_assume_side_effects : Warning<
- "the argument to __assume has side effects that will be discarded">,
+ "the argument to %0 has side effects that will be discarded">,
InGroup<DiagGroup<"assume">>;
+def warn_memcpy_chk_overflow : Warning<
+ "%0 will always overflow destination buffer">,
+ InGroup<DiagGroup<"builtin-memcpy-chk-size">>;
+
/// main()
// static main() is not an error in C, just in C++.
def warn_static_main : Warning<"'main' should not be declared static">,
@@ -521,6 +534,11 @@ def warn_cxx_ms_struct :
"with base classes or virtual functions">,
DefaultError, InGroup<IncompatibleMSStruct>;
def err_section_conflict : Error<"%0 causes a section type conflict with %1">;
+def err_no_base_classes : Error<"invalid use of '__super', %0 has no base classes">;
+def err_invalid_super_scope : Error<"invalid use of '__super', "
+ "this keyword can only be used inside class or member function scope">;
+def err_super_in_lambda_unsupported : Error<
+ "use of '__super' inside a lambda is unsupported">;
def warn_pragma_unused_undeclared_var : Warning<
"undeclared variable %0 used as an argument for '#pragma unused'">,
@@ -536,10 +554,10 @@ def err_pragma_pop_visibility_mismatch : Error<
"#pragma visibility pop with no matching #pragma visibility push">;
def note_surrounding_namespace_starts_here : Note<
"surrounding namespace with visibility attribute starts here">;
-def err_pragma_loop_invalid_value : Error<
- "invalid argument; expected a positive integer value">;
-def err_pragma_loop_invalid_keyword : Error<
- "invalid argument; expected 'enable' or 'disable'">;
+def err_pragma_loop_invalid_argument_type : Error<
+ "invalid argument of type %0; expected an integer type">;
+def err_pragma_loop_invalid_argument_value : Error<
+ "%select{invalid value '%0'; must be positive|value '%0' is too large}1">;
def err_pragma_loop_compatibility : Error<
"%select{incompatible|duplicate}0 directives '%1' and '%2'">;
def err_pragma_loop_precedes_nonloop : Error<
@@ -563,14 +581,19 @@ def err_protocol_has_circular_dependency : Error<
"protocol has circular dependency">;
def err_undeclared_protocol : Error<"cannot find protocol declaration for %0">;
def warn_undef_protocolref : Warning<"cannot find protocol definition for %0">;
+def warn_atprotocol_protocol : Warning<
+ "@protocol is using a forward protocol declaration of %0">, InGroup<AtProtocol>;
def warn_readonly_property : Warning<
"attribute 'readonly' of property %0 restricts attribute "
- "'readwrite' of property inherited from %1">;
+ "'readwrite' of property inherited from %1">,
+ InGroup<PropertyAttr>;
def warn_property_attribute : Warning<
- "'%1' attribute on property %0 does not match the property inherited from %2">;
+ "'%1' attribute on property %0 does not match the property inherited from %2">,
+ InGroup<PropertyAttr>;
def warn_property_types_are_incompatible : Warning<
- "property type %0 is incompatible with type %1 inherited from %2">;
+ "property type %0 is incompatible with type %1 inherited from %2">,
+ InGroup<DiagGroup<"incompatible-property-type">>;
def warn_protocol_property_mismatch : Warning<
"property of type %0 was selected for synthesis">,
InGroup<DiagGroup<"protocol-property-synthesis-ambiguity">>;
@@ -587,6 +610,8 @@ def note_class_declared : Note<
"class is declared here">;
def note_receiver_class_declared : Note<
"receiver is instance of class declared here">;
+def note_receiver_expr_here : Note<
+ "receiver expression is here">;
def note_receiver_is_id : Note<
"receiver is treated with 'id' type for purpose of method lookup">;
def note_suppressed_class_declare : Note<
@@ -696,7 +721,8 @@ def warn_implements_nscopying : Warning<
"default assign attribute on property %0 which implements "
"NSCopying protocol is not appropriate with -fobjc-gc[-only]">;
-def warn_multiple_method_decl : Warning<"multiple methods named %0 found">;
+def warn_multiple_method_decl : Warning<"multiple methods named %0 found">,
+ InGroup<ObjCMultipleMethodNames>;
def warn_strict_multiple_method_decl : Warning<
"multiple methods named %0 found">, InGroup<StrictSelector>, DefaultIgnore;
def warn_accessor_property_type_mismatch : Warning<
@@ -710,6 +736,11 @@ def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
def warn_duplicate_method_decl :
Warning<"multiple declarations of method %0 found and ignored">,
InGroup<MethodDuplicate>, DefaultIgnore;
+def warn_objc_cdirective_format_string :
+ Warning<"using %0 directive in %select{NSString|CFString}1 "
+ "which is being passed as a formatting argument to the formatting "
+ "%select{method|CFfunction}2">,
+ InGroup<ObjCCStringFormat>, DefaultIgnore;
def err_objc_var_decl_inclass :
Error<"cannot declare variable inside @interface or @protocol">;
def error_missing_method_context : Error<
@@ -738,7 +769,8 @@ def warn_objc_property_default_assign_on_object : Warning<
"default property attribute 'assign' not appropriate for non-GC object">,
InGroup<ObjCPropertyNoAttribute>;
def warn_property_attr_mismatch : Warning<
- "property attribute in class extension does not match the primary class">;
+ "property attribute in class extension does not match the primary class">,
+ InGroup<PropertyAttr>;
def warn_property_implicitly_mismatched : Warning <
"primary property declaration is implicitly strong while redeclaration "
"in class extension is weak">,
@@ -778,6 +810,11 @@ def warn_no_autosynthesis_property : Warning<
"%0 because it is 'readwrite' but it will be synthesized 'readonly' "
"via another property">,
InGroup<ObjCNoPropertyAutoSynthesis>;
+def warn_autosynthesis_property_in_superclass : Warning<
+ "auto property synthesis will not synthesize property "
+ "%0; it will be implemented by its superclass, use @dynamic to "
+ "acknowledge intention">,
+ InGroup<ObjCNoPropertyAutoSynthesis>;
def warn_autosynthesis_property_ivar_match :Warning<
"autosynthesized property %0 will use %select{|synthesized}1 instance variable "
"%2, not existing instance variable %3">,
@@ -927,7 +964,7 @@ def err_static_assert_expression_is_not_constant : Error<
def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">;
def ext_static_assert_no_message : ExtWarn<
"static_assert with no message is a C++1z extension">, InGroup<CXX1z>;
-def warn_cxx1y_compat_static_assert_no_message : Warning<
+def warn_cxx14_compat_static_assert_no_message : Warning<
"static_assert with no message is incompatible with C++ standards before C++1z">,
DefaultIgnore, InGroup<CXXPre1zCompat>;
@@ -1085,6 +1122,8 @@ 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_not_parsed : Error<
+ "exception specification is not available until end of class definition">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
@@ -1098,7 +1137,7 @@ def ext_ms_using_declaration_inaccessible : ExtWarn<
def err_access_ctor : Error<
"calling a %select{private|protected}0 constructor of class %2">,
AccessControl;
-def ext_rvalue_to_reference_access_ctor : ExtWarn<
+def ext_rvalue_to_reference_access_ctor : Extension<
"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>;
@@ -1462,6 +1501,9 @@ def note_uninit_reference_member : Note<
"uninitialized reference member is here">;
def warn_field_is_uninit : Warning<"field %0 is uninitialized when used here">,
InGroup<Uninitialized>;
+def warn_base_class_is_uninit : Warning<
+ "base class %0 is uninitialized when used here to access %q1">,
+ InGroup<Uninitialized>;
def warn_reference_field_is_uninit : Warning<
"reference %0 is not yet bound to a value when used here">,
InGroup<Uninitialized>;
@@ -1505,6 +1547,9 @@ def note_block_var_fixit_add_initialization : Note<
def note_in_omitted_aggregate_initializer : Note<
"in implicit initialization of %select{array element %1|field %1}0 "
"with omitted initializer">;
+def note_in_reference_temporary_list_initializer : Note<
+ "in initialization of temporary of type %0 created to "
+ "list-initialize this reference">;
def note_var_fixit_add_initialization : Note<
"initialize the variable %0 to silence this warning">;
def note_uninit_fixit_remove_cond : Note<
@@ -1522,7 +1567,7 @@ def err_temp_copy_no_viable : Error<
"returning object|throwing object|copying member subobject|copying array "
"element|allocating object|copying temporary|initializing base subobject|"
"initializing vector element|capturing value}0 of type %1">;
-def ext_rvalue_to_reference_temp_copy_no_viable : ExtWarn<
+def ext_rvalue_to_reference_temp_copy_no_viable : Extension<
"no viable constructor %select{copying variable|copying parameter|"
"returning object|throwing object|copying member subobject|copying array "
"element|allocating object|copying temporary|initializing base subobject|"
@@ -1594,9 +1639,9 @@ def err_auto_new_ctor_multiple_expressions : Error<
"new expression for type %0 contains multiple constructor arguments">;
def err_auto_missing_trailing_return : Error<
"'auto' return without trailing return type; deduced return types are a "
- "C++1y extension">;
+ "C++14 extension">;
def err_deduced_return_type : Error<
- "deduced return types are a C++1y extension">;
+ "deduced return types are a C++14 extension">;
def err_trailing_return_without_auto : Error<
"function with trailing return type must specify return type 'auto', not %0">;
def err_trailing_return_in_parens : Error<
@@ -1656,6 +1701,9 @@ def override_keyword_hides_virtual_member_function : Error<
"%select{function|functions}1">;
def err_function_marked_override_not_overriding : Error<
"%0 marked 'override' but does not override any member functions">;
+def warn_function_marked_not_override_overriding : Warning <
+ "%0 overrides a member function but is not marked 'override'">,
+ InGroup<CXX11WarnOverrideMethod>;
def err_class_marked_final_used_as_base : Error<
"base %0 is marked '%select{final|sealed}1'">;
def warn_abstract_final_class : Warning<
@@ -1745,10 +1793,10 @@ def note_for_range_begin_end : Note<
def warn_cxx98_compat_constexpr : Warning<
"'constexpr' specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
-// FIXME: Maybe this should also go in -Wc++1y-compat?
-def warn_cxx1y_compat_constexpr_not_const : Warning<
+// FIXME: Maybe this should also go in -Wc++14-compat?
+def warn_cxx14_compat_constexpr_not_const : Warning<
"'constexpr' non-static member function will not be implicitly 'const' "
- "in C++1y; add 'const' to avoid a change in behavior">,
+ "in C++14; add 'const' to avoid a change in behavior">,
InGroup<DiagGroup<"constexpr-not-const">>;
def err_invalid_constexpr : Error<
"%select{function parameter|typedef|non-static data member}0 "
@@ -1790,28 +1838,28 @@ def err_constexpr_body_invalid_stmt : Error<
"statement not allowed in constexpr %select{function|constructor}0">;
def ext_constexpr_body_invalid_stmt : ExtWarn<
"use of this statement in a constexpr %select{function|constructor}0 "
- "is a C++1y extension">, InGroup<CXX1y>;
+ "is a C++14 extension">, InGroup<CXX14>;
def warn_cxx11_compat_constexpr_body_invalid_stmt : Warning<
"use of this statement in a constexpr %select{function|constructor}0 "
- "is incompatible with C++ standards before C++1y">,
- InGroup<CXXPre1yCompat>, DefaultIgnore;
+ "is incompatible with C++ standards before C++14">,
+ InGroup<CXXPre14Compat>, DefaultIgnore;
def ext_constexpr_type_definition : ExtWarn<
"type definition in a constexpr %select{function|constructor}0 "
- "is a C++1y extension">, InGroup<CXX1y>;
+ "is a C++14 extension">, InGroup<CXX14>;
def warn_cxx11_compat_constexpr_type_definition : Warning<
"type definition in a constexpr %select{function|constructor}0 "
- "is incompatible with C++ standards before C++1y">,
- InGroup<CXXPre1yCompat>, DefaultIgnore;
+ "is incompatible with C++ standards before C++14">,
+ InGroup<CXXPre14Compat>, DefaultIgnore;
def err_constexpr_vla : Error<
"variably-modified type %0 cannot be used in a constexpr "
"%select{function|constructor}1">;
def ext_constexpr_local_var : ExtWarn<
"variable declaration in a constexpr %select{function|constructor}0 "
- "is a C++1y extension">, InGroup<CXX1y>;
+ "is a C++14 extension">, InGroup<CXX14>;
def warn_cxx11_compat_constexpr_local_var : Warning<
"variable declaration in a constexpr %select{function|constructor}0 "
- "is incompatible with C++ standards before C++1y">,
- InGroup<CXXPre1yCompat>, DefaultIgnore;
+ "is incompatible with C++ standards before C++14">,
+ InGroup<CXXPre14Compat>, DefaultIgnore;
def err_constexpr_local_var_static : Error<
"%select{static|thread_local}1 variable not permitted in a constexpr "
"%select{function|constructor}0">;
@@ -1828,16 +1876,18 @@ def err_enable_if_never_constant_expr : Error<
"'enable_if' attribute expression never produces a constant expression">;
def err_constexpr_body_no_return : Error<
"no return statement in constexpr function">;
+def err_constexpr_return_missing_expr : Error<
+ "non-void constexpr function %0 should return a value">;
def warn_cxx11_compat_constexpr_body_no_return : Warning<
"constexpr function with no return statements is incompatible with C++ "
- "standards before C++1y">, InGroup<CXXPre1yCompat>, DefaultIgnore;
+ "standards before C++14">, InGroup<CXXPre14Compat>, DefaultIgnore;
def ext_constexpr_body_multiple_return : ExtWarn<
- "multiple return statements in constexpr function is a C++1y extension">,
- InGroup<CXX1y>;
+ "multiple return statements in constexpr function is a C++14 extension">,
+ InGroup<CXX14>;
def warn_cxx11_compat_constexpr_body_multiple_return : Warning<
"multiple return statements in constexpr function "
- "is incompatible with C++ standards before C++1y">,
- InGroup<CXXPre1yCompat>, DefaultIgnore;
+ "is incompatible with C++ standards before C++14">,
+ InGroup<CXXPre14Compat>, DefaultIgnore;
def note_constexpr_body_previous_return : Note<
"previous return statement is here">;
def err_constexpr_function_try_block : Error<
@@ -1848,8 +1898,6 @@ def err_constexpr_ctor_missing_init : Error<
"constexpr constructor must initialize all members">;
def note_constexpr_ctor_missing_init : Note<
"member not initialized by constructor">;
-def err_constexpr_method_non_literal : Error<
- "non-literal type %0 cannot have constexpr members">;
def note_non_literal_no_constexpr_ctors : Note<
"%0 is not literal because it is not an aggregate and has no constexpr "
"constructors other than copy or move constructors">;
@@ -1897,8 +1945,12 @@ def err_attribute_bad_neon_vector_size : Error<
"Neon vector size must be 64 or 128 bits">;
def err_attribute_unsupported : Error<
"%0 attribute is not supported for this target">;
+// The err_*_attribute_argument_not_int are seperate because they're used by
+// VerifyIntegerConstantExpression.
def err_aligned_attribute_argument_not_int : Error<
"'aligned' attribute requires integer constant">;
+def err_align_value_attribute_argument_not_int : Error<
+ "'align_value' attribute requires integer constant">;
def err_alignas_attribute_wrong_decl_type : Error<
"%0 attribute cannot be applied to a %select{function parameter|"
"variable with 'register' storage class|'catch' variable|bit-field}1">;
@@ -1934,12 +1986,22 @@ def err_attribute_pointers_only : Error<warn_attribute_pointers_only.Text>;
def warn_attribute_return_pointers_only : Warning<
"%0 attribute only applies to return values that are pointers">,
InGroup<IgnoredAttributes>;
+def warn_attribute_return_pointers_refs_only : Warning<
+ "%0 attribute only applies to return values that are pointers or references">,
+ InGroup<IgnoredAttributes>;
+def warn_attribute_pointer_or_reference_only : Warning<
+ "%0 attribute only applies to a pointer or reference (%1 is invalid)">,
+ InGroup<IgnoredAttributes>;
def err_attribute_no_member_pointers : Error<
"%0 attribute cannot be used with pointers to members">;
def err_attribute_invalid_implicit_this_argument : Error<
"%0 attribute is invalid for the implicit this argument">;
def err_ownership_type : Error<
"%0 attribute only applies to %select{pointer|integer}1 arguments">;
+def err_ownership_returns_index_mismatch : Error<
+ "'ownership_returns' attribute index does not match; here it is %0">;
+def note_ownership_returns_index_mismatch : Note<
+ "declared with index %0 here">;
def err_format_strftime_third_parameter : Error<
"strftime format attribute requires 3rd parameter to be 0">;
def err_format_attribute_requires_variadic : Error<
@@ -2054,14 +2116,22 @@ def err_no_accessor_for_property : Error<
def error_cannot_find_suitable_accessor : Error<
"cannot find suitable %select{getter|setter}0 for property %1">;
-def err_attribute_aligned_not_power_of_two : Error<
+def err_alignment_not_power_of_two : Error<
"requested alignment is not a power of 2">;
+
def err_attribute_aligned_too_great : Error<
"requested alignment must be %0 bytes or smaller">;
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
- "%q0 redeclared without %1 attribute: previous %1 ignored">;
+ "%q0 redeclared without %1 attribute: previous %1 ignored">,
+ InGroup<DiagGroup<"inconsistent-dllimport">>;
+def warn_dllimport_dropped_from_inline_function : Warning<
+ "%q0 redeclared inline; %1 attribute ignored">,
+ InGroup<IgnoredAttributes>;
def warn_attribute_ignored : Warning<"%0 attribute ignored">,
InGroup<IgnoredAttributes>;
+def warn_attribute_ignored_on_inline :
+ Warning<"%0 attribute ignored on inline function">,
+ InGroup<IgnoredAttributes>;
def warn_attribute_after_definition_ignored : Warning<
"attribute %0 after definition is ignored">,
InGroup<IgnoredAttributes>;
@@ -2110,6 +2180,8 @@ def err_declspec_thread_on_thread_variable : Error<
"thread-local storage specifier">;
def err_attribute_dll_not_extern : Error<
"%q0 must have external linkage when declared %q1">;
+def err_attribute_dll_thread_local : Error<
+ "%q0 cannot be thread local when declared %q1">;
def warn_attribute_invalid_on_definition : Warning<
"'%0' attribute cannot be specified on a definition">,
InGroup<IgnoredAttributes>;
@@ -2139,7 +2211,7 @@ def warn_attribute_dll_instantiated_base_class : Warning<
"propagating dll attribute to %select{already instantiated|explicitly specialized}0 "
"base class template "
"%select{without dll attribute|with different dll attribute}1 is not supported">,
- InGroup<DiagGroup<"unsupported-dll-base-class-template">>;
+ InGroup<DiagGroup<"unsupported-dll-base-class-template">>, DefaultIgnore;
def err_attribute_weakref_not_static : Error<
"weakref declaration must have internal linkage">;
def err_attribute_weakref_not_global_context : Error<
@@ -2164,22 +2236,25 @@ def warn_attribute_wrong_decl_type : Warning<
"%0 attribute only applies to %select{functions|unions|"
"variables and functions|functions and methods|parameters|"
"functions, methods and blocks|functions, methods, and classes|"
- "functions, methods, and parameters|classes|variables|methods|"
+ "functions, methods, and parameters|classes|enums|variables|methods|"
"variables, functions and labels|fields and global variables|structs|"
- "variables, functions and tag types|thread-local variables|"
+ "variables and typedefs|thread-local variables|"
"variables and fields|variables, data members and tag types|"
"types and namespaces|Objective-C interfaces|methods and properties|"
"struct or union|struct, union or class|types|"
"Objective-C instance methods|init methods of interface or class extension declarations|"
"variables, functions and classes|Objective-C protocols|"
"functions and global variables|structs or typedefs|"
- "interface or protocol declarations}1">,
+ "interface or protocol declarations|kernel functions}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
def warn_type_attribute_wrong_type : Warning<
"'%0' only applies to %select{function|pointer|"
"Objective-C object or block pointer}1 types; type here is %2">,
InGroup<IgnoredAttributes>;
+def warn_incomplete_encoded_type : Warning<
+ "encoding of %0 type is incomplete because %1 component has unknown encoding">,
+ InGroup<DiagGroup<"encode-type">>;
def warn_attribute_requires_functions_or_static_globals : Warning<
"%0 only applies to variables with static storage duration and functions">,
InGroup<IgnoredAttributes>;
@@ -2197,7 +2272,10 @@ def err_cconv_change : Error<
def warn_cconv_ignored : Warning<
"calling convention %0 ignored for this target">, InGroup<IgnoredAttributes>;
def err_cconv_knr : Error<
- "function with no prototype cannot use %0 calling convention">;
+ "function with no prototype cannot use the %0 calling convention">;
+def warn_cconv_knr : Warning<
+ err_cconv_knr.Text>,
+ InGroup<DiagGroup<"missing-prototype-for-cc">>;
def err_cconv_varargs : Error<
"variadic function cannot use %0 calling convention">;
def warn_cconv_varargs : Warning<
@@ -2307,6 +2385,21 @@ def warn_cannot_resolve_lock : Warning<
"cannot resolve lock expression">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
+// Thread safety warnings negative capabilities
+def warn_acquire_requires_negative_cap : Warning<
+ "acquiring %0 '%1' requires negative capability '%2'">,
+ InGroup<ThreadSafetyNegative>, DefaultIgnore;
+
+// Thread safety warnings on pass by reference
+def warn_guarded_pass_by_reference : Warning<
+ "passing variable '%1' by reference requires holding %0 "
+ "%select{'%2'|'%2' exclusively}3">,
+ InGroup<ThreadSafetyReference>, DefaultIgnore;
+def warn_pt_guarded_pass_by_reference : Warning<
+ "passing the value that '%1' points to by reference requires holding %0 "
+ "%select{'%2'|'%2' exclusively}3">,
+ InGroup<ThreadSafetyReference>, DefaultIgnore;
+
// Imprecise thread safety warnings
def warn_variable_requires_lock : Warning<
"%select{reading|writing}3 variable '%1' requires holding %0 "
@@ -2332,9 +2425,15 @@ def warn_fun_requires_lock_precise :
InGroup<ThreadSafetyPrecise>, DefaultIgnore;
def note_found_mutex_near_match : Note<"found near match '%0'">;
+// Verbose thread safety warnings
+def warn_thread_safety_verbose : Warning<"Thread safety verbose warning.">,
+ InGroup<ThreadSafetyVerbose>, DefaultIgnore;
+def note_thread_warning_in_fun : Note<"Thread warning in function '%0'">;
+def note_guarded_by_declared_here : Note<"Guarded_by declared here.">;
+
// Dummy warning that will trigger "beta" warnings from the analysis if enabled.
-def warn_thread_safety_beta : Warning<
- "Thread safety beta warning.">, InGroup<ThreadSafetyBeta>, DefaultIgnore;
+def warn_thread_safety_beta : Warning<"Thread safety beta warning.">,
+ InGroup<ThreadSafetyBeta>, DefaultIgnore;
// Consumed warnings
def warn_use_in_invalid_state : Warning<
@@ -2408,7 +2507,7 @@ def warn_non_literal_null_pointer : Warning<
"expression which evaluates to zero treated as a null pointer constant of "
"type %0">, InGroup<NonLiteralNullConversion>;
def warn_impcast_null_pointer_to_integer : Warning<
- "implicit conversion of NULL constant to %0">,
+ "implicit conversion of %select{NULL|nullptr}0 constant to %1">,
InGroup<NullConversion>;
def warn_impcast_floating_point_to_bool : Warning<
"implicit conversion turns floating-point number into bool: %0 to %1">,
@@ -2418,6 +2517,10 @@ def warn_impcast_pointer_to_bool : Warning<
"address of%select{| function| array}0 '%1' will always evaluate to "
"'true'">,
InGroup<PointerBoolConversion>;
+def warn_cast_nonnull_to_bool : Warning<
+ "nonnull parameter '%0' will evaluate to "
+ "'true' on first encounter">,
+ InGroup<PointerBoolConversion>;
def warn_this_bool_conversion : Warning<
"'this' pointer cannot be null in well-defined C++ code; pointer may be "
"assumed to always convert to true">, InGroup<UndefinedBoolConversion>;
@@ -2430,6 +2533,10 @@ def warn_null_pointer_compare : Warning<
"comparison of %select{address of|function|array}0 '%1' %select{not |}2"
"equal to a null pointer is always %select{true|false}2">,
InGroup<TautologicalPointerCompare>;
+def warn_nonnull_parameter_compare : Warning<
+ "comparison of nonnull parameter '%0' %select{not |}1"
+ "equal to a null pointer is %select{true|false}1 on first encounter">,
+ InGroup<TautologicalPointerCompare>;
def warn_this_null_compare : Warning<
"'this' pointer cannot be null in well-defined C++ code; comparison may be "
"assumed to always evaluate to %select{true|false}0">,
@@ -2500,6 +2607,7 @@ def warn_attribute_protected_visibility :
InGroup<DiagGroup<"unsupported-visibility">>;
def err_mismatched_visibility: Error<"visibility does not match previous declaration">;
def note_previous_attribute : Note<"previous attribute is here">;
+def note_conflicting_attribute : Note<"conflicting attribute is here">;
def note_attribute : Note<"attribute is here">;
def err_mismatched_ms_inheritance : Error<
"inheritance model does not match %select{definition|previous declaration}0">;
@@ -2739,6 +2847,9 @@ def note_ovl_candidate : Note<"candidate "
"|volatile and restrict|const, volatile, and restrict}4)}2">;
def note_ovl_candidate_inherited_constructor : Note<"inherited from here">;
+def note_ovl_candidate_illegal_constructor : Note<
+ "candidate %select{constructor|template}0 ignored: "
+ "instantiation %select{takes|would take}0 its own class type by value">;
def note_ovl_candidate_bad_deduction : Note<
"candidate template ignored: failed template argument deduction">;
def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "
@@ -2756,7 +2867,7 @@ def note_ovl_candidate_instantiation_depth : Note<
"candidate template ignored: substitution exceeded maximum template "
"instantiation depth">;
def note_ovl_candidate_underqualified : Note<
- "candidate template ignored: can't deduce a type for %0 which would "
+ "candidate template ignored: can't deduce a type for %0 that would "
"make %2 equal %1">;
def note_ovl_candidate_substitution_failure : Note<
"candidate template ignored: substitution failure%0%1">;
@@ -2962,8 +3073,18 @@ def note_ovl_candidate_bad_target : Note<
"function (the implicit copy assignment operator)|"
"function (the implicit move assignment operator)|"
"constructor (inherited)}0 not viable: call to "
- "%select{__device__|__global__|__host__|__host__ __device__}1 function from"
- " %select{__device__|__global__|__host__|__host__ __device__}2 function">;
+ "%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from"
+ " %select{__device__|__global__|__host__|__host__ __device__|invalid}2 function">;
+def note_implicit_member_target_infer_collision : Note<
+ "implicit %select{"
+ "default constructor|"
+ "copy constructor|"
+ "move constructor|"
+ "copy assignment operator|"
+ "move assignment operator|"
+ "destructor}0 inferred target collision: call to both "
+ "%select{__device__|__global__|__host__|__host__ __device__}1 and "
+ "%select{__device__|__global__|__host__|__host__ __device__}2 members">;
def note_ambiguous_type_conversion: Note<
"because of ambiguity in conversion %diff{of $ to $|between types}0,1">;
@@ -3103,11 +3224,11 @@ def err_template_parameter_default_friend_template : Error<
def err_template_template_parm_no_parms : Error<
"template template parameter must have its own template parameters">;
-def ext_variable_template : ExtWarn<"variable templates are a C++1y extension">,
- InGroup<CXX1y>;
+def ext_variable_template : ExtWarn<"variable templates are a C++14 extension">,
+ InGroup<CXX14>;
def warn_cxx11_compat_variable_template : Warning<
- "variable templates are incompatible with C++ standards before C++1y">,
- InGroup<CXXPre1yCompat>, DefaultIgnore;
+ "variable templates are incompatible with C++ standards before C++14">,
+ InGroup<CXXPre14Compat>, DefaultIgnore;
def err_template_variable_noparams : Error<
"extraneous 'template<>' in declaration of variable %0">;
def err_template_member : Error<"member %0 declared as a template">;
@@ -3181,6 +3302,10 @@ def err_template_arg_wrongtype_null_constant : Error<
def err_deduced_non_type_template_arg_type_mismatch : Error<
"deduced non-type template argument does not have the same type as the "
"its corresponding template parameter%diff{ ($ vs $)|}0,1">;
+def err_non_type_template_arg_subobject : Error<
+ "non-type template argument refers to subobject '%0'">;
+def err_non_type_template_arg_addr_label_diff : Error<
+ "template argument / label address difference / what did you expect?">;
def err_template_arg_not_convertible : Error<
"non-type template argument of type %0 cannot be converted to a value "
"of type %1">;
@@ -3232,6 +3357,9 @@ def err_template_arg_not_object_or_func : Error<
"non-type template argument does not refer to an object or function">;
def err_template_arg_not_pointer_to_member_form : Error<
"non-type template argument is not a pointer to member constant">;
+def err_template_arg_member_ptr_base_derived_not_supported : Error<
+ "sorry, non-type template argument of pointer-to-member type %1 that refers "
+ "to member %q0 of a different class is not supported yet">;
def ext_template_arg_extra_parens : ExtWarn<
"address non-type template argument cannot be surrounded by parentheses">;
def warn_cxx98_compat_template_arg_extra_parens : Warning<
@@ -3435,6 +3563,8 @@ def note_template_variable_def_here : Note<
"in instantiation of variable template specialization %q0 requested here">;
def note_template_enum_def_here : Note<
"in instantiation of enumeration %q0 requested here">;
+def note_template_nsdmi_here : Note<
+ "in instantiation of default member initializer %q0 requested here">;
def note_template_type_alias_instantiation_here : Note<
"in instantiation of template type alias %0 requested here">;
def note_template_exception_spec_instantiation_here : Note<
@@ -3559,6 +3689,11 @@ def err_invalid_var_template_spec_type : Error<"type %2 "
"of %select{explicit instantiation|explicit specialization|"
"partial specialization|redeclaration}0 of %1 does not match"
" expected type %3">;
+def err_mismatched_exception_spec_explicit_instantiation : Error<
+ "exception specification in explicit instantiation does not match instantiated one">;
+def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn<
+ "exception specification in explicit instantiation does not match instantiated one">,
+ InGroup<Microsoft>;
// C++ typename-specifiers
def err_typename_nested_not_found : Error<"no type named %0 in %1">;
@@ -3680,6 +3815,14 @@ def err_ellipsis_in_declarator_not_parameter : Error<
def err_sizeof_pack_no_pack_name : Error<
"%0 does not refer to the name of a parameter pack">;
+def err_fold_expression_packs_both_sides : Error<
+ "binary fold expression has unexpanded parameter packs in both operands">;
+def err_fold_expression_empty : Error<
+ "unary fold expression has empty expansion for operator '%0' "
+ "with no fallback value">;
+def err_fold_expression_bad_operand : Error<
+ "expression not permitted as operand of fold expression">;
+
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;
def err_unexpected_namespace : Error<
@@ -3706,6 +3849,9 @@ def warn_property_method_deprecated :
InGroup<DeprecatedDeclarations>;
def warn_deprecated_message : Warning<"%0 is deprecated: %1">,
InGroup<DeprecatedDeclarations>;
+def warn_deprecated_anonymous_namespace : Warning<
+ "'deprecated' attribute on anonymous namespace ignored">,
+ InGroup<IgnoredAttributes>;
def warn_deprecated_fwdclass_message : Warning<
"%0 may be deprecated because the receiver type is unknown">,
InGroup<DeprecatedDeclarations>;
@@ -3854,6 +4000,10 @@ def err_redefinition_different_type : Error<
"redefinition of %0 with a different type%diff{: $ vs $|}1,2">;
def err_redefinition_different_kind : Error<
"redefinition of %0 as different kind of symbol">;
+def err_redefinition_different_namespace_alias : Error<
+ "redefinition of %0 as an alias for a different namespace">;
+def note_previous_namespace_alias : Note<
+ "previously defined as an alias for %0">;
def warn_forward_class_redefinition : Warning<
"redefinition of forward class %0 of a typedef name of an object type is ignored">,
InGroup<DiagGroup<"objc-forward-class-redefinition">>;
@@ -3909,6 +4059,9 @@ def ext_enum_too_large : ExtWarn<
def ext_enumerator_increment_too_large : ExtWarn<
"incremented enumerator value %0 is not representable in the "
"largest integer type">, InGroup<EnumTooLarge>;
+def warn_flag_enum_constant_out_of_range : Warning<
+ "enumeration value %0 is out of range of flags in enumeration type %1">,
+ InGroup<FlagEnum>;
def warn_illegal_constant_array_size : Extension<
"size of static array must be an integer constant expression">;
@@ -4067,28 +4220,35 @@ def warn_missing_braces : Warning<
def err_redefinition_of_label : Error<"redefinition of label %0">;
def err_undeclared_label_use : Error<"use of undeclared label %0">;
+def err_goto_ms_asm_label : Error<
+ "cannot jump from this goto statement to label %0 inside an inline assembly block">;
+def note_goto_ms_asm_label : Note<
+ "inline assembly label %0 declared here">;
def warn_unused_label : Warning<"unused label %0">,
InGroup<UnusedLabel>, DefaultIgnore;
-def err_goto_into_protected_scope : Error<"goto into protected scope">;
-def ext_goto_into_protected_scope : ExtWarn<"goto into protected scope">,
+def err_goto_into_protected_scope : Error<
+ "cannot jump from this goto statement to its label">;
+def ext_goto_into_protected_scope : ExtWarn<
+ "jump from this goto statement to its label is a Microsoft extension">,
InGroup<Microsoft>;
def warn_cxx98_compat_goto_into_protected_scope : Warning<
- "goto would jump into protected scope in C++98">,
+ "jump from this goto statement to its label is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_switch_into_protected_scope : Error<
- "switch case is in protected scope">;
+ "cannot jump from switch statement to this case label">;
def warn_cxx98_compat_switch_into_protected_scope : Warning<
- "switch case would be in a protected scope in C++98">,
+ "jump from switch statement to this case label is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_indirect_goto_without_addrlabel : Error<
"indirect goto in function with no address-of-label expressions">;
def err_indirect_goto_in_protected_scope : Error<
- "indirect goto might cross protected scopes">;
+ "cannot jump from this indirect goto statement to one of its possible targets">;
def warn_cxx98_compat_indirect_goto_in_protected_scope : Warning<
- "indirect goto might cross protected scopes in C++98">,
- InGroup<CXX98Compat>, DefaultIgnore;
-def note_indirect_goto_target : Note<"possible target of indirect goto">;
+ "jump from this indirect goto statement to one of its possible targets "
+ "is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
+def note_indirect_goto_target : Note<
+ "possible target of indirect goto statement">;
def note_protected_by_variable_init : Note<
"jump bypasses variable initialization">;
def note_protected_by_variable_nontriv_destructor : Note<
@@ -4528,7 +4688,7 @@ def warn_logical_and_in_logical_or : Warning<
"'&&' within '||'">, InGroup<LogicalOpParentheses>;
def warn_overloaded_shift_in_comparison :Warning<
- "overloaded operator %select{>>|<<}0 has lower precedence than "
+ "overloaded operator %select{>>|<<}0 has higher precedence than "
"comparison operator">,
InGroup<OverloadedShiftOpParentheses>;
def note_evaluate_comparison_first :Note<
@@ -4541,6 +4701,9 @@ def warn_addition_in_bitshift : Warning<
def warn_self_assignment : Warning<
"explicitly assigning value of variable of type %0 to itself">,
InGroup<SelfAssignment>, DefaultIgnore;
+def warn_self_move : Warning<
+ "explicitly moving variable of type %0 to itself">,
+ InGroup<SelfMove>, DefaultIgnore;
def warn_string_plus_int : Warning<
"adding %0 to a string does not append to the string">,
@@ -4819,9 +4982,11 @@ def err_typecheck_comparison_of_distinct_pointers : Error<
def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn<
"comparison of distinct pointer types (%0 and %1) uses non-standard "
"composite pointer type %2">, InGroup<CompareDistinctPointerType>;
+def err_typecheck_op_on_nonoverlapping_address_space_pointers : Error<
+ "%select{comparison between %diff{ ($ and $)|}0,1"
+ "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1}2"
+ " which are pointers to non-overlapping address spaces">;
def err_typecheck_assign_const : Error<"read-only variable is not assignable">;
-def err_stmtexpr_file_scope : Error<
- "statement expression not allowed at file scope">;
def warn_mixed_sign_comparison : Warning<
"comparison of integers of different signs: %0 and %1">,
InGroup<SignCompare>, DefaultIgnore;
@@ -5128,7 +5293,7 @@ def err_bad_cxx_cast_member_pointer_size : Error<
"cannot %select{||reinterpret_cast||C-style cast|}0 from member pointer "
"type %1 to member pointer type %2 of different size">;
def err_bad_reinterpret_cast_reference : Error<
- "reinterpret_cast of a %0 to %1 needs its address which is not allowed">;
+ "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<UndefinedReinterpretCast>, DefaultIgnore;
@@ -5162,6 +5327,7 @@ def err_uuidof_without_guid : Error<
def err_uuidof_with_multiple_guids : Error<
"cannot call operator __uuidof on a type with multiple GUIDs">;
def err_incomplete_typeid : Error<"'typeid' of incomplete type %0">;
+def err_variably_modified_typeid : Error<"'typeid' of variably modified type %0">;
def err_static_illegal_in_new : Error<
"the 'static' modifier for the array size is not legal in new expressions">;
def err_array_new_needs_size : Error<
@@ -5206,15 +5372,18 @@ def err_address_space_qualified_delete : Error<
def err_default_init_const : Error<
"default initialization of an object of const type %0"
- "%select{| requires a user-provided default constructor}1">;
+ "%select{| without a user-provided default constructor}1">;
+def note_add_initializer : Note<
+ "add an explicit initializer to initialize %0">;
def err_delete_operand : Error<"cannot delete expression of type %0">;
def ext_delete_void_ptr_operand : ExtWarn<
- "cannot delete expression with pointer-to-'void' type %0">;
+ "cannot delete expression with pointer-to-'void' type %0">,
+ InGroup<DeleteIncomplete>;
def err_ambiguous_delete_operand : Error<
"ambiguous conversion of delete expression of type %0 to a pointer">;
def warn_delete_incomplete : Warning<
"deleting pointer to incomplete type %0 may cause undefined behavior">,
- InGroup<DiagGroup<"delete-incomplete">>;
+ InGroup<DeleteIncomplete>;
def err_delete_incomplete_class_type : Error<
"deleting incomplete class type %0; no conversions to pointer type">;
def err_delete_explicit_conversion : Error<
@@ -5323,9 +5492,6 @@ let CategoryName = "Lambda Issue" in {
"'this' cannot be %select{implicitly |}0captured in this context">;
def err_lambda_capture_anonymous_var : Error<
"unnamed variable cannot be implicitly captured in a lambda expression">;
- def err_lambda_capture_vm_type : Error<
- "variable %0 with variably modified type cannot be captured in "
- "a lambda expression">;
def err_lambda_capture_flexarray_type : Error<
"variable %0 with flexible array member cannot be captured in "
"a lambda expression">;
@@ -5361,12 +5527,12 @@ let CategoryName = "Lambda Issue" in {
"implicit capture of lambda object due to conversion to block pointer "
"here">;
- // C++1y lambda init-captures.
+ // C++14 lambda init-captures.
def warn_cxx11_compat_init_capture : Warning<
"initialized lambda captures are incompatible with C++ standards "
- "before C++1y">, InGroup<CXXPre1yCompat>, DefaultIgnore;
+ "before C++14">, InGroup<CXXPre14Compat>, DefaultIgnore;
def ext_init_capture : ExtWarn<
- "initialized lambda captures are a C++1y extension">, InGroup<CXX1y>;
+ "initialized lambda captures are a C++14 extension">, InGroup<CXX14>;
def err_init_capture_no_expression : Error<
"initializer missing for lambda capture %0">;
def err_init_capture_multiple_expressions : Error<
@@ -5936,13 +6102,19 @@ def warn_unused_voidptr : Warning<
InGroup<UnusedValue>;
def warn_unused_property_expr : Warning<
"property access result unused - getters should not be used for side effects">,
- InGroup<UnusedValue>;
+ InGroup<UnusedGetterReturnValue>;
def warn_unused_container_subscript_expr : Warning<
"container access result unused - container access should not be used for side effects">,
InGroup<UnusedValue>;
def warn_unused_call : Warning<
"ignoring return value of function declared with %0 attribute">,
InGroup<UnusedValue>;
+def warn_side_effects_unevaluated_context : Warning<
+ "expression with side effects has no effect in an unevaluated context">,
+ InGroup<UnevaluatedExpression>;
+def warn_side_effects_typeid : Warning<
+ "expression with side effects will be evaluated despite being used as an "
+ "operand to 'typeid'">, InGroup<PotentiallyEvaluatedExpression>;
def warn_unused_result : Warning<
"ignoring return value of function declared with warn_unused_result "
"attribute">, InGroup<DiagGroup<"unused-result">>;
@@ -5974,11 +6146,15 @@ def warn_zero_size_struct_union_compat : Warning<"%select{|empty }0"
def warn_zero_size_struct_union_in_extern_c : Warning<"%select{|empty }0"
"%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">,
InGroup<ExternCCompat>;
+def warn_cast_qual : Warning<"cast from %0 to %1 drops %select{const and "
+ "volatile qualifiers|const qualifier|volatile qualifier}2">,
+ InGroup<CastQual>, DefaultIgnore;
+def warn_cast_qual2 : Warning<"cast from %0 to %1 must have all intermediate "
+ "pointers const qualified to be safe">, InGroup<CastQual>, DefaultIgnore;
} // End of general sema category.
// inline asm.
let CategoryName = "Inline Assembly Issue" in {
- def err_asm_wide_character : Error<"wide string is invalid in 'asm'">;
def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">;
def err_asm_invalid_output_constraint : Error<
"invalid output constraint '%0' in asm">;
@@ -5991,14 +6167,20 @@ let CategoryName = "Inline Assembly Issue" in {
def err_asm_tying_incompatible_types : Error<
"unsupported inline asm: input with type "
"%diff{$ matching output with type $|}0,1">;
+ def err_asm_unexpected_constraint_alternatives : Error<
+ "asm constraint has an unexpected number of alternatives: %0 vs %1">;
def err_asm_incomplete_type : Error<"asm operand has incomplete type %0">;
def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">;
def err_asm_bad_register_type : Error<"bad type for named register variable">;
def err_asm_invalid_input_size : Error<
"invalid input size for constraint '%0'">;
+ def err_asm_invalid_output_size : Error<
+ "invalid output size for constraint '%0'">;
def err_invalid_asm_cast_lvalue : Error<
"invalid use of a cast in a inline asm context requiring an l-value: "
"remove the cast or build with -fheinous-gnu-extensions">;
+ def err_invalid_asm_value_for_constraint
+ : Error <"value '%0' out of range for constraint '%1'">;
def warn_asm_label_on_auto_decl : Warning<
"ignored asm label '%0' on automatic variable">;
@@ -6010,6 +6192,9 @@ let CategoryName = "Inline Assembly Issue" in {
"value size does not match register size specified by the constraint "
"and modifier">,
InGroup<ASMOperandWidths>;
+
+ def note_asm_missing_constraint_modifier : Note<
+ "use constraint modifier \"%0\"">;
}
let CategoryName = "Semantic Issue" in {
@@ -6080,9 +6265,12 @@ def err_in_class_initializer_literal_type : Error<
"'constexpr' specifier">;
def err_in_class_initializer_non_constant : Error<
"in-class initializer for static data member is not a constant expression">;
-def err_in_class_initializer_references_def_ctor : Error<
- "defaulted default constructor of %0 cannot be used by non-static data "
- "member initializer which appears before end of class definition">;
+def err_in_class_initializer_not_yet_parsed
+ : Error<"cannot use defaulted default constructor of %0 within the class "
+ "outside of member functions because %1 has an initializer">;
+def err_in_class_initializer_not_yet_parsed_outer_class
+ : Error<"cannot use defaulted default constructor of %0 within "
+ "%1 outside of member functions because %2 has an initializer">;
def ext_in_class_initializer_non_constant : Extension<
"in-class initializer for static data member is not a constant expression; "
@@ -6130,8 +6318,9 @@ def err_anonymous_record_bad_member : Error<
def err_anonymous_record_nonpublic_member : Error<
"anonymous %select{struct|union}0 cannot contain a "
"%select{private|protected}1 data member">;
-def ext_ms_anonymous_struct : ExtWarn<
- "anonymous structs are a Microsoft extension">, InGroup<Microsoft>;
+def ext_ms_anonymous_record : ExtWarn<
+ "anonymous %select{structs|unions}0 are a Microsoft extension">,
+ InGroup<Microsoft>;
// C++ local classes
def err_reference_to_local_var_in_enclosing_function : Error<
@@ -6267,7 +6456,13 @@ def err_conv_function_to_array : Error<
def err_conv_function_to_function : Error<
"conversion function cannot convert to a function type">;
def err_conv_function_with_complex_decl : Error<
- "must use a typedef to declare a conversion to %0">;
+ "cannot specify any part of a return type in the "
+ "declaration of a conversion function"
+ "%select{"
+ "; put the complete type after 'operator'|"
+ "; use a typedef to declare a conversion to %1|"
+ "; use an alias template to declare a conversion to %1|"
+ "}0">;
def err_conv_function_redeclared : Error<
"conversion function cannot be redeclared">;
def warn_conv_to_self_not_used : Warning<
@@ -6435,7 +6630,7 @@ def note_format_fix_specifier : Note<"did you mean to use '%0'?">;
def note_printf_c_str: Note<"did you mean to call the %0 method?">;
def warn_null_arg : Warning<
- "null passed to a callee which requires a non-null argument">,
+ "null passed to a callee that requires a non-null argument">,
InGroup<NonNull>;
def warn_null_ret : Warning<
"null returned from %select{function|method}0 that requires a non-null return value">,
@@ -6744,6 +6939,17 @@ def err_convertvector_non_vector_type : Error<
def err_convertvector_incompatible_vector : Error<
"first two arguments to __builtin_convertvector must have the same number of elements">;
+def err_first_argument_to_cwsc_not_call : Error<
+ "first argument to __builtin_call_with_static_chain must be a non-member call expression">;
+def err_first_argument_to_cwsc_block_call : Error<
+ "first argument to __builtin_call_with_static_chain must not be a block call">;
+def err_first_argument_to_cwsc_builtin_call : Error<
+ "first argument to __builtin_call_with_static_chain must not be a builtin call">;
+def err_first_argument_to_cwsc_pdtor_call : Error<
+ "first argument to __builtin_call_with_static_chain must not be a pseudo-destructor call">;
+def err_second_argument_to_cwsc_not_pointer : Error<
+ "second argument to __builtin_call_with_static_chain must be of pointer type">;
+
def err_vector_incorrect_num_initializers : Error<
"%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">;
def err_altivec_empty_initializer : Error<"expected initializer">;
@@ -6801,6 +7007,11 @@ def warn_duplicate_attribute : Warning<
"attribute %0 is already applied with different parameters">,
InGroup<IgnoredAttributes>;
+def warn_sync_fetch_and_nand_semantics_change : Warning<
+ "the semantics of this intrinsic changed with GCC "
+ "version 4.4 - the newer semantics are provided here">,
+ InGroup<DiagGroup<"sync-fetch-and-nand-semantics-changed">>;
+
// Type
def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">;
def warn_receiver_forward_class : Warning<
@@ -6842,6 +7053,13 @@ def err_invalid_protocol_qualifiers : Error<
def warn_ivar_use_hidden : Warning<
"local declaration of %0 hides instance variable">,
InGroup<DiagGroup<"shadow-ivar">>;
+def warn_direct_initialize_call : Warning<
+ "explicit call to +initialize results in duplicate call to +initialize">,
+ InGroup<ExplicitInitializeCall>;
+def warn_direct_super_initialize_call : Warning<
+ "explicit call to [super initialize] should only be in implementation "
+ "of +initialize">,
+ InGroup<ExplicitInitializeCall>;
def error_ivar_use_in_class_method : Error<
"instance variable %0 accessed in class method">;
def error_implicit_ivar_access : Error<
@@ -6891,6 +7109,9 @@ def err_property_not_found_suggest : Error<
"property %0 not found on object of type %1; did you mean %2?">;
def err_ivar_access_using_property_syntax_suggest : Error<
"property %0 not found on object of type %1; did you mean to access instance variable %2?">;
+def warn_property_access_suggest : Warning<
+"property %0 not found on object of type %1; did you mean to access property %2?">,
+InGroup<PropertyAccessDotSyntax>;
def err_property_found_suggest : Error<
"property %0 found on object of type %1; did you mean to access "
"it with the \".\" operator?">;
@@ -6938,6 +7159,11 @@ def err_unknown_any_function : Error<
def err_filter_expression_integral : Error<
"filter expression type should be an integral value not %0">;
+def err_non_asm_stmt_in_naked_function : Error<
+ "non-ASM statement in naked function is not supported">;
+def err_asm_naked_parm_ref : Error<
+ "parameter references not allowed in naked functions">;
+
// OpenCL warnings and errors.
def err_invalid_astype_of_different_size : Error<
"invalid reinterpretation: sizes of %0 and %1 must match">;
@@ -7000,7 +7226,7 @@ def err_omp_var_scope : Error<
def err_omp_var_used : Error<
"'#pragma omp %0' must precede all references to variable %q1">;
def err_omp_var_thread_local : Error<
- "variable %0 cannot be threadprivate because it is thread-local">;
+ "variable %0 cannot be threadprivate because it is %select{thread-local|a global named register variable}1">;
def err_omp_private_incomplete_type : Error<
"a private variable with incomplete type %0">;
def err_omp_firstprivate_incomplete_type : Error<
@@ -7015,8 +7241,8 @@ def err_omp_expected_var_name : Error<
"expected variable name">;
def err_omp_required_method : Error<
"%0 variable must have an accessible, unambiguous %select{default constructor|copy constructor|copy assignment operator|'%2'|destructor}1">;
-def err_omp_task_predetermined_firstprivate_required_method : Error<
- "predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous %select{copy constructor|destructor}0">;
+def note_omp_task_predetermined_firstprivate_here : Note<
+ "predetermined as a firstprivate in a task construct here">;
def err_omp_clause_ref_type_arg : Error<
"arguments of OpenMP clause '%0' cannot be of reference type %1">;
def err_omp_task_predetermined_firstprivate_ref_type_arg : Error<
@@ -7044,6 +7270,8 @@ def note_omp_implicit_dsa : Note<
"implicitly determined as %0">;
def err_omp_loop_var_dsa : Error<
"loop iteration variable in the associated loop of 'omp %1' directive may not be %0, predetermined as %2">;
+def err_omp_global_loop_var_dsa : Error<
+ "loop iteration variable in the associated loop of 'omp %1' directive may not be a variable with global storage without being explicitly marked as %0">;
def err_omp_not_for : Error<
"%select{statement after '#pragma omp %1' must be a for loop|"
"expected %2 for loops after '#pragma omp %1'%select{|, but found only %4}3}0">;
@@ -7075,6 +7303,9 @@ def err_omp_linear_expected_int_or_ptr : Error<
def warn_omp_linear_step_zero : Warning<
"zero linear step (%0 %select{|and other variables in clause }1should probably be const)">,
InGroup<OpenMPClauses>;
+def warn_omp_alignment_not_power_of_two : Warning<
+ "aligned clause will be ignored because the requested alignment is not a power of 2">,
+ InGroup<OpenMPClauses>;
def err_omp_aligned_expected_array_or_ptr : Error<
"argument of aligned clause should be array"
"%select{ or pointer|, pointer, reference to array or reference to pointer}1"
@@ -7102,10 +7333,16 @@ def err_omp_loop_incr_not_compatible : Error<
"on each iteration of OpenMP for loop">;
def note_omp_loop_cond_requres_compatible_incr : Note<
"loop step is expected to be %select{negative|positive}0 due to this condition">;
+def err_omp_loop_diff_cxx : Error<
+ "could not calculate number of iterations calling 'operator-' with "
+ "upper and lower loop bounds">;
def err_omp_loop_cannot_use_stmt : Error<
"'%0' statement cannot be used in OpenMP for loop">;
def err_omp_simd_region_cannot_use_stmt : Error<
"'%0' statement cannot be used in OpenMP simd region">;
+def warn_omp_loop_64_bit_var : Warning<
+ "OpenMP loop iteration variable cannot have more than 64 bits size and will be narrowed">,
+ InGroup<OpenMPLoopForm>;
def err_omp_unknown_reduction_identifier : Error<
"incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'">;
def err_omp_reduction_type_array : Error<
@@ -7126,9 +7363,13 @@ def err_omp_reduction_id_not_compatible : Error<
"variable of type %0 is not valid for specified reduction operation">;
def err_omp_prohibited_region : Error<
"region cannot be%select{| closely}0 nested inside '%1' region"
- "%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?}2">;
+ "%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|"
+ "; perhaps you forget to enclose 'omp %3' directive into a for or a parallel for region with 'ordered' clause?|"
+ "; perhaps you forget to enclose 'omp %3' directive into a target region?}2">;
def err_omp_prohibited_region_simd : Error<
"OpenMP constructs may not be nested inside a simd region">;
+def err_omp_prohibited_region_atomic : Error<
+ "OpenMP constructs may not be nested inside an atomic region">;
def err_omp_prohibited_region_critical_same_name : Error<
"cannot nest 'critical' regions having the same name %0">;
def note_omp_previous_critical_region : Note<
@@ -7146,6 +7387,35 @@ def err_omp_parallel_sections_substmt_not_section : Error<
"statement in 'omp parallel sections' directive must be enclosed into a section region">;
def err_omp_parallel_reduction_in_task_firstprivate : Error<
"argument of a reduction clause of a %0 construct must not appear in a firstprivate clause on a task construct">;
+def err_omp_atomic_read_not_expression_statement : Error<
+ "the statement for 'atomic read' must be an expression statement of form 'v = x;',"
+ " where v and x are both lvalue expressions with scalar type">;
+def note_omp_atomic_read_write: Note<
+ "%select{expected an expression statement|expected built-in assignment operator|expected expression of scalar type|expected lvalue expression}0">;
+def err_omp_atomic_write_not_expression_statement : Error<
+ "the statement for 'atomic write' must be an expression statement of form 'x = expr;',"
+ " where x is a lvalue expression with scalar type">;
+def err_omp_atomic_update_not_expression_statement : Error<
+ "the statement for 'atomic%select{| update}0' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x',"
+ " where x is an l-value expression with scalar type">;
+def err_omp_atomic_capture_not_expression_statement : Error<
+ "the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x',"
+ " where x and v are both l-value expressions with scalar type">;
+def err_omp_atomic_capture_not_compound_statement : Error<
+ "the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}',"
+ " '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}',"
+ " '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}'"
+ " where x is an l-value expression with scalar type">;
+def err_omp_atomic_several_clauses : Error<
+ "directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause">;
+def note_omp_atomic_previous_clause : Note<
+ "'%0' clause used here">;
+def err_omp_target_contains_not_only_teams : Error<
+ "target construct with nested teams region contains statements outside of the teams construct">;
+def note_omp_nested_teams_construct_here : Note<
+ "nested teams construct here">;
+def note_omp_nested_statement_here : Note<
+ "%select{statement|directive}0 outside teams construct here">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
@@ -7197,6 +7467,8 @@ def err_module_import_not_at_top_level : Error<
def note_module_import_not_at_top_level : Note<"%0 begins here">;
def err_module_self_import : Error<
"import of module '%0' appears within same top-level module '%1'">;
+def err_module_import_in_implementation : Error<
+ "@import of module '%0' in implementation of '%1'; use #import">;
}
let CategoryName = "Documentation Issue" in {
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index be9d2bdbd2de..a685db0137f5 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -52,10 +52,18 @@ def err_pch_with_compiler_errors : Error<
"PCH file contains compiler errors">;
def err_imported_module_not_found : Error<
- "module '%0' imported by AST file '%1' not found">, DefaultFatal;
+ "module '%0' in AST file '%1' (imported by AST file '%2') "
+ "is not defined in any loaded module map file; "
+ "maybe you need to load '%3'?">, DefaultFatal;
def err_imported_module_modmap_changed : Error<
"module '%0' imported by AST file '%1' found in a different module map file"
" (%2) than when the importing AST file was built (%3)">, DefaultFatal;
+def err_imported_module_relocated : Error<
+ "module '%0' was built in directory '%1' but now resides in "
+ "directory '%2'">, DefaultFatal;
+def err_module_different_modmap : Error<
+ "module '%0' %select{uses|does not use}1 additional module map '%2'"
+ "%select{| not}1 used when the module was built">;
def warn_module_conflict : Warning<
"module '%0' conflicts with already-imported module '%1': %2">,
InGroup<ModuleConflict>;
diff --git a/include/clang/Basic/ExceptionSpecificationType.h b/include/clang/Basic/ExceptionSpecificationType.h
index edd89ec709d7..132b5ba1e5a7 100644
--- a/include/clang/Basic/ExceptionSpecificationType.h
+++ b/include/clang/Basic/ExceptionSpecificationType.h
@@ -26,7 +26,8 @@ enum ExceptionSpecificationType {
EST_BasicNoexcept, ///< noexcept
EST_ComputedNoexcept, ///< noexcept(expression)
EST_Unevaluated, ///< not evaluated yet, for special member function
- EST_Uninstantiated ///< not instantiated yet
+ EST_Uninstantiated, ///< not instantiated yet
+ EST_Unparsed ///< not parsed yet
};
inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
diff --git a/include/clang/Basic/ExpressionTraits.h b/include/clang/Basic/ExpressionTraits.h
index e87771572129..0363a1d2c74c 100644
--- a/include/clang/Basic/ExpressionTraits.h
+++ b/include/clang/Basic/ExpressionTraits.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_EXPRESSIONTRAITS_H
-#define LLVM_CLANG_EXPRESSIONTRAITS_H
+#ifndef LLVM_CLANG_BASIC_EXPRESSIONTRAITS_H
+#define LLVM_CLANG_BASIC_EXPRESSIONTRAITS_H
namespace clang {
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index 0ad53c4df5ac..bd3f27ab9e5e 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FILEMANAGER_H
-#define LLVM_CLANG_FILEMANAGER_H
+#ifndef LLVM_CLANG_BASIC_FILEMANAGER_H
+#define LLVM_CLANG_BASIC_FILEMANAGER_H
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/LLVM.h"
@@ -59,7 +59,7 @@ public:
/// If the 'File' member is valid, then this FileEntry has an open file
/// descriptor for the file.
class FileEntry {
- std::string Name; // Name of the file.
+ const char *Name; // Name of the file.
off_t Size; // File size in bytes.
time_t ModTime; // Modification time of file.
const DirectoryEntry *Dir; // Directory file lives in.
@@ -93,7 +93,7 @@ public:
assert(!isValid() && "Cannot copy an initialized FileEntry");
}
- const char *getName() const { return Name.c_str(); }
+ const char *getName() const { return Name; }
bool isValid() const { return IsValid; }
off_t getSize() const { return Size; }
unsigned getUID() const { return UID; }
@@ -194,7 +194,8 @@ public:
/// \param AtBeginning whether this new stat cache must be installed at the
/// beginning of the chain of stat caches. Otherwise, it will be added to
/// the end of the chain.
- void addStatCache(FileSystemStatCache *statCache, bool AtBeginning = false);
+ void addStatCache(std::unique_ptr<FileSystemStatCache> statCache,
+ bool AtBeginning = false);
/// \brief Removes the specified FileSystemStatCache object from the manager.
void removeStatCache(FileSystemStatCache *statCache);
@@ -240,12 +241,11 @@ public:
/// \brief Open the specified file as a MemoryBuffer, returning a new
/// MemoryBuffer if successful, otherwise returning null.
- llvm::MemoryBuffer *getBufferForFile(const FileEntry *Entry,
- std::string *ErrorStr = nullptr,
- bool isVolatile = false,
- bool ShouldCloseOpenFile = true);
- llvm::MemoryBuffer *getBufferForFile(StringRef Filename,
- std::string *ErrorStr = nullptr);
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBufferForFile(const FileEntry *Entry, bool isVolatile = false,
+ bool ShouldCloseOpenFile = true);
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBufferForFile(StringRef Filename);
/// \brief Get the 'stat' information for the given \p Path.
///
@@ -274,6 +274,9 @@ public:
static void modifyFileEntry(FileEntry *File, off_t Size,
time_t ModificationTime);
+ /// \brief Remove any './' components from a path.
+ static bool removeDotPaths(SmallVectorImpl<char> &Path);
+
/// \brief Retrieve the canonical name for a given directory.
///
/// This is a very expensive operation, despite its results being cached,
diff --git a/include/clang/Basic/FileSystemStatCache.h b/include/clang/Basic/FileSystemStatCache.h
index 9be8b1074b2f..cad91893489b 100644
--- a/include/clang/Basic/FileSystemStatCache.h
+++ b/include/clang/Basic/FileSystemStatCache.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FILESYSTEMSTATCACHE_H
-#define LLVM_CLANG_FILESYSTEMSTATCACHE_H
+#ifndef LLVM_CLANG_BASIC_FILESYSTEMSTATCACHE_H
+#define LLVM_CLANG_BASIC_FILESYSTEMSTATCACHE_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringMap.h"
@@ -74,8 +74,8 @@ public:
/// \brief Sets the next stat call cache in the chain of stat caches.
/// Takes ownership of the given stat cache.
- void setNextStatCache(FileSystemStatCache *Cache) {
- NextStatCache.reset(Cache);
+ void setNextStatCache(std::unique_ptr<FileSystemStatCache> Cache) {
+ NextStatCache = std::move(Cache);
}
/// \brief Retrieve the next stat call cache in the chain.
@@ -84,7 +84,9 @@ public:
/// \brief Retrieve the next stat call cache in the chain, transferring
/// ownership of this cache (and, transitively, all of the remaining caches)
/// to the caller.
- FileSystemStatCache *takeNextStatCache() { return NextStatCache.release(); }
+ std::unique_ptr<FileSystemStatCache> takeNextStatCache() {
+ return std::move(NextStatCache);
+ }
protected:
// FIXME: The pointer here is a non-owning/optional reference to the
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 0c278a17a32d..1de9dd1c0e10 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -249,6 +249,9 @@ public:
}
bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; }
+ /// \brief Return true if this token is a keyword in the specified language.
+ bool isKeyword(const LangOptions &LangOpts);
+
/// getFETokenInfo/setFETokenInfo - The language front-end is allowed to
/// associate arbitrary metadata with this token.
template<typename T>
@@ -444,26 +447,21 @@ public:
/// \brief Return the identifier token info for the specified named
/// identifier.
IdentifierInfo &get(StringRef Name) {
- llvm::StringMapEntry<IdentifierInfo*> &Entry =
- HashTable.GetOrCreateValue(Name);
+ auto &Entry = *HashTable.insert(std::make_pair(Name, nullptr)).first;
- IdentifierInfo *II = Entry.getValue();
+ IdentifierInfo *&II = Entry.second;
if (II) return *II;
// No entry; if we have an external lookup, look there first.
if (ExternalLookup) {
II = ExternalLookup->get(Name);
- if (II) {
- // Cache in the StringMap for subsequent lookups.
- Entry.setValue(II);
+ if (II)
return *II;
- }
}
// Lookups failed, make a new IdentifierInfo.
void *Mem = getAllocator().Allocate<IdentifierInfo>();
II = new (Mem) IdentifierInfo();
- Entry.setValue(II);
// Make sure getName() knows how to find the IdentifierInfo
// contents.
@@ -486,25 +484,23 @@ public:
/// introduce or modify an identifier. If they called get(), they would
/// likely end up in a recursion.
IdentifierInfo &getOwn(StringRef Name) {
- llvm::StringMapEntry<IdentifierInfo*> &Entry =
- HashTable.GetOrCreateValue(Name);
-
- IdentifierInfo *II = Entry.getValue();
- if (!II) {
-
- // Lookups failed, make a new IdentifierInfo.
- void *Mem = getAllocator().Allocate<IdentifierInfo>();
- II = new (Mem) IdentifierInfo();
- Entry.setValue(II);
-
- // Make sure getName() knows how to find the IdentifierInfo
- // contents.
- II->Entry = &Entry;
-
- // If this is the 'import' contextual keyword, mark it as such.
- if (Name.equals("import"))
- II->setModulesImport(true);
- }
+ auto &Entry = *HashTable.insert(std::make_pair(Name, nullptr)).first;
+
+ IdentifierInfo *&II = Entry.second;
+ if (II)
+ return *II;
+
+ // Lookups failed, make a new IdentifierInfo.
+ void *Mem = getAllocator().Allocate<IdentifierInfo>();
+ II = new (Mem) IdentifierInfo();
+
+ // Make sure getName() knows how to find the IdentifierInfo
+ // contents.
+ II->Entry = &Entry;
+
+ // If this is the 'import' contextual keyword, mark it as such.
+ if (Name.equals("import"))
+ II->setModulesImport(true);
return *II;
}
@@ -563,6 +559,7 @@ enum ObjCMethodFamily {
OMF_retain,
OMF_retainCount,
OMF_self,
+ OMF_initialize,
// performSelector families
OMF_performSelector
@@ -588,6 +585,12 @@ enum ObjCInstanceTypeFamily {
OIT_ReturnsSelf
};
+enum ObjCStringFormatFamily {
+ SFF_None,
+ SFF_NSString,
+ SFF_CFString
+};
+
/// \brief Smart pointer class that efficiently represents Objective-C method
/// names.
///
@@ -633,6 +636,8 @@ class Selector {
}
static ObjCMethodFamily getMethodFamilyImpl(Selector sel);
+
+ static ObjCStringFormatFamily getStringFormatFamilyImpl(Selector sel);
public:
friend class SelectorTable; // only the SelectorTable can create these
@@ -703,7 +708,11 @@ public:
ObjCMethodFamily getMethodFamily() const {
return getMethodFamilyImpl(*this);
}
-
+
+ ObjCStringFormatFamily getStringFormatFamily() const {
+ return getStringFormatFamilyImpl(*this);
+ }
+
static Selector getEmptyMarker() {
return Selector(uintptr_t(-1));
}
diff --git a/include/clang/Basic/LLVM.h b/include/clang/Basic/LLVM.h
index 5a71fa85b3d9..3e01d25add2d 100644
--- a/include/clang/Basic/LLVM.h
+++ b/include/clang/Basic/LLVM.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef CLANG_BASIC_LLVM_H
-#define CLANG_BASIC_LLVM_H
+#ifndef LLVM_CLANG_BASIC_LLVM_H
+#define LLVM_CLANG_BASIC_LLVM_H
// Do not proliferate #includes here, require clients to #include their
// dependencies.
diff --git a/include/clang/Basic/Lambda.h b/include/clang/Basic/Lambda.h
index 280ae94fedc5..e676e726dd7a 100644
--- a/include/clang/Basic/Lambda.h
+++ b/include/clang/Basic/Lambda.h
@@ -34,7 +34,8 @@ enum LambdaCaptureDefault {
enum LambdaCaptureKind {
LCK_This, ///< Capturing the \c this pointer
LCK_ByCopy, ///< Capturing by copy (a.k.a., by value)
- LCK_ByRef ///< Capturing by reference
+ LCK_ByRef, ///< Capturing by reference
+ LCK_VLAType ///< Capturing variable-length array type
};
} // end namespace clang
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index a297a4c219cf..cf9638d7ea81 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -9,26 +9,40 @@
//
// This file defines the language options. Users of this file must
// define the LANGOPT macro to make use of this information.
-// Optionally, the user may also define BENIGN_LANGOPT
-// (for options that don't affect the construction of the AST in an
-// incompatible way), ENUM_LANGOPT (for options that have enumeration,
-// rather than unsigned, type), BENIGN_ENUM_LANGOPT (for benign
-// options that have enumeration type), and VALUE_LANGOPT is a language option
-// that describes a value rather than a flag.
//
+// Optionally, the user may also define:
+//
+// BENIGN_LANGOPT: for options that don't affect the construction of the AST in
+// any way (that is, the value can be different between an implicit module
+// and the user of that module).
+//
+// COMPATIBLE_LANGOPT: for options that affect the construction of the AST in
+// a way that doesn't prevent interoperability (that is, the value can be
+// different between an explicit module and the user of that module).
+//
+// ENUM_LANGOPT: for options that have enumeration, rather than unsigned, type.
+//
+// VALUE_LANGOPT: for options that describe a value rather than a flag.
+//
+// BENIGN_ENUM_LANGOPT, COMPATIBLE_ENUM_LANGOPT: combinations of the above.
+//
+// FIXME: Clients should be able to more easily select whether they want
+// different levels of compatibility versus how to handle different kinds
+// of option.
//===----------------------------------------------------------------------===//
+
#ifndef LANGOPT
# error Define the LANGOPT macro to handle language options
#endif
-#ifndef VALUE_LANGOPT
-# define VALUE_LANGOPT(Name, Bits, Default, Description) \
+#ifndef COMPATIBLE_LANGOPT
+# define COMPATIBLE_LANGOPT(Name, Bits, Default, Description) \
LANGOPT(Name, Bits, Default, Description)
#endif
#ifndef BENIGN_LANGOPT
# define BENIGN_LANGOPT(Name, Bits, Default, Description) \
- LANGOPT(Name, Bits, Default, Description)
+ COMPATIBLE_LANGOPT(Name, Bits, Default, Description)
#endif
#ifndef ENUM_LANGOPT
@@ -36,11 +50,22 @@
LANGOPT(Name, Bits, Default, Description)
#endif
+#ifndef COMPATIBLE_ENUM_LANGOPT
+# define COMPATIBLE_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#endif
+
#ifndef BENIGN_ENUM_LANGOPT
# define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+ COMPATIBLE_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#endif
+#ifndef VALUE_LANGOPT
+# define VALUE_LANGOPT(Name, Bits, Default, Description) \
+ LANGOPT(Name, Bits, Default, Description)
+#endif
+
+// FIXME: A lot of the BENIGN_ options should be COMPATIBLE_ instead.
LANGOPT(C99 , 1, 0, "C99")
LANGOPT(C11 , 1, 0, "C11")
LANGOPT(MSVCCompat , 1, 0, "Microsoft Visual C++ full compatibility mode")
@@ -49,7 +74,7 @@ LANGOPT(AsmBlocks , 1, 0, "Microsoft inline asm blocks")
LANGOPT(Borland , 1, 0, "Borland extensions")
LANGOPT(CPlusPlus , 1, 0, "C++")
LANGOPT(CPlusPlus11 , 1, 0, "C++11")
-LANGOPT(CPlusPlus1y , 1, 0, "C++1y")
+LANGOPT(CPlusPlus14 , 1, 0, "C++14")
LANGOPT(CPlusPlus1z , 1, 0, "C++1z")
LANGOPT(ObjC1 , 1, 0, "Objective-C 1")
LANGOPT(ObjC2 , 1, 0, "Objective-C 2")
@@ -101,16 +126,19 @@ LANGOPT(ModulesDeclUse , 1, 0, "require declaration of module uses")
LANGOPT(ModulesSearchAll , 1, 1, "search even non-imported modules to find unresolved references")
LANGOPT(ModulesStrictDeclUse, 1, 0, "require declaration of module uses and all headers to be in modules")
LANGOPT(ModulesErrorRecovery, 1, 1, "automatically import modules as needed when performing error recovery")
-LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro")
-LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
+BENIGN_LANGOPT(ModulesImplicitMaps, 1, 1, "use files called module.modulemap implicitly as module maps")
+COMPATIBLE_LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro")
+COMPATIBLE_LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)")
VALUE_LANGOPT(PackStruct , 32, 0,
"default struct packing maximum alignment")
+VALUE_LANGOPT(MaxTypeAlign , 32, 0,
+ "default maximum alignment for types")
VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level")
VALUE_LANGOPT(PIELevel , 2, 0, "__PIE__ level")
LANGOPT(GNUInline , 1, 0, "GNU inline semantics")
-LANGOPT(NoInlineDefine , 1, 0, "__NO_INLINE__ predefined macro")
-LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro")
+COMPATIBLE_LANGOPT(NoInlineDefine , 1, 0, "__NO_INLINE__ predefined macro")
+COMPATIBLE_LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro")
LANGOPT(FastMath , 1, 0, "__FAST_MATH__ predefined macro")
LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro")
@@ -126,8 +154,10 @@ LANGOPT(ShortEnums , 1, 0, "short enum types")
LANGOPT(OpenCL , 1, 0, "OpenCL")
LANGOPT(OpenCLVersion , 32, 0, "OpenCL version")
LANGOPT(NativeHalfType , 1, 0, "Native half type support")
+LANGOPT(HalfArgsAndReturns, 1, 0, "half args and returns")
LANGOPT(CUDA , 1, 0, "CUDA")
LANGOPT(OpenMP , 1, 0, "OpenMP support")
+LANGOPT(CUDAIsDevice , 1, 0, "Compiling for CUDA device")
LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'s new operators")
LANGOPT(SizedDeallocation , 1, 0, "enable sized deallocation functions")
@@ -187,9 +217,15 @@ LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")
LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")
+LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan "
+ "field padding (0: none, 1:least "
+ "aggressive, 2: more aggressive)")
+
#undef LANGOPT
-#undef VALUE_LANGOPT
+#undef COMPATIBLE_LANGOPT
#undef BENIGN_LANGOPT
#undef ENUM_LANGOPT
+#undef COMPATIBLE_ENUM_LANGOPT
#undef BENIGN_ENUM_LANGOPT
+#undef VALUE_LANGOPT
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 9bffc7cb18cf..5ac96c519855 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -12,25 +12,18 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LANGOPTIONS_H
-#define LLVM_CLANG_LANGOPTIONS_H
+#ifndef LLVM_CLANG_BASIC_LANGOPTIONS_H
+#define LLVM_CLANG_BASIC_LANGOPTIONS_H
#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Basic/Sanitizers.h"
#include "clang/Basic/Visibility.h"
#include <string>
namespace clang {
-struct SanitizerOptions {
-#define SANITIZER(NAME, ID) unsigned ID : 1;
-#include "clang/Basic/Sanitizers.def"
-
- /// \brief Cached set of sanitizer options with all sanitizers disabled.
- static const SanitizerOptions Disabled;
-};
-
/// Bitfields of LangOptions, split out from LangOptions in order to ensure that
/// this large collection of bitfields is a trivial class type.
class LangOptionsBase {
@@ -40,7 +33,6 @@ public:
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
- SanitizerOptions Sanitize;
protected:
// Define language options of enumeration type. These are private, and will
// have accessors (below).
@@ -75,6 +67,13 @@ public:
enum AddrSpaceMapMangling { ASMM_Target, ASMM_On, ASMM_Off };
public:
+ /// \brief Set of enabled sanitizers.
+ SanitizerSet Sanitize;
+
+ /// \brief Path to blacklist file specifying which objects
+ /// (files, functions, variables) should not be instrumented.
+ std::string SanitizerBlacklistFile;
+
clang::ObjCRuntime ObjCRuntime;
std::string ObjCConstantStringClass;
@@ -88,6 +87,11 @@ public:
/// \brief The name of the current module.
std::string CurrentModule;
+ /// \brief The name of the module that the translation unit is an
+ /// implementation of. Prevents semantic imports, but does not otherwise
+ /// treat this as the CurrentModule.
+ std::string ImplementationOfModule;
+
/// \brief Options for parsing comments.
CommentOptions CommentOpts;
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index 9b66840ba412..e3953a4571fa 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -56,17 +56,11 @@ public:
/// module.
Module *Parent;
- /// \brief The module map file that (along with the module name) uniquely
- /// identifies this module.
- ///
- /// The particular module that \c Name refers to may depend on how the module
- /// was found in header search. However, the combination of \c Name and
- /// \c ModuleMap will be globally unique for top-level modules. In the case of
- /// inferred modules, \c ModuleMap will contain the module map that allowed
- /// the inference (e.g. contained 'Module *') rather than the virtual
- /// inferred module map file.
- const FileEntry *ModuleMap;
-
+ /// \brief The build directory of this module. This is the directory in
+ /// which the module is notionally built, and relative to which its headers
+ /// are found.
+ const DirectoryEntry *Directory;
+
/// \brief The umbrella header or directory.
llvm::PointerUnion<const DirectoryEntry *, const FileEntry *> Umbrella;
@@ -92,18 +86,28 @@ private:
mutable llvm::DenseSet<const Module*> VisibleModulesCache;
public:
- /// \brief The headers that are part of this module.
- SmallVector<const FileEntry *, 2> NormalHeaders;
-
- /// \brief The headers that are explicitly excluded from this module.
- SmallVector<const FileEntry *, 2> ExcludedHeaders;
-
- /// \brief The headers that are private to this module.
- SmallVector<const FileEntry *, 2> PrivateHeaders;
+ enum HeaderKind {
+ HK_Normal,
+ HK_Textual,
+ HK_Private,
+ HK_PrivateTextual,
+ HK_Excluded
+ };
+ static const int NumHeaderKinds = HK_Excluded + 1;
/// \brief Information about a header directive as found in the module map
/// file.
- struct HeaderDirective {
+ struct Header {
+ std::string NameAsWritten;
+ const FileEntry *Entry;
+ };
+
+ /// \brief The headers that are part of this module.
+ SmallVector<Header, 2> Headers[5];
+
+ /// \brief Stored information about a header directive that was found in the
+ /// module map file but has not been resolved to a file.
+ struct UnresolvedHeaderDirective {
SourceLocation FileNameLoc;
std::string FileName;
bool IsUmbrella;
@@ -111,7 +115,7 @@ public:
/// \brief Headers that are mentioned in the module map file but could not be
/// found on the file system.
- SmallVector<HeaderDirective, 1> MissingHeaders;
+ SmallVector<UnresolvedHeaderDirective, 1> MissingHeaders;
/// \brief An individual requirement: a feature name and a flag indicating
/// the required state of that feature.
@@ -283,10 +287,8 @@ public:
std::vector<Conflict> Conflicts;
/// \brief Construct a new module or submodule.
- ///
- /// For an explanation of \p ModuleMap, see Module::ModuleMap.
Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
- const FileEntry *ModuleMap, bool IsFramework, bool IsExplicit);
+ bool IsFramework, bool IsExplicit);
~Module();
@@ -308,7 +310,7 @@ public:
bool isAvailable(const LangOptions &LangOpts,
const TargetInfo &Target,
Requirement &Req,
- HeaderDirective &MissingHeader) const;
+ UnresolvedHeaderDirective &MissingHeader) const;
/// \brief Determine whether this module is a submodule.
bool isSubModule() const { return Parent != nullptr; }
diff --git a/include/clang/Basic/ObjCRuntime.h b/include/clang/Basic/ObjCRuntime.h
index fa375f4e183e..e33587d8f30f 100644
--- a/include/clang/Basic/ObjCRuntime.h
+++ b/include/clang/Basic/ObjCRuntime.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_OBJCRUNTIME_H
-#define LLVM_CLANG_OBJCRUNTIME_H
+#ifndef LLVM_CLANG_BASIC_OBJCRUNTIME_H
+#define LLVM_CLANG_BASIC_OBJCRUNTIME_H
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/Triple.h"
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
index 6cfa5ea549f1..0145db059329 100644
--- a/include/clang/Basic/OpenMPKinds.def
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -30,6 +30,9 @@
#ifndef OPENMP_FOR_CLAUSE
# define OPENMP_FOR_CLAUSE(Name)
#endif
+#ifndef OPENMP_FOR_SIMD_CLAUSE
+# define OPENMP_FOR_SIMD_CLAUSE(Name)
+#endif
#ifndef OPENMP_SECTIONS_CLAUSE
# define OPENMP_SECTIONS_CLAUSE(Name)
#endif
@@ -39,12 +42,24 @@
#ifndef OPENMP_PARALLEL_FOR_CLAUSE
# define OPENMP_PARALLEL_FOR_CLAUSE(Name)
#endif
+#ifndef OPENMP_PARALLEL_FOR_SIMD_CLAUSE
+# define OPENMP_PARALLEL_FOR_SIMD_CLAUSE(Name)
+#endif
#ifndef OPENMP_PARALLEL_SECTIONS_CLAUSE
# define OPENMP_PARALLEL_SECTIONS_CLAUSE(Name)
#endif
#ifndef OPENMP_TASK_CLAUSE
# define OPENMP_TASK_CLAUSE(Name)
#endif
+#ifndef OPENMP_ATOMIC_CLAUSE
+# define OPENMP_ATOMIC_CLAUSE(Name)
+#endif
+#ifndef OPENMP_TARGET_CLAUSE
+# define OPENMP_TARGET_CLAUSE(Name)
+#endif
+#ifndef OPENMP_TEAMS_CLAUSE
+# define OPENMP_TEAMS_CLAUSE(Name)
+#endif
#ifndef OPENMP_DEFAULT_KIND
# define OPENMP_DEFAULT_KIND(Name)
#endif
@@ -70,8 +85,14 @@ OPENMP_DIRECTIVE(taskyield)
OPENMP_DIRECTIVE(barrier)
OPENMP_DIRECTIVE(taskwait)
OPENMP_DIRECTIVE(flush)
+OPENMP_DIRECTIVE(ordered)
+OPENMP_DIRECTIVE(atomic)
+OPENMP_DIRECTIVE(target)
+OPENMP_DIRECTIVE(teams)
OPENMP_DIRECTIVE_EXT(parallel_for, "parallel for")
+OPENMP_DIRECTIVE_EXT(parallel_for_simd, "parallel for simd")
OPENMP_DIRECTIVE_EXT(parallel_sections, "parallel sections")
+OPENMP_DIRECTIVE_EXT(for_simd, "for simd")
// OpenMP clauses.
OPENMP_CLAUSE(if, OMPIfClause)
@@ -96,6 +117,11 @@ OPENMP_CLAUSE(nowait, OMPNowaitClause)
OPENMP_CLAUSE(untied, OMPUntiedClause)
OPENMP_CLAUSE(mergeable, OMPMergeableClause)
OPENMP_CLAUSE(flush, OMPFlushClause)
+OPENMP_CLAUSE(read, OMPReadClause)
+OPENMP_CLAUSE(write, OMPWriteClause)
+OPENMP_CLAUSE(update, OMPUpdateClause)
+OPENMP_CLAUSE(capture, OMPCaptureClause)
+OPENMP_CLAUSE(seq_cst, OMPSeqCstClause)
// Clauses allowed for OpenMP directive 'parallel'.
OPENMP_PARALLEL_CLAUSE(if)
@@ -127,6 +153,18 @@ OPENMP_FOR_CLAUSE(schedule)
OPENMP_FOR_CLAUSE(ordered)
OPENMP_FOR_CLAUSE(nowait)
+// Clauses allowed for directive 'omp for simd'.
+OPENMP_FOR_SIMD_CLAUSE(private)
+OPENMP_FOR_SIMD_CLAUSE(firstprivate)
+OPENMP_FOR_SIMD_CLAUSE(lastprivate)
+OPENMP_FOR_SIMD_CLAUSE(reduction)
+OPENMP_FOR_SIMD_CLAUSE(schedule)
+OPENMP_FOR_SIMD_CLAUSE(collapse)
+OPENMP_FOR_SIMD_CLAUSE(nowait)
+OPENMP_FOR_SIMD_CLAUSE(safelen)
+OPENMP_FOR_SIMD_CLAUSE(linear)
+OPENMP_FOR_SIMD_CLAUSE(aligned)
+
// Clauses allowed for OpenMP directive 'omp sections'.
OPENMP_SECTIONS_CLAUSE(private)
OPENMP_SECTIONS_CLAUSE(lastprivate)
@@ -171,6 +209,23 @@ OPENMP_PARALLEL_FOR_CLAUSE(collapse)
OPENMP_PARALLEL_FOR_CLAUSE(schedule)
OPENMP_PARALLEL_FOR_CLAUSE(ordered)
+// Clauses allowed for OpenMP directive 'parallel for simd'.
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(if)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(num_threads)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(default)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(proc_bind)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(private)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(firstprivate)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(shared)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(reduction)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(copyin)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(lastprivate)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(collapse)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(schedule)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(safelen)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(linear)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(aligned)
+
// Clauses allowed for OpenMP directive 'parallel sections'.
OPENMP_PARALLEL_SECTIONS_CLAUSE(if)
OPENMP_PARALLEL_SECTIONS_CLAUSE(num_threads)
@@ -193,6 +248,25 @@ OPENMP_TASK_CLAUSE(shared)
OPENMP_TASK_CLAUSE(untied)
OPENMP_TASK_CLAUSE(mergeable)
+// Clauses allowed for OpenMP directive 'atomic'.
+OPENMP_ATOMIC_CLAUSE(read)
+OPENMP_ATOMIC_CLAUSE(write)
+OPENMP_ATOMIC_CLAUSE(update)
+OPENMP_ATOMIC_CLAUSE(capture)
+OPENMP_ATOMIC_CLAUSE(seq_cst)
+
+// Clauses allowed for OpenMP directive 'target'.
+// TODO More clauses for 'target' directive.
+OPENMP_TARGET_CLAUSE(if)
+
+// Clauses allowed for OpenMP directive 'teams'.
+// TODO More clauses for 'teams' directive.
+OPENMP_TEAMS_CLAUSE(default)
+OPENMP_TEAMS_CLAUSE(private)
+OPENMP_TEAMS_CLAUSE(firstprivate)
+OPENMP_TEAMS_CLAUSE(shared)
+OPENMP_TEAMS_CLAUSE(reduction)
+
#undef OPENMP_SCHEDULE_KIND
#undef OPENMP_PROC_BIND_KIND
#undef OPENMP_DEFAULT_KIND
@@ -203,8 +277,13 @@ OPENMP_TASK_CLAUSE(mergeable)
#undef OPENMP_SECTIONS_CLAUSE
#undef OPENMP_PARALLEL_CLAUSE
#undef OPENMP_PARALLEL_FOR_CLAUSE
+#undef OPENMP_PARALLEL_FOR_SIMD_CLAUSE
#undef OPENMP_PARALLEL_SECTIONS_CLAUSE
#undef OPENMP_TASK_CLAUSE
+#undef OPENMP_ATOMIC_CLAUSE
+#undef OPENMP_TARGET_CLAUSE
+#undef OPENMP_TEAMS_CLAUSE
#undef OPENMP_SIMD_CLAUSE
#undef OPENMP_FOR_CLAUSE
+#undef OPENMP_FOR_SIMD_CLAUSE
diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h
index 526cbb26cf15..e2f115113e20 100644
--- a/include/clang/Basic/OpenMPKinds.h
+++ b/include/clang/Basic/OpenMPKinds.h
@@ -93,6 +93,12 @@ bool isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind);
/// parallel', otherwise - false.
bool isOpenMPParallelDirective(OpenMPDirectiveKind DKind);
+/// \brief Checks if the specified directive is a teams-kind directive.
+/// \param DKind Specified directive.
+/// \return true - the directive is a teams-like directive like 'omp teams',
+/// otherwise - false.
+bool isOpenMPTeamsDirective(OpenMPDirectiveKind DKind);
+
/// \brief Checks if the specified directive is a simd directive.
/// \param DKind Specified directive.
/// \return true - the directive is a simd directive like 'omp simd',
diff --git a/include/clang/Basic/OperatorKinds.h b/include/clang/Basic/OperatorKinds.h
index d3b70c2f4d22..7120baeef675 100644
--- a/include/clang/Basic/OperatorKinds.h
+++ b/include/clang/Basic/OperatorKinds.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_BASIC_OPERATOR_KINDS_H
-#define LLVM_CLANG_BASIC_OPERATOR_KINDS_H
+#ifndef LLVM_CLANG_BASIC_OPERATORKINDS_H
+#define LLVM_CLANG_BASIC_OPERATORKINDS_H
namespace clang {
diff --git a/include/clang/Basic/OperatorPrecedence.h b/include/clang/Basic/OperatorPrecedence.h
index b68d577c806c..640749fdd10d 100644
--- a/include/clang/Basic/OperatorPrecedence.h
+++ b/include/clang/Basic/OperatorPrecedence.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_OPERATOR_PRECEDENCE_H
-#define LLVM_CLANG_OPERATOR_PRECEDENCE_H
+#ifndef LLVM_CLANG_BASIC_OPERATORPRECEDENCE_H
+#define LLVM_CLANG_BASIC_OPERATORPRECEDENCE_H
#include "clang/Basic/TokenKinds.h"
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index 8ae3b22b0cc8..84c8dd159615 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PARTIALDIAGNOSTIC_H
-#define LLVM_CLANG_PARTIALDIAGNOSTIC_H
+#ifndef LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
+#define LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
diff --git a/include/clang/Basic/PlistSupport.h b/include/clang/Basic/PlistSupport.h
index b7a938209a1d..081f22d48d4a 100644
--- a/include/clang/Basic/PlistSupport.h
+++ b/include/clang/Basic/PlistSupport.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PLISTSUPPORT_H
-#define LLVM_CLANG_PLISTSUPPORT_H
+#ifndef LLVM_CLANG_BASIC_PLISTSUPPORT_H
+#define LLVM_CLANG_BASIC_PLISTSUPPORT_H
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
diff --git a/include/clang/Basic/PrettyStackTrace.h b/include/clang/Basic/PrettyStackTrace.h
index 0e49295540b4..6badae5c0349 100644
--- a/include/clang/Basic/PrettyStackTrace.h
+++ b/include/clang/Basic/PrettyStackTrace.h
@@ -14,8 +14,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef CLANG_BASIC_PRETTYSTACKTRACE_H
-#define CLANG_BASIC_PRETTYSTACKTRACE_H
+#ifndef LLVM_CLANG_BASIC_PRETTYSTACKTRACE_H
+#define LLVM_CLANG_BASIC_PRETTYSTACKTRACE_H
#include "clang/Basic/SourceLocation.h"
#include "llvm/Support/PrettyStackTrace.h"
diff --git a/include/clang/Basic/SanitizerBlacklist.h b/include/clang/Basic/SanitizerBlacklist.h
new file mode 100644
index 000000000000..2ce268aa0a3b
--- /dev/null
+++ b/include/clang/Basic/SanitizerBlacklist.h
@@ -0,0 +1,45 @@
+//===--- SanitizerBlacklist.h - Blacklist for sanitizers --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided blacklist used to disable/alter instrumentation done in
+// sanitizers.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_SANITIZERBLACKLIST_H
+#define LLVM_CLANG_BASIC_SANITIZERBLACKLIST_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include <memory>
+
+namespace clang {
+
+class SanitizerBlacklist {
+ std::unique_ptr<llvm::SpecialCaseList> SCL;
+ SourceManager &SM;
+
+public:
+ SanitizerBlacklist(StringRef BlacklistPath, SourceManager &SM);
+ bool isBlacklistedGlobal(StringRef GlobalName,
+ StringRef Category = StringRef()) const;
+ bool isBlacklistedType(StringRef MangledTypeName,
+ StringRef Category = StringRef()) const;
+ bool isBlacklistedFunction(StringRef FunctionName) const;
+ bool isBlacklistedFile(StringRef FileName,
+ StringRef Category = StringRef()) const;
+ bool isBlacklistedLocation(SourceLocation Loc,
+ StringRef Category = StringRef()) const;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def
index 0ef39bc710bb..91a1ef4d197c 100644
--- a/include/clang/Basic/Sanitizers.def
+++ b/include/clang/Basic/Sanitizers.def
@@ -59,9 +59,11 @@ SANITIZER("float-cast-overflow", FloatCastOverflow)
SANITIZER("float-divide-by-zero", FloatDivideByZero)
SANITIZER("function", Function)
SANITIZER("integer-divide-by-zero", IntegerDivideByZero)
+SANITIZER("nonnull-attribute", NonnullAttribute)
SANITIZER("null", Null)
SANITIZER("object-size", ObjectSize)
SANITIZER("return", Return)
+SANITIZER("returns-nonnull-attribute", ReturnsNonnullAttribute)
SANITIZER("shift", Shift)
SANITIZER("signed-integer-overflow", SignedIntegerOverflow)
SANITIZER("unreachable", Unreachable)
@@ -78,9 +80,10 @@ SANITIZER("dataflow", DataFlow)
// ABI or address space layout implications, and only catch undefined behavior.
SANITIZER_GROUP("undefined", Undefined,
Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |
- FloatDivideByZero | Function | IntegerDivideByZero | Null |
- ObjectSize | Return | Shift | SignedIntegerOverflow |
- Unreachable | VLABound | Vptr)
+ FloatDivideByZero | Function | IntegerDivideByZero |
+ NonnullAttribute | Null | ObjectSize | Return |
+ ReturnsNonnullAttribute | Shift | SignedIntegerOverflow |
+ Unreachable | VLABound | Vptr)
// -fsanitize=undefined-trap includes
// all sanitizers included by -fsanitize=undefined, except those that require
@@ -88,9 +91,9 @@ SANITIZER_GROUP("undefined", Undefined,
// -fsanitize-undefined-trap-on-error flag.
SANITIZER_GROUP("undefined-trap", UndefinedTrap,
Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |
- FloatDivideByZero | IntegerDivideByZero | Null | ObjectSize |
- Return | Shift | SignedIntegerOverflow | Unreachable |
- VLABound)
+ FloatDivideByZero | IntegerDivideByZero | NonnullAttribute |
+ Null | ObjectSize | Return | ReturnsNonnullAttribute |
+ Shift | SignedIntegerOverflow | Unreachable | VLABound)
SANITIZER_GROUP("integer", Integer,
SignedIntegerOverflow | UnsignedIntegerOverflow | Shift |
@@ -99,5 +102,9 @@ SANITIZER_GROUP("integer", Integer,
SANITIZER("local-bounds", LocalBounds)
SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds)
+// Magic group, containing all sanitizers. For example, "-fno-sanitize=all"
+// can be used to disable all the sanitizers.
+SANITIZER_GROUP("all", All, ~0)
+
#undef SANITIZER
#undef SANITIZER_GROUP
diff --git a/include/clang/Basic/Sanitizers.h b/include/clang/Basic/Sanitizers.h
new file mode 100644
index 000000000000..868b331f2f36
--- /dev/null
+++ b/include/clang/Basic/Sanitizers.h
@@ -0,0 +1,47 @@
+//===--- Sanitizers.h - C Language Family Language Options ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the clang::SanitizerKind enum.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_SANITIZERS_H
+#define LLVM_CLANG_BASIC_SANITIZERS_H
+
+namespace clang {
+
+enum class SanitizerKind {
+#define SANITIZER(NAME, ID) ID,
+#include "clang/Basic/Sanitizers.def"
+ Unknown
+};
+
+class SanitizerSet {
+ /// \brief Bitmask of enabled sanitizers.
+ unsigned Kinds;
+public:
+ SanitizerSet();
+
+ /// \brief Check if a certain sanitizer is enabled.
+ bool has(SanitizerKind K) const;
+
+ /// \brief Enable or disable a certain sanitizer.
+ void set(SanitizerKind K, bool Value);
+
+ /// \brief Disable all sanitizers.
+ void clear();
+
+ /// \brief Returns true if at least one sanitizer is enabled.
+ bool empty() const;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 7b637d7e1fb3..7aaee1df2260 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SOURCELOCATION_H
-#define LLVM_CLANG_SOURCELOCATION_H
+#ifndef LLVM_CLANG_BASIC_SOURCELOCATION_H
+#define LLVM_CLANG_BASIC_SOURCELOCATION_H
#include "clang/Basic/LLVM.h"
#include "llvm/Support/Compiler.h"
@@ -292,7 +292,6 @@ public:
const char *getCharacterData(bool *Invalid = nullptr) const;
- const llvm::MemoryBuffer* getBuffer(bool *Invalid = nullptr) const;
/// \brief Return a StringRef to the source buffer data for the
/// specified FileID.
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index e567a7a28da5..717258ddcf04 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -32,8 +32,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SOURCEMANAGER_H
-#define LLVM_CLANG_SOURCEMANAGER_H
+#ifndef LLVM_CLANG_BASIC_SOURCEMANAGER_H
+#define LLVM_CLANG_BASIC_SOURCEMANAGER_H
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
@@ -205,10 +205,10 @@ namespace SrcMgr {
/// this content cache. This is used for performance analysis.
llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const;
- void setBuffer(llvm::MemoryBuffer *B) {
+ void setBuffer(std::unique_ptr<llvm::MemoryBuffer> B) {
assert(!Buffer.getPointer() && "MemoryBuffer already set.");
- Buffer.setPointer(B);
- Buffer.setInt(false);
+ Buffer.setPointer(B.release());
+ Buffer.setInt(0);
}
/// \brief Get the underlying buffer, returning NULL if the buffer is not
@@ -685,9 +685,9 @@ class SourceManager : public RefCountedBase<SourceManager> {
InBeforeInTUCacheEntry &getInBeforeInTUCache(FileID LFID, FileID RFID) const;
// Cache for the "fake" buffer used for error-recovery purposes.
- mutable llvm::MemoryBuffer *FakeBufferForRecovery;
+ mutable std::unique_ptr<llvm::MemoryBuffer> FakeBufferForRecovery;
- mutable SrcMgr::ContentCache *FakeContentCacheForRecovery;
+ mutable std::unique_ptr<SrcMgr::ContentCache> FakeContentCacheForRecovery;
/// \brief Lazily computed map of macro argument chunks to their expanded
/// source location.
@@ -754,7 +754,6 @@ public:
/// \brief Set the file ID for the main source file.
void setMainFileID(FileID FID) {
- assert(MainFileID.isInvalid() && "MainFileID already set!");
MainFileID = FID;
}
@@ -789,12 +788,12 @@ public:
///
/// This does no caching of the buffer and takes ownership of the
/// MemoryBuffer, so only pass a MemoryBuffer to this once.
- FileID createFileID(llvm::MemoryBuffer *Buffer,
+ FileID createFileID(std::unique_ptr<llvm::MemoryBuffer> Buffer,
SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
int LoadedID = 0, unsigned LoadedOffset = 0,
SourceLocation IncludeLoc = SourceLocation()) {
- return createFileID(createMemBufferContentCache(Buffer), IncludeLoc,
- FileCharacter, LoadedID, LoadedOffset);
+ return createFileID(createMemBufferContentCache(std::move(Buffer)),
+ IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
}
/// \brief Return a new SourceLocation that encodes the
@@ -833,7 +832,11 @@ public:
/// \param DoNotFree If true, then the buffer will not be freed when the
/// source manager is destroyed.
void overrideFileContents(const FileEntry *SourceFile,
- llvm::MemoryBuffer *Buffer, bool DoNotFree = false);
+ llvm::MemoryBuffer *Buffer, bool DoNotFree);
+ void overrideFileContents(const FileEntry *SourceFile,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+ overrideFileContents(SourceFile, Buffer.release(), /*DoNotFree*/ false);
+ }
/// \brief Override the given source file with another one.
///
@@ -1624,7 +1627,7 @@ private:
/// \brief Create a new ContentCache for the specified memory buffer.
const SrcMgr::ContentCache *
- createMemBufferContentCache(llvm::MemoryBuffer *Buf);
+ createMemBufferContentCache(std::unique_ptr<llvm::MemoryBuffer> Buf);
FileID getFileIDSlow(unsigned SLocOffset) const;
FileID getFileIDLocal(unsigned SLocOffset) const;
@@ -1674,7 +1677,7 @@ class BeforeThanCompare<SourceRange> {
public:
explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { }
- bool operator()(SourceRange LHS, SourceRange RHS) {
+ bool operator()(SourceRange LHS, SourceRange RHS) const {
return SM.isBeforeInTranslationUnit(LHS.getBegin(), RHS.getBegin());
}
};
diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h
index af95b78883fe..f31d604244d0 100644
--- a/include/clang/Basic/SourceManagerInternals.h
+++ b/include/clang/Basic/SourceManagerInternals.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SOURCEMANAGER_INTERNALS_H
-#define LLVM_CLANG_SOURCEMANAGER_INTERNALS_H
+#ifndef LLVM_CLANG_BASIC_SOURCEMANAGERINTERNALS_H
+#define LLVM_CLANG_BASIC_SOURCEMANAGERINTERNALS_H
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index f89567356be5..a968d00d2089 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -203,6 +203,7 @@ namespace clang {
CC_X86StdCall, // __attribute__((stdcall))
CC_X86FastCall, // __attribute__((fastcall))
CC_X86ThisCall, // __attribute__((thiscall))
+ CC_X86VectorCall, // __attribute__((vectorcall))
CC_X86Pascal, // __attribute__((pascal))
CC_X86_64Win64, // __attribute__((ms_abi))
CC_X86_64SysV, // __attribute__((sysv_abi))
@@ -212,16 +213,18 @@ namespace clang {
CC_IntelOclBicc // __attribute__((intel_ocl_bicc))
};
- /// \brief Checks whether the given calling convention is callee-cleanup.
- inline bool isCalleeCleanup(CallingConv CC) {
+ /// \brief Checks whether the given calling convention supports variadic
+ /// calls. Unprototyped calls also use the variadic call rules.
+ inline bool supportsVariadicCall(CallingConv CC) {
switch (CC) {
case CC_X86StdCall:
case CC_X86FastCall:
case CC_X86ThisCall:
case CC_X86Pascal:
- return true;
- default:
+ case CC_X86VectorCall:
return false;
+ default:
+ return true;
}
}
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index d9806486497d..750108f39f9a 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -135,6 +135,7 @@ def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
def FunctionParmPackExpr : DStmt<Expr>;
def MaterializeTemporaryExpr : DStmt<Expr>;
def LambdaExpr : DStmt<Expr>;
+def CXXFoldExpr : DStmt<Expr>;
// Obj-C Expressions.
def ObjCStringLiteral : DStmt<Expr>;
@@ -163,6 +164,7 @@ def ShuffleVectorExpr : DStmt<Expr>;
def ConvertVectorExpr : DStmt<Expr>;
def BlockExpr : DStmt<Expr>;
def OpaqueValueExpr : DStmt<Expr>;
+def TypoExpr : DStmt<Expr>;
// Microsoft Extensions.
def MSPropertyRefExpr : DStmt<Expr>;
@@ -178,18 +180,25 @@ def AsTypeExpr : DStmt<Expr>;
// OpenMP Directives.
def OMPExecutableDirective : Stmt<1>;
+def OMPLoopDirective : DStmt<OMPExecutableDirective, 1>;
def OMPParallelDirective : DStmt<OMPExecutableDirective>;
-def OMPSimdDirective : DStmt<OMPExecutableDirective>;
-def OMPForDirective : DStmt<OMPExecutableDirective>;
+def OMPSimdDirective : DStmt<OMPLoopDirective>;
+def OMPForDirective : DStmt<OMPLoopDirective>;
+def OMPForSimdDirective : DStmt<OMPLoopDirective>;
def OMPSectionsDirective : DStmt<OMPExecutableDirective>;
def OMPSectionDirective : DStmt<OMPExecutableDirective>;
def OMPSingleDirective : DStmt<OMPExecutableDirective>;
def OMPMasterDirective : DStmt<OMPExecutableDirective>;
def OMPCriticalDirective : DStmt<OMPExecutableDirective>;
-def OMPParallelForDirective : DStmt<OMPExecutableDirective>;
+def OMPParallelForDirective : DStmt<OMPLoopDirective>;
+def OMPParallelForSimdDirective : DStmt<OMPLoopDirective>;
def OMPParallelSectionsDirective : DStmt<OMPExecutableDirective>;
def OMPTaskDirective : DStmt<OMPExecutableDirective>;
def OMPTaskyieldDirective : DStmt<OMPExecutableDirective>;
def OMPBarrierDirective : DStmt<OMPExecutableDirective>;
def OMPTaskwaitDirective : DStmt<OMPExecutableDirective>;
def OMPFlushDirective : DStmt<OMPExecutableDirective>;
+def OMPOrderedDirective : DStmt<OMPExecutableDirective>;
+def OMPAtomicDirective : DStmt<OMPExecutableDirective>;
+def OMPTargetDirective : DStmt<OMPExecutableDirective>;
+def OMPTeamsDirective : DStmt<OMPExecutableDirective>;
diff --git a/include/clang/Basic/TargetBuiltins.h b/include/clang/Basic/TargetBuiltins.h
index b1652bed07f2..e112c654b5d0 100644
--- a/include/clang/Basic/TargetBuiltins.h
+++ b/include/clang/Basic/TargetBuiltins.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_BASIC_TARGET_BUILTINS_H
-#define LLVM_CLANG_BASIC_TARGET_BUILTINS_H
+#ifndef LLVM_CLANG_BASIC_TARGETBUILTINS_H
+#define LLVM_CLANG_BASIC_TARGETBUILTINS_H
#include "clang/Basic/Builtins.h"
#undef PPC
@@ -164,6 +164,17 @@ namespace clang {
LastTSBuiltin
};
}
+
+ /// \brief Le64 builtins
+ namespace Le64 {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
+ #define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+ #include "clang/Basic/BuiltinsLe64.def"
+ LastTSBuiltin
+ };
+ }
+
} // end namespace clang.
#endif
diff --git a/include/clang/Basic/TargetCXXABI.h b/include/clang/Basic/TargetCXXABI.h
index f9e37c360b4f..5669d2a55937 100644
--- a/include/clang/Basic/TargetCXXABI.h
+++ b/include/clang/Basic/TargetCXXABI.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TARGETCXXABI_H
-#define LLVM_CLANG_TARGETCXXABI_H
+#ifndef LLVM_CLANG_BASIC_TARGETCXXABI_H
+#define LLVM_CLANG_BASIC_TARGETCXXABI_H
#include "llvm/ADT/Triple.h"
#include "llvm/Support/ErrorHandling.h"
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index edef7c0377f2..69a54044680d 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -370,6 +370,15 @@ public:
/// \brief Return the maximum width lock-free atomic operation which can be
/// inlined given the supported features of the given target.
unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; }
+ /// \brief Returns true if the given target supports lock-free atomic
+ /// operations at the specified width and alignment.
+ virtual bool hasBuiltinAtomic(uint64_t AtomicSizeInBits,
+ uint64_t AlignmentInBits) const {
+ return AtomicSizeInBits <= AlignmentInBits &&
+ AtomicSizeInBits <= getMaxAtomicInlineWidth() &&
+ (AtomicSizeInBits <= getCharWidth() ||
+ llvm::isPowerOf2_64(AtomicSizeInBits / getCharWidth()));
+ }
/// \brief Return the maximum vector alignment supported for the given target.
unsigned getMaxVectorAlign() const { return MaxVectorAlign; }
@@ -519,22 +528,31 @@ public:
CI_None = 0x00,
CI_AllowsMemory = 0x01,
CI_AllowsRegister = 0x02,
- CI_ReadWrite = 0x04, // "+r" output constraint (read and write).
- CI_HasMatchingInput = 0x08 // This output operand has a matching input.
+ CI_ReadWrite = 0x04, // "+r" output constraint (read and write).
+ CI_HasMatchingInput = 0x08, // This output operand has a matching input.
+ CI_ImmediateConstant = 0x10, // This operand must be an immediate constant
+ CI_EarlyClobber = 0x20, // "&" output constraint (early clobber).
};
unsigned Flags;
int TiedOperand;
+ struct {
+ int Min;
+ int Max;
+ } ImmRange;
std::string ConstraintStr; // constraint: "=rm"
std::string Name; // Operand name: [foo] with no []'s.
public:
ConstraintInfo(StringRef ConstraintStr, StringRef Name)
- : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()),
- Name(Name.str()) {}
+ : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()),
+ Name(Name.str()) {
+ ImmRange.Min = ImmRange.Max = 0;
+ }
const std::string &getConstraintStr() const { return ConstraintStr; }
const std::string &getName() const { return Name; }
bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; }
+ bool earlyClobber() { return (Flags & CI_EarlyClobber) != 0; }
bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; }
bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; }
@@ -553,10 +571,22 @@ public:
return (unsigned)TiedOperand;
}
+ bool requiresImmediateConstant() const {
+ return (Flags & CI_ImmediateConstant) != 0;
+ }
+ int getImmConstantMin() const { return ImmRange.Min; }
+ int getImmConstantMax() const { return ImmRange.Max; }
+
void setIsReadWrite() { Flags |= CI_ReadWrite; }
+ void setEarlyClobber() { Flags |= CI_EarlyClobber; }
void setAllowsMemory() { Flags |= CI_AllowsMemory; }
void setAllowsRegister() { Flags |= CI_AllowsRegister; }
void setHasMatchingInput() { Flags |= CI_HasMatchingInput; }
+ void setRequiresImmediate(int Min, int Max) {
+ Flags |= CI_ImmediateConstant;
+ ImmRange.Min = Min;
+ ImmRange.Max = Max;
+ }
/// \brief Indicate that this is an input operand that is tied to
/// the specified output operand.
@@ -577,13 +607,21 @@ public:
bool validateInputConstraint(ConstraintInfo *OutputConstraints,
unsigned NumOutputs,
ConstraintInfo &info) const;
+
+ virtual bool validateOutputSize(StringRef /*Constraint*/,
+ unsigned /*Size*/) const {
+ return true;
+ }
+
virtual bool validateInputSize(StringRef /*Constraint*/,
unsigned /*Size*/) const {
return true;
}
- virtual bool validateConstraintModifier(StringRef /*Constraint*/,
- const char /*Modifier*/,
- unsigned /*Size*/) const {
+ virtual bool
+ validateConstraintModifier(StringRef /*Constraint*/,
+ char /*Modifier*/,
+ unsigned /*Size*/,
+ std::string &/*SuggestedModifier*/) const {
return true;
}
bool resolveSymbolicName(const char *&Name,
diff --git a/include/clang/Basic/TargetOptions.h b/include/clang/Basic/TargetOptions.h
index 2c86c31c2391..97825394202f 100644
--- a/include/clang/Basic/TargetOptions.h
+++ b/include/clang/Basic/TargetOptions.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_TARGETOPTIONS_H
-#define LLVM_CLANG_FRONTEND_TARGETOPTIONS_H
+#ifndef LLVM_CLANG_BASIC_TARGETOPTIONS_H
+#define LLVM_CLANG_BASIC_TARGETOPTIONS_H
#include <string>
#include <vector>
diff --git a/include/clang/Basic/TemplateKinds.h b/include/clang/Basic/TemplateKinds.h
index b730143b6391..aed287b46228 100644
--- a/include/clang/Basic/TemplateKinds.h
+++ b/include/clang/Basic/TemplateKinds.h
@@ -11,8 +11,8 @@
/// \brief Defines the clang::TemplateNameKind enum.
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TEMPLATEKINDS_H
-#define LLVM_CLANG_TEMPLATEKINDS_H
+#ifndef LLVM_CLANG_BASIC_TEMPLATEKINDS_H
+#define LLVM_CLANG_BASIC_TEMPLATEKINDS_H
namespace clang {
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 5d088336dfe2..3319d4ed35e0 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -116,7 +116,6 @@ TOK(eof) // End of file.
TOK(eod) // End of preprocessing directive (end of line inside a
// directive).
TOK(code_completion) // Code completion marker
-TOK(cxx_defaultarg_end) // C++ default argument end marker
// C99 6.4.9: Comments.
TOK(comment) // Comment (only in -E -C[C] mode)
@@ -133,6 +132,9 @@ TOK(numeric_constant) // 0x123
TOK(char_constant) // 'a'
TOK(wide_char_constant) // L'b'
+// C++1z Character Constants
+TOK(utf8_char_constant) // u8'a'
+
// C++11 Character Constants
TOK(utf16_char_constant) // u'a'
TOK(utf32_char_constant) // U'a'
@@ -457,18 +459,22 @@ KEYWORD(__cdecl , KEYALL)
KEYWORD(__stdcall , KEYALL)
KEYWORD(__fastcall , KEYALL)
KEYWORD(__thiscall , KEYALL)
+KEYWORD(__vectorcall , KEYALL)
KEYWORD(__forceinline , KEYMS)
KEYWORD(__unaligned , KEYMS)
+KEYWORD(__super , KEYMS)
// OpenCL address space qualifiers
KEYWORD(__global , KEYOPENCL)
KEYWORD(__local , KEYOPENCL)
KEYWORD(__constant , KEYOPENCL)
KEYWORD(__private , KEYOPENCL)
+KEYWORD(__generic , KEYOPENCL)
ALIAS("global", __global , KEYOPENCL)
ALIAS("local", __local , KEYOPENCL)
ALIAS("constant", __constant , KEYOPENCL)
ALIAS("private", __private , KEYOPENCL)
+ALIAS("generic", __generic , KEYOPENCL)
// OpenCL function qualifiers
KEYWORD(__kernel , KEYOPENCL)
ALIAS("kernel", __kernel , KEYOPENCL)
@@ -489,6 +495,7 @@ KEYWORD(__pascal , KEYALL)
// Altivec Extension.
KEYWORD(__vector , KEYALTIVEC)
KEYWORD(__pixel , KEYALTIVEC)
+KEYWORD(__bool , KEYALTIVEC)
// ARM NEON extensions.
ALIAS("__fp16", half , KEYALL)
@@ -545,8 +552,12 @@ KEYWORD(__multiple_inheritance , KEYMS)
KEYWORD(__virtual_inheritance , KEYMS)
KEYWORD(__interface , KEYMS)
ALIAS("__int8" , char , KEYMS)
+ALIAS("_int8" , char , KEYMS)
ALIAS("__int16" , short , KEYMS)
+ALIAS("_int16" , short , KEYMS)
ALIAS("__int32" , int , KEYMS)
+ALIAS("_int32" , int , KEYMS)
+ALIAS("_int64" , __int64 , KEYMS)
ALIAS("__wchar_t" , wchar_t , KEYMS)
ALIAS("_asm" , asm , KEYMS)
ALIAS("_alignof" , __alignof , KEYMS)
@@ -555,6 +566,7 @@ ALIAS("_cdecl" , __cdecl , KEYMS | KEYBORLAND)
ALIAS("_fastcall" , __fastcall , KEYMS | KEYBORLAND)
ALIAS("_stdcall" , __stdcall , KEYMS | KEYBORLAND)
ALIAS("_thiscall" , __thiscall , KEYMS)
+ALIAS("_vectorcall" , __vectorcall, KEYMS)
ALIAS("_uuidof" , __uuidof , KEYMS | KEYBORLAND)
ALIAS("_inline" , inline , KEYMS)
ALIAS("_declspec" , __declspec , KEYMS)
diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h
index 794625ca91e3..f4ecb3eb306f 100644
--- a/include/clang/Basic/TokenKinds.h
+++ b/include/clang/Basic/TokenKinds.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOKENKINDS_H
-#define LLVM_CLANG_TOKENKINDS_H
+#ifndef LLVM_CLANG_BASIC_TOKENKINDS_H
+#define LLVM_CLANG_BASIC_TOKENKINDS_H
#include "llvm/Support/Compiler.h"
@@ -86,9 +86,9 @@ inline bool isStringLiteral(TokenKind K) {
/// constant, string, etc.
inline bool isLiteral(TokenKind K) {
return K == tok::numeric_constant || K == tok::char_constant ||
- K == tok::wide_char_constant || K == tok::utf16_char_constant ||
- K == tok::utf32_char_constant || isStringLiteral(K) ||
- K == tok::angle_string_literal;
+ K == tok::wide_char_constant || K == tok::utf8_char_constant ||
+ K == tok::utf16_char_constant || K == tok::utf32_char_constant ||
+ isStringLiteral(K) || K == tok::angle_string_literal;
}
/// \brief Return true if this is any of tok::annot_* kinds.
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index d7d2b18f3101..ef84d2b11163 100644
--- a/include/clang/Basic/TypeTraits.h
+++ b/include/clang/Basic/TypeTraits.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TYPETRAITS_H
-#define LLVM_CLANG_TYPETRAITS_H
+#ifndef LLVM_CLANG_BASIC_TYPETRAITS_H
+#define LLVM_CLANG_BASIC_TYPETRAITS_H
namespace clang {
diff --git a/include/clang/Basic/VersionTuple.h b/include/clang/Basic/VersionTuple.h
index 54d06e07396a..77fd947f96a9 100644
--- a/include/clang/Basic/VersionTuple.h
+++ b/include/clang/Basic/VersionTuple.h
@@ -24,30 +24,35 @@ namespace clang {
/// \brief Represents a version number in the form major[.minor[.subminor]].
class VersionTuple {
- unsigned Major;
+ unsigned Major : 31;
unsigned Minor : 31;
unsigned Subminor : 31;
unsigned HasMinor : 1;
unsigned HasSubminor : 1;
+ unsigned UsesUnderscores : 1;
public:
VersionTuple()
- : Major(0), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false) { }
+ : Major(0), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false),
+ UsesUnderscores(false) { }
explicit VersionTuple(unsigned Major)
- : Major(Major), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false)
+ : Major(Major), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false),
+ UsesUnderscores(false)
{ }
- explicit VersionTuple(unsigned Major, unsigned Minor)
+ explicit VersionTuple(unsigned Major, unsigned Minor,
+ bool UsesUnderscores = false)
: Major(Major), Minor(Minor), Subminor(0), HasMinor(true),
- HasSubminor(false)
+ HasSubminor(false), UsesUnderscores(UsesUnderscores)
{ }
- explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor)
+ explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor,
+ bool UsesUnderscores = false)
: Major(Major), Minor(Minor), Subminor(Subminor), HasMinor(true),
- HasSubminor(true)
+ HasSubminor(true), UsesUnderscores(UsesUnderscores)
{ }
-
+
/// \brief Determine whether this version information is empty
/// (e.g., all version components are zero).
bool empty() const { return Major == 0 && Minor == 0 && Subminor == 0; }
@@ -69,6 +74,14 @@ public:
return Subminor;
}
+ bool usesUnderscores() const {
+ return UsesUnderscores;
+ }
+
+ void UseDotAsSeparator() {
+ UsesUnderscores = false;
+ }
+
/// \brief Determine if two version numbers are equivalent. If not
/// provided, minor and subminor version numbers are considered to be zero.
friend bool operator==(const VersionTuple& X, const VersionTuple &Y) {
diff --git a/include/clang/Basic/VirtualFileSystem.h b/include/clang/Basic/VirtualFileSystem.h
index 36f78fd8725f..1c65fb5eac06 100644
--- a/include/clang/Basic/VirtualFileSystem.h
+++ b/include/clang/Basic/VirtualFileSystem.h
@@ -10,16 +10,16 @@
/// \brief Defines the virtual file system interface vfs::FileSystem.
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H
-#define LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H
+#ifndef LLVM_CLANG_BASIC_VIRTUALFILESYSTEM_H
+#define LLVM_CLANG_BASIC_VIRTUALFILESYSTEM_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
namespace llvm {
class MemoryBuffer;
@@ -89,11 +89,9 @@ public:
/// \brief Get the status of the file.
virtual llvm::ErrorOr<Status> status() = 0;
/// \brief Get the contents of the file as a \p MemoryBuffer.
- virtual std::error_code getBuffer(const Twine &Name,
- std::unique_ptr<llvm::MemoryBuffer> &Result,
- int64_t FileSize = -1,
- bool RequiresNullTerminator = true,
- bool IsVolatile = false) = 0;
+ virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBuffer(const Twine &Name, int64_t FileSize = -1,
+ bool RequiresNullTerminator = true, bool IsVolatile = false) = 0;
/// \brief Closes the file.
virtual std::error_code close() = 0;
/// \brief Sets the name to use for this file.
@@ -188,16 +186,14 @@ public:
/// \brief Get the status of the entry at \p Path, if one exists.
virtual llvm::ErrorOr<Status> status(const Twine &Path) = 0;
/// \brief Get a \p File object for the file at \p Path, if one exists.
- virtual std::error_code openFileForRead(const Twine &Path,
- std::unique_ptr<File> &Result) = 0;
+ virtual llvm::ErrorOr<std::unique_ptr<File>>
+ openFileForRead(const Twine &Path) = 0;
/// This is a convenience method that opens a file, gets its content and then
/// closes the file.
- std::error_code getBufferForFile(const Twine &Name,
- std::unique_ptr<llvm::MemoryBuffer> &Result,
- int64_t FileSize = -1,
- bool RequiresNullTerminator = true,
- bool IsVolatile = false);
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBufferForFile(const Twine &Name, int64_t FileSize = -1,
+ bool RequiresNullTerminator = true, bool IsVolatile = false);
/// \brief Get a directory_iterator for \p Dir.
/// \note The 'end' iterator is directory_iterator().
@@ -231,8 +227,8 @@ public:
void pushOverlay(IntrusiveRefCntPtr<FileSystem> FS);
llvm::ErrorOr<Status> status(const Twine &Path) override;
- std::error_code openFileForRead(const Twine &Path,
- std::unique_ptr<File> &Result) override;
+ llvm::ErrorOr<std::unique_ptr<File>>
+ openFileForRead(const Twine &Path) override;
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
typedef FileSystemList::reverse_iterator iterator;
@@ -250,10 +246,8 @@ llvm::sys::fs::UniqueID getNextVirtualUniqueID();
/// \brief Gets a \p FileSystem for a virtual file system described in YAML
/// format.
-///
-/// Takes ownership of \p Buffer.
IntrusiveRefCntPtr<FileSystem>
-getVFSFromYAML(llvm::MemoryBuffer *Buffer,
+getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer> Buffer,
llvm::SourceMgr::DiagHandlerTy DiagHandler,
void *DiagContext = nullptr,
IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem());
@@ -280,4 +274,4 @@ public:
} // end namespace vfs
} // end namespace clang
-#endif // LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H
+#endif
diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td
index 0247bb5dd0d7..933f204bfb52 100644
--- a/include/clang/Basic/arm_neon.td
+++ b/include/clang/Basic/arm_neon.td
@@ -944,13 +944,6 @@ def VCVT_F64 : SInst<"vcvt_f64", "Fd", "lUlQlQUl">;
def VCVT_HIGH_F64_F32 : SOpInst<"vcvt_high_f64", "wj", "f", OP_VCVT_EX_HI_F64>;
def VCVTX_F32_F64 : SInst<"vcvtx_f32", "fj", "d">;
def VCVTX_HIGH_F32_F64 : SOpInst<"vcvtx_high_f32", "qfj", "d", OP_VCVTX_HI>;
-def FRINTN : SInst<"vrndn", "dd", "fdQfQd">;
-def FRINTA : SInst<"vrnda", "dd", "fdQfQd">;
-def FRINTP : SInst<"vrndp", "dd", "fdQfQd">;
-def FRINTM : SInst<"vrndm", "dd", "fdQfQd">;
-def FRINTX : SInst<"vrndx", "dd", "fdQfQd">;
-def FRINTZ : SInst<"vrnd", "dd", "fdQfQd">;
-def FRINTI : SInst<"vrndi", "dd", "fdQfQd">;
def VCVT_S64 : SInst<"vcvt_s64", "xd", "dQd">;
def VCVT_U64 : SInst<"vcvt_u64", "ud", "dQd">;
def FRECPE : SInst<"vrecpe", "dd", "dQd">;
@@ -983,11 +976,6 @@ def MAX : SInst<"vmax", "ddd", "dQd">;
def MIN : SInst<"vmin", "ddd", "dQd">;
////////////////////////////////////////////////////////////////////////////////
-// MaxNum/MinNum Floating Point
-def FMAXNM : SInst<"vmaxnm", "ddd", "fdQfQd">;
-def FMINNM : SInst<"vminnm", "ddd", "fdQfQd">;
-
-////////////////////////////////////////////////////////////////////////////////
// Pairwise Max/Min
def MAXP : SInst<"vpmax", "ddd", "QcQsQiQUcQUsQUiQfQd">;
def MINP : SInst<"vpmin", "ddd", "QcQsQiQUcQUsQUiQfQd">;
@@ -1089,7 +1077,7 @@ def VDUP_LANE2: WOpInst<"vdup_laneq", "dji",
"csilUcUsUiUlPcPshfdQcQsQiQlQPcQPsQUcQUsQUiQUlQhQfQdPlQPl",
OP_DUP_LN>;
def DUP_N : WOpInst<"vdup_n", "ds", "dQdPlQPl", OP_DUP>;
-def MOV_N : WOpInst<"vmov_n", "ds", "dQd", OP_DUP>;
+def MOV_N : WOpInst<"vmov_n", "ds", "dQdPlQPl", OP_DUP>;
////////////////////////////////////////////////////////////////////////////////
def COMBINE : NoTestOpInst<"vcombine", "kdd", "dPl", OP_CONC>;
@@ -1223,6 +1211,41 @@ def FCVTAU_S64 : SInst<"vcvta_u64", "ud", "dQd">;
}
////////////////////////////////////////////////////////////////////////////////
+// Round to Integral
+
+let ArchGuard = "__ARM_ARCH >= 8 && defined(__ARM_FEATURE_DIRECTED_ROUNDING)" in {
+def FRINTN_S32 : SInst<"vrndn", "dd", "fQf">;
+def FRINTA_S32 : SInst<"vrnda", "dd", "fQf">;
+def FRINTP_S32 : SInst<"vrndp", "dd", "fQf">;
+def FRINTM_S32 : SInst<"vrndm", "dd", "fQf">;
+def FRINTX_S32 : SInst<"vrndx", "dd", "fQf">;
+def FRINTZ_S32 : SInst<"vrnd", "dd", "fQf">;
+}
+
+let ArchGuard = "__ARM_ARCH >= 8 && defined(__aarch64__) && defined(__ARM_FEATURE_DIRECTED_ROUNDING)" in {
+def FRINTN_S64 : SInst<"vrndn", "dd", "dQd">;
+def FRINTA_S64 : SInst<"vrnda", "dd", "dQd">;
+def FRINTP_S64 : SInst<"vrndp", "dd", "dQd">;
+def FRINTM_S64 : SInst<"vrndm", "dd", "dQd">;
+def FRINTX_S64 : SInst<"vrndx", "dd", "dQd">;
+def FRINTZ_S64 : SInst<"vrnd", "dd", "dQd">;
+def FRINTI_S64 : SInst<"vrndi", "dd", "fdQfQd">;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// MaxNum/MinNum Floating Point
+
+let ArchGuard = "__ARM_ARCH >= 8 && defined(__ARM_FEATURE_NUMERIC_MAXMIN)" in {
+def FMAXNM_S32 : SInst<"vmaxnm", "ddd", "fQf">;
+def FMINNM_S32 : SInst<"vminnm", "ddd", "fQf">;
+}
+
+let ArchGuard = "__ARM_ARCH >= 8 && defined(__aarch64__) && defined(__ARM_FEATURE_NUMERIC_MAXMIN)" in {
+def FMAXNM_S64 : SInst<"vmaxnm", "ddd", "dQd">;
+def FMINNM_S64 : SInst<"vminnm", "ddd", "dQd">;
+}
+
+////////////////////////////////////////////////////////////////////////////////
// Permutation
def VTRN1 : SOpInst<"vtrn1", "ddd",
"csiUcUsUifPcPsQcQsQiQlQUcQUsQUiQUlQfQdQPcQPsQPl", OP_TRN1>;
diff --git a/include/clang/CodeGen/BackendUtil.h b/include/clang/CodeGen/BackendUtil.h
index f8b90b34eeec..07c618368329 100644
--- a/include/clang/CodeGen/BackendUtil.h
+++ b/include/clang/CodeGen/BackendUtil.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CODEGEN_BACKEND_UTIL_H
-#define LLVM_CLANG_CODEGEN_BACKEND_UTIL_H
+#ifndef LLVM_CLANG_CODEGEN_BACKENDUTIL_H
+#define LLVM_CLANG_CODEGEN_BACKENDUTIL_H
#include "clang/Basic/LLVM.h"
diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h
index 449827e02891..102d25d79e04 100644
--- a/include/clang/CodeGen/CGFunctionInfo.h
+++ b/include/clang/CodeGen/CGFunctionInfo.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CODEGEN_FUNCTION_INFO_H
-#define LLVM_CLANG_CODEGEN_FUNCTION_INFO_H
+#ifndef LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H
+#define LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H
#include "clang/AST/CanonicalType.h"
#include "clang/AST/Type.h"
@@ -87,6 +87,7 @@ private:
bool IndirectRealign : 1; // isIndirect()
bool SRetAfterThis : 1; // isIndirect()
bool InReg : 1; // isDirect() || isExtend() || isIndirect()
+ bool CanBeFlattened: 1; // isDirect()
ABIArgInfo(Kind K)
: PaddingType(nullptr), TheKind(K), PaddingInReg(false), InReg(false) {}
@@ -97,11 +98,13 @@ public:
TheKind(Direct), PaddingInReg(false), InReg(false) {}
static ABIArgInfo getDirect(llvm::Type *T = nullptr, unsigned Offset = 0,
- llvm::Type *Padding = nullptr) {
+ llvm::Type *Padding = nullptr,
+ bool CanBeFlattened = true) {
auto AI = ABIArgInfo(Direct);
AI.setCoerceToType(T);
AI.setDirectOffset(Offset);
AI.setPaddingType(Padding);
+ AI.setCanBeFlattened(CanBeFlattened);
return AI;
}
static ABIArgInfo getDirectInReg(llvm::Type *T = nullptr) {
@@ -265,6 +268,16 @@ public:
InAllocaSRet = SRet;
}
+ bool getCanBeFlattened() const {
+ assert(isDirect() && "Invalid kind!");
+ return CanBeFlattened;
+ }
+
+ void setCanBeFlattened(bool Flatten) {
+ assert(isDirect() && "Invalid kind!");
+ CanBeFlattened = Flatten;
+ }
+
void dump() const;
};
@@ -339,6 +352,9 @@ class CGFunctionInfo : public llvm::FoldingSetNode {
/// Whether this is an instance method.
unsigned InstanceMethod : 1;
+ /// Whether this is a chain call.
+ unsigned ChainCall : 1;
+
/// Whether this function is noreturn.
unsigned NoReturn : 1;
@@ -347,7 +363,7 @@ class CGFunctionInfo : public llvm::FoldingSetNode {
/// How many arguments to pass inreg.
unsigned HasRegParm : 1;
- unsigned RegParm : 4;
+ unsigned RegParm : 3;
RequiredArgs Required;
@@ -367,7 +383,8 @@ class CGFunctionInfo : public llvm::FoldingSetNode {
public:
static CGFunctionInfo *create(unsigned llvmCC,
- bool InstanceMethod,
+ bool instanceMethod,
+ bool chainCall,
const FunctionType::ExtInfo &extInfo,
CanQualType resultType,
ArrayRef<CanQualType> argTypes,
@@ -393,9 +410,14 @@ public:
bool isVariadic() const { return Required.allowsOptionalArgs(); }
RequiredArgs getRequiredArgs() const { return Required; }
+ unsigned getNumRequiredArgs() const {
+ return isVariadic() ? getRequiredArgs().getNumRequiredArgs() : arg_size();
+ }
bool isInstanceMethod() const { return InstanceMethod; }
+ bool isChainCall() const { return ChainCall; }
+
bool isNoReturn() const { return NoReturn; }
/// In ARC, whether this function retains its return value. This
@@ -446,6 +468,7 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getASTCallingConvention());
ID.AddBoolean(InstanceMethod);
+ ID.AddBoolean(ChainCall);
ID.AddBoolean(NoReturn);
ID.AddBoolean(ReturnsRetained);
ID.AddBoolean(HasRegParm);
@@ -457,12 +480,14 @@ public:
}
static void Profile(llvm::FoldingSetNodeID &ID,
bool InstanceMethod,
+ bool ChainCall,
const FunctionType::ExtInfo &info,
RequiredArgs required,
CanQualType resultType,
ArrayRef<CanQualType> argTypes) {
ID.AddInteger(info.getCC());
ID.AddBoolean(InstanceMethod);
+ ID.AddBoolean(ChainCall);
ID.AddBoolean(info.getNoReturn());
ID.AddBoolean(info.getProducesResult());
ID.AddBoolean(info.getHasRegParm());
diff --git a/include/clang/CodeGen/CodeGenABITypes.h b/include/clang/CodeGen/CodeGenABITypes.h
index 2502982b23fb..97a9dc82940d 100644
--- a/include/clang/CodeGen/CodeGenABITypes.h
+++ b/include/clang/CodeGen/CodeGenABITypes.h
@@ -21,8 +21,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CODEGEN_ABITYPES_H
-#define LLVM_CLANG_CODEGEN_ABITYPES_H
+#ifndef LLVM_CLANG_CODEGEN_CODEGENABITYPES_H
+#define LLVM_CLANG_CODEGEN_CODEGENABITYPES_H
#include "clang/AST/CanonicalType.h"
#include "clang/AST/Type.h"
@@ -39,6 +39,7 @@ class CXXRecordDecl;
class CodeGenOptions;
class DiagnosticsEngine;
class ObjCMethodDecl;
+class CoverageSourceInfo;
namespace CodeGen {
class CGFunctionInfo;
@@ -47,7 +48,8 @@ class CodeGenModule;
class CodeGenABITypes
{
public:
- CodeGenABITypes(ASTContext &C, llvm::Module &M, const llvm::DataLayout &TD);
+ CodeGenABITypes(ASTContext &C, llvm::Module &M, const llvm::DataLayout &TD,
+ CoverageSourceInfo *CoverageInfo = nullptr);
~CodeGenABITypes();
/// These methods all forward to methods in the private implementation class
diff --git a/include/clang/CodeGen/CodeGenAction.h b/include/clang/CodeGen/CodeGenAction.h
index 37819c780d5d..f8fd56152f23 100644
--- a/include/clang/CodeGen/CodeGenAction.h
+++ b/include/clang/CodeGen/CodeGenAction.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CODEGEN_CODE_GEN_ACTION_H
-#define LLVM_CLANG_CODEGEN_CODE_GEN_ACTION_H
+#ifndef LLVM_CLANG_CODEGEN_CODEGENACTION_H
+#define LLVM_CLANG_CODEGEN_CODEGENACTION_H
#include "clang/Frontend/FrontendAction.h"
#include <memory>
@@ -37,8 +37,8 @@ protected:
bool hasIRSupport() const override;
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
void ExecuteAction() override;
@@ -52,9 +52,9 @@ public:
/// the action will load it from the specified file.
void setLinkModule(llvm::Module *Mod) { LinkModule = Mod; }
- /// takeModule - Take the generated LLVM module, for use after the action has
- /// been run. The result may be null on failure.
- llvm::Module *takeModule();
+ /// Take the generated LLVM module, for use after the action has been run.
+ /// The result may be null on failure.
+ std::unique_ptr<llvm::Module> takeModule();
/// Take the LLVM context used by this action.
llvm::LLVMContext *takeLLVMContext();
diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h
index 4b7236bfd03b..f4c31074e9cd 100644
--- a/include/clang/CodeGen/ModuleBuilder.h
+++ b/include/clang/CodeGen/ModuleBuilder.h
@@ -24,6 +24,7 @@ namespace llvm {
namespace clang {
class DiagnosticsEngine;
+ class CoverageSourceInfo;
class LangOptions;
class CodeGenOptions;
class TargetOptions;
@@ -44,7 +45,8 @@ namespace clang {
const std::string &ModuleName,
const CodeGenOptions &CGO,
const TargetOptions &TO,
- llvm::LLVMContext& C);
+ llvm::LLVMContext& C,
+ CoverageSourceInfo *CoverageInfo = nullptr);
}
#endif
diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake
index 7629ef9129b1..5d89b1aaa1ac 100644
--- a/include/clang/Config/config.h.cmake
+++ b/include/clang/Config/config.h.cmake
@@ -8,6 +8,9 @@
/* Bug report URL. */
#define BUG_REPORT_URL "${BUG_REPORT_URL}"
+/* Multilib suffix for libdir. */
+#define CLANG_LIBDIR_SUFFIX "${CLANG_LIBDIR_SUFFIX}"
+
/* Relative directory for resource files */
#define CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}"
@@ -26,4 +29,7 @@
/* The LLVM product name and version */
#define BACKEND_PACKAGE_STRING "${BACKEND_PACKAGE_STRING}"
+/* Linker version detected at compile time. */
+#cmakedefine HOST_LINK_VERSION "${HOST_LINK_VERSION}"
+
#endif
diff --git a/include/clang/Config/config.h.in b/include/clang/Config/config.h.in
index 1530fefaa53d..dba05db2b99d 100644
--- a/include/clang/Config/config.h.in
+++ b/include/clang/Config/config.h.in
@@ -8,15 +8,15 @@
/* Bug report URL. */
#undef BUG_REPORT_URL
+/* Multilib suffix for libdir. */
+#undef CLANG_LIBDIR_SUFFIX
+
/* Relative directory for resource files */
#undef CLANG_RESOURCE_DIR
/* Directories clang will search for headers */
#undef C_INCLUDE_DIRS
-/* Linker version detected at compile time. */
-#undef HOST_LINK_VERSION
-
/* Default <path> to all compiler invocations for --sysroot=<path>. */
#undef DEFAULT_SYSROOT
@@ -31,4 +31,7 @@
/* The LLVM product name and version */
#define BACKEND_PACKAGE_STRING PACKAGE_STRING
+/* Linker version detected at compile time. */
+#undef HOST_LINK_VERSION
+
#endif
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index 2cdb581b85c3..dd0261c2f3a1 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_DRIVER_ACTION_H_
-#define CLANG_DRIVER_ACTION_H_
+#ifndef LLVM_CLANG_DRIVER_ACTION_H
+#define LLVM_CLANG_DRIVER_ACTION_H
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
@@ -46,6 +46,7 @@ public:
AnalyzeJobClass,
MigrateJobClass,
CompileJobClass,
+ BackendJobClass,
AssembleJobClass,
LinkJobClass,
LipoJobClass,
@@ -72,8 +73,12 @@ private:
protected:
Action(ActionClass _Kind, types::ID _Type)
: Kind(_Kind), Type(_Type), OwnsInputs(true) {}
- Action(ActionClass _Kind, Action *Input, types::ID _Type)
- : Kind(_Kind), Type(_Type), Inputs(&Input, &Input + 1), OwnsInputs(true) {}
+ Action(ActionClass _Kind, std::unique_ptr<Action> Input, types::ID _Type)
+ : Kind(_Kind), Type(_Type), Inputs(1, Input.release()), OwnsInputs(true) {
+ }
+ Action(ActionClass _Kind, std::unique_ptr<Action> Input)
+ : Kind(_Kind), Type(Input->getType()), Inputs(1, Input.release()),
+ OwnsInputs(true) {}
Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type)
: Kind(_Kind), Type(_Type), Inputs(_Inputs), OwnsInputs(true) {}
public:
@@ -119,7 +124,7 @@ class BindArchAction : public Action {
const char *ArchName;
public:
- BindArchAction(Action *Input, const char *_ArchName);
+ BindArchAction(std::unique_ptr<Action> Input, const char *_ArchName);
const char *getArchName() const { return ArchName; }
@@ -131,7 +136,7 @@ public:
class JobAction : public Action {
virtual void anchor();
protected:
- JobAction(ActionClass Kind, Action *Input, types::ID Type);
+ JobAction(ActionClass Kind, std::unique_ptr<Action> Input, types::ID Type);
JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type);
public:
@@ -144,7 +149,7 @@ public:
class PreprocessJobAction : public JobAction {
void anchor() override;
public:
- PreprocessJobAction(Action *Input, types::ID OutputType);
+ PreprocessJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == PreprocessJobClass;
@@ -154,7 +159,7 @@ public:
class PrecompileJobAction : public JobAction {
void anchor() override;
public:
- PrecompileJobAction(Action *Input, types::ID OutputType);
+ PrecompileJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == PrecompileJobClass;
@@ -164,7 +169,7 @@ public:
class AnalyzeJobAction : public JobAction {
void anchor() override;
public:
- AnalyzeJobAction(Action *Input, types::ID OutputType);
+ AnalyzeJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == AnalyzeJobClass;
@@ -174,7 +179,7 @@ public:
class MigrateJobAction : public JobAction {
void anchor() override;
public:
- MigrateJobAction(Action *Input, types::ID OutputType);
+ MigrateJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == MigrateJobClass;
@@ -184,17 +189,27 @@ public:
class CompileJobAction : public JobAction {
void anchor() override;
public:
- CompileJobAction(Action *Input, types::ID OutputType);
+ CompileJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == CompileJobClass;
}
};
+class BackendJobAction : public JobAction {
+ void anchor() override;
+public:
+ BackendJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == BackendJobClass;
+ }
+};
+
class AssembleJobAction : public JobAction {
void anchor() override;
public:
- AssembleJobAction(Action *Input, types::ID OutputType);
+ AssembleJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == AssembleJobClass;
@@ -234,7 +249,8 @@ public:
class VerifyJobAction : public JobAction {
void anchor() override;
public:
- VerifyJobAction(ActionClass Kind, Action *Input, types::ID Type);
+ VerifyJobAction(ActionClass Kind, std::unique_ptr<Action> Input,
+ types::ID Type);
VerifyJobAction(ActionClass Kind, ActionList &Inputs, types::ID Type);
static bool classof(const Action *A) {
return A->getKind() == VerifyDebugInfoJobClass ||
@@ -245,7 +261,7 @@ public:
class VerifyDebugInfoJobAction : public VerifyJobAction {
void anchor() override;
public:
- VerifyDebugInfoJobAction(Action *Input, types::ID Type);
+ VerifyDebugInfoJobAction(std::unique_ptr<Action> Input, types::ID Type);
static bool classof(const Action *A) {
return A->getKind() == VerifyDebugInfoJobClass;
}
@@ -254,7 +270,7 @@ public:
class VerifyPCHJobAction : public VerifyJobAction {
void anchor() override;
public:
- VerifyPCHJobAction(Action *Input, types::ID Type);
+ VerifyPCHJobAction(std::unique_ptr<Action> Input, types::ID Type);
static bool classof(const Action *A) {
return A->getKind() == VerifyPCHJobClass;
}
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index d25560c9f3ac..e0430014105c 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -108,6 +108,9 @@ def analyzer_disable_checker : Separate<["-"], "analyzer-disable-checker">,
def analyzer_disable_checker_EQ : Joined<["-"], "analyzer-disable-checker=">,
Alias<analyzer_disable_checker>;
+def analyzer_disable_all_checks : Flag<["-"], "analyzer-disable-all-checks">,
+ HelpText<"Disable all static analyzer checks">;
+
def analyzer_checker_help : Flag<["-"], "analyzer-checker-help">,
HelpText<"Display the list of analyzer checkers that are available">;
@@ -135,6 +138,8 @@ def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
HelpText<"The string to embed in the Dwarf debug flags record.">;
def mno_exec_stack : Flag<["-"], "mnoexecstack">,
HelpText<"Mark the file as not needing an executable stack">;
+def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">,
+ HelpText<"Make assembler warnings fatal">;
def compress_debug_sections : Flag<["-"], "compress-debug-sections">,
HelpText<"Compress DWARF debug sections using zlib">;
def msave_temp_labels : Flag<["-"], "msave-temp-labels">,
@@ -164,6 +169,8 @@ def no_implicit_float : Flag<["-"], "no-implicit-float">,
HelpText<"Don't generate implicit floating point instructions">;
def fdump_vtable_layouts : Flag<["-"], "fdump-vtable-layouts">,
HelpText<"Dump the layouts of all vtables that will be emitted in a translation unit">;
+def fmerge_functions : Flag<["-"], "fmerge-functions">,
+ HelpText<"Permit merging of identical functions when optimizing.">;
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">,
@@ -179,6 +186,8 @@ def coverage_version_EQ : Joined<["-"], "coverage-version=">,
HelpText<"Four-byte version string for gcov files.">;
def test_coverage : Flag<["-"], "test-coverage">,
HelpText<"Do not generate coverage files or remove coverage changes from IR">;
+def dump_coverage_mapping : Flag<["-"], "dump-coverage-mapping">,
+ HelpText<"Dump the coverage mapping records, for testing">;
def fuse_register_sized_bitfield_access: Flag<["-"], "fuse-register-sized-bitfield-access">,
HelpText<"Use register sized accesses to bit-fields, when possible.">;
def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">,
@@ -270,6 +279,8 @@ def ftemplate_backtrace_limit : Separate<["-"], "ftemplate-backtrace-limit">, Me
HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">;
def fconstexpr_backtrace_limit : Separate<["-"], "fconstexpr-backtrace-limit">, MetaVarName<"<N>">,
HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">;
+def fspell_checking_limit : Separate<["-"], "fspell-checking-limit">, MetaVarName<"<N>">,
+ HelpText<"Set the maximum number of times to perform spell checking on unrecognized identifiers (0 = no limit).">;
def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">,
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
def verify : Flag<["-"], "verify">,
@@ -321,12 +332,16 @@ def ast_dump_filter : Separate<["-"], "ast-dump-filter">,
HelpText<"Use with -ast-dump or -ast-print to dump/print only AST declaration"
" nodes having a certain substring in a qualified name. Use"
" -ast-list to list all filterable declaration node names.">;
-def ast_dump_lookups : Flag<["-"], "ast-dump-lookups">,
- HelpText<"Include name lookup table dumps in AST dumps">;
def fno_modules_global_index : Flag<["-"], "fno-modules-global-index">,
HelpText<"Do not automatically generate or update the global module index">;
def fno_modules_error_recovery : Flag<["-"], "fno-modules-error-recovery">,
HelpText<"Do not automatically import modules for error recovery">;
+def fmodule_implementation_of : Separate<["-"], "fmodule-implementation-of">,
+ MetaVarName<"<name>">,
+ HelpText<"Specify the name of the module whose implementation file this is">;
+def fmodule_map_file_home_is_cwd : Flag<["-"], "fmodule-map-file-home-is-cwd">,
+ HelpText<"Use the current working directory as the home directory of "
+ "module maps specified by -fmodule-map-file=<FILE>">;
let Group = Action_Group in {
@@ -355,6 +370,8 @@ def ast_list : Flag<["-"], "ast-list">,
HelpText<"Build ASTs and print the list of declaration node qualified names">;
def ast_dump : Flag<["-"], "ast-dump">,
HelpText<"Build ASTs and then debug dump them">;
+def ast_dump_lookups : Flag<["-"], "ast-dump-lookups">,
+ HelpText<"Build ASTs and then debug dump their name lookup tables">;
def ast_view : Flag<["-"], "ast-view">,
HelpText<"Build ASTs and view them with GraphViz">;
def print_decl_contexts : Flag<["-"], "print-decl-contexts">,
@@ -497,13 +514,15 @@ def fdeprecated_macro : Flag<["-"], "fdeprecated-macro">,
def fno_deprecated_macro : Flag<["-"], "fno-deprecated-macro">,
HelpText<"Undefines the __DEPRECATED macro">;
def fsized_deallocation : Flag<["-"], "fsized-deallocation">,
- HelpText<"Enable C++1y sized global deallocation functions">;
+ HelpText<"Enable C++14 sized global deallocation functions">;
def fobjc_subscripting_legacy_runtime : Flag<["-"], "fobjc-subscripting-legacy-runtime">,
HelpText<"Allow Objective-C array and dictionary subscripting in legacy runtime">;
def vtordisp_mode_EQ : Joined<["-"], "vtordisp-mode=">,
HelpText<"Control vtordisp placement on win32 targets">;
def fno_rtti_data : Flag<["-"], "fno-rtti-data">,
HelpText<"Control emission of RTTI data">;
+def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">,
+ HelpText<"Allow function arguments and returns of type half">;
//===----------------------------------------------------------------------===//
// Header Search Options
@@ -561,6 +580,8 @@ def cl_finite_math_only : Flag<["-"], "cl-finite-math-only">,
HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">;
def cl_kernel_arg_info : Flag<["-"], "cl-kernel-arg-info">,
HelpText<"OpenCL only. Generate kernel argument metadata.">;
+def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">,
+ HelpText<"OpenCL only. Allow optimizations to ignore the signedness of the floating-point zero.">;
def cl_unsafe_math_optimizations : Flag<["-"], "cl-unsafe-math-optimizations">,
HelpText<"OpenCL only. Allow unsafe floating-point optimizations. Also implies -cl-no-signed-zeros and -cl-mad-enable">;
def cl_fast_relaxed_math : Flag<["-"], "cl-fast-relaxed-math">,
@@ -569,6 +590,8 @@ def cl_mad_enable : Flag<["-"], "cl-mad-enable">,
HelpText<"OpenCL only. Enable less precise MAD instructions to be generated.">;
def cl_std_EQ : Joined<["-"], "cl-std=">,
HelpText<"OpenCL language standard to compile for">;
+def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">,
+ HelpText<"OpenCL only. Allow denormals to be flushed to zero">;
//===----------------------------------------------------------------------===//
// CUDA Options
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
index 7278bf868355..363dd4933c10 100644
--- a/include/clang/Driver/CLCompatOptions.td
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -129,9 +129,22 @@ def _SLASH_wd4005 : CLFlag<"wd4005">, Alias<W_Joined>,
AliasArgs<["no-macro-redefined"]>;
def _SLASH_vd : CLJoined<"vd">, HelpText<"Control vtordisp placement">,
Alias<vtordisp_mode_EQ>;
+def _SLASH_Zc_strictStrings : CLFlag<"Zc:strictStrings">,
+ HelpText<"Treat string literals as const">, Alias<W_Joined>,
+ AliasArgs<["error=c++11-compat-deprecated-writable-strings"]>;
+def _SLASH_Zc_trigraphs : CLFlag<"Zc:trigraphs">,
+ HelpText<"Enable trigraphs">, Alias<ftrigraphs>;
+def _SLASH_Zc_trigraphs_off : CLFlag<"Zc:trigraphs-">,
+ HelpText<"Disable trigraphs (default)">, Alias<fno_trigraphs>;
def _SLASH_Z7 : CLFlag<"Z7">, Alias<gline_tables_only>;
def _SLASH_Zi : CLFlag<"Zi">, HelpText<"Enable debug information">,
Alias<gline_tables_only>;
+def _SLASH_Zp : CLJoined<"Zp">,
+ HelpText<"Specify the default maximum struct packing alignment">,
+ Alias<fpack_struct_EQ>;
+def _SLASH_Zp_flag : CLFlag<"Zp">,
+ HelpText<"Set the default maximum struct packing alignment to 1">,
+ Alias<fpack_struct_EQ>, AliasArgs<["1"]>;
def _SLASH_Zs : CLFlag<"Zs">, HelpText<"Syntax-check only">,
Alias<fsyntax_only>;
@@ -176,6 +189,9 @@ def _SLASH_MT : Option<["/", "-"], "MT", KIND_FLAG>, Group<_SLASH_M_Group>,
Flags<[CLOption, DriverOption]>, HelpText<"Use static run-time">;
def _SLASH_MTd : Option<["/", "-"], "MTd", KIND_FLAG>, Group<_SLASH_M_Group>,
Flags<[CLOption, DriverOption]>, HelpText<"Use static debug run-time">;
+def _SLASH_o : CLJoinedOrSeparate<"o">,
+ HelpText<"Set output file or directory (ends in / or \\)">,
+ MetaVarName<"<file or directory>">;
def _SLASH_P : CLFlag<"P">, HelpText<"Preprocess to file">;
def _SLASH_Tc : CLCompileJoinedOrSeparate<"Tc">,
HelpText<"Specify a C source file">, MetaVarName<"<filename>">;
@@ -188,8 +204,11 @@ def _SLASH_TP : CLCompileFlag<"TP">, HelpText<"Treat all source files as C++">;
// Ignored:
def _SLASH_analyze_ : CLIgnoredFlag<"analyze-">;
+def _SLASH_cgthreads : CLIgnoredJoined<"cgthreads">;
+def _SLASH_d2Zi_PLUS : CLIgnoredFlag<"d2Zi+">;
def _SLASH_errorReport : CLIgnoredJoined<"errorReport">;
def _SLASH_FS : CLIgnoredFlag<"FS">, HelpText<"Force synchronous PDB writes">;
+def _SLASH_Gd : CLIgnoredFlag<"Gd">;
def _SLASH_GF : CLIgnoredFlag<"GF">;
def _SLASH_GS_ : CLIgnoredFlag<"GS-">;
def _SLASH_kernel_ : CLIgnoredFlag<"kernel-">;
@@ -199,12 +218,16 @@ def _SLASH_Ob2 : CLIgnoredFlag<"Ob2">;
def _SLASH_RTC : CLIgnoredJoined<"RTC">;
def _SLASH_sdl : CLIgnoredFlag<"sdl">;
def _SLASH_sdl_ : CLIgnoredFlag<"sdl-">;
+def _SLASH_volatile_iso : CLIgnoredFlag<"volatile:iso">;
def _SLASH_w : CLIgnoredJoined<"w">;
+def _SLASH_Zc_auto : CLIgnoredFlag<"Zc:auto">;
def _SLASH_Zc_forScope : CLIgnoredFlag<"Zc:forScope">;
def _SLASH_Zc_inline : CLIgnoredFlag<"Zc:inline">;
def _SLASH_Zc_rvalueCast : CLIgnoredFlag<"Zc:rvalueCast">;
def _SLASH_Zc_wchar_t : CLIgnoredFlag<"Zc:wchar_t">;
def _SLASH_Zm : CLIgnoredJoined<"Zm">;
+def _SLASH_Zo : CLIgnoredFlag<"Zo">;
+def _SLASH_Zo_ : CLIgnoredFlag<"Zo-">;
// Unsupported:
@@ -212,7 +235,6 @@ def _SLASH_Zm : CLIgnoredJoined<"Zm">;
def _SLASH_AI : CLJoined<"AI">;
def _SLASH_bigobj : CLFlag<"bigobj">;
def _SLASH_clr : CLJoined<"clr">;
-def _SLASH_d2Zi_PLUS : CLFlag<"d2Zi+">;
def _SLASH_doc : CLJoined<"doc">;
def _SLASH_FA_joined : CLJoined<"FA">;
def _SLASH_favor : CLJoined<"favor">;
@@ -229,7 +251,6 @@ def _SLASH_Fx : CLFlag<"Fx">;
def _SLASH_G1 : CLFlag<"G1">;
def _SLASH_G2 : CLFlag<"G2">;
def _SLASH_GA : CLFlag<"GA">;
-def _SLASH_Gd : CLFlag<"Gd">;
def _SLASH_Ge : CLFlag<"Ge">;
def _SLASH_Gh : CLFlag<"Gh">;
def _SLASH_GH : CLFlag<"GH">;
@@ -242,6 +263,7 @@ def _SLASH_GS : CLFlag<"GS">;
def _SLASH_Gs : CLJoined<"Gs">;
def _SLASH_GT : CLFlag<"GT">;
def _SLASH_GX : CLFlag<"GX">;
+def _SLASH_Gv : CLFlag<"Gv">;
def _SLASH_Gz : CLFlag<"Gz">;
def _SLASH_GZ : CLFlag<"GZ">;
def _SLASH_H : CLFlag<"H">;
@@ -250,7 +272,6 @@ def _SLASH_hotpatch : CLFlag<"hotpatch">;
def _SLASH_kernel : CLFlag<"kernel">;
def _SLASH_LN : CLFlag<"LN">;
def _SLASH_MP : CLJoined<"MP">;
-def _SLASH_o : CLJoinedOrSeparate<"o">;
def _SLASH_openmp : CLFlag<"openmp">;
def _SLASH_Qfast_transcendentals : CLFlag<"Qfast_transcendentals">;
def _SLASH_QIfist : CLFlag<"QIfist">;
@@ -259,7 +280,7 @@ def _SLASH_Qpar : CLFlag<"Qpar">;
def _SLASH_Qvec_report : CLJoined<"Qvec-report">;
def _SLASH_u : CLFlag<"u">;
def _SLASH_V : CLFlag<"V">;
-def _SLASH_volatile : CLFlag<"volatile">;
+def _SLASH_volatile_ms : CLFlag<"volatile:ms">;
def _SLASH_WL : CLFlag<"WL">;
def _SLASH_Wp64 : CLFlag<"Wp64">;
def _SLASH_X : CLFlag<"X">;
@@ -274,5 +295,4 @@ def _SLASH_Ze : CLFlag<"Ze">;
def _SLASH_Zg : CLFlag<"Zg">;
def _SLASH_ZI : CLFlag<"ZI">;
def _SLASH_Zl : CLFlag<"Zl">;
-def _SLASH_Zp : CLJoined<"Zp">;
def _SLASH_ZW : CLJoined<"ZW">;
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
index c1c0f4326d76..5574e2ca0533 100644
--- a/include/clang/Driver/Compilation.h
+++ b/include/clang/Driver/Compilation.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_DRIVER_COMPILATION_H_
-#define CLANG_DRIVER_COMPILATION_H_
+#ifndef LLVM_CLANG_DRIVER_COMPILATION_H
+#define LLVM_CLANG_DRIVER_COMPILATION_H
#include "clang/Driver/Job.h"
#include "clang/Driver/Util.h"
@@ -94,7 +94,7 @@ public:
JobList &getJobs() { return Jobs; }
const JobList &getJobs() const { return Jobs; }
- void addCommand(Command *C) { Jobs.addJob(C); }
+ void addCommand(std::unique_ptr<Command> C) { Jobs.addJob(std::move(C)); }
const llvm::opt::ArgStringList &getTempFiles() const { return TempFiles; }
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index df974ad1d760..67d67c3074d7 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_DRIVER_DRIVER_H_
-#define CLANG_DRIVER_DRIVER_H_
+#ifndef LLVM_CLANG_DRIVER_DRIVER_H
+#define LLVM_CLANG_DRIVER_DRIVER_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
@@ -42,6 +42,7 @@ namespace driver {
class Command;
class Compilation;
class InputInfo;
+ class Job;
class JobAction;
class SanitizerArgs;
class ToolChain;
@@ -103,9 +104,6 @@ public:
/// Default target triple.
std::string DefaultTargetTriple;
- /// Default name for linked images (e.g., "a.out").
- std::string DefaultImageName;
-
/// Driver title to use with help.
std::string DriverTitle;
@@ -190,6 +188,12 @@ private:
phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL,
llvm::opt::Arg **FinalPhaseArg = nullptr) const;
+ // Before executing jobs, sets up response files for commands that need them.
+ void setUpResponseFiles(Compilation &C, Job &J);
+
+ void generatePrefixedToolNames(const char *Tool, const ToolChain &TC,
+ SmallVectorImpl<std::string> &Names) const;
+
public:
Driver(StringRef _ClangExecutable,
StringRef _DefaultTargetTriple,
@@ -291,16 +295,16 @@ public:
/// arguments and return an appropriate exit code.
///
/// This routine handles additional processing that must be done in addition
- /// to just running the subprocesses, for example reporting errors, removing
- /// temporary files, etc.
- int ExecuteCompilation(const Compilation &C,
- SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) const;
+ /// to just running the subprocesses, for example reporting errors, setting
+ /// up response files, removing temporary files, etc.
+ int ExecuteCompilation(Compilation &C,
+ SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands);
/// generateCompilationDiagnostics - Generate diagnostics information
/// including preprocessed source file(s).
///
void generateCompilationDiagnostics(Compilation &C,
- const Command *FailingCommand);
+ const Command &FailingCommand);
/// @}
/// @name Helper Methods
@@ -343,8 +347,9 @@ public:
/// ConstructAction - Construct the appropriate action to do for
/// \p Phase on the \p Input, taking in to account arguments
/// like -fsyntax-only or --analyze.
- Action *ConstructPhaseAction(const llvm::opt::ArgList &Args, phases::ID Phase,
- Action *Input) const;
+ std::unique_ptr<Action>
+ ConstructPhaseAction(const llvm::opt::ArgList &Args, phases::ID Phase,
+ std::unique_ptr<Action> Input) const;
/// BuildJobsForAction - Construct the jobs to perform for the
/// action \p A.
@@ -357,6 +362,9 @@ public:
const char *LinkingOutput,
InputInfo &Result) const;
+ /// Returns the default name for linked images (e.g., "a.out").
+ const char *getDefaultImageName() const;
+
/// GetNamedOutputPath - Return the name to use for the output of
/// the action \p JA. The result is appended to the compilation's
/// list of temporary or result files, as appropriate.
diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h
index f3c33aeccb42..680338a2ea7a 100644
--- a/include/clang/Driver/DriverDiagnostic.h
+++ b/include/clang/Driver/DriverDiagnostic.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_DRIVERDIAGNOSTIC_H
-#define LLVM_CLANG_DRIVERDIAGNOSTIC_H
+#ifndef LLVM_CLANG_DRIVER_DRIVERDIAGNOSTIC_H
+#define LLVM_CLANG_DRIVER_DRIVERDIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index 5b19efeddeea..b510676c09a7 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -7,11 +7,12 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_DRIVER_JOB_H_
-#define CLANG_DRIVER_JOB_H_
+#ifndef LLVM_CLANG_DRIVER_JOB_H
+#define LLVM_CLANG_DRIVER_JOB_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/iterator.h"
#include "llvm/Option/Option.h"
#include <memory>
@@ -28,6 +29,14 @@ class Tool;
// Re-export this as clang::driver::ArgStringList.
using llvm::opt::ArgStringList;
+struct CrashReportInfo {
+ StringRef Filename;
+ StringRef VFSPath;
+
+ CrashReportInfo(StringRef Filename, StringRef VFSPath)
+ : Filename(Filename), VFSPath(VFSPath) {}
+};
+
class Job {
public:
enum JobClass {
@@ -51,9 +60,9 @@ public:
/// \param OS - The stream to print on.
/// \param Terminator - A string to print at the end of the line.
/// \param Quote - Should separate arguments be quoted.
- /// \param CrashReport - Whether to print for inclusion in a crash report.
- virtual void Print(llvm::raw_ostream &OS, const char *Terminator,
- bool Quote, bool CrashReport = false) const = 0;
+ /// \param CrashInfo - Details for inclusion in a crash report.
+ virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
+ CrashReportInfo *CrashInfo = nullptr) const = 0;
};
/// Command - An executable path/name and argument vector to
@@ -72,12 +81,36 @@ class Command : public Job {
/// argument, which will be the executable).
llvm::opt::ArgStringList Arguments;
+ /// Response file name, if this command is set to use one, or nullptr
+ /// otherwise
+ const char *ResponseFile;
+
+ /// The input file list in case we need to emit a file list instead of a
+ /// proper response file
+ llvm::opt::ArgStringList InputFileList;
+
+ /// String storage if we need to create a new argument to specify a response
+ /// file
+ std::string ResponseFileFlag;
+
+ /// When a response file is needed, we try to put most arguments in an
+ /// exclusive file, while others remains as regular command line arguments.
+ /// This functions fills a vector with the regular command line arguments,
+ /// argv, excluding the ones passed in a response file.
+ void buildArgvForResponseFile(llvm::SmallVectorImpl<const char *> &Out) const;
+
+ /// Encodes an array of C strings into a single string separated by whitespace.
+ /// This function will also put in quotes arguments that have whitespaces and
+ /// will escape the regular backslashes (used in Windows paths) and quotes.
+ /// The results are the contents of a response file, written into a raw_ostream.
+ void writeResponseFile(raw_ostream &OS) const;
+
public:
Command(const Action &_Source, const Tool &_Creator, const char *_Executable,
const llvm::opt::ArgStringList &_Arguments);
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
- bool CrashReport = false) const override;
+ CrashReportInfo *CrashInfo = nullptr) const override;
virtual int Execute(const StringRef **Redirects, std::string *ErrMsg,
bool *ExecutionFailed) const;
@@ -88,6 +121,15 @@ public:
/// getCreator - Return the Tool which caused the creation of this job.
const Tool &getCreator() const { return Creator; }
+ /// Set to pass arguments via a response file when launching the command
+ void setResponseFile(const char *FileName);
+
+ /// Set an input file list, necessary if we need to use a response file but
+ /// the tool being called only supports input files lists.
+ void setInputFileList(llvm::opt::ArgStringList List) {
+ InputFileList = std::move(List);
+ }
+
const char *getExecutable() const { return Executable; }
const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
@@ -104,10 +146,10 @@ class FallbackCommand : public Command {
public:
FallbackCommand(const Action &Source_, const Tool &Creator_,
const char *Executable_, const ArgStringList &Arguments_,
- Command *Fallback_);
+ std::unique_ptr<Command> Fallback_);
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
- bool CrashReport = false) const override;
+ CrashReportInfo *CrashInfo = nullptr) const override;
int Execute(const StringRef **Redirects, std::string *ErrMsg,
bool *ExecutionFailed) const override;
@@ -123,23 +165,23 @@ private:
/// JobList - A sequence of jobs to perform.
class JobList : public Job {
public:
- typedef SmallVector<Job*, 4> list_type;
+ typedef SmallVector<std::unique_ptr<Job>, 4> list_type;
typedef list_type::size_type size_type;
- typedef list_type::iterator iterator;
- typedef list_type::const_iterator const_iterator;
+ typedef llvm::pointee_iterator<list_type::iterator> iterator;
+ typedef llvm::pointee_iterator<list_type::const_iterator> const_iterator;
private:
list_type Jobs;
public:
JobList();
- virtual ~JobList();
+ virtual ~JobList() {}
void Print(llvm::raw_ostream &OS, const char *Terminator,
- bool Quote, bool CrashReport = false) const override;
+ bool Quote, CrashReportInfo *CrashInfo = nullptr) const override;
/// Add a job to the list (taking ownership).
- void addJob(Job *J) { Jobs.push_back(J); }
+ void addJob(std::unique_ptr<Job> J) { Jobs.push_back(std::move(J)); }
/// Clear the job list.
void clear();
diff --git a/include/clang/Driver/Multilib.h b/include/clang/Driver/Multilib.h
index 6c3738a9cc03..dcf609ab99c6 100644
--- a/include/clang/Driver/Multilib.h
+++ b/include/clang/Driver/Multilib.h
@@ -7,12 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_LIB_DRIVER_MULTILIB_H_
-#define CLANG_LIB_DRIVER_MULTILIB_H_
+#ifndef LLVM_CLANG_DRIVER_MULTILIB_H
+#define LLVM_CLANG_DRIVER_MULTILIB_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Option.h"
+#include <functional>
#include <string>
#include <vector>
@@ -97,6 +98,10 @@ public:
typedef multilib_list::iterator iterator;
typedef multilib_list::const_iterator const_iterator;
+ typedef std::function<std::vector<std::string>(
+ StringRef InstallDir, StringRef Triple, const Multilib &M)>
+ IncludeDirsFunc;
+
struct FilterCallback {
virtual ~FilterCallback() {};
/// \return true iff the filter should remove the Multilib from the set
@@ -105,6 +110,7 @@ public:
private:
multilib_list Multilibs;
+ IncludeDirsFunc IncludeCallback;
public:
MultilibSet() {}
@@ -150,6 +156,12 @@ public:
void print(raw_ostream &OS) const;
+ MultilibSet &setIncludeDirsCallback(IncludeDirsFunc F) {
+ IncludeCallback = F;
+ return *this;
+ }
+ IncludeDirsFunc includeDirsCallback() const { return IncludeCallback; }
+
private:
/// Apply the filter to Multilibs and return the subset that remains
static multilib_list filterCopy(const FilterCallback &F,
diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h
index cee705deac63..2716fa9ae85e 100644
--- a/include/clang/Driver/Options.h
+++ b/include/clang/Driver/Options.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_DRIVER_OPTIONS_H
-#define CLANG_DRIVER_OPTIONS_H
+#ifndef LLVM_CLANG_DRIVER_OPTIONS_H
+#define LLVM_CLANG_DRIVER_OPTIONS_H
namespace llvm {
namespace opt {
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 9d4fdad46ade..4daddba332d7 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -80,6 +80,7 @@ def m_hexagon_Features_Group : OptionGroup<"<m hexagon features group>">, Group
def m_arm_Features_Group : OptionGroup<"<m arm features group>">, Group<m_Group>;
def m_aarch64_Features_Group : OptionGroup<"<m aarch64 features group>">, Group<m_Group>;
def m_ppc_Features_Group : OptionGroup<"<m ppc features group>">, Group<m_Group>;
+def m_libc_Group : OptionGroup<"<m libc group>">, Group<m_Group>;
def u_Group : OptionGroup<"<u group>">;
def pedantic_Group : OptionGroup<"<pedantic group>">,
@@ -180,6 +181,8 @@ def objcmt_migrate_readonly_property : Flag<["-"], "objcmt-migrate-readonly-prop
HelpText<"Enable migration to modern ObjC readonly property">;
def objcmt_migrate_readwrite_property : Flag<["-"], "objcmt-migrate-readwrite-property">, Flags<[CC1Option]>,
HelpText<"Enable migration to modern ObjC readwrite property">;
+def objcmt_migrate_property_dot_syntax : Flag<["-"], "objcmt-migrate-property-dot-syntax">, Flags<[CC1Option]>,
+ HelpText<"Enable migration of setter/getter messages to property-dot syntax">;
def objcmt_migrate_annotation : Flag<["-"], "objcmt-migrate-annotation">, Flags<[CC1Option]>,
HelpText<"Enable migration to property and method annotations">;
def objcmt_migrate_instancetype : Flag<["-"], "objcmt-migrate-instancetype">, Flags<[CC1Option]>,
@@ -413,6 +416,9 @@ def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>;
def fprofile_instr_use_EQ : Joined<["-"], "fprofile-instr-use=">,
Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use instrumentation data for profile-guided optimization">;
+def fcoverage_mapping : Flag<["-"], "fcoverage-mapping">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Generate coverage mapping to enable code coverage analysis">;
def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable the 'blocks' language feature">;
@@ -480,6 +486,8 @@ def fencoding_EQ : Joined<["-"], "fencoding=">, Group<f_Group>;
def ferror_limit_EQ : Joined<["-"], "ferror-limit=">, Group<f_Group>, Flags<[CoreOption]>;
def fexceptions : Flag<["-"], "fexceptions">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable support for exception handling">;
+def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">,
+ Group<clang_ignored_gcc_optimization_f_Group>;
def : Flag<["-"], "fexpensive-optimizations">, Group<clang_ignored_gcc_optimization_f_Group>;
def : Flag<["-"], "fno-expensive-optimizations">, Group<clang_ignored_gcc_optimization_f_Group>;
def fextdirs_EQ : Joined<["-"], "fextdirs=">, Group<f_Group>;
@@ -501,9 +509,8 @@ def fsignaling_math : Flag<["-"], "fsignaling-math">, Group<f_Group>;
def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>;
def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
Flags<[CC1Option, CoreOption]>, MetaVarName<"<check>">,
- HelpText<"Enable runtime instrumentation for bug detection: "
- "address (memory errors) | thread (race detection) | "
- "undefined (miscellaneous undefined behavior)">;
+ HelpText<"Turn on runtime checks for various forms of undefined "
+ "or suspicious behavior. See user manual for available checks ">;
def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>;
def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">,
Group<f_clang_Group>, Flags<[CC1Option, CoreOption]>,
@@ -511,6 +518,9 @@ def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">,
def fno_sanitize_blacklist : Flag<["-"], "fno-sanitize-blacklist">,
Group<f_clang_Group>,
HelpText<"Don't use blacklist file for sanitizers">;
+def fsanitize_coverage : Joined<["-"], "fsanitize-coverage=">,
+ Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable coverage instrumentation for Sanitizers">;
def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">,
Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Enable origins tracking in MemorySanitizer">;
@@ -520,15 +530,26 @@ def fsanitize_memory_track_origins : Flag<["-"], "fsanitize-memory-track-origins
def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-origins">,
Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Disable origins tracking in MemorySanitizer">;
-def fsanitize_recover : Flag<["-"], "fsanitize-recover">,
- Group<f_clang_Group>;
+def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">,
+ Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Level of field padding for AddressSanitizer">;
+def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>;
def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
- HelpText<"Disable sanitizer check recovery">;
+ Group<f_clang_Group>;
+def fsanitize_recover_EQ : CommaJoined<["-"], "fsanitize-recover=">,
+ Group<f_clang_Group>,
+ Flags<[CC1Option]>,
+ HelpText<"Enable recovery for specified sanitizers">;
+def fno_sanitize_recover_EQ
+ : CommaJoined<["-"], "fno-sanitize-recover=">,
+ Group<f_clang_Group>,
+ HelpText<"Disable recovery for specified sanitizers">;
def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">,
Group<f_clang_Group>, Flags<[CC1Option]>;
def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">,
Group<f_clang_Group>;
+def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">,
+ Group<f_clang_Group>;
def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
Group<f_Group>;
def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">,
@@ -561,6 +582,13 @@ def frewrite_includes : Flag<["-"], "frewrite-includes">, Group<f_Group>,
Flags<[CC1Option]>;
def fno_rewrite_includes : Flag<["-"], "fno-rewrite-includes">, Group<f_Group>;
+def frewrite_map_file : Separate<["-"], "frewrite-map-file">,
+ Group<f_Group>,
+ Flags<[ DriverOption, CC1Option ]>;
+def frewrite_map_file_EQ : Joined<["-"], "frewrite-map-file=">,
+ Group<f_Group>,
+ Flags<[DriverOption]>;
+
def ffreestanding : Flag<["-"], "ffreestanding">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Assert that the compilation takes place in a freestanding environment">;
def fgnu_keywords : Flag<["-"], "fgnu-keywords">, Group<f_Group>, Flags<[CC1Option]>,
@@ -576,11 +604,13 @@ def : Flag<["-"], "findirect-virtual-calls">, Alias<fapple_kext>;
def finline_functions : Flag<["-"], "finline-functions">, Group<clang_ignored_gcc_optimization_f_Group>;
def finline : Flag<["-"], "finline">, Group<clang_ignored_f_Group>;
def finput_charset_EQ : Joined<["-"], "finput-charset=">, Group<f_Group>;
+def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group<f_Group>;
def finstrument_functions : Flag<["-"], "finstrument-functions">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Generate calls to instrument function entry and exit">;
def flat__namespace : Flag<["-"], "flat_namespace">;
def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
+def flto_EQ : Joined<["-"], "flto=">, Group<clang_ignored_gcc_optimization_f_Group>;
def flto : Flag<["-"], "flto">, Group<f_Group>;
def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>;
def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">,
@@ -622,10 +652,13 @@ def fmodules_search_all : Flag <["-"], "fmodules-search-all">, Group<f_Group>,
def fbuild_session_timestamp : Joined<["-"], "fbuild-session-timestamp=">,
Group<i_Group>, Flags<[CC1Option]>, MetaVarName<"<time since Epoch in seconds>">,
HelpText<"Time when the current build session started">;
+def fbuild_session_file : Joined<["-"], "fbuild-session-file=">,
+ Group<i_Group>, MetaVarName<"<file>">,
+ HelpText<"Use the last modification time of <file> as the build session timestamp">;
def fmodules_validate_once_per_build_session : Flag<["-"], "fmodules-validate-once-per-build-session">,
Group<i_Group>, Flags<[CC1Option]>,
HelpText<"Don't verify input files for the modules if the module has been "
- "successfully validate or loaded during this build session">;
+ "successfully validated or loaded during this build session">;
def fmodules_validate_system_headers : Flag<["-"], "fmodules-validate-system-headers">,
Group<i_Group>, Flags<[CC1Option]>,
HelpText<"Validate the system headers that a module depends on when loading the module">;
@@ -638,9 +671,12 @@ def fmodule_maps : Flag <["-"], "fmodule-maps">, Group<f_Group>,
def fmodule_name : JoinedOrSeparate<["-"], "fmodule-name=">, Group<f_Group>,
Flags<[DriverOption,CC1Option]>, MetaVarName<"<name>">,
HelpText<"Specify the name of the module to build">;
-def fmodule_map_file : JoinedOrSeparate<["-"], "fmodule-map-file=">,
+def fmodule_map_file : Joined<["-"], "fmodule-map-file=">,
Group<f_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"<file>">,
HelpText<"Load this module map file">;
+def fmodule_file : Joined<["-"], "fmodule-file=">,
+ Group<f_Group>, Flags<[DriverOption,CC1Option]>,
+ HelpText<"Load this precompiled module file">, MetaVarName<"<file>">;
def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Ignore the definition of the given macro when building and loading modules">;
def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>,
@@ -651,6 +687,12 @@ def fmodules_strict_decluse : Flag <["-"], "fmodules-strict-decluse">, Group<f_G
HelpText<"Like -fmodules-decluse but requires all headers to be in modules">;
def fno_modules_search_all : Flag <["-"], "fno-modules-search-all">, Group<f_Group>,
Flags<[DriverOption, CC1Option]>;
+def fmodules_implicit_maps :
+ Flag <["-"], "fmodules-implicit-maps">,
+ Group<f_Group>, Flags<[DriverOption, CC1Option]>;
+def fno_modules_implicit_maps :
+ Flag <["-"], "fno-modules-implicit-maps">,
+ Group<f_Group>, Flags<[DriverOption, CC1Option]>;
def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>;
def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>;
@@ -793,11 +835,15 @@ def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Gr
def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;
def force__flat__namespace : Flag<["-"], "force_flat_namespace">;
def force__load : Separate<["-"], "force_load">;
+def force_addr : Joined<["-"], "fforce-addr">, Group<clang_ignored_f_Group>;
def foutput_class_dir_EQ : Joined<["-"], "foutput-class-dir=">, Group<f_Group>;
def fpack_struct : Flag<["-"], "fpack-struct">, Group<f_Group>;
def fno_pack_struct : Flag<["-"], "fno-pack-struct">, Group<f_Group>;
def fpack_struct_EQ : Joined<["-"], "fpack-struct=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Specify the default maximum struct packing alignment">;
+def fmax_type_align_EQ : Joined<["-"], "fmax-type-align=">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Specify the maximum alignment to enforce on pointers lacking an explicit alignment">;
+def fno_max_type_align : Flag<["-"], "fno-max-type-align">, Group<f_Group>;
def fpascal_strings : Flag<["-"], "fpascal-strings">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Recognize and construct Pascal-style string literals">;
def fpcc_struct_return : Flag<["-"], "fpcc-struct-return">, Group<f_Group>, Flags<[CC1Option]>,
@@ -808,6 +854,7 @@ def fno_pic : Flag<["-"], "fno-pic">, Group<f_Group>;
def fpie : Flag<["-"], "fpie">, Group<f_Group>;
def fno_pie : Flag<["-"], "fno-pie">, Group<f_Group>;
def fprofile_arcs : Flag<["-"], "fprofile-arcs">, Group<f_Group>;
+def fno_profile_arcs : Flag<["-"], "fno-profile-arcs">, Group<f_Group>;
def fprofile_generate : Flag<["-"], "fprofile-generate">, Group<f_Group>;
def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>;
def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, Group<clang_ignored_f_Group>;
@@ -817,7 +864,6 @@ def frtti : Flag<["-"], "frtti">, Group<f_Group>;
def : Flag<["-"], "fsched-interblock">, Group<clang_ignored_f_Group>;
def fshort_enums : Flag<["-"], "fshort-enums">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">;
-def : Flag<["-"], "freorder-blocks">, Group<clang_ignored_gcc_optimization_f_Group>;
def fshort_wchar : Flag<["-"], "fshort-wchar">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Force wchar_t to be a short unsigned int">;
def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>, Flags<[CC1Option]>,
@@ -828,6 +874,7 @@ def fshow_overloads_EQ : Joined<["-"], "fshow-overloads=">, Group<f_Group>, Flag
def fshow_column : Flag<["-"], "fshow-column">, Group<f_Group>, Flags<[CC1Option]>;
def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>;
def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>;
+def fspell_checking_limit_EQ : Joined<["-"], "fspell-checking-limit=">, Group<f_Group>;
def fsigned_bitfields : Flag<["-"], "fsigned-bitfields">, Group<f_Group>;
def fsigned_char : Flag<["-"], "fsigned-char">, Group<f_Group>;
def fno_signed_char : Flag<["-"], "fno-signed-char">, Flags<[CC1Option]>,
@@ -905,6 +952,10 @@ def freroll_loops : Flag<["-"], "freroll-loops">, Group<f_Group>,
HelpText<"Turn on loop reroller">, Flags<[CC1Option]>;
def fno_reroll_loops : Flag<["-"], "fno-reroll-loops">, Group<f_Group>,
HelpText<"Turn off loop reroller">;
+def ftrigraphs : Flag<["-"], "ftrigraphs">, Group<f_Group>,
+ HelpText<"Process trigraph sequences">, Flags<[CC1Option]>;
+def fno_trigraphs : Flag<["-"], "fno-trigraphs">, Group<f_Group>,
+ HelpText<"Do not process trigraph sequences">, Flags<[CC1Option]>;
def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>;
def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>;
def fno_unsigned_char : Flag<["-"], "fno-unsigned-char">, Group<clang_ignored_f_Group>;
@@ -912,8 +963,7 @@ def funwind_tables : Flag<["-"], "funwind-tables">, Group<f_Group>;
def fuse_cxa_atexit : Flag<["-"], "fuse-cxa-atexit">, Group<f_Group>;
def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use .init_array instead of .ctors">;
-def fno_var_tracking : Flag<["-"], "fno-var-tracking">,
- Group<clang_ignored_f_Group>;
+def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group<clang_ignored_f_Group>;
def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>;
def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>,
HelpText<"Set the default symbol visibility for all global declarations">;
@@ -1037,6 +1087,10 @@ def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>;
def m64 : Flag<["-"], "m64">, Group<m_Group>, Flags<[DriverOption, CoreOption]>;
def mx32 : Flag<["-"], "mx32">, Group<m_Group>, Flags<[DriverOption, CoreOption]>;
def mabi_EQ : Joined<["-"], "mabi=">, Group<m_Group>;
+def malign_functions_EQ : Joined<["-"], "malign-functions=">, Group<clang_ignored_m_Group>;
+def malign_loops_EQ : Joined<["-"], "malign-loops=">, Group<clang_ignored_m_Group>;
+def malign_jumps_EQ : Joined<["-"], "malign-jumps=">, Group<clang_ignored_m_Group>;
+def mfancy_math_387 : Flag<["-"], "mfancy-math-387">, Group<clang_ignored_m_Group>;
def march_EQ : Joined<["-"], "march=">, Group<m_Group>;
def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Flags<[DriverOption]>;
def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>;
@@ -1054,20 +1108,25 @@ def mhwdiv_EQ : Joined<["-"], "mhwdiv=">, Group<m_Group>;
def mglobal_merge : Flag<["-"], "mglobal-merge">, Group<m_Group>;
def mhard_float : Flag<["-"], "mhard-float">, Group<m_Group>;
def miphoneos_version_min_EQ : Joined<["-"], "miphoneos-version-min=">, Group<m_Group>;
-def mios_version_min_EQ : Joined<["-"], "mios-version-min=">, Alias<miphoneos_version_min_EQ>;
-def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">, Group<m_Group>;
+def mios_version_min_EQ : Joined<["-"], "mios-version-min=">,
+ Alias<miphoneos_version_min_EQ>, HelpText<"Set iOS deployment target">;
+def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">, Alias<miphoneos_version_min_EQ>;
def mkernel : Flag<["-"], "mkernel">, Group<m_Group>;
def mlinker_version_EQ : Joined<["-"], "mlinker-version=">,
Flags<[DriverOption]>;
def mllvm : Separate<["-"], "mllvm">, Flags<[CC1Option,CC1AsOption,CoreOption]>,
HelpText<"Additional arguments to forward to LLVM's option processing">;
-def mmacosx_version_min_EQ : Joined<["-"], "mmacosx-version-min=">, Group<m_Group>;
+def mmacosx_version_min_EQ : Joined<["-"], "mmacosx-version-min=">,
+ Group<m_Group>, HelpText<"Set Mac OS X deployment target">;
def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">;
def mstackrealign : Flag<["-"], "mstackrealign">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Force realign the stack at entry to every function">;
def mstack_alignment : Joined<["-"], "mstack-alignment=">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Set the stack alignment">;
+def mthread_model : Separate<["-"], "mthread-model">, Group<m_Group>, Flags<[CC1Option]>,
+ HelpText<"The thread model to use, e.g. posix, single (posix by default)">;
+
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>;
@@ -1097,9 +1156,13 @@ def mno_avx512f : Flag<["-"], "mno-avx512f">, Group<m_x86_Features_Group>;
def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group<m_x86_Features_Group>;
def mno_avx512er : Flag<["-"], "mno-avx512er">, Group<m_x86_Features_Group>;
def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group<m_x86_Features_Group>;
+def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group<m_x86_Features_Group>;
+def mno_avx512bw : Flag<["-"], "mno-avx512bw">, Group<m_x86_Features_Group>;
+def mno_avx512vl : Flag<["-"], "mno-avx512vl">, Group<m_x86_Features_Group>;
def mno_pclmul : Flag<["-"], "mno-pclmul">, Group<m_x86_Features_Group>;
def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group<m_x86_Features_Group>;
def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>;
+def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group<m_x86_Features_Group>;
def mno_bmi : Flag<["-"], "mno-bmi">, Group<m_x86_Features_Group>;
def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group<m_x86_Features_Group>;
def mno_popcnt : Flag<["-"], "mno-popcnt">, Group<m_x86_Features_Group>;
@@ -1111,6 +1174,7 @@ def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>;
def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>;
def mno_prfchw : Flag<["-"], "mno-prfchw">, Group<m_x86_Features_Group>;
def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>;
+def mno_adx : Flag<["-"], "mno-adx">, Group<m_x86_Features_Group>;
def mno_sha : Flag<["-"], "mno-sha">, Group<m_x86_Features_Group>;
def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>,
@@ -1118,7 +1182,7 @@ def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_G
def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group<m_arm_Features_Group>,
HelpText<"Force all memory accesses to be aligned (AArch32/AArch64 only)">;
def mstrict_align : Flag<["-"], "mstrict-align">, Alias<mno_unaligned_access>, Flags<[CC1Option,HelpHidden]>,
- HelpText<"Force all memory accesses to be aligned (AArch64 only, same as mno-unaligned-access)">;
+ HelpText<"Force all memory accesses to be aligned (same as mno-unaligned-access)">;
def mno_thumb : Flag<["-"], "mno-thumb">, Group<m_arm_Features_Group>;
def mrestrict_it: Flag<["-"], "mrestrict-it">, Group<m_arm_Features_Group>,
HelpText<"Disallow generation of deprecated IT blocks for ARMv8. It is on by default for ARMv8 Thumb mode.">;
@@ -1139,10 +1203,23 @@ def mno_long_calls : Flag<["-"], "mno-long-calls">, Group<m_arm_Features_Group>,
def mgeneral_regs_only : Flag<["-"], "mgeneral-regs-only">, Group<m_aarch64_Features_Group>,
HelpText<"Generate code which only uses the general purpose registers (AArch64 only)">;
+def mfix_cortex_a53_835769 : Flag<["-"], "mfix-cortex-a53-835769">,
+ Group<m_aarch64_Features_Group>,
+ HelpText<"Workaround Cortex-A53 erratum 835769 (AArch64 only)">;
+def mno_fix_cortex_a53_835769 : Flag<["-"], "mno-fix-cortex-a53-835769">,
+ Group<m_aarch64_Features_Group>,
+ HelpText<"Don't workaround Cortex-A53 erratum 835769 (AArch64 only)">;
+
def mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>;
def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>;
+def mpower8_vector : Flag<["-"], "mpower8-vector">,
+ Group<m_ppc_Features_Group>;
+def mno_power8_vector : Flag<["-"], "mno-power8-vector">,
+ Group<m_ppc_Features_Group>;
def mfprnd : Flag<["-"], "mfprnd">, Group<m_ppc_Features_Group>;
def mno_fprnd : Flag<["-"], "mno-fprnd">, Group<m_ppc_Features_Group>;
+def mcmpb : Flag<["-"], "mcmpb">, Group<m_ppc_Features_Group>;
+def mno_cmpb : Flag<["-"], "mno-cmpb">, Group<m_ppc_Features_Group>;
def mmfcrf : Flag<["-"], "mmfcrf">, Group<m_ppc_Features_Group>;
def mno_mfcrf : Flag<["-"], "mno-mfcrf">, Group<m_ppc_Features_Group>;
def mpopcntd : Flag<["-"], "mpopcntd">, Group<m_ppc_Features_Group>;
@@ -1191,9 +1268,13 @@ def mavx512f : Flag<["-"], "mavx512f">, Group<m_x86_Features_Group>;
def mavx512cd : Flag<["-"], "mavx512cd">, Group<m_x86_Features_Group>;
def mavx512er : Flag<["-"], "mavx512er">, Group<m_x86_Features_Group>;
def mavx512pf : Flag<["-"], "mavx512pf">, Group<m_x86_Features_Group>;
+def mavx512dq : Flag<["-"], "mavx512dq">, Group<m_x86_Features_Group>;
+def mavx512bw : Flag<["-"], "mavx512bw">, Group<m_x86_Features_Group>;
+def mavx512vl : Flag<["-"], "mavx512vl">, Group<m_x86_Features_Group>;
def mpclmul : Flag<["-"], "mpclmul">, Group<m_x86_Features_Group>;
def mlzcnt : Flag<["-"], "mlzcnt">, Group<m_x86_Features_Group>;
def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>;
+def mfsgsbase : Flag<["-"], "mfsgsbase">, Group<m_x86_Features_Group>;
def mbmi : Flag<["-"], "mbmi">, Group<m_x86_Features_Group>;
def mbmi2 : Flag<["-"], "mbmi2">, Group<m_x86_Features_Group>;
def mpopcnt : Flag<["-"], "mpopcnt">, Group<m_x86_Features_Group>;
@@ -1205,6 +1286,7 @@ def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>;
def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>;
def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>;
def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>;
+def madx : Flag<["-"], "madx">, Group<m_x86_Features_Group>;
def msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>;
def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>;
def mips16 : Flag<["-"], "mips16">, Group<m_Group>;
@@ -1233,6 +1315,10 @@ def mfp64 : Flag<["-"], "mfp64">, Group<m_Group>,
def mfp32 : Flag<["-"], "mfp32">, Group<m_Group>,
HelpText<"Use 32-bit floating point registers (MIPS only)">;
def mnan_EQ : Joined<["-"], "mnan=">, Group<m_Group>;
+def mabicalls : Flag<["-"], "mabicalls">, Group<m_Group>,
+ HelpText<"Enable SVR4-style position-independent code (Mips only)">;
+def mno_abicalls : Flag<["-"], "mno-abicalls">, Group<m_Group>,
+ HelpText<"Disable SVR4-style position-independent code (Mips only)">;
def mips1 : Flag<["-"], "mips1">,
Alias<march_EQ>, AliasArgs<["mips1"]>,
HelpText<"Equivalent to -march=mips1">, Flags<[HelpHidden]>;
@@ -1275,6 +1361,8 @@ def modd_spreg : Flag<["-"], "modd-spreg">, Group<m_Group>,
def mno_odd_spreg : Flag<["-"], "mno-odd-spreg">, Group<m_Group>,
HelpText<"Disable odd single-precision floating point registers">,
Flags<[HelpHidden]>;
+def mglibc : Flag<["-"], "mglibc">, Group<m_libc_Group>, Flags<[HelpHidden]>;
+def muclibc : Flag<["-"], "muclibc">, Group<m_libc_Group>, Flags<[HelpHidden]>;
def module_file_info : Flag<["-"], "module-file-info">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>;
def mthumb : Flag<["-"], "mthumb">, Group<m_Group>;
def mtune_EQ : Joined<["-"], "mtune=">, Group<m_Group>;
@@ -1403,7 +1491,7 @@ def time : Flag<["-"], "time">,
def traditional_cpp : Flag<["-", "--"], "traditional-cpp">, Flags<[CC1Option]>,
HelpText<"Enable some traditional CPP emulation">;
def traditional : Flag<["-", "--"], "traditional">;
-def trigraphs : Flag<["-", "--"], "trigraphs">, Flags<[CC1Option]>,
+def trigraphs : Flag<["-", "--"], "trigraphs">, Alias<ftrigraphs>,
HelpText<"Process trigraph sequences">;
def twolevel__namespace__hints : Flag<["-"], "twolevel_namespace_hints">;
def twolevel__namespace : Flag<["-"], "twolevel_namespace">;
@@ -1455,7 +1543,7 @@ def _all_warnings : Flag<["--"], "all-warnings">, Alias<Wall>;
def _analyze_auto : Flag<["--"], "analyze-auto">, Flags<[DriverOption]>;
def _analyzer_no_default_checks : Flag<["--"], "analyzer-no-default-checks">, Flags<[DriverOption]>;
def _analyzer_output : JoinedOrSeparate<["--"], "analyzer-output">, Flags<[DriverOption]>;
-def _analyze : Flag<["--"], "analyze">, Flags<[DriverOption]>,
+def _analyze : Flag<["--"], "analyze">, Flags<[DriverOption, CoreOption]>,
HelpText<"Run the static analyzer">;
def _assemble : Flag<["--"], "assemble">, Alias<S>;
def _assert_EQ : Joined<["--"], "assert=">, Alias<A>;
@@ -1591,7 +1679,7 @@ multiclass BooleanFFlag<string name> {
def _fno : Flag<["-"], "fno-"#name>;
}
-defm : BooleanFFlag<"no-keep-inline-functions">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm : BooleanFFlag<"keep-inline-functions">, Group<clang_ignored_gcc_optimization_f_Group>;
def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group<clang_ignored_gcc_optimization_f_Group>;
@@ -1601,22 +1689,52 @@ def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<f_Group>;
defm align_functions : BooleanFFlag<"align-functions">, Group<clang_ignored_gcc_optimization_f_Group>;
def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm align_labels : BooleanFFlag<"align-labels">, Group<clang_ignored_gcc_optimization_f_Group>;
+def falign_labels_EQ : Joined<["-"], "falign-labels=">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm align_loops : BooleanFFlag<"align-loops">, Group<clang_ignored_gcc_optimization_f_Group>;
+def falign_loops_EQ : Joined<["-"], "falign-loops=">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm align_jumps : BooleanFFlag<"align-jumps">, Group<clang_ignored_gcc_optimization_f_Group>;
+def falign_jumps_EQ : Joined<["-"], "falign-jumps=">, Group<clang_ignored_gcc_optimization_f_Group>;
// FIXME: This option should be supported and wired up to our diognostics, but
// ignore it for now to avoid breaking builds that use it.
def fdiagnostics_show_location_EQ : Joined<["-"], "fdiagnostics-show-location=">, Group<clang_ignored_f_Group>;
+defm fcheck_new : BooleanFFlag<"check-new">, Group<clang_ignored_f_Group>;
+defm caller_saves : BooleanFFlag<"caller-saves">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm reorder_blocks : BooleanFFlag<"reorder-blocks">, Group<clang_ignored_gcc_optimization_f_Group>;
defm eliminate_unused_debug_types : BooleanFFlag<"eliminate-unused-debug-types">, Group<clang_ignored_f_Group>;
+defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm default_inline : BooleanFFlag<"default-inline">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm delete_null_pointer_checks : BooleanFFlag<"delete-null-pointer-checks">,
+ Group<clang_ignored_gcc_optimization_f_Group>;
+defm fat_lto_objects : BooleanFFlag<"fat-lto-objects">, Group<clang_ignored_gcc_optimization_f_Group>;
defm float_store : BooleanFFlag<"float-store">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm friend_injection : BooleanFFlag<"friend-injection">, Group<clang_ignored_f_Group>;
defm function_attribute_list : BooleanFFlag<"function-attribute-list">, Group<clang_ignored_f_Group>;
defm gcse : BooleanFFlag<"gcse">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm gcse_after_reload: BooleanFFlag<"gcse-after-reload">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm gcse_las: BooleanFFlag<"gcse-las">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm gcse_sm: BooleanFFlag<"gcse-sm">, Group<clang_ignored_gcc_optimization_f_Group>;
defm gnu : BooleanFFlag<"gnu">, Group<clang_ignored_f_Group>;
defm ident : BooleanFFlag<"ident">, Group<clang_ignored_f_Group>;
defm implicit_templates : BooleanFFlag<"implicit-templates">, Group<clang_ignored_f_Group>;
+defm implement_inlines : BooleanFFlag<"implement-inlines">, Group<clang_ignored_f_Group>;
+defm merge_constants : BooleanFFlag<"merge-constants">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm modulo_sched : BooleanFFlag<"modulo-sched">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm modulo_sched_allow_regmoves : BooleanFFlag<"modulo-sched-allow-regmoves">,
+ Group<clang_ignored_gcc_optimization_f_Group>;
+defm inline_functions_called_once : BooleanFFlag<"inline-functions-called-once">,
+ Group<clang_ignored_gcc_optimization_f_Group>;
def finline_limit_EQ : Joined<["-"], "finline-limit=">, Group<clang_ignored_gcc_optimization_f_Group>;
defm finline_limit : BooleanFFlag<"inline-limit">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm inline_small_functions : BooleanFFlag<"inline-small-functions">,
+ Group<clang_ignored_gcc_optimization_f_Group>;
+defm ipa_cp : BooleanFFlag<"ipa-cp">,
+ Group<clang_ignored_gcc_optimization_f_Group>;
defm ivopts : BooleanFFlag<"ivopts">, Group<clang_ignored_gcc_optimization_f_Group>;
defm non_call_exceptions : BooleanFFlag<"non-call-exceptions">, Group<clang_ignored_f_Group>;
+defm peel_loops : BooleanFFlag<"peel-loops">, Group<clang_ignored_gcc_optimization_f_Group>;
defm permissive : BooleanFFlag<"permissive">, Group<clang_ignored_f_Group>;
defm prefetch_loop_arrays : BooleanFFlag<"prefetch-loop-arrays">, Group<clang_ignored_gcc_optimization_f_Group>;
defm printf : BooleanFFlag<"printf">, Group<clang_ignored_f_Group>;
@@ -1626,21 +1744,42 @@ defm profile_generate_sampling : BooleanFFlag<"profile-generate-sampling">, Grou
defm profile_reusedist : BooleanFFlag<"profile-reusedist">, Group<clang_ignored_f_Group>;
defm profile_values : BooleanFFlag<"profile-values">, Group<clang_ignored_gcc_optimization_f_Group>;
defm regs_graph : BooleanFFlag<"regs-graph">, Group<clang_ignored_f_Group>;
+defm rename_registers : BooleanFFlag<"rename-registers">, Group<clang_ignored_gcc_optimization_f_Group>;
defm ripa : BooleanFFlag<"ripa">, Group<clang_ignored_f_Group>;
defm rounding_math : BooleanFFlag<"rounding-math">, Group<clang_ignored_gcc_optimization_f_Group>;
defm schedule_insns : BooleanFFlag<"schedule-insns">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm schedule_insns2 : BooleanFFlag<"schedule-insns2">, Group<clang_ignored_gcc_optimization_f_Group>;
defm see : BooleanFFlag<"see">, Group<clang_ignored_f_Group>;
defm signaling_nans : BooleanFFlag<"signaling-nans">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm single_precision_constant : BooleanFFlag<"single-precision-constant">,
+ Group<clang_ignored_gcc_optimization_f_Group>;
defm spec_constr_count : BooleanFFlag<"spec-constr-count">, Group<clang_ignored_f_Group>;
+defm stack_check : BooleanFFlag<"stack-check">, Group<clang_ignored_f_Group>;
defm strength_reduce :
BooleanFFlag<"strength-reduce">, Group<clang_ignored_gcc_optimization_f_Group>;
defm tls_model : BooleanFFlag<"tls-model">, Group<clang_ignored_f_Group>;
defm tracer : BooleanFFlag<"tracer">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm tree_dce : BooleanFFlag<"tree-dce">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm tree_loop_im : BooleanFFlag<"tree_loop_im">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm tree_loop_ivcanon : BooleanFFlag<"tree_loop_ivcanon">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm tree_loop_linear : BooleanFFlag<"tree_loop_linear">, Group<clang_ignored_gcc_optimization_f_Group>;
defm tree_salias : BooleanFFlag<"tree-salias">, Group<clang_ignored_f_Group>;
+defm tree_ter : BooleanFFlag<"tree-ter">, Group<clang_ignored_gcc_optimization_f_Group>;
defm tree_vectorizer_verbose : BooleanFFlag<"tree-vectorizer-verbose">, Group<clang_ignored_f_Group>;
+defm tree_vrp : BooleanFFlag<"tree-vrp">, Group<clang_ignored_gcc_optimization_f_Group>;
defm unroll_all_loops : BooleanFFlag<"unroll-all-loops">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm unsafe_loop_optimizations : BooleanFFlag<"unsafe-loop-optimizations">,
+ Group<clang_ignored_gcc_optimization_f_Group>;
defm unswitch_loops : BooleanFFlag<"unswitch-loops">, Group<clang_ignored_gcc_optimization_f_Group>;
-
+defm use_linker_plugin : BooleanFFlag<"use-linker-plugin">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm vect_cost_model : BooleanFFlag<"vect-cost-model">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm variable_expansion_in_unroller : BooleanFFlag<"variable-expansion-in-unroller">,
+ Group<clang_ignored_gcc_optimization_f_Group>;
+defm web : BooleanFFlag<"web">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm whole_program : BooleanFFlag<"whole-program">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm devirtualize : BooleanFFlag<"devirtualize">, Group<clang_ignored_gcc_optimization_f_Group>;
+defm devirtualize_speculatively : BooleanFFlag<"devirtualize-speculatively">,
+ Group<clang_ignored_gcc_optimization_f_Group>;
// gfortran options that we recognize in the driver and pass along when
// invoking GCC to compile Fortran code.
diff --git a/include/clang/Driver/Phases.h b/include/clang/Driver/Phases.h
index 4e0f40c17dff..cd6b5b5c9f05 100644
--- a/include/clang/Driver/Phases.h
+++ b/include/clang/Driver/Phases.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_DRIVER_PHASES_H_
-#define CLANG_DRIVER_PHASES_H_
+#ifndef LLVM_CLANG_DRIVER_PHASES_H
+#define LLVM_CLANG_DRIVER_PHASES_H
namespace clang {
namespace driver {
@@ -19,6 +19,7 @@ namespace phases {
Preprocess,
Precompile,
Compile,
+ Backend,
Assemble,
Link
};
diff --git a/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h
index c79c4714f4f9..3524da0e7ffe 100644
--- a/include/clang/Driver/SanitizerArgs.h
+++ b/include/clang/Driver/SanitizerArgs.h
@@ -6,9 +6,10 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_
-#define CLANG_LIB_DRIVER_SANITIZERARGS_H_
+#ifndef LLVM_CLANG_DRIVER_SANITIZERARGS_H
+#define LLVM_CLANG_DRIVER_SANITIZERARGS_H
+#include "clang/Basic/Sanitizers.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include <string>
@@ -20,131 +21,46 @@ class Driver;
class ToolChain;
class SanitizerArgs {
- /// Assign ordinals to sanitizer flags. We'll use the ordinal values as
- /// bit positions within \c Kind.
- enum SanitizeOrdinal {
-#define SANITIZER(NAME, ID) SO_##ID,
-#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
-#include "clang/Basic/Sanitizers.def"
- SO_Count
- };
-
- /// Bugs to catch at runtime.
- enum SanitizeKind {
-#define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
-#define SANITIZER_GROUP(NAME, ID, ALIAS) \
- ID = ALIAS, ID##Group = 1 << SO_##ID##Group,
-#include "clang/Basic/Sanitizers.def"
- NeedsAsanRt = Address,
- NeedsTsanRt = Thread,
- NeedsMsanRt = Memory,
- NeedsDfsanRt = DataFlow,
- NeedsLeakDetection = Leak,
- NeedsUbsanRt = Undefined | Integer,
- NotAllowedWithTrap = Vptr,
- HasZeroBaseShadow = Thread | Memory | DataFlow,
- NeedsUnwindTables = Address | Thread | Memory | DataFlow
- };
- unsigned Kind;
+ SanitizerSet Sanitizers;
+ SanitizerSet RecoverableSanitizers;
std::string BlacklistFile;
+ int SanitizeCoverage;
int MsanTrackOrigins;
+ int AsanFieldPadding;
bool AsanZeroBaseShadow;
bool UbsanTrapOnError;
bool AsanSharedRuntime;
+ bool LinkCXXRuntimes;
public:
- SanitizerArgs();
/// Parses the sanitizer arguments from an argument list.
SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args);
- bool needsAsanRt() const { return Kind & NeedsAsanRt; }
+ bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); }
bool needsSharedAsanRt() const { return AsanSharedRuntime; }
- bool needsTsanRt() const { return Kind & NeedsTsanRt; }
- bool needsMsanRt() const { return Kind & NeedsMsanRt; }
- bool needsLeakDetection() const { return Kind & NeedsLeakDetection; }
+ bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
+ bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
bool needsLsanRt() const {
- return needsLeakDetection() && !needsAsanRt();
- }
- bool needsUbsanRt() const {
- return !UbsanTrapOnError && (Kind & NeedsUbsanRt);
+ return Sanitizers.has(SanitizerKind::Leak) &&
+ !Sanitizers.has(SanitizerKind::Address);
}
- bool needsDfsanRt() const { return Kind & NeedsDfsanRt; }
+ bool needsUbsanRt() const;
+ bool needsDfsanRt() const { return Sanitizers.has(SanitizerKind::DataFlow); }
- bool sanitizesVptr() const { return Kind & Vptr; }
- bool notAllowedWithTrap() const { return Kind & NotAllowedWithTrap; }
- bool hasZeroBaseShadow() const {
- return (Kind & HasZeroBaseShadow) || AsanZeroBaseShadow;
- }
- bool needsUnwindTables() const { return Kind & NeedsUnwindTables; }
+ bool sanitizesVptr() const { return Sanitizers.has(SanitizerKind::Vptr); }
+ bool requiresPIE() const;
+ bool needsUnwindTables() const;
+ bool linkCXXRuntimes() const { return LinkCXXRuntimes; }
void addArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
private:
void clear();
-
- /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
- /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0
- /// if \p Value is not known.
- static unsigned parse(const char *Value);
-
- /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
- /// invalid components.
- static unsigned parse(const Driver &D, const llvm::opt::Arg *A,
- bool DiagnoseErrors);
-
- /// Parse a single flag of the form -f[no]sanitize=, or
- /// -f*-sanitizer. Sets the masks defining required change of Kind value.
- /// Returns true if the flag was parsed successfully.
- static bool parse(const Driver &D, const llvm::opt::ArgList &Args,
- const llvm::opt::Arg *A, unsigned &Add, unsigned &Remove,
- bool DiagnoseErrors);
-
- /// Produce an argument string from ArgList \p Args, which shows how it
- /// provides a sanitizer kind in \p Mask. For example, the argument list
- /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
- /// would produce "-fsanitize=vptr".
- static std::string lastArgumentForKind(const Driver &D,
- const llvm::opt::ArgList &Args,
- unsigned Kind);
-
- /// Produce an argument string from argument \p A, which shows how it provides
- /// a value in \p Mask. For instance, the argument
- /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
- /// "-fsanitize=alignment".
- static std::string describeSanitizeArg(const llvm::opt::ArgList &Args,
- const llvm::opt::Arg *A,
- unsigned Mask);
-
- static bool getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
- std::string &BLPath);
-
- /// Return the smallest superset of sanitizer set \p Kinds such that each
- /// member of each group whose flag is set in \p Kinds has its flag set in the
- /// result.
- static unsigned expandGroups(unsigned Kinds);
-
- /// Return the subset of \p Kinds supported by toolchain \p TC. If
- /// \p DiagnoseErrors is true, produce an error diagnostic for each sanitizer
- /// removed from \p Kinds.
- static unsigned filterUnsupportedKinds(const ToolChain &TC, unsigned Kinds,
- const llvm::opt::ArgList &Args,
- const llvm::opt::Arg *A,
- bool DiagnoseErrors,
- unsigned &DiagnosedKinds);
-
- /// The flags in \p Mask are unsupported by \p TC. If present in \p Kinds,
- /// remove them and produce an error diagnostic referring to \p A if
- /// \p DiagnoseErrors is true.
- static void filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds,
- unsigned Mask,
- const llvm::opt::ArgList &Args,
- const llvm::opt::Arg *A,
- bool DiagnoseErrors,
- unsigned &DiagnosedKinds);
+ bool getDefaultBlacklist(const Driver &D, std::string &BLPath);
};
} // namespace driver
} // namespace clang
-#endif // CLANG_LIB_DRIVER_SANITIZERARGS_H_
+#endif
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index 015dcf513e0a..b9eac1cad65d 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -7,10 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_DRIVER_TOOL_H_
-#define CLANG_DRIVER_TOOL_H_
+#ifndef LLVM_CLANG_DRIVER_TOOL_H
+#define LLVM_CLANG_DRIVER_TOOL_H
#include "clang/Basic/LLVM.h"
+#include "llvm/Support/Program.h"
namespace llvm {
namespace opt {
@@ -31,6 +32,24 @@ namespace driver {
/// Tool - Information on a specific compilation tool.
class Tool {
+public:
+ // Documents the level of support for response files in this tool.
+ // Response files are necessary if the command line gets too large,
+ // requiring the arguments to be transfered to a file.
+ enum ResponseFileSupport {
+ // Provides full support for response files, which means we can transfer
+ // all tool input arguments to a file. E.g.: clang, gcc, binutils and MSVC
+ // tools.
+ RF_Full,
+ // Input file names can live in a file, but flags can't. E.g.: ld64 (Mac
+ // OS X linker).
+ RF_FileList,
+ // Does not support response files: all arguments must be passed via
+ // command line.
+ RF_None
+ };
+
+private:
/// The tool name (for debugging).
const char *Name;
@@ -40,9 +59,20 @@ class Tool {
/// The tool chain this tool is a part of.
const ToolChain &TheToolChain;
+ /// The level of support for response files seen in this tool
+ const ResponseFileSupport ResponseSupport;
+
+ /// The encoding to use when writing response files for this tool on Windows
+ const llvm::sys::WindowsEncodingMethod ResponseEncoding;
+
+ /// The flag used to pass a response file via command line to this tool
+ const char *const ResponseFlag;
+
public:
- Tool(const char *Name, const char *ShortName,
- const ToolChain &TC);
+ Tool(const char *Name, const char *ShortName, const ToolChain &TC,
+ ResponseFileSupport ResponseSupport = RF_None,
+ llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8,
+ const char *ResponseFlag = "@");
public:
virtual ~Tool();
@@ -54,9 +84,33 @@ public:
const ToolChain &getToolChain() const { return TheToolChain; }
virtual bool hasIntegratedAssembler() const { return false; }
+ virtual bool canEmitIR() const { return false; }
virtual bool hasIntegratedCPP() const = 0;
virtual bool isLinkJob() const { return false; }
virtual bool isDsymutilJob() const { return false; }
+ /// \brief Returns the level of support for response files of this tool,
+ /// whether it accepts arguments to be passed via a file on disk.
+ ResponseFileSupport getResponseFilesSupport() const {
+ return ResponseSupport;
+ }
+ /// \brief Returns which encoding the response file should use. This is only
+ /// relevant on Windows platforms where there are different encodings being
+ /// accepted for different tools. On UNIX, UTF8 is universal.
+ ///
+ /// Windows use cases: - GCC and Binutils on mingw only accept ANSI response
+ /// files encoded with the system current code page.
+ /// - MSVC's CL.exe and LINK.exe accept UTF16 on Windows.
+ /// - Clang accepts both UTF8 and UTF16.
+ ///
+ /// FIXME: When GNU tools learn how to parse UTF16 on Windows, we should
+ /// always use UTF16 for Windows, which is the Windows official encoding for
+ /// international characters.
+ llvm::sys::WindowsEncodingMethod getResponseFileEncoding() const {
+ return ResponseEncoding;
+ }
+ /// \brief Returns which prefix to use when passing the name of a response
+ /// file as a parameter to this tool.
+ const char *getResponseFileFlag() const { return ResponseFlag; }
/// \brief Does this tool have "good" standardized diagnostics, or should the
/// driver add an additional "command failed" diagnostic on failures.
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index 550e4dfc60c3..3092e81b95b5 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_DRIVER_TOOLCHAIN_H_
-#define CLANG_DRIVER_TOOLCHAIN_H_
+#ifndef LLVM_CLANG_DRIVER_TOOLCHAIN_H
+#define LLVM_CLANG_DRIVER_TOOLCHAIN_H
#include "clang/Driver/Action.h"
#include "clang/Driver/Multilib.h"
@@ -41,7 +41,7 @@ namespace driver {
/// ToolChain - Access to tools for a single platform.
class ToolChain {
public:
- typedef SmallVector<std::string, 4> path_list;
+ typedef SmallVector<std::string, 16> path_list;
enum CXXStdlibType {
CST_Libcxx,
@@ -118,7 +118,7 @@ public:
/// \brief Provide the default architecture name (as expected by -arch) for
/// this toolchain. Note t
- std::string getDefaultUniversalArchName() const;
+ StringRef getDefaultUniversalArchName() const;
std::string getTripleString() const {
return Triple.getTriple();
@@ -248,6 +248,12 @@ public:
/// UseSjLjExceptions - Does this tool chain use SjLj exceptions.
virtual bool UseSjLjExceptions() const { return false; }
+ /// getThreadModel() - Which thread model does this target use?
+ virtual std::string getThreadModel() const { return "posix"; }
+
+ /// isThreadModelSupported() - Does this target support a thread model?
+ virtual bool isThreadModelSupported(const StringRef Model) const;
+
/// ComputeLLVMTriple - Return the LLVM target triple to use, after taking
/// command line arguments into account.
virtual std::string
diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h
index cca576a054aa..34442eb6379f 100644
--- a/include/clang/Driver/Types.h
+++ b/include/clang/Driver/Types.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_DRIVER_TYPES_H_
-#define CLANG_DRIVER_TYPES_H_
+#ifndef LLVM_CLANG_DRIVER_TYPES_H
+#define LLVM_CLANG_DRIVER_TYPES_H
#include "clang/Driver/Phases.h"
#include "llvm/ADT/SmallVector.h"
diff --git a/include/clang/Driver/Util.h b/include/clang/Driver/Util.h
index b24b9904f2b5..07495a18508c 100644
--- a/include/clang/Driver/Util.h
+++ b/include/clang/Driver/Util.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_DRIVER_UTIL_H_
-#define CLANG_DRIVER_UTIL_H_
+#ifndef LLVM_CLANG_DRIVER_UTIL_H
+#define LLVM_CLANG_DRIVER_UTIL_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index 45cccaacd569..60c54abd1a9b 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -15,8 +15,9 @@
#ifndef LLVM_CLANG_FORMAT_FORMAT_H
#define LLVM_CLANG_FORMAT_FORMAT_H
-#include "clang/Frontend/FrontendAction.h"
-#include "clang/Tooling/Refactoring.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/ArrayRef.h"
#include <system_error>
namespace clang {
@@ -47,6 +48,8 @@ struct FormatStyle {
LK_None,
/// Should be used for C, C++, ObjectiveC, ObjectiveC++.
LK_Cpp,
+ /// Should be used for Java.
+ LK_Java,
/// Should be used for JavaScript.
LK_JavaScript,
/// Should be used for Protocol Buffers
@@ -150,10 +153,14 @@ struct FormatStyle {
/// commonly have different usage patterns and a number of special cases.
unsigned SpacesBeforeTrailingComments;
- /// \brief If \c false, a function call's or function definition's parameters
- /// will either all be on the same line or will have one line each.
+ /// \brief If \c false, a function declaration's or function definition's
+ /// parameters will either all be on the same line or will have one line each.
bool BinPackParameters;
+ /// \brief If \c false, a function call's arguments will either be all on the
+ /// same line or will have one line each.
+ bool BinPackArguments;
+
/// \brief If \c true, clang-format detects whether function calls and
/// definitions are formatted with one parameter per line.
///
@@ -195,6 +202,9 @@ struct FormatStyle {
/// single line.
bool AllowShortLoopsOnASingleLine;
+ /// \brief If \c true, short case labels will be contracted to a single line.
+ bool AllowShortCaseLabelsOnASingleLine;
+
/// \brief Different styles for merging short functions containing at most one
/// statement.
enum ShortFunctionStyle {
@@ -202,6 +212,8 @@ struct FormatStyle {
SFS_None,
/// \brief Only merge functions defined inside a class.
SFS_Inline,
+ /// \brief Only merge empty functions.
+ SFS_Empty,
/// \brief Merge all functions fitting on a single line.
SFS_All,
};
@@ -218,6 +230,20 @@ struct FormatStyle {
/// <tt>Foo <Protocol></tt> instead of \c Foo<Protocol>.
bool ObjCSpaceBeforeProtocolList;
+ /// \brief If \c true, horizontally aligns arguments after an open bracket.
+ ///
+ /// This applies to round brackets (parentheses), angle brackets and square
+ /// brackets. This will result in formattings like
+ /// \code
+ /// someLongFunction(argument1,
+ /// argument2);
+ /// \endcode
+ bool AlignAfterOpenBracket;
+
+ /// \brief If \c true, horizontally align operands of binary and ternary
+ /// expressions.
+ bool AlignOperands;
+
/// \brief If \c true, aligns trailing comments.
bool AlignTrailingComments;
@@ -235,6 +261,16 @@ struct FormatStyle {
/// initializer lists.
unsigned ConstructorInitializerIndentWidth;
+ /// \brief The number of characters to use for indentation of ObjC blocks.
+ unsigned ObjCBlockIndentWidth;
+
+ /// \brief If \c true, always break after function definition return types.
+ ///
+ /// More truthfully called 'break before the identifier following the type
+ /// in a function definition'. PenaltyReturnTypeOnItsOwnLine becomes
+ /// irrelevant.
+ bool AlwaysBreakAfterDefinitionReturnType;
+
/// \brief If \c true, always break after the <tt>template<...></tt> of a
/// template declaration.
bool AlwaysBreakTemplateDeclarations;
@@ -256,8 +292,18 @@ struct FormatStyle {
/// \brief The way to use tab characters in the resulting file.
UseTabStyle UseTab;
- /// \brief If \c true, binary operators will be placed after line breaks.
- bool BreakBeforeBinaryOperators;
+ /// \brief The style of breaking before or after binary operators.
+ enum BinaryOperatorStyle {
+ /// Break after operators.
+ BOS_None,
+ /// Break before operators that aren't assignments.
+ BOS_NonAssignment,
+ /// Break before operators.
+ BOS_All,
+ };
+
+ /// \brief The way to wrap binary operators.
+ BinaryOperatorStyle BreakBeforeBinaryOperators;
/// \brief If \c true, ternary operators will be placed after line breaks.
bool BreakBeforeTernaryOperators;
@@ -269,7 +315,7 @@ struct FormatStyle {
/// Like \c Attach, but break before braces on function, namespace and
/// class definitions.
BS_Linux,
- /// Like \c Attach, but break before function definitions.
+ /// Like \c Attach, but break before function definitions, and 'else'.
BS_Stroustrup,
/// Always break before braces.
BS_Allman,
@@ -304,6 +350,9 @@ struct FormatStyle {
/// template argument lists
bool SpacesInAngles;
+ /// \brief If \c true, spaces will be inserted after '[' and before ']'.
+ bool SpacesInSquareBrackets;
+
/// \brief If \c true, spaces may be inserted into '()'.
bool SpaceInEmptyParentheses;
@@ -314,6 +363,9 @@ struct FormatStyle {
/// \brief If \c true, spaces may be inserted into C style casts.
bool SpacesInCStyleCastParentheses;
+ /// \brief If \c true, a space may be inserted after C style casts.
+ bool SpaceAfterCStyleCast;
+
/// \brief Different ways to put a space before opening parentheses.
enum SpaceBeforeParensOptions {
/// Never put a space before opening parentheses.
@@ -358,8 +410,8 @@ struct FormatStyle {
bool operator==(const FormatStyle &R) const {
return AccessModifierOffset == R.AccessModifierOffset &&
- ConstructorInitializerIndentWidth ==
- R.ConstructorInitializerIndentWidth &&
+ AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
+ AlignOperands == R.AlignOperands &&
AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft &&
AlignTrailingComments == R.AlignTrailingComments &&
AllowAllParametersOfDeclarationOnNextLine ==
@@ -370,11 +422,14 @@ struct FormatStyle {
AllowShortIfStatementsOnASingleLine ==
R.AllowShortIfStatementsOnASingleLine &&
AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine &&
+ AlwaysBreakAfterDefinitionReturnType ==
+ R.AlwaysBreakAfterDefinitionReturnType &&
AlwaysBreakTemplateDeclarations ==
R.AlwaysBreakTemplateDeclarations &&
AlwaysBreakBeforeMultilineStrings ==
R.AlwaysBreakBeforeMultilineStrings &&
BinPackParameters == R.BinPackParameters &&
+ BinPackArguments == R.BinPackArguments &&
BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators &&
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
BreakBeforeBraces == R.BreakBeforeBraces &&
@@ -383,6 +438,8 @@ struct FormatStyle {
ColumnLimit == R.ColumnLimit &&
ConstructorInitializerAllOnOneLineOrOnePerLine ==
R.ConstructorInitializerAllOnOneLineOrOnePerLine &&
+ ConstructorInitializerIndentWidth ==
+ R.ConstructorInitializerIndentWidth &&
DerivePointerAlignment == R.DerivePointerAlignment &&
ExperimentalAutoDetectBinPacking ==
R.ExperimentalAutoDetectBinPacking &&
@@ -393,6 +450,7 @@ struct FormatStyle {
KeepEmptyLinesAtTheStartOfBlocks ==
R.KeepEmptyLinesAtTheStartOfBlocks &&
NamespaceIndentation == R.NamespaceIndentation &&
+ ObjCBlockIndentWidth == R.ObjCBlockIndentWidth &&
ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty &&
ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&
PenaltyBreakComment == R.PenaltyBreakComment &&
@@ -405,10 +463,12 @@ struct FormatStyle {
Cpp11BracedListStyle == R.Cpp11BracedListStyle &&
Standard == R.Standard && TabWidth == R.TabWidth &&
UseTab == R.UseTab && SpacesInParentheses == R.SpacesInParentheses &&
+ SpacesInSquareBrackets == R.SpacesInSquareBrackets &&
SpacesInAngles == R.SpacesInAngles &&
SpaceInEmptyParentheses == R.SpaceInEmptyParentheses &&
SpacesInContainerLiterals == R.SpacesInContainerLiterals &&
SpacesInCStyleCastParentheses == R.SpacesInCStyleCastParentheses &&
+ SpaceAfterCStyleCast == R.SpaceAfterCStyleCast &&
SpaceBeforeParens == R.SpaceBeforeParens &&
SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators &&
ContinuationIndentWidth == R.ContinuationIndentWidth &&
@@ -470,29 +530,34 @@ std::string configurationAsText(const FormatStyle &Style);
/// \brief Reformats the given \p Ranges in the token stream coming out of
/// \c Lex.
///
+/// DEPRECATED: Do not use.
+tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
+ SourceManager &SourceMgr,
+ ArrayRef<CharSourceRange> Ranges);
+
+/// \brief Reformats the given \p Ranges in the file \p ID.
+///
/// Each range is extended on either end to its next bigger logic unit, i.e.
/// everything that might influence its formatting or might be influenced by its
/// formatting.
///
/// Returns the \c Replacements necessary to make all \p Ranges comply with
/// \p Style.
-tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
- SourceManager &SourceMgr,
- std::vector<CharSourceRange> Ranges);
+tooling::Replacements reformat(const FormatStyle &Style,
+ SourceManager &SourceMgr, FileID ID,
+ ArrayRef<CharSourceRange> Ranges);
/// \brief Reformats the given \p Ranges in \p Code.
///
/// Otherwise identical to the reformat() function consuming a \c Lexer.
tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
- std::vector<tooling::Range> Ranges,
+ ArrayRef<tooling::Range> Ranges,
StringRef FileName = "<stdin>");
/// \brief Returns the \c LangOpts that the formatter expects you to set.
///
-/// \param Standard determines lexing mode: LC_Cpp11 and LS_Auto turn on C++11
-/// lexing mode, LS_Cpp03 - C++03 mode.
-LangOptions getFormattingLangOpts(
- FormatStyle::LanguageStandard Standard = FormatStyle::LS_Cpp11);
+/// \param Style determines specific settings for lexing mode.
+LangOptions getFormattingLangOpts(const FormatStyle &Style = getLLVMStyle());
/// \brief Description to be used for help text for a llvm::cl option for
/// specifying format style. The description is closely related to the operation
diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h
index 366c499b67f5..757fcae988fc 100644
--- a/include/clang/Frontend/ASTConsumers.h
+++ b/include/clang/Frontend/ASTConsumers.h
@@ -11,10 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#ifndef DRIVER_ASTCONSUMERS_H
-#define DRIVER_ASTCONSUMERS_H
+#ifndef LLVM_CLANG_FRONTEND_ASTCONSUMERS_H
+#define LLVM_CLANG_FRONTEND_ASTCONSUMERS_H
#include "clang/Basic/LLVM.h"
+#include <memory>
namespace clang {
@@ -30,24 +31,27 @@ class TargetOptions;
// original C code. The output is intended to be in a format such that
// clang could re-parse the output back into the same AST, but the
// implementation is still incomplete.
-ASTConsumer *CreateASTPrinter(raw_ostream *OS, StringRef FilterString);
+std::unique_ptr<ASTConsumer> CreateASTPrinter(raw_ostream *OS,
+ StringRef FilterString);
// AST dumper: dumps the raw AST in human-readable form to stderr; this is
// intended for debugging.
-ASTConsumer *CreateASTDumper(StringRef FilterString, bool DumpLookups = false);
+std::unique_ptr<ASTConsumer> CreateASTDumper(StringRef FilterString,
+ bool DumpDecls,
+ bool DumpLookups);
// AST Decl node lister: prints qualified names of all filterable AST Decl
// nodes.
-ASTConsumer *CreateASTDeclNodeLister();
+std::unique_ptr<ASTConsumer> CreateASTDeclNodeLister();
// Graphical AST viewer: for each function definition, creates a graph of
// the AST and displays it with the graph viewer "dotty". Also outputs
// function declarations to stderr.
-ASTConsumer *CreateASTViewer();
+std::unique_ptr<ASTConsumer> CreateASTViewer();
// DeclContext printer: prints out the DeclContext tree in human-readable form
// to stderr; this is intended for debugging.
-ASTConsumer *CreateDeclContextPrinter();
+std::unique_ptr<ASTConsumer> CreateDeclContextPrinter();
} // end clang namespace
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 42dc69ab4a15..634224d08bbf 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -272,12 +272,12 @@ private:
/// \brief When non-NULL, this is the buffer used to store the contents of
/// the main file when it has been padded for use with the precompiled
/// preamble.
- llvm::MemoryBuffer *SavedMainFileBuffer;
+ std::unique_ptr<llvm::MemoryBuffer> SavedMainFileBuffer;
/// \brief When non-NULL, this is the buffer used to store the
/// contents of the preamble when it has been padded to build the
/// precompiled preamble.
- llvm::MemoryBuffer *PreambleBuffer;
+ std::unique_ptr<llvm::MemoryBuffer> PreambleBuffer;
/// \brief The number of warnings that occurred while parsing the preamble.
///
@@ -305,8 +305,7 @@ private:
/// \brief The language options used when we load an AST file.
LangOptions ASTFileLangOpts;
- static void ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
- const char **ArgBegin, const char **ArgEnd,
+ static void ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
ASTUnit &AST, bool CaptureDiagnostics);
void TranslateStoredDiagnostics(FileManager &FileMgr,
@@ -423,16 +422,28 @@ private:
explicit ASTUnit(bool MainFileIsAST);
void CleanTemporaryFiles();
- bool Parse(llvm::MemoryBuffer *OverrideMainBuffer);
-
- std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> >
- ComputePreamble(CompilerInvocation &Invocation,
- unsigned MaxLines, bool &CreatedBuffer);
-
- llvm::MemoryBuffer *getMainBufferWithPrecompiledPreamble(
- const CompilerInvocation &PreambleInvocationIn,
- bool AllowRebuild = true,
- unsigned MaxLines = 0);
+ bool Parse(std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer);
+
+ struct ComputedPreamble {
+ llvm::MemoryBuffer *Buffer;
+ std::unique_ptr<llvm::MemoryBuffer> Owner;
+ unsigned Size;
+ bool PreambleEndsAtStartOfLine;
+ ComputedPreamble(llvm::MemoryBuffer *Buffer,
+ std::unique_ptr<llvm::MemoryBuffer> Owner, unsigned Size,
+ bool PreambleEndsAtStartOfLine)
+ : Buffer(Buffer), Owner(std::move(Owner)), Size(Size),
+ PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
+ ComputedPreamble(ComputedPreamble &&C)
+ : Buffer(C.Buffer), Owner(std::move(C.Owner)), Size(C.Size),
+ PreambleEndsAtStartOfLine(C.PreambleEndsAtStartOfLine) {}
+ };
+ ComputedPreamble ComputePreamble(CompilerInvocation &Invocation,
+ unsigned MaxLines);
+
+ std::unique_ptr<llvm::MemoryBuffer> getMainBufferWithPrecompiledPreamble(
+ const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild = true,
+ unsigned MaxLines = 0);
void RealizeTopLevelDeclsFromPreamble();
/// \brief Transfers ownership of the objects (like SourceManager) from
@@ -684,8 +695,8 @@ public:
/// module file.
bool isModuleFile();
- llvm::MemoryBuffer *getBufferForFile(StringRef Filename,
- std::string *ErrorStr = nullptr);
+ std::unique_ptr<llvm::MemoryBuffer>
+ getBufferForFile(StringRef Filename, std::string *ErrorStr = nullptr);
/// \brief Determine what kind of translation unit this AST represents.
TranslationUnitKind getTranslationUnitKind() const { return TUKind; }
@@ -708,14 +719,12 @@ public:
/// lifetime is expected to extend past that of the returned ASTUnit.
///
/// \returns - The initialized ASTUnit or null if the AST failed to load.
- static ASTUnit *LoadFromASTFile(const std::string &Filename,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
- const FileSystemOptions &FileSystemOpts,
- bool OnlyLocalDecls = false,
- ArrayRef<RemappedFile> RemappedFiles = None,
- bool CaptureDiagnostics = false,
- bool AllowPCHWithCompilerErrors = false,
- bool UserFilesAreVolatile = false);
+ static std::unique_ptr<ASTUnit> LoadFromASTFile(
+ const std::string &Filename, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ const FileSystemOptions &FileSystemOpts, bool OnlyLocalDecls = false,
+ ArrayRef<RemappedFile> RemappedFiles = None,
+ bool CaptureDiagnostics = false, bool AllowPCHWithCompilerErrors = false,
+ bool UserFilesAreVolatile = false);
private:
/// \brief Helper function for \c LoadFromCompilerInvocation() and
diff --git a/include/clang/Frontend/ChainedDiagnosticConsumer.h b/include/clang/Frontend/ChainedDiagnosticConsumer.h
index 11762a97cfc4..eb33273c2fb3 100644
--- a/include/clang/Frontend/ChainedDiagnosticConsumer.h
+++ b/include/clang/Frontend/ChainedDiagnosticConsumer.h
@@ -22,15 +22,20 @@ class LangOptions;
/// diagnostics should be included in counts.
class ChainedDiagnosticConsumer : public DiagnosticConsumer {
virtual void anchor();
- std::unique_ptr<DiagnosticConsumer> Primary;
+ std::unique_ptr<DiagnosticConsumer> OwningPrimary;
+ DiagnosticConsumer *Primary;
std::unique_ptr<DiagnosticConsumer> Secondary;
public:
- ChainedDiagnosticConsumer(DiagnosticConsumer *_Primary,
- DiagnosticConsumer *_Secondary) {
- Primary.reset(_Primary);
- Secondary.reset(_Secondary);
- }
+ ChainedDiagnosticConsumer(std::unique_ptr<DiagnosticConsumer> Primary,
+ std::unique_ptr<DiagnosticConsumer> Secondary)
+ : OwningPrimary(std::move(Primary)), Primary(OwningPrimary.get()),
+ Secondary(std::move(Secondary)) {}
+
+ /// \brief Construct without taking ownership of \c Primary.
+ ChainedDiagnosticConsumer(DiagnosticConsumer *Primary,
+ std::unique_ptr<DiagnosticConsumer> Secondary)
+ : Primary(Primary), Secondary(std::move(Secondary)) {}
void BeginSourceFile(const LangOptions &LO,
const Preprocessor *PP) override {
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index 1d92efeda258..b44672d0f5f0 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -67,14 +67,18 @@ CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled.
CODEGENOPT(LessPreciseFPMAD , 1, 0) ///< Enable less precise MAD instructions to
///< be generated.
CODEGENOPT(MergeAllConstants , 1, 1) ///< Merge identical constants.
+CODEGENOPT(MergeFunctions , 1, 0) ///< Set when -fmerge-functions is enabled.
CODEGENOPT(NoCommon , 1, 0) ///< Set when -fno-common or C++ is enabled.
CODEGENOPT(NoDwarfDirectoryAsm , 1, 0) ///< Set when -fno-dwarf-directory-asm is
///< enabled.
CODEGENOPT(NoExecStack , 1, 0) ///< Set when -Wa,--noexecstack is enabled.
+CODEGENOPT(FatalWarnings , 1, 0) ///< Set when -Wa,--fatal-warnings is
+ ///< enabled.
CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled.
CODEGENOPT(NoGlobalMerge , 1, 0) ///< Set when -mno-global-merge is enabled.
CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled.
CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf.
+CODEGENOPT(NoSignedZeros , 1, 0) ///< Allow ignoring the signedness of FP zero
CODEGENOPT(NoInline , 1, 0) ///< Set when -fno-inline is enabled.
///< Disables use of the inline keyword.
CODEGENOPT(NoNaNsFPMath , 1, 0) ///< Assume FP arguments, results not NaN.
@@ -83,11 +87,15 @@ CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss.
ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy)
CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
///< enabled.
-VALUE_CODEGENOPT(OptimizationLevel, 3, 0) ///< The -O[0-4] option specified.
+VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified.
VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
CODEGENOPT(ProfileInstrGenerate , 1, 0) ///< Instrument code to generate
///< execution counts to use with PGO.
+CODEGENOPT(CoverageMapping , 1, 0) ///< Generate coverage mapping regions to
+ ///< enable code coverage analysis.
+CODEGENOPT(DumpCoverageMapping , 1, 0) ///< Dump the generated coverage mapping
+ ///< regions.
/// If -fpcc-struct-return or -freg-struct-return is specified.
ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default)
@@ -100,6 +108,7 @@ CODEGENOPT(SanitizeAddressZeroBaseShadow , 1, 0) ///< Map shadow memory at zero
///< offset in AddressSanitizer.
CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in
///< MemorySanitizer
+CODEGENOPT(SanitizeCoverage, 3, 0) ///< Enable sanitizer coverage instrumentation.
CODEGENOPT(SanitizeUndefinedTrapOnError, 1, 0) ///< Set on
/// -fsanitize-undefined-trap-on-error
CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
@@ -151,9 +160,6 @@ ENUM_CODEGENOPT(Inlining, InliningMethod, 2, NoInlining)
/// The default TLS model to use.
ENUM_CODEGENOPT(DefaultTLSModel, TLSModel, 2, GeneralDynamicTLSModel)
-CODEGENOPT(SanitizeRecover, 1, 1) ///< Attempt to recover from sanitizer checks
- ///< by continuing execution when possible
-
#undef CODEGENOPT
#undef ENUM_CODEGENOPT
#undef VALUE_CODEGENOPT
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 3d532cea3431..819606429efb 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -14,9 +14,11 @@
#ifndef LLVM_CLANG_FRONTEND_CODEGENOPTIONS_H
#define LLVM_CLANG_FRONTEND_CODEGENOPTIONS_H
+#include "clang/Basic/Sanitizers.h"
+#include "llvm/Support/Regex.h"
+#include <memory>
#include <string>
#include <vector>
-#include "llvm/Support/Regex.h"
namespace clang {
@@ -134,8 +136,8 @@ public:
/// The name of the relocation model to use.
std::string RelocationModel;
- /// Path to blacklist file for sanitizers.
- std::string SanitizerBlacklistFile;
+ /// The thread model to use
+ std::string ThreadModel;
/// If not an empty string, trap intrinsics are lowered to calls to this
/// function instead of to trap instructions.
@@ -175,6 +177,13 @@ public:
/// flag.
std::shared_ptr<llvm::Regex> OptimizationRemarkAnalysisPattern;
+ /// Set of files definining the rules for the symbol rewriting.
+ std::vector<std::string> RewriteMapFiles;
+
+ /// Set of sanitizer checks that are non-fatal (i.e. execution should be
+ /// continued when possible).
+ SanitizerSet SanitizeRecover;
+
public:
// Define accessors/mutators for code generation options of enumeration type.
#define CODEGENOPT(Name, Bits, Default)
@@ -183,15 +192,7 @@ public:
void set##Name(Type Value) { Name = static_cast<unsigned>(Value); }
#include "clang/Frontend/CodeGenOptions.def"
- CodeGenOptions() {
-#define CODEGENOPT(Name, Bits, Default) Name = Default;
-#define ENUM_CODEGENOPT(Name, Type, Bits, Default) \
- set##Name(Default);
-#include "clang/Frontend/CodeGenOptions.def"
-
- RelocationModel = "pic";
- memcpy(CoverageVersion, "402*", 4);
- }
+ CodeGenOptions();
};
} // end namespace clang
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 44e91026acb5..0f49b346107b 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_
#define LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_
+#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -116,7 +117,10 @@ class CompilerInstance : public ModuleLoader {
/// \brief The set of top-level modules that has already been loaded,
/// along with the module map
llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules;
-
+
+ /// \brief Module names that have an override for the target file.
+ llvm::StringMap<std::string> ModuleFileOverrides;
+
/// \brief The location of the module-import keyword for the last module
/// import.
SourceLocation LastModuleImportLoc;
@@ -246,6 +250,9 @@ public:
return Invocation->getDiagnosticOpts();
}
+ FileSystemOptions &getFileSystemOpts() {
+ return Invocation->getFileSystemOpts();
+ }
const FileSystemOptions &getFileSystemOpts() const {
return Invocation->getFileSystemOpts();
}
@@ -443,11 +450,11 @@ public:
/// takeASTConsumer - Remove the current AST consumer and give ownership to
/// the caller.
- ASTConsumer *takeASTConsumer() { return Consumer.release(); }
+ std::unique_ptr<ASTConsumer> takeASTConsumer() { return std::move(Consumer); }
/// setASTConsumer - Replace the current AST consumer; the compiler instance
/// takes ownership of \p Value.
- void setASTConsumer(ASTConsumer *Value);
+ void setASTConsumer(std::unique_ptr<ASTConsumer> Value);
/// }
/// @name Semantic analysis
@@ -459,8 +466,8 @@ public:
return *TheSema;
}
- Sema *takeSema() { return TheSema.release(); }
- void resetAndLeakSema() { BuryPointer(TheSema.release()); }
+ std::unique_ptr<Sema> takeSema();
+ void resetAndLeakSema();
/// }
/// @name Module Management
@@ -485,12 +492,6 @@ public:
return *CompletionConsumer;
}
- /// takeCodeCompletionConsumer - Remove the current code completion consumer
- /// and give ownership to the caller.
- CodeCompleteConsumer *takeCodeCompletionConsumer() {
- return CompletionConsumer.release();
- }
-
/// setCodeCompletionConsumer - Replace the current code completion consumer;
/// the compiler instance takes ownership of \p Value.
void setCodeCompletionConsumer(CodeCompleteConsumer *Value);
@@ -646,7 +647,7 @@ public:
/// renamed to \p OutputPath in the end.
///
/// \param OutputPath - If given, the path to the output file.
- /// \param Error [out] - On failure, the error message.
+ /// \param Error [out] - On failure, the error.
/// \param BaseInput - If \p OutputPath is empty, the input path name to use
/// for deriving the output path.
/// \param Extension - The extension to use for derived output names.
@@ -663,13 +664,10 @@ public:
/// \param TempPathName [out] - If given, the temporary file path name
/// will be stored here on success.
static llvm::raw_fd_ostream *
- createOutputFile(StringRef OutputPath, std::string &Error,
- bool Binary, bool RemoveFileOnSignal,
- StringRef BaseInput,
- StringRef Extension,
- bool UseTemporary,
- bool CreateMissingDirectories,
- std::string *ResultPathName,
+ createOutputFile(StringRef OutputPath, std::error_code &Error, bool Binary,
+ bool RemoveFileOnSignal, StringRef BaseInput,
+ StringRef Extension, bool UseTemporary,
+ bool CreateMissingDirectories, std::string *ResultPathName,
std::string *TempPathName);
llvm::raw_null_ostream *createNullOutputFile();
@@ -699,6 +697,8 @@ public:
// Create module manager.
void createModuleManager();
+ bool loadModuleFile(StringRef FileName);
+
ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) override;
diff --git a/include/clang/Frontend/DiagnosticRenderer.h b/include/clang/Frontend/DiagnosticRenderer.h
index ce1dc9046557..5becadf40eda 100644
--- a/include/clang/Frontend/DiagnosticRenderer.h
+++ b/include/clang/Frontend/DiagnosticRenderer.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_DIAGNOSTIC_RENDERER_H_
-#define LLVM_CLANG_FRONTEND_DIAGNOSTIC_RENDERER_H_
+#ifndef LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H
+#define LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h
index 9ac9d2828f6a..c407ff80ac56 100644
--- a/include/clang/Frontend/FrontendAction.h
+++ b/include/clang/Frontend/FrontendAction.h
@@ -18,8 +18,10 @@
#ifndef LLVM_CLANG_FRONTEND_FRONTENDACTION_H
#define LLVM_CLANG_FRONTEND_FRONTENDACTION_H
+#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/FrontendOptions.h"
#include "llvm/ADT/StringRef.h"
#include <memory>
@@ -27,9 +29,7 @@
#include <vector>
namespace clang {
-class ASTConsumer;
class ASTMergeAction;
-class ASTUnit;
class CompilerInstance;
/// Abstract base class for actions which can be performed by the frontend.
@@ -41,8 +41,8 @@ class FrontendAction {
friend class WrapperFrontendAction;
private:
- ASTConsumer* CreateWrappedASTConsumer(CompilerInstance &CI,
- StringRef InFile);
+ std::unique_ptr<ASTConsumer> CreateWrappedASTConsumer(CompilerInstance &CI,
+ StringRef InFile);
protected:
/// @name Implementation Action Interface
@@ -61,8 +61,8 @@ protected:
/// getCurrentFile().
///
/// \return The new AST consumer, or null on failure.
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) = 0;
+ virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) = 0;
/// \brief Callback before starting processing a single input, giving the
/// opportunity to modify the CompilerInvocation or do some other action
@@ -146,15 +146,24 @@ public:
return *CurrentASTUnit;
}
- ASTUnit *takeCurrentASTUnit() { return CurrentASTUnit.release(); }
+ std::unique_ptr<ASTUnit> takeCurrentASTUnit() {
+ return std::move(CurrentASTUnit);
+ }
void setCurrentInput(const FrontendInputFile &CurrentInput,
- ASTUnit *AST = nullptr);
+ std::unique_ptr<ASTUnit> AST = nullptr);
/// @}
/// @name Supported Modes
/// @{
+ /// \brief Is this action invoked on a model file?
+ ///
+ /// Model files are incomplete translation units that relies on type
+ /// information from another translation unit. Check ParseModelFileAction for
+ /// details.
+ virtual bool isModelParsingAction() const { return false; }
+
/// \brief Does this action only use the preprocessor?
///
/// If so no AST context will be created and this action will be invalid
@@ -222,16 +231,16 @@ protected:
void ExecuteAction() override;
public:
+ ASTFrontendAction() {}
bool usesPreprocessorOnly() const override { return false; }
};
class PluginASTAction : public ASTFrontendAction {
virtual void anchor();
-protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override = 0;
-
public:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override = 0;
+
/// \brief Parse the given plugin command line arguments.
///
/// \param CI - The compiler instance, for use in reporting diagnostics.
@@ -247,8 +256,8 @@ class PreprocessorFrontendAction : public FrontendAction {
protected:
/// \brief Provide a default implementation which returns aborts;
/// this method should never be called by FrontendAction clients.
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
public:
bool usesPreprocessorOnly() const override { return true; }
@@ -264,8 +273,8 @@ class WrapperFrontendAction : public FrontendAction {
std::unique_ptr<FrontendAction> WrappedAction;
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
bool BeginInvocation(CompilerInstance &CI) override;
bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
void ExecuteAction() override;
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 84cc82cfbe2f..850f87c073c5 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -26,8 +26,8 @@ class FileEntry;
class InitOnlyAction : public FrontendAction {
void ExecuteAction() override;
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
public:
// Don't claim to only use the preprocessor, we want to follow the AST path,
@@ -41,38 +41,38 @@ public:
class ASTPrintAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
};
class ASTDumpAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
};
class ASTDeclListAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
};
class ASTViewAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
};
class DeclContextPrintAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
};
class GeneratePCHAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
TranslationUnitKind getTranslationUnitKind() override {
return TU_Prefix;
@@ -98,8 +98,8 @@ class GenerateModuleAction : public ASTFrontendAction {
bool IsSystem;
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
TranslationUnitKind getTranslationUnitKind() override {
return TU_Module;
@@ -128,8 +128,8 @@ public:
class SyntaxOnlyAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
public:
bool hasCodeCompletionSupport() const override { return true; }
@@ -139,8 +139,8 @@ public:
/// basic debugging and discovery.
class DumpModuleInfoAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
void ExecuteAction() override;
public:
@@ -152,8 +152,8 @@ public:
class VerifyPCHAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
void ExecuteAction() override;
@@ -177,8 +177,8 @@ class ASTMergeAction : public FrontendAction {
std::vector<std::string> ASTFiles;
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
bool BeginSourceFileAction(CompilerInstance &CI,
StringRef Filename) override;
@@ -200,7 +200,8 @@ public:
class PrintPreambleAction : public FrontendAction {
protected:
void ExecuteAction() override;
- ASTConsumer *CreateASTConsumer(CompilerInstance &, StringRef) override {
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &,
+ StringRef) override {
return nullptr;
}
diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h
index 312dbf14115b..0f37b7ece7e0 100644
--- a/include/clang/Frontend/FrontendDiagnostic.h
+++ b/include/clang/Frontend/FrontendDiagnostic.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTENDDIAGNOSTIC_H
-#define LLVM_CLANG_FRONTENDDIAGNOSTIC_H
+#ifndef LLVM_CLANG_FRONTEND_FRONTENDDIAGNOSTIC_H
+#define LLVM_CLANG_FRONTEND_FRONTENDDIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index e87da8de1cfa..71c5aa47af99 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -142,6 +142,8 @@ public:
///< global module index if available.
unsigned GenerateGlobalModuleIndex : 1; ///< Whether we can generate the
///< global module index if needed.
+ unsigned ASTDumpDecls : 1; ///< Whether we include declaration
+ ///< dumps in AST dumps.
unsigned ASTDumpLookups : 1; ///< Whether we include lookup table
///< dumps in AST dumps.
@@ -182,12 +184,15 @@ public:
ObjCMT_NsAtomicIOSOnlyProperty = 0x400,
/// \brief Enable inferring NS_DESIGNATED_INITIALIZER for ObjC methods.
ObjCMT_DesignatedInitializer = 0x800,
+ /// \brief Enable converting setter/getter expressions to property-dot syntx.
+ ObjCMT_PropertyDotSyntax = 0x1000,
ObjCMT_MigrateDecls = (ObjCMT_ReadonlyProperty | ObjCMT_ReadwriteProperty |
ObjCMT_Annotation | ObjCMT_Instancetype |
ObjCMT_NsMacros | ObjCMT_ProtocolConformance |
ObjCMT_NsAtomicIOSOnlyProperty |
ObjCMT_DesignatedInitializer),
- ObjCMT_MigrateAll = (ObjCMT_Literals | ObjCMT_Subscripting | ObjCMT_MigrateDecls)
+ ObjCMT_MigrateAll = (ObjCMT_Literals | ObjCMT_Subscripting |
+ ObjCMT_MigrateDecls | ObjCMT_PropertyDotSyntax)
};
unsigned ObjCMTAction;
std::string ObjCMTWhiteListPath;
@@ -228,6 +233,13 @@ public:
/// The list of plugins to load.
std::vector<std::string> Plugins;
+ /// \brief The list of module map files to load before processing the input.
+ std::vector<std::string> ModuleMapFiles;
+
+ /// \brief The list of additional prebuilt module files to load before
+ /// processing the input.
+ std::vector<std::string> ModuleFiles;
+
/// \brief The list of AST files to merge.
std::vector<std::string> ASTMergeFiles;
@@ -246,7 +258,7 @@ public:
FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false),
FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
SkipFunctionBodies(false), UseGlobalModuleIndex(true),
- GenerateGlobalModuleIndex(true), ASTDumpLookups(false),
+ GenerateGlobalModuleIndex(true), ASTDumpDecls(false), ASTDumpLookups(false),
ARCMTAction(ARCMT_None), ObjCMTAction(ObjCMT_None),
ProgramAction(frontend::ParseSyntaxOnly)
{}
diff --git a/include/clang/Frontend/FrontendPluginRegistry.h b/include/clang/Frontend/FrontendPluginRegistry.h
index 49be495daa37..ecab630c1228 100644
--- a/include/clang/Frontend/FrontendPluginRegistry.h
+++ b/include/clang/Frontend/FrontendPluginRegistry.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_PLUGINFRONTENDACTION_H
-#define LLVM_CLANG_FRONTEND_PLUGINFRONTENDACTION_H
+#ifndef LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
+#define LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
#include "clang/Frontend/FrontendAction.h"
#include "llvm/Support/Registry.h"
diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h
index 9680e1f2e04c..8021d08942e5 100644
--- a/include/clang/Frontend/LangStandard.h
+++ b/include/clang/Frontend/LangStandard.h
@@ -24,7 +24,7 @@ enum LangFeatures {
C11 = (1 << 3),
CPlusPlus = (1 << 4),
CPlusPlus11 = (1 << 5),
- CPlusPlus1y = (1 << 6),
+ CPlusPlus14 = (1 << 6),
CPlusPlus1z = (1 << 7),
Digraphs = (1 << 8),
GNUMode = (1 << 9),
@@ -73,8 +73,8 @@ public:
/// isCPlusPlus11 - Language is a C++11 variant (or later).
bool isCPlusPlus11() const { return Flags & frontend::CPlusPlus11; }
- /// isCPlusPlus1y - Language is a C++14 variant (or later).
- bool isCPlusPlus1y() const { return Flags & frontend::CPlusPlus1y; }
+ /// isCPlusPlus14 - Language is a C++14 variant (or later).
+ bool isCPlusPlus14() const { return Flags & frontend::CPlusPlus14; }
/// isCPlusPlus1z - Language is a C++17 variant (or later).
bool isCPlusPlus1z() const { return Flags & frontend::CPlusPlus1z; }
diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def
index 90a27b5b9982..cac9c3c4155f 100644
--- a/include/clang/Frontend/LangStandards.def
+++ b/include/clang/Frontend/LangStandards.def
@@ -109,26 +109,26 @@ LANGSTANDARD(gnucxx11, "gnu++11",
LANGSTANDARD(cxx1y, "c++1y",
"ISO C++ 2014 with amendments",
- LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus1y | Digraphs)
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs)
LANGSTANDARD(cxx14, "c++14",
"ISO C++ 2014 with amendments",
- LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus1y | Digraphs)
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs)
LANGSTANDARD(gnucxx1y, "gnu++1y",
"ISO C++ 2014 with amendments and GNU extensions",
- LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus1y | Digraphs |
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs |
GNUMode)
LANGSTANDARD(gnucxx14, "gnu++14",
"ISO C++ 2014 with amendments and GNU extensions",
- LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus1y | Digraphs |
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs |
GNUMode)
LANGSTANDARD(cxx1z, "c++1z",
"Working draft for ISO C++ 2017",
- LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus1y | CPlusPlus1z |
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z |
Digraphs)
LANGSTANDARD(gnucxx1z, "gnu++1z",
"Working draft for ISO C++ 2017 with GNU extensions",
- LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus1y | CPlusPlus1z |
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z |
Digraphs | GNUMode)
// OpenCL
@@ -141,6 +141,9 @@ LANGSTANDARD(opencl11, "CL1.1",
LANGSTANDARD(opencl12, "CL1.2",
"OpenCL 1.2",
LineComment | C99 | Digraphs | HexFloat)
+LANGSTANDARD(opencl20, "CL2.0",
+ "OpenCL 2.0",
+ LineComment | C99 | Digraphs | HexFloat)
// CUDA
LANGSTANDARD(cuda, "cuda",
diff --git a/include/clang/Frontend/LogDiagnosticPrinter.h b/include/clang/Frontend/LogDiagnosticPrinter.h
index 013031987045..98adf655fcf1 100644
--- a/include/clang/Frontend/LogDiagnosticPrinter.h
+++ b/include/clang/Frontend/LogDiagnosticPrinter.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_LOG_DIAGNOSTIC_PRINTER_H_
-#define LLVM_CLANG_FRONTEND_LOG_DIAGNOSTIC_PRINTER_H_
+#ifndef LLVM_CLANG_FRONTEND_LOGDIAGNOSTICPRINTER_H
+#define LLVM_CLANG_FRONTEND_LOGDIAGNOSTICPRINTER_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
@@ -35,6 +35,9 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
/// The ID of the diagnostic.
unsigned DiagnosticID;
+
+ /// The Option Flag for the diagnostic
+ std::string WarningOption;
/// The level of the diagnostic.
DiagnosticsEngine::Level DiagnosticLevel;
@@ -43,13 +46,16 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
void EmitDiagEntry(llvm::raw_ostream &OS,
const LogDiagnosticPrinter::DiagEntry &DE);
+ // Conditional ownership (when StreamOwner is non-null, it's keeping OS
+ // alive). We might want to replace this with a wrapper for conditional
+ // ownership eventually - it seems to pop up often enough.
raw_ostream &OS;
+ std::unique_ptr<raw_ostream> StreamOwner;
const LangOptions *LangOpts;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
SourceLocation LastWarningLoc;
FullSourceLoc LastLoc;
- unsigned OwnsOutputStream : 1;
SmallVector<DiagEntry, 8> Entries;
@@ -58,8 +64,7 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
public:
LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags,
- bool OwnsOutputStream = false);
- virtual ~LogDiagnosticPrinter();
+ std::unique_ptr<raw_ostream> StreamOwner);
void setDwarfDebugFlags(StringRef Value) {
DwarfDebugFlags = Value;
diff --git a/include/clang/Frontend/MigratorOptions.h b/include/clang/Frontend/MigratorOptions.h
index f9554e4a61fd..8eb71b13f885 100644
--- a/include/clang/Frontend/MigratorOptions.h
+++ b/include/clang/Frontend/MigratorOptions.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_MIGRATOROPTIONS
-#define LLVM_CLANG_FRONTEND_MIGRATOROPTIONS
+#ifndef LLVM_CLANG_FRONTEND_MIGRATOROPTIONS_H
+#define LLVM_CLANG_FRONTEND_MIGRATOROPTIONS_H
namespace clang {
diff --git a/include/clang/Frontend/MultiplexConsumer.h b/include/clang/Frontend/MultiplexConsumer.h
index 4d31104cce18..c9122dacb8f1 100644
--- a/include/clang/Frontend/MultiplexConsumer.h
+++ b/include/clang/Frontend/MultiplexConsumer.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_FRONTEND_MULTIPLEXCONSUMER_H
-#define CLANG_FRONTEND_MULTIPLEXCONSUMER_H
+#ifndef LLVM_CLANG_FRONTEND_MULTIPLEXCONSUMER_H
+#define LLVM_CLANG_FRONTEND_MULTIPLEXCONSUMER_H
#include "clang/Basic/LLVM.h"
#include "clang/Sema/SemaConsumer.h"
@@ -29,7 +29,7 @@ class MultiplexASTDeserializationListener;
class MultiplexConsumer : public SemaConsumer {
public:
// Takes ownership of the pointers in C.
- MultiplexConsumer(ArrayRef<ASTConsumer*> C);
+ MultiplexConsumer(std::vector<std::unique_ptr<ASTConsumer>> C);
~MultiplexConsumer();
// ASTConsumer
@@ -59,7 +59,7 @@ public:
void ForgetSema() override;
private:
- std::vector<ASTConsumer*> Consumers; // Owns these.
+ std::vector<std::unique_ptr<ASTConsumer>> Consumers; // Owns these.
std::unique_ptr<MultiplexASTMutationListener> MutationListener;
std::unique_ptr<MultiplexASTDeserializationListener> DeserializationListener;
};
diff --git a/include/clang/Frontend/SerializedDiagnosticPrinter.h b/include/clang/Frontend/SerializedDiagnosticPrinter.h
index 4dda1fa4b655..4c57e9d404f0 100644
--- a/include/clang/Frontend/SerializedDiagnosticPrinter.h
+++ b/include/clang/Frontend/SerializedDiagnosticPrinter.h
@@ -7,10 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTIC_PRINTER_H_
-#define LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTIC_PRINTER_H_
+#ifndef LLVM_CLANG_FRONTEND_SERIALIZEDDIAGNOSTICPRINTER_H
+#define LLVM_CLANG_FRONTEND_SERIALIZEDDIAGNOSTICPRINTER_H
#include "clang/Basic/LLVM.h"
+#include "clang/Frontend/SerializedDiagnostics.h"
#include "llvm/Bitcode/BitstreamWriter.h"
namespace llvm {
@@ -23,41 +24,6 @@ class DiagnosticsEngine;
class DiagnosticOptions;
namespace serialized_diags {
-
-enum BlockIDs {
- /// \brief A top-level block which represents any meta data associated
- /// with the diagostics, including versioning of the format.
- BLOCK_META = llvm::bitc::FIRST_APPLICATION_BLOCKID,
-
- /// \brief The this block acts as a container for all the information
- /// for a specific diagnostic.
- BLOCK_DIAG
-};
-
-enum RecordIDs {
- RECORD_VERSION = 1,
- RECORD_DIAG,
- RECORD_SOURCE_RANGE,
- RECORD_DIAG_FLAG,
- RECORD_CATEGORY,
- RECORD_FILENAME,
- RECORD_FIXIT,
- RECORD_FIRST = RECORD_VERSION,
- RECORD_LAST = RECORD_FIXIT
-};
-
-/// A stable version of DiagnosticIDs::Level.
-///
-/// Do not change the order of values in this enum, and please increment the
-/// serialized diagnostics version number when you add to it.
-enum Level {
- Ignored = 0,
- Note,
- Warning,
- Error,
- Fatal,
- Remark
-};
/// \brief Returns a DiagnosticConsumer that serializes diagnostics to
/// a bitcode file.
@@ -67,8 +33,9 @@ enum Level {
/// This allows wrapper tools for Clang to get diagnostics from Clang
/// (via libclang) without needing to parse Clang's command line output.
///
-DiagnosticConsumer *create(raw_ostream *OS,
- DiagnosticOptions *diags);
+std::unique_ptr<DiagnosticConsumer> create(StringRef OutputFile,
+ DiagnosticOptions *Diags,
+ bool MergeChildRecords = false);
} // end serialized_diags namespace
} // end clang namespace
diff --git a/include/clang/Frontend/SerializedDiagnosticReader.h b/include/clang/Frontend/SerializedDiagnosticReader.h
new file mode 100644
index 000000000000..92e99d305da5
--- /dev/null
+++ b/include/clang/Frontend/SerializedDiagnosticReader.h
@@ -0,0 +1,131 @@
+//===--- SerializedDiagnosticReader.h - Reads diagnostics -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_SERIALIZED_DIAGNOSTIC_READER_H_
+#define LLVM_CLANG_FRONTEND_SERIALIZED_DIAGNOSTIC_READER_H_
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/ErrorOr.h"
+
+namespace clang {
+namespace serialized_diags {
+
+enum class SDError {
+ CouldNotLoad = 1,
+ InvalidSignature,
+ InvalidDiagnostics,
+ MalformedTopLevelBlock,
+ MalformedSubBlock,
+ MalformedBlockInfoBlock,
+ MalformedMetadataBlock,
+ MalformedDiagnosticBlock,
+ MalformedDiagnosticRecord,
+ MissingVersion,
+ VersionMismatch,
+ UnsupportedConstruct,
+ /// A generic error for subclass handlers that don't want or need to define
+ /// their own error_category.
+ HandlerFailed
+};
+
+const std::error_category &SDErrorCategory();
+
+inline std::error_code make_error_code(SDError E) {
+ return std::error_code(static_cast<int>(E), SDErrorCategory());
+}
+
+/// \brief A location that is represented in the serialized diagnostics.
+struct Location {
+ unsigned FileID;
+ unsigned Line;
+ unsigned Col;
+ unsigned Offset;
+ Location(unsigned FileID, unsigned Line, unsigned Col, unsigned Offset)
+ : FileID(FileID), Line(Line), Col(Col), Offset(Offset) {}
+};
+
+/// \brief A base class that handles reading serialized diagnostics from a file.
+///
+/// Subclasses should override the visit* methods with their logic for handling
+/// the various constructs that are found in serialized diagnostics.
+class SerializedDiagnosticReader {
+public:
+ SerializedDiagnosticReader() {}
+ virtual ~SerializedDiagnosticReader() {}
+
+ /// \brief Read the diagnostics in \c File
+ std::error_code readDiagnostics(StringRef File);
+
+private:
+ enum class Cursor;
+
+ /// \brief Read to the next record or block to process.
+ llvm::ErrorOr<Cursor> skipUntilRecordOrBlock(llvm::BitstreamCursor &Stream,
+ unsigned &BlockOrRecordId);
+
+ /// \brief Read a metadata block from \c Stream.
+ std::error_code readMetaBlock(llvm::BitstreamCursor &Stream);
+
+ /// \brief Read a diagnostic block from \c Stream.
+ std::error_code readDiagnosticBlock(llvm::BitstreamCursor &Stream);
+
+protected:
+ /// \brief Visit the start of a diagnostic block.
+ virtual std::error_code visitStartOfDiagnostic() {
+ return std::error_code();
+ };
+ /// \brief Visit the end of a diagnostic block.
+ virtual std::error_code visitEndOfDiagnostic() { return std::error_code(); };
+ /// \brief Visit a category. This associates the category \c ID to a \c Name.
+ virtual std::error_code visitCategoryRecord(unsigned ID, StringRef Name) {
+ return std::error_code();
+ };
+ /// \brief Visit a flag. This associates the flag's \c ID to a \c Name.
+ virtual std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) {
+ return std::error_code();
+ };
+ /// \brief Visit a diagnostic.
+ virtual std::error_code
+ visitDiagnosticRecord(unsigned Severity, const Location &Location,
+ unsigned Category, unsigned Flag, StringRef Message) {
+ return std::error_code();
+ };
+ /// \brief Visit a filename. This associates the file's \c ID to a \c Name.
+ virtual std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
+ unsigned Timestamp,
+ StringRef Name) {
+ return std::error_code();
+ };
+ /// \brief Visit a fixit hint.
+ virtual std::error_code
+ visitFixitRecord(const Location &Start, const Location &End, StringRef Text) {
+ return std::error_code();
+ };
+ /// \brief Visit a source range.
+ virtual std::error_code visitSourceRangeRecord(const Location &Start,
+ const Location &End) {
+ return std::error_code();
+ };
+ /// \brief Visit the version of the set of diagnostics.
+ virtual std::error_code visitVersionRecord(unsigned Version) {
+ return std::error_code();
+ };
+};
+
+} // end serialized_diags namespace
+} // end clang namespace
+
+namespace std {
+template <>
+struct is_error_code_enum<clang::serialized_diags::SDError> : std::true_type {};
+}
+
+#endif
diff --git a/include/clang/Frontend/SerializedDiagnostics.h b/include/clang/Frontend/SerializedDiagnostics.h
new file mode 100644
index 000000000000..2032cd3988db
--- /dev/null
+++ b/include/clang/Frontend/SerializedDiagnostics.h
@@ -0,0 +1,59 @@
+//===--- SerializedDiagnostics.h - Common data for serialized diagnostics -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTICS_H_
+#define LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTICS_H_
+
+#include "llvm/Bitcode/BitCodes.h"
+
+namespace clang {
+namespace serialized_diags {
+
+enum BlockIDs {
+ /// \brief A top-level block which represents any meta data associated
+ /// with the diagostics, including versioning of the format.
+ BLOCK_META = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+
+ /// \brief The this block acts as a container for all the information
+ /// for a specific diagnostic.
+ BLOCK_DIAG
+};
+
+enum RecordIDs {
+ RECORD_VERSION = 1,
+ RECORD_DIAG,
+ RECORD_SOURCE_RANGE,
+ RECORD_DIAG_FLAG,
+ RECORD_CATEGORY,
+ RECORD_FILENAME,
+ RECORD_FIXIT,
+ RECORD_FIRST = RECORD_VERSION,
+ RECORD_LAST = RECORD_FIXIT
+};
+
+/// \brief A stable version of DiagnosticIDs::Level.
+///
+/// Do not change the order of values in this enum, and please increment the
+/// serialized diagnostics version number when you add to it.
+enum Level {
+ Ignored = 0,
+ Note,
+ Warning,
+ Error,
+ Fatal,
+ Remark
+};
+
+/// \brief The serialized diagnostics version number.
+enum { VersionNumber = 2 };
+
+} // end serialized_diags namespace
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Frontend/TextDiagnostic.h b/include/clang/Frontend/TextDiagnostic.h
index acebb90b7076..42c78af1d2b0 100644
--- a/include/clang/Frontend/TextDiagnostic.h
+++ b/include/clang/Frontend/TextDiagnostic.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_H_
-#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_H_
+#ifndef LLVM_CLANG_FRONTEND_TEXTDIAGNOSTIC_H
+#define LLVM_CLANG_FRONTEND_TEXTDIAGNOSTIC_H
#include "clang/Frontend/DiagnosticRenderer.h"
diff --git a/include/clang/Frontend/TextDiagnosticBuffer.h b/include/clang/Frontend/TextDiagnosticBuffer.h
index fe5aa3e91d7f..3bcf824455e2 100644
--- a/include/clang/Frontend/TextDiagnosticBuffer.h
+++ b/include/clang/Frontend/TextDiagnosticBuffer.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_BUFFER_H_
-#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_BUFFER_H_
+#ifndef LLVM_CLANG_FRONTEND_TEXTDIAGNOSTICBUFFER_H
+#define LLVM_CLANG_FRONTEND_TEXTDIAGNOSTICBUFFER_H
#include "clang/Basic/Diagnostic.h"
#include <vector>
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index 9f6d5ff9dd17..f8a71fe5e0f6 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_PRINTER_H_
-#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_PRINTER_H_
+#ifndef LLVM_CLANG_FRONTEND_TEXTDIAGNOSTICPRINTER_H
+#define LLVM_CLANG_FRONTEND_TEXTDIAGNOSTICPRINTER_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 4c0a7b7a9c66..4cd93b994fe4 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -125,7 +125,7 @@ class ModuleDependencyCollector {
public:
StringRef getDest() { return DestDir; }
- bool insertSeen(StringRef Filename) { return Seen.insert(Filename); }
+ bool insertSeen(StringRef Filename) { return Seen.insert(Filename).second; }
void setHasErrors() { HasErrors = true; }
void addFileMapping(StringRef VPath, StringRef RPath) {
VFSWriter.addFileMapping(VPath, RPath);
@@ -206,6 +206,9 @@ inline uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args,
// global objects, but we don't want LeakDetectors to complain, so we bury them
// in a globally visible array.
void BuryPointer(const void *Ptr);
+template <typename T> void BuryPointer(std::unique_ptr<T> Ptr) {
+ BuryPointer(Ptr.release());
+}
} // end namespace clang
diff --git a/include/clang/Frontend/VerifyDiagnosticConsumer.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h
index 9273fac50910..80e140bc5023 100644
--- a/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICSCLIENT_H
-#define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICSCLIENT_H
+#ifndef LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
+#define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Lex/Preprocessor.h"
@@ -145,9 +145,12 @@ public:
///
class Directive {
public:
- static Directive *create(bool RegexKind, SourceLocation DirectiveLoc,
- SourceLocation DiagnosticLoc, bool MatchAnyLine,
- StringRef Text, unsigned Min, unsigned Max);
+ static std::unique_ptr<Directive> create(bool RegexKind,
+ SourceLocation DirectiveLoc,
+ SourceLocation DiagnosticLoc,
+ bool MatchAnyLine, StringRef Text,
+ unsigned Min, unsigned Max);
+
public:
/// Constant representing n or more matches.
static const unsigned MaxCount = UINT_MAX;
@@ -181,7 +184,7 @@ public:
void operator=(const Directive &) LLVM_DELETED_FUNCTION;
};
- typedef std::vector<Directive*> DirectiveList;
+ typedef std::vector<std::unique_ptr<Directive>> DirectiveList;
/// ExpectedData - owns directive objects and deletes on destructor.
///
@@ -192,13 +195,11 @@ public:
DirectiveList Notes;
void Reset() {
- llvm::DeleteContainerPointers(Errors);
- llvm::DeleteContainerPointers(Warnings);
- llvm::DeleteContainerPointers(Remarks);
- llvm::DeleteContainerPointers(Notes);
+ Errors.clear();
+ Warnings.clear();
+ Remarks.clear();
+ Notes.clear();
}
-
- ~ExpectedData() { Reset(); }
};
enum DirectiveStatus {
@@ -211,7 +212,7 @@ public:
private:
DiagnosticsEngine &Diags;
DiagnosticConsumer *PrimaryClient;
- bool OwnsPrimaryClient;
+ std::unique_ptr<DiagnosticConsumer> PrimaryClientOwner;
std::unique_ptr<TextDiagnosticBuffer> Buffer;
const Preprocessor *CurrentPreprocessor;
const LangOptions *LangOpts;
diff --git a/include/clang/Lex/ExternalPreprocessorSource.h b/include/clang/Lex/ExternalPreprocessorSource.h
index d9a4de4d9981..2f9231dc9f22 100644
--- a/include/clang/Lex/ExternalPreprocessorSource.h
+++ b/include/clang/Lex/ExternalPreprocessorSource.h
@@ -11,8 +11,8 @@
// construction of macro definitions from some external source.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H
-#define LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H
+#ifndef LLVM_CLANG_LEX_EXTERNALPREPROCESSORSOURCE_H
+#define LLVM_CLANG_LEX_EXTERNALPREPROCESSORSOURCE_H
namespace clang {
@@ -36,4 +36,4 @@ public:
}
-#endif // LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H
+#endif
diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h
index 8e78b5ac9884..993c8612b0f8 100644
--- a/include/clang/Lex/HeaderMap.h
+++ b/include/clang/Lex/HeaderMap.h
@@ -16,6 +16,7 @@
#include "clang/Basic/LLVM.h"
#include "llvm/Support/Compiler.h"
+#include <memory>
namespace llvm {
class MemoryBuffer;
@@ -34,15 +35,12 @@ class HeaderMap {
HeaderMap(const HeaderMap &) LLVM_DELETED_FUNCTION;
void operator=(const HeaderMap &) LLVM_DELETED_FUNCTION;
- const llvm::MemoryBuffer *FileBuffer;
+ std::unique_ptr<const llvm::MemoryBuffer> FileBuffer;
bool NeedsBSwap;
- HeaderMap(const llvm::MemoryBuffer *File, bool BSwap)
- : FileBuffer(File), NeedsBSwap(BSwap) {
- }
+ HeaderMap(std::unique_ptr<const llvm::MemoryBuffer> File, bool BSwap)
+ : FileBuffer(std::move(File)), NeedsBSwap(BSwap) {}
public:
- ~HeaderMap();
-
/// HeaderMap::Create - This attempts to load the specified file as a header
/// map. If it doesn't look like a HeaderMap, it gives up and returns null.
static const HeaderMap *Create(const FileEntry *FE, FileManager &FM);
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 034262982770..158f67d40b49 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -231,7 +231,11 @@ class HeaderSearch {
/// \brief Describes whether a given directory has a module map in it.
llvm::DenseMap<const DirectoryEntry *, bool> DirectoryHasModuleMap;
-
+
+ /// \brief Set of module map files we've already loaded, and a flag indicating
+ /// whether they were valid or not.
+ llvm::DenseMap<const FileEntry *, bool> LoadedModuleMaps;
+
/// \brief Uniqued set of framework names, which is used to track which
/// headers were included as framework headers.
llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames;
@@ -248,7 +252,7 @@ class HeaderSearch {
unsigned NumMultiIncludeFileOptzn;
unsigned NumFrameworkLookups, NumSubFrameworkLookups;
- bool EnabledModules;
+ const LangOptions &LangOpts;
// HeaderSearch doesn't support default or copy construction.
HeaderSearch(const HeaderSearch&) LLVM_DELETED_FUNCTION;
@@ -384,14 +388,12 @@ public:
/// \param SuggestedModule If non-null, and the file found is semantically
/// part of a known module, this will be set to the module that should
/// be imported instead of preprocessing/parsing the file found.
- const FileEntry *LookupFile(StringRef Filename, SourceLocation IncludeLoc,
- bool isAngled, const DirectoryLookup *FromDir,
- const DirectoryLookup *&CurDir,
- ArrayRef<const FileEntry *> Includers,
- SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath,
- ModuleMap::KnownHeader *SuggestedModule,
- bool SkipCache = false);
+ const FileEntry *LookupFile(
+ StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
+ const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
+ ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
+ SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
+ ModuleMap::KnownHeader *SuggestedModule, bool SkipCache = false);
/// \brief Look up a subframework for the specified \#include file.
///
@@ -409,7 +411,7 @@ public:
/// \brief Look up the specified framework name in our framework cache.
/// \returns The DirectoryEntry it is in if we know, null otherwise.
FrameworkCacheEntry &LookupFrameworkCache(StringRef FWName) {
- return FrameworkMap.GetOrCreateValue(FWName).getValue();
+ return FrameworkMap[FWName];
}
/// \brief Mark the specified file as a target of of a \#include,
@@ -477,7 +479,7 @@ public:
const HeaderMap *CreateHeaderMap(const FileEntry *FE);
/// Returns true if modules are enabled.
- bool enabledModules() const { return EnabledModules; }
+ bool enabledModules() const { return LangOpts.Modules; }
/// \brief Retrieve the name of the module file that should be used to
/// load the given module.
@@ -638,7 +640,8 @@ private:
};
LoadModuleMapResult loadModuleMapFileImpl(const FileEntry *File,
- bool IsSystem);
+ bool IsSystem,
+ const DirectoryEntry *Dir);
/// \brief Try to load the module map file in the given directory.
///
diff --git a/include/clang/Lex/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h
index 06024b2e90f2..775943de8169 100644
--- a/include/clang/Lex/HeaderSearchOptions.h
+++ b/include/clang/Lex/HeaderSearchOptions.h
@@ -101,6 +101,15 @@ public:
/// \brief Interpret module maps. This option is implied by full modules.
unsigned ModuleMaps : 1;
+ /// \brief Set the 'home directory' of a module map file to the current
+ /// working directory (or the home directory of the module map file that
+ /// contained the 'extern module' directive importing this module map file
+ /// if any) rather than the directory containing the module map file.
+ //
+ /// The home directory is where we look for files named in the module map
+ /// file.
+ unsigned ModuleMapFileHomeIsCwd : 1;
+
/// \brief The interval (in seconds) between pruning operations.
///
/// This operation is expensive, because it requires Clang to walk through
@@ -129,9 +138,6 @@ public:
/// of computing the module hash.
llvm::SetVector<std::string> ModulesIgnoreMacros;
- /// \brief The set of user-provided module-map-files.
- llvm::SetVector<std::string> ModuleMapFiles;
-
/// \brief The set of user-provided virtual filesystem overlay files.
std::vector<std::string> VFSOverlayFiles;
@@ -161,6 +167,7 @@ public:
public:
HeaderSearchOptions(StringRef _Sysroot = "/")
: Sysroot(_Sysroot), DisableModuleHash(0), ModuleMaps(0),
+ ModuleMapFileHomeIsCwd(0),
ModuleCachePruneInterval(7*24*60*60),
ModuleCachePruneAfter(31*24*60*60),
BuildSessionTimestamp(0),
diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h
index 85424aa8a10f..5d724c0de879 100644
--- a/include/clang/Lex/LexDiagnostic.h
+++ b/include/clang/Lex/LexDiagnostic.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_DIAGNOSTICLEX_H
-#define LLVM_CLANG_DIAGNOSTICLEX_H
+#ifndef LLVM_CLANG_LEX_LEXDIAGNOSTIC_H
+#define LLVM_CLANG_LEX_LEXDIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index edcf883eced3..c1f968be5584 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LEXER_H
-#define LLVM_CLANG_LEXER_H
+#ifndef LLVM_CLANG_LEX_LEXER_H
+#define LLVM_CLANG_LEX_LEXER_H
#include "clang/Basic/LangOptions.h"
#include "clang/Lex/PreprocessorLexer.h"
@@ -405,9 +405,9 @@ public:
/// \returns The offset into the file where the preamble ends and the rest
/// of the file begins along with a boolean value indicating whether
/// the preamble ends at the beginning of a new line.
- static std::pair<unsigned, bool>
- ComputePreamble(const llvm::MemoryBuffer *Buffer, const LangOptions &LangOpts,
- unsigned MaxLines = 0);
+ static std::pair<unsigned, bool> ComputePreamble(StringRef Buffer,
+ const LangOptions &LangOpts,
+ unsigned MaxLines = 0);
/// \brief Checks that the given token is the first token that occurs after
/// the given location (this excludes comments and whitespace). Returns the
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index b7fcc5d34de6..f60a152a0aa9 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_LITERALSUPPORT_H
-#define CLANG_LITERALSUPPORT_H
+#ifndef LLVM_CLANG_LEX_LITERALSUPPORT_H
+#define LLVM_CLANG_LEX_LITERALSUPPORT_H
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LLVM.h"
diff --git a/include/clang/Lex/MacroArgs.h b/include/clang/Lex/MacroArgs.h
index 4c0120c77f04..d858ec2b4292 100644
--- a/include/clang/Lex/MacroArgs.h
+++ b/include/clang/Lex/MacroArgs.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_MACROARGS_H
-#define LLVM_CLANG_MACROARGS_H
+#ifndef LLVM_CLANG_LEX_MACROARGS_H
+#define LLVM_CLANG_LEX_MACROARGS_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index e9a66e857dbc..ca5d49704877 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -12,10 +12,11 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_MACROINFO_H
-#define LLVM_CLANG_MACROINFO_H
+#ifndef LLVM_CLANG_LEX_MACROINFO_H
+#define LLVM_CLANG_LEX_MACROINFO_H
#include "clang/Lex/Token.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include <cassert>
@@ -45,7 +46,7 @@ class MacroInfo {
/// \see ArgumentList
unsigned NumArguments;
-
+
/// \brief This is the list of tokens that the macro is defined to.
SmallVector<Token, 8> ReplacementTokens;
@@ -78,8 +79,7 @@ class MacroInfo {
/// \brief Whether this macro contains the sequence ", ## __VA_ARGS__"
bool HasCommaPasting : 1;
-
-private:
+
//===--------------------------------------------------------------------===//
// State that changes as the macro is used.
@@ -107,28 +107,11 @@ private:
/// \brief Whether this macro was used as header guard.
bool UsedForHeaderGuard : 1;
- ~MacroInfo() {
- assert(!ArgumentList && "Didn't call destroy before dtor!");
- }
-
-public:
+ // Only the Preprocessor gets to create and destroy these.
MacroInfo(SourceLocation DefLoc);
-
- /// \brief Free the argument list of the macro.
- ///
- /// This restores this MacroInfo to a state where it can be reused for other
- /// devious purposes.
- void FreeArgumentList() {
- ArgumentList = nullptr;
- NumArguments = 0;
- }
-
- /// \brief Destroy this MacroInfo object.
- void Destroy() {
- FreeArgumentList();
- this->~MacroInfo();
- }
+ ~MacroInfo() {}
+public:
/// \brief Return the location that the macro was defined at.
SourceLocation getDefinitionLoc() const { return Location; }
@@ -350,9 +333,6 @@ protected:
// Used by DefMacroDirective -----------------------------------------------//
- /// \brief True if this macro was imported from a module.
- bool IsImported : 1;
-
/// \brief Whether the definition of this macro is ambiguous, due to
/// multiple definitions coming in from multiple modules.
bool IsAmbiguous : 1;
@@ -363,11 +343,35 @@ protected:
/// module).
bool IsPublic : 1;
- MacroDirective(Kind K, SourceLocation Loc)
- : Previous(nullptr), Loc(Loc), MDKind(K), IsFromPCH(false),
- IsImported(false), IsAmbiguous(false),
- IsPublic(true) {
- }
+ // Used by DefMacroDirective and UndefMacroDirective -----------------------//
+
+ /// \brief True if this macro was imported from a module.
+ bool IsImported : 1;
+
+ /// \brief For an imported directive, the number of modules whose macros are
+ /// overridden by this directive. Only used if IsImported.
+ unsigned NumOverrides : 26;
+
+ unsigned *getModuleDataStart();
+ const unsigned *getModuleDataStart() const {
+ return const_cast<MacroDirective*>(this)->getModuleDataStart();
+ }
+
+ MacroDirective(Kind K, SourceLocation Loc,
+ unsigned ImportedFromModuleID = 0,
+ ArrayRef<unsigned> Overrides = None)
+ : Previous(nullptr), Loc(Loc), MDKind(K), IsFromPCH(false),
+ IsAmbiguous(false), IsPublic(true), IsImported(ImportedFromModuleID),
+ NumOverrides(Overrides.size()) {
+ assert(NumOverrides == Overrides.size() && "too many overrides");
+ assert((IsImported || !NumOverrides) && "overrides for non-module macro");
+
+ if (IsImported) {
+ unsigned *Extra = getModuleDataStart();
+ *Extra++ = ImportedFromModuleID;
+ std::copy(Overrides.begin(), Overrides.end(), Extra);
+ }
+ }
public:
Kind getKind() const { return Kind(MDKind); }
@@ -390,6 +394,27 @@ public:
void setIsFromPCH() { IsFromPCH = true; }
+ /// \brief True if this macro was imported from a module.
+ /// Note that this is never the case for a VisibilityMacroDirective.
+ bool isImported() const { return IsImported; }
+
+ /// \brief If this directive was imported from a module, get the submodule
+ /// whose directive this is. Note that this may be different from the module
+ /// that owns the MacroInfo for a DefMacroDirective due to #pragma pop_macro
+ /// and similar effects.
+ unsigned getOwningModuleID() const {
+ if (isImported())
+ return *getModuleDataStart();
+ return 0;
+ }
+
+ /// \brief Get the module IDs of modules whose macros are overridden by this
+ /// directive. Only valid if this is an imported directive.
+ ArrayRef<unsigned> getOverriddenModules() const {
+ assert(IsImported && "can only get overridden modules for imported macro");
+ return llvm::makeArrayRef(getModuleDataStart() + 1, NumOverrides);
+ }
+
class DefInfo {
DefMacroDirective *DefDirective;
SourceLocation UndefLoc;
@@ -463,23 +488,22 @@ class DefMacroDirective : public MacroDirective {
public:
explicit DefMacroDirective(MacroInfo *MI)
- : MacroDirective(MD_Define, MI->getDefinitionLoc()), Info(MI) {
+ : MacroDirective(MD_Define, MI->getDefinitionLoc()), Info(MI) {
assert(MI && "MacroInfo is null");
}
- DefMacroDirective(MacroInfo *MI, SourceLocation Loc, bool isImported)
- : MacroDirective(MD_Define, Loc), Info(MI) {
+ DefMacroDirective(MacroInfo *MI, SourceLocation Loc,
+ unsigned ImportedFromModuleID = 0,
+ ArrayRef<unsigned> Overrides = None)
+ : MacroDirective(MD_Define, Loc, ImportedFromModuleID, Overrides),
+ Info(MI) {
assert(MI && "MacroInfo is null");
- IsImported = isImported;
}
/// \brief The data for the macro definition.
const MacroInfo *getInfo() const { return Info; }
MacroInfo *getInfo() { return Info; }
- /// \brief True if this macro was imported from a module.
- bool isImported() const { return IsImported; }
-
/// \brief Determine whether this macro definition is ambiguous with
/// other macro definitions.
bool isAmbiguous() const { return IsAmbiguous; }
@@ -496,9 +520,11 @@ public:
/// \brief A directive for an undefined macro.
class UndefMacroDirective : public MacroDirective {
public:
- explicit UndefMacroDirective(SourceLocation UndefLoc)
- : MacroDirective(MD_Undefine, UndefLoc) {
- assert(UndefLoc.isValid() && "Invalid UndefLoc!");
+ explicit UndefMacroDirective(SourceLocation UndefLoc,
+ unsigned ImportedFromModuleID = 0,
+ ArrayRef<unsigned> Overrides = None)
+ : MacroDirective(MD_Undefine, UndefLoc, ImportedFromModuleID, Overrides) {
+ assert((UndefLoc.isValid() || ImportedFromModuleID) && "Invalid UndefLoc!");
}
static bool classof(const MacroDirective *MD) {
@@ -525,6 +551,13 @@ public:
static bool classof(const VisibilityMacroDirective *) { return true; }
};
+inline unsigned *MacroDirective::getModuleDataStart() {
+ if (auto *Def = dyn_cast<DefMacroDirective>(this))
+ return reinterpret_cast<unsigned*>(Def + 1);
+ else
+ return reinterpret_cast<unsigned*>(cast<UndefMacroDirective>(this) + 1);
+}
+
inline SourceLocation MacroDirective::DefInfo::getLocation() const {
if (isInvalid())
return SourceLocation();
diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h
index 7869799c2c54..36605c9c18c6 100644
--- a/include/clang/Lex/ModuleLoader.h
+++ b/include/clang/Lex/ModuleLoader.h
@@ -11,8 +11,8 @@
// loading named modules.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LEX_MODULE_LOADER_H
-#define LLVM_CLANG_LEX_MODULE_LOADER_H
+#ifndef LLVM_CLANG_LEX_MODULELOADER_H
+#define LLVM_CLANG_LEX_MODULELOADER_H
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h
index a86a92749959..ed885a7410d5 100644
--- a/include/clang/Lex/ModuleMap.h
+++ b/include/clang/Lex/ModuleMap.h
@@ -65,19 +65,21 @@ private:
llvm::StringMap<Module *> Modules;
public:
- /// \brief Describes the role of a module header.
+ /// \brief Flags describing the role of a module header.
enum ModuleHeaderRole {
/// \brief This header is normally included in the module.
- NormalHeader,
+ NormalHeader = 0x0,
/// \brief This header is included but private.
- PrivateHeader,
- /// \brief This header is explicitly excluded from the module.
- ExcludedHeader
+ PrivateHeader = 0x1,
+ /// \brief This header is part of the module (for layering purposes) but
+ /// should be textually included.
+ TextualHeader = 0x2,
// Caution: Adding an enumerator needs other changes.
// Adjust the number of bits for KnownHeader::Storage.
// Adjust the bitfield HeaderFileInfo::HeaderRole size.
// Adjust the HeaderFileInfoTrait::ReadData streaming.
// Adjust the HeaderFileInfoTrait::EmitData streaming.
+ // Adjust ModuleMap::addHeader.
};
/// \brief A header that is known to reside within a given module,
@@ -96,8 +98,8 @@ public:
ModuleHeaderRole getRole() const { return Storage.getInt(); }
/// \brief Whether this header is available in the module.
- bool isAvailable() const {
- return getRole() != ExcludedHeader && getModule()->isAvailable();
+ bool isAvailable() const {
+ return getModule()->isAvailable();
}
// \brief Whether this known header is valid (i.e., it has an
@@ -107,6 +109,8 @@ public:
}
};
+ typedef llvm::SmallPtrSet<const FileEntry *, 1> AdditionalModMapsSet;
+
private:
typedef llvm::DenseMap<const FileEntry *, SmallVector<KnownHeader, 1> >
HeadersMap;
@@ -123,15 +127,29 @@ private:
/// header.
llvm::DenseMap<const DirectoryEntry *, Module *> UmbrellaDirs;
+ /// \brief The set of attributes that can be attached to a module.
+ struct Attributes {
+ Attributes() : IsSystem(), IsExternC(), IsExhaustive() {}
+
+ /// \brief Whether this is a system module.
+ unsigned IsSystem : 1;
+
+ /// \brief Whether this is an extern "C" module.
+ unsigned IsExternC : 1;
+
+ /// \brief Whether this is an exhaustive set of configuration macros.
+ unsigned IsExhaustive : 1;
+ };
+
/// \brief A directory for which framework modules can be inferred.
struct InferredDirectory {
- InferredDirectory() : InferModules(), InferSystemModules() { }
+ InferredDirectory() : InferModules() {}
/// \brief Whether to infer modules from this directory.
unsigned InferModules : 1;
- /// \brief Whether the modules we infer are [system] modules.
- unsigned InferSystemModules : 1;
+ /// \brief The attributes to use for inferred modules.
+ Attributes Attrs;
/// \brief If \c InferModules is non-zero, the module map file that allowed
/// inferred modules. Otherwise, nullptr.
@@ -146,6 +164,12 @@ private:
/// framework modules from within those directories.
llvm::DenseMap<const DirectoryEntry *, InferredDirectory> InferredDirectories;
+ /// A mapping from an inferred module to the module map that allowed the
+ /// inference.
+ llvm::DenseMap<const Module *, const FileEntry *> InferredModuleAllowedBy;
+
+ llvm::DenseMap<const Module *, AdditionalModMapsSet> AdditionalModMaps;
+
/// \brief Describes whether we haved parsed a particular file as a module
/// map.
llvm::DenseMap<const FileEntry *, bool> ParsedModuleMap;
@@ -204,6 +228,10 @@ private:
return static_cast<bool>(findHeaderInUmbrellaDirs(File, IntermediateDirs));
}
+ Module *inferFrameworkModule(StringRef ModuleName,
+ const DirectoryEntry *FrameworkDir,
+ Attributes Attrs, Module *Parent);
+
public:
/// \brief Construct a new module map.
///
@@ -241,11 +269,16 @@ public:
/// used from. Used to disambiguate if a header is present in multiple
/// modules.
///
+ /// \param IncludeTextualHeaders If \c true, also find textual headers. By
+ /// default, these are treated like excluded headers and result in no known
+ /// header being found.
+ ///
/// \returns The module KnownHeader, which provides the module that owns the
/// given header file. The KnownHeader is default constructed to indicate
/// that no module owns this header file.
KnownHeader findModuleForHeader(const FileEntry *File,
- Module *RequestingModule = nullptr);
+ Module *RequestingModule = nullptr,
+ bool IncludeTextualHeaders = false);
/// \brief Reports errors if a module must not include a specific file.
///
@@ -306,9 +339,6 @@ public:
/// \param Parent The module that will act as the parent of this submodule,
/// or NULL to indicate that this is a top-level module.
///
- /// \param ModuleMap The module map that defines or allows the inference of
- /// this module.
- ///
/// \param IsFramework Whether this is a framework module.
///
/// \param IsExplicit Whether this is an explicit submodule.
@@ -316,26 +346,9 @@ public:
/// \returns The found or newly-created module, along with a boolean value
/// that will be true if the module is newly-created.
std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent,
- const FileEntry *ModuleMap,
bool IsFramework,
bool IsExplicit);
- /// \brief Determine whether we can infer a framework module a framework
- /// with the given name in the given
- ///
- /// \param ParentDir The directory that is the parent of the framework
- /// directory.
- ///
- /// \param Name The name of the module.
- ///
- /// \param IsSystem Will be set to 'true' if the inferred module must be a
- /// system module.
- ///
- /// \returns true if we are allowed to infer a framework module, and false
- /// otherwise.
- bool canInferFrameworkModule(const DirectoryEntry *ParentDir,
- StringRef Name, bool &IsSystem) const;
-
/// \brief Infer the contents of a framework module map from the given
/// framework directory.
Module *inferFrameworkModule(StringRef ModuleName,
@@ -349,7 +362,35 @@ public:
///
/// \returns The file entry for the module map file containing the given
/// module, or NULL if the module definition was inferred.
- const FileEntry *getContainingModuleMapFile(Module *Module) const;
+ const FileEntry *getContainingModuleMapFile(const Module *Module) const;
+
+ /// \brief Get the module map file that (along with the module name) uniquely
+ /// identifies this module.
+ ///
+ /// The particular module that \c Name refers to may depend on how the module
+ /// was found in header search. However, the combination of \c Name and
+ /// this module map will be globally unique for top-level modules. In the case
+ /// of inferred modules, returns the module map that allowed the inference
+ /// (e.g. contained 'module *'). Otherwise, returns
+ /// getContainingModuleMapFile().
+ const FileEntry *getModuleMapFileForUniquing(const Module *M) const;
+
+ void setInferredModuleAllowedBy(Module *M, const FileEntry *ModuleMap);
+
+ /// \brief Get any module map files other than getModuleMapFileForUniquing(M)
+ /// that define submodules of a top-level module \p M. This is cheaper than
+ /// getting the module map file for each submodule individually, since the
+ /// expected number of results is very small.
+ AdditionalModMapsSet *getAdditionalModuleMapFiles(const Module *M) {
+ auto I = AdditionalModMaps.find(M);
+ if (I == AdditionalModMaps.end())
+ return nullptr;
+ return &I->second;
+ }
+
+ void addAdditionalModuleMapFile(const Module *M, const FileEntry *ModuleMap) {
+ AdditionalModMaps[M].insert(ModuleMap);
+ }
/// \brief Resolve all of the unresolved exports in the given module.
///
@@ -401,9 +442,12 @@ public:
/// \brief Adds this header to the given module.
/// \param Role The role of the header wrt the module.
- void addHeader(Module *Mod, const FileEntry *Header,
+ void addHeader(Module *Mod, Module::Header Header,
ModuleHeaderRole Role);
+ /// \brief Marks this header as being excluded from the given module.
+ void excludeHeader(Module *Mod, Module::Header Header);
+
/// \brief Parse the given module map file, and record any modules we
/// encounter.
///
@@ -412,8 +456,12 @@ public:
/// \param IsSystem Whether this module map file is in a system header
/// directory, and therefore should be considered a system module.
///
+ /// \param HomeDir The directory in which relative paths within this module
+ /// map file will be resolved.
+ ///
/// \returns true if an error occurred, false otherwise.
- bool parseModuleMapFile(const FileEntry *File, bool IsSystem);
+ bool parseModuleMapFile(const FileEntry *File, bool IsSystem,
+ const DirectoryEntry *HomeDir);
/// \brief Dump the contents of the module map, for debugging purposes.
void dump();
diff --git a/include/clang/Lex/MultipleIncludeOpt.h b/include/clang/Lex/MultipleIncludeOpt.h
index e3c6de555b35..83e6f99078df 100644
--- a/include/clang/Lex/MultipleIncludeOpt.h
+++ b/include/clang/Lex/MultipleIncludeOpt.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H
-#define LLVM_CLANG_MULTIPLEINCLUDEOPT_H
+#ifndef LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H
+#define LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H
#include "clang/Basic/SourceLocation.h"
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index 7f1ea34a460e..056c58aa3348 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -322,15 +322,12 @@ public:
/// \brief Simple wrapper class for chaining callbacks.
class PPChainedCallbacks : public PPCallbacks {
virtual void anchor();
- PPCallbacks *First, *Second;
+ std::unique_ptr<PPCallbacks> First, Second;
public:
- PPChainedCallbacks(PPCallbacks *_First, PPCallbacks *_Second)
- : First(_First), Second(_Second) {}
- ~PPChainedCallbacks() {
- delete Second;
- delete First;
- }
+ PPChainedCallbacks(std::unique_ptr<PPCallbacks> _First,
+ std::unique_ptr<PPCallbacks> _Second)
+ : First(std::move(_First)), Second(std::move(_Second)) {}
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h
index 2352ccea1853..54c91f6b0860 100644
--- a/include/clang/Lex/PTHLexer.h
+++ b/include/clang/Lex/PTHLexer.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PTHLEXER_H
-#define LLVM_CLANG_PTHLEXER_H
+#ifndef LLVM_CLANG_LEX_PTHLEXER_H
+#define LLVM_CLANG_LEX_PTHLEXER_H
#include "clang/Lex/PreprocessorLexer.h"
diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h
index 11b5ceaad1de..64ecf5f575f3 100644
--- a/include/clang/Lex/PTHManager.h
+++ b/include/clang/Lex/PTHManager.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PTHMANAGER_H
-#define LLVM_CLANG_PTHMANAGER_H
+#ifndef LLVM_CLANG_LEX_PTHMANAGER_H
+#define LLVM_CLANG_LEX_PTHMANAGER_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
@@ -20,6 +20,7 @@
#include "clang/Lex/PTHLexer.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/OnDiskHashTable.h"
#include <string>
namespace llvm {
@@ -36,19 +37,26 @@ class FileSystemStatCache;
class PTHManager : public IdentifierInfoLookup {
friend class PTHLexer;
+ friend class PTHStatCache;
+
+ class PTHStringLookupTrait;
+ class PTHFileLookupTrait;
+ typedef llvm::OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup;
+ typedef llvm::OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup;
+
/// The memory mapped PTH file.
- const llvm::MemoryBuffer* Buf;
+ std::unique_ptr<const llvm::MemoryBuffer> Buf;
/// Alloc - Allocator used for IdentifierInfo objects.
llvm::BumpPtrAllocator Alloc;
/// IdMap - A lazily generated cache mapping from persistent identifiers to
/// IdentifierInfo*.
- IdentifierInfo** PerIDCache;
+ std::unique_ptr<IdentifierInfo *[], llvm::FreeDeleter> PerIDCache;
/// FileLookup - Abstract data structure used for mapping between files
/// and token data in the PTH file.
- void* FileLookup;
+ std::unique_ptr<PTHFileLookup> FileLookup;
/// IdDataTable - Array representing the mapping from persistent IDs to the
/// data offset within the PTH file containing the information to
@@ -57,7 +65,7 @@ class PTHManager : public IdentifierInfoLookup {
/// SortedIdTable - Abstract data structure mapping from strings to
/// persistent IDs. This is used by get().
- void* StringIdLookup;
+ std::unique_ptr<PTHStringIdLookup> StringIdLookup;
/// NumIds - The number of identifiers in the PTH file.
const unsigned NumIds;
@@ -76,10 +84,12 @@ class PTHManager : public IdentifierInfoLookup {
/// This constructor is intended to only be called by the static 'Create'
/// method.
- PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup,
- const unsigned char* idDataTable, IdentifierInfo** perIDCache,
- void* stringIdLookup, unsigned numIds,
- const unsigned char* spellingBase, const char *originalSourceFile);
+ PTHManager(std::unique_ptr<const llvm::MemoryBuffer> buf,
+ std::unique_ptr<PTHFileLookup> fileLookup,
+ const unsigned char *idDataTable,
+ std::unique_ptr<IdentifierInfo *[], llvm::FreeDeleter> perIDCache,
+ std::unique_ptr<PTHStringIdLookup> stringIdLookup, unsigned numIds,
+ const unsigned char *spellingBase, const char *originalSourceFile);
PTHManager(const PTHManager &) LLVM_DELETED_FUNCTION;
void operator=(const PTHManager &) LLVM_DELETED_FUNCTION;
@@ -131,7 +141,7 @@ public:
/// FileManager objects. These objects use the PTH data to speed up
/// calls to stat by memoizing their results from when the PTH file
/// was generated.
- FileSystemStatCache *createStatCache();
+ std::unique_ptr<FileSystemStatCache> createStatCache();
};
} // end namespace clang
diff --git a/include/clang/Lex/Pragma.h b/include/clang/Lex/Pragma.h
index 4a695a0e901c..4123bae2ea3a 100644
--- a/include/clang/Lex/Pragma.h
+++ b/include/clang/Lex/Pragma.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PRAGMA_H
-#define LLVM_CLANG_PRAGMA_H
+#ifndef LLVM_CLANG_LEX_PRAGMA_H
+#define LLVM_CLANG_LEX_PRAGMA_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringMap.h"
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index d4b4ba246961..326f519e914e 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -79,6 +79,13 @@ public:
}
};
+/// \brief Context in which macro name is used.
+enum MacroUse {
+ MU_Other = 0, // other than #define or #undef
+ MU_Define = 1, // macro name specified in #define
+ MU_Undef = 2 // macro name specified in #undef
+};
+
/// \brief Engages in a tight little dance with the lexer to efficiently
/// preprocess tokens.
///
@@ -92,7 +99,7 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
const TargetInfo *Target;
FileManager &FileMgr;
SourceManager &SourceMgr;
- ScratchBuffer *ScratchBuf;
+ std::unique_ptr<ScratchBuffer> ScratchBuf;
HeaderSearch &HeaderInfo;
ModuleLoader &TheModuleLoader;
@@ -128,6 +135,8 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
IdentifierInfo *Ident__is_identifier; // __is_identifier
IdentifierInfo *Ident__building_module; // __building_module
IdentifierInfo *Ident__MODULE__; // __MODULE__
+ IdentifierInfo *Ident__has_cpp_attribute; // __has_cpp_attribute
+ IdentifierInfo *Ident__has_declspec; // __has_declspec_attribute
SourceLocation DATELoc, TIMELoc;
unsigned CounterValue; // Next __COUNTER__ value.
@@ -192,7 +201,11 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// \brief Tracks all of the pragmas that the client registered
/// with this preprocessor.
- PragmaNamespace *PragmaHandlers;
+ std::unique_ptr<PragmaNamespace> PragmaHandlers;
+
+ /// \brief Pragma handlers of the original source is stored here during the
+ /// parsing of a model file.
+ std::unique_ptr<PragmaNamespace> PragmaHandlersBackup;
/// \brief Tracks all of the comment handlers that the client registered
/// with this preprocessor.
@@ -245,12 +258,17 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// \brief True if we hit the code-completion point.
bool CodeCompletionReached;
+ /// \brief The directory that the main file should be considered to occupy,
+ /// if it does not correspond to a real file (as happens when building a
+ /// module).
+ const DirectoryEntry *MainFileDir;
+
/// \brief The number of bytes that we will initially skip when entering the
/// main file, along with a flag that indicates whether skipping this number
/// of bytes will place the lexer at the start of a line.
///
/// This is used when loading a precompiled preamble.
- std::pair<unsigned, bool> SkipMainFilePreamble;
+ std::pair<int, bool> SkipMainFilePreamble;
/// \brief The current top of the stack that we're lexing from if
/// not expanding a macro and we are lexing directly from source code.
@@ -334,7 +352,7 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// \brief Actions invoked when some preprocessor activity is
/// encountered (e.g. a file is \#included, etc).
- PPCallbacks *Callbacks;
+ std::unique_ptr<PPCallbacks> Callbacks;
struct MacroExpandsInfo {
Token Tok;
@@ -391,7 +409,7 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// \brief Cache of macro expanders to reduce malloc traffic.
enum { TokenLexerCacheSize = 8 };
unsigned NumCachedTokenLexers;
- TokenLexer *TokenLexerCache[TokenLexerCacheSize];
+ std::unique_ptr<TokenLexer> TokenLexerCache[TokenLexerCacheSize];
/// \}
/// \brief Keeps macro expanded tokens for TokenLexers.
@@ -433,17 +451,12 @@ private: // Cached tokens state.
struct MacroInfoChain {
MacroInfo MI;
MacroInfoChain *Next;
- MacroInfoChain *Prev;
};
/// MacroInfos are managed as a chain for easy disposal. This is the head
/// of that list.
MacroInfoChain *MIChainHead;
- /// A "freelist" of MacroInfo objects that can be reused for quick
- /// allocation.
- MacroInfoChain *MICache;
-
struct DeserializedMacroInfoChain {
MacroInfo MI;
unsigned OwningModuleID; // MUST be immediately after the MacroInfo object
@@ -469,6 +482,17 @@ public:
/// lifetime of the preprocessor.
void Initialize(const TargetInfo &Target);
+ /// \brief Initialize the preprocessor to parse a model file
+ ///
+ /// To parse model files the preprocessor of the original source is reused to
+ /// preserver the identifier table. However to avoid some duplicate
+ /// information in the preprocessor some cleanup is needed before it is used
+ /// to parse model files. This method does that cleanup.
+ void InitializeForModelFile();
+
+ /// \brief Cleanup after model file parsing
+ void FinalizeForModelFile();
+
/// \brief Retrieve the preprocessor options used to initialize this
/// preprocessor.
PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; }
@@ -557,6 +581,9 @@ public:
/// expansions going on at the time.
PreprocessorLexer *getCurrentFileLexer() const;
+ /// \brief Return the submodule owning the file being lexed.
+ Module *getCurrentSubmodule() const { return CurSubmodule; }
+
/// \brief Returns the FileID for the preprocessor predefines.
FileID getPredefinesFileID() const { return PredefinesFileID; }
@@ -565,11 +592,12 @@ public:
///
/// Note that this class takes ownership of any PPCallbacks object given to
/// it.
- PPCallbacks *getPPCallbacks() const { return Callbacks; }
- void addPPCallbacks(PPCallbacks *C) {
+ PPCallbacks *getPPCallbacks() const { return Callbacks.get(); }
+ void addPPCallbacks(std::unique_ptr<PPCallbacks> C) {
if (Callbacks)
- C = new PPChainedCallbacks(C, Callbacks);
- Callbacks = C;
+ C = llvm::make_unique<PPChainedCallbacks>(std::move(C),
+ std::move(Callbacks));
+ Callbacks = std::move(C);
}
/// \}
@@ -605,13 +633,15 @@ public:
void appendMacroDirective(IdentifierInfo *II, MacroDirective *MD);
DefMacroDirective *appendDefMacroDirective(IdentifierInfo *II, MacroInfo *MI,
SourceLocation Loc,
- bool isImported) {
- DefMacroDirective *MD = AllocateDefMacroDirective(MI, Loc, isImported);
+ unsigned ImportedFromModuleID,
+ ArrayRef<unsigned> Overrides) {
+ DefMacroDirective *MD =
+ AllocateDefMacroDirective(MI, Loc, ImportedFromModuleID, Overrides);
appendMacroDirective(II, MD);
return MD;
}
DefMacroDirective *appendDefMacroDirective(IdentifierInfo *II, MacroInfo *MI){
- return appendDefMacroDirective(II, MI, MI->getDefinitionLoc(), false);
+ return appendDefMacroDirective(II, MI, MI->getDefinitionLoc(), 0, None);
}
/// \brief Set a MacroDirective that was loaded from a PCH file.
void setLoadedMacroDirective(IdentifierInfo *II, MacroDirective *MD);
@@ -990,6 +1020,12 @@ public:
PragmaARCCFCodeAuditedLoc = Loc;
}
+ /// \brief Set the directory in which the main file should be considered
+ /// to have been found, if it is not a real file.
+ void setMainFileDir(const DirectoryEntry *Dir) {
+ MainFileDir = Dir;
+ }
+
/// \brief Instruct the preprocessor to skip part of the main source file.
///
/// \param Bytes The number of bytes in the preamble to skip.
@@ -1307,6 +1343,7 @@ public:
/// reference is for system \#include's or not (i.e. using <> instead of "").
const FileEntry *LookupFile(SourceLocation FilenameLoc, StringRef Filename,
bool isAngled, const DirectoryLookup *FromDir,
+ const FileEntry *FromFile,
const DirectoryLookup *&CurDir,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
@@ -1343,11 +1380,13 @@ public:
/// followed by EOD. Return true if the token is not a valid on-off-switch.
bool LexOnOffSwitch(tok::OnOffSwitch &OOS);
- bool CheckMacroName(Token &MacroNameTok, char isDefineUndef);
+ bool CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
+ bool *ShadowFlag = nullptr);
private:
void PushIncludeMacroStack() {
+ assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer");
IncludeMacroStack.push_back(IncludeStackInfo(
CurLexerKind, CurSubmodule, std::move(CurLexer), std::move(CurPTHLexer),
CurPPLexer, std::move(CurTokenLexer), CurDirLookup));
@@ -1370,24 +1409,29 @@ private:
/// \brief Allocate a new MacroInfo object.
MacroInfo *AllocateMacroInfo();
- DefMacroDirective *AllocateDefMacroDirective(MacroInfo *MI,
- SourceLocation Loc,
- bool isImported);
- UndefMacroDirective *AllocateUndefMacroDirective(SourceLocation UndefLoc);
+ DefMacroDirective *
+ AllocateDefMacroDirective(MacroInfo *MI, SourceLocation Loc,
+ unsigned ImportedFromModuleID = 0,
+ ArrayRef<unsigned> Overrides = None);
+ UndefMacroDirective *
+ AllocateUndefMacroDirective(SourceLocation UndefLoc,
+ unsigned ImportedFromModuleID = 0,
+ ArrayRef<unsigned> Overrides = None);
VisibilityMacroDirective *AllocateVisibilityMacroDirective(SourceLocation Loc,
bool isPublic);
- /// \brief Release the specified MacroInfo for re-use.
- ///
- /// This memory will be reused for allocating new MacroInfo objects.
- void ReleaseMacroInfo(MacroInfo* MI);
-
/// \brief Lex and validate a macro name, which occurs after a
- /// \#define or \#undef.
+ /// \#define or \#undef.
+ ///
+ /// \param MacroNameTok Token that represents the name defined or undefined.
+ /// \param IsDefineUndef Kind if preprocessor directive.
+ /// \param ShadowFlag Points to flag that is set if macro name shadows
+ /// a keyword.
///
/// This emits a diagnostic, sets the token kind to eod,
/// and discards the rest of the macro line if the macro name is invalid.
- void ReadMacroName(Token &MacroNameTok, char isDefineUndef = 0);
+ void ReadMacroName(Token &MacroNameTok, MacroUse IsDefineUndef = MU_Other,
+ bool *ShadowFlag = nullptr);
/// The ( starting an argument list of a macro definition has just been read.
/// Lex the rest of the arguments and the closing ), updating \p MI with
@@ -1521,6 +1565,7 @@ private:
void HandleIncludeDirective(SourceLocation HashLoc,
Token &Tok,
const DirectoryLookup *LookupFrom = nullptr,
+ const FileEntry *LookupFromFile = nullptr,
bool isImport = false);
void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok);
void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok);
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
index ed226ae9a3f6..3a91fa72f2e5 100644
--- a/include/clang/Lex/PreprocessorLexer.h
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PreprocessorLexer_H
-#define LLVM_CLANG_PreprocessorLexer_H
+#ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H
+#define LLVM_CLANG_LEX_PREPROCESSORLEXER_H
#include "clang/Lex/MultipleIncludeOpt.h"
#include "clang/Lex/Token.h"
diff --git a/include/clang/Lex/ScratchBuffer.h b/include/clang/Lex/ScratchBuffer.h
index f03515ffc142..a3d6096821e7 100644
--- a/include/clang/Lex/ScratchBuffer.h
+++ b/include/clang/Lex/ScratchBuffer.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SCRATCHBUFFER_H
-#define LLVM_CLANG_SCRATCHBUFFER_H
+#ifndef LLVM_CLANG_LEX_SCRATCHBUFFER_H
+#define LLVM_CLANG_LEX_SCRATCHBUFFER_H
#include "clang/Basic/SourceLocation.h"
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
index c8b77d11747e..4a53c9c1bb19 100644
--- a/include/clang/Lex/Token.h
+++ b/include/clang/Lex/Token.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOKEN_H
-#define LLVM_CLANG_TOKEN_H
+#ifndef LLVM_CLANG_LEX_TOKEN_H
+#define LLVM_CLANG_LEX_TOKEN_H
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
@@ -58,6 +58,8 @@ class Token {
/// may be dirty (have trigraphs / escaped newlines).
/// Annotations (resolved type names, C++ scopes, etc): isAnnotation().
/// This is a pointer to sema-specific data for the annotation token.
+ /// Eof:
+ // This is a pointer to a Decl.
/// Other:
/// This is null.
void *PtrData;
@@ -66,7 +68,7 @@ class Token {
tok::TokenKind Kind;
/// Flags - Bits we track about this token, members of the TokenFlags enum.
- unsigned char Flags;
+ unsigned short Flags;
public:
// Various flags set per token:
@@ -80,7 +82,9 @@ public:
LeadingEmptyMacro = 0x10, // Empty macro exists before this token.
HasUDSuffix = 0x20, // This string or character literal has a ud-suffix.
HasUCN = 0x40, // This identifier contains a UCN.
- IgnoredComma = 0x80 // This comma is not a macro argument separator (MS).
+ IgnoredComma = 0x80, // This comma is not a macro argument separator (MS).
+ StringifiedInMacro = 0x100, // This string or character literal is formed by
+ // macro stringizing or charizing operator.
};
tok::TokenKind getKind() const { return Kind; }
@@ -162,12 +166,23 @@ public:
assert(!isAnnotation() &&
"getIdentifierInfo() on an annotation token!");
if (isLiteral()) return nullptr;
+ if (is(tok::eof)) return nullptr;
return (IdentifierInfo*) PtrData;
}
void setIdentifierInfo(IdentifierInfo *II) {
PtrData = (void*) II;
}
+ const void *getEofData() const {
+ assert(is(tok::eof));
+ return reinterpret_cast<const void *>(PtrData);
+ }
+ void setEofData(const void *D) {
+ assert(is(tok::eof));
+ assert(!PtrData);
+ PtrData = const_cast<void *>(D);
+ }
+
/// getRawIdentifier - For a raw identifier token (i.e., an identifier
/// lexed in raw mode), returns a reference to the text substring in the
/// buffer if known.
@@ -262,6 +277,12 @@ public:
/// Returns true if this token contains a universal character name.
bool hasUCN() const { return (Flags & HasUCN) ? true : false; }
+
+ /// Returns true if this token is formed by macro by stringizing or charizing
+ /// operator.
+ bool stringifiedInMacro() const {
+ return (Flags & StringifiedInMacro) ? true : false;
+ }
};
/// \brief Information about the conditional stack (\#if directives)
diff --git a/include/clang/Lex/TokenConcatenation.h b/include/clang/Lex/TokenConcatenation.h
index 551300f402c2..a2d98b0d473a 100644
--- a/include/clang/Lex/TokenConcatenation.h
+++ b/include/clang/Lex/TokenConcatenation.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_LEX_TOKEN_CONCATENATION_H
-#define CLANG_LEX_TOKEN_CONCATENATION_H
+#ifndef LLVM_CLANG_LEX_TOKENCONCATENATION_H
+#define LLVM_CLANG_LEX_TOKENCONCATENATION_H
#include "clang/Basic/TokenKinds.h"
diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h
index a873a2e27508..306f98e2609a 100644
--- a/include/clang/Lex/TokenLexer.h
+++ b/include/clang/Lex/TokenLexer.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOKENLEXER_H
-#define LLVM_CLANG_TOKENLEXER_H
+#ifndef LLVM_CLANG_LEX_TOKENLEXER_H
+#define LLVM_CLANG_LEX_TOKENLEXER_H
#include "clang/Basic/SourceLocation.h"
diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h
index b593806ff391..f3a7f3b7a8d7 100644
--- a/include/clang/Parse/ParseDiagnostic.h
+++ b/include/clang/Parse/ParseDiagnostic.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_DIAGNOSTICPARSE_H
-#define LLVM_CLANG_DIAGNOSTICPARSE_H
+#ifndef LLVM_CLANG_PARSE_PARSEDIAGNOSTIC_H
+#define LLVM_CLANG_PARSE_PARSEDIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index c58c41a44c58..f12bec6929e1 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -135,10 +135,9 @@ class Parser : public CodeCompletionHandler {
mutable IdentifierInfo *Ident_final;
mutable IdentifierInfo *Ident_override;
- // Some token kinds such as C++ type traits can be reverted to identifiers and
- // still get used as keywords depending on context.
- llvm::SmallDenseMap<const IdentifierInfo *, tok::TokenKind>
- ContextualKeywords;
+ // C++ type trait keywords that can be reverted to identifiers and still be
+ // used as type traits.
+ llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertibleTypeTraits;
std::unique_ptr<PragmaHandler> AlignHandler;
std::unique_ptr<PragmaHandler> GCCVisibilityHandler;
@@ -164,6 +163,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> OptimizeHandler;
std::unique_ptr<PragmaHandler> LoopHintHandler;
std::unique_ptr<PragmaHandler> UnrollHintHandler;
+ std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
std::unique_ptr<CommentHandler> CommentSemaHandler;
@@ -258,24 +258,8 @@ public:
typedef SmallVector<TemplateParameterList *, 4> TemplateParameterLists;
- typedef clang::ExprResult ExprResult;
- typedef clang::StmtResult StmtResult;
- typedef clang::BaseResult BaseResult;
- typedef clang::MemInitResult MemInitResult;
- typedef clang::TypeResult TypeResult;
-
- typedef Expr *ExprArg;
- typedef MutableArrayRef<Stmt*> MultiStmtArg;
typedef Sema::FullExprArg FullExprArg;
- ExprResult ExprError() { return ExprResult(true); }
- StmtResult StmtError() { return StmtResult(true); }
-
- ExprResult ExprError(const DiagnosticBuilder &) { return ExprError(); }
- StmtResult StmtError(const DiagnosticBuilder &) { return StmtError(); }
-
- ExprResult ExprEmpty() { return ExprResult(false); }
-
// Parsing methods.
/// Initialize - Warm up the parser.
@@ -350,6 +334,15 @@ private:
/// For typos, give a fixit to '='
bool isTokenEqualOrEqualTypo();
+ /// \brief Return the current token to the token stream and make the given
+ /// token the current token.
+ void UnconsumeToken(Token &Consumed) {
+ Token Next = Tok;
+ PP.EnterToken(Consumed);
+ PP.Lex(Tok);
+ PP.EnterToken(Next);
+ }
+
/// ConsumeAnyToken - Dispatch to the right Consume* method based on the
/// current token type. This should only be used in cases where the type of
/// the token really isn't known, e.g. in error recovery.
@@ -524,7 +517,7 @@ private:
/// \brief Handle the annotation token produced for
/// #pragma clang loop and #pragma unroll.
- LoopHint HandlePragmaLoopHint();
+ bool HandlePragmaLoopHint(LoopHint &Hint);
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
@@ -591,8 +584,9 @@ private:
/// Annotation was successful.
ANK_Success
};
- AnnotatedNameKind TryAnnotateName(bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC = nullptr);
+ AnnotatedNameKind
+ TryAnnotateName(bool IsAddressOfOperand,
+ std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr);
/// Push a tok::annot_cxxscope token onto the token stream.
void AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation);
@@ -633,12 +627,6 @@ private:
/// otherwise emits a diagnostic and returns true.
bool TryKeywordIdentFallback(bool DisableKeyword);
- /// TryIdentKeywordUpgrade - Convert the current identifier token back to
- /// its original kind and return true if it was disabled by
- /// TryKeywordIdentFallback(), otherwise return false. Use this to
- /// contextually enable keywords.
- bool TryIdentKeywordUpgrade();
-
/// \brief Get the TemplateIdAnnotation from the token.
TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok);
@@ -1161,6 +1149,7 @@ private:
void ParseLateTemplatedFuncDef(LateParsedTemplate &LPT);
static void LateTemplateParserCallback(void *P, LateParsedTemplate &LPT);
+ static void LateTemplateParserCleanupCallback(void *P);
Sema::ParsingClassState
PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface);
@@ -1412,8 +1401,12 @@ private:
ExprResult ParseObjCBoolLiteral();
+ ExprResult ParseFoldExpression(ExprResult LHS, BalancedDelimiterTracker &T);
+
//===--------------------------------------------------------------------===//
// C++ Expressions
+ ExprResult tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand,
+ Token &Replacement);
ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
bool areTokensAdjacent(const Token &A, const Token &B);
@@ -1457,7 +1450,7 @@ private:
//===--------------------------------------------------------------------===//
// C++ 5.2.4: C++ Pseudo-Destructor Expressions
- ExprResult ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
+ ExprResult ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
tok::TokenKind OpKind,
CXXScopeSpec &SS,
ParsedType ObjectType);
@@ -1471,10 +1464,12 @@ private:
ExprResult ParseThrowExpression();
ExceptionSpecificationType tryParseExceptionSpecification(
+ bool Delayed,
SourceRange &SpecificationRange,
SmallVectorImpl<ParsedType> &DynamicExceptions,
SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
- ExprResult &NoexceptExpr);
+ ExprResult &NoexceptExpr,
+ CachedTokens *&ExceptionSpecTokens);
// EndLoc is filled with the location of the last token of the specification.
ExceptionSpecificationType ParseDynamicExceptionSpecification(
@@ -1557,10 +1552,10 @@ private:
ExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc,
SourceLocation SuperLoc,
ParsedType ReceiverType,
- ExprArg ReceiverExpr);
+ Expr *ReceiverExpr);
ExprResult ParseAssignmentExprWithObjCMessageExprStart(
SourceLocation LBracloc, SourceLocation SuperLoc,
- ParsedType ReceiverType, ExprArg ReceiverExpr);
+ ParsedType ReceiverType, Expr *ReceiverExpr);
bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr);
//===--------------------------------------------------------------------===//
@@ -1724,18 +1719,15 @@ private:
bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); }
};
- DeclGroupPtrTy ParseDeclaration(StmtVector &Stmts,
- unsigned Context, SourceLocation &DeclEnd,
+ DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs);
- DeclGroupPtrTy ParseSimpleDeclaration(StmtVector &Stmts,
- unsigned Context,
+ DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context,
SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs,
bool RequireSemi,
ForRangeInit *FRI = nullptr);
bool MightBeDeclarator(unsigned Context);
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context,
- bool AllowFunctionDefinitions,
SourceLocation *DeclEnd = nullptr,
ForRangeInit *FRI = nullptr);
Decl *ParseDeclarationAfterDeclarator(Declarator &D,
@@ -1781,16 +1773,9 @@ private:
void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
Decl *TagDecl);
- struct FieldCallback {
- virtual void invoke(ParsingFieldDeclarator &Field) = 0;
- virtual ~FieldCallback() {}
-
- private:
- virtual void _anchor();
- };
- struct ObjCPropertyCallback;
-
- void ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Callback);
+ void ParseStructDeclaration(
+ ParsingDeclSpec &DS,
+ llvm::function_ref<void(ParsingFieldDeclarator &)> FieldsCallback);
bool isDeclarationSpecifier(bool DisambiguatingWithExpression = false);
bool isTypeSpecifierQualifier();
@@ -2108,6 +2093,8 @@ private:
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs);
void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs);
+ void DiagnoseAndSkipExtendedMicrosoftTypeAttributes();
+ SourceLocation SkipExtendedMicrosoftTypeAttributes();
void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs);
void ParseBorlandTypeAttributes(ParsedAttributes &attrs);
void ParseOpenCLAttributes(ParsedAttributes &attrs);
@@ -2163,7 +2150,8 @@ private:
VirtSpecifiers::Specifier isCXX11VirtSpecifier() const {
return isCXX11VirtSpecifier(Tok);
}
- void ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface);
+ void ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface,
+ SourceLocation FriendLoc);
bool isCXX11FinalKeyword() const;
@@ -2207,8 +2195,21 @@ private:
void ParseDeclaratorInternal(Declarator &D,
DirectDeclParseFunction DirectDeclParser);
- void ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed = true,
- bool CXX11AttributesAllowed = true,
+ enum AttrRequirements {
+ AR_NoAttributesParsed = 0, ///< No attributes are diagnosed.
+ AR_GNUAttributesParsedAndRejected = 1 << 0, ///< Diagnose GNU attributes.
+ AR_GNUAttributesParsed = 1 << 1,
+ AR_CXX11AttributesParsed = 1 << 2,
+ AR_DeclspecAttributesParsed = 1 << 3,
+ AR_AllAttributesParsed = AR_GNUAttributesParsed |
+ AR_CXX11AttributesParsed |
+ AR_DeclspecAttributesParsed,
+ AR_VendorAttributesParsed = AR_GNUAttributesParsed |
+ AR_DeclspecAttributesParsed
+ };
+
+ void ParseTypeQualifierListOpt(DeclSpec &DS,
+ unsigned AttrReqs = AR_AllAttributesParsed,
bool AtomicAllowed = true,
bool IdentifierRequired = false);
void ParseDirectDeclarator(Declarator &D);
diff --git a/include/clang/Rewrite/Core/DeltaTree.h b/include/clang/Rewrite/Core/DeltaTree.h
index a6109bf90157..248f2a07eac1 100644
--- a/include/clang/Rewrite/Core/DeltaTree.h
+++ b/include/clang/Rewrite/Core/DeltaTree.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_REWRITE_DELTATREE_H
-#define CLANG_REWRITE_DELTATREE_H
+#ifndef LLVM_CLANG_REWRITE_CORE_DELTATREE_H
+#define LLVM_CLANG_REWRITE_CORE_DELTATREE_H
#include "llvm/Support/Compiler.h"
diff --git a/include/clang/Rewrite/Core/HTMLRewrite.h b/include/clang/Rewrite/Core/HTMLRewrite.h
index ec061dc7dba8..dafdf51ce63b 100644
--- a/include/clang/Rewrite/Core/HTMLRewrite.h
+++ b/include/clang/Rewrite/Core/HTMLRewrite.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_HTMLREWRITER_H
-#define LLVM_CLANG_HTMLREWRITER_H
+#ifndef LLVM_CLANG_REWRITE_CORE_HTMLREWRITE_H
+#define LLVM_CLANG_REWRITE_CORE_HTMLREWRITE_H
#include "clang/Basic/SourceLocation.h"
#include <string>
diff --git a/include/clang/Rewrite/Core/RewriteRope.h b/include/clang/Rewrite/Core/RewriteRope.h
index f312aedc082a..1c6f3eb952dd 100644
--- a/include/clang/Rewrite/Core/RewriteRope.h
+++ b/include/clang/Rewrite/Core/RewriteRope.h
@@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_REWRITEROPE_H
-#define LLVM_CLANG_REWRITEROPE_H
+#ifndef LLVM_CLANG_REWRITE_CORE_REWRITEROPE_H
+#define LLVM_CLANG_REWRITE_CORE_REWRITEROPE_H
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include <cassert>
@@ -34,11 +35,10 @@ namespace clang {
unsigned RefCount;
char Data[1]; // Variable sized.
- void addRef() {
- ++RefCount;
- }
+ void Retain() { ++RefCount; }
- void dropRef() {
+ void Release() {
+ assert(RefCount > 0 && "Reference count is already zero.");
if (--RefCount == 0)
delete [] (char*)this;
}
@@ -57,39 +57,15 @@ namespace clang {
/// that both refer to the same underlying RopeRefCountString (just with
/// different offsets) which is a nice constant time operation.
struct RopePiece {
- RopeRefCountString *StrData;
+ llvm::IntrusiveRefCntPtr<RopeRefCountString> StrData;
unsigned StartOffs;
unsigned EndOffs;
RopePiece() : StrData(nullptr), StartOffs(0), EndOffs(0) {}
- RopePiece(RopeRefCountString *Str, unsigned Start, unsigned End)
- : StrData(Str), StartOffs(Start), EndOffs(End) {
- if (StrData)
- StrData->addRef();
- }
- RopePiece(const RopePiece &RP)
- : StrData(RP.StrData), StartOffs(RP.StartOffs), EndOffs(RP.EndOffs) {
- if (StrData)
- StrData->addRef();
- }
-
- ~RopePiece() {
- if (StrData)
- StrData->dropRef();
- }
-
- void operator=(const RopePiece &RHS) {
- if (StrData != RHS.StrData) {
- if (StrData)
- StrData->dropRef();
- StrData = RHS.StrData;
- if (StrData)
- StrData->addRef();
- }
- StartOffs = RHS.StartOffs;
- EndOffs = RHS.EndOffs;
- }
+ RopePiece(llvm::IntrusiveRefCntPtr<RopeRefCountString> Str, unsigned Start,
+ unsigned End)
+ : StrData(std::move(Str)), StartOffs(Start), EndOffs(End) {}
const char &operator[](unsigned Offset) const {
return StrData->Data[Offset+StartOffs];
@@ -191,7 +167,7 @@ class RewriteRope {
/// We allocate space for string data out of a buffer of size AllocChunkSize.
/// This keeps track of how much space is left.
- RopeRefCountString *AllocBuffer;
+ llvm::IntrusiveRefCntPtr<RopeRefCountString> AllocBuffer;
unsigned AllocOffs;
enum { AllocChunkSize = 4080 };
@@ -201,12 +177,6 @@ public:
: Chunks(RHS.Chunks), AllocBuffer(nullptr), AllocOffs(AllocChunkSize) {
}
- ~RewriteRope() {
- // If we had an allocation buffer, drop our reference to it.
- if (AllocBuffer)
- AllocBuffer->dropRef();
- }
-
typedef RopePieceBTree::iterator iterator;
typedef RopePieceBTree::iterator const_iterator;
iterator begin() const { return Chunks.begin(); }
diff --git a/include/clang/Rewrite/Core/Rewriter.h b/include/clang/Rewrite/Core/Rewriter.h
index 7b22fb49bc2c..1ab7be6c5317 100644
--- a/include/clang/Rewrite/Core/Rewriter.h
+++ b/include/clang/Rewrite/Core/Rewriter.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_REWRITER_H
-#define LLVM_CLANG_REWRITER_H
+#ifndef LLVM_CLANG_REWRITE_CORE_REWRITER_H
+#define LLVM_CLANG_REWRITE_CORE_REWRITER_H
#include "clang/Basic/SourceLocation.h"
#include "clang/Rewrite/Core/DeltaTree.h"
@@ -27,7 +27,6 @@ namespace clang {
class LangOptions;
class Rewriter;
class SourceManager;
- class Stmt;
/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original
/// input with modifications get a new RewriteBuffer associated with them. The
@@ -245,11 +244,6 @@ public:
/// operation.
bool ReplaceText(SourceRange range, SourceRange replacementRange);
- /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
- /// printer to generate the replacement code. This returns true if the input
- /// could not be rewritten, or false if successful.
- bool ReplaceStmt(Stmt *From, Stmt *To);
-
/// \brief Increase indentation for the lines between the given source range.
/// To determine what the indentation should be, 'parentIndent' is used
/// that should be at a source location with an indentation one degree
@@ -260,10 +254,6 @@ public:
parentIndent);
}
- /// ConvertToString converts statement 'From' to a string using the
- /// pretty printer.
- std::string ConvertToString(Stmt *From);
-
/// getEditBuffer - This is like getRewriteBufferFor, but always returns a
/// buffer, and allows you to write on it directly. This is useful if you
/// want efficient low-level access to apis for scribbling on one specific
diff --git a/include/clang/Rewrite/Core/TokenRewriter.h b/include/clang/Rewrite/Core/TokenRewriter.h
index c313b453d984..598477f318fc 100644
--- a/include/clang/Rewrite/Core/TokenRewriter.h
+++ b/include/clang/Rewrite/Core/TokenRewriter.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOKENREWRITER_H
-#define LLVM_CLANG_TOKENREWRITER_H
+#ifndef LLVM_CLANG_REWRITE_CORE_TOKENREWRITER_H
+#define LLVM_CLANG_REWRITE_CORE_TOKENREWRITER_H
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/Token.h"
diff --git a/include/clang/Rewrite/Frontend/ASTConsumers.h b/include/clang/Rewrite/Frontend/ASTConsumers.h
index 584af3fa18b0..c9df8895041d 100644
--- a/include/clang/Rewrite/Frontend/ASTConsumers.h
+++ b/include/clang/Rewrite/Frontend/ASTConsumers.h
@@ -11,10 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#ifndef REWRITE_ASTCONSUMERS_H
-#define REWRITE_ASTCONSUMERS_H
+#ifndef LLVM_CLANG_REWRITE_FRONTEND_ASTCONSUMERS_H
+#define LLVM_CLANG_REWRITE_FRONTEND_ASTCONSUMERS_H
#include "clang/Basic/LLVM.h"
+#include <memory>
#include <string>
namespace clang {
@@ -26,23 +27,21 @@ class Preprocessor;
// ObjC rewriter: attempts to rewrite ObjC constructs into pure C code.
// This is considered experimental, and only works with Apple's ObjC runtime.
-ASTConsumer *CreateObjCRewriter(const std::string &InFile,
- raw_ostream *OS,
- DiagnosticsEngine &Diags,
- const LangOptions &LOpts,
- bool SilenceRewriteMacroWarning);
-ASTConsumer *CreateModernObjCRewriter(const std::string &InFile,
- raw_ostream *OS,
- DiagnosticsEngine &Diags,
- const LangOptions &LOpts,
- bool SilenceRewriteMacroWarning,
- bool LineInfo);
+std::unique_ptr<ASTConsumer>
+CreateObjCRewriter(const std::string &InFile, raw_ostream *OS,
+ DiagnosticsEngine &Diags, const LangOptions &LOpts,
+ bool SilenceRewriteMacroWarning);
+std::unique_ptr<ASTConsumer>
+CreateModernObjCRewriter(const std::string &InFile, raw_ostream *OS,
+ DiagnosticsEngine &Diags, const LangOptions &LOpts,
+ bool SilenceRewriteMacroWarning, bool LineInfo);
/// CreateHTMLPrinter - Create an AST consumer which rewrites source code to
/// HTML with syntax highlighting suitable for viewing in a web-browser.
-ASTConsumer *CreateHTMLPrinter(raw_ostream *OS, Preprocessor &PP,
- bool SyntaxHighlight = true,
- bool HighlightMacros = true);
+std::unique_ptr<ASTConsumer> CreateHTMLPrinter(raw_ostream *OS,
+ Preprocessor &PP,
+ bool SyntaxHighlight = true,
+ bool HighlightMacros = true);
} // end clang namespace
diff --git a/include/clang/Rewrite/Frontend/FixItRewriter.h b/include/clang/Rewrite/Frontend/FixItRewriter.h
index 3ad8f408af6e..599417235464 100644
--- a/include/clang/Rewrite/Frontend/FixItRewriter.h
+++ b/include/clang/Rewrite/Frontend/FixItRewriter.h
@@ -12,8 +12,8 @@
// then forwards any diagnostics to the adapted diagnostic client.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_REWRITE_FIX_IT_REWRITER_H
-#define LLVM_CLANG_REWRITE_FIX_IT_REWRITER_H
+#ifndef LLVM_CLANG_REWRITE_FRONTEND_FIXITREWRITER_H
+#define LLVM_CLANG_REWRITE_FRONTEND_FIXITREWRITER_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
@@ -66,7 +66,7 @@ class FixItRewriter : public DiagnosticConsumer {
/// \brief The diagnostic client that performs the actual formatting
/// of error messages.
DiagnosticConsumer *Client;
- bool OwnsClient;
+ std::unique_ptr<DiagnosticConsumer> Owner;
/// \brief Turn an input path into an output path. NULL implies overwriting
/// the original.
@@ -125,4 +125,4 @@ public:
}
-#endif // LLVM_CLANG_REWRITE_FIX_IT_REWRITER_H
+#endif
diff --git a/include/clang/Rewrite/Frontend/FrontendActions.h b/include/clang/Rewrite/Frontend/FrontendActions.h
index fc792707487d..c8ea8b2dd878 100644
--- a/include/clang/Rewrite/Frontend/FrontendActions.h
+++ b/include/clang/Rewrite/Frontend/FrontendActions.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_REWRITE_FRONTENDACTIONS_H
-#define LLVM_CLANG_REWRITE_FRONTENDACTIONS_H
+#ifndef LLVM_CLANG_REWRITE_FRONTEND_FRONTENDACTIONS_H
+#define LLVM_CLANG_REWRITE_FRONTEND_FRONTENDACTIONS_H
#include "clang/Frontend/FrontendAction.h"
@@ -22,8 +22,8 @@ class FixItOptions;
class HTMLPrintAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
};
class FixItAction : public ASTFrontendAction {
@@ -31,8 +31,8 @@ protected:
std::unique_ptr<FixItRewriter> Rewriter;
std::unique_ptr<FixItOptions> FixItOpts;
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
bool BeginSourceFileAction(CompilerInstance &CI,
StringRef Filename) override;
@@ -59,8 +59,8 @@ protected:
class RewriteObjCAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
};
class RewriteMacrosAction : public PreprocessorFrontendAction {
diff --git a/include/clang/Rewrite/Frontend/Rewriters.h b/include/clang/Rewrite/Frontend/Rewriters.h
index f5ade5ad35d3..3ad76dff824f 100644
--- a/include/clang/Rewrite/Frontend/Rewriters.h
+++ b/include/clang/Rewrite/Frontend/Rewriters.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_REWRITE_REWRITERS_H
-#define LLVM_CLANG_REWRITE_REWRITERS_H
+#ifndef LLVM_CLANG_REWRITE_FRONTEND_REWRITERS_H
+#define LLVM_CLANG_REWRITE_FRONTEND_REWRITERS_H
#include "clang/Basic/LLVM.h"
diff --git a/include/clang/Sema/AnalysisBasedWarnings.h b/include/clang/Sema/AnalysisBasedWarnings.h
index 432c4e23a993..64dd2d36bef8 100644
--- a/include/clang/Sema/AnalysisBasedWarnings.h
+++ b/include/clang/Sema/AnalysisBasedWarnings.h
@@ -11,8 +11,8 @@
// that issues warnings based on dataflow-analysis.
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
-#define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
+#ifndef LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H
+#define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H
#include "llvm/ADT/DenseMap.h"
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index c21c19fd55c9..dc85f5d2084c 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_ATTRLIST_H
-#define LLVM_CLANG_SEMA_ATTRLIST_H
+#ifndef LLVM_CLANG_SEMA_ATTRIBUTELIST_H
+#define LLVM_CLANG_SEMA_ATTRIBUTELIST_H
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/VersionTuple.h"
@@ -94,10 +94,10 @@ private:
/// The number of expression arguments this attribute has.
/// The expressions themselves are stored after the object.
- unsigned NumArgs : 16;
+ unsigned NumArgs : 15;
/// Corresponds to the Syntax enum.
- unsigned SyntaxUsed : 2;
+ unsigned SyntaxUsed : 3;
/// True if already diagnosed as invalid.
mutable unsigned Invalid : 1;
@@ -455,6 +455,7 @@ public:
bool hasCustomParsing() const;
unsigned getMinArgs() const;
unsigned getMaxArgs() const;
+ bool hasVariadicArg() const;
bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
bool diagnoseLangOpts(class Sema &S) const;
bool existsInTarget(const llvm::Triple &T) const;
@@ -821,12 +822,13 @@ enum AttributeDeclKind {
ExpectedFunctionMethodOrClass,
ExpectedFunctionMethodOrParameter,
ExpectedClass,
+ ExpectedEnum,
ExpectedVariable,
ExpectedMethod,
ExpectedVariableFunctionOrLabel,
ExpectedFieldOrGlobalVar,
ExpectedStruct,
- ExpectedVariableFunctionOrTag,
+ ExpectedVariableOrTypedef,
ExpectedTLSVar,
ExpectedVariableOrField,
ExpectedVariableFieldOrTag,
@@ -842,7 +844,8 @@ enum AttributeDeclKind {
ExpectedObjectiveCProtocol,
ExpectedFunctionGlobalVarMethodOrProperty,
ExpectedStructOrTypedef,
- ExpectedObjectiveCInterfaceOrProtocol
+ ExpectedObjectiveCInterfaceOrProtocol,
+ ExpectedKernelFunction
};
} // end namespace clang
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 8364dfc4b0bb..d36882660298 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -37,6 +37,7 @@
namespace clang {
class ASTContext;
+ class CXXRecordDecl;
class TypeLoc;
class LangOptions;
class DiagnosticsEngine;
@@ -141,6 +142,22 @@ public:
/// nested-name-specifier '::'.
void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
+ /// \brief Turns this (empty) nested-name-specifier into '__super'
+ /// nested-name-specifier.
+ ///
+ /// \param Context The AST context in which this nested-name-specifier
+ /// resides.
+ ///
+ /// \param RD The declaration of the class in which nested-name-specifier
+ /// appeared.
+ ///
+ /// \param SuperLoc The location of the '__super' keyword.
+ /// name.
+ ///
+ /// \param ColonColonLoc The location of the trailing '::'.
+ void MakeSuper(ASTContext &Context, CXXRecordDecl *RD,
+ SourceLocation SuperLoc, SourceLocation ColonColonLoc);
+
/// \brief Make a new nested-name-specifier from incomplete source-location
/// information.
///
@@ -1053,6 +1070,12 @@ struct DeclaratorChunk {
/// EndLoc - If valid, the place where this chunck ends.
SourceLocation EndLoc;
+ SourceRange getSourceRange() const {
+ if (EndLoc.isInvalid())
+ return SourceRange(Loc, Loc);
+ return SourceRange(Loc, EndLoc);
+ }
+
struct TypeInfoCommon {
AttributeList *AttrList;
};
@@ -1159,7 +1182,7 @@ struct DeclaratorChunk {
unsigned TypeQuals : 3;
/// ExceptionSpecType - An ExceptionSpecificationType value.
- unsigned ExceptionSpecType : 3;
+ unsigned ExceptionSpecType : 4;
/// DeleteParams - If this is true, we need to delete[] Params.
unsigned DeleteParams : 1;
@@ -1200,6 +1223,11 @@ struct DeclaratorChunk {
/// If this is an invalid location, there is no volatile-qualifier.
unsigned VolatileQualifierLoc;
+ /// \brief The location of the restrict-qualifier, if any.
+ ///
+ /// If this is an invalid location, there is no restrict-qualifier.
+ unsigned RestrictQualifierLoc;
+
/// \brief The location of the 'mutable' qualifer in a lambda-declarator, if
/// any.
unsigned MutableLoc;
@@ -1221,6 +1249,10 @@ struct DeclaratorChunk {
/// \brief Pointer to the expression in the noexcept-specifier of this
/// function, if it has one.
Expr *NoexceptExpr;
+
+ /// \brief Pointer to the cached tokens for an exception-specification
+ /// that has not yet been parsed.
+ CachedTokens *ExceptionSpecTokens;
};
/// \brief If HasTrailingReturnType is true, this is the trailing return
@@ -1247,6 +1279,8 @@ struct DeclaratorChunk {
delete[] Params;
if (getExceptionSpecType() == EST_Dynamic)
delete[] Exceptions;
+ else if (getExceptionSpecType() == EST_Unparsed)
+ delete ExceptionSpecTokens;
}
/// isKNRPrototype - Return true if this is a K&R style identifier list,
@@ -1275,16 +1309,21 @@ struct DeclaratorChunk {
return SourceLocation::getFromRawEncoding(RefQualifierLoc);
}
- /// \brief Retrieve the location of the ref-qualifier, if any.
+ /// \brief Retrieve the location of the 'const' qualifier, if any.
SourceLocation getConstQualifierLoc() const {
return SourceLocation::getFromRawEncoding(ConstQualifierLoc);
}
- /// \brief Retrieve the location of the ref-qualifier, if any.
+ /// \brief Retrieve the location of the 'volatile' qualifier, if any.
SourceLocation getVolatileQualifierLoc() const {
return SourceLocation::getFromRawEncoding(VolatileQualifierLoc);
}
+ /// \brief Retrieve the location of the 'restrict' qualifier, if any.
+ SourceLocation getRestrictQualifierLoc() const {
+ return SourceLocation::getFromRawEncoding(RestrictQualifierLoc);
+ }
+
/// \brief Retrieve the location of the 'mutable' qualifier, if any.
SourceLocation getMutableLoc() const {
return SourceLocation::getFromRawEncoding(MutableLoc);
@@ -1429,6 +1468,7 @@ struct DeclaratorChunk {
SourceLocation RefQualifierLoc,
SourceLocation ConstQualifierLoc,
SourceLocation VolatileQualifierLoc,
+ SourceLocation RestrictQualifierLoc,
SourceLocation MutableLoc,
ExceptionSpecificationType ESpecType,
SourceLocation ESpecLoc,
@@ -1436,6 +1476,7 @@ struct DeclaratorChunk {
SourceRange *ExceptionRanges,
unsigned NumExceptions,
Expr *NoexceptExpr,
+ CachedTokens *ExceptionSpecTokens,
SourceLocation LocalRangeBegin,
SourceLocation LocalRangeEnd,
Declarator &TheDeclarator,
@@ -1458,7 +1499,8 @@ struct DeclaratorChunk {
SourceLocation Loc) {
DeclaratorChunk I;
I.Kind = MemberPointer;
- I.Loc = Loc;
+ I.Loc = SS.getBeginLoc();
+ I.EndLoc = Loc;
I.Mem.TypeQuals = TypeQuals;
I.Mem.AttrList = nullptr;
new (I.Mem.ScopeMem.Mem) CXXScopeSpec(SS);
@@ -1881,6 +1923,14 @@ public:
return DeclTypeInfo[i];
}
+ typedef SmallVectorImpl<DeclaratorChunk>::const_iterator type_object_iterator;
+ typedef llvm::iterator_range<type_object_iterator> type_object_range;
+
+ /// Returns the range of type objects, from the identifier outwards.
+ type_object_range type_objects() const {
+ return type_object_range(DeclTypeInfo.begin(), DeclTypeInfo.end());
+ }
+
void DropFirstTypeObject() {
assert(!DeclTypeInfo.empty() && "No type chunks to drop.");
DeclTypeInfo.front().destroy();
diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h
index 85551f8db036..7fd6779f344d 100644
--- a/include/clang/Sema/DelayedDiagnostic.h
+++ b/include/clang/Sema/DelayedDiagnostic.h
@@ -19,8 +19,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H
-#define LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H
+#ifndef LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H
+#define LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H
#include "clang/Sema/Sema.h"
diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h
index 325abdf8e517..c0ef7121a6ee 100644
--- a/include/clang/Sema/ExternalSemaSource.h
+++ b/include/clang/Sema/ExternalSemaSource.h
@@ -10,8 +10,8 @@
// This file defines the ExternalSemaSource interface.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H
-#define LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H
+#ifndef LLVM_CLANG_SEMA_EXTERNALSEMASOURCE_H
+#define LLVM_CLANG_SEMA_EXTERNALSEMASOURCE_H
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Type.h"
@@ -20,6 +20,10 @@
#include "llvm/ADT/MapVector.h"
#include <utility>
+namespace llvm {
+template <class T, unsigned n> class SmallSetVector;
+}
+
namespace clang {
class CXXConstructorDecl;
@@ -132,6 +136,15 @@ public:
/// introduce the same declarations repeatedly.
virtual void ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {}
+ /// \brief Read the set of potentially unused typedefs known to the source.
+ ///
+ /// The external source should append its own potentially unused local
+ /// typedefs to the given vector of declarations. Note that this routine may
+ /// be invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadUnusedLocalTypedefNameCandidates(
+ llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {};
+
/// \brief Read the set of locally-scoped external declarations known to the
/// external Sema source.
///
diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h
index b2404bc14b93..a07834f95629 100644
--- a/include/clang/Sema/IdentifierResolver.h
+++ b/include/clang/Sema/IdentifierResolver.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H
-#define LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H
+#ifndef LLVM_CLANG_SEMA_IDENTIFIERRESOLVER_H
+#define LLVM_CLANG_SEMA_IDENTIFIERRESOLVER_H
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/SmallVector.h"
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index 00cc164d964c..1c6c7bbbd997 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -132,7 +132,7 @@ public:
: ResultKind(NotFound),
Paths(nullptr),
NamingClass(nullptr),
- SemaRef(SemaRef),
+ SemaPtr(&SemaRef),
NameInfo(NameInfo),
LookupKind(LookupKind),
IDNS(0),
@@ -154,7 +154,7 @@ public:
: ResultKind(NotFound),
Paths(nullptr),
NamingClass(nullptr),
- SemaRef(SemaRef),
+ SemaPtr(&SemaRef),
NameInfo(Name, NameLoc),
LookupKind(LookupKind),
IDNS(0),
@@ -174,7 +174,7 @@ public:
: ResultKind(NotFound),
Paths(nullptr),
NamingClass(nullptr),
- SemaRef(Other.SemaRef),
+ SemaPtr(Other.SemaPtr),
NameInfo(Other.NameInfo),
LookupKind(Other.LookupKind),
IDNS(Other.IDNS),
@@ -305,7 +305,7 @@ public:
if (!D->isInIdentifierNamespace(IDNS))
return nullptr;
- if (isHiddenDeclarationVisible() || isVisible(SemaRef, D))
+ if (isHiddenDeclarationVisible() || isVisible(getSema(), D))
return D;
return getAcceptableDeclSlow(D);
@@ -424,13 +424,20 @@ public:
Paths = nullptr;
}
} else {
- AmbiguityKind SavedAK = Ambiguity;
+ AmbiguityKind SavedAK;
+ bool WasAmbiguous = false;
+ if (ResultKind == Ambiguous) {
+ SavedAK = Ambiguity;
+ WasAmbiguous = true;
+ }
ResultKind = Found;
resolveKind();
// If we didn't make the lookup unambiguous, restore the old
// ambiguity kind.
if (ResultKind == Ambiguous) {
+ (void)WasAmbiguous;
+ assert(WasAmbiguous);
Ambiguity = SavedAK;
} else if (Paths) {
deletePaths(Paths);
@@ -544,7 +551,7 @@ public:
/// \brief Get the Sema object that this lookup result is searching
/// with.
- Sema &getSema() const { return SemaRef; }
+ Sema &getSema() const { return *SemaPtr; }
/// A class for iterating through a result set and possibly
/// filtering out results. The results returned are possibly
@@ -623,9 +630,9 @@ public:
private:
void diagnose() {
if (isAmbiguous())
- SemaRef.DiagnoseAmbiguousLookup(*this);
- else if (isClassLookup() && SemaRef.getLangOpts().AccessControl)
- SemaRef.CheckLookupAccess(*this);
+ getSema().DiagnoseAmbiguousLookup(*this);
+ else if (isClassLookup() && getSema().getLangOpts().AccessControl)
+ getSema().CheckLookupAccess(*this);
}
void setAmbiguous(AmbiguityKind AK) {
@@ -657,7 +664,7 @@ private:
QualType BaseObjectType;
// Parameters.
- Sema &SemaRef;
+ Sema *SemaPtr;
DeclarationNameInfo NameInfo;
SourceRange NameContextRange;
Sema::LookupNameKind LookupKind;
diff --git a/include/clang/Sema/LoopHint.h b/include/clang/Sema/LoopHint.h
index d4b985df544c..c8b2ee845e59 100644
--- a/include/clang/Sema/LoopHint.h
+++ b/include/clang/Sema/LoopHint.h
@@ -26,13 +26,18 @@ struct LoopHint {
// hints.
IdentifierLoc *PragmaNameLoc;
// Name of the loop hint. Examples: "unroll", "vectorize". In the
- // "#pragma unroll" case, this is identical to PragmaNameLoc.
+ // "#pragma unroll" and "#pragma nounroll" cases, this is identical to
+ // PragmaNameLoc.
IdentifierLoc *OptionLoc;
- // Identifier for the hint argument. If null, then the hint has no argument
- // such as for "#pragma unroll".
- IdentifierLoc *ValueLoc;
+ // Identifier for the hint state argument. If null, then the state is
+ // default value such as for "#pragma unroll".
+ IdentifierLoc *StateLoc;
// Expression for the hint argument if it exists, null otherwise.
Expr *ValueExpr;
+
+ LoopHint()
+ : PragmaNameLoc(nullptr), OptionLoc(nullptr), StateLoc(nullptr),
+ ValueExpr(nullptr) {}
};
} // end namespace clang
diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h
index 7860b6da06a0..f06d19629a30 100644
--- a/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -10,8 +10,8 @@
// This file defines ExternalSemaSource interface, dispatching to all clients
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_MULTIPLEX_EXTERNAL_SEMA_SOURCE_H
-#define LLVM_CLANG_SEMA_MULTIPLEX_EXTERNAL_SEMA_SOURCE_H
+#ifndef LLVM_CLANG_SEMA_MULTIPLEXEXTERNALSEMASOURCE_H
+#define LLVM_CLANG_SEMA_MULTIPLEXEXTERNALSEMASOURCE_H
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Weak.h"
@@ -282,6 +282,15 @@ public:
/// introduce the same declarations repeatedly.
void ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl*> &Decls) override;
+ /// \brief Read the set of potentially unused typedefs known to the source.
+ ///
+ /// The external source should append its own potentially unused local
+ /// typedefs to the given vector of declarations. Note that this routine may
+ /// be invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ void ReadUnusedLocalTypedefNameCandidates(
+ llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) override;
+
/// \brief Read the set of locally-scoped extern "C" declarations known to the
/// external Sema source.
///
@@ -368,4 +377,4 @@ public:
} // end namespace clang
-#endif // LLVM_CLANG_SEMA_MULTIPLEX_EXTERNAL_SEMA_SOURCE_H
+#endif
diff --git a/include/clang/Sema/ObjCMethodList.h b/include/clang/Sema/ObjCMethodList.h
index 20033567dff9..b618e38f88cd 100644
--- a/include/clang/Sema/ObjCMethodList.h
+++ b/include/clang/Sema/ObjCMethodList.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_OBJC_METHOD_LIST_H
-#define LLVM_CLANG_SEMA_OBJC_METHOD_LIST_H
+#ifndef LLVM_CLANG_SEMA_OBJCMETHODLIST_H
+#define LLVM_CLANG_SEMA_OBJCMETHODLIST_H
#include "llvm/ADT/PointerIntPair.h"
@@ -20,20 +20,37 @@ namespace clang {
class ObjCMethodDecl;
-/// ObjCMethodList - a linked list of methods with different signatures.
+/// \brief a linked list of methods with the same selector name but different
+/// signatures.
struct ObjCMethodList {
- ObjCMethodDecl *Method;
+ // NOTE: If you add any members to this struct, make sure to serialize them.
+ /// \brief If there is more than one decl with this signature.
+ llvm::PointerIntPair<ObjCMethodDecl *, 1> MethodAndHasMoreThanOneDecl;
/// \brief The next list object and 2 bits for extra info.
llvm::PointerIntPair<ObjCMethodList *, 2> NextAndExtraBits;
- ObjCMethodList() : Method(nullptr) { }
- ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C)
- : Method(M), NextAndExtraBits(C, 0) { }
+ ObjCMethodList() { }
+ ObjCMethodList(ObjCMethodDecl *M)
+ : MethodAndHasMoreThanOneDecl(M, 0) {}
ObjCMethodList *getNext() const { return NextAndExtraBits.getPointer(); }
unsigned getBits() const { return NextAndExtraBits.getInt(); }
void setNext(ObjCMethodList *L) { NextAndExtraBits.setPointer(L); }
void setBits(unsigned B) { NextAndExtraBits.setInt(B); }
+
+ ObjCMethodDecl *getMethod() const {
+ return MethodAndHasMoreThanOneDecl.getPointer();
+ }
+ void setMethod(ObjCMethodDecl *M) {
+ return MethodAndHasMoreThanOneDecl.setPointer(M);
+ }
+
+ bool hasMoreThanOneDecl() const {
+ return MethodAndHasMoreThanOneDecl.getInt();
+ }
+ void setHasMoreThanOneDecl(bool B) {
+ return MethodAndHasMoreThanOneDecl.setInt(B);
+ }
};
}
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 7c221a2336ce..4447db2b3ef0 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -25,6 +25,7 @@
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Allocator.h"
namespace clang {
@@ -85,21 +86,6 @@ namespace clang {
ICK_Num_Conversion_Kinds ///< The number of conversion kinds
};
- /// ImplicitConversionCategory - The category of an implicit
- /// conversion kind. The enumerator values match with Table 9 of
- /// (C++ 13.3.3.1.1) and are listed such that better conversion
- /// categories have smaller values.
- enum ImplicitConversionCategory {
- ICC_Identity = 0, ///< Identity
- ICC_Lvalue_Transformation, ///< Lvalue transformation
- ICC_Qualification_Adjustment, ///< Qualification adjustment
- ICC_Promotion, ///< Promotion
- ICC_Conversion ///< Conversion
- };
-
- ImplicitConversionCategory
- GetConversionCategory(ImplicitConversionKind Kind);
-
/// ImplicitConversionRank - The rank of an implicit conversion
/// kind. The enumerator values match with Table 9 of (C++
/// 13.3.3.1.1) and are listed such that better conversion ranks
@@ -567,6 +553,17 @@ namespace clang {
/// conversion.
ovl_fail_trivial_conversion,
+ /// This conversion candidate was not considered because it is
+ /// an illegal instantiation of a constructor temploid: it is
+ /// callable with one argument, we only have one argument, and
+ /// its first parameter type is exactly the type of the class.
+ ///
+ /// Defining such a constructor directly is illegal, and
+ /// template-argument deduction is supposed to ignore such
+ /// instantiations, but we can still get one with the right
+ /// kind of implicit instantiation.
+ ovl_fail_illegal_constructor,
+
/// This conversion candidate is not viable because its result
/// type is not implicitly convertible to the desired type.
ovl_fail_bad_final_conversion,
@@ -718,7 +715,8 @@ namespace clang {
CandidateSetKind Kind;
unsigned NumInlineSequences;
- char InlineSpace[16 * sizeof(ImplicitConversionSequence)];
+ llvm::AlignedCharArray<llvm::AlignOf<ImplicitConversionSequence>::Alignment,
+ 16 * sizeof(ImplicitConversionSequence)> InlineSpace;
OverloadCandidateSet(const OverloadCandidateSet &) LLVM_DELETED_FUNCTION;
void operator=(const OverloadCandidateSet &) LLVM_DELETED_FUNCTION;
@@ -735,8 +733,8 @@ namespace clang {
/// \brief Determine when this overload candidate will be new to the
/// overload set.
- bool isNewCandidate(Decl *F) {
- return Functions.insert(F->getCanonicalDecl());
+ bool isNewCandidate(Decl *F) {
+ return Functions.insert(F->getCanonicalDecl()).second;
}
/// \brief Clear out all of the candidates.
@@ -759,7 +757,7 @@ namespace clang {
// available.
if (NumConversions + NumInlineSequences <= 16) {
ImplicitConversionSequence *I =
- (ImplicitConversionSequence*)InlineSpace;
+ (ImplicitConversionSequence *)InlineSpace.buffer;
C.Conversions = &I[NumInlineSequences];
NumInlineSequences += NumConversions;
} else {
diff --git a/include/clang/Sema/PrettyDeclStackTrace.h b/include/clang/Sema/PrettyDeclStackTrace.h
index c0c772dc5983..ca22e640deb4 100644
--- a/include/clang/Sema/PrettyDeclStackTrace.h
+++ b/include/clang/Sema/PrettyDeclStackTrace.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_PRETTY_DECL_STACK_TRACE_H
-#define LLVM_CLANG_SEMA_PRETTY_DECL_STACK_TRACE_H
+#ifndef LLVM_CLANG_SEMA_PRETTYDECLSTACKTRACE_H
+#define LLVM_CLANG_SEMA_PRETTYDECLSTACKTRACE_H
#include "clang/Basic/SourceLocation.h"
#include "llvm/Support/PrettyStackTrace.h"
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index 8e4e2ef4be21..97e447d1fd67 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -135,14 +135,6 @@ private:
/// scopes seen as a component.
unsigned short MSLocalManglingNumber;
- /// \brief SEH __try blocks get uniquely numbered within a function. This
- /// variable holds the index for an SEH try block.
- short SEHTryIndex;
-
- /// \brief SEH __try blocks get uniquely numbered within a function. This
- /// variable holds the next free index at a function's scope.
- short SEHTryIndexPool;
-
/// PrototypeDepth - This is the number of function prototype scopes
/// enclosing this scope, including this scope.
unsigned short PrototypeDepth;
@@ -155,7 +147,6 @@ private:
/// pointer is non-null and points to it. This is used for label processing.
Scope *FnParent;
Scope *MSLocalManglingParent;
- Scope *SEHTryParent;
/// BreakParent/ContinueParent - This is a direct link to the innermost
/// BreakScope/ContinueScope which contains the contents of this scope
@@ -294,14 +285,6 @@ public:
return 1;
}
- int getSEHTryIndex() {
- return SEHTryIndex;
- }
-
- int getSEHTryParentIndex() const {
- return SEHTryParent ? SEHTryParent->SEHTryIndex : -1;
- }
-
/// isDeclScope - Return true if this is the scope that the specified decl is
/// declared in.
bool isDeclScope(Decl *D) {
@@ -317,6 +300,9 @@ public:
return ErrorTrap.hasUnrecoverableErrorOccurred();
}
+ /// isFunctionScope() - Return true if this scope is a function scope.
+ bool isFunctionScope() const { return (getFlags() & Scope::FnScope); }
+
/// isClassScope - Return true if this scope is a class/struct/union scope.
bool isClassScope() const {
return (getFlags() & Scope::ClassScope);
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 63427aaa4a75..d63b734a8dbf 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -12,9 +12,10 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_SCOPE_INFO_H
-#define LLVM_CLANG_SEMA_SCOPE_INFO_H
+#ifndef LLVM_CLANG_SEMA_SCOPEINFO_H
+#define LLVM_CLANG_SEMA_SCOPEINFO_H
+#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Basic/CapturedStmt.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -41,8 +42,6 @@ class SwitchStmt;
class TemplateTypeParmDecl;
class TemplateParameterList;
class VarDecl;
-class DeclRefExpr;
-class MemberExpr;
class ObjCIvarRefExpr;
class ObjCPropertyRefExpr;
class ObjCMessageExpr;
@@ -145,6 +144,10 @@ public:
/// current function scope. These diagnostics are vetted for reachability
/// prior to being emitted.
SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags;
+
+ /// \brief A list of parameters which have the nonnull attribute and are
+ /// modified in the function.
+ llvm::SmallPtrSet<const ParmVarDecl*, 8> ModifiedNonNullParams;
public:
/// Represents a simple identification of a weak object.
@@ -187,8 +190,6 @@ public:
/// Used to find the proper base profile for a given base expression.
static BaseInfoTy getBaseInfo(const Expr *BaseE);
- // For use in DenseMap.
- friend class DenseMapInfo;
inline WeakObjectProfileTy();
static inline WeakObjectProfileTy getSentinel();
@@ -381,7 +382,7 @@ public:
/// capture (if this is a capture and not an init-capture). The expression
/// is only required if we are capturing ByVal and the variable's type has
/// a non-trivial copy constructor.
- llvm::PointerIntPair<Expr*, 2, CaptureKind> InitExprAndCaptureKind;
+ llvm::PointerIntPair<void *, 2, CaptureKind> InitExprAndCaptureKind;
/// \brief The source location at which the first capture occurred.
SourceLocation Loc;
@@ -413,10 +414,11 @@ public:
return InitExprAndCaptureKind.getInt() == Cap_This;
}
bool isVariableCapture() const {
- return InitExprAndCaptureKind.getInt() != Cap_This;
+ return InitExprAndCaptureKind.getInt() != Cap_This && !isVLATypeCapture();
}
bool isCopyCapture() const {
- return InitExprAndCaptureKind.getInt() == Cap_ByCopy;
+ return InitExprAndCaptureKind.getInt() == Cap_ByCopy &&
+ !isVLATypeCapture();
}
bool isReferenceCapture() const {
return InitExprAndCaptureKind.getInt() == Cap_ByRef;
@@ -424,7 +426,11 @@ public:
bool isBlockCapture() const {
return InitExprAndCaptureKind.getInt() == Cap_Block;
}
- bool isNested() { return VarAndNested.getInt(); }
+ bool isVLATypeCapture() const {
+ return InitExprAndCaptureKind.getInt() == Cap_ByCopy &&
+ getVariable() == nullptr;
+ }
+ bool isNested() const { return VarAndNested.getInt(); }
VarDecl *getVariable() const {
return VarAndNested.getPointer();
@@ -443,7 +449,8 @@ public:
QualType getCaptureType() const { return CaptureType; }
Expr *getInitExpr() const {
- return InitExprAndCaptureKind.getPointer();
+ assert(!isVLATypeCapture() && "no init expression for type capture");
+ return static_cast<Expr *>(InitExprAndCaptureKind.getPointer());
}
};
@@ -478,6 +485,13 @@ public:
CaptureMap[Var] = Captures.size();
}
+ void addVLATypeCapture(SourceLocation Loc, QualType CaptureType) {
+ Captures.push_back(Capture(/*Var*/ nullptr, /*isBlock*/ false,
+ /*isByref*/ false, /*isNested*/ false, Loc,
+ /*EllipsisLoc*/ SourceLocation(), CaptureType,
+ /*Cpy*/ nullptr));
+ }
+
void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType,
Expr *Cpy);
@@ -494,7 +508,10 @@ public:
bool isCaptured(VarDecl *Var) const {
return CaptureMap.count(Var);
}
-
+
+ /// \brief Determine whether the given variable-array type has been captured.
+ bool isVLATypeCaptured(const VariableArrayType *VAT) const;
+
/// \brief Retrieve the capture of the given variable, if it has been
/// captured already.
Capture &getCapture(VarDecl *Var) {
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index e254afdbadaa..74efa60c9366 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -129,7 +129,6 @@ namespace clang {
class ModuleLoader;
class MultiLevelTemplateArgumentList;
class NamedDecl;
- class NonNullAttr;
class ObjCCategoryDecl;
class ObjCCategoryImplDecl;
class ObjCCompatibleAliasDecl;
@@ -169,6 +168,7 @@ namespace clang {
class TypedefDecl;
class TypedefNameDecl;
class TypeLoc;
+ class TypoCorrectionConsumer;
class UnqualifiedId;
class UnresolvedLookupExpr;
class UnresolvedMemberExpr;
@@ -390,6 +390,10 @@ public:
/// \brief Set containing all declared private fields that are not used.
NamedDeclSetType UnusedPrivateFields;
+ /// \brief Set containing all typedefs that are likely unused.
+ llvm::SmallSetVector<const TypedefNameDecl *, 4>
+ UnusedLocalTypedefNameCandidates;
+
typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy;
/// PureVirtualClassDiagSet - a set of class declarations which we have
@@ -454,12 +458,11 @@ public:
/// cycle detection at the end of the TU.
DelegatingCtorDeclsType 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.
- SmallVector<std::pair<const CXXDestructorDecl*,
- const CXXDestructorDecl*>, 2>
- DelayedDestructorExceptionSpecChecks;
+ /// \brief All the overriding functions seen during a class definition
+ /// that had their exception spec checks delayed, plus the overridden
+ /// function.
+ SmallVector<std::pair<const CXXMethodDecl*, const CXXMethodDecl*>, 2>
+ DelayedExceptionSpecChecks;
/// \brief All the members seen during a class definition which were both
/// explicitly defaulted and had explicitly-specified exception
@@ -477,11 +480,16 @@ public:
/// \brief Callback to the parser to parse templated functions when needed.
typedef void LateTemplateParserCB(void *P, LateParsedTemplate &LPT);
+ typedef void LateTemplateParserCleanupCB(void *P);
LateTemplateParserCB *LateTemplateParser;
+ LateTemplateParserCleanupCB *LateTemplateParserCleanup;
void *OpaqueParser;
- void SetLateTemplateParser(LateTemplateParserCB *LTP, void *P) {
+ void SetLateTemplateParser(LateTemplateParserCB *LTP,
+ LateTemplateParserCleanupCB *LTPCleanup,
+ void *P) {
LateTemplateParser = LTP;
+ LateTemplateParserCleanup = LTPCleanup;
OpaqueParser = P;
}
@@ -684,7 +692,10 @@ public:
/// \brief will hold 'respondsToSelector:'
Selector RespondsToSelectorSel;
-
+
+ /// \brief counter for internal MS Asm label names.
+ unsigned MSAsmLabelNameCounter;
+
/// A flag to remember whether the implicit forms of operator new and delete
/// have been declared.
bool GlobalNewDeleteDeclared;
@@ -745,6 +756,10 @@ public:
/// this expression evaluation context.
unsigned NumCleanupObjects;
+ /// \brief The number of typos encountered during this expression evaluation
+ /// context (i.e. the number of TypoExprs created).
+ unsigned NumTypos;
+
llvm::SmallPtrSet<Expr*, 2> SavedMaybeODRUseExprs;
/// \brief The lambdas that are present within this context, if it
@@ -778,6 +793,7 @@ public:
bool IsDecltype)
: Context(Context), ParentNeedsCleanups(ParentNeedsCleanups),
IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects),
+ NumTypos(0),
ManglingContextDecl(ManglingContextDecl), MangleNumbering() { }
/// \brief Retrieve the mangling numbering context, used to consistently
@@ -1037,6 +1053,8 @@ public:
/// \brief Retrieve the module loader associated with the preprocessor.
ModuleLoader &getModuleLoader() const;
+ void emitAndClearUnusedLocalTypedefWarnings();
+
void ActOnEndOfTranslationUnit();
void CheckDelegatingCtorCycles();
@@ -1181,7 +1199,7 @@ public:
const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
const FunctionProtoType *FPT);
void UpdateExceptionSpec(FunctionDecl *FD,
- const FunctionProtoType::ExtProtoInfo &EPI);
+ const FunctionProtoType::ExceptionSpecInfo &ESI);
bool CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range);
bool CheckDistantExceptionSpec(QualType T);
bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
@@ -1233,7 +1251,7 @@ public:
static QualType getPrintable(QualType T) { return T; }
static SourceRange getPrintable(SourceRange R) { return R; }
static SourceRange getPrintable(SourceLocation L) { return L; }
- static SourceRange getPrintable(Expr *E) { return E->getSourceRange(); }
+ static SourceRange getPrintable(const Expr *E) { return E->getSourceRange(); }
static SourceRange getPrintable(TypeLoc TL) { return TL.getSourceRange();}
template<typename T1>
@@ -1381,7 +1399,10 @@ public:
const CXXScopeSpec &SS, QualType T);
QualType BuildTypeofExprType(Expr *E, SourceLocation Loc);
- QualType BuildDecltypeType(Expr *E, SourceLocation Loc);
+ /// If AsUnevaluated is false, E is treated as though it were an evaluated
+ /// context, such as when building a type for decltype(auto).
+ QualType BuildDecltypeType(Expr *E, SourceLocation Loc,
+ bool AsUnevaluated = true);
QualType BuildUnaryTransformType(QualType BaseType,
UnaryTransformType::UTTKind UKind,
SourceLocation Loc);
@@ -1543,13 +1564,11 @@ public:
/// expression.
///
/// \param CCC The correction callback, if typo correction is desired.
- NameClassification ClassifyName(Scope *S,
- CXXScopeSpec &SS,
- IdentifierInfo *&Name,
- SourceLocation NameLoc,
- const Token &NextToken,
- bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC = nullptr);
+ NameClassification
+ ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
+ SourceLocation NameLoc, const Token &NextToken,
+ bool IsAddressOfOperand,
+ std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr);
Decl *ActOnDeclarator(Scope *S, Declarator &D);
@@ -1989,6 +2008,13 @@ public:
int FirstArg, unsigned AttrSpellingListIndex);
SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name,
unsigned AttrSpellingListIndex);
+ AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Ident,
+ unsigned AttrSpellingListIndex);
+ MinSizeAttr *mergeMinSizeAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex);
+ OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex);
/// \brief Describes the kind of merge to perform for availability
/// attributes (including "deprecated", "unavailable", and "availability").
@@ -2132,6 +2158,8 @@ public:
};
ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
llvm::APSInt &Value, CCEKind CCE);
+ ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
+ APValue &Value, CCEKind CCE);
/// \brief Abstract base class used to perform a contextual implicit
/// conversion from an expression to any type passing a filter.
@@ -2562,9 +2590,30 @@ public:
bool ConstThis,
bool VolatileThis);
+ typedef std::function<void(const TypoCorrection &)> TypoDiagnosticGenerator;
+ typedef std::function<ExprResult(Sema &, TypoExpr *, TypoCorrection)>
+ TypoRecoveryCallback;
+
private:
bool CppLookupName(LookupResult &R, Scope *S);
+ struct TypoExprState {
+ std::unique_ptr<TypoCorrectionConsumer> Consumer;
+ TypoDiagnosticGenerator DiagHandler;
+ TypoRecoveryCallback RecoveryHandler;
+ TypoExprState();
+ TypoExprState(TypoExprState&& other) LLVM_NOEXCEPT;
+ TypoExprState& operator=(TypoExprState&& other) LLVM_NOEXCEPT;
+ };
+
+ /// \brief The set of unhandled TypoExprs and their associated state.
+ llvm::MapVector<TypoExpr *, TypoExprState> DelayedTypos;
+
+ /// \brief Creates a new TypoExpr AST node.
+ TypoExpr *createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC,
+ TypoDiagnosticGenerator TDG,
+ TypoRecoveryCallback TRC);
+
// \brief The set of known/encountered (unique, canonicalized) NamespaceDecls.
//
// The boolean value will be true to indicate that the namespace was loaded
@@ -2575,7 +2624,24 @@ private:
/// source.
bool LoadedExternalKnownNamespaces;
+ /// \brief Helper for CorrectTypo and CorrectTypoDelayed used to create and
+ /// populate a new TypoCorrectionConsumer. Returns nullptr if typo correction
+ /// should be skipped entirely.
+ std::unique_ptr<TypoCorrectionConsumer>
+ makeTypoCorrectionConsumer(const DeclarationNameInfo &Typo,
+ Sema::LookupNameKind LookupKind, Scope *S,
+ CXXScopeSpec *SS,
+ std::unique_ptr<CorrectionCandidateCallback> CCC,
+ DeclContext *MemberContext, bool EnteringContext,
+ const ObjCObjectPointerType *OPT,
+ bool ErrorRecovery);
+
public:
+ const TypoExprState &getTypoExprState(TypoExpr *TE) const;
+
+ /// \brief Clears the state of the given TypoExpr.
+ void clearDelayedTypo(TypoExpr *TE);
+
/// \brief Look up a name, looking for a single declaration. Return
/// null if the results were absent, ambiguous, or overloaded.
///
@@ -2590,12 +2656,15 @@ public:
bool AllowBuiltinCreation = false);
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
bool InUnqualifiedLookup = false);
+ bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+ CXXScopeSpec &SS);
bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
bool AllowBuiltinCreation = false,
bool EnteringContext = false);
ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc,
RedeclarationKind Redecl
= NotForRedeclaration);
+ bool LookupInSuper(LookupResult &R, CXXRecordDecl *Class);
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
@@ -2645,13 +2714,35 @@ public:
TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
Sema::LookupNameKind LookupKind,
Scope *S, CXXScopeSpec *SS,
- CorrectionCandidateCallback &CCC,
+ std::unique_ptr<CorrectionCandidateCallback> CCC,
CorrectTypoKind Mode,
DeclContext *MemberContext = nullptr,
bool EnteringContext = false,
const ObjCObjectPointerType *OPT = nullptr,
bool RecordFailure = true);
+ TypoExpr *CorrectTypoDelayed(const DeclarationNameInfo &Typo,
+ Sema::LookupNameKind LookupKind, Scope *S,
+ CXXScopeSpec *SS,
+ std::unique_ptr<CorrectionCandidateCallback> CCC,
+ TypoDiagnosticGenerator TDG,
+ TypoRecoveryCallback TRC, CorrectTypoKind Mode,
+ DeclContext *MemberContext = nullptr,
+ bool EnteringContext = false,
+ const ObjCObjectPointerType *OPT = nullptr);
+
+ ExprResult
+ CorrectDelayedTyposInExpr(Expr *E,
+ llvm::function_ref<ExprResult(Expr *)> Filter =
+ [](Expr *E) -> ExprResult { return E; });
+
+ ExprResult
+ CorrectDelayedTyposInExpr(ExprResult ER,
+ llvm::function_ref<ExprResult(Expr *)> Filter =
+ [](Expr *E) -> ExprResult { return E; }) {
+ return ER.isInvalid() ? ER : CorrectDelayedTyposInExpr(ER.get(), Filter);
+ }
+
void diagnoseTypo(const TypoCorrection &Correction,
const PartialDiagnostic &TypoDiag,
bool ErrorRecovery = true);
@@ -2694,6 +2785,12 @@ public:
void checkUnusedDeclAttributes(Declarator &D);
+ /// Determine if type T is a valid subject for a nonnull and similar
+ /// attributes. By default, we look through references (the behavior used by
+ /// nonnull), but if the second parameter is true, then we treat a reference
+ /// type as valid.
+ bool isValidPointerAttrType(QualType T, bool RefOkay = false);
+
bool CheckRegparmAttr(const AttributeList &attr, unsigned &value);
bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
const FunctionDecl *FD = nullptr);
@@ -2872,12 +2969,27 @@ private:
bool receiverIdOrClass,
bool warn, bool instance);
+public:
+ /// \brief - Returns instance or factory methods in global method pool for
+ /// given selector. If no such method or only one method found, function returns
+ /// false; otherwise, it returns true
+ bool CollectMultipleMethodsInGlobalPool(Selector Sel,
+ SmallVectorImpl<ObjCMethodDecl*>& Methods,
+ bool instance);
+
+ bool AreMultipleMethodsInGlobalPool(Selector Sel,
+ bool instance);
+
+private:
+ /// \brief - Returns a selector which best matches given argument list or
+ /// nullptr if none could be found
+ ObjCMethodDecl *SelectBestMethod(Selector Sel, MultiExprArg Args,
+ bool IsInstance);
+
+
/// \brief Record the typo correction failure and return an empty correction.
TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc,
- bool RecordFailure = true,
- bool IsUnqualifiedLookup = false) {
- if (IsUnqualifiedLookup)
- (void)UnqualifiedTyposCorrected[Typo];
+ bool RecordFailure = true) {
if (RecordFailure)
TypoCorrectionFailures[Typo].insert(TypoLoc);
return TypoCorrection();
@@ -2937,11 +3049,6 @@ public:
public:
FullExprArg(Sema &actions) : E(nullptr) { }
- // FIXME: The const_cast here is ugly. RValue references would make this
- // much nicer (or we could duplicate a bunch of the move semantics
- // emulation code from Ownership.h).
- FullExprArg(const FullExprArg& Other) : E(Other.E) {}
-
ExprResult release() {
return E;
}
@@ -3001,6 +3108,18 @@ public:
Sema &S;
};
+ /// An RAII helper that pops function a function scope on exit.
+ struct FunctionScopeRAII {
+ Sema &S;
+ bool Active;
+ FunctionScopeRAII(Sema &S) : S(S), Active(true) {}
+ ~FunctionScopeRAII() {
+ if (Active)
+ S.PopFunctionScopeInfo();
+ }
+ void disable() { Active = false; }
+ };
+
StmtResult ActOnDeclStmt(DeclGroupPtrTy Decl,
SourceLocation StartLoc,
SourceLocation EndLoc);
@@ -3128,6 +3247,9 @@ public:
ArrayRef<StringRef> Clobbers,
ArrayRef<Expr*> Exprs,
SourceLocation EndLoc);
+ LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName,
+ SourceLocation Location,
+ bool AlwaysCreate);
VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType,
SourceLocation StartLoc,
@@ -3169,9 +3291,9 @@ public:
StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ?
SourceLocation TryLoc, Stmt *TryBlock,
- Stmt *Handler, int HandlerIndex,
- int HandlerParentIndex);
- StmtResult ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr,
+ Stmt *Handler);
+ StmtResult ActOnSEHExceptBlock(SourceLocation Loc,
+ Expr *FilterExpr,
Stmt *Block);
StmtResult ActOnSEHFinallyBlock(SourceLocation Loc, Stmt *Block);
StmtResult ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope);
@@ -3187,6 +3309,7 @@ public:
/// DiagnoseUnusedExprResult - If the statement passed in is an expression
/// whose result is unused, warn.
void DiagnoseUnusedExprResult(const Stmt *S);
+ void DiagnoseUnusedNestedTypedefs(const RecordDecl *D);
void DiagnoseUnusedDecl(const NamedDecl *ND);
/// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null
@@ -3204,6 +3327,10 @@ public:
void DiagnoseEmptyLoopBody(const Stmt *S,
const Stmt *PossibleBody);
+ /// Warn if a value is moved to itself.
+ void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
+ SourceLocation OpLoc);
+
ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) {
return DelayedDiagnostics.push(pool);
}
@@ -3228,8 +3355,6 @@ public:
const ObjCPropertyDecl *ObjCProperty,
bool ObjCPropertyAccess);
- void HandleDelayedAvailabilityCheck(sema::DelayedDiagnostic &DD, Decl *Ctx);
-
bool makeUnavailableInSystemHeader(SourceLocation loc,
StringRef message);
@@ -3271,7 +3396,8 @@ public:
// needs to be delayed for some constant variables when we build one of the
// named expressions.
void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse);
- void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func);
+ void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
+ bool OdrUse = true);
void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
void MarkDeclRefReferenced(DeclRefExpr *E);
void MarkMemberReferenced(MemberExpr *E);
@@ -3327,6 +3453,9 @@ public:
TryCaptureKind Kind = TryCapture_Implicit,
SourceLocation EllipsisLoc = SourceLocation());
+ /// \brief Checks if the variable must be captured.
+ bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc);
+
/// \brief Given a variable, determine the type that a reference to that
/// variable will have in the given scope.
QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc);
@@ -3359,12 +3488,11 @@ public:
// Primary Expressions.
SourceRange getExprRange(Expr *E) const;
- ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
- UnqualifiedId &Id,
- bool HasTrailingLParen, bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC = nullptr,
- bool IsInlineAsmIdentifier = false);
+ ExprResult ActOnIdExpression(
+ Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+ UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand,
+ std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr,
+ bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr);
void DecomposeUnqualifiedId(const UnqualifiedId &Id,
TemplateArgumentListInfo &Buffer,
@@ -3373,9 +3501,9 @@ public:
bool
DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- CorrectionCandidateCallback &CCC,
+ std::unique_ptr<CorrectionCandidateCallback> CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr,
- ArrayRef<Expr *> Args = None);
+ ArrayRef<Expr *> Args = None, TypoExpr **Out = nullptr);
ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S,
IdentifierInfo *II,
@@ -3430,11 +3558,13 @@ public:
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS,
LookupResult &R,
- bool NeedsADL);
+ bool NeedsADL,
+ bool AcceptInvalidDecl = false);
ExprResult BuildDeclarationNameExpr(
const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
NamedDecl *FoundD = nullptr,
- const TemplateArgumentListInfo *TemplateArgs = nullptr);
+ const TemplateArgumentListInfo *TemplateArgs = nullptr,
+ bool AcceptInvalidDecl = false);
ExprResult BuildLiteralOperatorCall(LookupResult &R,
DeclarationNameInfo &SuffixInfo,
@@ -3446,6 +3576,9 @@ public:
PredefinedExpr::IdentType IT);
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
+
+ bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);
+
ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);
ExprResult ActOnCharacterConstant(const Token &Tok,
Scope *UDLScope = nullptr);
@@ -3629,6 +3762,10 @@ public:
bool GNUSyntax,
ExprResult Init);
+private:
+ static BinaryOperatorKind ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind);
+
+public:
ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr);
ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc,
@@ -3876,6 +4013,8 @@ public:
bool IsStdInitListInitialization, bool RequiresZeroInit,
unsigned ConstructKind, SourceRange ParenRange);
+ ExprResult BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field);
+
/// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
/// the default expr if needed.
ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc,
@@ -3934,24 +4073,20 @@ public:
/// \brief Overwrite an EPI's exception specification with this
/// computed exception specification.
- void getEPI(FunctionProtoType::ExtProtoInfo &EPI) const {
- EPI.ExceptionSpecType = getExceptionSpecType();
- if (EPI.ExceptionSpecType == EST_Dynamic) {
- EPI.NumExceptions = size();
- EPI.Exceptions = data();
- } else if (EPI.ExceptionSpecType == EST_None) {
+ FunctionProtoType::ExceptionSpecInfo getExceptionSpec() const {
+ FunctionProtoType::ExceptionSpecInfo ESI;
+ ESI.Type = getExceptionSpecType();
+ if (ESI.Type == EST_Dynamic) {
+ ESI.Exceptions = Exceptions;
+ } else if (ESI.Type == EST_None) {
/// C++11 [except.spec]p14:
/// The exception-specification is noexcept(false) if the set of
/// potential exceptions of the special member function contains "any"
- EPI.ExceptionSpecType = EST_ComputedNoexcept;
- EPI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(),
+ ESI.Type = EST_ComputedNoexcept;
+ ESI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(),
tok::kw_false).get();
}
- }
- FunctionProtoType::ExtProtoInfo getEPI() const {
- FunctionProtoType::ExtProtoInfo EPI;
- getEPI(EPI);
- return EPI;
+ return ESI;
}
};
@@ -3998,13 +4133,28 @@ public:
void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD);
/// \brief Check the given exception-specification and update the
- /// extended prototype information with the results.
- void checkExceptionSpecification(ExceptionSpecificationType EST,
+ /// exception specification information with the results.
+ void checkExceptionSpecification(bool IsTopLevel,
+ ExceptionSpecificationType EST,
ArrayRef<ParsedType> DynamicExceptions,
ArrayRef<SourceRange> DynamicExceptionRanges,
Expr *NoexceptExpr,
SmallVectorImpl<QualType> &Exceptions,
- FunctionProtoType::ExtProtoInfo &EPI);
+ FunctionProtoType::ExceptionSpecInfo &ESI);
+
+ /// \brief Determine if we're in a case where we need to (incorrectly) eagerly
+ /// parse an exception specification to work around a libstdc++ bug.
+ bool isLibstdcxxEagerExceptionSpecHack(const Declarator &D);
+
+ /// \brief Add an exception-specification to the given member function
+ /// (or member function template). The exception-specification was parsed
+ /// after the method itself was declared.
+ void actOnDelayedExceptionSpecification(Decl *Method,
+ ExceptionSpecificationType EST,
+ SourceRange SpecificationRange,
+ ArrayRef<ParsedType> DynamicExceptions,
+ ArrayRef<SourceRange> DynamicExceptionRanges,
+ Expr *NoexceptExpr);
/// \brief Determine if a special member function should have a deleted
/// definition when it is defaulted.
@@ -4206,6 +4356,17 @@ public:
void *TyOrExpr,
SourceLocation RParenLoc);
+ /// \brief Handle a C++1z fold-expression: ( expr op ... op expr ).
+ ExprResult ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
+ tok::TokenKind Operator,
+ SourceLocation EllipsisLoc, Expr *RHS,
+ SourceLocation RParenLoc);
+ ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
+ BinaryOperatorKind Operator,
+ SourceLocation EllipsisLoc, Expr *RHS,
+ SourceLocation RParenLoc);
+ ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
+ BinaryOperatorKind Operator);
//// ActOnCXXThis - Parse 'this' pointer.
ExprResult ActOnCXXThis(SourceLocation loc);
@@ -4450,16 +4611,26 @@ public:
/// \brief The parser has parsed a global nested-name-specifier '::'.
///
- /// \param S The scope in which this nested-name-specifier occurs.
- ///
/// \param CCLoc The location of the '::'.
///
/// \param SS The nested-name-specifier, which will be updated in-place
/// to reflect the parsed nested-name-specifier.
///
/// \returns true if an error occurred, false otherwise.
- bool ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,
- CXXScopeSpec &SS);
+ bool ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS);
+
+ /// \brief The parser has parsed a '__super' nested-name-specifier.
+ ///
+ /// \param SuperLoc The location of the '__super' keyword.
+ ///
+ /// \param ColonColonLoc The location of the '::'.
+ ///
+ /// \param SS The nested-name-specifier, which will be updated in-place
+ /// to reflect the parsed nested-name-specifier.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool ActOnSuperScopeSpecifier(SourceLocation SuperLoc,
+ SourceLocation ColonColonLoc, CXXScopeSpec &SS);
bool isAcceptableNestedNameSpecifier(const NamedDecl *SD);
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
@@ -5038,6 +5209,10 @@ public:
/// CheckOverrideControl - Check C++11 override control semantics.
void CheckOverrideControl(NamedDecl *D);
+
+ /// DiagnoseAbsenceOfOverrideControl - Diagnose if 'override' keyword was
+ /// not used in the declaration of an overriding method.
+ void DiagnoseAbsenceOfOverrideControl(NamedDecl *D);
/// CheckForFunctionMarkedFinal - Checks whether a virtual member function
/// overrides a virtual member function marked 'final', according to
@@ -5582,6 +5757,10 @@ public:
// C++ Variadic Templates (C++0x [temp.variadic])
//===--------------------------------------------------------------------===//
+ /// Determine whether an unexpanded parameter pack might be permitted in this
+ /// location. Useful for error recovery.
+ bool isUnexpandedParameterPackPermitted();
+
/// \brief The context in which an unexpanded parameter pack is
/// being diagnosed.
///
@@ -6053,6 +6232,8 @@ public:
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
+ TypeLoc getReturnTypeLoc(FunctionDecl *FD) const;
+
bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
SourceLocation ReturnLoc,
Expr *&RetExpr, AutoType *AT);
@@ -6512,17 +6693,6 @@ public:
/// \brief The number of typos corrected by CorrectTypo.
unsigned TyposCorrected;
- typedef llvm::DenseMap<IdentifierInfo *, TypoCorrection>
- UnqualifiedTyposCorrectedMap;
-
- /// \brief A cache containing the results of typo correction for unqualified
- /// name lookup.
- ///
- /// The string is the string that we corrected to (which may be empty, if
- /// there was no correction), while the boolean will be true when the
- /// string represents a keyword.
- UnqualifiedTyposCorrectedMap UnqualifiedTyposCorrected;
-
typedef llvm::SmallSet<SourceLocation, 2> SrcLocSet;
typedef llvm::DenseMap<IdentifierInfo *, SrcLocSet> IdentifierSourceLocations;
@@ -6548,6 +6718,31 @@ public:
/// but have not yet been performed.
std::deque<PendingImplicitInstantiation> PendingInstantiations;
+ class SavePendingInstantiationsAndVTableUsesRAII {
+ public:
+ SavePendingInstantiationsAndVTableUsesRAII(Sema &S): S(S) {
+ SavedPendingInstantiations.swap(S.PendingInstantiations);
+ SavedVTableUses.swap(S.VTableUses);
+ }
+
+ ~SavePendingInstantiationsAndVTableUsesRAII() {
+ // Restore the set of pending vtables.
+ assert(S.VTableUses.empty() &&
+ "VTableUses should be empty before it is discarded.");
+ S.VTableUses.swap(SavedVTableUses);
+
+ // Restore the set of pending implicit instantiations.
+ assert(S.PendingInstantiations.empty() &&
+ "PendingInstantiations should be empty before it is discarded.");
+ S.PendingInstantiations.swap(SavedPendingInstantiations);
+ }
+
+ private:
+ Sema &S;
+ SmallVector<VTableUse, 16> SavedVTableUses;
+ std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
+ };
+
/// \brief The queue of implicit template instantiations that are required
/// and must be performed within the current local scope.
///
@@ -6597,6 +6792,8 @@ public:
DeclarationName Entity,
CXXRecordDecl *ThisContext,
unsigned ThisTypeQuals);
+ void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
+ const MultiLevelTemplateArgumentList &Args);
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
@@ -6656,6 +6853,10 @@ public:
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateSpecializationKind TSK);
+ bool InstantiateInClassInitializer(
+ SourceLocation PointOfInstantiation, FieldDecl *Instantiation,
+ FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs);
+
struct LateInstantiatedAttribute {
const Attr *TmplAttr;
LocalInstantiationScope *Scope;
@@ -7142,33 +7343,10 @@ public:
PSK_CodeSeg,
};
- enum PragmaSectionFlag : unsigned {
- PSF_None = 0,
- PSF_Read = 0x1,
- PSF_Write = 0x2,
- PSF_Execute = 0x4,
- PSF_Implicit = 0x8,
- PSF_Invalid = 0x80000000U,
- };
-
- struct SectionInfo {
- DeclaratorDecl *Decl;
- SourceLocation PragmaSectionLocation;
- int SectionFlags;
- SectionInfo() {}
- SectionInfo(DeclaratorDecl *Decl,
- SourceLocation PragmaSectionLocation,
- int SectionFlags)
- : Decl(Decl),
- PragmaSectionLocation(PragmaSectionLocation),
- SectionFlags(SectionFlags) {}
- };
-
- llvm::StringMap<SectionInfo> SectionInfos;
- bool UnifySection(const StringRef &SectionName,
+ bool UnifySection(StringRef SectionName,
int SectionFlags,
DeclaratorDecl *TheDecl);
- bool UnifySection(const StringRef &SectionName,
+ bool UnifySection(StringRef SectionName,
int SectionFlags,
SourceLocation PragmaSectionLocation);
@@ -7283,6 +7461,16 @@ public:
void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T,
unsigned SpellingListIndex, bool IsPackExpansion);
+ /// AddAssumeAlignedAttr - Adds an assume_aligned attribute to a particular
+ /// declaration.
+ void AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, Expr *OE,
+ unsigned SpellingListIndex);
+
+ /// AddAlignValueAttr - Adds an align_value attribute to a particular
+ /// declaration.
+ void AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
+ unsigned SpellingListIndex);
+
// OpenMP directives and clauses.
private:
void *VarDataSharingAttributesStack;
@@ -7291,6 +7479,10 @@ private:
void DestroyDataSharingAttributesStack();
ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op,
OpenMPClauseKind CKind);
+ /// \brief Checks if the specified variable is used in one of the private
+ /// clauses in OpenMP constructs.
+ bool IsOpenMPCapturedVar(VarDecl *VD);
+
public:
ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc,
Expr *Op);
@@ -7342,6 +7534,12 @@ public:
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA);
+ /// \brief Called on well-formed '\#pragma omp for simd' after parsing
+ /// of the associated statement.
+ StmtResult ActOnOpenMPForSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA);
/// \brief Called on well-formed '\#pragma omp sections' after parsing
/// of the associated statement.
StmtResult ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses,
@@ -7371,6 +7569,12 @@ public:
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA);
+ /// \brief Called on well-formed '\#pragma omp parallel for simd' after
+ /// parsing of the associated statement.
+ StmtResult ActOnOpenMPParallelForSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA);
/// \brief Called on well-formed '\#pragma omp parallel sections' after
/// parsing of the associated statement.
StmtResult ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses,
@@ -7395,6 +7599,25 @@ public:
StmtResult ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc);
+ /// \brief Called on well-formed '\#pragma omp ordered' after parsing of the
+ /// associated statement.
+ StmtResult ActOnOpenMPOrderedDirective(Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed '\#pragma omp atomic' after parsing of the
+ /// associated statement.
+ StmtResult ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed '\#pragma omp target' after parsing of the
+ /// associated statement.
+ StmtResult ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed '\#pragma omp teams' after parsing of the
+ /// associated statement.
+ StmtResult ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc);
OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
Expr *Expr,
@@ -7473,6 +7696,21 @@ public:
/// \brief Called on well-formed 'mergeable' clause.
OMPClause *ActOnOpenMPMergeableClause(SourceLocation StartLoc,
SourceLocation EndLoc);
+ /// \brief Called on well-formed 'read' clause.
+ OMPClause *ActOnOpenMPReadClause(SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'write' clause.
+ OMPClause *ActOnOpenMPWriteClause(SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'update' clause.
+ OMPClause *ActOnOpenMPUpdateClause(SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'capture' clause.
+ OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'seq_cst' clause.
+ OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc,
+ SourceLocation EndLoc);
OMPClause *
ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> Vars,
@@ -7615,6 +7853,7 @@ public:
VAK_Valid,
VAK_ValidInCXX11,
VAK_Undefined,
+ VAK_MSVCUndefined,
VAK_Invalid
};
@@ -7732,6 +7971,12 @@ public:
Expr *SrcExpr, AssignmentAction Action,
bool *Complained = nullptr);
+ /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag
+ /// enum. If AllowMask is true, then we also allow the complement of a valid
+ /// value, to be used as a mask.
+ bool IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
+ bool AllowMask) const;
+
/// DiagnoseAssignmentEnum - Warn if assignment to enum is a constant
/// integer not in the range of enum values.
void DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
@@ -7976,6 +8221,7 @@ public:
ObjCMethodDecl *Method, bool isClassMessage,
bool isSuperMessage,
SourceLocation lbrac, SourceLocation rbrac,
+ SourceRange RecRange,
QualType &ReturnType, ExprValueKind &VK);
/// \brief Determine the result of a message send expression based on
@@ -8067,18 +8313,30 @@ public:
CFT_Device,
CFT_Global,
CFT_Host,
- CFT_HostDevice
+ CFT_HostDevice,
+ CFT_InvalidTarget
};
CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D);
- bool CheckCUDATarget(CUDAFunctionTarget CallerTarget,
- CUDAFunctionTarget CalleeTarget);
-
- bool CheckCUDATarget(const FunctionDecl *Caller, const FunctionDecl *Callee) {
- return CheckCUDATarget(IdentifyCUDATarget(Caller),
- IdentifyCUDATarget(Callee));
- }
+ bool CheckCUDATarget(const FunctionDecl *Caller, const FunctionDecl *Callee);
+
+ /// Given a implicit special member, infer its CUDA target from the
+ /// calls it needs to make to underlying base/field special members.
+ /// \param ClassDecl the class for which the member is being created.
+ /// \param CSM the kind of special member.
+ /// \param MemberDecl the special member itself.
+ /// \param ConstRHS true if this is a copy operation with a const object on
+ /// its RHS.
+ /// \param Diagnose true if this call should emit diagnostics.
+ /// \return true if there was an error inferring.
+ /// The result of this call is implicit CUDA target attribute(s) attached to
+ /// the member declaration.
+ bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
+ CXXSpecialMember CSM,
+ CXXMethodDecl *MemberDecl,
+ bool ConstRHS,
+ bool Diagnose);
/// \name Code completion
//@{
@@ -8269,7 +8527,8 @@ private:
bool CheckObjCString(Expr *Arg);
- ExprResult CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+ ExprResult CheckBuiltinFunctionCall(FunctionDecl *FDecl,
+ unsigned BuiltinID, CallExpr *TheCall);
bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
unsigned MaxWidth);
@@ -8295,6 +8554,7 @@ public:
private:
bool SemaBuiltinPrefetch(CallExpr *TheCall);
bool SemaBuiltinAssume(CallExpr *TheCall);
+ bool SemaBuiltinAssumeAligned(CallExpr *TheCall);
bool SemaBuiltinLongjmp(CallExpr *TheCall);
ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult);
ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult,
@@ -8322,6 +8582,10 @@ public:
FormatStringType Type, bool inFunctionCall,
VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs);
+
+ bool FormatStringHasSArg(const StringLiteral *FExpr);
+
+ bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx);
private:
bool CheckFormatArguments(const FormatAttr *Format,
@@ -8359,6 +8623,7 @@ private:
void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS);
void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation());
+ void CheckBoolLikeConversion(Expr *E, SourceLocation CC);
void CheckForIntOverflow(Expr *E);
void CheckUnsequencedOperations(Expr *E);
diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h
index fdf959305151..7740d5e29c00 100644
--- a/include/clang/Sema/SemaDiagnostic.h
+++ b/include/clang/Sema/SemaDiagnostic.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_DIAGNOSTICSEMA_H
-#define LLVM_CLANG_DIAGNOSTICSEMA_H
+#ifndef LLVM_CLANG_SEMA_SEMADIAGNOSTIC_H
+#define LLVM_CLANG_SEMA_SEMADIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
diff --git a/include/clang/Sema/SemaFixItUtils.h b/include/clang/Sema/SemaFixItUtils.h
index fffca6791454..343ccfb3d630 100644
--- a/include/clang/Sema/SemaFixItUtils.h
+++ b/include/clang/Sema/SemaFixItUtils.h
@@ -10,8 +10,8 @@
// This file defines helper classes for generation of Sema FixItHints.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_FIXITUTILS_H
-#define LLVM_CLANG_SEMA_FIXITUTILS_H
+#ifndef LLVM_CLANG_SEMA_SEMAFIXITUTILS_H
+#define LLVM_CLANG_SEMA_SEMAFIXITUTILS_H
#include "clang/AST/Expr.h"
@@ -88,4 +88,4 @@ struct ConversionFixItGenerator {
};
} // endof namespace clang
-#endif // LLVM_CLANG_SEMA_FIXITUTILS_H
+#endif
diff --git a/include/clang/Sema/SemaInternal.h b/include/clang/Sema/SemaInternal.h
index 9199b0fba2a5..045bacf21360 100644
--- a/include/clang/Sema/SemaInternal.h
+++ b/include/clang/Sema/SemaInternal.h
@@ -12,10 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_SEMA_INTERNAL_H
-#define LLVM_CLANG_SEMA_SEMA_INTERNAL_H
+#ifndef LLVM_CLANG_SEMA_SEMAINTERNAL_H
+#define LLVM_CLANG_SEMA_SEMAINTERNAL_H
#include "clang/AST/ASTContext.h"
+#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
@@ -86,6 +87,213 @@ inline InheritableAttr *getDLLAttr(Decl *D) {
return nullptr;
}
+class TypoCorrectionConsumer : public VisibleDeclConsumer {
+ typedef SmallVector<TypoCorrection, 1> TypoResultList;
+ typedef llvm::StringMap<TypoResultList> TypoResultsMap;
+ typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
+
+public:
+ TypoCorrectionConsumer(Sema &SemaRef,
+ const DeclarationNameInfo &TypoName,
+ Sema::LookupNameKind LookupKind,
+ Scope *S, CXXScopeSpec *SS,
+ std::unique_ptr<CorrectionCandidateCallback> CCC,
+ DeclContext *MemberContext,
+ bool EnteringContext)
+ : Typo(TypoName.getName().getAsIdentifierInfo()), CurrentTCIndex(0),
+ SemaRef(SemaRef), S(S),
+ SS(SS ? llvm::make_unique<CXXScopeSpec>(*SS) : nullptr),
+ CorrectionValidator(std::move(CCC)), MemberContext(MemberContext),
+ Result(SemaRef, TypoName, LookupKind),
+ Namespaces(SemaRef.Context, SemaRef.CurContext, SS),
+ EnteringContext(EnteringContext), SearchNamespaces(false) {
+ Result.suppressDiagnostics();
+ // Arrange for ValidatedCorrections[0] to always be an empty correction.
+ ValidatedCorrections.push_back(TypoCorrection());
+ }
+
+ bool includeHiddenDecls() const override { return true; }
+
+ // Methods for adding potential corrections to the consumer.
+ void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
+ bool InBaseClass) override;
+ void FoundName(StringRef Name);
+ void addKeywordResult(StringRef Keyword);
+ void addCorrection(TypoCorrection Correction);
+
+ bool empty() const {
+ return CorrectionResults.empty() && ValidatedCorrections.size() == 1;
+ }
+
+ /// \brief Return the list of TypoCorrections for the given identifier from
+ /// the set of corrections that have the closest edit distance, if any.
+ TypoResultList &operator[](StringRef Name) {
+ return CorrectionResults.begin()->second[Name];
+ }
+
+ /// \brief Return the edit distance of the corrections that have the
+ /// closest/best edit distance from the original typop.
+ unsigned getBestEditDistance(bool Normalized) {
+ if (CorrectionResults.empty())
+ return (std::numeric_limits<unsigned>::max)();
+
+ unsigned BestED = CorrectionResults.begin()->first;
+ return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED;
+ }
+
+ /// \brief Set-up method to add to the consumer the set of namespaces to use
+ /// in performing corrections to nested name specifiers. This method also
+ /// implicitly adds all of the known classes in the current AST context to the
+ /// to the consumer for correcting nested name specifiers.
+ void
+ addNamespaces(const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces);
+
+ /// \brief Return the next typo correction that passes all internal filters
+ /// and is deemed valid by the consumer's CorrectionCandidateCallback,
+ /// starting with the corrections that have the closest edit distance. An
+ /// empty TypoCorrection is returned once no more viable corrections remain
+ /// in the consumer.
+ const TypoCorrection &getNextCorrection();
+
+ /// \brief Get the last correction returned by getNextCorrection().
+ const TypoCorrection &getCurrentCorrection() {
+ return CurrentTCIndex < ValidatedCorrections.size()
+ ? ValidatedCorrections[CurrentTCIndex]
+ : ValidatedCorrections[0]; // The empty correction.
+ }
+
+ /// \brief Return the next typo correction like getNextCorrection, but keep
+ /// the internal state pointed to the current correction (i.e. the next time
+ /// getNextCorrection is called, it will return the same correction returned
+ /// by peekNextcorrection).
+ const TypoCorrection &peekNextCorrection() {
+ auto Current = CurrentTCIndex;
+ const TypoCorrection &TC = getNextCorrection();
+ CurrentTCIndex = Current;
+ return TC;
+ }
+
+ /// \brief Reset the consumer's position in the stream of viable corrections
+ /// (i.e. getNextCorrection() will return each of the previously returned
+ /// corrections in order before returning any new corrections).
+ void resetCorrectionStream() {
+ CurrentTCIndex = 0;
+ }
+
+ /// \brief Return whether the end of the stream of corrections has been
+ /// reached.
+ bool finished() {
+ return CorrectionResults.empty() &&
+ CurrentTCIndex >= ValidatedCorrections.size();
+ }
+
+ ASTContext &getContext() const { return SemaRef.Context; }
+ const LookupResult &getLookupResult() const { return Result; }
+
+ bool isAddressOfOperand() const { return CorrectionValidator->IsAddressOfOperand; }
+ const CXXScopeSpec *getSS() const { return SS.get(); }
+ Scope *getScope() const { return S; }
+
+private:
+ class NamespaceSpecifierSet {
+ struct SpecifierInfo {
+ DeclContext* DeclCtx;
+ NestedNameSpecifier* NameSpecifier;
+ unsigned EditDistance;
+ };
+
+ typedef SmallVector<DeclContext*, 4> DeclContextList;
+ typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList;
+
+ ASTContext &Context;
+ DeclContextList CurContextChain;
+ std::string CurNameSpecifier;
+ SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers;
+ SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers;
+ bool isSorted;
+
+ SpecifierInfoList Specifiers;
+ llvm::SmallSetVector<unsigned, 4> Distances;
+ llvm::DenseMap<unsigned, SpecifierInfoList> DistanceMap;
+
+ /// \brief Helper for building the list of DeclContexts between the current
+ /// context and the top of the translation unit
+ static DeclContextList buildContextChain(DeclContext *Start);
+
+ void sortNamespaces();
+
+ unsigned buildNestedNameSpecifier(DeclContextList &DeclChain,
+ NestedNameSpecifier *&NNS);
+
+ public:
+ NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext,
+ CXXScopeSpec *CurScopeSpec);
+
+ /// \brief Add the DeclContext (a namespace or record) to the set, computing
+ /// the corresponding NestedNameSpecifier and its distance in the process.
+ void addNameSpecifier(DeclContext *Ctx);
+
+ typedef SpecifierInfoList::iterator iterator;
+ iterator begin() {
+ if (!isSorted) sortNamespaces();
+ return Specifiers.begin();
+ }
+ iterator end() { return Specifiers.end(); }
+ };
+
+ void addName(StringRef Name, NamedDecl *ND,
+ NestedNameSpecifier *NNS = nullptr, bool isKeyword = false);
+
+ /// \brief Find any visible decls for the given typo correction candidate.
+ /// If none are found, it to the set of candidates for which qualified lookups
+ /// will be performed to find possible nested name specifier changes.
+ bool resolveCorrection(TypoCorrection &Candidate);
+
+ /// \brief Perform qualified lookups on the queued set of typo correction
+ /// candidates and add the nested name specifier changes to each candidate if
+ /// a lookup succeeds (at which point the candidate will be returned to the
+ /// main pool of potential corrections).
+ void performQualifiedLookups();
+
+ /// \brief The name written that is a typo in the source.
+ IdentifierInfo *Typo;
+
+ /// \brief The results found that have the smallest edit distance
+ /// found (so far) with the typo name.
+ ///
+ /// The pointer value being set to the current DeclContext indicates
+ /// whether there is a keyword with this name.
+ TypoEditDistanceMap CorrectionResults;
+
+ SmallVector<TypoCorrection, 4> ValidatedCorrections;
+ size_t CurrentTCIndex;
+
+ Sema &SemaRef;
+ Scope *S;
+ std::unique_ptr<CXXScopeSpec> SS;
+ std::unique_ptr<CorrectionCandidateCallback> CorrectionValidator;
+ DeclContext *MemberContext;
+ LookupResult Result;
+ NamespaceSpecifierSet Namespaces;
+ SmallVector<TypoCorrection, 2> QualifiedResults;
+ bool EnteringContext;
+ bool SearchNamespaces;
+};
+
+inline Sema::TypoExprState::TypoExprState() {}
+
+inline Sema::TypoExprState::TypoExprState(TypoExprState &&other) LLVM_NOEXCEPT {
+ *this = std::move(other);
}
+inline Sema::TypoExprState &Sema::TypoExprState::operator=(
+ Sema::TypoExprState &&other) LLVM_NOEXCEPT {
+ Consumer = std::move(other.Consumer);
+ DiagHandler = std::move(other.DiagHandler);
+ RecoveryHandler = std::move(other.RecoveryHandler);
+ return *this;
+}
+
+} // end namespace clang
+
#endif
diff --git a/include/clang/Sema/SemaLambda.h b/include/clang/Sema/SemaLambda.h
index f6367505f866..d043e2c459b3 100644
--- a/include/clang/Sema/SemaLambda.h
+++ b/include/clang/Sema/SemaLambda.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_LAMBDA_H
-#define LLVM_CLANG_SEMA_LAMBDA_H
+#ifndef LLVM_CLANG_SEMA_SEMALAMBDA_H
+#define LLVM_CLANG_SEMA_SEMALAMBDA_H
#include "clang/AST/ASTLambda.h"
#include "clang/Sema/ScopeInfo.h"
namespace clang {
@@ -33,4 +33,4 @@ Optional<unsigned> getStackIndexOfNearestEnclosingCaptureCapableLambda(
} // clang
-#endif // LLVM_CLANG_SEMA_LAMBDA_H
+#endif
diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index 2c2c36d30be3..8338d975752c 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/include/clang/Sema/TemplateDeduction.h
@@ -10,8 +10,8 @@
// routines.
//
//===----------------------------------------------------------------------===/
-#ifndef LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H
-#define LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H
+#ifndef LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H
+#define LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/PartialDiagnostic.h"
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index 6cab59c93efc..922d0ffa1142 100644
--- a/include/clang/Sema/TypoCorrection.h
+++ b/include/clang/Sema/TypoCorrection.h
@@ -17,6 +17,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Ownership.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -198,10 +199,9 @@ public:
void setCorrectionRange(CXXScopeSpec *SS,
const DeclarationNameInfo &TypoName) {
- CorrectionRange.setBegin(ForceSpecifierReplacement && SS && !SS->isEmpty()
- ? SS->getBeginLoc()
- : TypoName.getLoc());
- CorrectionRange.setEnd(TypoName.getLoc());
+ CorrectionRange = TypoName.getSourceRange();
+ if (ForceSpecifierReplacement && SS && !SS->isEmpty())
+ CorrectionRange.setBegin(SS->getBeginLoc());
}
SourceRange getCorrectionRange() const {
@@ -247,11 +247,13 @@ class CorrectionCandidateCallback {
public:
static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
- CorrectionCandidateCallback()
+ explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr,
+ NestedNameSpecifier *TypoNNS = nullptr)
: WantTypeSpecifiers(true), WantExpressionKeywords(true),
- WantCXXNamedCasts(true), WantRemainingKeywords(true),
- WantObjCSuper(false), IsObjCIvarLookup(false),
- IsAddressOfOperand(false) {}
+ WantCXXNamedCasts(true), WantFunctionLikeCasts(true),
+ WantRemainingKeywords(true), WantObjCSuper(false),
+ IsObjCIvarLookup(false), IsAddressOfOperand(false), Typo(Typo),
+ TypoNNS(TypoNNS) {}
virtual ~CorrectionCandidateCallback() {}
@@ -274,20 +276,39 @@ public:
/// the default RankCandidate returns either 0 or InvalidDistance depending
/// whether ValidateCandidate returns true or false.
virtual unsigned RankCandidate(const TypoCorrection &candidate) {
- return ValidateCandidate(candidate) ? 0 : InvalidDistance;
+ return (!MatchesTypo(candidate) && ValidateCandidate(candidate))
+ ? 0
+ : InvalidDistance;
}
- // Flags for context-dependent keywords.
+ void setTypoName(IdentifierInfo *II) { Typo = II; }
+ void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; }
+
+ // Flags for context-dependent keywords. WantFunctionLikeCasts is only
+ // used/meaningful when WantCXXNamedCasts is false.
// TODO: Expand these to apply to non-keywords or possibly remove them.
bool WantTypeSpecifiers;
bool WantExpressionKeywords;
bool WantCXXNamedCasts;
+ bool WantFunctionLikeCasts;
bool WantRemainingKeywords;
bool WantObjCSuper;
// Temporary hack for the one case where a CorrectTypoContext enum is used
// when looking up results.
bool IsObjCIvarLookup;
bool IsAddressOfOperand;
+
+protected:
+ bool MatchesTypo(const TypoCorrection &candidate) {
+ return Typo && candidate.isResolved() && !candidate.requiresImport() &&
+ candidate.getCorrectionAsIdentifierInfo() == Typo &&
+ // FIXME: This probably does not return true when both
+ // NestedNameSpecifiers have the same textual representation.
+ candidate.getCorrectionSpecifier() == TypoNNS;
+ }
+
+ IdentifierInfo *Typo;
+ NestedNameSpecifier *TypoNNS;
};
/// @brief Simple template class for restricting typo correction candidates
@@ -325,6 +346,7 @@ public:
WantTypeSpecifiers = false;
WantExpressionKeywords = false;
WantCXXNamedCasts = false;
+ WantFunctionLikeCasts = false;
WantRemainingKeywords = false;
}
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 7ae1977d3e71..3874f3a64c1b 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -14,8 +14,8 @@
// respective lists.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_PCHBITCODES_H
-#define LLVM_CLANG_FRONTEND_PCHBITCODES_H
+#ifndef LLVM_CLANG_SERIALIZATION_ASTBITCODES_H
+#define LLVM_CLANG_SERIALIZATION_ASTBITCODES_H
#include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h"
@@ -35,7 +35,7 @@ namespace clang {
/// Version 4 of AST files also requires that the version control branch and
/// revision match exactly, since there is no backward compatibility of
/// AST files at this time.
- const unsigned VERSION_MAJOR = 5;
+ const unsigned VERSION_MAJOR = 6;
/// \brief AST file minor version number supported by this version of
/// Clang.
@@ -288,7 +288,13 @@ namespace clang {
/// \brief Record code for the module map file that was used to build this
/// AST file.
- MODULE_MAP_FILE = 14
+ MODULE_MAP_FILE = 14,
+
+ /// \brief Record code for the signature that identifiers this AST file.
+ SIGNATURE = 15,
+
+ /// \brief Record code for the module build directory.
+ MODULE_DIRECTORY = 16,
};
/// \brief Record types that occur within the input-files block
@@ -545,7 +551,10 @@ namespace clang {
LATE_PARSED_TEMPLATE = 50,
/// \brief Record code for \#pragma optimize options.
- OPTIMIZE_PRAGMA_OPTIONS = 51
+ OPTIMIZE_PRAGMA_OPTIONS = 51,
+
+ /// \brief Record code for potentially unused local typedef names.
+ UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES = 52,
};
/// \brief Record types used within a source manager block.
@@ -635,7 +644,13 @@ namespace clang {
/// \brief Specifies a conflict with another module.
SUBMODULE_CONFLICT = 12,
/// \brief Specifies a header that is private to this submodule.
- SUBMODULE_PRIVATE_HEADER = 13
+ SUBMODULE_PRIVATE_HEADER = 13,
+ /// \brief Specifies a header that is part of the module but must be
+ /// textually included.
+ SUBMODULE_TEXTUAL_HEADER = 14,
+ /// \brief Specifies a header that is private to this submodule but
+ /// must be textually included.
+ SUBMODULE_PRIVATE_TEXTUAL_HEADER = 15,
};
/// \brief Record types used within a comments block.
@@ -759,9 +774,6 @@ 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
@@ -1323,7 +1335,8 @@ namespace clang {
EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr
EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr
EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
-
+ EXPR_CXX_FOLD, // CXXFoldExpr
+
// CUDA
EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
@@ -1339,22 +1352,28 @@ namespace clang {
STMT_SEH_FINALLY, // SEHFinallyStmt
STMT_SEH_TRY, // SEHTryStmt
- // OpenMP drectives
+ // OpenMP directives
STMT_OMP_PARALLEL_DIRECTIVE,
STMT_OMP_SIMD_DIRECTIVE,
STMT_OMP_FOR_DIRECTIVE,
+ STMT_OMP_FOR_SIMD_DIRECTIVE,
STMT_OMP_SECTIONS_DIRECTIVE,
STMT_OMP_SECTION_DIRECTIVE,
STMT_OMP_SINGLE_DIRECTIVE,
STMT_OMP_MASTER_DIRECTIVE,
STMT_OMP_CRITICAL_DIRECTIVE,
STMT_OMP_PARALLEL_FOR_DIRECTIVE,
+ STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE,
STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE,
STMT_OMP_TASK_DIRECTIVE,
STMT_OMP_TASKYIELD_DIRECTIVE,
STMT_OMP_BARRIER_DIRECTIVE,
STMT_OMP_TASKWAIT_DIRECTIVE,
STMT_OMP_FLUSH_DIRECTIVE,
+ STMT_OMP_ORDERED_DIRECTIVE,
+ STMT_OMP_ATOMIC_DIRECTIVE,
+ STMT_OMP_TARGET_DIRECTIVE,
+ STMT_OMP_TEAMS_DIRECTIVE,
// ARC
EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr
diff --git a/include/clang/Serialization/ASTDeserializationListener.h b/include/clang/Serialization/ASTDeserializationListener.h
index 180f554dafea..c24ccdcd4f56 100644
--- a/include/clang/Serialization/ASTDeserializationListener.h
+++ b/include/clang/Serialization/ASTDeserializationListener.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_AST_DESERIALIZATION_LISTENER_H
-#define LLVM_CLANG_FRONTEND_AST_DESERIALIZATION_LISTENER_H
+#ifndef LLVM_CLANG_SERIALIZATION_ASTDESERIALIZATIONLISTENER_H
+#define LLVM_CLANG_SERIALIZATION_ASTDESERIALIZATIONLISTENER_H
#include "clang/Basic/IdentifierTable.h"
#include "clang/Serialization/ASTBitCodes.h"
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 3f44440d4b9a..91ad34bd1ca1 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_AST_READER_H
-#define LLVM_CLANG_FRONTEND_AST_READER_H
+#ifndef LLVM_CLANG_SERIALIZATION_ASTREADER_H
+#define LLVM_CLANG_SERIALIZATION_ASTREADER_H
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclarationName.h"
@@ -115,7 +115,8 @@ public:
///
/// \returns true to indicate the options are invalid or false otherwise.
virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) {
+ bool Complain,
+ bool AllowCompatibleDifferences) {
return false;
}
@@ -193,6 +194,13 @@ public:
bool isOverridden) {
return true;
}
+
+ /// \brief Returns true if this \c ASTReaderListener wants to receive the
+ /// imports of the AST file via \c visitImport, false otherwise.
+ virtual bool needsImportVisitation() const { return false; }
+ /// \brief If needsImportVisitation returns \c true, this is called for each
+ /// AST file imported by this AST file.
+ virtual void visitImport(StringRef Filename) {}
};
/// \brief Simple wrapper class for chaining listeners.
@@ -202,13 +210,18 @@ class ChainedASTReaderListener : public ASTReaderListener {
public:
/// Takes ownership of \p First and \p Second.
- ChainedASTReaderListener(ASTReaderListener *First, ASTReaderListener *Second)
- : First(First), Second(Second) { }
+ ChainedASTReaderListener(std::unique_ptr<ASTReaderListener> First,
+ std::unique_ptr<ASTReaderListener> Second)
+ : First(std::move(First)), Second(std::move(Second)) {}
+
+ std::unique_ptr<ASTReaderListener> takeFirst() { return std::move(First); }
+ std::unique_ptr<ASTReaderListener> takeSecond() { return std::move(Second); }
bool ReadFullVersionInformation(StringRef FullVersion) override;
void ReadModuleName(StringRef ModuleName) override;
void ReadModuleMapFile(StringRef ModuleMapPath) override;
- bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain) override;
+ bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
+ bool AllowCompatibleDifferences) override;
bool ReadTargetOptions(const TargetOptions &TargetOpts,
bool Complain) override;
bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
@@ -240,8 +253,8 @@ public:
PCHValidator(Preprocessor &PP, ASTReader &Reader)
: PP(PP), Reader(Reader) {}
- bool ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) override;
+ bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
+ bool AllowCompatibleDifferences) override;
bool ReadTargetOptions(const TargetOptions &TargetOpts,
bool Complain) override;
bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
@@ -437,6 +450,16 @@ private:
/// \brief Declarations that have been replaced in a later file in the chain.
DeclReplacementMap ReplacedDecls;
+ /// \brief Declarations that have been imported and have typedef names for
+ /// linkage purposes.
+ llvm::DenseMap<std::pair<DeclContext*, IdentifierInfo*>, NamedDecl*>
+ ImportedTypedefNamesForLinkage;
+
+ /// \brief Mergeable declaration contexts that have anonymous declarations
+ /// within them, and those anonymous declarations.
+ llvm::DenseMap<DeclContext*, llvm::SmallVector<NamedDecl*, 2>>
+ AnonymousDeclarationsForMerging;
+
struct FileDeclsInfo {
ModuleFile *Mod;
ArrayRef<serialization::LocalDeclID> Decls;
@@ -748,6 +771,11 @@ private:
/// at the end of the TU, in which case it directs CodeGen to emit the VTable.
SmallVector<uint64_t, 16> DynamicClasses;
+ /// \brief The IDs of all potentially unused typedef names in the chain.
+ ///
+ /// Sema tracks these to emit warnings.
+ SmallVector<uint64_t, 16> UnusedLocalTypedefNameCandidates;
+
/// \brief The IDs of the declarations Sema stores directly.
///
/// Sema tracks a few important decls, such as namespace std, directly.
@@ -1085,12 +1113,11 @@ private:
serialization::InputFile getInputFile(ModuleFile &F, unsigned ID,
bool Complain = true);
- /// \brief Get a FileEntry out of stored-in-PCH filename, making sure we take
- /// into account all the necessary relocations.
- const FileEntry *getFileEntry(StringRef filename);
-
- void MaybeAddSystemRootToFilename(ModuleFile &M, std::string &Filename);
+public:
+ void ResolveImportedPath(ModuleFile &M, std::string &Filename);
+ static void ResolveImportedPath(std::string &Filename, StringRef Prefix);
+private:
struct ImportedModule {
ModuleFile *Mod;
ModuleFile *ImportedBy;
@@ -1106,20 +1133,25 @@ private:
SourceLocation ImportLoc, ModuleFile *ImportedBy,
SmallVectorImpl<ImportedModule> &Loaded,
off_t ExpectedSize, time_t ExpectedModTime,
+ serialization::ASTFileSignature ExpectedSignature,
unsigned ClientLoadCapabilities);
ASTReadResult ReadControlBlock(ModuleFile &F,
SmallVectorImpl<ImportedModule> &Loaded,
const ModuleFile *ImportedBy,
unsigned ClientLoadCapabilities);
ASTReadResult ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities);
- bool ParseLineTable(ModuleFile &F, SmallVectorImpl<uint64_t> &Record);
+ bool ParseLineTable(ModuleFile &F, const RecordData &Record);
bool ReadSourceManagerBlock(ModuleFile &F);
llvm::BitstreamCursor &SLocCursorForID(int ID);
SourceLocation getImportLocation(ModuleFile *F);
+ ASTReadResult ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
+ const ModuleFile *ImportedBy,
+ unsigned ClientLoadCapabilities);
ASTReadResult ReadSubmoduleBlock(ModuleFile &F,
unsigned ClientLoadCapabilities);
static bool ParseLanguageOptions(const RecordData &Record, bool Complain,
- ASTReaderListener &Listener);
+ ASTReaderListener &Listener,
+ bool AllowCompatibleDifferences);
static bool ParseTargetOptions(const RecordData &Record, bool Complain,
ASTReaderListener &Listener);
static bool ParseDiagnosticOptions(const RecordData &Record, bool Complain,
@@ -1142,7 +1174,7 @@ private:
QualType readTypeRecord(unsigned Index);
void readExceptionSpec(ModuleFile &ModuleFile,
SmallVectorImpl<QualType> &ExceptionStorage,
- FunctionProtoType::ExtProtoInfo &EPI,
+ FunctionProtoType::ExceptionSpecInfo &ESI,
const RecordData &Record, unsigned &Index);
RecordLocation TypeCursorForIndex(unsigned Index);
void LoadedDecl(unsigned Index, Decl *D);
@@ -1245,6 +1277,7 @@ private:
void PassInterestingDeclToConsumer(Decl *D);
void finishPendingActions();
+ void diagnoseOdrViolations();
void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name);
@@ -1369,20 +1402,50 @@ public:
void makeNamesVisible(const HiddenNames &Names, Module *Owner,
bool FromFinalization);
+ /// \brief Take the AST callbacks listener.
+ std::unique_ptr<ASTReaderListener> takeListener() {
+ return std::move(Listener);
+ }
+
/// \brief Set the AST callbacks listener.
- void setListener(ASTReaderListener *listener) {
- Listener.reset(listener);
+ void setListener(std::unique_ptr<ASTReaderListener> Listener) {
+ this->Listener = std::move(Listener);
}
- /// \brief Add an AST callbak listener.
+ /// \brief Add an AST callback listener.
///
/// Takes ownership of \p L.
- void addListener(ASTReaderListener *L) {
+ void addListener(std::unique_ptr<ASTReaderListener> L) {
if (Listener)
- L = new ChainedASTReaderListener(L, Listener.release());
- Listener.reset(L);
+ L = llvm::make_unique<ChainedASTReaderListener>(std::move(L),
+ std::move(Listener));
+ Listener = std::move(L);
}
+ /// RAII object to temporarily add an AST callback listener.
+ class ListenerScope {
+ ASTReader &Reader;
+ bool Chained;
+
+ public:
+ ListenerScope(ASTReader &Reader, std::unique_ptr<ASTReaderListener> L)
+ : Reader(Reader), Chained(false) {
+ auto Old = Reader.takeListener();
+ if (Old) {
+ Chained = true;
+ L = llvm::make_unique<ChainedASTReaderListener>(std::move(L),
+ std::move(Old));
+ }
+ Reader.setListener(std::move(L));
+ }
+ ~ListenerScope() {
+ auto New = Reader.takeListener();
+ if (Chained)
+ Reader.setListener(static_cast<ChainedASTReaderListener *>(New.get())
+ ->takeSecond());
+ }
+ };
+
/// \brief Set the AST deserialization listener.
void setDeserializationListener(ASTDeserializationListener *Listener,
bool TakeOwnership = false);
@@ -1412,8 +1475,9 @@ public:
void UpdateSema();
/// \brief Add in-memory (virtual file) buffer.
- void addInMemoryBuffer(StringRef &FileName, llvm::MemoryBuffer *Buffer) {
- ModuleMgr.addInMemoryBuffer(FileName, Buffer);
+ void addInMemoryBuffer(StringRef &FileName,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+ ModuleMgr.addInMemoryBuffer(FileName, std::move(Buffer));
}
/// \brief Finalizes the AST reader's state before writing an AST file to
@@ -1772,6 +1836,9 @@ public:
void ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) override;
+ void ReadUnusedLocalTypedefNameCandidates(
+ llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) override;
+
void ReadLocallyScopedExternCDecls(
SmallVectorImpl<NamedDecl *> &Decls) override;
@@ -1832,17 +1899,18 @@ public:
ModuleFile &M, uint64_t Offset);
void installImportedMacro(IdentifierInfo *II, ModuleMacroInfo *MMI,
- Module *Owner, bool FromFinalization);
+ Module *Owner);
typedef llvm::TinyPtrVector<DefMacroDirective *> AmbiguousMacros;
llvm::DenseMap<IdentifierInfo*, AmbiguousMacros> AmbiguousMacroDefs;
void
- removeOverriddenMacros(IdentifierInfo *II, AmbiguousMacros &Ambig,
+ removeOverriddenMacros(IdentifierInfo *II, SourceLocation Loc,
+ AmbiguousMacros &Ambig,
ArrayRef<serialization::SubmoduleID> Overrides);
AmbiguousMacros *
- removeOverriddenMacros(IdentifierInfo *II,
+ removeOverriddenMacros(IdentifierInfo *II, SourceLocation Loc,
ArrayRef<serialization::SubmoduleID> Overrides);
/// \brief Retrieve the macro with the given ID.
@@ -1976,6 +2044,9 @@ public:
// \brief Read a string
static std::string ReadString(const RecordData &Record, unsigned &Idx);
+ // \brief Read a path
+ std::string ReadPath(ModuleFile &F, const RecordData &Record, unsigned &Idx);
+
/// \brief Read a version tuple.
static VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx);
@@ -2050,9 +2121,9 @@ public:
/// \brief Retrieve the AST context that this AST reader supplements.
ASTContext &getContext() { return Context; }
- // \brief Contains declarations that were loaded before we have
+ // \brief Contains the IDs for declarations that were requested before we have
// access to a Sema object.
- SmallVector<NamedDecl *, 16> PreloadedDecls;
+ SmallVector<uint64_t, 16> PreloadedDeclIDs;
/// \brief Retrieve the semantic analysis object used to analyze the
/// translation unit in which the precompiled header is being
@@ -2078,6 +2149,10 @@ public:
//RIDErief Loads comments ranges.
void ReadComments() override;
+
+ /// Return all input files for the given module file.
+ void getInputFiles(ModuleFile &F,
+ SmallVectorImpl<serialization::InputFile> &Files);
};
/// \brief Helper class that saves the current stream position and
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index ad6ecdd3519b..9907fae67654 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -11,8 +11,8 @@
// containing a serialized representation of a translation unit.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_AST_WRITER_H
-#define LLVM_CLANG_FRONTEND_AST_WRITER_H
+#ifndef LLVM_CLANG_SERIALIZATION_ASTWRITER_H
+#define LLVM_CLANG_SERIALIZATION_ASTWRITER_H
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/Decl.h"
@@ -111,7 +111,10 @@ private:
/// \brief The module we're currently writing, if any.
Module *WritingModule;
-
+
+ /// \brief The base directory for any relative paths we emit.
+ std::string BaseDirectory;
+
/// \brief Indicates when the AST writing is actively performing
/// serialization, rather than just queueing updates.
bool WritingAST;
@@ -283,6 +286,10 @@ private:
llvm::DenseMap<const MacroDefinition *, serialization::PreprocessedEntityID>
MacroDefinitions;
+ /// \brief Cache of indices of anonymous declarations within their lexical
+ /// contexts.
+ llvm::DenseMap<const Decl *, unsigned> AnonymousDeclarationNumbers;
+
/// An update to a Decl.
class DeclUpdate {
/// A DeclUpdateKind.
@@ -453,20 +460,23 @@ private:
StringRef isysroot, const std::string &OutputFile);
void WriteInputFiles(SourceManager &SourceMgr,
HeaderSearchOptions &HSOpts,
- StringRef isysroot,
bool Modules);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
- const Preprocessor &PP,
- StringRef isysroot);
+ const Preprocessor &PP);
void WritePreprocessor(const Preprocessor &PP, bool IsModule);
- void WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot);
+ void WriteHeaderSearch(const HeaderSearch &HS);
void WritePreprocessorDetail(PreprocessingRecord &PPRec);
void WriteSubmodules(Module *WritingModule);
void WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
bool isModule);
void WriteCXXBaseSpecifiersOffsets();
+
+ unsigned TypeExtQualAbbrev;
+ unsigned TypeFunctionProtoAbbrev;
+ void WriteTypeAbbrevs();
void WriteType(QualType T);
+
uint32_t GenerateNameLookupTable(const DeclContext *DC,
llvm::SmallVectorImpl<char> &LookupTable);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
@@ -494,17 +504,20 @@ private:
unsigned DeclContextLexicalAbbrev;
unsigned DeclContextVisibleLookupAbbrev;
unsigned UpdateVisibleAbbrev;
- unsigned DeclRefExprAbbrev;
- unsigned CharacterLiteralAbbrev;
unsigned DeclRecordAbbrev;
- unsigned IntegerLiteralAbbrev;
unsigned DeclTypedefAbbrev;
unsigned DeclVarAbbrev;
unsigned DeclFieldAbbrev;
unsigned DeclEnumAbbrev;
unsigned DeclObjCIvarAbbrev;
+ unsigned DeclCXXMethodAbbrev;
+
+ unsigned DeclRefExprAbbrev;
+ unsigned CharacterLiteralAbbrev;
+ unsigned IntegerLiteralAbbrev;
+ unsigned ExprImplicitCastAbbrev;
- void WriteDeclsBlockAbbrevs();
+ void WriteDeclAbbrevs();
void WriteDecl(ASTContext &Context, Decl *D);
void AddFunctionDefinition(const FunctionDecl *FD, RecordData &Record);
@@ -527,7 +540,8 @@ public:
/// writing a precompiled header.
///
/// \param isysroot if non-empty, write a relocatable file whose headers
- /// are relative to the given system root.
+ /// are relative to the given system root. If we're writing a module, its
+ /// build directory will be used in preference to this if both are available.
void WriteAST(Sema &SemaRef,
const std::string &OutputFile,
Module *WritingModule, StringRef isysroot,
@@ -631,6 +645,7 @@ public:
DeclarationName Name, RecordDataImpl &Record);
void AddDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
RecordDataImpl &Record);
+ unsigned getAnonymousDeclarationNumber(const NamedDecl *D);
void AddQualifierInfo(const QualifierInfo &Info, RecordDataImpl &Record);
@@ -673,6 +688,17 @@ public:
/// \brief Add a string to the given record.
void AddString(StringRef Str, RecordDataImpl &Record);
+ /// \brief Convert a path from this build process into one that is appropriate
+ /// for emission in the module file.
+ bool PreparePathForOutput(SmallVectorImpl<char> &Path);
+
+ /// \brief Add a path to the given record.
+ void AddPath(StringRef Path, RecordDataImpl &Record);
+
+ /// \brief Emit the current record with the given path as a blob.
+ void EmitRecordWithPath(unsigned Abbrev, RecordDataImpl &Record,
+ StringRef Path);
+
/// \brief Add a version tuple to the given record
void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record);
@@ -731,16 +757,26 @@ public:
void ClearSwitchCaseIDs();
+ unsigned getTypeExtQualAbbrev() const {
+ return TypeExtQualAbbrev;
+ }
+ unsigned getTypeFunctionProtoAbbrev() const {
+ return TypeFunctionProtoAbbrev;
+ }
+
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; }
+ unsigned getDeclCXXMethodAbbrev() const { return DeclCXXMethodAbbrev; }
+
+ unsigned getDeclRefExprAbbrev() const { return DeclRefExprAbbrev; }
+ unsigned getCharacterLiteralAbbrev() const { return CharacterLiteralAbbrev; }
+ unsigned getIntegerLiteralAbbrev() const { return IntegerLiteralAbbrev; }
+ unsigned getExprImplicitCastAbbrev() const { return ExprImplicitCastAbbrev; }
bool hasChain() const { return Chain; }
@@ -775,6 +811,7 @@ public:
const ObjCPropertyDecl *OrigProp,
const ObjCCategoryDecl *ClassExt) override;
void DeclarationMarkedUsed(const Decl *D) override;
+ void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
};
/// \brief AST and semantic-analysis consumer that generates a
diff --git a/include/clang/Serialization/ContinuousRangeMap.h b/include/clang/Serialization/ContinuousRangeMap.h
index f8ef8a1a63cf..5f8ae1fe7bee 100644
--- a/include/clang/Serialization/ContinuousRangeMap.h
+++ b/include/clang/Serialization/ContinuousRangeMap.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SERIALIZATION_CONTINUOUS_RANGE_MAP_H
-#define LLVM_CLANG_SERIALIZATION_CONTINUOUS_RANGE_MAP_H
+#ifndef LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H
+#define LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallVector.h"
@@ -117,6 +117,14 @@ public:
~Builder() {
std::sort(Self.Rep.begin(), Self.Rep.end(), Compare());
+ std::unique(Self.Rep.begin(), Self.Rep.end(),
+ [](const_reference A, const_reference B) {
+ // FIXME: we should not allow any duplicate keys, but there are a lot of
+ // duplicate 0 -> 0 mappings to remove first.
+ assert((A == B || A.first != B.first) &&
+ "ContinuousRangeMap::Builder given non-unique keys");
+ return A == B;
+ });
}
void insert(const value_type &Val) {
diff --git a/include/clang/Serialization/GlobalModuleIndex.h b/include/clang/Serialization/GlobalModuleIndex.h
index 1f0d7523ec29..d8a57be84a52 100644
--- a/include/clang/Serialization/GlobalModuleIndex.h
+++ b/include/clang/Serialization/GlobalModuleIndex.h
@@ -13,8 +13,8 @@
// queries such as "do any modules know about this identifier?"
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SERIALIZATION_GLOBAL_MODULE_INDEX_H
-#define LLVM_CLANG_SERIALIZATION_GLOBAL_MODULE_INDEX_H
+#ifndef LLVM_CLANG_SERIALIZATION_GLOBALMODULEINDEX_H
+#define LLVM_CLANG_SERIALIZATION_GLOBALMODULEINDEX_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -115,7 +115,7 @@ class GlobalModuleIndex {
unsigned NumIdentifierLookupHits;
/// \brief Internal constructor. Use \c readIndex() to read an index.
- explicit GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
+ explicit GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer,
llvm::BitstreamCursor Cursor);
GlobalModuleIndex(const GlobalModuleIndex &) LLVM_DELETED_FUNCTION;
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 49520390559b..426cec5dd7c2 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -42,10 +42,11 @@ namespace reader {
/// \brief Specifies the kind of module that has been loaded.
enum ModuleKind {
- MK_Module, ///< File is a module proper.
- MK_PCH, ///< File is a PCH file treated as such.
- MK_Preamble, ///< File is a PCH file treated as the preamble.
- MK_MainFile ///< File is a PCH file treated as the actual main file.
+ MK_ImplicitModule, ///< File is an implicitly-loaded module.
+ MK_ExplicitModule, ///< File is an explicitly-loaded module.
+ MK_PCH, ///< File is a PCH file treated as such.
+ MK_Preamble, ///< File is a PCH file treated as the preamble.
+ MK_MainFile ///< File is a PCH file treated as the actual main file.
};
/// \brief Information about the contents of a DeclContext.
@@ -96,6 +97,8 @@ public:
bool isNotFound() const { return Val.getInt() == NotFound; }
};
+typedef unsigned ASTFileSignature;
+
/// \brief Information about a module that has been loaded by the ASTReader.
///
/// Each instance of the Module class corresponds to a single AST file, which
@@ -122,6 +125,9 @@ public:
/// \brief The name of the module.
std::string ModuleName;
+ /// \brief The base directory of the module.
+ std::string BaseDirectory;
+
std::string getTimestampFilename() const {
return FileName + ".timestamp";
}
@@ -151,6 +157,10 @@ public:
/// \brief The file entry for the module file.
const FileEntry *File;
+ /// \brief The signature of the module file, which may be used along with size
+ /// and modification time to identify this particular file.
+ ASTFileSignature Signature;
+
/// \brief Whether this module has been directly imported by the
/// user.
bool DirectlyImported;
diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h
index 3259902222d8..3d10fad0a1b6 100644
--- a/include/clang/Serialization/ModuleManager.h
+++ b/include/clang/Serialization/ModuleManager.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SERIALIZATION_MODULE_MANAGER_H
-#define LLVM_CLANG_SERIALIZATION_MODULE_MANAGER_H
+#ifndef LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H
+#define LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H
#include "clang/Basic/FileManager.h"
#include "clang/Serialization/Module.h"
@@ -41,7 +41,8 @@ class ModuleManager {
FileManager &FileMgr;
/// \brief A lookup of in-memory (virtual file) buffers
- llvm::DenseMap<const FileEntry *, llvm::MemoryBuffer *> InMemoryBuffers;
+ llvm::DenseMap<const FileEntry *, std::unique_ptr<llvm::MemoryBuffer>>
+ InMemoryBuffers;
/// \brief The visitation order.
SmallVector<ModuleFile *, 4> VisitOrder;
@@ -141,7 +142,7 @@ public:
ModuleFile *lookup(const FileEntry *File);
/// \brief Returns the in-memory (virtual file) buffer with the given name
- llvm::MemoryBuffer *lookupBuffer(StringRef Name);
+ std::unique_ptr<llvm::MemoryBuffer> lookupBuffer(StringRef Name);
/// \brief Number of modules loaded
unsigned size() const { return Chain.size(); }
@@ -178,6 +179,12 @@ public:
/// \param ExpectedModTime The expected modification time of the module
/// file, used for validation. This will be zero if unknown.
///
+ /// \param ExpectedSignature The expected signature of the module file, used
+ /// for validation. This will be zero if unknown.
+ ///
+ /// \param ReadSignature Reads the signature from an AST file without actually
+ /// loading it.
+ ///
/// \param Module A pointer to the module file if the module was successfully
/// loaded.
///
@@ -190,6 +197,9 @@ public:
SourceLocation ImportLoc,
ModuleFile *ImportedBy, unsigned Generation,
off_t ExpectedSize, time_t ExpectedModTime,
+ ASTFileSignature ExpectedSignature,
+ std::function<ASTFileSignature(llvm::BitstreamReader &)>
+ ReadSignature,
ModuleFile *&Module,
std::string &ErrorStr);
@@ -199,7 +209,8 @@ public:
ModuleMap *modMap);
/// \brief Add an in-memory buffer the list of known buffers
- void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer);
+ void addInMemoryBuffer(StringRef FileName,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer);
/// \brief Set the global module index.
void setGlobalIndex(GlobalModuleIndex *Index);
@@ -232,7 +243,7 @@ public:
/// Any module that is known to both the global module index and the module
/// manager that is *not* in this set can be skipped.
void visit(bool (*Visitor)(ModuleFile &M, void *UserData), void *UserData,
- llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit = nullptr);
+ llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit = nullptr);
/// \brief Visit each of the modules with a depth-first traversal.
///
diff --git a/include/clang/Serialization/SerializationDiagnostic.h b/include/clang/Serialization/SerializationDiagnostic.h
index c28cfea25c87..d50422aa466c 100644
--- a/include/clang/Serialization/SerializationDiagnostic.h
+++ b/include/clang/Serialization/SerializationDiagnostic.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SERIALIZATIONDIAGNOSTIC_H
-#define LLVM_CLANG_SERIALIZATIONDIAGNOSTIC_H
+#ifndef LLVM_CLANG_SERIALIZATION_SERIALIZATIONDIAGNOSTIC_H
+#define LLVM_CLANG_SERIALIZATION_SERIALIZATIONDIAGNOSTIC_H
#include "clang/Basic/Diagnostic.h"
diff --git a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
index eee38e920898..463f04a65ac3 100644
--- a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
+++ b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_LOCALCHECKERS_H
-#define LLVM_CLANG_GR_LOCALCHECKERS_H
+#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_LOCALCHECKERS_H
+#define LLVM_CLANG_STATICANALYZER_CHECKERS_LOCALCHECKERS_H
namespace clang {
namespace ento {
diff --git a/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h b/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
index 26335bf68dd9..ab92a2465c53 100644
--- a/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
+++ b/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
@@ -16,10 +16,18 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_OBJCRETAINCOUNT_H
-#define LLVM_CLANG_OBJCRETAINCOUNT_H
+#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H
+#define LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H
-namespace clang { namespace ento { namespace objc_retain {
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+class FunctionDecl;
+class ObjCMethodDecl;
+
+namespace ento { namespace objc_retain {
/// An ArgEffect summarizes the retain count behavior on an argument or receiver
/// to a function or method.
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index 978c3e20ab20..fc9fc5ee7931 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ANALYZEROPTIONS_H
-#define LLVM_CLANG_ANALYZEROPTIONS_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
+#define LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -137,6 +137,13 @@ public:
unsigned maxBlockVisitOnPath;
+ /// \brief Disable all analyzer checks.
+ ///
+ /// This flag allows one to disable analyzer checks on the code processed by
+ /// the given analysis consumer. Note, the code will get parsed and the
+ /// command-line options will get checked.
+ unsigned DisableAllChecks : 1;
+
unsigned ShowCheckerHelp : 1;
unsigned AnalyzeAll : 1;
unsigned AnalyzerDisplayProgress : 1;
@@ -420,6 +427,7 @@ public:
AnalysisConstraintsOpt(RangeConstraintsModel),
AnalysisDiagOpt(PD_HTML),
AnalysisPurgeOpt(PurgeStmt),
+ DisableAllChecks(0),
ShowCheckerHelp(0),
AnalyzeAll(0),
AnalyzerDisplayProgress(0),
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 53712319253c..b03371ccee9c 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_BUGREPORTER
-#define LLVM_CLANG_GR_BUGREPORTER
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
#include "clang/Basic/SourceLocation.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
@@ -63,7 +63,7 @@ public:
};
typedef const SourceRange *ranges_iterator;
- typedef SmallVector<BugReporterVisitor *, 8> VisitorList;
+ typedef SmallVector<std::unique_ptr<BugReporterVisitor>, 8> VisitorList;
typedef VisitorList::iterator visitor_iterator;
typedef SmallVector<StringRef, 2> ExtraTextList;
@@ -179,9 +179,9 @@ public:
const ExplodedNode *getErrorNode() const { return ErrorNode; }
- const StringRef getDescription() const { return Description; }
+ StringRef getDescription() const { return Description; }
- const StringRef getShortDescription(bool UseFallback = true) const {
+ StringRef getShortDescription(bool UseFallback = true) const {
if (ShortDescription.empty() && UseFallback)
return Description;
return ShortDescription;
@@ -299,9 +299,9 @@ public:
/// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(),
/// registerFindLastStore(), registerNilReceiverVisitor(), and
/// registerVarDeclsLastStore().
- void addVisitor(BugReporterVisitor *visitor);
+ void addVisitor(std::unique_ptr<BugReporterVisitor> visitor);
- /// Iterators through the custom diagnostic visitors.
+ /// Iterators through the custom diagnostic visitors.
visitor_iterator visitor_begin() { return Callbacks.begin(); }
visitor_iterator visitor_end() { return Callbacks.end(); }
@@ -345,9 +345,12 @@ class BugReportEquivClass : public llvm::FoldingSetNode {
llvm::ilist<BugReport> Reports;
friend class BugReporter;
- void AddReport(BugReport* R) { Reports.push_back(R); }
+ void AddReport(std::unique_ptr<BugReport> R) {
+ Reports.push_back(R.release());
+ }
+
public:
- BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
+ BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); }
~BugReportEquivClass();
void Profile(llvm::FoldingSetNodeID& ID) const {
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index f352f806eb9c..83b05ecc52a5 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_BUGREPORTERVISITOR
-#define LLVM_CLANG_GR_BUGREPORTERVISITOR
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H
+#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/FoldingSet.h"
@@ -48,7 +48,7 @@ public:
/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
/// default implementation of clone() will NOT do the right thing, and you
/// will have to provide your own implementation.)
- virtual BugReporterVisitor *clone() const = 0;
+ virtual std::unique_ptr<BugReporterVisitor> clone() const = 0;
/// \brief Return a diagnostic piece which should be associated with the
/// given node.
@@ -66,17 +66,15 @@ public:
/// If returns NULL the default implementation will be used.
/// Also note that at most one visitor of a BugReport should generate a
/// non-NULL end of path diagnostic piece.
- virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
- const ExplodedNode *N,
- BugReport &BR);
+ virtual std::unique_ptr<PathDiagnosticPiece>
+ getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR);
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
/// \brief Generates the default final diagnostic piece.
- static PathDiagnosticPiece *getDefaultEndPath(BugReporterContext &BRC,
- const ExplodedNode *N,
- BugReport &BR);
-
+ static std::unique_ptr<PathDiagnosticPiece>
+ getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N,
+ BugReport &BR);
};
/// This class provides a convenience implementation for clone() using the
@@ -89,8 +87,8 @@ public:
/// will have to provide your own implementation.)
template <class DERIVED>
class BugReporterVisitorImpl : public BugReporterVisitor {
- BugReporterVisitor *clone() const override {
- return new DERIVED(*static_cast<const DERIVED *>(this));
+ std::unique_ptr<BugReporterVisitor> clone() const override {
+ return llvm::make_unique<DERIVED>(*static_cast<const DERIVED *>(this));
}
};
@@ -268,9 +266,9 @@ public:
return nullptr;
}
- PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
- const ExplodedNode *N,
- BugReport &BR) override;
+ std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) override;
};
/// \brief When a region containing undefined value or '0' value is passed
@@ -364,4 +362,4 @@ bool isDeclRefExprToReference(const Expr *E);
} // end namespace bugreporter
-#endif //LLVM_CLANG_GR__BUGREPORTERVISITOR
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index 24c778552ee4..16226e94df48 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
-#define LLVM_CLANG_ANALYSIS_BUGTYPE
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGTYPE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGTYPE_H
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
index 3f0fe968cc11..8df2bc331b51 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_STATIC_ANALYZER_BUG_CATEGORIES_H
-#define LLVM_CLANG_STATIC_ANALYZER_BUG_CATEGORIES_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_COMMONBUGCATEGORIES_H
+#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_COMMONBUGCATEGORIES_H
// Common strings used for the "category" of many static analyzer issues.
namespace clang {
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 5a578d015e39..b4ab1ea78545 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
-#define LLVM_CLANG_PATH_DIAGNOSTIC_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
+#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/SourceLocation.h"
@@ -94,8 +94,8 @@ public:
FilesMade *filesMade) = 0;
virtual StringRef getName() const = 0;
-
- void HandlePathDiagnostic(PathDiagnostic *D);
+
+ void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D);
enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive };
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
@@ -762,11 +762,11 @@ public:
bool isWithinCall() const { return !pathStack.empty(); }
- void setEndOfPath(PathDiagnosticPiece *EndPiece) {
+ void setEndOfPath(std::unique_ptr<PathDiagnosticPiece> EndPiece) {
assert(!Loc.isValid() && "End location already set!");
Loc = EndPiece->getLocation();
assert(Loc.isValid() && "Invalid location for end-of-path piece");
- getActivePath().push_back(EndPiece);
+ getActivePath().push_back(EndPiece.release());
}
void appendToDesc(StringRef S) {
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index b9a5b8a27fa9..8cc35148e07f 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SA_CORE_CHECKER
-#define LLVM_CLANG_SA_CORE_CHECKER
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H
#include "clang/Analysis/ProgramPoint.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index b364115c99b6..30b048023578 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SA_CORE_CHECKERMANAGER_H
-#define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/LangOptions.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index 43e9166b3cdc..ce512fd301ee 100644
--- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
+++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H
-#define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHDIAGNOSTICCONSUMERS_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHDIAGNOSTICCONSUMERS_H
#include <string>
#include <vector>
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
index 37be69aaba84..cc8a9b8ef071 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SA_CORE_APSINTTYPE_H
-#define LLVM_CLANG_SA_CORE_APSINTTYPE_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSINTTYPE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSINTTYPE_H
#include "llvm/ADT/APSInt.h"
#include <tuple>
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 1a398b86484d..dbc59cfbd9d7 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_ANALYSISMANAGER_H
-#define LLVM_CLANG_GR_ANALYSISMANAGER_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H
#include "clang/Analysis/AnalysisContext.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
@@ -23,6 +23,8 @@
namespace clang {
+class CodeInjector;
+
namespace ento {
class CheckerManager;
@@ -50,7 +52,8 @@ public:
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
- AnalyzerOptions &Options);
+ AnalyzerOptions &Options,
+ CodeInjector* injector = nullptr);
~AnalysisManager();
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 08905fdf0783..5b007f1531df 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
-#define LLVM_CLANG_GR_BASICVALUEFACTORY_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H
#include "clang/AST/ASTContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
index 0408070e493f..1d779e6cb6ec 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_BLOCKCOUNTER
-#define LLVM_CLANG_GR_BLOCKCOUNTER
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BLOCKCOUNTER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BLOCKCOUNTER_H
#include "llvm/Support/Allocator.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 4a5426b2747d..00deaa6c1977 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL
-#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLEVENT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLEVENT_H
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 5a33bdf01b3c..68274f52a60c 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
-#define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
index 12547e0969a1..6a42df20d1cb 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_PATHSENSITIVE_CHECKERHELPERS
-#define LLVM_CLANG_GR_PATHSENSITIVE_CHECKERHELPERS
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H
#include "clang/AST/Stmt.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 51bb89b9e1f9..f8760964b754 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
-#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -148,8 +148,9 @@ protected:
virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
};
-ConstraintManager* CreateRangeConstraintManager(ProgramStateManager& statemgr,
- SubEngine *subengine);
+std::unique_ptr<ConstraintManager>
+CreateRangeConstraintManager(ProgramStateManager &statemgr,
+ SubEngine *subengine);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 76ace6d7cc2a..0dafd5f3bdee 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_COREENGINE
-#define LLVM_CLANG_GR_COREENGINE
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
#include "clang/AST/Expr.h"
#include "clang/Analysis/AnalysisContext.h"
@@ -60,7 +60,7 @@ private:
SubEngine& SubEng;
/// G - The simulation graph. Each node is a (location,state) pair.
- std::unique_ptr<ExplodedGraph> G;
+ mutable ExplodedGraph G;
/// WList - A set of queued nodes that need to be processed by the
/// worklist algorithm. It is up to the implementation of WList to decide
@@ -95,6 +95,8 @@ private:
void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
ExplodedNode *Pred);
+ void HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
+ const CFGBlock *B, ExplodedNode *Pred);
/// Handle conditional logic for running static initializers.
void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
@@ -108,19 +110,12 @@ private:
public:
/// Construct a CoreEngine object to analyze the provided CFG.
- CoreEngine(SubEngine& subengine,
- FunctionSummariesTy *FS)
- : SubEng(subengine), G(new ExplodedGraph()),
- WList(WorkList::makeDFS()),
- BCounterFactory(G->getAllocator()),
- FunctionSummaries(FS){}
+ CoreEngine(SubEngine &subengine, FunctionSummariesTy *FS)
+ : SubEng(subengine), WList(WorkList::makeDFS()),
+ BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
/// getGraph - Returns the exploded graph.
- ExplodedGraph& getGraph() { return *G.get(); }
-
- /// takeGraph - Returns the exploded graph. Ownership of the graph is
- /// transferred to the caller.
- ExplodedGraph *takeGraph() { return G.release(); }
+ ExplodedGraph &getGraph() { return G; }
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
/// steps. Returns true if there is still simulation state on the worklist.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
index 5ac97dbc3145..e13c6410c7be 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SA_CORE_DYNAMICTYPEINFO_H
-#define LLVM_CLANG_SA_CORE_DYNAMICTYPEINFO_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEINFO_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEINFO_H
#include "clang/AST/Type.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index f3a582da040f..ba9715b38f3f 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_ENVIRONMENT_H
-#define LLVM_CLANG_GR_ENVIRONMENT_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H
#include "clang/Analysis/AnalysisContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index 98092ef00db7..c4eabb8c2ace 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -16,8 +16,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_EXPLODEDGRAPH
-#define LLVM_CLANG_GR_EXPLODEDGRAPH
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
#include "clang/AST/Decl.h"
#include "clang/Analysis/AnalysisContext.h"
@@ -297,8 +297,8 @@ public:
bool IsSink = false,
bool* IsNew = nullptr);
- ExplodedGraph* MakeEmptyGraph() const {
- return new ExplodedGraph();
+ std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const {
+ return llvm::make_unique<ExplodedGraph>();
}
/// addRoot - Add an untyped node to the set of roots.
@@ -372,9 +372,10 @@ public:
/// \param[out] InverseMap An optional map from nodes in the returned graph to
/// nodes in this graph.
/// \returns The trimmed graph
- ExplodedGraph *trim(ArrayRef<const NodeTy *> Nodes,
- InterExplodedGraphMap *ForwardMap = nullptr,
- InterExplodedGraphMap *InverseMap = nullptr) const;
+ std::unique_ptr<ExplodedGraph>
+ trim(ArrayRef<const NodeTy *> Nodes,
+ InterExplodedGraphMap *ForwardMap = nullptr,
+ InterExplodedGraphMap *InverseMap = nullptr) const;
/// Enable tracking of recently allocated nodes for potential reclamation
/// when calling reclaimRecentlyAllocatedNodes().
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 0fb4a245916f..247bf0c69deb 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_EXPRENGINE
-#define LLVM_CLANG_GR_EXPRENGINE
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
@@ -227,6 +227,15 @@ public:
const CFGBlock *DstT,
const CFGBlock *DstF) override;
+ /// Called by CoreEngine.
+ /// Used to generate successor nodes for temporary destructors depending
+ /// on whether the corresponding constructor was visited.
+ void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
+ NodeBuilderContext &BldCtx,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) override;
+
/// Called by CoreEngine. Used to processing branching behavior
/// at static initalizers.
void processStaticInitializer(const DeclStmt *DS,
@@ -408,7 +417,11 @@ public:
void VisitIncrementDecrementOperator(const UnaryOperator* U,
ExplodedNode *Pred,
ExplodedNodeSet &Dst);
-
+
+ void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
+ ExplodedNodeSet &PreVisit,
+ ExplodedNodeSet &Dst);
+
void VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
index 169af939f08e..faa350004511 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_FUNCTIONSUMMARY_H
-#define LLVM_CLANG_GR_FUNCTIONSUMMARY_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 92b082d5215c..1be7a2612625 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_MEMREGION_H
-#define LLVM_CLANG_GR_MEMREGION_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 4902ef50c7fe..e819b8891179 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_VALUESTATE_H
-#define LLVM_CLANG_GR_VALUESTATE_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
@@ -39,9 +39,10 @@ namespace ento {
class CallEvent;
class CallEventManager;
-typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&,
- SubEngine*);
-typedef StoreManager* (*StoreManagerCreator)(ProgramStateManager&);
+typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)(
+ ProgramStateManager &, SubEngine *);
+typedef std::unique_ptr<StoreManager>(*StoreManagerCreator)(
+ ProgramStateManager &);
//===----------------------------------------------------------------------===//
// ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
index 823bde798e55..6b4da7db244d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
@@ -15,8 +15,8 @@
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_PROGRAMSTATETRAIT_H
-#define LLVM_CLANG_GR_PROGRAMSTATETRAIT_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
#include "llvm/Support/Allocator.h"
#include "llvm/Support/DataTypes.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h
index 371f3c582f7f..415bb7713d4b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PROGRAMSTATE_FWD_H
-#define LLVM_CLANG_PROGRAMSTATE_FWD_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_FWD_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_FWD_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 29fb413d1ce7..a68d3410a87b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_SVALBUILDER
-#define LLVM_CLANG_GR_SVALBUILDER
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index d50c3be4bf5d..ef43fe0eea9a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_RVALUE_H
-#define LLVM_CLANG_GR_RVALUE_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 84c31661212f..5500c3c9efe3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_STORE_H
-#define LLVM_CLANG_GR_STORE_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
@@ -276,8 +276,10 @@ inline StoreRef &StoreRef::operator=(StoreRef const &newStore) {
}
// FIXME: Do we need to pass ProgramStateManager anymore?
-StoreManager *CreateRegionStoreManager(ProgramStateManager& StMgr);
-StoreManager *CreateFieldsOnlyRegionStoreManager(ProgramStateManager& StMgr);
+std::unique_ptr<StoreManager>
+CreateRegionStoreManager(ProgramStateManager &StMgr);
+std::unique_ptr<StoreManager>
+CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
index d5ba003a6915..958c8c377ea2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_STOREREF_H
-#define LLVM_CLANG_GR_STOREREF_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STOREREF_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STOREREF_H
#include <cassert>
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 3482e8d27dbb..741ba0e2f290 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -10,8 +10,8 @@
// This file defines the interface of a subengine of the CoreEngine.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_SUBENGINE_H
-#define LLVM_CLANG_GR_SUBENGINE_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SUBENGINE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SUBENGINE_H
#include "clang/Analysis/ProgramPoint.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
@@ -72,6 +72,16 @@ public:
const CFGBlock *DstT,
const CFGBlock *DstF) = 0;
+ /// Called by CoreEngine.
+ /// Used to generate successor nodes for temporary destructors depending
+ /// on whether the corresponding constructor was visited.
+ virtual void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
+ NodeBuilderContext &BldCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) = 0;
+
/// Called by CoreEngine. Used to processing branching behavior
/// at static initalizers.
virtual void processStaticInitializer(const DeclStmt *DS,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 2b5cc18c9a29..fbeaae48dc9c 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_SYMMGR_H
-#define LLVM_CLANG_GR_SYMMGR_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
index 4c58d4b1d261..d39b5017d312 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TAINTMANAGER_H
-#define LLVM_CLANG_TAINTMANAGER_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTMANAGER_H
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
index 8ddc8b9d6f6c..0c56e7d8ea69 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
@@ -11,8 +11,8 @@
// of taint.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TAINTTAG_H
-#define LLVM_CLANG_TAINTTAG_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTTAG_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTTAG_H
namespace clang {
namespace ento {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
index 3ed145dbd2b6..4f1a60e67556 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_WORKLIST
-#define LLVM_CLANG_GR_WORKLIST
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_WORKLIST_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_WORKLIST_H
#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
diff --git a/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h b/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
index 30e5d3dd9a2b..37ea05fb99cf 100644
--- a/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
+++ b/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_ANALYSISCONSUMER_H
-#define LLVM_CLANG_GR_ANALYSISCONSUMER_H
+#ifndef LLVM_CLANG_STATICANALYZER_FRONTEND_ANALYSISCONSUMER_H
+#define LLVM_CLANG_STATICANALYZER_FRONTEND_ANALYSISCONSUMER_H
#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/LLVM.h"
@@ -25,6 +25,8 @@ namespace clang {
class Preprocessor;
class DiagnosticsEngine;
+class CodeInjector;
+class CompilerInstance;
namespace ento {
class CheckerManager;
@@ -37,10 +39,8 @@ public:
/// CreateAnalysisConsumer - Creates an ASTConsumer to run various code
/// analysis passes. (The set of analyses run is controlled by command-line
/// options.)
-AnalysisASTConsumer *CreateAnalysisConsumer(const Preprocessor &pp,
- const std::string &output,
- AnalyzerOptionsRef opts,
- ArrayRef<std::string> plugins);
+std::unique_ptr<AnalysisASTConsumer>
+CreateAnalysisConsumer(CompilerInstance &CI);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
index 1df8c098d93d..2985b7c117ef 100644
--- a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
+++ b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
@@ -7,10 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H
-#define LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H
+#ifndef LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H
+#define LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H
#include "clang/Basic/LLVM.h"
+#include <memory>
#include <string>
namespace clang {
@@ -21,10 +22,9 @@ namespace clang {
namespace ento {
class CheckerManager;
-CheckerManager *createCheckerManager(AnalyzerOptions &opts,
- const LangOptions &langOpts,
- ArrayRef<std::string> plugins,
- DiagnosticsEngine &diags);
+ std::unique_ptr<CheckerManager>
+ createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts,
+ ArrayRef<std::string> plugins, DiagnosticsEngine &diags);
} // end ento namespace
diff --git a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
index 21ecfc234fbe..36afb4bc5d73 100644
--- a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
+++ b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
@@ -7,13 +7,17 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_FRONTENDACTIONS_H
-#define LLVM_CLANG_GR_FRONTENDACTIONS_H
+#ifndef LLVM_CLANG_STATICANALYZER_FRONTEND_FRONTENDACTIONS_H
+#define LLVM_CLANG_STATICANALYZER_FRONTEND_FRONTENDACTIONS_H
#include "clang/Frontend/FrontendAction.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
namespace clang {
+class Stmt;
+
namespace ento {
//===----------------------------------------------------------------------===//
@@ -22,8 +26,29 @@ namespace ento {
class AnalysisAction : public ASTFrontendAction {
protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
+};
+
+/// \brief Frontend action to parse model files.
+///
+/// This frontend action is responsible for parsing model files. Model files can
+/// not be parsed on their own, they rely on type information that is available
+/// in another translation unit. The parsing of model files is done by a
+/// separate compiler instance that reuses the ASTContext and othen information
+/// from the main translation unit that is being compiled. After a model file is
+/// parsed, the function definitions will be collected into a StringMap.
+class ParseModelFileAction : public ASTFrontendAction {
+public:
+ ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies);
+ bool isModelParsingAction() const override { return true; }
+
+protected:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
+
+private:
+ llvm::StringMap<Stmt *> &Bodies;
};
void printCheckerHelp(raw_ostream &OS, ArrayRef<std::string> plugins);
diff --git a/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h b/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h
new file mode 100644
index 000000000000..24f8042587f3
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h
@@ -0,0 +1,44 @@
+//===-- ModelConsumer.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements clang::ento::ModelConsumer which is an
+/// ASTConsumer for model files.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_MODELCONSUMER_H
+#define LLVM_CLANG_GR_MODELCONSUMER_H
+
+#include "clang/AST/ASTConsumer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+
+class Stmt;
+
+namespace ento {
+
+/// \brief ASTConsumer to consume model files' AST.
+///
+/// This consumer collects the bodies of function definitions into a StringMap
+/// from a model file.
+class ModelConsumer : public ASTConsumer {
+public:
+ ModelConsumer(llvm::StringMap<Stmt *> &Bodies);
+
+ bool HandleTopLevelDecl(DeclGroupRef D) override;
+
+private:
+ llvm::StringMap<Stmt *> &Bodies;
+};
+}
+}
+
+#endif
diff --git a/include/clang/Tooling/ArgumentsAdjusters.h b/include/clang/Tooling/ArgumentsAdjusters.h
index 765e7d2e051d..a92e02142005 100644
--- a/include/clang/Tooling/ArgumentsAdjusters.h
+++ b/include/clang/Tooling/ArgumentsAdjusters.h
@@ -7,59 +7,61 @@
//
//===----------------------------------------------------------------------===//
//
-// This file declares base abstract class ArgumentsAdjuster and its descendants.
-// These classes are intended to modify command line arguments obtained from
-// a compilation database before they are used to run a frontend action.
+// This file declares typedef ArgumentsAdjuster and functions to create several
+// useful argument adjusters.
+// ArgumentsAdjusters modify command line arguments obtained from a compilation
+// database before they are used to run a frontend action.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLING_ARGUMENTSADJUSTERS_H
#define LLVM_CLANG_TOOLING_ARGUMENTSADJUSTERS_H
+#include <functional>
#include <string>
#include <vector>
namespace clang {
-
namespace tooling {
/// \brief A sequence of command line arguments.
typedef std::vector<std::string> CommandLineArguments;
-/// \brief Abstract interface for a command line adjusters.
+/// \brief A prototype of a command line adjuster.
///
-/// This abstract interface describes a command line argument adjuster,
-/// which is responsible for command line arguments modification before
-/// the arguments are used to run a frontend action.
-class ArgumentsAdjuster {
- virtual void anchor();
-public:
- /// \brief Returns adjusted command line arguments.
- ///
- /// \param Args Input sequence of command line arguments.
- ///
- /// \returns Modified sequence of command line arguments.
- virtual CommandLineArguments Adjust(const CommandLineArguments &Args) = 0;
- virtual ~ArgumentsAdjuster() {
- }
-};
+/// Command line argument adjuster is responsible for command line arguments
+/// modification before the arguments are used to run a frontend action.
+typedef std::function<CommandLineArguments(const CommandLineArguments &)>
+ ArgumentsAdjuster;
-/// \brief Syntax check only command line adjuster.
-///
-/// This class implements ArgumentsAdjuster interface and converts input
-/// command line arguments to the "syntax check only" variant.
-class ClangSyntaxOnlyAdjuster : public ArgumentsAdjuster {
- CommandLineArguments Adjust(const CommandLineArguments &Args) override;
-};
+/// \brief Gets an argument adjuster that converts input command line arguments
+/// to the "syntax check only" variant.
+ArgumentsAdjuster getClangSyntaxOnlyAdjuster();
-/// \brief An argument adjuster which removes output-related command line
+/// \brief Gets an argument adjuster which removes output-related command line
/// arguments.
-class ClangStripOutputAdjuster : public ArgumentsAdjuster {
- CommandLineArguments Adjust(const CommandLineArguments &Args) override;
-};
+ArgumentsAdjuster getClangStripOutputAdjuster();
+
+enum class ArgumentInsertPosition { BEGIN, END };
+
+/// \brief Gets an argument adjuster which inserts \p Extra arguments in the
+/// specified position.
+ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra,
+ ArgumentInsertPosition Pos);
+
+/// \brief Gets an argument adjuster which inserts an \p Extra argument in the
+/// specified position.
+ArgumentsAdjuster getInsertArgumentAdjuster(
+ const char *Extra,
+ ArgumentInsertPosition Pos = ArgumentInsertPosition::END);
+
+/// \brief Gets an argument adjuster which adjusts the arguments in sequence
+/// with the \p First adjuster and then with the \p Second one.
+ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
+ ArgumentsAdjuster Second);
-} // end namespace tooling
-} // end namespace clang
+} // namespace tooling
+} // namespace clang
#endif // LLVM_CLANG_TOOLING_ARGUMENTSADJUSTERS_H
diff --git a/include/clang/Tooling/CommonOptionsParser.h b/include/clang/Tooling/CommonOptionsParser.h
index 815ede80c233..c23dc9211dc8 100644
--- a/include/clang/Tooling/CommonOptionsParser.h
+++ b/include/clang/Tooling/CommonOptionsParser.h
@@ -24,8 +24,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMONOPTIONSPARSER_H
-#define LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMONOPTIONSPARSER_H
+#ifndef LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H
+#define LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/Support/CommandLine.h"
@@ -89,6 +89,8 @@ public:
private:
std::unique_ptr<CompilationDatabase> Compilations;
std::vector<std::string> SourcePathList;
+ std::vector<std::string> ExtraArgsBefore;
+ std::vector<std::string> ExtraArgsAfter;
};
} // namespace tooling
diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h
index d1e729a88b27..27c16524e62e 100644
--- a/include/clang/Tooling/CompilationDatabase.h
+++ b/include/clang/Tooling/CompilationDatabase.h
@@ -25,8 +25,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H
-#define LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H
+#ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASE_H
+#define LLVM_CLANG_TOOLING_COMPILATIONDATABASE_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
@@ -84,22 +84,22 @@ public:
/// FIXME: Currently only supports JSON compilation databases, which
/// are named 'compile_commands.json' in the given directory. Extend this
/// for other build types (like ninja build files).
- static CompilationDatabase *loadFromDirectory(StringRef BuildDirectory,
- std::string &ErrorMessage);
+ static std::unique_ptr<CompilationDatabase>
+ loadFromDirectory(StringRef BuildDirectory, std::string &ErrorMessage);
/// \brief Tries to detect a compilation database location and load it.
///
/// Looks for a compilation database in all parent paths of file 'SourceFile'
/// by calling loadFromDirectory.
- static CompilationDatabase *autoDetectFromSource(StringRef SourceFile,
- std::string &ErrorMessage);
+ static std::unique_ptr<CompilationDatabase>
+ autoDetectFromSource(StringRef SourceFile, std::string &ErrorMessage);
/// \brief Tries to detect a compilation database location and load it.
///
/// Looks for a compilation database in directory 'SourceDir' and all
/// its parent paths by calling loadFromDirectory.
- static CompilationDatabase *autoDetectFromDirectory(StringRef SourceDir,
- std::string &ErrorMessage);
+ static std::unique_ptr<CompilationDatabase>
+ autoDetectFromDirectory(StringRef SourceDir, std::string &ErrorMessage);
/// \brief Returns all compile commands in which the specified file was
/// compiled.
@@ -142,8 +142,8 @@ public:
/// \brief Loads a compilation database from a build directory.
///
/// \see CompilationDatabase::loadFromDirectory().
- virtual CompilationDatabase *loadFromDirectory(StringRef Directory,
- std::string &ErrorMessage) = 0;
+ virtual std::unique_ptr<CompilationDatabase>
+ loadFromDirectory(StringRef Directory, std::string &ErrorMessage) = 0;
};
/// \brief A compilation database that returns a single compile command line.
@@ -213,4 +213,4 @@ private:
} // end namespace tooling
} // end namespace clang
-#endif // LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H
+#endif
diff --git a/include/clang/Tooling/CompilationDatabasePluginRegistry.h b/include/clang/Tooling/CompilationDatabasePluginRegistry.h
index 84fcd24b4a12..7323ec897403 100644
--- a/include/clang/Tooling/CompilationDatabasePluginRegistry.h
+++ b/include/clang/Tooling/CompilationDatabasePluginRegistry.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_COMPILATION_DATABASE_PLUGIN_REGISTRY_H
-#define LLVM_CLANG_TOOLING_COMPILATION_DATABASE_PLUGIN_REGISTRY_H
+#ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
+#define LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/Support/Registry.h"
@@ -24,4 +24,4 @@ typedef llvm::Registry<CompilationDatabasePlugin>
} // end namespace tooling
} // end namespace clang
-#endif // LLVM_CLANG_TOOLING_COMPILATION_DATABASE_PLUGIN_REGISTRY_H
+#endif
diff --git a/include/clang/Tooling/Core/Replacement.h b/include/clang/Tooling/Core/Replacement.h
new file mode 100644
index 000000000000..30a7036c2bb5
--- /dev/null
+++ b/include/clang/Tooling/Core/Replacement.h
@@ -0,0 +1,229 @@
+//===--- Replacement.h - Framework for clang refactoring tools --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Classes supporting refactorings that span multiple translation units.
+// While single translation unit refactorings are supported via the Rewriter,
+// when refactoring multiple translation units changes must be stored in a
+// SourceManager independent form, duplicate changes need to be removed, and
+// all changes must be applied at once at the end of the refactoring so that
+// the code is always parseable.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
+#define LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/StringRef.h"
+#include <set>
+#include <string>
+#include <vector>
+
+namespace clang {
+
+class Rewriter;
+
+namespace tooling {
+
+/// \brief A source range independent of the \c SourceManager.
+class Range {
+public:
+ Range() : Offset(0), Length(0) {}
+ Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
+
+ /// \brief Accessors.
+ /// @{
+ unsigned getOffset() const { return Offset; }
+ unsigned getLength() const { return Length; }
+ /// @}
+
+ /// \name Range Predicates
+ /// @{
+ /// \brief Whether this range overlaps with \p RHS or not.
+ bool overlapsWith(Range RHS) const {
+ return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length;
+ }
+
+ /// \brief Whether this range contains \p RHS or not.
+ bool contains(Range RHS) const {
+ return RHS.Offset >= Offset &&
+ (RHS.Offset + RHS.Length) <= (Offset + Length);
+ }
+ /// @}
+
+private:
+ unsigned Offset;
+ unsigned Length;
+};
+
+/// \brief A text replacement.
+///
+/// Represents a SourceManager independent replacement of a range of text in a
+/// specific file.
+class Replacement {
+public:
+ /// \brief Creates an invalid (not applicable) replacement.
+ Replacement();
+
+ /// \brief Creates a replacement of the range [Offset, Offset+Length) in
+ /// FilePath with ReplacementText.
+ ///
+ /// \param FilePath A source file accessible via a SourceManager.
+ /// \param Offset The byte offset of the start of the range in the file.
+ /// \param Length The length of the range in bytes.
+ Replacement(StringRef FilePath, unsigned Offset,
+ unsigned Length, StringRef ReplacementText);
+
+ /// \brief Creates a Replacement of the range [Start, Start+Length) with
+ /// ReplacementText.
+ Replacement(const SourceManager &Sources, SourceLocation Start, unsigned Length,
+ StringRef ReplacementText);
+
+ /// \brief Creates a Replacement of the given range with ReplacementText.
+ Replacement(const SourceManager &Sources, const CharSourceRange &Range,
+ StringRef ReplacementText);
+
+ /// \brief Creates a Replacement of the node with ReplacementText.
+ template <typename Node>
+ Replacement(const SourceManager &Sources, const Node &NodeToReplace,
+ StringRef ReplacementText);
+
+ /// \brief Returns whether this replacement can be applied to a file.
+ ///
+ /// Only replacements that are in a valid file can be applied.
+ bool isApplicable() const;
+
+ /// \brief Accessors.
+ /// @{
+ StringRef getFilePath() const { return FilePath; }
+ unsigned getOffset() const { return ReplacementRange.getOffset(); }
+ unsigned getLength() const { return ReplacementRange.getLength(); }
+ StringRef getReplacementText() const { return ReplacementText; }
+ /// @}
+
+ /// \brief Applies the replacement on the Rewriter.
+ bool apply(Rewriter &Rewrite) const;
+
+ /// \brief Returns a human readable string representation.
+ std::string toString() const;
+
+ private:
+ void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start,
+ unsigned Length, StringRef ReplacementText);
+ void setFromSourceRange(const SourceManager &Sources,
+ const CharSourceRange &Range,
+ StringRef ReplacementText);
+
+ std::string FilePath;
+ Range ReplacementRange;
+ std::string ReplacementText;
+};
+
+/// \brief Less-than operator between two Replacements.
+bool operator<(const Replacement &LHS, const Replacement &RHS);
+
+/// \brief Equal-to operator between two Replacements.
+bool operator==(const Replacement &LHS, const Replacement &RHS);
+
+/// \brief A set of Replacements.
+/// FIXME: Change to a vector and deduplicate in the RefactoringTool.
+typedef std::set<Replacement> Replacements;
+
+/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
+///
+/// Replacement applications happen independently of the success of
+/// other applications.
+///
+/// \returns true if all replacements apply. false otherwise.
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
+
+/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
+///
+/// Replacement applications happen independently of the success of
+/// other applications.
+///
+/// \returns true if all replacements apply. false otherwise.
+bool applyAllReplacements(const std::vector<Replacement> &Replaces,
+ Rewriter &Rewrite);
+
+/// \brief Applies all replacements in \p Replaces to \p Code.
+///
+/// This completely ignores the path stored in each replacement. If one or more
+/// replacements cannot be applied, this returns an empty \c string.
+std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
+
+/// \brief Calculates how a code \p Position is shifted when \p Replaces are
+/// applied.
+unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position);
+
+/// \brief Calculates how a code \p Position is shifted when \p Replaces are
+/// applied.
+///
+/// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset().
+unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
+ unsigned Position);
+
+/// \brief Removes duplicate Replacements and reports if Replacements conflict
+/// with one another. All Replacements are assumed to be in the same file.
+///
+/// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset().
+///
+/// This function sorts \p Replaces so that conflicts can be reported simply by
+/// offset into \p Replaces and number of elements in the conflict.
+void deduplicate(std::vector<Replacement> &Replaces,
+ std::vector<Range> &Conflicts);
+
+/// \brief Collection of Replacements generated from a single translation unit.
+struct TranslationUnitReplacements {
+ /// Name of the main source for the translation unit.
+ std::string MainSourceFile;
+
+ /// A freeform chunk of text to describe the context of the replacements.
+ /// Will be printed, for example, when detecting conflicts during replacement
+ /// deduplication.
+ std::string Context;
+
+ std::vector<Replacement> Replacements;
+};
+
+/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
+///
+/// Replacement applications happen independently of the success of
+/// other applications.
+///
+/// \returns true if all replacements apply. false otherwise.
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
+
+/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
+///
+/// Replacement applications happen independently of the success of
+/// other applications.
+///
+/// \returns true if all replacements apply. false otherwise.
+bool applyAllReplacements(const std::vector<Replacement> &Replaces,
+ Rewriter &Rewrite);
+
+/// \brief Applies all replacements in \p Replaces to \p Code.
+///
+/// This completely ignores the path stored in each replacement. If one or more
+/// replacements cannot be applied, this returns an empty \c string.
+std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
+
+template <typename Node>
+Replacement::Replacement(const SourceManager &Sources,
+ const Node &NodeToReplace, StringRef ReplacementText) {
+ const CharSourceRange Range =
+ CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
+ setFromSourceRange(Sources, Range, ReplacementText);
+}
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
diff --git a/include/clang/Tooling/FileMatchTrie.h b/include/clang/Tooling/FileMatchTrie.h
index be37baff2ffc..745c1645068a 100644
--- a/include/clang/Tooling/FileMatchTrie.h
+++ b/include/clang/Tooling/FileMatchTrie.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_FILE_MATCH_TRIE_H
-#define LLVM_CLANG_TOOLING_FILE_MATCH_TRIE_H
+#ifndef LLVM_CLANG_TOOLING_FILEMATCHTRIE_H
+#define LLVM_CLANG_TOOLING_FILEMATCHTRIE_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
@@ -86,4 +86,4 @@ private:
} // end namespace tooling
} // end namespace clang
-#endif // LLVM_CLANG_TOOLING_FILE_MATCH_TRIE_H
+#endif
diff --git a/include/clang/Tooling/JSONCompilationDatabase.h b/include/clang/Tooling/JSONCompilationDatabase.h
index 1b3335968594..b4edc31652f7 100644
--- a/include/clang/Tooling/JSONCompilationDatabase.h
+++ b/include/clang/Tooling/JSONCompilationDatabase.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_JSON_COMPILATION_DATABASE_H
-#define LLVM_CLANG_TOOLING_JSON_COMPILATION_DATABASE_H
+#ifndef LLVM_CLANG_TOOLING_JSONCOMPILATIONDATABASE_H
+#define LLVM_CLANG_TOOLING_JSONCOMPILATIONDATABASE_H
#include "clang/Basic/LLVM.h"
#include "clang/Tooling/CompilationDatabase.h"
@@ -53,14 +53,14 @@ public:
///
/// Returns NULL and sets ErrorMessage if the database could not be
/// loaded from the given file.
- static JSONCompilationDatabase *loadFromFile(StringRef FilePath,
- std::string &ErrorMessage);
+ static std::unique_ptr<JSONCompilationDatabase>
+ loadFromFile(StringRef FilePath, std::string &ErrorMessage);
/// \brief Loads a JSON compilation database from a data buffer.
///
/// Returns NULL and sets ErrorMessage if the database could not be loaded.
- static JSONCompilationDatabase *loadFromBuffer(StringRef DatabaseString,
- std::string &ErrorMessage);
+ static std::unique_ptr<JSONCompilationDatabase>
+ loadFromBuffer(StringRef DatabaseString, std::string &ErrorMessage);
/// \brief Returns all compile comamnds in which the specified file was
/// compiled.
@@ -81,8 +81,9 @@ public:
private:
/// \brief Constructs a JSON compilation database on a memory buffer.
- JSONCompilationDatabase(llvm::MemoryBuffer *Database)
- : Database(Database), YAMLStream(Database->getBuffer(), SM) {}
+ JSONCompilationDatabase(std::unique_ptr<llvm::MemoryBuffer> Database)
+ : Database(std::move(Database)),
+ YAMLStream(this->Database->getBuffer(), SM) {}
/// \brief Parses the database file and creates the index.
///
@@ -112,4 +113,4 @@ private:
} // end namespace tooling
} // end namespace clang
-#endif // LLVM_CLANG_TOOLING_JSON_COMPILATION_DATABASE_H
+#endif
diff --git a/include/clang/Tooling/Refactoring.h b/include/clang/Tooling/Refactoring.h
index cd2fb9f6c563..e3e7f83c38c8 100644
--- a/include/clang/Tooling/Refactoring.h
+++ b/include/clang/Tooling/Refactoring.h
@@ -19,180 +19,16 @@
#ifndef LLVM_CLANG_TOOLING_REFACTORING_H
#define LLVM_CLANG_TOOLING_REFACTORING_H
-#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Core/Replacement.h"
#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/StringRef.h"
-#include <set>
#include <string>
namespace clang {
class Rewriter;
-class SourceLocation;
namespace tooling {
-/// \brief A source range independent of the \c SourceManager.
-class Range {
-public:
- Range() : Offset(0), Length(0) {}
- Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
-
- /// \brief Accessors.
- /// @{
- unsigned getOffset() const { return Offset; }
- unsigned getLength() const { return Length; }
- /// @}
-
- /// \name Range Predicates
- /// @{
- /// \brief Whether this range overlaps with \p RHS or not.
- bool overlapsWith(Range RHS) const {
- return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length;
- }
-
- /// \brief Whether this range contains \p RHS or not.
- bool contains(Range RHS) const {
- return RHS.Offset >= Offset &&
- (RHS.Offset + RHS.Length) <= (Offset + Length);
- }
- /// @}
-
-private:
- unsigned Offset;
- unsigned Length;
-};
-
-/// \brief A text replacement.
-///
-/// Represents a SourceManager independent replacement of a range of text in a
-/// specific file.
-class Replacement {
-public:
- /// \brief Creates an invalid (not applicable) replacement.
- Replacement();
-
- /// \brief Creates a replacement of the range [Offset, Offset+Length) in
- /// FilePath with ReplacementText.
- ///
- /// \param FilePath A source file accessible via a SourceManager.
- /// \param Offset The byte offset of the start of the range in the file.
- /// \param Length The length of the range in bytes.
- Replacement(StringRef FilePath, unsigned Offset,
- unsigned Length, StringRef ReplacementText);
-
- /// \brief Creates a Replacement of the range [Start, Start+Length) with
- /// ReplacementText.
- Replacement(const SourceManager &Sources, SourceLocation Start, unsigned Length,
- StringRef ReplacementText);
-
- /// \brief Creates a Replacement of the given range with ReplacementText.
- Replacement(const SourceManager &Sources, const CharSourceRange &Range,
- StringRef ReplacementText);
-
- /// \brief Creates a Replacement of the node with ReplacementText.
- template <typename Node>
- Replacement(const SourceManager &Sources, const Node &NodeToReplace,
- StringRef ReplacementText);
-
- /// \brief Returns whether this replacement can be applied to a file.
- ///
- /// Only replacements that are in a valid file can be applied.
- bool isApplicable() const;
-
- /// \brief Accessors.
- /// @{
- StringRef getFilePath() const { return FilePath; }
- unsigned getOffset() const { return ReplacementRange.getOffset(); }
- unsigned getLength() const { return ReplacementRange.getLength(); }
- StringRef getReplacementText() const { return ReplacementText; }
- /// @}
-
- /// \brief Applies the replacement on the Rewriter.
- bool apply(Rewriter &Rewrite) const;
-
- /// \brief Returns a human readable string representation.
- std::string toString() const;
-
- private:
- void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start,
- unsigned Length, StringRef ReplacementText);
- void setFromSourceRange(const SourceManager &Sources,
- const CharSourceRange &Range,
- StringRef ReplacementText);
-
- std::string FilePath;
- Range ReplacementRange;
- std::string ReplacementText;
-};
-
-/// \brief Less-than operator between two Replacements.
-bool operator<(const Replacement &LHS, const Replacement &RHS);
-
-/// \brief Equal-to operator between two Replacements.
-bool operator==(const Replacement &LHS, const Replacement &RHS);
-
-/// \brief A set of Replacements.
-/// FIXME: Change to a vector and deduplicate in the RefactoringTool.
-typedef std::set<Replacement> Replacements;
-
-/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
-///
-/// Replacement applications happen independently of the success of
-/// other applications.
-///
-/// \returns true if all replacements apply. false otherwise.
-bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
-
-/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
-///
-/// Replacement applications happen independently of the success of
-/// other applications.
-///
-/// \returns true if all replacements apply. false otherwise.
-bool applyAllReplacements(const std::vector<Replacement> &Replaces,
- Rewriter &Rewrite);
-
-/// \brief Applies all replacements in \p Replaces to \p Code.
-///
-/// This completely ignores the path stored in each replacement. If one or more
-/// replacements cannot be applied, this returns an empty \c string.
-std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
-
-/// \brief Calculates how a code \p Position is shifted when \p Replaces are
-/// applied.
-unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position);
-
-/// \brief Calculates how a code \p Position is shifted when \p Replaces are
-/// applied.
-///
-/// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset().
-unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
- unsigned Position);
-
-/// \brief Removes duplicate Replacements and reports if Replacements conflict
-/// with one another.
-///
-/// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset().
-///
-/// This function sorts \p Replaces so that conflicts can be reported simply by
-/// offset into \p Replaces and number of elements in the conflict.
-void deduplicate(std::vector<Replacement> &Replaces,
- std::vector<Range> &Conflicts);
-
-/// \brief Collection of Replacements generated from a single translation unit.
-struct TranslationUnitReplacements {
- /// Name of the main source for the translation unit.
- std::string MainSourceFile;
-
- /// A freeform chunk of text to describe the context of the replacements.
- /// Will be printed, for example, when detecting conflicts during replacement
- /// deduplication.
- std::string Context;
-
- std::vector<Replacement> Replacements;
-};
-
/// \brief A tool to run refactorings.
///
/// This is a refactoring specific version of \see ClangTool. FrontendActions
@@ -230,15 +66,7 @@ private:
Replacements Replace;
};
-template <typename Node>
-Replacement::Replacement(const SourceManager &Sources,
- const Node &NodeToReplace, StringRef ReplacementText) {
- const CharSourceRange Range =
- CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
- setFromSourceRange(Sources, Range, ReplacementText);
-}
-
} // end namespace tooling
} // end namespace clang
-#endif // end namespace LLVM_CLANG_TOOLING_REFACTORING_H
+#endif // LLVM_CLANG_TOOLING_REFACTORING_H
diff --git a/include/clang/Tooling/RefactoringCallbacks.h b/include/clang/Tooling/RefactoringCallbacks.h
index 19f277431a3e..6ef9ea11f0ae 100644
--- a/include/clang/Tooling/RefactoringCallbacks.h
+++ b/include/clang/Tooling/RefactoringCallbacks.h
@@ -26,8 +26,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_REFACTORING_CALLBACKS_H
-#define LLVM_CLANG_TOOLING_REFACTORING_CALLBACKS_H
+#ifndef LLVM_CLANG_TOOLING_REFACTORINGCALLBACKS_H
+#define LLVM_CLANG_TOOLING_REFACTORINGCALLBACKS_H
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Refactoring.h"
@@ -87,4 +87,4 @@ private:
} // end namespace tooling
} // end namespace clang
-#endif // LLVM_CLANG_TOOLING_REFACTORING_CALLBACKS_H
+#endif
diff --git a/include/clang/Tooling/ReplacementsYaml.h b/include/clang/Tooling/ReplacementsYaml.h
index ac9f46908ffe..4a7666d2c555 100644
--- a/include/clang/Tooling/ReplacementsYaml.h
+++ b/include/clang/Tooling/ReplacementsYaml.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_REPLACEMENTS_YAML_H
-#define LLVM_CLANG_TOOLING_REPLACEMENTS_YAML_H
+#ifndef LLVM_CLANG_TOOLING_REPLACEMENTSYAML_H
+#define LLVM_CLANG_TOOLING_REPLACEMENTSYAML_H
#include "clang/Tooling/Refactoring.h"
#include "llvm/Support/YAMLTraits.h"
@@ -73,4 +73,4 @@ template <> struct MappingTraits<clang::tooling::TranslationUnitReplacements> {
} // end namespace yaml
} // end namespace llvm
-#endif // LLVM_CLANG_TOOLING_REPLACEMENTS_YAML_H
+#endif
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
index 769acd325367..393cc1deace5 100644
--- a/include/clang/Tooling/Tooling.h
+++ b/include/clang/Tooling/Tooling.h
@@ -30,6 +30,7 @@
#ifndef LLVM_CLANG_TOOLING_TOOLING_H
#define LLVM_CLANG_TOOLING_TOOLING_H
+#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
@@ -142,6 +143,10 @@ inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(
bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
const Twine &FileName = "input.cc");
+/// The first part of the pair is the filename, the second part the
+/// file-content.
+typedef std::vector<std::pair<std::string, std::string>> FileContentMappings;
+
/// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag and
/// with additional other flags.
///
@@ -151,9 +156,10 @@ bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
/// \param FileName The file name which 'Code' will be mapped as.
///
/// \return - True if 'ToolAction' was successfully executed.
-bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
- const std::vector<std::string> &Args,
- const Twine &FileName = "input.cc");
+bool runToolOnCodeWithArgs(
+ clang::FrontendAction *ToolAction, const Twine &Code,
+ const std::vector<std::string> &Args, const Twine &FileName = "input.cc",
+ const FileContentMappings &VirtualMappedFiles = FileContentMappings());
/// \brief Builds an AST for 'Code'.
///
@@ -202,7 +208,9 @@ class ToolInvocation {
~ToolInvocation();
/// \brief Set a \c DiagnosticConsumer to use during parsing.
- void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer);
+ void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) {
+ this->DiagConsumer = DiagConsumer;
+ }
/// \brief Map a virtual file to be used while running the tool.
///
@@ -249,10 +257,12 @@ class ClangTool {
ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths);
- virtual ~ClangTool() { clearArgumentsAdjusters(); }
+ ~ClangTool();
/// \brief Set a \c DiagnosticConsumer to use during parsing.
- void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer);
+ void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) {
+ this->DiagConsumer = DiagConsumer;
+ }
/// \brief Map a virtual file to be used while running the tool.
///
@@ -260,19 +270,11 @@ class ClangTool {
/// \param Content A null terminated buffer of the file's content.
void mapVirtualFile(StringRef FilePath, StringRef Content);
- /// \brief Install command line arguments adjuster.
- ///
- /// \param Adjuster Command line arguments adjuster.
- //
- /// FIXME: Function is deprecated. Use (clear/append)ArgumentsAdjuster instead.
- /// Remove it once all callers are gone.
- void setArgumentsAdjuster(ArgumentsAdjuster *Adjuster);
-
/// \brief Append a command line arguments adjuster to the adjuster chain.
///
/// \param Adjuster An argument adjuster, which will be run on the output of
/// previous argument adjusters.
- void appendArgumentsAdjuster(ArgumentsAdjuster *Adjuster);
+ void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster);
/// \brief Clear the command line arguments adjuster chain.
void clearArgumentsAdjusters();
@@ -292,14 +294,14 @@ class ClangTool {
FileManager &getFiles() { return *Files; }
private:
- // We store compile commands as pair (file name, compile command).
- std::vector< std::pair<std::string, CompileCommand> > CompileCommands;
+ const CompilationDatabase &Compilations;
+ std::vector<std::string> SourcePaths;
llvm::IntrusiveRefCntPtr<FileManager> Files;
// Contains a list of pairs (<file name>, <file content>).
std::vector< std::pair<StringRef, StringRef> > MappedFileContents;
- SmallVector<ArgumentsAdjuster *, 2> ArgsAdjusters;
+ ArgumentsAdjuster ArgsAdjuster;
DiagnosticConsumer *DiagConsumer;
};
@@ -335,8 +337,8 @@ inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(
SourceFileCallbacks *Callbacks)
: ConsumerFactory(ConsumerFactory), Callbacks(Callbacks) {}
- clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &,
- StringRef) override {
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &, StringRef) override {
return ConsumerFactory->newASTConsumer();
}
diff --git a/include/clang/module.modulemap b/include/clang/module.modulemap
index 03806016cc48..5058d15025d8 100644
--- a/include/clang/module.modulemap
+++ b/include/clang/module.modulemap
@@ -39,6 +39,7 @@ module Clang_Basic {
exclude header "Basic/BuiltinsR600.def"
exclude header "Basic/BuiltinsX86.def"
exclude header "Basic/BuiltinsXCore.def"
+ exclude header "Basic/BuiltinsLe64.def"
exclude header "Basic/DiagnosticOptions.def"
exclude header "Basic/LangOptions.def"
exclude header "Basic/OpenCLExtensions.def"
@@ -47,9 +48,6 @@ module Clang_Basic {
exclude header "Basic/Sanitizers.def"
exclude header "Basic/TokenKinds.def"
- // This file is one big layering violation.
- exclude header "Basic/AllDiagnostics.h"
-
// This file includes a header from Lex.
exclude header "Basic/PlistSupport.h"
@@ -62,6 +60,24 @@ module Clang_Basic {
module Clang_CodeGen { requires cplusplus umbrella "CodeGen" module * { export * } }
module Clang_Config { requires cplusplus umbrella "Config" module * { export * } }
+// Files for diagnostic groups are spread all over the include/clang/ tree, but
+// logically form a single module.
+module Clang_Diagnostics {
+ requires cplusplus
+
+ module All { header "Basic/AllDiagnostics.h" export * }
+ module Analysis { header "Analysis/AnalysisDiagnostic.h" export * }
+ module AST { header "AST/ASTDiagnostic.h" export * }
+ module Comment { header "AST/CommentDiagnostic.h" export * }
+ module Driver { header "Driver/DriverDiagnostic.h" export * }
+ module Frontend { header "Frontend/FrontendDiagnostic.h" export * }
+ module Lex { header "Lex/LexDiagnostic.h" export * }
+ module Parse { header "Parse/ParseDiagnostic.h" export * }
+ // FIXME: This breaks the build of Clang_Sema, for unknown reasons.
+ //module Sema { header "Sema/SemaDiagnostic.h" export * }
+ module Serialization { header "Serialization/SerializationDiagnostic.h" export * }
+}
+
module Clang_Driver {
requires cplusplus
umbrella "Driver"
@@ -101,9 +117,6 @@ module Clang_StaticAnalyzer {
// This file is intended for repeated textual inclusion.
exclude header "StaticAnalyzer/Core/Analyses.def"
- // FIXME: This is logically a part of Basic, but has been put in the wrong place.
- exclude header "StaticAnalyzer/Core/AnalyzerOptions.h"
-
module * { export * }
}
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index 8a13b2ee4f1d..dddc886a269c 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -446,11 +446,11 @@ public:
ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs)
: ARCMTMacroLocs(ARCMTMacroLocs) { }
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override {
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override {
CI.getPreprocessor().addPPCallbacks(
- new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs));
- return new ASTConsumer();
+ llvm::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs));
+ return llvm::make_unique<ASTConsumer>();
}
};
@@ -597,11 +597,12 @@ bool MigrationProcess::applyTransform(TransformFn trans,
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
vecOS.flush();
- llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
- StringRef(newText.data(), newText.size()), newFname);
+ std::unique_ptr<llvm::MemoryBuffer> memBuf(
+ llvm::MemoryBuffer::getMemBufferCopy(
+ StringRef(newText.data(), newText.size()), newFname));
SmallString<64> filePath(file->getName());
Unit->getFileManager().FixupRelativePath(filePath);
- Remapper.remap(filePath.str(), memBuf);
+ Remapper.remap(filePath.str(), std::move(memBuf));
}
return false;
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index 40e606090064..72a55da5d50b 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -58,9 +58,7 @@ bool FileRemapper::initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
assert(FromToMappings.empty() &&
"initFromDisk should be called before any remap calls");
std::string infoFile = filePath;
- bool fileExists = false;
- llvm::sys::fs::exists(infoFile, fileExists);
- if (!fileExists)
+ if (!llvm::sys::fs::exists(infoFile))
return false;
std::vector<std::pair<const FileEntry *, const FileEntry *> > pairs;
@@ -122,11 +120,11 @@ bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) {
bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
using namespace llvm::sys;
- std::string errMsg;
+ std::error_code EC;
std::string infoFile = outputPath;
- llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg, llvm::sys::fs::F_None);
- if (!errMsg.empty())
- return report(errMsg, Diag);
+ llvm::raw_fd_ostream infoOut(infoFile, EC, llvm::sys::fs::F_None);
+ if (EC)
+ return report(EC.message(), Diag);
for (MappingsTy::iterator
I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
@@ -173,16 +171,14 @@ bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag,
I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
const FileEntry *origFE = I->first;
assert(I->second.is<llvm::MemoryBuffer *>());
- bool fileExists = false;
- fs::exists(origFE->getName(), fileExists);
- if (!fileExists)
+ if (!fs::exists(origFE->getName()))
return report(StringRef("File does not exist: ") + origFE->getName(),
Diag);
- std::string errMsg;
- llvm::raw_fd_ostream Out(origFE->getName(), errMsg, llvm::sys::fs::F_None);
- if (!errMsg.empty())
- return report(errMsg, Diag);
+ std::error_code EC;
+ llvm::raw_fd_ostream Out(origFE->getName(), EC, llvm::sys::fs::F_None);
+ if (EC)
+ return report(EC.message(), Diag);
llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
Out.write(mem->getBufferStart(), mem->getBufferSize());
@@ -207,15 +203,17 @@ void FileRemapper::applyMappings(PreprocessorOptions &PPOpts) const {
PPOpts.RetainRemappedFileBuffers = true;
}
-void FileRemapper::remap(StringRef filePath, llvm::MemoryBuffer *memBuf) {
- remap(getOriginalFile(filePath), memBuf);
+void FileRemapper::remap(StringRef filePath,
+ std::unique_ptr<llvm::MemoryBuffer> memBuf) {
+ remap(getOriginalFile(filePath), std::move(memBuf));
}
-void FileRemapper::remap(const FileEntry *file, llvm::MemoryBuffer *memBuf) {
+void FileRemapper::remap(const FileEntry *file,
+ std::unique_ptr<llvm::MemoryBuffer> memBuf) {
assert(file);
Target &targ = FromToMappings[file];
resetTarget(targ);
- targ = memBuf;
+ targ = memBuf.release();
}
void FileRemapper::remap(const FileEntry *file, const FileEntry *newfile) {
diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h
index a65b329c5b03..4f153b1ad2f4 100644
--- a/lib/ARCMigrate/Internals.h
+++ b/lib/ARCMigrate/Internals.h
@@ -73,7 +73,7 @@ public:
bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range);
bool clearAllDiagnostics(SourceRange range) {
- return clearDiagnostic(ArrayRef<unsigned>(), range);
+ return clearDiagnostic(None, range);
}
bool clearDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) {
unsigned IDs[] = { ID1, ID2 };
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index 1a2055e9c452..52c424c000f8 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -29,6 +29,7 @@
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"
@@ -81,6 +82,8 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
void inferDesignatedInitializers(ASTContext &Ctx,
const ObjCImplementationDecl *ImplD);
+
+ bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc);
public:
std::string MigrateDir;
@@ -95,10 +98,11 @@ public:
const PPConditionalDirectiveRecord *PPRec;
Preprocessor &PP;
bool IsOutputFile;
+ bool FoundationIncluded;
llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
- llvm::StringMap<char> WhiteListFilenames;
-
+ llvm::StringSet<> WhiteListFilenames;
+
ObjCMigrateASTConsumer(StringRef migrateDir,
unsigned astMigrateActions,
FileRemapper &remapper,
@@ -111,12 +115,12 @@ public:
ASTMigrateActions(astMigrateActions),
NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr),
Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
- IsOutputFile(isOutputFile) {
+ IsOutputFile(isOutputFile),
+ FoundationIncluded(false){
- for (ArrayRef<std::string>::iterator
- I = WhiteList.begin(), E = WhiteList.end(); I != E; ++I) {
- WhiteListFilenames.GetOrCreateValue(*I);
- }
+ // FIXME: StringSet should have insert(iter, iter) to use here.
+ for (const std::string &Val : WhiteList)
+ WhiteListFilenames.insert(Val);
}
protected:
@@ -185,23 +189,17 @@ ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
MigrateDir = "."; // user current directory if none is given.
}
-ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
PPConditionalDirectiveRecord *
PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
- CompInst->getPreprocessor().addPPCallbacks(PPRec);
- ASTConsumer *
- WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
- ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
- ObjCMigAction,
- Remapper,
- CompInst->getFileManager(),
- PPRec,
- CompInst->getPreprocessor(),
- false,
- ArrayRef<std::string>());
- ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
- return new MultiplexConsumer(Consumers);
+ CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
+ std::vector<std::unique_ptr<ASTConsumer>> Consumers;
+ Consumers.push_back(WrapperFrontendAction::CreateASTConsumer(CI, InFile));
+ Consumers.push_back(llvm::make_unique<ObjCMigrateASTConsumer>(
+ MigrateDir, ObjCMigAction, Remapper, CompInst->getFileManager(), PPRec,
+ CompInst->getPreprocessor(), false, None));
+ return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
}
bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
@@ -213,6 +211,110 @@ bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
}
namespace {
+ // FIXME. This duplicates one in RewriteObjCFoundationAPI.cpp
+ bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
+ const Expr* Expr = FullExpr->IgnoreImpCasts();
+ if (isa<ArraySubscriptExpr>(Expr) ||
+ isa<CallExpr>(Expr) ||
+ isa<DeclRefExpr>(Expr) ||
+ isa<CXXNamedCastExpr>(Expr) ||
+ isa<CXXConstructExpr>(Expr) ||
+ isa<CXXThisExpr>(Expr) ||
+ isa<CXXTypeidExpr>(Expr) ||
+ isa<CXXUnresolvedConstructExpr>(Expr) ||
+ isa<ObjCMessageExpr>(Expr) ||
+ isa<ObjCPropertyRefExpr>(Expr) ||
+ isa<ObjCProtocolExpr>(Expr) ||
+ isa<MemberExpr>(Expr) ||
+ isa<ObjCIvarRefExpr>(Expr) ||
+ isa<ParenExpr>(FullExpr) ||
+ isa<ParenListExpr>(Expr) ||
+ isa<SizeOfPackExpr>(Expr))
+ return false;
+
+ return true;
+ }
+
+ /// \brief - Rewrite message expression for Objective-C setter and getters into
+ /// property-dot syntax.
+ bool rewriteToPropertyDotSyntax(const ObjCMessageExpr *Msg,
+ Preprocessor &PP,
+ const NSAPI &NS, edit::Commit &commit,
+ const ParentMap *PMap) {
+ if (!Msg || Msg->isImplicit() ||
+ (Msg->getReceiverKind() != ObjCMessageExpr::Instance &&
+ Msg->getReceiverKind() != ObjCMessageExpr::SuperInstance))
+ return false;
+ const ObjCMethodDecl *Method = Msg->getMethodDecl();
+ if (!Method)
+ return false;
+ if (!Method->isPropertyAccessor())
+ return false;
+
+ const ObjCInterfaceDecl *IFace =
+ NS.getASTContext().getObjContainingInterface(Method);
+ if (!IFace)
+ return false;
+
+ const ObjCPropertyDecl *Prop = Method->findPropertyDecl();
+ if (!Prop)
+ return false;
+
+ SourceRange MsgRange = Msg->getSourceRange();
+ bool ReceiverIsSuper =
+ (Msg->getReceiverKind() == ObjCMessageExpr::SuperInstance);
+ // for 'super' receiver is nullptr.
+ const Expr *receiver = Msg->getInstanceReceiver();
+ bool NeedsParen =
+ ReceiverIsSuper ? false : subscriptOperatorNeedsParens(receiver);
+ bool IsGetter = (Msg->getNumArgs() == 0);
+ if (IsGetter) {
+ // Find space location range between receiver expression and getter method.
+ SourceLocation BegLoc =
+ ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getLocEnd();
+ BegLoc = PP.getLocForEndOfToken(BegLoc);
+ SourceLocation EndLoc = Msg->getSelectorLoc(0);
+ SourceRange SpaceRange(BegLoc, EndLoc);
+ std::string PropertyDotString;
+ // rewrite getter method expression into: receiver.property or
+ // (receiver).property
+ if (NeedsParen) {
+ commit.insertBefore(receiver->getLocStart(), "(");
+ PropertyDotString = ").";
+ }
+ else
+ PropertyDotString = ".";
+ PropertyDotString += Prop->getName();
+ commit.replace(SpaceRange, PropertyDotString);
+
+ // remove '[' ']'
+ commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
+ commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
+ } else {
+ if (NeedsParen)
+ commit.insertWrap("(", receiver->getSourceRange(), ")");
+ std::string PropertyDotString = ".";
+ PropertyDotString += Prop->getName();
+ PropertyDotString += " =";
+ const Expr*const* Args = Msg->getArgs();
+ const Expr *RHS = Args[0];
+ if (!RHS)
+ return false;
+ SourceLocation BegLoc =
+ ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getLocEnd();
+ BegLoc = PP.getLocForEndOfToken(BegLoc);
+ SourceLocation EndLoc = RHS->getLocStart();
+ EndLoc = EndLoc.getLocWithOffset(-1);
+ SourceRange Range(BegLoc, EndLoc);
+ commit.replace(Range, PropertyDotString);
+ // remove '[' ']'
+ commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
+ commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
+ }
+ return true;
+ }
+
+
class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
ObjCMigrateASTConsumer &Consumer;
ParentMap &PMap;
@@ -237,6 +339,13 @@ public:
Consumer.Editor->commit(commit);
}
+ if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_PropertyDotSyntax) {
+ edit::Commit commit(*Consumer.Editor);
+ rewriteToPropertyDotSyntax(E, Consumer.PP, *Consumer.NSAPIObj,
+ commit, &PMap);
+ Consumer.Editor->commit(commit);
+ }
+
return true;
}
@@ -590,18 +699,32 @@ static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
return true;
}
+static StringRef GetUnsignedName(StringRef NSIntegerName) {
+ StringRef UnsignedName = llvm::StringSwitch<StringRef>(NSIntegerName)
+ .Case("int8_t", "uint8_t")
+ .Case("int16_t", "uint16_t")
+ .Case("int32_t", "uint32_t")
+ .Case("NSInteger", "NSUInteger")
+ .Case("int64_t", "uint64_t")
+ .Default(NSIntegerName);
+ return UnsignedName;
+}
+
static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
const TypedefDecl *TypedefDcl,
const NSAPI &NS, edit::Commit &commit,
- bool IsNSIntegerType,
+ StringRef NSIntegerName,
bool NSOptions) {
std::string ClassString;
- if (NSOptions)
- ClassString = "typedef NS_OPTIONS(NSUInteger, ";
- else
- ClassString =
- IsNSIntegerType ? "typedef NS_ENUM(NSInteger, "
- : "typedef NS_ENUM(NSUInteger, ";
+ if (NSOptions) {
+ ClassString = "typedef NS_OPTIONS(";
+ ClassString += GetUnsignedName(NSIntegerName);
+ }
+ else {
+ ClassString = "typedef NS_ENUM(";
+ ClassString += NSIntegerName;
+ }
+ ClassString += ", ";
ClassString += TypedefDcl->getIdentifier()->getName();
ClassString += ')';
@@ -640,18 +763,31 @@ static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
return false;
}
-static void rewriteToNSMacroDecl(const EnumDecl *EnumDcl,
+static void rewriteToNSMacroDecl(ASTContext &Ctx,
+ const EnumDecl *EnumDcl,
const TypedefDecl *TypedefDcl,
const NSAPI &NS, edit::Commit &commit,
bool IsNSIntegerType) {
- std::string ClassString =
- IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, ";
+ QualType EnumUnderlyingT = EnumDcl->getPromotionType();
+ assert(!EnumUnderlyingT.isNull()
+ && "rewriteToNSMacroDecl - underlying enum type is null");
+
+ PrintingPolicy Policy(Ctx.getPrintingPolicy());
+ std::string TypeString = EnumUnderlyingT.getAsString(Policy);
+ std::string ClassString = IsNSIntegerType ? "NS_ENUM(" : "NS_OPTIONS(";
+ ClassString += TypeString;
+ ClassString += ", ";
+
ClassString += TypedefDcl->getIdentifier()->getName();
ClassString += ')';
SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
commit.replace(R, ClassString);
- SourceLocation TypedefLoc = TypedefDcl->getLocEnd();
- commit.remove(SourceRange(TypedefLoc, TypedefLoc));
+ // This is to remove spaces between '}' and typedef name.
+ SourceLocation StartTypedefLoc = EnumDcl->getLocEnd();
+ StartTypedefLoc = StartTypedefLoc.getLocWithOffset(+1);
+ SourceLocation EndTypedefLoc = TypedefDcl->getLocEnd();
+
+ commit.remove(SourceRange(StartTypedefLoc, EndTypedefLoc));
}
static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
@@ -706,11 +842,9 @@ void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
- for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I =
- ObjCProtocolDecls.begin(),
- E = ObjCProtocolDecls.end(); I != E; ++I)
- if (!ExplicitProtocols.count(*I))
- PotentialImplicitProtocols.push_back(*I);
+ for (ObjCProtocolDecl *ProtDecl : ObjCProtocolDecls)
+ if (!ExplicitProtocols.count(ProtDecl))
+ PotentialImplicitProtocols.push_back(ProtDecl);
if (PotentialImplicitProtocols.empty())
return;
@@ -768,7 +902,7 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
const EnumDecl *EnumDcl,
const TypedefDecl *TypedefDcl) {
if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
- EnumDcl->isDeprecated())
+ EnumDcl->isDeprecated() || EnumDcl->getIntegerTypeSourceInfo())
return false;
if (!TypedefDcl) {
if (NSIntegerTypedefed) {
@@ -792,22 +926,17 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
return false;
QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
- bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt);
- bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt);
+ StringRef NSIntegerName = NSAPIObj->GetNSIntegralKind(qt);
- if (!IsNSIntegerType && !IsNSUIntegerType) {
+ if (NSIntegerName.empty()) {
// Also check for typedef enum {...} TD;
if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
if (EnumTy->getDecl() == EnumDcl) {
bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
- if (NSOptions) {
- if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
- return false;
- }
- else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
+ if (!InsertFoundation(Ctx, TypedefDcl->getLocStart()))
return false;
edit::Commit commit(*Editor);
- rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
+ rewriteToNSMacroDecl(Ctx, EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
Editor->commit(commit);
return true;
}
@@ -817,15 +946,11 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
// We may still use NS_OPTIONS based on what we find in the enumertor list.
bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
- // NS_ENUM must be available.
- if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
- return false;
- // NS_OPTIONS must be available.
- if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
+ if (!InsertFoundation(Ctx, TypedefDcl->getLocStart()))
return false;
edit::Commit commit(*Editor);
bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj,
- commit, IsNSIntegerType, NSOptions);
+ commit, NSIntegerName, NSOptions);
Editor->commit(commit);
return Res;
}
@@ -1606,6 +1731,22 @@ void ObjCMigrateASTConsumer::inferDesignatedInitializers(
}
}
+bool ObjCMigrateASTConsumer::InsertFoundation(ASTContext &Ctx,
+ SourceLocation Loc) {
+ if (FoundationIncluded)
+ return true;
+ if (Loc.isInvalid())
+ return false;
+ edit::Commit commit(*Editor);
+ if (Ctx.getLangOpts().Modules)
+ commit.insert(Loc, "#ifndef NS_ENUM\n@import Foundation;\n#endif\n");
+ else
+ commit.insert(Loc, "#ifndef NS_ENUM\n#import <Foundation/Foundation.h>\n#endif\n");
+ Editor->commit(commit);
+ FoundationIncluded = true;
+ return true;
+}
+
namespace {
class RewritesReceiver : public edit::EditsReceiver {
@@ -1799,12 +1940,12 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
}
if (IsOutputFile) {
- std::string Error;
- llvm::raw_fd_ostream OS(MigrateDir.c_str(), Error, llvm::sys::fs::F_None);
- if (!Error.empty()) {
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(MigrateDir, EC, llvm::sys::fs::F_None);
+ if (EC) {
DiagnosticsEngine &Diags = Ctx.getDiagnostics();
Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
- << Error;
+ << EC.message();
return;
}
@@ -1827,11 +1968,12 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
vecOS.flush();
- llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
- StringRef(newText.data(), newText.size()), file->getName());
+ std::unique_ptr<llvm::MemoryBuffer> memBuf(
+ llvm::MemoryBuffer::getMemBufferCopy(
+ StringRef(newText.data(), newText.size()), file->getName()));
SmallString<64> filePath(file->getName());
FileMgr.FixupRelativePath(filePath);
- Remapper.remap(filePath.str(), memBuf);
+ Remapper.remap(filePath.str(), std::move(memBuf));
}
if (IsOutputFile) {
@@ -1865,8 +2007,8 @@ static std::vector<std::string> getWhiteListFilenames(StringRef DirPath) {
return Filenames;
}
-ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
PPConditionalDirectiveRecord *
PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction;
@@ -1880,17 +2022,13 @@ ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
ObjCMTAction |= FrontendOptions::ObjCMT_Literals |
FrontendOptions::ObjCMT_Subscripting;
}
- CI.getPreprocessor().addPPCallbacks(PPRec);
+ CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
std::vector<std::string> WhiteList =
getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath);
- return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
- ObjCMTAction,
- Remapper,
- CI.getFileManager(),
- PPRec,
- CI.getPreprocessor(),
- /*isOutputFile=*/true,
- WhiteList);
+ return llvm::make_unique<ObjCMigrateASTConsumer>(
+ CI.getFrontendOpts().OutputFile, ObjCMTAction, Remapper,
+ CI.getFileManager(), PPRec, CI.getPreprocessor(),
+ /*isOutputFile=*/true, WhiteList);
}
namespace {
@@ -1949,7 +2087,7 @@ public:
return true;
llvm::SourceMgr SM;
- Stream YAMLStream(FileBufOrErr.get().release(), SM);
+ Stream YAMLStream(FileBufOrErr.get()->getMemBufferRef(), SM);
document_iterator I = YAMLStream.begin();
if (I == YAMLStream.end())
return true;
diff --git a/lib/ARCMigrate/PlistReporter.cpp b/lib/ARCMigrate/PlistReporter.cpp
index 6b34ef0c2b9e..53398b27af49 100644
--- a/lib/ARCMigrate/PlistReporter.cpp
+++ b/lib/ARCMigrate/PlistReporter.cpp
@@ -56,9 +56,9 @@ void arcmt::writeARCDiagsToPlist(const std::string &outPath,
}
}
- std::string errMsg;
- llvm::raw_fd_ostream o(outPath.c_str(), errMsg, llvm::sys::fs::F_Text);
- if (!errMsg.empty()) {
+ std::error_code EC;
+ llvm::raw_fd_ostream o(outPath, EC, llvm::sys::fs::F_Text);
+ if (EC) {
llvm::errs() << "error: could not create file: " << outPath << '\n';
return;
}
diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp
index 6d178bea0907..9fb2f1d3eea8 100644
--- a/lib/ARCMigrate/TransformActions.cpp
+++ b/lib/ARCMigrate/TransformActions.cpp
@@ -581,8 +581,7 @@ void TransformActionsImpl::applyRewrites(
/// "alive". Since the vast majority of text will be the same, we also unique
/// the strings using a StringMap.
StringRef TransformActionsImpl::getUniqueText(StringRef text) {
- llvm::StringMapEntry<bool> &entry = UniqueText.GetOrCreateValue(text);
- return entry.getKey();
+ return UniqueText.insert(std::make_pair(text, false)).first->first();
}
/// \brief Computes the source location just past the end of the token at
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 0fa0216d9dac..91f1e20d73b6 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -573,7 +573,7 @@ bool APValue::hasLValuePath() const {
ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
assert(isLValue() && hasLValuePath() && "Invalid accessor");
const LV &LVal = *((const LV*)(const char*)Data.buffer);
- return ArrayRef<LValuePathEntry>(LVal.getPath(), LVal.PathLength);
+ return llvm::makeArrayRef(LVal.getPath(), LVal.PathLength);
}
unsigned APValue::getLValueCallIndex() const {
@@ -623,7 +623,7 @@ ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
assert(isMemberPointer() && "Invalid accessor");
const MemberPointerData &MPD =
*((const MemberPointerData *)(const char *)Data.buffer);
- return ArrayRef<const CXXRecordDecl*>(MPD.getPath(), MPD.PathLength);
+ return llvm::makeArrayRef(MPD.getPath(), MPD.PathLength);
}
void APValue::MakeLValue() {
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index bccdae91d2eb..6b864d0f0ac2 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -699,9 +699,10 @@ static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T,
1, // opencl_global
2, // opencl_local
3, // opencl_constant
- 4, // cuda_device
- 5, // cuda_constant
- 6 // cuda_shared
+ 4, // opencl_generic
+ 5, // cuda_device
+ 6, // cuda_constant
+ 7 // cuda_shared
};
return &FakeAddrSpaceMap;
} else {
@@ -722,35 +723,28 @@ static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI,
llvm_unreachable("getAddressSpaceMapMangling() doesn't cover anything.");
}
-ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
+ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins)
- : FunctionProtoTypes(this_()),
- TemplateSpecializationTypes(this_()),
- DependentTemplateSpecializationTypes(this_()),
- SubstTemplateTemplateParmPacks(this_()),
- GlobalNestedNameSpecifier(nullptr),
- Int128Decl(nullptr), UInt128Decl(nullptr), Float128StubDecl(nullptr),
- BuiltinVaListDecl(nullptr),
- ObjCIdDecl(nullptr), ObjCSelDecl(nullptr), ObjCClassDecl(nullptr),
- ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr),
- CFConstantStringTypeDecl(nullptr), ObjCInstanceTypeDecl(nullptr),
- FILEDecl(nullptr),
- jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr),
- BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr),
- cudaConfigureCallDecl(nullptr),
- NullTypeSourceInfo(QualType()),
- FirstLocalImport(), LastLocalImport(),
- SourceMgr(SM), LangOpts(LOpts),
- AddrSpaceMap(nullptr), Target(nullptr), PrintingPolicy(LOpts),
- Idents(idents), Selectors(sels),
- BuiltinInfo(builtins),
- DeclarationNames(*this),
- ExternalSource(nullptr), Listener(nullptr),
- Comments(SM), CommentsLoaded(false),
- CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
- LastSDM(nullptr, 0)
-{
+ : FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()),
+ DependentTemplateSpecializationTypes(this_()),
+ SubstTemplateTemplateParmPacks(this_()),
+ GlobalNestedNameSpecifier(nullptr), Int128Decl(nullptr),
+ UInt128Decl(nullptr), Float128StubDecl(nullptr),
+ BuiltinVaListDecl(nullptr), ObjCIdDecl(nullptr), ObjCSelDecl(nullptr),
+ ObjCClassDecl(nullptr), ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr),
+ CFConstantStringTypeDecl(nullptr), ObjCInstanceTypeDecl(nullptr),
+ FILEDecl(nullptr), jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr),
+ ucontext_tDecl(nullptr), BlockDescriptorType(nullptr),
+ BlockDescriptorExtendedType(nullptr), cudaConfigureCallDecl(nullptr),
+ FirstLocalImport(), LastLocalImport(),
+ SourceMgr(SM), LangOpts(LOpts),
+ SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFile, SM)),
+ AddrSpaceMap(nullptr), Target(nullptr), PrintingPolicy(LOpts),
+ Idents(idents), Selectors(sels), BuiltinInfo(builtins),
+ DeclarationNames(*this), ExternalSource(nullptr), Listener(nullptr),
+ Comments(SM), CommentsLoaded(false),
+ CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), LastSDM(nullptr, 0) {
TUDecl = TranslationUnitDecl::Create(*this);
}
@@ -1413,9 +1407,9 @@ std::pair<CharUnits, CharUnits>
ASTContext::getTypeInfoInChars(const Type *T) const {
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T))
return getConstantArrayInfoInChars(*this, CAT);
- std::pair<uint64_t, unsigned> Info = getTypeInfo(T);
- return std::make_pair(toCharUnitsFromBits(Info.first),
- toCharUnitsFromBits(Info.second));
+ TypeInfo Info = getTypeInfo(T);
+ return std::make_pair(toCharUnitsFromBits(Info.Width),
+ toCharUnitsFromBits(Info.Align));
}
std::pair<CharUnits, CharUnits>
@@ -1423,14 +1417,23 @@ ASTContext::getTypeInfoInChars(QualType T) const {
return getTypeInfoInChars(T.getTypePtr());
}
-std::pair<uint64_t, unsigned> ASTContext::getTypeInfo(const Type *T) const {
- TypeInfoMap::iterator it = MemoizedTypeInfo.find(T);
- if (it != MemoizedTypeInfo.end())
- return it->second;
+bool ASTContext::isAlignmentRequired(const Type *T) const {
+ return getTypeInfo(T).AlignIsRequired;
+}
+
+bool ASTContext::isAlignmentRequired(QualType T) const {
+ return isAlignmentRequired(T.getTypePtr());
+}
+
+TypeInfo ASTContext::getTypeInfo(const Type *T) const {
+ TypeInfoMap::iterator I = MemoizedTypeInfo.find(T);
+ if (I != MemoizedTypeInfo.end())
+ return I->second;
- std::pair<uint64_t, unsigned> Info = getTypeInfoImpl(T);
- MemoizedTypeInfo.insert(std::make_pair(T, Info));
- return Info;
+ // This call can invalidate MemoizedTypeInfo[T], so we need a second lookup.
+ TypeInfo TI = getTypeInfoImpl(T);
+ MemoizedTypeInfo[T] = TI;
+ return TI;
}
/// getTypeInfoImpl - Return the size of the specified type, in bits. This
@@ -1439,10 +1442,10 @@ std::pair<uint64_t, unsigned> ASTContext::getTypeInfo(const Type *T) const {
/// FIXME: Pointers into different addr spaces could have different sizes and
/// alignment requirements: getPointerInfo should take an AddrSpace, this
/// should take a QualType, &c.
-std::pair<uint64_t, unsigned>
-ASTContext::getTypeInfoImpl(const Type *T) const {
- uint64_t Width=0;
- unsigned Align=8;
+TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
+ uint64_t Width = 0;
+ unsigned Align = 8;
+ bool AlignIsRequired = false;
switch (T->getTypeClass()) {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
@@ -1471,12 +1474,12 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::ConstantArray: {
const ConstantArrayType *CAT = cast<ConstantArrayType>(T);
- std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType());
+ TypeInfo EltInfo = getTypeInfo(CAT->getElementType());
uint64_t Size = CAT->getSize().getZExtValue();
- assert((Size == 0 || EltInfo.first <= (uint64_t)(-1)/Size) &&
+ assert((Size == 0 || EltInfo.Width <= (uint64_t)(-1) / Size) &&
"Overflow in array type bit size evaluation");
- Width = EltInfo.first*Size;
- Align = EltInfo.second;
+ Width = EltInfo.Width * Size;
+ Align = EltInfo.Align;
if (!getTargetInfo().getCXXABI().isMicrosoft() ||
getTargetInfo().getPointerWidth(0) == 64)
Width = llvm::RoundUpToAlignment(Width, Align);
@@ -1485,8 +1488,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::ExtVector:
case Type::Vector: {
const VectorType *VT = cast<VectorType>(T);
- std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(VT->getElementType());
- Width = EltInfo.first*VT->getNumElements();
+ TypeInfo EltInfo = getTypeInfo(VT->getElementType());
+ Width = EltInfo.Width * VT->getNumElements();
Align = Width;
// If the alignment is not a power of 2, round up to the next power of 2.
// This happens for non-power-of-2 length vectors.
@@ -1638,10 +1641,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::Complex: {
// Complex types have the same alignment as their elements, but twice the
// size.
- std::pair<uint64_t, unsigned> EltInfo =
- getTypeInfo(cast<ComplexType>(T)->getElementType());
- Width = EltInfo.first*2;
- Align = EltInfo.second;
+ TypeInfo EltInfo = getTypeInfo(cast<ComplexType>(T)->getElementType());
+ Width = EltInfo.Width * 2;
+ Align = EltInfo.Align;
break;
}
case Type::ObjCObject:
@@ -1692,16 +1694,18 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::Typedef: {
const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl();
- std::pair<uint64_t, unsigned> Info
- = getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
+ TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
// If the typedef has an aligned attribute on it, it overrides any computed
// alignment we have. This violates the GCC documentation (which says that
// attribute(aligned) can only round up) but matches its implementation.
- if (unsigned AttrAlign = Typedef->getMaxAlignment())
+ if (unsigned AttrAlign = Typedef->getMaxAlignment()) {
Align = AttrAlign;
- else
- Align = Info.second;
- Width = Info.first;
+ AlignIsRequired = true;
+ } else {
+ Align = Info.Align;
+ AlignIsRequired = Info.AlignIsRequired;
+ }
+ Width = Info.Width;
break;
}
@@ -1714,10 +1718,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::Atomic: {
// Start with the base type information.
- std::pair<uint64_t, unsigned> Info
- = getTypeInfo(cast<AtomicType>(T)->getValueType());
- Width = Info.first;
- Align = Info.second;
+ TypeInfo Info = getTypeInfo(cast<AtomicType>(T)->getValueType());
+ Width = Info.Width;
+ Align = Info.Align;
// If the size of the type doesn't exceed the platform's max
// atomic promotion width, make the size and alignment more
@@ -1735,7 +1738,7 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2");
- return std::make_pair(Width, Align);
+ return TypeInfo(Width, Align, AlignIsRequired);
}
/// toCharUnitsFromBits - Convert a size in bits to a size in characters.
@@ -1771,13 +1774,12 @@ CharUnits ASTContext::getTypeAlignInChars(const Type *T) const {
/// alignment in cases where it is beneficial for performance to overalign
/// a data type.
unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
- unsigned ABIAlign = getTypeAlign(T);
+ TypeInfo TI = getTypeInfo(T);
+ unsigned ABIAlign = TI.Align;
if (Target->getTriple().getArch() == llvm::Triple::xcore)
return ABIAlign; // Never overalign on XCore.
- const TypedefType *TT = T->getAs<TypedefType>();
-
// Double and long long should be naturally aligned if possible.
T = T->getBaseElementTypeUnsafe();
if (const ComplexType *CT = T->getAs<ComplexType>())
@@ -1787,7 +1789,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
T->isSpecificBuiltinType(BuiltinType::ULongLong))
// Don't increase the alignment if an alignment attribute was specified on a
// typedef declaration.
- if (!TT || !TT->getDecl()->getMaxAlignment())
+ if (!TI.AlignIsRequired)
return std::max(ABIAlign, (unsigned)getTypeSize(T));
return ABIAlign;
@@ -2110,6 +2112,62 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
L->DeducedReturnType(FD, ResultType);
}
+/// Get a function type and produce the equivalent function type with the
+/// specified exception specification. Type sugar that can be present on a
+/// declaration of a function with an exception specification is permitted
+/// and preserved. Other type sugar (for instance, typedefs) is not.
+static QualType getFunctionTypeWithExceptionSpec(
+ ASTContext &Context, QualType Orig,
+ const FunctionProtoType::ExceptionSpecInfo &ESI) {
+ // Might have some parens.
+ if (auto *PT = dyn_cast<ParenType>(Orig))
+ return Context.getParenType(
+ getFunctionTypeWithExceptionSpec(Context, PT->getInnerType(), ESI));
+
+ // Might have a calling-convention attribute.
+ if (auto *AT = dyn_cast<AttributedType>(Orig))
+ return Context.getAttributedType(
+ AT->getAttrKind(),
+ getFunctionTypeWithExceptionSpec(Context, AT->getModifiedType(), ESI),
+ getFunctionTypeWithExceptionSpec(Context, AT->getEquivalentType(),
+ ESI));
+
+ // Anything else must be a function type. Rebuild it with the new exception
+ // specification.
+ const FunctionProtoType *Proto = cast<FunctionProtoType>(Orig);
+ return Context.getFunctionType(
+ Proto->getReturnType(), Proto->getParamTypes(),
+ Proto->getExtProtoInfo().withExceptionSpec(ESI));
+}
+
+void ASTContext::adjustExceptionSpec(
+ FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI,
+ bool AsWritten) {
+ // Update the type.
+ QualType Updated =
+ getFunctionTypeWithExceptionSpec(*this, FD->getType(), ESI);
+ FD->setType(Updated);
+
+ if (!AsWritten)
+ return;
+
+ // Update the type in the type source information too.
+ if (TypeSourceInfo *TSInfo = FD->getTypeSourceInfo()) {
+ // If the type and the type-as-written differ, we may need to update
+ // the type-as-written too.
+ if (TSInfo->getType() != FD->getType())
+ Updated = getFunctionTypeWithExceptionSpec(*this, TSInfo->getType(), ESI);
+
+ // FIXME: When we get proper type location information for exceptions,
+ // we'll also have to rebuild the TypeSourceInfo. For now, we just patch
+ // up the TypeSourceInfo;
+ assert(TypeLoc::getFullDataSizeForType(Updated) ==
+ TypeLoc::getFullDataSizeForType(TSInfo->getType()) &&
+ "TypeLoc size mismatch from updating exception specification");
+ TSInfo->overrideType(Updated);
+ }
+}
+
/// getComplexType - Return the uniqued reference to the type for a complex
/// number with the specified element type.
QualType ASTContext::getComplexType(QualType T) const {
@@ -2840,7 +2898,7 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
// Determine whether the type being created is already canonical or not.
bool isCanonical =
- EPI.ExceptionSpecType == EST_None && isCanonicalResultType(ResultTy) &&
+ EPI.ExceptionSpec.Type == EST_None && isCanonicalResultType(ResultTy) &&
!EPI.HasTrailingReturn;
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i].isCanonicalAsParam())
@@ -2857,8 +2915,7 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI;
CanonicalEPI.HasTrailingReturn = false;
- CanonicalEPI.ExceptionSpecType = EST_None;
- CanonicalEPI.NumExceptions = 0;
+ CanonicalEPI.ExceptionSpec = FunctionProtoType::ExceptionSpecInfo();
// Result types do not have ARC lifetime qualifiers.
QualType CanResultTy = getCanonicalType(ResultTy);
@@ -2886,13 +2943,13 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
// specification.
size_t Size = sizeof(FunctionProtoType) +
NumArgs * sizeof(QualType);
- if (EPI.ExceptionSpecType == EST_Dynamic) {
- Size += EPI.NumExceptions * sizeof(QualType);
- } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+ if (EPI.ExceptionSpec.Type == EST_Dynamic) {
+ Size += EPI.ExceptionSpec.Exceptions.size() * sizeof(QualType);
+ } else if (EPI.ExceptionSpec.Type == EST_ComputedNoexcept) {
Size += sizeof(Expr*);
- } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
+ } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) {
Size += 2 * sizeof(FunctionDecl*);
- } else if (EPI.ExceptionSpecType == EST_Unevaluated) {
+ } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) {
Size += sizeof(FunctionDecl*);
}
if (EPI.ConsumedParameters)
@@ -4099,7 +4156,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
case TemplateArgument::Declaration: {
ValueDecl *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl());
- return TemplateArgument(D, Arg.isDeclForReferenceParam());
+ return TemplateArgument(D, Arg.getParamTypeForDecl());
}
case TemplateArgument::NullPtr:
@@ -4188,7 +4245,8 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
}
case NestedNameSpecifier::Global:
- // The global specifier is canonical and unique.
+ case NestedNameSpecifier::Super:
+ // The global specifier and __super specifer are canonical and unique.
return NNS;
}
@@ -4414,7 +4472,11 @@ unsigned ASTContext::getIntegerRank(const Type *T) const {
QualType ASTContext::isPromotableBitField(Expr *E) const {
if (E->isTypeDependent() || E->isValueDependent())
return QualType();
-
+
+ // FIXME: We should not do this unless E->refersToBitField() is true. This
+ // matters in C where getSourceBitField() will find bit-fields for various
+ // cases where the source expression is not a bit-field designator.
+
FieldDecl *Field = E->getSourceBitField(); // FIXME: conditional bit-fields?
if (!Field)
return QualType();
@@ -4423,9 +4485,20 @@ QualType ASTContext::isPromotableBitField(Expr *E) const {
uint64_t BitWidth = Field->getBitWidthValue(*this);
uint64_t IntSize = getTypeSize(IntTy);
- // GCC extension compatibility: if the bit-field size is less than or equal
- // to the size of int, it gets promoted no matter what its type is.
- // For instance, unsigned long bf : 4 gets promoted to signed int.
+ // C++ [conv.prom]p5:
+ // A prvalue for an integral bit-field can be converted to a prvalue of type
+ // int if int can represent all the values of the bit-field; otherwise, it
+ // can be converted to unsigned int if unsigned int can represent all the
+ // values of the bit-field. If the bit-field is larger yet, no integral
+ // promotion applies to it.
+ // C11 6.3.1.1/2:
+ // [For a bit-field of type _Bool, int, signed int, or unsigned int:]
+ // If an int can represent all values of the original type (as restricted by
+ // the width, for a bit-field), the value is converted to an int; otherwise,
+ // it is converted to an unsigned int.
+ //
+ // FIXME: C does not permit promotion of a 'long : 3' bitfield to int.
+ // We perform that promotion here to match GCC and C++.
if (BitWidth < IntSize)
return IntTy;
@@ -4433,9 +4506,10 @@ QualType ASTContext::isPromotableBitField(Expr *E) const {
return FT->isSignedIntegerType() ? IntTy : UnsignedIntTy;
// Types bigger than int are not subject to promotions, and therefore act
- // like the base type.
- // FIXME: This doesn't quite match what gcc does, but what gcc does here
- // is ridiculous.
+ // like the base type. GCC has some weird bugs in this area that we
+ // deliberately do not follow (GCC follows a pre-standard resolution to
+ // C's DR315 which treats bit-width as being part of the type, and this leaks
+ // into their semantics in some cases).
return QualType();
}
@@ -5090,13 +5164,15 @@ void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const {
}
void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
- const FieldDecl *Field) const {
+ const FieldDecl *Field,
+ QualType *NotEncodedT) const {
// We follow the behavior of gcc, expanding structures which are
// directly pointed to, and expanding embedded structures. Note that
// these rules are sufficient to prevent recursive encoding of the
// same type.
getObjCEncodingForTypeImpl(T, S, true, true, Field,
- true /* outermost type */);
+ true /* outermost type */, false, false,
+ false, false, false, NotEncodedT);
}
void ASTContext::getObjCEncodingForPropertyType(QualType T,
@@ -5222,7 +5298,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
bool StructField,
bool EncodeBlockParameters,
bool EncodeClassNames,
- bool EncodePointerToObjCTypedef) const {
+ bool EncodePointerToObjCTypedef,
+ QualType *NotEncodedT) const {
CanQualType CT = getCanonicalType(T);
switch (CT->getTypeClass()) {
case Type::Builtin:
@@ -5238,16 +5315,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
case Type::Complex: {
const ComplexType *CT = T->castAs<ComplexType>();
S += 'j';
- getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr,
- false, false);
+ getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr);
return;
}
case Type::Atomic: {
const AtomicType *AT = T->castAs<AtomicType>();
S += 'A';
- getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr,
- false, false);
+ getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr);
return;
}
@@ -5318,7 +5393,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
getLegacyIntegralTypeEncoding(PointeeTy);
getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures,
- nullptr);
+ nullptr, false, false, false, false, false, false,
+ NotEncodedT);
return;
}
@@ -5346,7 +5422,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
}
getObjCEncodingForTypeImpl(AT->getElementType(), S,
- false, ExpandStructures, FD);
+ false, ExpandStructures, FD,
+ false, false, false, false, false, false,
+ NotEncodedT);
S += ']';
}
return;
@@ -5378,7 +5456,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (ExpandStructures) {
S += '=';
if (!RDecl->isUnion()) {
- getObjCEncodingForStructureImpl(RDecl, S, FD);
+ getObjCEncodingForStructureImpl(RDecl, S, FD, true, NotEncodedT);
} else {
for (const auto *Field : RDecl->fields()) {
if (FD) {
@@ -5397,7 +5475,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
getObjCEncodingForTypeImpl(qt, S, false, true,
FD, /*OutermostType*/false,
/*EncodingProperty*/false,
- /*StructField*/true);
+ /*StructField*/true,
+ false, false, false, NotEncodedT);
}
}
}
@@ -5417,7 +5496,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
getObjCEncodingForTypeImpl(
FT->getReturnType(), S, ExpandPointedToStructures, ExpandStructures,
FD, false /* OutermostType */, EncodingProperty,
- false /* StructField */, EncodeBlockParameters, EncodeClassNames);
+ false /* StructField */, EncodeBlockParameters, EncodeClassNames, false,
+ NotEncodedT);
// Block self
S += "@?";
// Block parameters
@@ -5426,7 +5506,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
getObjCEncodingForTypeImpl(
I, S, ExpandPointedToStructures, ExpandStructures, FD,
false /* OutermostType */, EncodingProperty,
- false /* StructField */, EncodeBlockParameters, EncodeClassNames);
+ false /* StructField */, EncodeBlockParameters, EncodeClassNames,
+ false, NotEncodedT);
}
S += '>';
}
@@ -5468,7 +5549,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
else
getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD,
false, false, false, false, false,
- EncodePointerToObjCTypedef);
+ EncodePointerToObjCTypedef,
+ NotEncodedT);
}
S += '}';
return;
@@ -5555,19 +5637,21 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// gcc just blithely ignores member pointers.
// FIXME: we shoul do better than that. 'M' is available.
case Type::MemberPointer:
- return;
-
+ // This matches gcc's encoding, even though technically it is insufficient.
+ //FIXME. We should do a better job than gcc.
case Type::Vector:
case Type::ExtVector:
- // This matches gcc's encoding, even though technically it is
- // insufficient.
- // FIXME. We should do a better job than gcc.
- return;
-
+ // Until we have a coherent encoding of these three types, issue warning.
+ { if (NotEncodedT)
+ *NotEncodedT = T;
+ return;
+ }
+
+ // We could see an undeduced auto type here during error recovery.
+ // Just ignore it.
case Type::Auto:
- // We could see an undeduced auto type here during error recovery.
- // Just ignore it.
return;
+
#define ABSTRACT_TYPE(KIND, BASE)
#define TYPE(KIND, BASE)
@@ -5586,7 +5670,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
std::string &S,
const FieldDecl *FD,
- bool includeVBases) const {
+ bool includeVBases,
+ QualType *NotEncodedT) const {
assert(RDecl && "Expected non-null RecordDecl");
assert(!RDecl->isUnion() && "Should not be called for unions");
if (!RDecl->getDefinition())
@@ -5610,12 +5695,11 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
}
unsigned i = 0;
- for (RecordDecl::field_iterator Field = RDecl->field_begin(),
- FieldEnd = RDecl->field_end();
- Field != FieldEnd; ++Field, ++i) {
+ for (auto *Field : RDecl->fields()) {
uint64_t offs = layout.getFieldOffset(i);
FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
- std::make_pair(offs, *Field));
+ std::make_pair(offs, Field));
+ ++i;
}
if (CXXRec && includeVBases) {
@@ -5691,7 +5775,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
// 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);
+ getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false,
+ NotEncodedT);
assert(!base->isEmpty());
#ifndef NDEBUG
CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize());
@@ -5715,7 +5800,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
getObjCEncodingForTypeImpl(qt, S, false, true, FD,
/*OutermostType*/false,
/*EncodingProperty*/false,
- /*StructField*/true);
+ /*StructField*/true,
+ false, false, false, NotEncodedT);
#ifndef NDEBUG
CurOffs += getTypeSize(field->getType());
#endif
@@ -6654,11 +6740,9 @@ void getIntersectionOfProtocols(ASTContext &Context,
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
Context.CollectInheritedProtocols(RHS->getInterface(),
RHSInheritedProtocols);
- for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I =
- RHSInheritedProtocols.begin(),
- E = RHSInheritedProtocols.end(); I != E; ++I)
- if (InheritedProtocolSet.count((*I)))
- IntersectionOfProtocols.push_back((*I));
+ for (ObjCProtocolDecl *ProtDecl : RHSInheritedProtocols)
+ if (InheritedProtocolSet.count(ProtDecl))
+ IntersectionOfProtocols.push_back(ProtDecl);
}
}
@@ -6708,58 +6792,40 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
if (LHS->getNumProtocols() == 0)
return true;
- // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't,
- // more detailed analysis is required.
- if (RHS->getNumProtocols() == 0) {
- // OK, if LHS is a superclass of RHS *and*
- // this superclass is assignment compatible with LHS.
- // false otherwise.
- bool IsSuperClass =
- LHS->getInterface()->isSuperClassOf(RHS->getInterface());
- if (IsSuperClass) {
- // OK if conversion of LHS to SuperClass results in narrowing of types
- // ; i.e., SuperClass may implement at least one of the protocols
- // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok.
- // But not SuperObj<P1,P2,P3> = lhs<P1,P2>.
- llvm::SmallPtrSet<ObjCProtocolDecl *, 8> SuperClassInheritedProtocols;
- CollectInheritedProtocols(RHS->getInterface(), SuperClassInheritedProtocols);
- // If super class has no protocols, it is not a match.
- if (SuperClassInheritedProtocols.empty())
- return false;
+ // Okay, we know the LHS has protocol qualifiers. But RHS may or may not.
+ // More detailed analysis is required.
+ // OK, if LHS is same or a superclass of RHS *and*
+ // this LHS, or as RHS's super class is assignment compatible with LHS.
+ bool IsSuperClass =
+ LHS->getInterface()->isSuperClassOf(RHS->getInterface());
+ if (IsSuperClass) {
+ // OK if conversion of LHS to SuperClass results in narrowing of types
+ // ; i.e., SuperClass may implement at least one of the protocols
+ // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok.
+ // But not SuperObj<P1,P2,P3> = lhs<P1,P2>.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> SuperClassInheritedProtocols;
+ CollectInheritedProtocols(RHS->getInterface(), SuperClassInheritedProtocols);
+ // Also, if RHS has explicit quelifiers, include them for comparing with LHS's
+ // qualifiers.
+ for (auto *RHSPI : RHS->quals())
+ SuperClassInheritedProtocols.insert(RHSPI->getCanonicalDecl());
+ // If there is no protocols associated with RHS, it is not a match.
+ if (SuperClassInheritedProtocols.empty())
+ return false;
- for (const auto *LHSProto : LHS->quals()) {
- bool SuperImplementsProtocol = false;
- for (auto *SuperClassProto : SuperClassInheritedProtocols) {
- if (SuperClassProto->lookupProtocolNamed(LHSProto->getIdentifier())) {
- SuperImplementsProtocol = true;
- break;
- }
+ for (const auto *LHSProto : LHS->quals()) {
+ bool SuperImplementsProtocol = false;
+ for (auto *SuperClassProto : SuperClassInheritedProtocols)
+ if (SuperClassProto->lookupProtocolNamed(LHSProto->getIdentifier())) {
+ SuperImplementsProtocol = true;
+ break;
}
- if (!SuperImplementsProtocol)
- return false;
- }
- return true;
- }
- return false;
- }
-
- for (const auto *LHSPI : LHS->quals()) {
- bool RHSImplementsProtocol = false;
-
- // If the RHS doesn't implement the protocol on the left, the types
- // are incompatible.
- for (auto *RHSPI : RHS->quals()) {
- if (RHSPI->lookupProtocolNamed(LHSPI->getIdentifier())) {
- RHSImplementsProtocol = true;
- break;
- }
+ if (!SuperImplementsProtocol)
+ return false;
}
- // FIXME: For better diagnostics, consider passing back the protocol name.
- if (!RHSImplementsProtocol)
- return false;
+ return true;
}
- // The RHS implements all protocols listed on the LHS.
- return true;
+ return false;
}
bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
@@ -7895,7 +7961,9 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
// We never need to emit an uninstantiated function template.
if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
return false;
- } else
+ } else if (isa<OMPThreadPrivateDecl>(D))
+ return true;
+ else
return false;
// If this is a member of a class template, we do not need to emit it.
@@ -8236,7 +8304,7 @@ namespace {
} // end namespace
-ASTContext::ParentVector
+ArrayRef<ast_type_traits::DynTypedNode>
ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
assert(Node.getMemoizationData() &&
"Invariant broken: only nodes that support memoization may be "
@@ -8249,13 +8317,12 @@ ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
}
ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());
if (I == AllParents->end()) {
- return ParentVector();
+ return None;
}
- if (I->second.is<ast_type_traits::DynTypedNode *>()) {
- return ParentVector(1, *I->second.get<ast_type_traits::DynTypedNode *>());
+ if (auto *N = I->second.dyn_cast<ast_type_traits::DynTypedNode *>()) {
+ return llvm::makeArrayRef(N, 1);
}
- const auto &Parents = *I->second.get<ParentVector *>();
- return ParentVector(Parents.begin(), Parents.end());
+ return *I->second.get<ParentVector *>();
}
bool
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 8c8b1dff0cbf..3212359db183 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -342,26 +342,22 @@ void clang::FormatASTNodeDiagnosticArgument(
assert(DC && "Should never have a null declaration context");
NeedQuotes = false;
+ // FIXME: Get the strings for DeclContext from some localized place
if (DC->isTranslationUnit()) {
- // FIXME: Get these strings from some localized place
if (Context.getLangOpts().CPlusPlus)
OS << "the global namespace";
else
OS << "the global scope";
+ } else if (DC->isClosure()) {
+ OS << "block literal";
+ } else if (isLambdaCallOperator(DC)) {
+ OS << "lambda expression";
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
OS << ConvertTypeToDiagnosticString(Context,
Context.getTypeDeclType(Type),
PrevArgs, QualTypeVals);
} else {
- // FIXME: Get these strings from some localized place
- if (isa<BlockDecl>(DC)) {
- OS << "block literal";
- break;
- }
- if (isLambdaCallOperator(DC)) {
- OS << "lambda expression";
- break;
- }
+ assert(isa<NamedDecl>(DC) && "Expected a NamedDecl");
NamedDecl *ND = cast<NamedDecl>(DC);
if (isa<NamespaceDecl>(ND))
OS << "namespace ";
@@ -877,6 +873,194 @@ class TemplateDiff {
return Ty->getAs<TemplateSpecializationType>();
}
+ /// DiffTypes - Fills a DiffNode with information about a type difference.
+ void DiffTypes(const TSTiterator &FromIter, const TSTiterator &ToIter,
+ TemplateTypeParmDecl *FromDefaultTypeDecl,
+ TemplateTypeParmDecl *ToDefaultTypeDecl) {
+ QualType FromType = GetType(FromIter, FromDefaultTypeDecl);
+ QualType ToType = GetType(ToIter, ToDefaultTypeDecl);
+
+ Tree.SetNode(FromType, ToType);
+ Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),
+ ToIter.isEnd() && !ToType.isNull());
+ Tree.SetKind(DiffTree::Type);
+ if (FromType.isNull() || ToType.isNull())
+ return;
+
+ if (Context.hasSameType(FromType, ToType)) {
+ Tree.SetSame(true);
+ return;
+ }
+
+ const TemplateSpecializationType *FromArgTST =
+ GetTemplateSpecializationType(Context, FromType);
+ if (!FromArgTST)
+ return;
+
+ const TemplateSpecializationType *ToArgTST =
+ GetTemplateSpecializationType(Context, ToType);
+ if (!ToArgTST)
+ return;
+
+ if (!hasSameTemplate(FromArgTST, ToArgTST))
+ return;
+
+ Qualifiers FromQual = FromType.getQualifiers(),
+ ToQual = ToType.getQualifiers();
+ FromQual -= QualType(FromArgTST, 0).getQualifiers();
+ ToQual -= QualType(ToArgTST, 0).getQualifiers();
+ Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
+ ToArgTST->getTemplateName().getAsTemplateDecl());
+ Tree.SetNode(FromQual, ToQual);
+ Tree.SetKind(DiffTree::Template);
+ DiffTemplate(FromArgTST, ToArgTST);
+ }
+
+ /// DiffTemplateTemplates - Fills a DiffNode with information about a
+ /// template template difference.
+ void DiffTemplateTemplates(const TSTiterator &FromIter,
+ const TSTiterator &ToIter,
+ TemplateTemplateParmDecl *FromDefaultTemplateDecl,
+ TemplateTemplateParmDecl *ToDefaultTemplateDecl) {
+ TemplateDecl *FromDecl = GetTemplateDecl(FromIter, FromDefaultTemplateDecl);
+ TemplateDecl *ToDecl = GetTemplateDecl(ToIter, ToDefaultTemplateDecl);
+ Tree.SetNode(FromDecl, ToDecl);
+ Tree.SetSame(FromDecl && ToDecl &&
+ FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl());
+ Tree.SetDefault(FromIter.isEnd() && FromDecl, ToIter.isEnd() && ToDecl);
+ Tree.SetKind(DiffTree::TemplateTemplate);
+ }
+
+ /// InitializeNonTypeDiffVariables - Helper function for DiffNonTypes
+ static void InitializeNonTypeDiffVariables(
+ ASTContext &Context, const TSTiterator &Iter,
+ NonTypeTemplateParmDecl *Default, bool &HasInt, bool &HasValueDecl,
+ bool &IsNullPtr, Expr *&E, llvm::APSInt &Value, ValueDecl *&VD) {
+ HasInt = !Iter.isEnd() && Iter->getKind() == TemplateArgument::Integral;
+
+ HasValueDecl =
+ !Iter.isEnd() && Iter->getKind() == TemplateArgument::Declaration;
+
+ IsNullPtr = !Iter.isEnd() && Iter->getKind() == TemplateArgument::NullPtr;
+
+ if (HasInt)
+ Value = Iter->getAsIntegral();
+ else if (HasValueDecl)
+ VD = Iter->getAsDecl();
+ else if (!IsNullPtr)
+ E = GetExpr(Iter, Default);
+
+ if (E && Default->getType()->isPointerType())
+ IsNullPtr = CheckForNullPtr(Context, E);
+ }
+
+ /// NeedsAddressOf - Helper function for DiffNonTypes. Returns true if the
+ /// ValueDecl needs a '&' when printed.
+ static bool NeedsAddressOf(ValueDecl *VD, Expr *E,
+ NonTypeTemplateParmDecl *Default) {
+ if (!VD)
+ return false;
+
+ if (E) {
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
+ if (UO->getOpcode() == UO_AddrOf) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (!Default->getType()->isReferenceType()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /// DiffNonTypes - Handles any template parameters not handled by DiffTypes
+ /// of DiffTemplatesTemplates, such as integer and declaration parameters.
+ void DiffNonTypes(const TSTiterator &FromIter, const TSTiterator &ToIter,
+ NonTypeTemplateParmDecl *FromDefaultNonTypeDecl,
+ NonTypeTemplateParmDecl *ToDefaultNonTypeDecl) {
+ Expr *FromExpr = nullptr, *ToExpr = nullptr;
+ llvm::APSInt FromInt, ToInt;
+ ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr;
+ bool HasFromInt = false, HasToInt = false, HasFromValueDecl = false,
+ HasToValueDecl = false, FromNullPtr = false, ToNullPtr = false;
+ InitializeNonTypeDiffVariables(Context, FromIter, FromDefaultNonTypeDecl,
+ HasFromInt, HasFromValueDecl, FromNullPtr,
+ FromExpr, FromInt, FromValueDecl);
+ InitializeNonTypeDiffVariables(Context, ToIter, ToDefaultNonTypeDecl,
+ HasToInt, HasToValueDecl, ToNullPtr,
+ ToExpr, ToInt, ToValueDecl);
+
+ assert(((!HasFromInt && !HasToInt) ||
+ (!HasFromValueDecl && !HasToValueDecl)) &&
+ "Template argument cannot be both integer and declaration");
+
+ unsigned ParamWidth = 128; // Safe default
+ if (FromDefaultNonTypeDecl->getType()->isIntegralOrEnumerationType())
+ ParamWidth = Context.getIntWidth(FromDefaultNonTypeDecl->getType());
+
+ if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) {
+ Tree.SetNode(FromExpr, ToExpr);
+ Tree.SetDefault(FromIter.isEnd() && FromExpr, ToIter.isEnd() && ToExpr);
+ if (FromDefaultNonTypeDecl->getType()->isIntegralOrEnumerationType()) {
+ if (FromExpr)
+ HasFromInt = GetInt(Context, FromIter, FromExpr, FromInt);
+ if (ToExpr)
+ HasToInt = GetInt(Context, ToIter, ToExpr, ToInt);
+ }
+ if (HasFromInt && HasToInt) {
+ Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
+ Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
+ Tree.SetKind(DiffTree::Integer);
+ } else if (HasFromInt || HasToInt) {
+ Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
+ Tree.SetSame(false);
+ Tree.SetKind(DiffTree::Integer);
+ } else {
+ Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr) ||
+ (FromNullPtr && ToNullPtr));
+ Tree.SetNullPtr(FromNullPtr, ToNullPtr);
+ Tree.SetKind(DiffTree::Expression);
+ }
+ return;
+ }
+
+ if (HasFromInt || HasToInt) {
+ if (!HasFromInt && FromExpr)
+ HasFromInt = GetInt(Context, FromIter, FromExpr, FromInt);
+ if (!HasToInt && ToExpr)
+ HasToInt = GetInt(Context, ToIter, ToExpr, ToInt);
+ Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
+ Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
+ Tree.SetDefault(FromIter.isEnd() && HasFromInt,
+ ToIter.isEnd() && HasToInt);
+ Tree.SetKind(DiffTree::Integer);
+ return;
+ }
+
+ if (!HasFromValueDecl && FromExpr)
+ FromValueDecl = GetValueDecl(FromIter, FromExpr);
+ if (!HasToValueDecl && ToExpr)
+ ToValueDecl = GetValueDecl(ToIter, ToExpr);
+
+ bool FromAddressOf =
+ NeedsAddressOf(FromValueDecl, FromExpr, FromDefaultNonTypeDecl);
+ bool ToAddressOf =
+ NeedsAddressOf(ToValueDecl, ToExpr, ToDefaultNonTypeDecl);
+
+ Tree.SetNullPtr(FromNullPtr, ToNullPtr);
+ Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
+ Tree.SetSame(FromValueDecl && ToValueDecl &&
+ FromValueDecl->getCanonicalDecl() ==
+ ToValueDecl->getCanonicalDecl());
+ Tree.SetDefault(FromIter.isEnd() && FromValueDecl,
+ ToIter.isEnd() && ToValueDecl);
+ Tree.SetKind(DiffTree::Declaration);
+ }
+
/// DiffTemplate - recursively visits template arguments and stores the
/// argument info into a tree.
void DiffTemplate(const TemplateSpecializationType *FromTST,
@@ -894,191 +1078,33 @@ class TemplateDiff {
// Get the parameter at index TotalArgs. If index is larger
// than the total number of parameters, then there is an
// argument pack, so re-use the last parameter.
- unsigned ParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1);
- NamedDecl *ParamND = ParamsFrom->getParam(ParamIndex);
-
- // Handle Types
- if (TemplateTypeParmDecl *DefaultTTPD =
- dyn_cast<TemplateTypeParmDecl>(ParamND)) {
- QualType FromType, ToType;
- FromType = GetType(FromIter, DefaultTTPD);
- // A forward declaration can have no default arg but the actual class
- // can, don't mix up iterators and get the original parameter.
- ToType = GetType(
- ToIter, cast<TemplateTypeParmDecl>(ParamsTo->getParam(ParamIndex)));
- Tree.SetNode(FromType, ToType);
- Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),
- ToIter.isEnd() && !ToType.isNull());
- Tree.SetKind(DiffTree::Type);
- if (!FromType.isNull() && !ToType.isNull()) {
- if (Context.hasSameType(FromType, ToType)) {
- Tree.SetSame(true);
- } else {
- Qualifiers FromQual = FromType.getQualifiers(),
- ToQual = ToType.getQualifiers();
- const TemplateSpecializationType *FromArgTST =
- GetTemplateSpecializationType(Context, FromType);
- const TemplateSpecializationType *ToArgTST =
- GetTemplateSpecializationType(Context, ToType);
-
- if (FromArgTST && ToArgTST &&
- hasSameTemplate(FromArgTST, ToArgTST)) {
- FromQual -= QualType(FromArgTST, 0).getQualifiers();
- ToQual -= QualType(ToArgTST, 0).getQualifiers();
- Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
- ToArgTST->getTemplateName().getAsTemplateDecl());
- Tree.SetNode(FromQual, ToQual);
- Tree.SetKind(DiffTree::Template);
- DiffTemplate(FromArgTST, ToArgTST);
- }
- }
- }
- }
-
- // Handle Expressions
- if (NonTypeTemplateParmDecl *DefaultNTTPD =
- dyn_cast<NonTypeTemplateParmDecl>(ParamND)) {
- Expr *FromExpr = nullptr, *ToExpr = nullptr;
- llvm::APSInt FromInt, ToInt;
- ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr;
- unsigned ParamWidth = 128; // Safe default
- if (DefaultNTTPD->getType()->isIntegralOrEnumerationType())
- ParamWidth = Context.getIntWidth(DefaultNTTPD->getType());
- bool HasFromInt = !FromIter.isEnd() &&
- FromIter->getKind() == TemplateArgument::Integral;
- bool HasToInt = !ToIter.isEnd() &&
- ToIter->getKind() == TemplateArgument::Integral;
- bool HasFromValueDecl =
- !FromIter.isEnd() &&
- FromIter->getKind() == TemplateArgument::Declaration;
- bool HasToValueDecl =
- !ToIter.isEnd() &&
- ToIter->getKind() == TemplateArgument::Declaration;
- bool FromNullPtr = !FromIter.isEnd() &&
- FromIter->getKind() == TemplateArgument::NullPtr;
- bool ToNullPtr =
- !ToIter.isEnd() && ToIter->getKind() == TemplateArgument::NullPtr;
-
- assert(((!HasFromInt && !HasToInt) ||
- (!HasFromValueDecl && !HasToValueDecl)) &&
- "Template argument cannot be both integer and declaration");
-
- if (HasFromInt)
- FromInt = FromIter->getAsIntegral();
- else if (HasFromValueDecl)
- FromValueDecl = FromIter->getAsDecl();
- else if (!FromNullPtr)
- FromExpr = GetExpr(FromIter, DefaultNTTPD);
-
- if (HasToInt)
- ToInt = ToIter->getAsIntegral();
- else if (HasToValueDecl)
- ToValueDecl = ToIter->getAsDecl();
- else if (!ToNullPtr)
- ToExpr = GetExpr(ToIter, DefaultNTTPD);
-
- bool TemplateArgumentIsPointerType =
- DefaultNTTPD->getType()->isPointerType();
- if (FromExpr && TemplateArgumentIsPointerType) {
- FromNullPtr = CheckForNullPtr(FromExpr);
- }
- if (ToExpr && TemplateArgumentIsPointerType) {
- ToNullPtr = CheckForNullPtr(ToExpr);
- }
-
- if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) {
- Tree.SetNode(FromExpr, ToExpr);
- Tree.SetDefault(FromIter.isEnd() && FromExpr,
- ToIter.isEnd() && ToExpr);
- if (DefaultNTTPD->getType()->isIntegralOrEnumerationType()) {
- if (FromExpr)
- HasFromInt = GetInt(FromIter, FromExpr, FromInt);
- if (ToExpr)
- HasToInt = GetInt(ToIter, ToExpr, ToInt);
- }
- if (HasFromInt && HasToInt) {
- Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
- Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
- Tree.SetKind(DiffTree::Integer);
- } else if (HasFromInt || HasToInt) {
- Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
- Tree.SetSame(false);
- Tree.SetKind(DiffTree::Integer);
- } else {
- Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr) ||
- (FromNullPtr && ToNullPtr));
- Tree.SetNullPtr(FromNullPtr, ToNullPtr);
- Tree.SetKind(DiffTree::Expression);
- }
- } else if (HasFromInt || HasToInt) {
- if (!HasFromInt && FromExpr)
- HasFromInt = GetInt(FromIter, FromExpr, FromInt);
- if (!HasToInt && ToExpr)
- HasToInt = GetInt(ToIter, ToExpr, ToInt);
- Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
- Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
- Tree.SetDefault(FromIter.isEnd() && HasFromInt,
- ToIter.isEnd() && HasToInt);
- Tree.SetKind(DiffTree::Integer);
- } else {
- if (!HasFromValueDecl && FromExpr)
- FromValueDecl = GetValueDecl(FromIter, FromExpr);
- if (!HasToValueDecl && ToExpr)
- ToValueDecl = GetValueDecl(ToIter, ToExpr);
- QualType ArgumentType = DefaultNTTPD->getType();
- bool FromAddressOf = false;
- if (FromValueDecl) {
- if (FromExpr) {
- if (UnaryOperator *UO =
- dyn_cast<UnaryOperator>(FromExpr->IgnoreParens())) {
- if (UO->getOpcode() == UO_AddrOf)
- FromAddressOf = true;
- }
- } else {
- if (!ArgumentType->isReferenceType()) {
- FromAddressOf = true;
- }
- }
- }
- bool ToAddressOf = false;
- if (ToValueDecl) {
- if (ToExpr) {
- if (UnaryOperator *UO =
- dyn_cast<UnaryOperator>(ToExpr->IgnoreParens())) {
- if (UO->getOpcode() == UO_AddrOf) {
- ToAddressOf = true;
- }
- }
- } else {
- if (!ArgumentType->isReferenceType()) {
- ToAddressOf = true;
- }
- }
- }
- Tree.SetNullPtr(FromNullPtr, ToNullPtr);
- Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
- Tree.SetSame(FromValueDecl && ToValueDecl &&
- FromValueDecl->getCanonicalDecl() ==
- ToValueDecl->getCanonicalDecl());
- Tree.SetDefault(FromIter.isEnd() && FromValueDecl,
- ToIter.isEnd() && ToValueDecl);
- Tree.SetKind(DiffTree::Declaration);
- }
- }
-
- // Handle Templates
- if (TemplateTemplateParmDecl *DefaultTTPD =
- dyn_cast<TemplateTemplateParmDecl>(ParamND)) {
- TemplateDecl *FromDecl, *ToDecl;
- FromDecl = GetTemplateDecl(FromIter, DefaultTTPD);
- ToDecl = GetTemplateDecl(ToIter, DefaultTTPD);
- Tree.SetNode(FromDecl, ToDecl);
- Tree.SetSame(
- FromDecl && ToDecl &&
- FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl());
- Tree.SetDefault(FromIter.isEnd() && FromDecl, ToIter.isEnd() && ToDecl);
- Tree.SetKind(DiffTree::TemplateTemplate);
- }
+ unsigned FromParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1);
+ unsigned ToParamIndex = std::min(TotalArgs, ParamsTo->size() - 1);
+ NamedDecl *FromParamND = ParamsFrom->getParam(FromParamIndex);
+ NamedDecl *ToParamND = ParamsTo->getParam(ToParamIndex);
+
+ TemplateTypeParmDecl *FromDefaultTypeDecl =
+ dyn_cast<TemplateTypeParmDecl>(FromParamND);
+ TemplateTypeParmDecl *ToDefaultTypeDecl =
+ dyn_cast<TemplateTypeParmDecl>(ToParamND);
+ if (FromDefaultTypeDecl && ToDefaultTypeDecl)
+ DiffTypes(FromIter, ToIter, FromDefaultTypeDecl, ToDefaultTypeDecl);
+
+ TemplateTemplateParmDecl *FromDefaultTemplateDecl =
+ dyn_cast<TemplateTemplateParmDecl>(FromParamND);
+ TemplateTemplateParmDecl *ToDefaultTemplateDecl =
+ dyn_cast<TemplateTemplateParmDecl>(ToParamND);
+ if (FromDefaultTemplateDecl && ToDefaultTemplateDecl)
+ DiffTemplateTemplates(FromIter, ToIter, FromDefaultTemplateDecl,
+ ToDefaultTemplateDecl);
+
+ NonTypeTemplateParmDecl *FromDefaultNonTypeDecl =
+ dyn_cast<NonTypeTemplateParmDecl>(FromParamND);
+ NonTypeTemplateParmDecl *ToDefaultNonTypeDecl =
+ dyn_cast<NonTypeTemplateParmDecl>(ToParamND);
+ if (FromDefaultNonTypeDecl && ToDefaultNonTypeDecl)
+ DiffNonTypes(FromIter, ToIter, FromDefaultNonTypeDecl,
+ ToDefaultNonTypeDecl);
++FromIter;
++ToIter;
@@ -1147,7 +1173,8 @@ class TemplateDiff {
/// GetType - Retrieves the template type arguments, including default
/// arguments.
- QualType GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD) {
+ static QualType GetType(const TSTiterator &Iter,
+ TemplateTypeParmDecl *DefaultTTPD) {
bool isVariadic = DefaultTTPD->isParameterPack();
if (!Iter.isEnd())
@@ -1164,7 +1191,8 @@ class TemplateDiff {
/// GetExpr - Retrieves the template expression argument, including default
/// arguments.
- Expr *GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD) {
+ static Expr *GetExpr(const TSTiterator &Iter,
+ NonTypeTemplateParmDecl *DefaultNTTPD) {
Expr *ArgExpr = nullptr;
bool isVariadic = DefaultNTTPD->isParameterPack();
@@ -1183,7 +1211,8 @@ class TemplateDiff {
/// GetInt - Retrieves the template integer argument, including evaluating
/// default arguments.
- bool GetInt(const TSTiterator &Iter, Expr *ArgExpr, llvm::APInt &Int) {
+ static bool GetInt(ASTContext &Context, const TSTiterator &Iter,
+ Expr *ArgExpr, llvm::APInt &Int) {
// Default, value-depenedent expressions require fetching
// from the desugared TemplateArgument, otherwise expression needs to
// be evaluatable.
@@ -1209,7 +1238,7 @@ class TemplateDiff {
/// GetValueDecl - Retrieves the template Decl argument, including
/// default expression argument.
- ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) {
+ static ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) {
// Default, value-depenedent expressions require fetching
// from the desugared TemplateArgument
if (Iter.isEnd() && ArgExpr->isValueDependent())
@@ -1235,7 +1264,7 @@ class TemplateDiff {
/// CheckForNullPtr - returns true if the expression can be evaluated as
/// a null pointer
- bool CheckForNullPtr(Expr *E) {
+ static bool CheckForNullPtr(ASTContext &Context, Expr *E) {
assert(E && "Expected expression");
E = E->IgnoreParenCasts();
@@ -1256,7 +1285,7 @@ class TemplateDiff {
/// GetTemplateDecl - Retrieves the template template arguments, including
/// default arguments.
- TemplateDecl *GetTemplateDecl(const TSTiterator &Iter,
+ static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter,
TemplateTemplateParmDecl *DefaultTTPD) {
bool isVariadic = DefaultTTPD->isParameterPack();
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index df7a2cb4712b..ebf5e651ef9a 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
@@ -90,24 +91,22 @@ namespace {
class ASTDumper
: public ConstDeclVisitor<ASTDumper>, public ConstStmtVisitor<ASTDumper>,
- public ConstCommentVisitor<ASTDumper> {
+ public ConstCommentVisitor<ASTDumper>, public TypeVisitor<ASTDumper> {
raw_ostream &OS;
const CommandTraits *Traits;
const SourceManager *SM;
- bool IsFirstLine;
- // Indicates whether more child are expected at the current tree depth
- enum IndentType { IT_Child, IT_LastChild };
+ /// Pending[i] is an action to dump an entity at level i.
+ llvm::SmallVector<std::function<void(bool isLastChild)>, 32> Pending;
- /// Indents[i] indicates if another child exists at level i.
- /// Used by Indent() to print the tree structure.
- llvm::SmallVector<IndentType, 32> Indents;
+ /// Indicates whether we're at the top level.
+ bool TopLevel;
- /// Indicates that more children will be needed at this indent level.
- /// If true, prevents lastChild() from marking the node as the last child.
- /// This is used when there are multiple collections of children to be
- /// dumped as well as during conditional node dumping.
- bool MoreChildren;
+ /// Indicates if we're handling the first child after entering a new depth.
+ bool FirstChild;
+
+ /// Prefix for currently-being-dumped entity.
+ std::string Prefix;
/// Keep track of the last location we print out so that we can
/// print out deltas from then on out.
@@ -119,21 +118,70 @@ namespace {
bool ShowColors;
- class IndentScope {
- ASTDumper &Dumper;
- // Preserve the Dumper's MoreChildren value from the previous IndentScope
- bool MoreChildren;
- public:
- IndentScope(ASTDumper &Dumper) : Dumper(Dumper) {
- MoreChildren = Dumper.hasMoreChildren();
- Dumper.setMoreChildren(false);
- Dumper.indent();
+ /// Dump a child of the current node.
+ template<typename Fn> void dumpChild(Fn doDumpChild) {
+ // If we're at the top level, there's nothing interesting to do; just
+ // run the dumper.
+ if (TopLevel) {
+ TopLevel = false;
+ doDumpChild();
+ while (!Pending.empty()) {
+ Pending.back()(true);
+ Pending.pop_back();
+ }
+ Prefix.clear();
+ OS << "\n";
+ TopLevel = true;
+ return;
}
- ~IndentScope() {
- Dumper.setMoreChildren(MoreChildren);
- Dumper.unindent();
+
+ const FullComment *OrigFC = FC;
+ auto dumpWithIndent = [this, doDumpChild, OrigFC](bool isLastChild) {
+ // Print out the appropriate tree structure and work out the prefix for
+ // children of this node. For instance:
+ //
+ // A Prefix = ""
+ // |-B Prefix = "| "
+ // | `-C Prefix = "| "
+ // `-D Prefix = " "
+ // |-E Prefix = " | "
+ // `-F Prefix = " "
+ // G Prefix = ""
+ //
+ // Note that the first level gets no prefix.
+ {
+ OS << '\n';
+ ColorScope Color(*this, IndentColor);
+ OS << Prefix << (isLastChild ? '`' : '|') << '-';
+ this->Prefix.push_back(isLastChild ? ' ' : '|');
+ this->Prefix.push_back(' ');
+ }
+
+ FirstChild = true;
+ unsigned Depth = Pending.size();
+
+ FC = OrigFC;
+ doDumpChild();
+
+ // If any children are left, they're the last at their nesting level.
+ // Dump those ones out now.
+ while (Depth < Pending.size()) {
+ Pending.back()(true);
+ this->Pending.pop_back();
+ }
+
+ // Restore the old prefix.
+ this->Prefix.resize(Prefix.size() - 2);
+ };
+
+ if (FirstChild) {
+ Pending.push_back(std::move(dumpWithIndent));
+ } else {
+ Pending.back()(false);
+ Pending.back() = std::move(dumpWithIndent);
}
- };
+ FirstChild = false;
+ }
class ColorScope {
ASTDumper &Dumper;
@@ -149,78 +197,37 @@ namespace {
}
};
- class ChildDumper {
- ASTDumper &Dumper;
-
- const Decl *Prev;
- bool PrevRef;
- public:
- ChildDumper(ASTDumper &Dumper) : Dumper(Dumper), Prev(nullptr) {}
- ~ChildDumper() {
- if (Prev) {
- Dumper.lastChild();
- dump(nullptr);
- }
- }
-
- // FIXME: This should take an arbitrary callable as the dumping action.
- void dump(const Decl *D, bool Ref = false) {
- if (Prev) {
- if (PrevRef)
- Dumper.dumpDeclRef(Prev);
- else
- Dumper.dumpDecl(Prev);
- }
- Prev = D;
- PrevRef = Ref;
- }
- void dumpRef(const Decl *D) { dump(D, true); }
-
- // Give up ownership of the children of the node. By calling this,
- // the caller takes back responsibility for calling lastChild().
- void release() { dump(nullptr); }
- };
-
public:
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
const SourceManager *SM)
- : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false),
+ : OS(OS), Traits(Traits), SM(SM), TopLevel(true), FirstChild(true),
LastLocFilename(""), LastLocLine(~0U), FC(nullptr),
ShowColors(SM && SM->getDiagnostics().getShowColors()) { }
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
const SourceManager *SM, bool ShowColors)
- : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false),
+ : OS(OS), Traits(Traits), SM(SM), TopLevel(true), FirstChild(true),
LastLocFilename(""), LastLocLine(~0U),
ShowColors(ShowColors) { }
- ~ASTDumper() {
- OS << "\n";
- }
-
void dumpDecl(const Decl *D);
void dumpStmt(const Stmt *S);
void dumpFullComment(const FullComment *C);
- // Formatting
- void indent();
- void unindent();
- void lastChild();
- bool hasMoreChildren();
- void setMoreChildren(bool Value);
-
// Utilities
void dumpPointer(const void *Ptr);
void dumpSourceRange(SourceRange R);
void dumpLocation(SourceLocation Loc);
- void dumpBareType(QualType T);
+ void dumpBareType(QualType T, bool Desugar = true);
void dumpType(QualType T);
+ void dumpTypeAsChild(QualType T);
+ void dumpTypeAsChild(const Type *T);
void dumpBareDeclRef(const Decl *Node);
void dumpDeclRef(const Decl *Node, const char *Label = nullptr);
void dumpName(const NamedDecl *D);
bool hasNodes(const DeclContext *DC);
void dumpDeclContext(const DeclContext *DC);
- void dumpLookups(const DeclContext *DC);
+ void dumpLookups(const DeclContext *DC, bool DumpDecls);
void dumpAttr(const Attr *A);
// C++ Utilities
@@ -233,6 +240,175 @@ namespace {
void dumpTemplateArgument(const TemplateArgument &A,
SourceRange R = SourceRange());
+ // Types
+ void VisitComplexType(const ComplexType *T) {
+ dumpTypeAsChild(T->getElementType());
+ }
+ void VisitPointerType(const PointerType *T) {
+ dumpTypeAsChild(T->getPointeeType());
+ }
+ void VisitBlockPointerType(const BlockPointerType *T) {
+ dumpTypeAsChild(T->getPointeeType());
+ }
+ void VisitReferenceType(const ReferenceType *T) {
+ dumpTypeAsChild(T->getPointeeType());
+ }
+ void VisitRValueReferenceType(const ReferenceType *T) {
+ if (T->isSpelledAsLValue())
+ OS << " written as lvalue reference";
+ VisitReferenceType(T);
+ }
+ void VisitMemberPointerType(const MemberPointerType *T) {
+ dumpTypeAsChild(T->getClass());
+ dumpTypeAsChild(T->getPointeeType());
+ }
+ void VisitArrayType(const ArrayType *T) {
+ switch (T->getSizeModifier()) {
+ case ArrayType::Normal: break;
+ case ArrayType::Static: OS << " static"; break;
+ case ArrayType::Star: OS << " *"; break;
+ }
+ OS << " " << T->getIndexTypeQualifiers().getAsString();
+ dumpTypeAsChild(T->getElementType());
+ }
+ void VisitConstantArrayType(const ConstantArrayType *T) {
+ OS << " " << T->getSize();
+ VisitArrayType(T);
+ }
+ void VisitVariableArrayType(const VariableArrayType *T) {
+ OS << " ";
+ dumpSourceRange(T->getBracketsRange());
+ VisitArrayType(T);
+ dumpStmt(T->getSizeExpr());
+ }
+ void VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
+ VisitArrayType(T);
+ OS << " ";
+ dumpSourceRange(T->getBracketsRange());
+ dumpStmt(T->getSizeExpr());
+ }
+ void VisitDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) {
+ OS << " ";
+ dumpLocation(T->getAttributeLoc());
+ dumpTypeAsChild(T->getElementType());
+ dumpStmt(T->getSizeExpr());
+ }
+ void VisitVectorType(const VectorType *T) {
+ switch (T->getVectorKind()) {
+ case VectorType::GenericVector: break;
+ case VectorType::AltiVecVector: OS << " altivec"; break;
+ case VectorType::AltiVecPixel: OS << " altivec pixel"; break;
+ case VectorType::AltiVecBool: OS << " altivec bool"; break;
+ case VectorType::NeonVector: OS << " neon"; break;
+ case VectorType::NeonPolyVector: OS << " neon poly"; break;
+ }
+ OS << " " << T->getNumElements();
+ dumpTypeAsChild(T->getElementType());
+ }
+ void VisitFunctionType(const FunctionType *T) {
+ auto EI = T->getExtInfo();
+ if (EI.getNoReturn()) OS << " noreturn";
+ if (EI.getProducesResult()) OS << " produces_result";
+ if (EI.getHasRegParm()) OS << " regparm " << EI.getRegParm();
+ OS << " " << FunctionType::getNameForCallConv(EI.getCC());
+ dumpTypeAsChild(T->getReturnType());
+ }
+ void VisitFunctionProtoType(const FunctionProtoType *T) {
+ auto EPI = T->getExtProtoInfo();
+ if (EPI.HasTrailingReturn) OS << " trailing_return";
+ if (T->isConst()) OS << " const";
+ if (T->isVolatile()) OS << " volatile";
+ if (T->isRestrict()) OS << " restrict";
+ switch (EPI.RefQualifier) {
+ case RQ_None: break;
+ case RQ_LValue: OS << " &"; break;
+ case RQ_RValue: OS << " &&"; break;
+ }
+ // FIXME: Exception specification.
+ // FIXME: Consumed parameters.
+ VisitFunctionType(T);
+ for (QualType PT : T->getParamTypes())
+ dumpTypeAsChild(PT);
+ if (EPI.Variadic)
+ dumpChild([=] { OS << "..."; });
+ }
+ void VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
+ dumpDeclRef(T->getDecl());
+ }
+ void VisitTypedefType(const TypedefType *T) {
+ dumpDeclRef(T->getDecl());
+ }
+ void VisitTypeOfExprType(const TypeOfExprType *T) {
+ dumpStmt(T->getUnderlyingExpr());
+ }
+ void VisitDecltypeType(const DecltypeType *T) {
+ dumpStmt(T->getUnderlyingExpr());
+ }
+ void VisitUnaryTransformType(const UnaryTransformType *T) {
+ switch (T->getUTTKind()) {
+ case UnaryTransformType::EnumUnderlyingType:
+ OS << " underlying_type";
+ break;
+ }
+ dumpTypeAsChild(T->getBaseType());
+ }
+ void VisitTagType(const TagType *T) {
+ dumpDeclRef(T->getDecl());
+ }
+ void VisitAttributedType(const AttributedType *T) {
+ // FIXME: AttrKind
+ dumpTypeAsChild(T->getModifiedType());
+ }
+ void VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
+ OS << " depth " << T->getDepth() << " index " << T->getIndex();
+ if (T->isParameterPack()) OS << " pack";
+ dumpDeclRef(T->getDecl());
+ }
+ void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
+ dumpTypeAsChild(T->getReplacedParameter());
+ }
+ void VisitSubstTemplateTypeParmPackType(
+ const SubstTemplateTypeParmPackType *T) {
+ dumpTypeAsChild(T->getReplacedParameter());
+ dumpTemplateArgument(T->getArgumentPack());
+ }
+ void VisitAutoType(const AutoType *T) {
+ if (T->isDecltypeAuto()) OS << " decltype(auto)";
+ if (!T->isDeduced())
+ OS << " undeduced";
+ }
+ void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
+ if (T->isTypeAlias()) OS << " alias";
+ OS << " "; T->getTemplateName().dump(OS);
+ for (auto &Arg : *T)
+ dumpTemplateArgument(Arg);
+ if (T->isTypeAlias())
+ dumpTypeAsChild(T->getAliasedType());
+ }
+ void VisitInjectedClassNameType(const InjectedClassNameType *T) {
+ dumpDeclRef(T->getDecl());
+ }
+ void VisitObjCInterfaceType(const ObjCInterfaceType *T) {
+ dumpDeclRef(T->getDecl());
+ }
+ void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
+ dumpTypeAsChild(T->getPointeeType());
+ }
+ void VisitAtomicType(const AtomicType *T) {
+ dumpTypeAsChild(T->getValueType());
+ }
+ void VisitAdjustedType(const AdjustedType *T) {
+ dumpTypeAsChild(T->getOriginalType());
+ }
+ void VisitPackExpansionType(const PackExpansionType *T) {
+ if (auto N = T->getNumExpansions()) OS << " expansions " << *N;
+ if (!T->isSugared())
+ dumpTypeAsChild(T->getPattern());
+ }
+ // FIXME: ElaboratedType, DependentNameType,
+ // DependentTemplateSpecializationType, ObjCObjectType
+
// Decls
void VisitLabelDecl(const LabelDecl *D);
void VisitTypedefDecl(const TypedefDecl *D);
@@ -255,8 +431,7 @@ namespace {
void VisitCXXRecordDecl(const CXXRecordDecl *D);
void VisitStaticAssertDecl(const StaticAssertDecl *D);
template<typename SpecializationDecl>
- void VisitTemplateDeclSpecialization(ChildDumper &Children,
- const SpecializationDecl *D,
+ void VisitTemplateDeclSpecialization(const SpecializationDecl *D,
bool DumpExplicitInst,
bool DumpRefOnly);
template<typename TemplateDecl>
@@ -378,67 +553,6 @@ namespace {
// Utilities
//===----------------------------------------------------------------------===//
-// Print out the appropriate tree structure using the Indents vector.
-// Example of tree and the Indents vector at each level.
-// A { }
-// |-B { IT_Child }
-// | `-C { IT_Child, IT_LastChild }
-// `-D { IT_LastChild }
-// |-E { IT_LastChild, IT_Child }
-// `-F { IT_LastChild, IT_LastChild }
-// Type non-last element, last element
-// IT_Child "| " "|-"
-// IT_LastChild " " "`-"
-void ASTDumper::indent() {
- if (IsFirstLine)
- IsFirstLine = false;
- else
- OS << "\n";
-
- ColorScope Color(*this, IndentColor);
- for (SmallVectorImpl<IndentType>::const_iterator I = Indents.begin(),
- E = Indents.end();
- I != E; ++I) {
- switch (*I) {
- case IT_Child:
- if (I == E - 1)
- OS << "|-";
- else
- OS << "| ";
- continue;
- case IT_LastChild:
- if (I == E - 1)
- OS << "`-";
- else
- OS << " ";
- continue;
- }
- llvm_unreachable("Invalid IndentType");
- }
- Indents.push_back(IT_Child);
-}
-
-void ASTDumper::unindent() {
- Indents.pop_back();
-}
-
-// Call before each potential last child node is to be dumped. If MoreChildren
-// is false, then this is the last child, otherwise treat as a regular node.
-void ASTDumper::lastChild() {
- if (!hasMoreChildren())
- Indents.back() = IT_LastChild;
-}
-
-// MoreChildren should be set before calling another function that may print
-// additional nodes to prevent conflicting final child nodes.
-bool ASTDumper::hasMoreChildren() {
- return MoreChildren;
-}
-
-void ASTDumper::setMoreChildren(bool Value) {
- MoreChildren = Value;
-}
-
void ASTDumper::dumpPointer(const void *Ptr) {
ColorScope Color(*this, AddressColor);
OS << ' ' << Ptr;
@@ -491,13 +605,13 @@ void ASTDumper::dumpSourceRange(SourceRange R) {
}
-void ASTDumper::dumpBareType(QualType T) {
+void ASTDumper::dumpBareType(QualType T, bool Desugar) {
ColorScope Color(*this, TypeColor);
-
+
SplitQualType T_split = T.split();
OS << "'" << QualType::getAsString(T_split) << "'";
- if (!T.isNull()) {
+ if (Desugar && !T.isNull()) {
// If the type is sugared, also dump a (shallow) desugared type.
SplitQualType D_split = T.getSplitDesugaredType();
if (T_split != D_split)
@@ -510,6 +624,59 @@ void ASTDumper::dumpType(QualType T) {
dumpBareType(T);
}
+void ASTDumper::dumpTypeAsChild(QualType T) {
+ SplitQualType SQT = T.split();
+ if (!SQT.Quals.hasQualifiers())
+ return dumpTypeAsChild(SQT.Ty);
+
+ dumpChild([=] {
+ OS << "QualType";
+ dumpPointer(T.getAsOpaquePtr());
+ OS << " ";
+ dumpBareType(T, false);
+ OS << " " << T.split().Quals.getAsString();
+ dumpTypeAsChild(T.split().Ty);
+ });
+}
+
+void ASTDumper::dumpTypeAsChild(const Type *T) {
+ dumpChild([=] {
+ if (!T) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
+ {
+ ColorScope Color(*this, TypeColor);
+ OS << T->getTypeClassName() << "Type";
+ }
+ dumpPointer(T);
+ OS << " ";
+ dumpBareType(QualType(T, 0), false);
+
+ QualType SingleStepDesugar =
+ T->getLocallyUnqualifiedSingleStepDesugaredType();
+ if (SingleStepDesugar != QualType(T, 0))
+ OS << " sugar";
+ if (T->isDependentType())
+ OS << " dependent";
+ else if (T->isInstantiationDependentType())
+ OS << " instantiation_dependent";
+ if (T->isVariablyModifiedType())
+ OS << " variably_modified";
+ if (T->containsUnexpandedParameterPack())
+ OS << " contains_unexpanded_pack";
+ if (T->isFromAST())
+ OS << " imported";
+
+ TypeVisitor<ASTDumper>::Visit(T);
+
+ if (SingleStepDesugar != QualType(T, 0))
+ dumpTypeAsChild(SingleStepDesugar);
+ });
+}
+
void ASTDumper::dumpBareDeclRef(const Decl *D) {
{
ColorScope Color(*this, DeclKindNameColor);
@@ -530,10 +697,11 @@ void ASTDumper::dumpDeclRef(const Decl *D, const char *Label) {
if (!D)
return;
- IndentScope Indent(*this);
- if (Label)
- OS << Label << ' ';
- dumpBareDeclRef(D);
+ dumpChild([=]{
+ if (Label)
+ OS << Label << ' ';
+ dumpBareDeclRef(D);
+ });
}
void ASTDumper::dumpName(const NamedDecl *ND) {
@@ -555,86 +723,96 @@ void ASTDumper::dumpDeclContext(const DeclContext *DC) {
if (!DC)
return;
- ChildDumper Children(*this);
for (auto *D : DC->noload_decls())
- Children.dump(D);
+ dumpDecl(D);
if (DC->hasExternalLexicalStorage()) {
- Children.release();
-
- lastChild();
- IndentScope Indent(*this);
- ColorScope Color(*this, UndeserializedColor);
- OS << "<undeserialized declarations>";
+ dumpChild([=]{
+ ColorScope Color(*this, UndeserializedColor);
+ OS << "<undeserialized declarations>";
+ });
}
}
-void ASTDumper::dumpLookups(const DeclContext *DC) {
- IndentScope Indent(*this);
+void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
+ dumpChild([=] {
+ OS << "StoredDeclsMap ";
+ dumpBareDeclRef(cast<Decl>(DC));
- OS << "StoredDeclsMap ";
- dumpBareDeclRef(cast<Decl>(DC));
+ const DeclContext *Primary = DC->getPrimaryContext();
+ if (Primary != DC) {
+ OS << " primary";
+ dumpPointer(cast<Decl>(Primary));
+ }
- const DeclContext *Primary = DC->getPrimaryContext();
- if (Primary != DC) {
- OS << " primary";
- dumpPointer(cast<Decl>(Primary));
- }
+ bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
- bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
+ DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(),
+ E = Primary->noload_lookups_end();
+ while (I != E) {
+ DeclarationName Name = I.getLookupName();
+ DeclContextLookupResult R = *I++;
- DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(),
- E = Primary->noload_lookups_end();
- while (I != E) {
- DeclarationName Name = I.getLookupName();
- DeclContextLookupResult R = *I++;
- if (I == E && !HasUndeserializedLookups)
- lastChild();
+ dumpChild([=] {
+ OS << "DeclarationName ";
+ {
+ ColorScope Color(*this, DeclNameColor);
+ OS << '\'' << Name << '\'';
+ }
- IndentScope Indent(*this);
- OS << "DeclarationName ";
- {
- ColorScope Color(*this, DeclNameColor);
- OS << '\'' << Name << '\'';
+ for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
+ RI != RE; ++RI) {
+ dumpChild([=] {
+ dumpBareDeclRef(*RI);
+
+ if ((*RI)->isHidden())
+ OS << " hidden";
+
+ // If requested, dump the redecl chain for this lookup.
+ if (DumpDecls) {
+ // Dump earliest decl first.
+ std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) {
+ if (Decl *Prev = D->getPreviousDecl())
+ DumpWithPrev(Prev);
+ dumpDecl(D);
+ };
+ DumpWithPrev(*RI);
+ }
+ });
+ }
+ });
}
- for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
- RI != RE; ++RI) {
- if (RI + 1 == RE)
- lastChild();
- dumpDeclRef(*RI);
- if ((*RI)->isHidden())
- OS << " hidden";
+ if (HasUndeserializedLookups) {
+ dumpChild([=] {
+ ColorScope Color(*this, UndeserializedColor);
+ OS << "<undeserialized lookups>";
+ });
}
- }
-
- if (HasUndeserializedLookups) {
- lastChild();
- IndentScope Indent(*this);
- ColorScope Color(*this, UndeserializedColor);
- OS << "<undeserialized lookups>";
- }
+ });
}
void ASTDumper::dumpAttr(const Attr *A) {
- IndentScope Indent(*this);
- {
- ColorScope Color(*this, AttrColor);
+ dumpChild([=] {
+ {
+ ColorScope Color(*this, AttrColor);
- switch (A->getKind()) {
+ switch (A->getKind()) {
#define ATTR(X) case attr::X: OS << #X; break;
#include "clang/Basic/AttrList.inc"
- default: llvm_unreachable("unexpected attribute kind");
+ default:
+ llvm_unreachable("unexpected attribute kind");
+ }
+ OS << "Attr";
}
- OS << "Attr";
- }
- dumpPointer(A);
- dumpSourceRange(A->getRange());
- if (A->isInherited())
- OS << " Inherited";
- if (A->isImplicit())
- OS << " Implicit";
+ dumpPointer(A);
+ dumpSourceRange(A->getRange());
+ if (A->isInherited())
+ OS << " Inherited";
+ if (A->isImplicit())
+ OS << " Implicit";
#include "clang/AST/AttrDump.inc"
+ });
}
static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {}
@@ -687,15 +865,20 @@ void ASTDumper::dumpAccessSpecifier(AccessSpecifier AS) {
}
void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) {
- IndentScope Indent(*this);
- OS << "CXXCtorInitializer";
- if (Init->isAnyMemberInitializer()) {
- OS << ' ';
- dumpBareDeclRef(Init->getAnyMember());
- } else {
- dumpType(QualType(Init->getBaseClass(), 0));
- }
- dumpStmt(Init->getInit());
+ dumpChild([=] {
+ OS << "CXXCtorInitializer";
+ if (Init->isAnyMemberInitializer()) {
+ OS << ' ';
+ dumpBareDeclRef(Init->getAnyMember());
+ } else if (Init->isBaseInitializer()) {
+ dumpType(QualType(Init->getBaseClass(), 0));
+ } else if (Init->isDelegatingInitializer()) {
+ dumpType(Init->getTypeSourceInfo()->getType());
+ } else {
+ llvm_unreachable("Unknown initializer type");
+ }
+ dumpStmt(Init->getInit());
+ });
}
void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) {
@@ -709,11 +892,8 @@ void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) {
void ASTDumper::dumpTemplateArgumentListInfo(
const TemplateArgumentListInfo &TALI) {
- for (unsigned i = 0, e = TALI.size(); i < e; ++i) {
- if (i + 1 == e)
- lastChild();
+ for (unsigned i = 0, e = TALI.size(); i < e; ++i)
dumpTemplateArgumentLoc(TALI[i]);
- }
}
void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A) {
@@ -726,54 +906,49 @@ void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) {
}
void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) {
- IndentScope Indent(*this);
- OS << "TemplateArgument";
- if (R.isValid())
- dumpSourceRange(R);
-
- switch (A.getKind()) {
- case TemplateArgument::Null:
- OS << " null";
- break;
- case TemplateArgument::Type:
- OS << " type";
- lastChild();
- dumpType(A.getAsType());
- break;
- case TemplateArgument::Declaration:
- OS << " decl";
- lastChild();
- dumpDeclRef(A.getAsDecl());
- break;
- case TemplateArgument::NullPtr:
- OS << " nullptr";
- break;
- case TemplateArgument::Integral:
- OS << " integral " << A.getAsIntegral();
- break;
- case TemplateArgument::Template:
- OS << " template ";
- A.getAsTemplate().dump(OS);
- break;
- case TemplateArgument::TemplateExpansion:
- OS << " template expansion";
- A.getAsTemplateOrTemplatePattern().dump(OS);
- break;
- case TemplateArgument::Expression:
- OS << " expr";
- lastChild();
- dumpStmt(A.getAsExpr());
- break;
- case TemplateArgument::Pack:
- OS << " pack";
- for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
- dumpTemplateArgument(*I);
+ dumpChild([=] {
+ OS << "TemplateArgument";
+ if (R.isValid())
+ dumpSourceRange(R);
+
+ switch (A.getKind()) {
+ case TemplateArgument::Null:
+ OS << " null";
+ break;
+ case TemplateArgument::Type:
+ OS << " type";
+ dumpType(A.getAsType());
+ break;
+ case TemplateArgument::Declaration:
+ OS << " decl";
+ dumpDeclRef(A.getAsDecl());
+ break;
+ case TemplateArgument::NullPtr:
+ OS << " nullptr";
+ break;
+ case TemplateArgument::Integral:
+ OS << " integral " << A.getAsIntegral();
+ break;
+ case TemplateArgument::Template:
+ OS << " template ";
+ A.getAsTemplate().dump(OS);
+ break;
+ case TemplateArgument::TemplateExpansion:
+ OS << " template expansion";
+ A.getAsTemplateOrTemplatePattern().dump(OS);
+ break;
+ case TemplateArgument::Expression:
+ OS << " expr";
+ dumpStmt(A.getAsExpr());
+ break;
+ case TemplateArgument::Pack:
+ OS << " pack";
+ for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end();
+ I != E; ++I)
+ dumpTemplateArgument(*I);
+ break;
}
- break;
- }
+ });
}
//===----------------------------------------------------------------------===//
@@ -781,64 +956,57 @@ void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) {
//===----------------------------------------------------------------------===//
void ASTDumper::dumpDecl(const Decl *D) {
- IndentScope Indent(*this);
+ dumpChild([=] {
+ if (!D) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
- if (!D) {
- ColorScope Color(*this, NullColor);
- OS << "<<<NULL>>>";
- return;
- }
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << D->getDeclKindName() << "Decl";
+ }
+ dumpPointer(D);
+ if (D->getLexicalDeclContext() != D->getDeclContext())
+ OS << " parent " << cast<Decl>(D->getDeclContext());
+ dumpPreviousDecl(OS, D);
+ dumpSourceRange(D->getSourceRange());
+ OS << ' ';
+ dumpLocation(D->getLocation());
+ if (Module *M = D->getOwningModule())
+ OS << " in " << M->getFullModuleName();
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ if (ND->isHidden())
+ OS << " hidden";
+ if (D->isImplicit())
+ OS << " implicit";
+ if (D->isUsed())
+ OS << " used";
+ else if (D->isThisDeclarationReferenced())
+ OS << " referenced";
+ if (D->isInvalidDecl())
+ OS << " invalid";
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isConstexpr())
+ OS << " constexpr";
- {
- ColorScope Color(*this, DeclKindNameColor);
- OS << D->getDeclKindName() << "Decl";
- }
- dumpPointer(D);
- if (D->getLexicalDeclContext() != D->getDeclContext())
- OS << " parent " << cast<Decl>(D->getDeclContext());
- dumpPreviousDecl(OS, D);
- dumpSourceRange(D->getSourceRange());
- OS << ' ';
- dumpLocation(D->getLocation());
- if (Module *M = D->getOwningModule())
- OS << " in " << M->getFullModuleName();
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
- if (ND->isHidden())
- OS << " hidden";
- if (D->isImplicit())
- OS << " implicit";
- if (D->isUsed())
- OS << " used";
- else if (D->isReferenced())
- OS << " referenced";
- if (D->isInvalidDecl())
- OS << " invalid";
-
- bool HasAttrs = D->hasAttrs();
- const FullComment *Comment =
- D->getASTContext().getLocalCommentForDeclUncached(D);
- // Decls within functions are visited by the body
- bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
- hasNodes(dyn_cast<DeclContext>(D));
-
- setMoreChildren(HasAttrs || Comment || HasDeclContext);
- ConstDeclVisitor<ASTDumper>::Visit(D);
-
- setMoreChildren(Comment || HasDeclContext);
- for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
- dumpAttr(*I);
- }
- setMoreChildren(HasDeclContext);
- lastChild();
- dumpFullComment(Comment);
+ ConstDeclVisitor<ASTDumper>::Visit(D);
- setMoreChildren(false);
- if (HasDeclContext)
- dumpDeclContext(cast<DeclContext>(D));
+ for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); I != E;
+ ++I)
+ dumpAttr(*I);
+
+ if (const FullComment *Comment =
+ D->getASTContext().getLocalCommentForDeclUncached(D))
+ dumpFullComment(Comment);
+
+ // Decls within functions are visited by the body.
+ if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
+ hasNodes(dyn_cast<DeclContext>(D)))
+ dumpDeclContext(cast<DeclContext>(D));
+ });
}
void ASTDumper::VisitLabelDecl(const LabelDecl *D) {
@@ -878,19 +1046,16 @@ void ASTDumper::VisitRecordDecl(const RecordDecl *D) {
void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
dumpName(D);
dumpType(D->getType());
- if (const Expr *Init = D->getInitExpr()) {
- lastChild();
+ if (const Expr *Init = D->getInitExpr())
dumpStmt(Init);
- }
}
void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) {
dumpName(D);
dumpType(D->getType());
- ChildDumper Children(*this);
for (auto *Child : D->chain())
- Children.dumpRef(Child);
+ dumpDeclRef(Child);
}
void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
@@ -914,73 +1079,39 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
if (const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>()) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- switch (EPI.ExceptionSpecType) {
+ switch (EPI.ExceptionSpec.Type) {
default: break;
case EST_Unevaluated:
- OS << " noexcept-unevaluated " << EPI.ExceptionSpecDecl;
+ OS << " noexcept-unevaluated " << EPI.ExceptionSpec.SourceDecl;
break;
case EST_Uninstantiated:
- OS << " noexcept-uninstantiated " << EPI.ExceptionSpecTemplate;
+ OS << " noexcept-uninstantiated " << EPI.ExceptionSpec.SourceTemplate;
break;
}
}
- bool OldMoreChildren = hasMoreChildren();
- const FunctionTemplateSpecializationInfo *FTSI =
- D->getTemplateSpecializationInfo();
- bool HasTemplateSpecialization = FTSI;
-
- bool HasNamedDecls = D->getDeclsInPrototypeScope().begin() !=
- D->getDeclsInPrototypeScope().end();
-
- bool HasFunctionDecls = D->param_begin() != D->param_end();
-
- const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D);
- bool HasCtorInitializers = C && C->init_begin() != C->init_end();
-
- bool HasDeclarationBody = D->doesThisDeclarationHaveABody();
-
- setMoreChildren(OldMoreChildren || HasNamedDecls || HasFunctionDecls ||
- HasCtorInitializers || HasDeclarationBody);
- if (HasTemplateSpecialization) {
- lastChild();
+ if (const FunctionTemplateSpecializationInfo *FTSI =
+ D->getTemplateSpecializationInfo())
dumpTemplateArgumentList(*FTSI->TemplateArguments);
- }
- setMoreChildren(OldMoreChildren || HasFunctionDecls ||
- HasCtorInitializers || HasDeclarationBody);
for (ArrayRef<NamedDecl *>::iterator
I = D->getDeclsInPrototypeScope().begin(),
- E = D->getDeclsInPrototypeScope().end(); I != E; ++I) {
- if (I + 1 == E)
- lastChild();
+ E = D->getDeclsInPrototypeScope().end(); I != E; ++I)
dumpDecl(*I);
- }
- setMoreChildren(OldMoreChildren || HasCtorInitializers || HasDeclarationBody);
for (FunctionDecl::param_const_iterator I = D->param_begin(),
E = D->param_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
+ I != E; ++I)
dumpDecl(*I);
- }
-
- setMoreChildren(OldMoreChildren || HasDeclarationBody);
- if (HasCtorInitializers)
+
+ if (const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D))
for (CXXConstructorDecl::init_const_iterator I = C->init_begin(),
E = C->init_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
+ I != E; ++I)
dumpCXXCtorInitializer(*I);
- }
- setMoreChildren(OldMoreChildren);
- if (HasDeclarationBody) {
- lastChild();
+ if (D->doesThisDeclarationHaveABody())
dumpStmt(D->getBody());
- }
}
void ASTDumper::VisitFieldDecl(const FieldDecl *D) {
@@ -991,21 +1122,10 @@ void ASTDumper::VisitFieldDecl(const FieldDecl *D) {
if (D->isModulePrivate())
OS << " __module_private__";
- bool OldMoreChildren = hasMoreChildren();
- bool IsBitField = D->isBitField();
- Expr *Init = D->getInClassInitializer();
- bool HasInit = Init;
-
- setMoreChildren(OldMoreChildren || HasInit);
- if (IsBitField) {
- lastChild();
+ if (D->isBitField())
dumpStmt(D->getBitWidth());
- }
- setMoreChildren(OldMoreChildren);
- if (HasInit) {
- lastChild();
+ if (Expr *Init = D->getInClassInitializer())
dumpStmt(Init);
- }
}
void ASTDumper::VisitVarDecl(const VarDecl *D) {
@@ -1029,13 +1149,11 @@ void ASTDumper::VisitVarDecl(const VarDecl *D) {
case VarDecl::CallInit: OS << " callinit"; break;
case VarDecl::ListInit: OS << " listinit"; break;
}
- lastChild();
dumpStmt(D->getInit());
}
}
void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
- lastChild();
dumpStmt(D->getAsmString());
}
@@ -1082,25 +1200,24 @@ void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
return;
for (const auto &I : D->bases()) {
- IndentScope Indent(*this);
- if (I.isVirtual())
- OS << "virtual ";
- dumpAccessSpecifier(I.getAccessSpecifier());
- dumpType(I.getType());
- if (I.isPackExpansion())
- OS << "...";
+ dumpChild([=] {
+ if (I.isVirtual())
+ OS << "virtual ";
+ dumpAccessSpecifier(I.getAccessSpecifier());
+ dumpType(I.getType());
+ if (I.isPackExpansion())
+ OS << "...";
+ });
}
}
void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) {
dumpStmt(D->getAssertExpr());
- lastChild();
dumpStmt(D->getMessage());
}
template<typename SpecializationDecl>
-void ASTDumper::VisitTemplateDeclSpecialization(ChildDumper &Children,
- const SpecializationDecl *D,
+void ASTDumper::VisitTemplateDeclSpecialization(const SpecializationDecl *D,
bool DumpExplicitInst,
bool DumpRefOnly) {
bool DumpedAny = false;
@@ -1125,7 +1242,10 @@ void ASTDumper::VisitTemplateDeclSpecialization(ChildDumper &Children,
// Fall through.
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
- Children.dump(Redecl, DumpRefOnly);
+ if (DumpRefOnly)
+ dumpDeclRef(Redecl);
+ else
+ dumpDecl(Redecl);
DumpedAny = true;
break;
case TSK_ExplicitSpecialization:
@@ -1135,7 +1255,7 @@ void ASTDumper::VisitTemplateDeclSpecialization(ChildDumper &Children,
// Ensure we dump at least one decl for each specialization.
if (!DumpedAny)
- Children.dumpRef(D);
+ dumpDeclRef(D);
}
template<typename TemplateDecl>
@@ -1144,11 +1264,10 @@ void ASTDumper::VisitTemplateDecl(const TemplateDecl *D,
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
- ChildDumper Children(*this);
- Children.dump(D->getTemplatedDecl());
+ dumpDecl(D->getTemplatedDecl());
for (auto *Child : D->specializations())
- VisitTemplateDeclSpecialization(Children, Child, DumpExplicitInst,
+ VisitTemplateDeclSpecialization(Child, DumpExplicitInst,
!D->isCanonicalDecl());
}
@@ -1206,10 +1325,8 @@ void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
if (D->isParameterPack())
OS << " ...";
dumpName(D);
- if (D->hasDefaultArgument()) {
- lastChild();
+ if (D->hasDefaultArgument())
dumpTemplateArgument(D->getDefaultArgument());
- }
}
void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
@@ -1217,10 +1334,8 @@ void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
if (D->isParameterPack())
OS << " ...";
dumpName(D);
- if (D->hasDefaultArgument()) {
- lastChild();
+ if (D->hasDefaultArgument())
dumpTemplateArgument(D->getDefaultArgument());
- }
}
void ASTDumper::VisitTemplateTemplateParmDecl(
@@ -1229,10 +1344,8 @@ void ASTDumper::VisitTemplateTemplateParmDecl(
OS << " ...";
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
- if (D->hasDefaultArgument()) {
- lastChild();
+ if (D->hasDefaultArgument())
dumpTemplateArgumentLoc(D->getDefaultArgument());
- }
}
void ASTDumper::VisitUsingDecl(const UsingDecl *D) {
@@ -1273,7 +1386,6 @@ void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) {
}
void ASTDumper::VisitFriendDecl(const FriendDecl *D) {
- lastChild();
if (TypeSourceInfo *T = D->getFriendType())
dumpType(T->getType());
else
@@ -1317,96 +1429,66 @@ void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
dumpName(D);
dumpType(D->getReturnType());
- bool OldMoreChildren = hasMoreChildren();
- bool IsVariadic = D->isVariadic();
- bool HasBody = D->hasBody();
-
- setMoreChildren(OldMoreChildren || IsVariadic || HasBody);
if (D->isThisDeclarationADefinition()) {
- lastChild();
dumpDeclContext(D);
} else {
for (ObjCMethodDecl::param_const_iterator I = D->param_begin(),
E = D->param_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
+ I != E; ++I)
dumpDecl(*I);
- }
}
- setMoreChildren(OldMoreChildren || HasBody);
- if (IsVariadic) {
- lastChild();
- IndentScope Indent(*this);
- OS << "...";
- }
+ if (D->isVariadic())
+ dumpChild([=] { OS << "..."; });
- setMoreChildren(OldMoreChildren);
- if (HasBody) {
- lastChild();
+ if (D->hasBody())
dumpStmt(D->getBody());
- }
}
void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
dumpName(D);
dumpDeclRef(D->getClassInterface());
- if (D->protocol_begin() == D->protocol_end())
- lastChild();
dumpDeclRef(D->getImplementation());
for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
E = D->protocol_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
+ I != E; ++I)
dumpDeclRef(*I);
- }
}
void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
dumpName(D);
dumpDeclRef(D->getClassInterface());
- lastChild();
dumpDeclRef(D->getCategoryDecl());
}
void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
dumpName(D);
- ChildDumper Children(*this);
for (auto *Child : D->protocols())
- Children.dumpRef(Child);
+ dumpDeclRef(Child);
}
void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
dumpName(D);
dumpDeclRef(D->getSuperClass(), "super");
- ChildDumper Children(*this);
- Children.dumpRef(D->getImplementation());
+ dumpDeclRef(D->getImplementation());
for (auto *Child : D->protocols())
- Children.dumpRef(Child);
+ dumpDeclRef(Child);
}
void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
dumpName(D);
dumpDeclRef(D->getSuperClass(), "super");
- if (D->init_begin() == D->init_end())
- lastChild();
dumpDeclRef(D->getClassInterface());
for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(),
E = D->init_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
+ I != E; ++I)
dumpCXXCtorInitializer(*I);
- }
}
void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) {
dumpName(D);
- lastChild();
dumpDeclRef(D->getClassInterface());
}
@@ -1441,15 +1523,10 @@ void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
OS << " strong";
if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained)
OS << " unsafe_unretained";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) {
- if (!(Attrs & ObjCPropertyDecl::OBJC_PR_setter))
- lastChild();
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_getter)
dumpDeclRef(D->getGetterMethodDecl(), "getter");
- }
- if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) {
- lastChild();
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_setter)
dumpDeclRef(D->getSetterMethodDecl(), "setter");
- }
}
}
@@ -1460,7 +1537,6 @@ void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
else
OS << " dynamic";
dumpDeclRef(D->getPropertyDecl());
- lastChild();
dumpDeclRef(D->getPropertyIvarDecl());
}
@@ -1468,30 +1544,27 @@ void ASTDumper::VisitBlockDecl(const BlockDecl *D) {
for (auto I : D->params())
dumpDecl(I);
- if (D->isVariadic()) {
- IndentScope Indent(*this);
- OS << "...";
- }
+ if (D->isVariadic())
+ dumpChild([=]{ OS << "..."; });
+
+ if (D->capturesCXXThis())
+ dumpChild([=]{ OS << "capture this"; });
- if (D->capturesCXXThis()) {
- IndentScope Indent(*this);
- OS << "capture this";
- }
for (const auto &I : D->captures()) {
- IndentScope Indent(*this);
- OS << "capture";
- if (I.isByRef())
- OS << " byref";
- if (I.isNested())
- OS << " nested";
- if (I.getVariable()) {
- OS << ' ';
- dumpBareDeclRef(I.getVariable());
- }
- if (I.hasCopyExpr())
- dumpStmt(I.getCopyExpr());
+ dumpChild([=] {
+ OS << "capture";
+ if (I.isByRef())
+ OS << " byref";
+ if (I.isNested())
+ OS << " nested";
+ if (I.getVariable()) {
+ OS << ' ';
+ dumpBareDeclRef(I.getVariable());
+ }
+ if (I.hasCopyExpr())
+ dumpStmt(I.getCopyExpr());
+ });
}
- lastChild();
dumpStmt(D->getBody());
}
@@ -1500,29 +1573,23 @@ void ASTDumper::VisitBlockDecl(const BlockDecl *D) {
//===----------------------------------------------------------------------===//
void ASTDumper::dumpStmt(const Stmt *S) {
- IndentScope Indent(*this);
+ dumpChild([=] {
+ if (!S) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
- if (!S) {
- ColorScope Color(*this, NullColor);
- OS << "<<<NULL>>>";
- return;
- }
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ VisitDeclStmt(DS);
+ return;
+ }
- if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
- VisitDeclStmt(DS);
- return;
- }
+ ConstStmtVisitor<ASTDumper>::Visit(S);
- setMoreChildren(!S->children().empty());
- ConstStmtVisitor<ASTDumper>::Visit(S);
- setMoreChildren(false);
- for (Stmt::const_child_range CI = S->children(); CI; ++CI) {
- Stmt::const_child_range Next = CI;
- ++Next;
- if (!Next)
- lastChild();
- dumpStmt(*CI);
- }
+ for (Stmt::const_child_range CI = S->children(); CI; ++CI)
+ dumpStmt(*CI);
+ });
}
void ASTDumper::VisitStmt(const Stmt *Node) {
@@ -1538,22 +1605,16 @@ void ASTDumper::VisitDeclStmt(const DeclStmt *Node) {
VisitStmt(Node);
for (DeclStmt::const_decl_iterator I = Node->decl_begin(),
E = Node->decl_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
+ I != E; ++I)
dumpDecl(*I);
- }
}
void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) {
VisitStmt(Node);
for (ArrayRef<const Attr *>::iterator I = Node->getAttrs().begin(),
E = Node->getAttrs().end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
+ I != E; ++I)
dumpAttr(*I);
- }
}
void ASTDumper::VisitLabelStmt(const LabelStmt *Node) {
@@ -1693,15 +1754,7 @@ void ASTDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) {
void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
VisitExpr(Node);
- switch (Node->getIdentType()) {
- default: llvm_unreachable("unknown case");
- case PredefinedExpr::Func: OS << " __func__"; break;
- case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
- case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break;
- case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
- case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
- case PredefinedExpr::FuncSig: OS << " __FUNCSIG__"; break;
- }
+ OS << " " << PredefinedExpr::getIdentTypeName(Node->getIdentType());
}
void ASTDumper::VisitCharacterLiteral(const CharacterLiteral *Node) {
@@ -1734,12 +1787,10 @@ void ASTDumper::VisitStringLiteral(const StringLiteral *Str) {
void ASTDumper::VisitInitListExpr(const InitListExpr *ILE) {
VisitExpr(ILE);
if (auto *Filler = ILE->getArrayFiller()) {
- if (!ILE->getNumInits())
- lastChild();
- IndentScope Indent(*this);
- OS << "array filler";
- lastChild();
- dumpStmt(Filler);
+ dumpChild([=] {
+ OS << "array filler";
+ dumpStmt(Filler);
+ });
}
if (auto *Field = ILE->getInitializedFieldInUnion()) {
OS << " field ";
@@ -1805,10 +1856,8 @@ void ASTDumper::VisitBlockExpr(const BlockExpr *Node) {
void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
VisitExpr(Node);
- if (Expr *Source = Node->getSourceExpr()) {
- lastChild();
+ if (Expr *Source = Node->getSourceExpr())
dumpStmt(Source);
- }
}
// GNU extensions.
@@ -2024,27 +2073,24 @@ void ASTDumper::dumpFullComment(const FullComment *C) {
}
void ASTDumper::dumpComment(const Comment *C) {
- IndentScope Indent(*this);
-
- if (!C) {
- ColorScope Color(*this, NullColor);
- OS << "<<<NULL>>>";
- return;
- }
+ dumpChild([=] {
+ if (!C) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
- {
- ColorScope Color(*this, CommentColor);
- OS << C->getCommentKindName();
- }
- dumpPointer(C);
- dumpSourceRange(C->getSourceRange());
- ConstCommentVisitor<ASTDumper>::visit(C);
- for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
- dumpComment(*I);
- }
+ {
+ ColorScope Color(*this, CommentColor);
+ OS << C->getCommentKindName();
+ }
+ dumpPointer(C);
+ dumpSourceRange(C->getSourceRange());
+ ConstCommentVisitor<ASTDumper>::visit(C);
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I)
+ dumpComment(*I);
+ });
}
void ASTDumper::visitTextComment(const TextComment *C) {
@@ -2148,6 +2194,23 @@ void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
}
//===----------------------------------------------------------------------===//
+// Type method implementations
+//===----------------------------------------------------------------------===//
+
+void QualType::dump(const char *msg) const {
+ if (msg)
+ llvm::errs() << msg << ": ";
+ dump();
+}
+
+LLVM_DUMP_METHOD void QualType::dump() const {
+ ASTDumper Dumper(llvm::errs(), nullptr, nullptr);
+ Dumper.dumpTypeAsChild(*this);
+}
+
+LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); }
+
+//===----------------------------------------------------------------------===//
// Decl method implementations
//===----------------------------------------------------------------------===//
@@ -2169,13 +2232,14 @@ LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
dumpLookups(llvm::errs());
}
-LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS) const {
+LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS,
+ bool DumpDecls) const {
const DeclContext *DC = this;
while (!DC->isTranslationUnit())
DC = DC->getParent();
ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager());
- P.dumpLookups(this);
+ P.dumpLookups(this, DumpDecls);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index b0e0b1dc9e00..2442e8ec25f1 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -151,6 +151,7 @@ namespace clang {
Decl *VisitObjCMethodDecl(ObjCMethodDecl *D);
Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D);
Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D);
+ Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D);
Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D);
@@ -1622,15 +1623,14 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
ToEPI.HasTrailingReturn = FromEPI.HasTrailingReturn;
ToEPI.TypeQuals = FromEPI.TypeQuals;
ToEPI.RefQualifier = FromEPI.RefQualifier;
- ToEPI.NumExceptions = ExceptionTypes.size();
- ToEPI.Exceptions = ExceptionTypes.data();
- ToEPI.ConsumedParameters = FromEPI.ConsumedParameters;
- ToEPI.ExceptionSpecType = FromEPI.ExceptionSpecType;
- ToEPI.NoexceptExpr = Importer.Import(FromEPI.NoexceptExpr);
- ToEPI.ExceptionSpecDecl = cast_or_null<FunctionDecl>(
- Importer.Import(FromEPI.ExceptionSpecDecl));
- ToEPI.ExceptionSpecTemplate = cast_or_null<FunctionDecl>(
- Importer.Import(FromEPI.ExceptionSpecTemplate));
+ ToEPI.ExceptionSpec.Type = FromEPI.ExceptionSpec.Type;
+ ToEPI.ExceptionSpec.Exceptions = ExceptionTypes;
+ ToEPI.ExceptionSpec.NoexceptExpr =
+ Importer.Import(FromEPI.ExceptionSpec.NoexceptExpr);
+ ToEPI.ExceptionSpec.SourceDecl = cast_or_null<FunctionDecl>(
+ Importer.Import(FromEPI.ExceptionSpec.SourceDecl));
+ ToEPI.ExceptionSpec.SourceTemplate = cast_or_null<FunctionDecl>(
+ Importer.Import(FromEPI.ExceptionSpec.SourceTemplate));
return Importer.getToContext().getFunctionType(ToResultType, ArgTypes, ToEPI);
}
@@ -2093,10 +2093,11 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) {
}
case TemplateArgument::Declaration: {
- ValueDecl *FromD = From.getAsDecl();
- if (ValueDecl *To = cast_or_null<ValueDecl>(Importer.Import(FromD)))
- return TemplateArgument(To, From.isDeclForReferenceParam());
- return TemplateArgument();
+ ValueDecl *To = cast_or_null<ValueDecl>(Importer.Import(From.getAsDecl()));
+ QualType ToType = Importer.Import(From.getParamTypeForDecl());
+ if (!To || ToType.isNull())
+ return TemplateArgument();
+ return TemplateArgument(To, ToType);
}
case TemplateArgument::NullPtr: {
@@ -2253,7 +2254,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
} else {
SmallVector<NamedDecl *, 4> ConflictingDecls;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Namespace))
continue;
@@ -2316,7 +2317,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
@@ -2396,7 +2397,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
if (!DC->isFunctionOrMethod() && SearchName) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(SearchName, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
@@ -2482,7 +2483,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(SearchName, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
@@ -2604,7 +2605,7 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
@@ -2656,7 +2657,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
@@ -2712,8 +2713,9 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// FunctionDecl that we are importing the FunctionProtoType for.
// To avoid an infinite recursion when importing, create the FunctionDecl
// with a simplified function type and update it afterwards.
- if (FromEPI.ExceptionSpecDecl || FromEPI.ExceptionSpecTemplate ||
- FromEPI.NoexceptExpr) {
+ if (FromEPI.ExceptionSpec.SourceDecl ||
+ FromEPI.ExceptionSpec.SourceTemplate ||
+ FromEPI.ExceptionSpec.NoexceptExpr) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
FromTy = Importer.getFromContext().getFunctionType(
FromFPT->getReturnType(), FromFPT->getParamTypes(), DefaultEPI);
@@ -2858,7 +2860,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
// Determine whether we've already imported this field.
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) {
// For anonymous fields, match up by index.
@@ -2914,7 +2916,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
// Determine whether we've already imported this field.
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (IndirectFieldDecl *FoundField
= dyn_cast<IndirectFieldDecl>(FoundDecls[I])) {
@@ -2958,9 +2960,12 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
}
IndirectFieldDecl *ToIndirectField = IndirectFieldDecl::Create(
- Importer.getToContext(), DC,
- Loc, Name.getAsIdentifierInfo(), T,
- NamedChain, D->getChainingSize());
+ Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T,
+ NamedChain, D->getChainingSize());
+
+ for (const auto *Attr : D->attrs())
+ ToIndirectField->addAttr(Attr->clone(Importer.getToContext()));
+
ToIndirectField->setAccess(D->getAccess());
ToIndirectField->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToIndirectField);
@@ -2978,7 +2983,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
// Determine whether we've already imported this ivar
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecls[I])) {
if (Importer.IsStructurallyEquivalent(D->getType(),
@@ -3033,7 +3038,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
@@ -3203,7 +3208,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
return nullptr;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(FoundDecls[I])) {
if (FoundMethod->isInstanceMethod() != D->isInstanceMethod())
@@ -3439,7 +3444,7 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
ObjCProtocolDecl *MergeWithProtocol = nullptr;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol))
continue;
@@ -3466,6 +3471,36 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
return ToProto;
}
+Decl *ASTNodeImporter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ DeclContext *DC = Importer.ImportContext(D->getDeclContext());
+ DeclContext *LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+
+ SourceLocation ExternLoc = Importer.Import(D->getExternLoc());
+ SourceLocation LangLoc = Importer.Import(D->getLocation());
+
+ bool HasBraces = D->hasBraces();
+
+ LinkageSpecDecl *ToLinkageSpec =
+ LinkageSpecDecl::Create(Importer.getToContext(),
+ DC,
+ ExternLoc,
+ LangLoc,
+ D->getLanguage(),
+ HasBraces);
+
+ if (HasBraces) {
+ SourceLocation RBraceLoc = Importer.Import(D->getRBraceLoc());
+ ToLinkageSpec->setRBraceLoc(RBraceLoc);
+ }
+
+ ToLinkageSpec->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(ToLinkageSpec);
+
+ Importer.Imported(D, ToLinkageSpec);
+
+ return ToLinkageSpec;
+}
+
bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
ObjCInterfaceDecl *To,
ImportDefinitionKind Kind) {
@@ -3585,7 +3620,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
// Look for an existing interface with the same name.
ObjCInterfaceDecl *MergeWithIface = nullptr;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
continue;
@@ -3739,7 +3774,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
// Check whether we have already imported this property.
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCPropertyDecl *FoundProp
= dyn_cast<ObjCPropertyDecl>(FoundDecls[I])) {
@@ -3972,7 +4007,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
continue;
@@ -4161,7 +4196,7 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
"Variable templates cannot be declared at function scope");
SmallVector<NamedDecl *, 4> ConflictingDecls;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
continue;
@@ -4371,7 +4406,7 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
Importer.Import(E->getQualifierLoc()),
Importer.Import(E->getTemplateKeywordLoc()),
ToD,
- E->refersToEnclosingLocal(),
+ E->refersToEnclosingVariableOrCapture(),
Importer.Import(E->getLocation()),
T, E->getValueKind(),
FoundD,
@@ -4760,6 +4795,13 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
case NestedNameSpecifier::Global:
return NestedNameSpecifier::GlobalSpecifier(ToContext);
+ case NestedNameSpecifier::Super:
+ if (CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(Import(FromNNS->getAsRecordDecl()))) {
+ return NestedNameSpecifier::SuperSpecifier(ToContext, RD);
+ }
+ return nullptr;
+
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
QualType T = Import(QualType(FromNNS->getAsType(), 0u));
@@ -4882,7 +4924,10 @@ SourceLocation ASTImporter::Import(SourceLocation FromLoc) {
FromLoc = FromSM.getSpellingLoc(FromLoc);
std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc);
SourceManager &ToSM = ToContext.getSourceManager();
- return ToSM.getLocForStartOfFile(Import(Decomposed.first))
+ FileID ToFileID = Import(Decomposed.first);
+ if (ToFileID.isInvalid())
+ return SourceLocation();
+ return ToSM.getLocForStartOfFile(ToFileID)
.getLocWithOffset(Decomposed.second);
}
@@ -4913,16 +4958,19 @@ FileID ASTImporter::Import(FileID FromID) {
// FIXME: We definitely want to re-use the existing MemoryBuffer, rather
// than mmap the files several times.
const FileEntry *Entry = ToFileManager.getFile(Cache->OrigEntry->getName());
+ if (!Entry)
+ return FileID();
ToID = ToSM.createFileID(Entry, ToIncludeLoc,
FromSLoc.getFile().getFileCharacteristic());
} else {
// FIXME: We want to re-use the existing MemoryBuffer!
const llvm::MemoryBuffer *
FromBuf = Cache->getBuffer(FromContext.getDiagnostics(), FromSM);
- llvm::MemoryBuffer *ToBuf
+ std::unique_ptr<llvm::MemoryBuffer> ToBuf
= llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(),
FromBuf->getBufferIdentifier());
- ToID = ToSM.createFileID(ToBuf, FromSLoc.getFile().getFileCharacteristic());
+ ToID = ToSM.createFileID(std::move(ToBuf),
+ FromSLoc.getFile().getFileCharacteristic());
}
diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp
index baa8e48779a2..ec0671ceb1b5 100644
--- a/lib/AST/ASTTypeTraits.cpp
+++ b/lib/AST/ASTTypeTraits.cpp
@@ -62,6 +62,53 @@ bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived,
StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; }
+ASTNodeKind ASTNodeKind::getMostDerivedType(ASTNodeKind Kind1,
+ ASTNodeKind Kind2) {
+ if (Kind1.isBaseOf(Kind2)) return Kind2;
+ if (Kind2.isBaseOf(Kind1)) return Kind1;
+ return ASTNodeKind();
+}
+
+ASTNodeKind ASTNodeKind::getMostDerivedCommonAncestor(ASTNodeKind Kind1,
+ ASTNodeKind Kind2) {
+ NodeKindId Parent = Kind1.KindId;
+ while (!isBaseOf(Parent, Kind2.KindId, nullptr) && Parent != NKI_None) {
+ Parent = AllKindInfo[Parent].ParentId;
+ }
+ return ASTNodeKind(Parent);
+}
+
+ASTNodeKind ASTNodeKind::getFromNode(const Decl &D) {
+ switch (D.getKind()) {
+#define DECL(DERIVED, BASE) \
+ case Decl::DERIVED: return ASTNodeKind(NKI_##DERIVED##Decl);
+#define ABSTRACT_DECL(D)
+#include "clang/AST/DeclNodes.inc"
+ };
+ llvm_unreachable("invalid decl kind");
+}
+
+ASTNodeKind ASTNodeKind::getFromNode(const Stmt &S) {
+ switch (S.getStmtClass()) {
+ case Stmt::NoStmtClass: return NKI_None;
+#define STMT(CLASS, PARENT) \
+ case Stmt::CLASS##Class: return ASTNodeKind(NKI_##CLASS);
+#define ABSTRACT_STMT(S)
+#include "clang/AST/StmtNodes.inc"
+ }
+ llvm_unreachable("invalid stmt kind");
+}
+
+ASTNodeKind ASTNodeKind::getFromNode(const Type &T) {
+ switch (T.getTypeClass()) {
+#define TYPE(Class, Base) \
+ case Type::Class: return ASTNodeKind(NKI_##Class##Type);
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ }
+ llvm_unreachable("invalid type kind");
+}
+
void DynTypedNode::print(llvm::raw_ostream &OS,
const PrintingPolicy &PP) const {
if (const TemplateArgument *TA = get<TemplateArgument>())
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 9006be64f73f..6ce347b4a31c 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -35,7 +35,6 @@ add_clang_library(clangAST
ItaniumCXXABI.cpp
ItaniumMangle.cpp
Mangle.cpp
- MangleNumberingContext.cpp
MicrosoftCXXABI.cpp
MicrosoftMangle.cpp
NestedNameSpecifier.cpp
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 12b929b88db0..8e9e358525e8 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_CXXABI_H
-#define LLVM_CLANG_AST_CXXABI_H
+#ifndef LLVM_CLANG_LIB_AST_CXXABI_H
+#define LLVM_CLANG_LIB_AST_CXXABI_H
#include "clang/AST/Type.h"
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 4f433467f9bc..d05c5de543ff 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -157,8 +157,7 @@ void DeclInfo::fill() {
case Decl::CXXConversion: {
const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
Kind = FunctionKind;
- ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
- FD->getNumParams());
+ ParamVars = llvm::makeArrayRef(FD->param_begin(), FD->getNumParams());
ReturnType = FD->getReturnType();
unsigned NumLists = FD->getNumTemplateParameterLists();
if (NumLists != 0) {
@@ -178,8 +177,7 @@ void DeclInfo::fill() {
case Decl::ObjCMethod: {
const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
Kind = FunctionKind;
- ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
- MD->param_size());
+ ParamVars = llvm::makeArrayRef(MD->param_begin(), MD->param_size());
ReturnType = MD->getReturnType();
IsObjCMethod = true;
IsInstanceMethod = MD->isInstanceMethod();
@@ -191,8 +189,7 @@ void DeclInfo::fill() {
Kind = FunctionKind;
TemplateKind = Template;
const FunctionDecl *FD = FTD->getTemplatedDecl();
- ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
- FD->getNumParams());
+ ParamVars = llvm::makeArrayRef(FD->param_begin(), FD->getNumParams());
ReturnType = FD->getReturnType();
TemplateParameters = FTD->getTemplateParameters();
break;
@@ -278,9 +275,7 @@ void DeclInfo::fill() {
// Is this a typedef for a function type?
if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
Kind = FunctionKind;
- ArrayRef<ParmVarDecl *> Params = FTL.getParams();
- ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
- Params.size());
+ ParamVars = FTL.getParams();
ReturnType = FTL.getReturnLoc().getType();
break;
}
@@ -299,9 +294,7 @@ void DeclInfo::fill() {
TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc();
if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
Kind = FunctionKind;
- ArrayRef<ParmVarDecl *> Params = FTL.getParams();
- ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
- Params.size());
+ ParamVars = FTL.getParams();
ReturnType = FTL.getReturnLoc().getType();
}
break;
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index a7b07a40c985..7378a7c3ac06 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -89,6 +89,10 @@ CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
// Value-initialize (=zero-initialize in this case) a new CommandInfo.
CommandInfo *Info = new (Allocator) CommandInfo();
Info->Name = Name;
+ // We only have a limited number of bits to encode command IDs in the
+ // CommandInfo structure, so the ID numbers can potentially wrap around.
+ assert((NextID < (1 << CommandInfo::NumCommandIDBits))
+ && "Too many commands. We have limited bits for the command ID.");
Info->ID = NextID++;
RegisteredCommands.push_back(Info);
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index 792a8320449b..06a08bdad45f 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -362,7 +362,7 @@ void Lexer::lexCommentText(Token &T) {
}
}
- const StringRef CommandName(BufferPtr + 1, Length);
+ StringRef CommandName(BufferPtr + 1, Length);
const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName);
if (!Info) {
@@ -531,7 +531,7 @@ void Lexer::lexVerbatimLineText(Token &T) {
// Extract current line.
const char *Newline = findNewline(BufferPtr, CommentEnd);
- const StringRef Text(BufferPtr, Newline - BufferPtr);
+ StringRef Text(BufferPtr, Newline - BufferPtr);
formTokenWithChars(T, Newline, tok::verbatim_line_text);
T.setVerbatimLineText(Text);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 7448de2ffbc9..e43c28af9b69 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -29,6 +29,7 @@
#include "clang/Basic/Module.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
@@ -38,6 +39,11 @@ Decl *clang::getPrimaryMergedDecl(Decl *D) {
return D->getASTContext().getPrimaryMergedDecl(D);
}
+// Defined here so that it can be inlined into its direct callers.
+bool Decl::isOutOfLine() const {
+ return !getLexicalDeclContext()->Equals(getDeclContext());
+}
+
//===----------------------------------------------------------------------===//
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
@@ -613,9 +619,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// Explicitly declared static.
if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
return LinkageInfo(InternalLinkage, DefaultVisibility, false);
+ } else if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) {
+ // - a data member of an anonymous union.
+ const VarDecl *VD = IFD->getVarDecl();
+ assert(VD && "Expected a VarDecl in this IndirectFieldDecl!");
+ return getLVForNamespaceScopeDecl(VD, computation);
}
- // - a data member of an anonymous union.
- assert(!isa<IndirectFieldDecl>(D) && "Didn't expect an IndirectFieldDecl!");
assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!");
if (D->isInAnonymousNamespace()) {
@@ -811,6 +820,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// Everything not covered here has no linkage.
} else {
+ // FIXME: A typedef declaration has linkage if it gives a type a name for
+ // linkage purposes.
return LinkageInfo::none();
}
@@ -994,6 +1005,19 @@ bool NamedDecl::isLinkageValid() const {
getCachedLinkage();
}
+ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const {
+ StringRef name = getName();
+ if (name.empty()) return SFF_None;
+
+ if (name.front() == 'C')
+ if (name == "CFStringCreateWithFormat" ||
+ name == "CFStringCreateWithFormatAndArguments" ||
+ name == "CFStringAppendFormat" ||
+ name == "CFStringAppendFormatAndArguments")
+ return SFF_CFString;
+ return SFF_None;
+}
+
Linkage NamedDecl::getLinkageInternal() const {
// We don't care about visibility here, so ask for the cheapest
// possible visibility analysis.
@@ -1168,7 +1192,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
} else {
const FunctionDecl *FD = cast<FunctionDecl>(OuterD);
if (!FD->isInlined() &&
- FD->getTemplateSpecializationKind() == TSK_Undeclared)
+ !isTemplateInstantiation(FD->getTemplateSpecializationKind()))
return LinkageInfo::none();
LV = getLVForDecl(FD, computation);
@@ -2607,7 +2631,7 @@ void FunctionDecl::setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls) {
if (!NewDecls.empty()) {
NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()];
std::copy(NewDecls.begin(), NewDecls.end(), A);
- DeclsInPrototypeScope = ArrayRef<NamedDecl *>(A, NewDecls.size());
+ DeclsInPrototypeScope = llvm::makeArrayRef(A, NewDecls.size());
// Move declarations introduced in prototype to the function context.
for (auto I : NewDecls) {
DeclContext *DC = I->getDeclContext();
@@ -3168,8 +3192,11 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
return Builtin::BImemmove;
case Builtin::BIstrlcpy:
+ case Builtin::BI__builtin___strlcpy_chk:
return Builtin::BIstrlcpy;
+
case Builtin::BIstrlcat:
+ case Builtin::BI__builtin___strlcat_chk:
return Builtin::BIstrlcat;
case Builtin::BI__builtin_memcmp:
@@ -3261,7 +3288,7 @@ bool FieldDecl::isAnonymousStructOrUnion() const {
unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const {
assert(isBitField() && "not a bitfield");
- Expr *BitWidth = InitializerOrBitWidth.getPointer();
+ Expr *BitWidth = static_cast<Expr *>(InitStorage.getPointer());
return BitWidth->EvaluateKnownConstInt(Ctx).getZExtValue();
}
@@ -3275,30 +3302,39 @@ unsigned FieldDecl::getFieldIndex() const {
unsigned Index = 0;
const RecordDecl *RD = getParent();
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I, ++Index)
- I->getCanonicalDecl()->CachedFieldIndex = Index + 1;
+ for (auto *Field : RD->fields()) {
+ Field->getCanonicalDecl()->CachedFieldIndex = Index + 1;
+ ++Index;
+ }
assert(CachedFieldIndex && "failed to find field in parent");
return CachedFieldIndex - 1;
}
SourceRange FieldDecl::getSourceRange() const {
- if (const Expr *E = InitializerOrBitWidth.getPointer())
- return SourceRange(getInnerLocStart(), E->getLocEnd());
- return DeclaratorDecl::getSourceRange();
-}
+ switch (InitStorage.getInt()) {
+ // All three of these cases store an optional Expr*.
+ case ISK_BitWidthOrNothing:
+ case ISK_InClassCopyInit:
+ case ISK_InClassListInit:
+ if (const Expr *E = static_cast<const Expr *>(InitStorage.getPointer()))
+ return SourceRange(getInnerLocStart(), E->getLocEnd());
+ // FALLTHROUGH
-void FieldDecl::setBitWidth(Expr *Width) {
- assert(!InitializerOrBitWidth.getPointer() && !hasInClassInitializer() &&
- "bit width or initializer already set");
- InitializerOrBitWidth.setPointer(Width);
+ case ISK_CapturedVLAType:
+ return DeclaratorDecl::getSourceRange();
+ }
+ llvm_unreachable("bad init storage kind");
}
-void FieldDecl::setInClassInitializer(Expr *Init) {
- assert(!InitializerOrBitWidth.getPointer() && hasInClassInitializer() &&
- "bit width or initializer already set");
- InitializerOrBitWidth.setPointer(Init);
+void FieldDecl::setCapturedVLAType(const VariableArrayType *VLAType) {
+ assert((getParent()->isLambda() || getParent()->isCapturedRecord()) &&
+ "capturing type in non-lambda or captured record.");
+ assert(InitStorage.getInt() == ISK_BitWidthOrNothing &&
+ InitStorage.getPointer() == nullptr &&
+ "bit width, initializer or captured type already set");
+ InitStorage.setPointerAndInt(const_cast<VariableArrayType *>(VLAType),
+ ISK_CapturedVLAType);
}
//===----------------------------------------------------------------------===//
@@ -3521,6 +3557,20 @@ bool RecordDecl::isInjectedClassName() const {
cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName();
}
+bool RecordDecl::isLambda() const {
+ if (auto RD = dyn_cast<CXXRecordDecl>(this))
+ return RD->isLambda();
+ return false;
+}
+
+bool RecordDecl::isCapturedRecord() const {
+ return hasAttr<CapturedRecordAttr>();
+}
+
+void RecordDecl::setCapturedRecord() {
+ addAttr(CapturedRecordAttr::CreateImplicit(getASTContext()));
+}
+
RecordDecl::field_iterator RecordDecl::field_begin() const {
if (hasExternalLexicalStorage() && !LoadedFieldsFromExternalStorage)
LoadFieldsFromExternalStorage();
@@ -3578,6 +3628,64 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
/*FieldsAlreadyLoaded=*/false);
}
+bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
+ ASTContext &Context = getASTContext();
+ if (!Context.getLangOpts().Sanitize.has(SanitizerKind::Address) ||
+ !Context.getLangOpts().SanitizeAddressFieldPadding)
+ return false;
+ const auto &Blacklist = Context.getSanitizerBlacklist();
+ const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this);
+ // We may be able to relax some of these requirements.
+ int ReasonToReject = -1;
+ if (!CXXRD || CXXRD->isExternCContext())
+ ReasonToReject = 0; // is not C++.
+ else if (CXXRD->hasAttr<PackedAttr>())
+ ReasonToReject = 1; // is packed.
+ else if (CXXRD->isUnion())
+ ReasonToReject = 2; // is a union.
+ else if (CXXRD->isTriviallyCopyable())
+ ReasonToReject = 3; // is trivially copyable.
+ else if (CXXRD->hasTrivialDestructor())
+ ReasonToReject = 4; // has trivial destructor.
+ else if (CXXRD->isStandardLayout())
+ ReasonToReject = 5; // is standard layout.
+ else if (Blacklist.isBlacklistedLocation(getLocation(), "field-padding"))
+ ReasonToReject = 6; // is in a blacklisted file.
+ else if (Blacklist.isBlacklistedType(getQualifiedNameAsString(),
+ "field-padding"))
+ ReasonToReject = 7; // is blacklisted.
+
+ if (EmitRemark) {
+ if (ReasonToReject >= 0)
+ Context.getDiagnostics().Report(
+ getLocation(),
+ diag::remark_sanitize_address_insert_extra_padding_rejected)
+ << getQualifiedNameAsString() << ReasonToReject;
+ else
+ Context.getDiagnostics().Report(
+ getLocation(),
+ diag::remark_sanitize_address_insert_extra_padding_accepted)
+ << getQualifiedNameAsString();
+ }
+ return ReasonToReject < 0;
+}
+
+const FieldDecl *RecordDecl::findFirstNamedDataMember() const {
+ for (const auto *I : fields()) {
+ if (I->getIdentifier())
+ return I;
+
+ if (const RecordType *RT = I->getType()->getAs<RecordType>())
+ if (const FieldDecl *NamedDataMember =
+ RT->getDecl()->findFirstNamedDataMember())
+ return NamedDataMember;
+ }
+
+ // We didn't find a named data member.
+ return nullptr;
+}
+
+
//===----------------------------------------------------------------------===//
// BlockDecl Implementation
//===----------------------------------------------------------------------===//
@@ -3657,6 +3765,13 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
SourceLocation());
}
+void LabelDecl::setMSAsmLabel(StringRef Name) {
+ char *Buffer = new (getASTContext(), 1) char[Name.size() + 1];
+ memcpy(Buffer, Name.data(), Name.size());
+ Buffer[Name.size()] = '\0';
+ MSAsmName = Buffer;
+}
+
void ValueDecl::anchor() { }
bool ValueDecl::isWeak() const {
@@ -3892,8 +4007,8 @@ ArrayRef<SourceLocation> ImportDecl::getIdentifierLocs() const {
const SourceLocation *StoredLocs
= reinterpret_cast<const SourceLocation *>(this + 1);
- return ArrayRef<SourceLocation>(StoredLocs,
- getNumModuleIdentifiers(getImportedModule()));
+ return llvm::makeArrayRef(StoredLocs,
+ getNumModuleIdentifiers(getImportedModule()));
}
SourceRange ImportDecl::getSourceRange() const {
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 2b1506d191d1..a46787fb0e8f 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -374,8 +374,10 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
if (Message) {
Message->clear();
llvm::raw_string_ostream Out(*Message);
+ VersionTuple VTI(A->getIntroduced());
+ VTI.UseDotAsSeparator();
Out << "introduced in " << PrettyPlatformName << ' '
- << A->getIntroduced() << HintMessage;
+ << VTI << HintMessage;
}
return AR_NotYetIntroduced;
@@ -386,8 +388,10 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
if (Message) {
Message->clear();
llvm::raw_string_ostream Out(*Message);
+ VersionTuple VTO(A->getObsoleted());
+ VTO.UseDotAsSeparator();
Out << "obsoleted in " << PrettyPlatformName << ' '
- << A->getObsoleted() << HintMessage;
+ << VTO << HintMessage;
}
return AR_Unavailable;
@@ -398,8 +402,10 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
if (Message) {
Message->clear();
llvm::raw_string_ostream Out(*Message);
+ VersionTuple VTD(A->getDeprecated());
+ VTD.UseDotAsSeparator();
Out << "first deprecated in " << PrettyPlatformName << ' '
- << A->getDeprecated() << HintMessage;
+ << VTD << HintMessage;
}
return AR_Deprecated;
@@ -1296,6 +1302,11 @@ DeclContext::lookup(DeclarationName Name) {
if (PrimaryContext != this)
return PrimaryContext->lookup(Name);
+ // If this is a namespace, ensure that any later redeclarations of it have
+ // been loaded, since they may add names to the result of this lookup.
+ if (auto *ND = dyn_cast<NamespaceDecl>(this))
+ (void)ND->getMostRecentDecl();
+
if (hasExternalVisibleStorage()) {
if (NeedToReconcileExternalVisibleStorage)
reconcileExternalVisibleStorage();
@@ -1430,6 +1441,17 @@ DeclContext *DeclContext::getEnclosingNamespaceContext() {
return Ctx->getPrimaryContext();
}
+RecordDecl *DeclContext::getOuterLexicalRecordContext() {
+ // Loop until we find a non-record context.
+ RecordDecl *OutermostRD = nullptr;
+ DeclContext *DC = this;
+ while (DC->isRecord()) {
+ OutermostRD = cast<RecordDecl>(DC);
+ DC = DC->getLexicalParent();
+ }
+ return OutermostRD;
+}
+
bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const {
// For non-file contexts, this is equivalent to Equals.
if (!isFileContext())
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index ed26c5262a7b..a6d9d411eef3 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -209,7 +209,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// Now go through all virtual bases of this base and add them.
for (const auto &VBase : BaseClassDecl->vbases()) {
// Add this base if it's not already in the list.
- if (SeenVBaseTypes.insert(C.getCanonicalType(VBase.getType()))) {
+ if (SeenVBaseTypes.insert(C.getCanonicalType(VBase.getType())).second) {
VBases.push_back(&VBase);
// C++11 [class.copy]p8:
@@ -225,7 +225,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (Base->isVirtual()) {
// Add this base if it's not already in the list.
- if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
+ if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)).second)
VBases.push_back(Base);
// C++0x [meta.unary.prop] is_empty:
@@ -677,17 +677,24 @@ void CXXRecordDecl::addedMember(Decl *D) {
//
// Automatic Reference Counting: the presence of a member of Objective-C pointer type
// that does not explicitly have no lifetime makes the class a non-POD.
- // However, we delay setting PlainOldData to false in this case so that
- // Sema has a chance to diagnostic causes where the same class will be
- // non-POD with Automatic Reference Counting but a POD without ARC.
- // In this case, the class will become a non-POD class when we complete
- // the definition.
ASTContext &Context = getASTContext();
QualType T = Context.getBaseElementType(Field->getType());
if (T->isObjCRetainableType() || T.isObjCGCStrong()) {
- if (!Context.getLangOpts().ObjCAutoRefCount ||
- T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone)
+ if (!Context.getLangOpts().ObjCAutoRefCount) {
setHasObjectMember(true);
+ } else if (T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
+ // Objective-C Automatic Reference Counting:
+ // If a class has a non-static data member of Objective-C pointer
+ // type (or array thereof), it is a non-POD type and its
+ // default constructor (if any), copy constructor, move constructor,
+ // copy assignment operator, move assignment operator, and destructor are
+ // non-trivial.
+ setHasObjectMember(true);
+ struct DefinitionData &Data = data();
+ Data.PlainOldData = false;
+ Data.HasTrivialSpecialMembers = 0;
+ Data.HasIrrelevantDestructor = false;
+ }
} else if (!T.isCXX98PODType(Context))
data().PlainOldData = false;
@@ -720,7 +727,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
// brace-or-equal-initializers for non-static data members.
//
// This rule was removed in C++1y.
- if (!getASTContext().getLangOpts().CPlusPlus1y)
+ if (!getASTContext().getLangOpts().CPlusPlus14)
data().Aggregate = false;
// C++11 [class]p10:
@@ -1254,6 +1261,44 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
llvm_unreachable("Not a class template or member class specialization");
}
+const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
+ // If it's a class template specialization, find the template or partial
+ // specialization from which it was instantiated.
+ if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
+ auto From = TD->getInstantiatedFrom();
+ if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
+ while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
+ if (NewCTD->isMemberSpecialization())
+ break;
+ CTD = NewCTD;
+ }
+ return CTD->getTemplatedDecl();
+ }
+ if (auto *CTPSD =
+ From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
+ while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
+ if (NewCTPSD->isMemberSpecialization())
+ break;
+ CTPSD = NewCTPSD;
+ }
+ return CTPSD;
+ }
+ }
+
+ if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) {
+ if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) {
+ const CXXRecordDecl *RD = this;
+ while (auto *NewRD = RD->getInstantiatedFromMemberClass())
+ RD = NewRD;
+ return RD;
+ }
+ }
+
+ assert(!isTemplateInstantiation(this->getTemplateSpecializationKind()) &&
+ "couldn't find pattern for class template instantiation");
+ return nullptr;
+}
+
CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
ASTContext &Context = getASTContext();
QualType ClassType = Context.getTypeDeclType(this);
@@ -1277,19 +1322,6 @@ void CXXRecordDecl::completeDefinition() {
void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
RecordDecl::completeDefinition();
- if (hasObjectMember() && getASTContext().getLangOpts().ObjCAutoRefCount) {
- // Objective-C Automatic Reference Counting:
- // If a class has a non-static data member of Objective-C pointer
- // type (or array thereof), it is a non-POD type and its
- // default constructor (if any), copy constructor, move constructor,
- // copy assignment operator, move assignment operator, and destructor are
- // non-trivial.
- struct DefinitionData &Data = data();
- Data.PlainOldData = false;
- Data.HasTrivialSpecialMembers = 0;
- Data.HasIrrelevantDestructor = false;
- }
-
// If the class may be abstract (but hasn't been marked as such), check for
// any pure final overriders.
if (mayBeAbstract()) {
@@ -1799,7 +1831,6 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const {
bool CXXConstructorDecl::isSpecializationCopyingObject() const {
if ((getNumParams() < 1) ||
(getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
- (getPrimaryTemplate() == nullptr) ||
(getDescribedFunctionTemplate() != nullptr))
return false;
@@ -1970,6 +2001,16 @@ NamespaceDecl *NamespaceDecl::getMostRecentDeclImpl() {
void NamespaceAliasDecl::anchor() { }
+NamespaceAliasDecl *NamespaceAliasDecl::getNextRedeclarationImpl() {
+ return getNextRedeclaration();
+}
+NamespaceAliasDecl *NamespaceAliasDecl::getPreviousDeclImpl() {
+ return getPreviousDecl();
+}
+NamespaceAliasDecl *NamespaceAliasDecl::getMostRecentDeclImpl() {
+ return getMostRecentDecl();
+}
+
NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingLoc,
SourceLocation AliasLoc,
@@ -1977,15 +2018,16 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation IdentLoc,
NamedDecl *Namespace) {
+ // FIXME: Preserve the aliased namespace as written.
if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace))
Namespace = NS->getOriginalNamespace();
- return new (C, DC) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias,
+ return new (C, DC) NamespaceAliasDecl(C, DC, UsingLoc, AliasLoc, Alias,
QualifierLoc, IdentLoc, Namespace);
}
NamespaceAliasDecl *
NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- return new (C, ID) NamespaceAliasDecl(nullptr, SourceLocation(),
+ return new (C, ID) NamespaceAliasDecl(C, nullptr, SourceLocation(),
SourceLocation(), nullptr,
NestedNameSpecifierLoc(),
SourceLocation(), nullptr);
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 2204dff13739..ed5367514c30 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -93,13 +93,13 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance,
return nullptr;
}
-/// HasUserDeclaredSetterMethod - This routine returns 'true' if a user declared setter
-/// method was found in the class, its protocols, its super classes or categories.
-/// It also returns 'true' if one of its categories has declared a 'readwrite' property.
-/// This is because, user must provide a setter method for the category's 'readwrite'
-/// property.
-bool
-ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property) const {
+/// \brief This routine returns 'true' if a user declared setter method was
+/// found in the class, its protocols, its super classes or categories.
+/// It also returns 'true' if one of its categories has declared a 'readwrite'
+/// property. This is because, user must provide a setter method for the
+/// category's 'readwrite' property.
+bool ObjCContainerDecl::HasUserDeclaredSetterMethod(
+ const ObjCPropertyDecl *Property) const {
Selector Sel = Property->getSetterName();
lookup_const_result R = lookup(Sel);
for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end();
@@ -118,9 +118,10 @@ ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property)
return true;
if (Cat->IsClassExtension())
continue;
- // Also search through the categories looking for a 'readwrite' declaration
- // of this property. If one found, presumably a setter will be provided
- // (properties declared in categories will not get auto-synthesized).
+ // Also search through the categories looking for a 'readwrite'
+ // declaration of this property. If one found, presumably a setter will
+ // be provided (properties declared in categories will not get
+ // auto-synthesized).
for (const auto *P : Cat->properties())
if (P->getIdentifier() == Property->getIdentifier()) {
if (P->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite)
@@ -151,7 +152,7 @@ ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property)
ObjCPropertyDecl *
ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
- IdentifierInfo *propertyID) {
+ const IdentifierInfo *propertyID) {
// If this context is a hidden protocol definition, don't find any
// property.
if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(DC)) {
@@ -181,8 +182,8 @@ ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const {
/// FindPropertyDeclaration - Finds declaration of the property given its name
/// in 'PropertyId' and returns it. It returns 0, if not found.
-ObjCPropertyDecl *
-ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
+ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
+ const IdentifierInfo *PropertyId) const {
// Don't find properties within hidden protocol definitions.
if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
if (const ObjCProtocolDecl *Def = Proto->getDefinition())
@@ -558,36 +559,39 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
LoadExternalDefinition();
while (ClassDecl) {
+ // 1. Look through primary class.
if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance)))
return MethodDecl;
-
- // Didn't find one yet - look through protocols.
- for (const auto *I : ClassDecl->protocols())
- if ((MethodDecl = I->lookupMethod(Sel, isInstance)))
- return MethodDecl;
- // Didn't find one yet - now look through categories.
- for (const auto *Cat : ClassDecl->visible_categories()) {
+ // 2. Didn't find one yet - now look through categories.
+ for (const auto *Cat : ClassDecl->visible_categories())
if ((MethodDecl = Cat->getMethod(Sel, isInstance)))
if (C != Cat || !MethodDecl->isImplicit())
return MethodDecl;
- if (!shallowCategoryLookup) {
+ // 3. Didn't find one yet - look through primary class's protocols.
+ for (const auto *I : ClassDecl->protocols())
+ if ((MethodDecl = I->lookupMethod(Sel, isInstance)))
+ return MethodDecl;
+
+ // 4. Didn't find one yet - now look through categories' protocols
+ if (!shallowCategoryLookup)
+ for (const auto *Cat : ClassDecl->visible_categories()) {
// Didn't find one yet - look through protocols.
const ObjCList<ObjCProtocolDecl> &Protocols =
- Cat->getReferencedProtocols();
+ Cat->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
if (C != Cat || !MethodDecl->isImplicit())
return MethodDecl;
}
- }
-
+
+
if (!followSuper)
return nullptr;
- // Get the super class (if any).
+ // 5. Get to the super class (if any).
ClassDecl = ClassDecl->getSuperClass();
}
return nullptr;
@@ -849,6 +853,11 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
family = OMF_None;
break;
+ case OMF_initialize:
+ if (isInstanceMethod() || !getReturnType()->isVoidType())
+ family = OMF_None;
+ break;
+
case OMF_performSelector:
if (!isInstanceMethod() || !getReturnType()->isObjCIdType())
family = OMF_None;
@@ -952,6 +961,13 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
llvm_unreachable("unknown method context");
}
+SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const {
+ const auto *TSI = getReturnTypeSourceInfo();
+ if (TSI)
+ return TSI->getTypeLoc().getSourceRange();
+ return SourceRange();
+}
+
static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
const ObjCMethodDecl *Method,
SmallVectorImpl<const ObjCMethodDecl *> &Methods,
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index e5e5130f695a..c0f3e17693dc 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -87,6 +87,7 @@ namespace {
void PrintTemplateParameters(const TemplateParameterList *Params,
const TemplateArgumentList *Args = nullptr);
void prettyPrintAttributes(Decl *D);
+ void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
};
}
@@ -197,6 +198,17 @@ void DeclPrinter::prettyPrintAttributes(Decl *D) {
}
}
+void DeclPrinter::printDeclType(QualType T, StringRef DeclName, bool Pack) {
+ // Normally, a PackExpansionType is written as T[3]... (for instance, as a
+ // template argument), but if it is the type of a declaration, the ellipsis
+ // is placed before the name being declared.
+ if (auto *PET = T->getAs<PackExpansionType>()) {
+ Pack = true;
+ T = PET->getPattern();
+ }
+ T.print(Out, Policy, (Pack ? "..." : "") + DeclName);
+}
+
void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) {
this->Indent();
Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation);
@@ -365,6 +377,9 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
if (!Policy.SuppressSpecifiers && D->isModulePrivate())
Out << "__module_private__ ";
Out << D->getKindName();
+
+ prettyPrintAttributes(D);
+
if (D->getIdentifier())
Out << ' ' << *D;
@@ -647,7 +662,6 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
Out << *D << ":";
}
-
void DeclPrinter::VisitVarDecl(VarDecl *D) {
if (!Policy.SuppressSpecifiers) {
StorageClass SC = D->getStorageClass();
@@ -675,7 +689,7 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
QualType T = D->getTypeSourceInfo()
? D->getTypeSourceInfo()->getType()
: D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
- T.print(Out, Policy, D->getName());
+ printDeclType(T, D->getName());
Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
bool ImplicitInit = false;
@@ -757,6 +771,9 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (!Policy.SuppressSpecifiers && D->isModulePrivate())
Out << "__module_private__ ";
Out << D->getKindName();
+
+ prettyPrintAttributes(D);
+
if (D->getIdentifier())
Out << ' ' << *D;
@@ -773,9 +790,11 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Out << "virtual ";
AccessSpecifier AS = Base->getAccessSpecifierAsWritten();
- if (AS != AS_none)
+ if (AS != AS_none) {
Print(AS);
- Out << " " << Base->getType().getAsString(Policy);
+ Out << " ";
+ }
+ Out << Base->getType().getAsString(Policy);
if (Base->isPackExpansion())
Out << "...";
@@ -830,7 +849,7 @@ void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params,
Out << "class ";
if (TTP->isParameterPack())
- Out << "... ";
+ Out << "...";
Out << *TTP;
@@ -843,15 +862,10 @@ void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params,
};
} else if (const NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- Out << NTTP->getType().getAsString(Policy);
-
- if (NTTP->isParameterPack() && !isa<PackExpansionType>(NTTP->getType()))
- Out << "...";
-
- if (IdentifierInfo *Name = NTTP->getIdentifier()) {
- Out << ' ';
- Out << Name->getName();
- }
+ StringRef Name;
+ if (IdentifierInfo *II = NTTP->getIdentifier())
+ Name = II->getName();
+ printDeclType(NTTP->getType(), Name, NTTP->isParameterPack());
if (Args) {
Out << " = ";
@@ -940,11 +954,12 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
if (OMD->isVariadic())
Out << ", ...";
+
+ prettyPrintAttributes(OMD);
if (OMD->getBody() && !Policy.TerseOutput) {
Out << ' ';
OMD->getBody()->printPretty(Out, nullptr, Policy);
- Out << '\n';
}
else if (Policy.PolishForDeclaration)
Out << ';';
@@ -954,6 +969,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
std::string I = OID->getNameAsString();
ObjCInterfaceDecl *SID = OID->getSuperClass();
+ bool eolnOut = false;
if (SID)
Out << "@implementation " << I << " : " << *SID;
else
@@ -961,6 +977,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
if (OID->ivar_size() > 0) {
Out << "{\n";
+ eolnOut = true;
Indentation += Policy.Indentation;
for (const auto *I : OID->ivars()) {
Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()).
@@ -969,7 +986,13 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
Indentation -= Policy.Indentation;
Out << "}\n";
}
+ else if (SID || (OID->decls_begin() != OID->decls_end())) {
+ Out << "\n";
+ eolnOut = true;
+ }
VisitDeclContext(OID, false);
+ if (!eolnOut)
+ Out << "\n";
Out << "@end";
}
@@ -1008,14 +1031,14 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Indentation -= Policy.Indentation;
Out << "}\n";
}
- else if (SID) {
+ else if (SID || (OID->decls_begin() != OID->decls_end())) {
Out << "\n";
eolnOut = true;
}
VisitDeclContext(OID, false);
if (!eolnOut)
- Out << ' ';
+ Out << "\n";
Out << "@end";
// FIXME: implement the rest...
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 5f559b7e5ce3..712de5056e8d 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -195,12 +195,12 @@ SourceLocation Expr::getExprLoc() const {
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
- case Stmt::type##Class: llvm_unreachable(#type " is not an Expr"); break;
+ case Stmt::type##Class: break;
#define EXPR(type, base) \
case Stmt::type##Class: return getExprLocImpl<type>(this, &type::getExprLoc);
#include "clang/AST/StmtNodes.inc"
}
- llvm_unreachable("unknown statement kind");
+ llvm_unreachable("unknown expression kind");
}
//===----------------------------------------------------------------------===//
@@ -221,11 +221,11 @@ static void computeDeclRefDependence(const ASTContext &Ctx, NamedDecl *D,
// (TD) C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
//
- // and
+ // and
//
// (VD) C++ [temp.dep.constexpr]p2:
// An identifier is value-dependent if it is:
-
+
// (TD) - an identifier that was declared with dependent type
// (VD) - a name declared with a dependent type,
if (T->isDependentType()) {
@@ -309,29 +309,11 @@ void DeclRefExpr::computeDependence(const ASTContext &Ctx) {
bool InstantiationDependent = false;
computeDeclRefDependence(Ctx, getDecl(), getType(), TypeDependent,
ValueDependent, InstantiationDependent);
-
- // (TD) C++ [temp.dep.expr]p3:
- // An id-expression is type-dependent if it contains:
- //
- // and
- //
- // (VD) C++ [temp.dep.constexpr]p2:
- // An identifier is value-dependent if it is:
- if (!TypeDependent && !ValueDependent &&
- hasExplicitTemplateArgs() &&
- TemplateSpecializationType::anyDependentTemplateArguments(
- getTemplateArgs(),
- getNumTemplateArgs(),
- InstantiationDependent)) {
- TypeDependent = true;
- ValueDependent = true;
- InstantiationDependent = true;
- }
-
- ExprBits.TypeDependent = TypeDependent;
- ExprBits.ValueDependent = ValueDependent;
- ExprBits.InstantiationDependent = InstantiationDependent;
-
+
+ ExprBits.TypeDependent |= TypeDependent;
+ ExprBits.ValueDependent |= ValueDependent;
+ ExprBits.InstantiationDependent |= InstantiationDependent;
+
// Is the declaration a parameter pack?
if (getDecl()->isParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
@@ -340,7 +322,7 @@ void DeclRefExpr::computeDependence(const ASTContext &Ctx) {
DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
- ValueDecl *D, bool RefersToEnclosingLocal,
+ ValueDecl *D, bool RefersToEnclosingVariableOrCapture,
const DeclarationNameInfo &NameInfo,
NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs,
@@ -348,14 +330,21 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
D(D), Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) {
DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0;
- if (QualifierLoc)
+ if (QualifierLoc) {
getInternalQualifierLoc() = QualifierLoc;
+ auto *NNS = QualifierLoc.getNestedNameSpecifier();
+ if (NNS->isInstantiationDependent())
+ ExprBits.InstantiationDependent = true;
+ if (NNS->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+ }
DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0;
if (FoundD)
getInternalFoundDecl() = FoundD;
DeclRefExprBits.HasTemplateKWAndArgsInfo
= (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0;
- DeclRefExprBits.RefersToEnclosingLocal = RefersToEnclosingLocal;
+ DeclRefExprBits.RefersToEnclosingVariableOrCapture =
+ RefersToEnclosingVariableOrCapture;
if (TemplateArgs) {
bool Dependent = false;
bool InstantiationDependent = false;
@@ -364,8 +353,9 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
Dependent,
InstantiationDependent,
ContainsUnexpandedParameterPack);
- if (InstantiationDependent)
- setInstantiationDependent(true);
+ assert(!Dependent && "built a DeclRefExpr with dependent template args");
+ ExprBits.InstantiationDependent |= InstantiationDependent;
+ ExprBits.ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
} else if (TemplateKWLoc.isValid()) {
getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
@@ -378,14 +368,14 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D,
- bool RefersToEnclosingLocal,
+ bool RefersToEnclosingVariableOrCapture,
SourceLocation NameLoc,
QualType T,
ExprValueKind VK,
NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs) {
return Create(Context, QualifierLoc, TemplateKWLoc, D,
- RefersToEnclosingLocal,
+ RefersToEnclosingVariableOrCapture,
DeclarationNameInfo(D->getDeclName(), NameLoc),
T, VK, FoundD, TemplateArgs);
}
@@ -394,7 +384,7 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D,
- bool RefersToEnclosingLocal,
+ bool RefersToEnclosingVariableOrCapture,
const DeclarationNameInfo &NameInfo,
QualType T,
ExprValueKind VK,
@@ -416,7 +406,7 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D,
- RefersToEnclosingLocal,
+ RefersToEnclosingVariableOrCapture,
NameInfo, FoundD, TemplateArgs, T, VK);
}
@@ -448,6 +438,38 @@ SourceLocation DeclRefExpr::getLocEnd() const {
return getNameInfo().getLocEnd();
}
+PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT,
+ StringLiteral *SL)
+ : Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary,
+ FNTy->isDependentType(), FNTy->isDependentType(),
+ FNTy->isInstantiationDependentType(),
+ /*ContainsUnexpandedParameterPack=*/false),
+ Loc(L), Type(IT), FnName(SL) {}
+
+StringLiteral *PredefinedExpr::getFunctionName() {
+ return cast_or_null<StringLiteral>(FnName);
+}
+
+StringRef PredefinedExpr::getIdentTypeName(PredefinedExpr::IdentType IT) {
+ switch (IT) {
+ case Func:
+ return "__func__";
+ case Function:
+ return "__FUNCTION__";
+ case FuncDName:
+ return "__FUNCDNAME__";
+ case LFunction:
+ return "L__FUNCTION__";
+ case PrettyFunction:
+ return "__PRETTY_FUNCTION__";
+ case FuncSig:
+ return "__FUNCSIG__";
+ case PrettyFunctionNoVirtual:
+ break;
+ }
+ llvm_unreachable("Unknown ident type for PredefinedExpr");
+}
+
// FIXME: Maybe this should use DeclPrinter with a special "print predefined
// expr" policy instead.
std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
@@ -477,6 +499,22 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
}
return "";
}
+ if (auto *BD = dyn_cast<BlockDecl>(CurrentDecl)) {
+ std::unique_ptr<MangleContext> MC;
+ MC.reset(Context.createMangleContext());
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ auto DC = CurrentDecl->getDeclContext();
+ if (DC->isFileContext())
+ MC->mangleGlobalBlock(BD, /*ID*/ nullptr, Out);
+ else if (const auto *CD = dyn_cast<CXXConstructorDecl>(DC))
+ MC->mangleCtorBlock(CD, /*CT*/ Ctor_Complete, BD, Out);
+ else if (const auto *DD = dyn_cast<CXXDestructorDecl>(DC))
+ MC->mangleDtorBlock(DD, /*DT*/ Dtor_Complete, BD, Out);
+ else
+ MC->mangleBlock(DC, BD, Out);
+ return Out.str();
+ }
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual && IT != FuncSig)
return FD->getNameAsString();
@@ -509,6 +547,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
case CC_X86StdCall: POut << "__stdcall "; break;
case CC_X86FastCall: POut << "__fastcall "; break;
case CC_X86ThisCall: POut << "__thiscall "; break;
+ case CC_X86VectorCall: POut << "__vectorcall "; break;
// Only bother printing the conventions that MSVC knows about.
default: break;
}
@@ -600,9 +639,8 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
// type deduction and lambdas. For trailing return types resolve the
// decltype expression. Otherwise print the real type when this is
// not a constructor or destructor.
- if ((isa<CXXMethodDecl>(FD) &&
- cast<CXXMethodDecl>(FD)->getParent()->isLambda()) ||
- (FT && FT->getReturnType()->getAs<AutoType>()))
+ if (isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->getParent()->isLambda())
Proto = "auto " + Proto;
else if (FT && FT->getReturnType()->getAs<DecltypeType>())
FT->getReturnType()
@@ -1252,7 +1290,7 @@ SourceLocation CallExpr::getLocStart() const {
return cast<CXXOperatorCallExpr>(this)->getLocStart();
SourceLocation begin = getCallee()->getLocStart();
- if (begin.isInvalid() && getNumArgs() > 0)
+ if (begin.isInvalid() && getNumArgs() > 0 && getArg(0))
begin = getArg(0)->getLocStart();
return begin;
}
@@ -1261,7 +1299,7 @@ SourceLocation CallExpr::getLocEnd() const {
return cast<CXXOperatorCallExpr>(this)->getLocEnd();
SourceLocation end = getRParenLoc();
- if (end.isInvalid() && getNumArgs() > 0)
+ if (end.isInvalid() && getNumArgs() > 0 && getArg(getNumArgs() - 1))
end = getArg(getNumArgs() - 1)->getLocEnd();
return end;
}
@@ -2734,10 +2772,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
if (ILE->getType()->isRecordType()) {
unsigned ElementNo = 0;
RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) {
+ for (const auto *Field : RD->fields()) {
// If this is a union, skip all the fields that aren't being initialized.
- if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
+ if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field)
continue;
// Don't emit anonymous bitfields, they just affect layout.
@@ -2830,9 +2867,16 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
return false;
}
-bool Expr::HasSideEffects(const ASTContext &Ctx) const {
+bool Expr::HasSideEffects(const ASTContext &Ctx,
+ bool IncludePossibleEffects) const {
+ // In circumstances where we care about definite side effects instead of
+ // potential side effects, we want to ignore expressions that are part of a
+ // macro expansion as a potential side effect.
+ if (!IncludePossibleEffects && getExprLoc().isMacroID())
+ return false;
+
if (isInstantiationDependent())
- return true;
+ return IncludePossibleEffects;
switch (getStmtClass()) {
case NoStmtClass:
@@ -2850,6 +2894,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case PackExpansionExprClass:
case SubstNonTypeTemplateParmPackExprClass:
case FunctionParmPackExprClass:
+ case TypoExprClass:
+ case CXXFoldExprClass:
llvm_unreachable("shouldn't see dependent / unresolved nodes here");
case DeclRefExprClass:
@@ -2883,21 +2929,27 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
return false;
case CallExprClass:
+ case CXXOperatorCallExprClass:
+ case CXXMemberCallExprClass:
+ case CUDAKernelCallExprClass:
+ case BlockExprClass:
+ case CXXBindTemporaryExprClass:
+ case UserDefinedLiteralClass:
+ // We don't know a call definitely has side effects, but we can check the
+ // call's operands.
+ if (!IncludePossibleEffects)
+ break;
+ return true;
+
case MSPropertyRefExprClass:
case CompoundAssignOperatorClass:
case VAArgExprClass:
case AtomicExprClass:
case StmtExprClass:
- case CXXOperatorCallExprClass:
- case CXXMemberCallExprClass:
- case UserDefinedLiteralClass:
case CXXThrowExprClass:
case CXXNewExprClass:
case CXXDeleteExprClass:
case ExprWithCleanupsClass:
- case CXXBindTemporaryExprClass:
- case BlockExprClass:
- case CUDAKernelCallExprClass:
// These always have a side-effect.
return true;
@@ -2933,25 +2985,29 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case InitListExprClass:
// FIXME: The children for an InitListExpr doesn't include the array filler.
if (const Expr *E = cast<InitListExpr>(this)->getArrayFiller())
- if (E->HasSideEffects(Ctx))
+ if (E->HasSideEffects(Ctx, IncludePossibleEffects))
return true;
break;
case GenericSelectionExprClass:
return cast<GenericSelectionExpr>(this)->getResultExpr()->
- HasSideEffects(Ctx);
+ HasSideEffects(Ctx, IncludePossibleEffects);
case ChooseExprClass:
- return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects(Ctx);
+ return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects(
+ Ctx, IncludePossibleEffects);
case CXXDefaultArgExprClass:
- return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx);
+ return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(
+ Ctx, IncludePossibleEffects);
- case CXXDefaultInitExprClass:
- if (const Expr *E = cast<CXXDefaultInitExpr>(this)->getExpr())
- return E->HasSideEffects(Ctx);
+ case CXXDefaultInitExprClass: {
+ const FieldDecl *FD = cast<CXXDefaultInitExpr>(this)->getField();
+ if (const Expr *E = FD->getInClassInitializer())
+ return E->HasSideEffects(Ctx, IncludePossibleEffects);
// If we've not yet parsed the initializer, assume it has side-effects.
return true;
+ }
case CXXDynamicCastExprClass: {
// A dynamic_cast expression has side-effects if it can throw.
@@ -2966,6 +3022,13 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case CXXReinterpretCastExprClass:
case CXXConstCastExprClass:
case CXXFunctionalCastExprClass: {
+ // While volatile reads are side-effecting in both C and C++, we treat them
+ // as having possible (not definite) side-effects. This allows idiomatic
+ // code to behave without warning, such as sizeof(*v) for a volatile-
+ // qualified pointer.
+ if (!IncludePossibleEffects)
+ break;
+
const CastExpr *CE = cast<CastExpr>(this);
if (CE->getCastKind() == CK_LValueToRValue &&
CE->getSubExpr()->getType().isVolatileQualified())
@@ -2981,7 +3044,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case CXXConstructExprClass:
case CXXTemporaryObjectExprClass: {
const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
- if (!CE->getConstructor()->isTrivial())
+ if (!CE->getConstructor()->isTrivial() && IncludePossibleEffects)
return true;
// A trivial constructor does not add any side-effects of its own. Just look
// at its arguments.
@@ -3009,7 +3072,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
const Expr *Subexpr = *I;
if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Subexpr))
Subexpr = OVE->getSourceExpr();
- if (Subexpr->HasSideEffects(Ctx))
+ if (Subexpr->HasSideEffects(Ctx, IncludePossibleEffects))
return true;
}
return false;
@@ -3018,22 +3081,24 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case ObjCBoxedExprClass:
case ObjCArrayLiteralClass:
case ObjCDictionaryLiteralClass:
- case ObjCMessageExprClass:
case ObjCSelectorExprClass:
case ObjCProtocolExprClass:
- case ObjCPropertyRefExprClass:
case ObjCIsaExprClass:
case ObjCIndirectCopyRestoreExprClass:
case ObjCSubscriptRefExprClass:
case ObjCBridgedCastExprClass:
- // FIXME: Classify these cases better.
- return true;
+ case ObjCMessageExprClass:
+ case ObjCPropertyRefExprClass:
+ // FIXME: Classify these cases better.
+ if (IncludePossibleEffects)
+ return true;
+ break;
}
// Recurse to children.
for (const_child_range SubStmts = children(); SubStmts; ++SubStmts)
if (const Stmt *S = *SubStmts)
- if (cast<Expr>(S)->HasSideEffects(Ctx))
+ if (cast<Expr>(S)->HasSideEffects(Ctx, IncludePossibleEffects))
return true;
return false;
@@ -3279,6 +3344,10 @@ FieldDecl *Expr::getSourceBitField() {
return BinOp->getRHS()->getSourceBitField();
}
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E))
+ if (UnOp->isPrefix() && UnOp->isIncrementDecrementOp())
+ return UnOp->getSubExpr()->getSourceBitField();
+
return nullptr;
}
@@ -3759,7 +3828,7 @@ DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty,
// Compute type- and value-dependence.
Expr *Index = IndexExprs[IndexIdx];
if (Index->isTypeDependent() || Index->isValueDependent())
- ExprBits.ValueDependent = true;
+ ExprBits.TypeDependent = ExprBits.ValueDependent = true;
if (Index->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
// Propagate unexpanded parameter packs.
@@ -3774,7 +3843,7 @@ DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty,
Expr *End = IndexExprs[IndexIdx + 1];
if (Start->isTypeDependent() || Start->isValueDependent() ||
End->isTypeDependent() || End->isValueDependent()) {
- ExprBits.ValueDependent = true;
+ ExprBits.TypeDependent = ExprBits.ValueDependent = true;
ExprBits.InstantiationDependent = true;
} else if (Start->isInstantiationDependent() ||
End->isInstantiationDependent()) {
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 64c21dd5c4fd..93361666183b 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -909,16 +909,21 @@ LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit,
case LCK_ByRef:
assert(Var && "capture must have a variable!");
break;
+ case LCK_VLAType:
+ assert(!Var && "VLA type capture cannot have a variable!");
+ Bits |= Capture_ByCopy;
+ break;
}
DeclAndBits.setInt(Bits);
}
LambdaCaptureKind LambdaCapture::getCaptureKind() const {
Decl *D = DeclAndBits.getPointer();
+ bool CapByCopy = DeclAndBits.getInt() & Capture_ByCopy;
if (!D)
- return LCK_This;
+ return CapByCopy ? LCK_VLAType : LCK_This;
- return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef;
+ return CapByCopy ? LCK_ByCopy : LCK_ByRef;
}
LambdaExpr::LambdaExpr(QualType T,
@@ -1073,8 +1078,8 @@ LambdaExpr::getCaptureInitIndexVars(capture_init_iterator Iter) const {
"Capture index out-of-range");
VarDecl **IndexVars = getArrayIndexVars();
unsigned *IndexStarts = getArrayIndexStarts();
- return ArrayRef<VarDecl *>(IndexVars + IndexStarts[Index],
- IndexVars + IndexStarts[Index + 1]);
+ return llvm::makeArrayRef(IndexVars + IndexStarts[Index],
+ IndexVars + IndexStarts[Index + 1]);
}
CXXRecordDecl *LambdaExpr::getLambdaClass() const {
@@ -1399,7 +1404,8 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
// It can't be dependent: after all, we were actually able to do the
// lookup.
CXXRecordDecl *Record = nullptr;
- if (getQualifier()) {
+ auto *NNS = getQualifier();
+ if (NNS && NNS->getKind() != NestedNameSpecifier::Super) {
const Type *T = getQualifier()->getAsType();
assert(T && "qualifier in member expression does not name type");
Record = T->getAsCXXRecordDecl();
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index d3d25308a386..933ea97fa2ba 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -124,10 +124,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ObjCPropertyRefExprClass:
// C++ [expr.typeid]p1: The result of a typeid expression is an lvalue of...
case Expr::CXXTypeidExprClass:
- // Unresolved lookups get classified as lvalues.
+ // Unresolved lookups and uncorrected typos get classified as lvalues.
// FIXME: Is this wise? Should they get their own kind?
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
+ case Expr::TypoExprClass:
case Expr::CXXDependentScopeMemberExprClass:
case Expr::DependentScopeDeclRefExprClass:
// ObjC instance variables are lvalues
@@ -181,6 +182,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::AtomicExprClass:
+ case Expr::CXXFoldExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
@@ -613,14 +615,9 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
return Cl::CM_IncompleteType;
// Records with any const fields (recursively) are not modifiable.
- if (const RecordType *R = CT->getAs<RecordType>()) {
- assert((E->getObjectKind() == OK_ObjCProperty ||
- !Ctx.getLangOpts().CPlusPlus) &&
- "C++ struct assignment should be resolved by the "
- "copy assignment operator.");
+ if (const RecordType *R = CT->getAs<RecordType>())
if (R->hasConstFields())
return Cl::CM_ConstQualified;
- }
return Cl::CM_Modifiable;
}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 7d7ca9924c85..3d7f2dca7a2f 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -201,6 +201,7 @@ namespace {
/// Determine whether this is a one-past-the-end pointer.
bool isOnePastTheEnd() const {
+ assert(!Invalid);
if (IsOnePastTheEnd)
return true;
if (MostDerivedArraySize &&
@@ -1308,7 +1309,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
}
// Does this refer one past the end of some object?
- if (Designator.isOnePastTheEnd()) {
+ if (!Designator.Invalid && Designator.isOnePastTheEnd()) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
Info.Diag(Loc, diag::note_constexpr_past_end, 1)
<< !Designator.Entries.empty() << !!VD << VD;
@@ -1328,7 +1329,7 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
// C++1y: A constant initializer for an object o [...] may also invoke
// constexpr constructors for o and its subobjects even if those objects
// are of non-literal class types.
- if (Info.getLangOpts().CPlusPlus1y && This &&
+ if (Info.getLangOpts().CPlusPlus14 && This &&
Info.EvaluatingDecl == This->getLValueBase())
return true;
@@ -1421,6 +1422,17 @@ static bool IsWeakLValue(const LValue &Value) {
return Decl && Decl->isWeak();
}
+static bool isZeroSized(const LValue &Value) {
+ const ValueDecl *Decl = GetLValueBaseDecl(Value);
+ if (Decl && isa<VarDecl>(Decl)) {
+ QualType Ty = Decl->getType();
+ if (Ty->isArrayType())
+ return Ty->isIncompleteType() ||
+ Decl->getASTContext().getTypeSize(Ty) == 0;
+ }
+ return false;
+}
+
static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
// A null base expression indicates a null pointer. These are always
// evaluatable, and they are false unless the offset is zero.
@@ -2020,7 +2032,9 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
/// Extract the value of a character from a string literal.
static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
uint64_t Index) {
- // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
+ // FIXME: Support ObjCEncodeExpr, MakeStringConstant
+ if (auto PE = dyn_cast<PredefinedExpr>(Lit))
+ Lit = PE->getFunctionName();
const StringLiteral *S = cast<StringLiteral>(Lit);
const ConstantArrayType *CAT =
Info.Ctx.getAsConstantArrayType(S->getType());
@@ -2079,6 +2093,64 @@ static void expandArray(APValue &Array, unsigned Index) {
Array.swap(NewValue);
}
+/// Determine whether a type would actually be read by an lvalue-to-rvalue
+/// conversion. If it's of class type, we may assume that the copy operation
+/// is trivial. Note that this is never true for a union type with fields
+/// (because the copy always "reads" the active member) and always true for
+/// a non-class type.
+static bool isReadByLvalueToRvalueConversion(QualType T) {
+ CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (!RD || (RD->isUnion() && !RD->field_empty()))
+ return true;
+ if (RD->isEmpty())
+ return false;
+
+ for (auto *Field : RD->fields())
+ if (isReadByLvalueToRvalueConversion(Field->getType()))
+ return true;
+
+ for (auto &BaseSpec : RD->bases())
+ if (isReadByLvalueToRvalueConversion(BaseSpec.getType()))
+ return true;
+
+ return false;
+}
+
+/// Diagnose an attempt to read from any unreadable field within the specified
+/// type, which might be a class type.
+static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
+ QualType T) {
+ CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+
+ if (!RD->hasMutableFields())
+ return false;
+
+ for (auto *Field : RD->fields()) {
+ // If we're actually going to read this field in some way, then it can't
+ // be mutable. If we're in a union, then assigning to a mutable field
+ // (even an empty one) can change the active member, so that's not OK.
+ // FIXME: Add core issue number for the union case.
+ if (Field->isMutable() &&
+ (RD->isUnion() || isReadByLvalueToRvalueConversion(Field->getType()))) {
+ Info.Diag(E, diag::note_constexpr_ltor_mutable, 1) << Field;
+ Info.Note(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
+ if (diagnoseUnreadableFields(Info, E, Field->getType()))
+ return true;
+ }
+
+ for (auto &BaseSpec : RD->bases())
+ if (diagnoseUnreadableFields(Info, E, BaseSpec.getType()))
+ return true;
+
+ // All mutable fields were empty, and thus not actually read.
+ return false;
+}
+
/// Kinds of access we can perform on an object, for diagnostics.
enum AccessKinds {
AK_Read,
@@ -2134,6 +2206,14 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
}
if (I == N) {
+ // If we are reading an object of class type, there may still be more
+ // things we need to check: if there are any mutable subobjects, we
+ // cannot perform this read. (This only happens when performing a trivial
+ // copy or assignment.)
+ if (ObjType->isRecordType() && handler.AccessKind == AK_Read &&
+ diagnoseUnreadableFields(Info, E, ObjType))
+ return handler.failed();
+
if (!handler.found(*O, ObjType))
return false;
@@ -2490,7 +2570,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
// Unless we're looking at a local variable or argument in a constexpr call,
// the variable we're reading must be const.
if (!Frame) {
- if (Info.getLangOpts().CPlusPlus1y &&
+ if (Info.getLangOpts().CPlusPlus14 &&
VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) {
// OK, we can read and modify an object if we're in the process of
// evaluating its initializer, because its lifetime began in this
@@ -2606,7 +2686,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
//
// FIXME: Not all local state is mutable. Allow local constant subobjects
// to be read here (but take care with 'mutable' fields).
- if (Frame && Info.getLangOpts().CPlusPlus1y &&
+ if (Frame && Info.getLangOpts().CPlusPlus14 &&
(Info.EvalStatus.HasSideEffects || Info.keepEvaluatingAfterFailure()))
return CompleteObject();
@@ -2648,10 +2728,10 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
return false;
CompleteObject LitObj(&Lit, Base->getType());
return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal);
- } else if (isa<StringLiteral>(Base)) {
+ } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {
// We represent a string literal array as an lvalue pointing at the
// corresponding expression, rather than building an array of chars.
- // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
+ // FIXME: Support ObjCEncodeExpr, MakeStringConstant
APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0);
CompleteObject StrObj(&Str, Base->getType());
return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal);
@@ -2668,7 +2748,7 @@ static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal,
if (LVal.Designator.Invalid)
return false;
- if (!Info.getLangOpts().CPlusPlus1y) {
+ if (!Info.getLangOpts().CPlusPlus14) {
Info.Diag(E);
return false;
}
@@ -2789,7 +2869,7 @@ static bool handleCompoundAssignment(
if (LVal.Designator.Invalid)
return false;
- if (!Info.getLangOpts().CPlusPlus1y) {
+ if (!Info.getLangOpts().CPlusPlus14) {
Info.Diag(E);
return false;
}
@@ -2938,7 +3018,7 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal,
if (LVal.Designator.Invalid)
return false;
- if (!Info.getLangOpts().CPlusPlus1y) {
+ if (!Info.getLangOpts().CPlusPlus14) {
Info.Diag(E);
return false;
}
@@ -3588,6 +3668,22 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
return false;
}
+/// Determine if a class has any fields that might need to be copied by a
+/// trivial copy or move operation.
+static bool hasFields(const CXXRecordDecl *RD) {
+ if (!RD || RD->isEmpty())
+ return false;
+ for (auto *FD : RD->fields()) {
+ if (FD->isUnnamedBitfield())
+ continue;
+ return true;
+ }
+ for (auto &Base : RD->bases())
+ if (hasFields(Base.getType()->getAsCXXRecordDecl()))
+ return true;
+ return false;
+}
+
namespace {
typedef SmallVector<APValue, 8> ArgVector;
}
@@ -3626,8 +3722,12 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
// For a trivial copy or move assignment, perform an APValue copy. This is
// essential for unions, where the operations performed by the assignment
// operator cannot be represented as statements.
+ //
+ // Skip this for non-union classes with no fields; in that case, the defaulted
+ // copy/move does not actually read the object.
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee);
- if (MD && MD->isDefaulted() && MD->isTrivial()) {
+ if (MD && MD->isDefaulted() && MD->isTrivial() &&
+ (MD->getParent()->isUnion() || hasFields(MD->getParent()))) {
assert(This &&
(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
LValue RHS;
@@ -3684,11 +3784,18 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
}
// For a trivial copy or move constructor, perform an APValue copy. This is
- // essential for unions, where the operations performed by the constructor
- // cannot be represented by ctor-initializers.
+ // essential for unions (or classes with anonymous union members), where the
+ // operations performed by the constructor cannot be represented by
+ // ctor-initializers.
+ //
+ // Skip this for empty non-union classes; we should not perform an
+ // lvalue-to-rvalue conversion on them because their copy constructor does not
+ // actually read them.
if (Definition->isDefaulted() &&
((Definition->isCopyConstructor() && Definition->isTrivial()) ||
- (Definition->isMoveConstructor() && Definition->isTrivial()))) {
+ (Definition->isMoveConstructor() && Definition->isTrivial())) &&
+ (Definition->getParent()->isUnion() ||
+ hasFields(Definition->getParent()))) {
LValue RHS;
RHS.setFrom(Info.Ctx, ArgValues[0]);
return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
@@ -3985,7 +4092,7 @@ public:
const FunctionDecl *FD = nullptr;
LValue *This = nullptr, ThisVal;
- ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
+ auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
bool HasQualifier = false;
// Extract function decl and 'this' pointer from the callee.
@@ -4148,7 +4255,7 @@ public:
return VisitUnaryPostIncDec(UO);
}
bool VisitUnaryPostIncDec(const UnaryOperator *UO) {
- if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure())
+ if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure())
return Error(UO);
LValue LVal;
@@ -4573,7 +4680,7 @@ bool LValueExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
}
bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) {
- if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure())
+ if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure())
return Error(UO);
if (!this->Visit(UO->getSubExpr()))
@@ -4586,7 +4693,7 @@ bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) {
bool LValueExprEvaluator::VisitCompoundAssignOperator(
const CompoundAssignOperator *CAO) {
- if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure())
+ if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure())
return Error(CAO);
APValue RHS;
@@ -4608,7 +4715,7 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator(
}
bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
- if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure())
+ if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure())
return Error(E);
APValue NewVal;
@@ -4733,6 +4840,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
+ case CK_AddressSpaceConversion:
if (!Visit(SubExpr))
return false;
// Bitcasts to cv void* are static_casts, not reinterpret_casts, so are
@@ -4818,6 +4926,38 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return ExprEvaluatorBaseTy::VisitCastExpr(E);
}
+static CharUnits GetAlignOfType(EvalInfo &Info, QualType T) {
+ // C++ [expr.alignof]p3:
+ // When alignof is applied to a reference type, the result is the
+ // alignment of the referenced type.
+ if (const ReferenceType *Ref = T->getAs<ReferenceType>())
+ T = Ref->getPointeeType();
+
+ // __alignof is defined to return the preferred alignment.
+ return Info.Ctx.toCharUnitsFromBits(
+ Info.Ctx.getPreferredTypeAlign(T.getTypePtr()));
+}
+
+static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E) {
+ E = E->IgnoreParens();
+
+ // The kinds of expressions that we have special-case logic here for
+ // should be kept up to date with the special checks for those
+ // expressions in Sema.
+
+ // alignof decl is always accepted, even if it doesn't make sense: we default
+ // to 1 in those cases.
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ return Info.Ctx.getDeclAlign(DRE->getDecl(),
+ /*RefAsPointee*/true);
+
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ return Info.Ctx.getDeclAlign(ME->getMemberDecl(),
+ /*RefAsPointee*/true);
+
+ return GetAlignOfType(Info, E->getType());
+}
+
bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (IsStringLiteralCall(E))
return Success(E);
@@ -4825,7 +4965,71 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_addressof:
return EvaluateLValue(E->getArg(0), Result, Info);
+ case Builtin::BI__builtin_assume_aligned: {
+ // We need to be very careful here because: if the pointer does not have the
+ // asserted alignment, then the behavior is undefined, and undefined
+ // behavior is non-constant.
+ if (!EvaluatePointer(E->getArg(0), Result, Info))
+ return false;
+
+ LValue OffsetResult(Result);
+ APSInt Alignment;
+ if (!EvaluateInteger(E->getArg(1), Alignment, Info))
+ return false;
+ CharUnits Align = CharUnits::fromQuantity(getExtValue(Alignment));
+
+ if (E->getNumArgs() > 2) {
+ APSInt Offset;
+ if (!EvaluateInteger(E->getArg(2), Offset, Info))
+ return false;
+
+ int64_t AdditionalOffset = -getExtValue(Offset);
+ OffsetResult.Offset += CharUnits::fromQuantity(AdditionalOffset);
+ }
+
+ // If there is a base object, then it must have the correct alignment.
+ if (OffsetResult.Base) {
+ CharUnits BaseAlignment;
+ if (const ValueDecl *VD =
+ OffsetResult.Base.dyn_cast<const ValueDecl*>()) {
+ BaseAlignment = Info.Ctx.getDeclAlign(VD);
+ } else {
+ BaseAlignment =
+ GetAlignOfExpr(Info, OffsetResult.Base.get<const Expr*>());
+ }
+
+ if (BaseAlignment < Align) {
+ Result.Designator.setInvalid();
+ // FIXME: Quantities here cast to integers because the plural modifier
+ // does not work on APSInts yet.
+ CCEDiag(E->getArg(0),
+ diag::note_constexpr_baa_insufficient_alignment) << 0
+ << (int) BaseAlignment.getQuantity()
+ << (unsigned) getExtValue(Alignment);
+ return false;
+ }
+ }
+
+ // The offset must also have the correct alignment.
+ if (OffsetResult.Offset.RoundUpToAlignment(Align) != OffsetResult.Offset) {
+ Result.Designator.setInvalid();
+ APSInt Offset(64, false);
+ Offset = OffsetResult.Offset.getQuantity();
+ if (OffsetResult.Base)
+ CCEDiag(E->getArg(0),
+ diag::note_constexpr_baa_insufficient_alignment) << 1
+ << (int) getExtValue(Offset) << (unsigned) getExtValue(Alignment);
+ else
+ CCEDiag(E->getArg(0),
+ diag::note_constexpr_baa_value_insufficient_alignment)
+ << Offset << (unsigned) getExtValue(Alignment);
+
+ return false;
+ }
+
+ return true;
+ }
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
@@ -5166,7 +5370,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (ZeroInit && !ZeroInitialization(E))
return false;
- ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
+ auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), This, Args,
cast<CXXConstructorDecl>(Definition), Info,
Result);
@@ -5270,6 +5474,9 @@ public:
bool VisitCallExpr(const CallExpr *E) {
return VisitConstructExpr(E);
}
+ bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E) {
+ return VisitConstructExpr(E);
+ }
};
} // end anonymous namespace
@@ -5645,7 +5852,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
return false;
}
- ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
+ auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), Subobject, Args,
cast<CXXConstructorDecl>(Definition),
Info, *Value);
@@ -5786,8 +5993,6 @@ public:
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
private:
- CharUnits GetAlignOfExpr(const Expr *E);
- CharUnits GetAlignOfType(QualType T);
static QualType GetObjectType(APValue::LValueBase B);
bool TryEvaluateBuiltinObjectSize(const CallExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
@@ -5985,8 +6190,20 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) {
return false;
}
- // If we can prove the base is null, lower to zero now.
- if (!Base.getLValueBase()) return Success(0, E);
+ if (!Base.getLValueBase()) {
+ // It is not possible to determine which objects ptr points to at compile time,
+ // __builtin_object_size should return (size_t) -1 for type 0 or 1
+ // and (size_t) 0 for type 2 or 3.
+ llvm::APSInt TypeIntVaue;
+ const Expr *ExprType = E->getArg(1);
+ if (!ExprType->EvaluateAsInt(TypeIntVaue, Info.Ctx))
+ return false;
+ if (TypeIntVaue == 0 || TypeIntVaue == 1)
+ return Success(-1, E);
+ if (TypeIntVaue == 2 || TypeIntVaue == 3)
+ return Success(0, E);
+ return Error(E);
+ }
QualType T = GetObjectType(Base.getLValueBase());
if (T.isNull() ||
@@ -6286,6 +6503,27 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
A.getLValueCallIndex() == B.getLValueCallIndex();
}
+/// \brief Determine whether this is a pointer past the end of the complete
+/// object referred to by the lvalue.
+static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx,
+ const LValue &LV) {
+ // A null pointer can be viewed as being "past the end" but we don't
+ // choose to look at it that way here.
+ if (!LV.getLValueBase())
+ return false;
+
+ // If the designator is valid and refers to a subobject, we're not pointing
+ // past the end.
+ if (!LV.getLValueDesignator().Invalid &&
+ !LV.getLValueDesignator().isOnePastTheEnd())
+ return false;
+
+ // We're a past-the-end pointer if we point to the byte after the object,
+ // no matter what our type or path is.
+ auto Size = Ctx.getTypeSizeInChars(getType(LV.getLValueBase()));
+ return LV.getLValueOffset() == Size;
+}
+
namespace {
/// \brief Data recursive integer evaluator of certain binary operators.
@@ -6605,15 +6843,27 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
QualType LHSTy = E->getLHS()->getType();
QualType RHSTy = E->getRHS()->getType();
- if (LHSTy->isAnyComplexType()) {
- assert(RHSTy->isAnyComplexType() && "Invalid comparison");
+ if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) {
ComplexValue LHS, RHS;
-
- bool LHSOK = EvaluateComplex(E->getLHS(), LHS, Info);
+ bool LHSOK;
+ if (E->getLHS()->getType()->isRealFloatingType()) {
+ LHSOK = EvaluateFloat(E->getLHS(), LHS.FloatReal, Info);
+ if (LHSOK) {
+ LHS.makeComplexFloat();
+ LHS.FloatImag = APFloat(LHS.FloatReal.getSemantics());
+ }
+ } else {
+ LHSOK = EvaluateComplex(E->getLHS(), LHS, Info);
+ }
if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
- if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
+ if (E->getRHS()->getType()->isRealFloatingType()) {
+ if (!EvaluateFloat(E->getRHS(), RHS.FloatReal, Info) || !LHSOK)
+ return false;
+ RHS.makeComplexFloat();
+ RHS.FloatImag = APFloat(RHS.FloatReal.getSemantics());
+ } else if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
return false;
if (LHS.isComplexFloat()) {
@@ -6736,6 +6986,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
// object.
if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue))
return Error(E);
+ // We can't compare the address of the start of one object with the
+ // past-the-end address of another object, per C++ DR1652.
+ if ((LHSValue.Base && LHSValue.Offset.isZero() &&
+ isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) ||
+ (RHSValue.Base && RHSValue.Offset.isZero() &&
+ isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue)))
+ return Error(E);
+ // We can't tell whether an object is at the same address as another
+ // zero sized object.
+ if ((RHSValue.Base && isZeroSized(LHSValue)) ||
+ (LHSValue.Base && isZeroSized(RHSValue)))
+ return Error(E);
// Pointers with different bases cannot represent the same object.
// (Note that clang defaults to -fmerge-all-constants, which can
// lead to inconsistent results for comparisons involving the address
@@ -6940,39 +7202,6 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
}
-CharUnits IntExprEvaluator::GetAlignOfType(QualType T) {
- // C++ [expr.alignof]p3:
- // When alignof is applied to a reference type, the result is the
- // alignment of the referenced type.
- if (const ReferenceType *Ref = T->getAs<ReferenceType>())
- T = Ref->getPointeeType();
-
- // __alignof is defined to return the preferred alignment.
- return Info.Ctx.toCharUnitsFromBits(
- Info.Ctx.getPreferredTypeAlign(T.getTypePtr()));
-}
-
-CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
- E = E->IgnoreParens();
-
- // The kinds of expressions that we have special-case logic here for
- // should be kept up to date with the special checks for those
- // expressions in Sema.
-
- // alignof decl is always accepted, even if it doesn't make sense: we default
- // to 1 in those cases.
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return Info.Ctx.getDeclAlign(DRE->getDecl(),
- /*RefAsPointee*/true);
-
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
- return Info.Ctx.getDeclAlign(ME->getMemberDecl(),
- /*RefAsPointee*/true);
-
- return GetAlignOfType(E->getType());
-}
-
-
/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with
/// a result as the expression's type.
bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
@@ -6980,9 +7209,9 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
switch(E->getKind()) {
case UETT_AlignOf: {
if (E->isArgumentType())
- return Success(GetAlignOfType(E->getArgumentType()), E);
+ return Success(GetAlignOfType(Info, E->getArgumentType()), E);
else
- return Success(GetAlignOfExpr(E->getArgumentExpr()), E);
+ return Success(GetAlignOfExpr(Info, E->getArgumentExpr()), E);
}
case UETT_VecStep: {
@@ -7732,24 +7961,49 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma)
return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
- bool LHSOK = Visit(E->getLHS());
+ // Track whether the LHS or RHS is real at the type system level. When this is
+ // the case we can simplify our evaluation strategy.
+ bool LHSReal = false, RHSReal = false;
+
+ bool LHSOK;
+ if (E->getLHS()->getType()->isRealFloatingType()) {
+ LHSReal = true;
+ APFloat &Real = Result.FloatReal;
+ LHSOK = EvaluateFloat(E->getLHS(), Real, Info);
+ if (LHSOK) {
+ Result.makeComplexFloat();
+ Result.FloatImag = APFloat(Real.getSemantics());
+ }
+ } else {
+ LHSOK = Visit(E->getLHS());
+ }
if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
ComplexValue RHS;
- if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
+ if (E->getRHS()->getType()->isRealFloatingType()) {
+ RHSReal = true;
+ APFloat &Real = RHS.FloatReal;
+ if (!EvaluateFloat(E->getRHS(), Real, Info) || !LHSOK)
+ return false;
+ RHS.makeComplexFloat();
+ RHS.FloatImag = APFloat(Real.getSemantics());
+ } else if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
return false;
- assert(Result.isComplexFloat() == RHS.isComplexFloat() &&
- "Invalid operands to binary operator.");
+ assert(!(LHSReal && RHSReal) &&
+ "Cannot have both operands of a complex operation be real.");
switch (E->getOpcode()) {
default: return Error(E);
case BO_Add:
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().add(RHS.getComplexFloatReal(),
APFloat::rmNearestTiesToEven);
- Result.getComplexFloatImag().add(RHS.getComplexFloatImag(),
- APFloat::rmNearestTiesToEven);
+ if (LHSReal)
+ Result.getComplexFloatImag() = RHS.getComplexFloatImag();
+ else if (!RHSReal)
+ Result.getComplexFloatImag().add(RHS.getComplexFloatImag(),
+ APFloat::rmNearestTiesToEven);
} else {
Result.getComplexIntReal() += RHS.getComplexIntReal();
Result.getComplexIntImag() += RHS.getComplexIntImag();
@@ -7759,8 +8013,13 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().subtract(RHS.getComplexFloatReal(),
APFloat::rmNearestTiesToEven);
- Result.getComplexFloatImag().subtract(RHS.getComplexFloatImag(),
- APFloat::rmNearestTiesToEven);
+ if (LHSReal) {
+ Result.getComplexFloatImag() = RHS.getComplexFloatImag();
+ Result.getComplexFloatImag().changeSign();
+ } else if (!RHSReal) {
+ Result.getComplexFloatImag().subtract(RHS.getComplexFloatImag(),
+ APFloat::rmNearestTiesToEven);
+ }
} else {
Result.getComplexIntReal() -= RHS.getComplexIntReal();
Result.getComplexIntImag() -= RHS.getComplexIntImag();
@@ -7768,25 +8027,75 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
break;
case BO_Mul:
if (Result.isComplexFloat()) {
+ // This is an implementation of complex multiplication according to the
+ // constraints laid out in C11 Annex G. The implemantion uses the
+ // following naming scheme:
+ // (a + ib) * (c + id)
ComplexValue LHS = Result;
- APFloat &LHS_r = LHS.getComplexFloatReal();
- APFloat &LHS_i = LHS.getComplexFloatImag();
- APFloat &RHS_r = RHS.getComplexFloatReal();
- APFloat &RHS_i = RHS.getComplexFloatImag();
-
- APFloat Tmp = LHS_r;
- Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven);
- Result.getComplexFloatReal() = Tmp;
- Tmp = LHS_i;
- Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
- Result.getComplexFloatReal().subtract(Tmp, APFloat::rmNearestTiesToEven);
-
- Tmp = LHS_r;
- Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
- Result.getComplexFloatImag() = Tmp;
- Tmp = LHS_i;
- Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven);
- Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven);
+ APFloat &A = LHS.getComplexFloatReal();
+ APFloat &B = LHS.getComplexFloatImag();
+ APFloat &C = RHS.getComplexFloatReal();
+ APFloat &D = RHS.getComplexFloatImag();
+ APFloat &ResR = Result.getComplexFloatReal();
+ APFloat &ResI = Result.getComplexFloatImag();
+ if (LHSReal) {
+ assert(!RHSReal && "Cannot have two real operands for a complex op!");
+ ResR = A * C;
+ ResI = A * D;
+ } else if (RHSReal) {
+ ResR = C * A;
+ ResI = C * B;
+ } else {
+ // In the fully general case, we need to handle NaNs and infinities
+ // robustly.
+ APFloat AC = A * C;
+ APFloat BD = B * D;
+ APFloat AD = A * D;
+ APFloat BC = B * C;
+ ResR = AC - BD;
+ ResI = AD + BC;
+ if (ResR.isNaN() && ResI.isNaN()) {
+ bool Recalc = false;
+ if (A.isInfinity() || B.isInfinity()) {
+ A = APFloat::copySign(
+ APFloat(A.getSemantics(), A.isInfinity() ? 1 : 0), A);
+ B = APFloat::copySign(
+ APFloat(B.getSemantics(), B.isInfinity() ? 1 : 0), B);
+ if (C.isNaN())
+ C = APFloat::copySign(APFloat(C.getSemantics()), C);
+ if (D.isNaN())
+ D = APFloat::copySign(APFloat(D.getSemantics()), D);
+ Recalc = true;
+ }
+ if (C.isInfinity() || D.isInfinity()) {
+ C = APFloat::copySign(
+ APFloat(C.getSemantics(), C.isInfinity() ? 1 : 0), C);
+ D = APFloat::copySign(
+ APFloat(D.getSemantics(), D.isInfinity() ? 1 : 0), D);
+ if (A.isNaN())
+ A = APFloat::copySign(APFloat(A.getSemantics()), A);
+ if (B.isNaN())
+ B = APFloat::copySign(APFloat(B.getSemantics()), B);
+ Recalc = true;
+ }
+ if (!Recalc && (AC.isInfinity() || BD.isInfinity() ||
+ AD.isInfinity() || BC.isInfinity())) {
+ if (A.isNaN())
+ A = APFloat::copySign(APFloat(A.getSemantics()), A);
+ if (B.isNaN())
+ B = APFloat::copySign(APFloat(B.getSemantics()), B);
+ if (C.isNaN())
+ C = APFloat::copySign(APFloat(C.getSemantics()), C);
+ if (D.isNaN())
+ D = APFloat::copySign(APFloat(D.getSemantics()), D);
+ Recalc = true;
+ }
+ if (Recalc) {
+ ResR = APFloat::getInf(A.getSemantics()) * (A * C - B * D);
+ ResI = APFloat::getInf(A.getSemantics()) * (A * D + B * C);
+ }
+ }
+ }
} else {
ComplexValue LHS = Result;
Result.getComplexIntReal() =
@@ -7799,33 +8108,57 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
break;
case BO_Div:
if (Result.isComplexFloat()) {
+ // This is an implementation of complex division according to the
+ // constraints laid out in C11 Annex G. The implemantion uses the
+ // following naming scheme:
+ // (a + ib) / (c + id)
ComplexValue LHS = Result;
- APFloat &LHS_r = LHS.getComplexFloatReal();
- APFloat &LHS_i = LHS.getComplexFloatImag();
- APFloat &RHS_r = RHS.getComplexFloatReal();
- APFloat &RHS_i = RHS.getComplexFloatImag();
- APFloat &Res_r = Result.getComplexFloatReal();
- APFloat &Res_i = Result.getComplexFloatImag();
-
- APFloat Den = RHS_r;
- Den.multiply(RHS_r, APFloat::rmNearestTiesToEven);
- APFloat Tmp = RHS_i;
- Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
- Den.add(Tmp, APFloat::rmNearestTiesToEven);
-
- Res_r = LHS_r;
- Res_r.multiply(RHS_r, APFloat::rmNearestTiesToEven);
- Tmp = LHS_i;
- Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
- Res_r.add(Tmp, APFloat::rmNearestTiesToEven);
- Res_r.divide(Den, APFloat::rmNearestTiesToEven);
-
- Res_i = LHS_i;
- Res_i.multiply(RHS_r, APFloat::rmNearestTiesToEven);
- Tmp = LHS_r;
- Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
- Res_i.subtract(Tmp, APFloat::rmNearestTiesToEven);
- Res_i.divide(Den, APFloat::rmNearestTiesToEven);
+ APFloat &A = LHS.getComplexFloatReal();
+ APFloat &B = LHS.getComplexFloatImag();
+ APFloat &C = RHS.getComplexFloatReal();
+ APFloat &D = RHS.getComplexFloatImag();
+ APFloat &ResR = Result.getComplexFloatReal();
+ APFloat &ResI = Result.getComplexFloatImag();
+ if (RHSReal) {
+ ResR = A / C;
+ ResI = B / C;
+ } else {
+ if (LHSReal) {
+ // No real optimizations we can do here, stub out with zero.
+ B = APFloat::getZero(A.getSemantics());
+ }
+ int DenomLogB = 0;
+ APFloat MaxCD = maxnum(abs(C), abs(D));
+ if (MaxCD.isFinite()) {
+ DenomLogB = ilogb(MaxCD);
+ C = scalbn(C, -DenomLogB);
+ D = scalbn(D, -DenomLogB);
+ }
+ APFloat Denom = C * C + D * D;
+ ResR = scalbn((A * C + B * D) / Denom, -DenomLogB);
+ ResI = scalbn((B * C - A * D) / Denom, -DenomLogB);
+ if (ResR.isNaN() && ResI.isNaN()) {
+ if (Denom.isPosZero() && (!A.isNaN() || !B.isNaN())) {
+ ResR = APFloat::getInf(ResR.getSemantics(), C.isNegative()) * A;
+ ResI = APFloat::getInf(ResR.getSemantics(), C.isNegative()) * B;
+ } else if ((A.isInfinity() || B.isInfinity()) && C.isFinite() &&
+ D.isFinite()) {
+ A = APFloat::copySign(
+ APFloat(A.getSemantics(), A.isInfinity() ? 1 : 0), A);
+ B = APFloat::copySign(
+ APFloat(B.getSemantics(), B.isInfinity() ? 1 : 0), B);
+ ResR = APFloat::getInf(ResR.getSemantics()) * (A * C + B * D);
+ ResI = APFloat::getInf(ResI.getSemantics()) * (B * C - A * D);
+ } else if (MaxCD.isInfinity() && A.isFinite() && B.isFinite()) {
+ C = APFloat::copySign(
+ APFloat(C.getSemantics(), C.isInfinity() ? 1 : 0), C);
+ D = APFloat::copySign(
+ APFloat(D.getSemantics(), D.isInfinity() ? 1 : 0), D);
+ ResR = APFloat::getZero(ResR.getSemantics()) * (A * C + B * D);
+ ResI = APFloat::getZero(ResI.getSemantics()) * (B * C - A * D);
+ }
+ }
+ }
} else {
if (RHS.getComplexIntReal() == 0 && RHS.getComplexIntImag() == 0)
return Error(E, diag::note_expr_divide_by_zero);
@@ -7966,6 +8299,7 @@ public:
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
case Builtin::BI__assume:
+ case Builtin::BI__builtin_assume:
// The argument is not evaluated!
return true;
}
@@ -8338,6 +8672,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::CXXDeleteExprClass:
case Expr::CXXPseudoDestructorExprClass:
case Expr::UnresolvedLookupExprClass:
+ case Expr::TypoExprClass:
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
case Expr::CXXStdInitializerListExprClass:
@@ -8373,6 +8708,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::PseudoObjectExprClass:
case Expr::AtomicExprClass:
case Expr::LambdaExprClass:
+ case Expr::CXXFoldExprClass:
return ICEDiag(IK_NotICE, E->getLocStart());
case Expr::InitListExprClass: {
@@ -8682,7 +9018,11 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
if (!E->isCXX11ConstantExpr(Ctx, &Result, Loc))
return false;
- assert(Result.isInt() && "pointer cast to int is not an ICE");
+ if (!Result.isInt()) {
+ if (Loc) *Loc = E->getExprLoc();
+ return false;
+ }
+
if (Value) *Value = Result.getInt();
return true;
}
@@ -8751,7 +9091,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
ArgVector ArgValues(Args.size());
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
- if (!Evaluate(ArgValues[I - Args.begin()], Info, *I))
+ if ((*I)->isValueDependent() ||
+ !Evaluate(ArgValues[I - Args.begin()], Info, *I))
// If evaluation fails, throw away the argument entirely.
ArgValues[I - Args.begin()] = APValue();
if (Info.EvalStatus.HasSideEffects)
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index b5f8c0f4bc87..378121c8e5b9 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -29,16 +29,64 @@ using namespace clang;
namespace {
+/// According to Itanium C++ ABI 5.1.2:
+/// the name of an anonymous union is considered to be
+/// the name of the first named data member found by a pre-order,
+/// depth-first, declaration-order walk of the data members of
+/// the anonymous union.
+/// If there is no such data member (i.e., if all of the data members
+/// in the union are unnamed), then there is no way for a program to
+/// refer to the anonymous union, and there is therefore no need to mangle its name.
+///
+/// Returns the name of anonymous union VarDecl or nullptr if it is not found.
+static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) {
+ const RecordType *RT = VD.getType()->getAs<RecordType>();
+ assert(RT && "type of VarDecl is expected to be RecordType.");
+ assert(RT->getDecl()->isUnion() && "RecordType is expected to be a union.");
+ if (const FieldDecl *FD = RT->getDecl()->findFirstNamedDataMember()) {
+ return FD->getIdentifier();
+ }
+
+ return nullptr;
+}
+
/// \brief Keeps track of the mangled names of lambda expressions and block
/// literals within a particular context.
class ItaniumNumberingContext : public MangleNumberingContext {
- llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers;
- llvm::DenseMap<IdentifierInfo*, unsigned> TagManglingNumbers;
+ llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
+ llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers;
+ llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers;
public:
+ unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
+ const FunctionProtoType *Proto =
+ CallOperator->getType()->getAs<FunctionProtoType>();
+ ASTContext &Context = CallOperator->getASTContext();
+
+ QualType Key =
+ Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(),
+ FunctionProtoType::ExtProtoInfo());
+ Key = Context.getCanonicalType(Key);
+ return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
+ }
+
+ unsigned getManglingNumber(const BlockDecl *BD) override {
+ const Type *Ty = nullptr;
+ return ++ManglingNumbers[Ty];
+ }
+
+ unsigned getStaticLocalNumber(const VarDecl *VD) override {
+ return 0;
+ }
+
/// Variable decls are numbered by identifier.
unsigned getManglingNumber(const VarDecl *VD, unsigned) override {
- return ++VarManglingNumbers[VD->getIdentifier()];
+ const IdentifierInfo *Identifier = VD->getIdentifier();
+ if (!Identifier) {
+ // VarDecl without an identifier represents an anonymous union declaration.
+ Identifier = findAnonymousUnionVarDeclName(*VD);
+ }
+ return ++VarManglingNumbers[Identifier];
}
unsigned getManglingNumber(const TagDecl *TD, unsigned) override {
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 977d6fca2c40..156ad646fa6d 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -117,7 +117,7 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy;
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
-
+
public:
explicit ItaniumMangleContextImpl(ASTContext &Context,
DiagnosticsEngine &Diags)
@@ -150,6 +150,8 @@ public:
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
raw_ostream &) override;
+ void mangleCXXCtorComdat(const CXXConstructorDecl *D, raw_ostream &) override;
+ void mangleCXXDtorComdat(const CXXDestructorDecl *D, raw_ostream &) override;
void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) override;
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
@@ -373,6 +375,7 @@ private:
NamedDecl *firstQualifierLookup,
DeclarationName name,
unsigned knownArity);
+ void mangleCastExpression(const Expr *E, StringRef CastEncoding);
void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
@@ -634,13 +637,11 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
return;
// <template-template-param> ::= <template-param>
- if (const TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND))
mangleTemplateParameter(TTP->getIndex());
- return;
- }
+ else
+ mangleUnscopedName(ND->getTemplatedDecl());
- mangleUnscopedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
@@ -811,6 +812,9 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
// We never want an 'E' here.
return;
+ case NestedNameSpecifier::Super:
+ llvm_unreachable("Can't mangle __super specifier");
+
case NestedNameSpecifier::Namespace:
if (qualifier->getPrefix())
mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
@@ -1046,24 +1050,6 @@ void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier,
mangleUnqualifiedName(nullptr, name, knownArity);
}
-static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) {
- assert(RD->isAnonymousStructOrUnion() &&
- "Expected anonymous struct or union!");
-
- for (const auto *I : RD->fields()) {
- if (I->getIdentifier())
- return I;
-
- if (const RecordType *RT = I->getType()->getAs<RecordType>())
- if (const FieldDecl *NamedDataMember =
- FindFirstNamedDataMember(RT->getDecl()))
- return NamedDataMember;
- }
-
- // We didn't find a named data member.
- return nullptr;
-}
-
void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
DeclarationName Name,
unsigned KnownArity) {
@@ -1100,9 +1086,9 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
// We must have an anonymous union or struct declaration.
- const RecordDecl *RD =
+ const RecordDecl *RD =
cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl());
-
+
// Itanium C++ ABI 5.1.2:
//
// For the purposes of mangling, the name of an anonymous union is
@@ -1112,14 +1098,16 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// the data members in the union are unnamed), then there is no way for
// a program to refer to the anonymous union, and there is therefore no
// need to mangle its name.
- const FieldDecl *FD = FindFirstNamedDataMember(RD);
+ assert(RD->isAnonymousStructOrUnion()
+ && "Expected anonymous struct or union!");
+ const FieldDecl *FD = RD->findFirstNamedDataMember();
// It's actually possible for various reasons for us to get here
// with an empty anonymous struct / union. Fortunately, it
// doesn't really matter what name we generate.
if (!FD) break;
assert(FD->getIdentifier() && "Data member name isn't an identifier!");
-
+
mangleSourceName(FD->getIdentifier());
break;
}
@@ -1409,8 +1397,8 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
if (!Number)
Number = Context.getBlockId(Block, false);
Out << "Ub";
- if (Number > 1)
- Out << Number - 2;
+ if (Number > 0)
+ Out << Number - 1;
Out << '_';
}
@@ -1459,6 +1447,9 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
// nothing
return;
+ case NestedNameSpecifier::Super:
+ llvm_unreachable("Can't mangle __super specifier");
+
case NestedNameSpecifier::Namespace:
mangleName(qualifier->getAsNamespace());
return;
@@ -1554,14 +1545,13 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND,
return;
// <template-template-param> ::= <template-param>
- if (const TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
mangleTemplateParameter(TTP->getIndex());
- return;
+ } else {
+ manglePrefix(getEffectiveDeclContext(ND), NoFunction);
+ mangleUnqualifiedName(ND->getTemplatedDecl());
}
- manglePrefix(getEffectiveDeclContext(ND), NoFunction);
- mangleUnqualifiedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
@@ -1834,6 +1824,19 @@ void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
Context.mangleObjCMethodName(MD, Out);
}
+static bool isTypeSubstitutable(Qualifiers Quals, const Type *Ty) {
+ if (Quals)
+ return true;
+ if (Ty->isSpecificBuiltinType(BuiltinType::ObjCSel))
+ return true;
+ if (Ty->isOpenCLSpecificType())
+ return true;
+ if (Ty->isBuiltinType())
+ return false;
+
+ return true;
+}
+
void CXXNameMangler::mangleType(QualType T) {
// If our type is instantiation-dependent but not dependent, we mangle
// it as it was written in the source, removing any top-level sugar.
@@ -1875,7 +1878,7 @@ void CXXNameMangler::mangleType(QualType T) {
Qualifiers quals = split.Quals;
const Type *ty = split.Ty;
- bool isSubstitutable = quals || !isa<BuiltinType>(T);
+ bool isSubstitutable = isTypeSubstitutable(quals, ty);
if (isSubstitutable && mangleSubstitution(T))
return;
@@ -2301,9 +2304,7 @@ void CXXNameMangler::mangleType(const VectorType *T) {
llvm::Triple::ArchType Arch =
getASTContext().getTargetInfo().getTriple().getArch();
if ((Arch == llvm::Triple::aarch64 ||
- Arch == llvm::Triple::aarch64_be ||
- Arch == llvm::Triple::arm64_be ||
- Arch == llvm::Triple::arm64) && !Target.isOSDarwin())
+ Arch == llvm::Triple::aarch64_be) && !Target.isOSDarwin())
mangleAArch64NeonVectorType(T);
else
mangleNeonVectorType(T);
@@ -2528,6 +2529,18 @@ void CXXNameMangler::mangleMemberExpr(const Expr *base,
// <expression> ::= dt <expression> <unresolved-name>
// ::= pt <expression> <unresolved-name>
if (base) {
+
+ // Ignore member expressions involving anonymous unions.
+ while (const auto *RT = base->getType()->getAs<RecordType>()) {
+ if (!RT->getDecl()->isAnonymousStructOrUnion())
+ break;
+ const auto *ME = dyn_cast<MemberExpr>(base);
+ if (!ME)
+ break;
+ base = ME->getBase();
+ isArrow = ME->isArrow();
+ }
+
if (base->isImplicitCXXThis()) {
// Note: GCC mangles member expressions to the implicit 'this' as
// *this., whereas we represent them as this->. The Itanium C++ ABI
@@ -2572,12 +2585,23 @@ static bool isParenthesizedADLCallee(const CallExpr *call) {
return true;
}
+void CXXNameMangler::mangleCastExpression(const Expr *E, StringRef CastEncoding) {
+ const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E);
+ Out << CastEncoding;
+ mangleType(ECE->getType());
+ mangleExpression(ECE->getSubExpr());
+}
+
void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <trinary operator-name> <expression> <expression> <expression>
// ::= cv <type> expression # conversion with one argument
// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+ // ::= dc <type> <expression> # dynamic_cast<type> (expression)
+ // ::= sc <type> <expression> # static_cast<type> (expression)
+ // ::= cc <type> <expression> # const_cast<type> (expression)
+ // ::= rc <type> <expression> # reinterpret_cast<type> (expression)
// ::= st <type> # sizeof (a type)
// ::= at <type> # alignof (a type)
// ::= <template-param>
@@ -2612,6 +2636,7 @@ recurse:
case Expr::ParenListExprClass:
case Expr::LambdaExprClass:
case Expr::MSPropertyRefExprClass:
+ case Expr::TypoExprClass: // This should no longer exist in the AST by now.
llvm_unreachable("unexpected statement kind");
// FIXME: invent manglings for all these.
@@ -2643,7 +2668,6 @@ recurse:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::VAArgExprClass:
- case Expr::CXXUuidofExprClass:
case Expr::CUDAKernelCallExprClass:
case Expr::AsTypeExprClass:
case Expr::PseudoObjectExprClass:
@@ -2658,6 +2682,20 @@ recurse:
break;
}
+ case Expr::CXXUuidofExprClass: {
+ const CXXUuidofExpr *UE = cast<CXXUuidofExpr>(E);
+ if (UE->isTypeOperand()) {
+ QualType UuidT = UE->getTypeOperand(Context.getASTContext());
+ Out << "u8__uuidoft";
+ mangleType(UuidT);
+ } else {
+ Expr *UuidExp = UE->getExprOperand();
+ Out << "u8__uuidofz";
+ mangleExpression(UuidExp, Arity);
+ }
+ break;
+ }
+
// Even gcc-4.5 doesn't mangle this.
case Expr::BinaryConditionalOperatorClass: {
DiagnosticsEngine &Diags = Context.getDiags();
@@ -2982,17 +3020,22 @@ recurse:
// Fall through to mangle the cast itself.
case Expr::CStyleCastExprClass:
+ case Expr::CXXFunctionalCastExprClass:
+ mangleCastExpression(E, "cv");
+ break;
+
case Expr::CXXStaticCastExprClass:
+ mangleCastExpression(E, "sc");
+ break;
case Expr::CXXDynamicCastExprClass:
+ mangleCastExpression(E, "dc");
+ break;
case Expr::CXXReinterpretCastExprClass:
+ mangleCastExpression(E, "rc");
+ break;
case Expr::CXXConstCastExprClass:
- case Expr::CXXFunctionalCastExprClass: {
- const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E);
- Out << "cv";
- mangleType(ECE->getType());
- mangleExpression(ECE->getSubExpr());
+ mangleCastExpression(E, "cc");
break;
- }
case Expr::CXXOperatorCallExprClass: {
const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E);
@@ -3175,12 +3218,33 @@ recurse:
mangleFunctionParam(cast<ParmVarDecl>(Pack));
break;
}
-
+
case Expr::MaterializeTemporaryExprClass: {
mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
break;
}
-
+
+ case Expr::CXXFoldExprClass: {
+ auto *FE = cast<CXXFoldExpr>(E);
+ if (FE->isLeftFold())
+ Out << (FE->getInit() ? "fL" : "fl");
+ else
+ Out << (FE->getInit() ? "fR" : "fr");
+
+ if (FE->getOperator() == BO_PtrMemD)
+ Out << "ds";
+ else
+ mangleOperatorName(
+ BinaryOperator::getOverloadedOperator(FE->getOperator()),
+ /*Arity=*/2);
+
+ if (FE->getLHS())
+ mangleExpression(FE->getLHS());
+ if (FE->getRHS())
+ mangleExpression(FE->getRHS());
+ break;
+ }
+
case Expr::CXXThisExprClass:
Out << "fpT";
break;
@@ -3251,8 +3315,8 @@ void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) {
void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
// <ctor-dtor-name> ::= C1 # complete object constructor
// ::= C2 # base object constructor
- // ::= C3 # complete object allocating constructor
//
+ // In addition, C5 is a comdat name with C1 and C2 in it.
switch (T) {
case Ctor_Complete:
Out << "C1";
@@ -3260,8 +3324,8 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
case Ctor_Base:
Out << "C2";
break;
- case Ctor_CompleteAllocating:
- Out << "C3";
+ case Ctor_Comdat:
+ Out << "C5";
break;
}
}
@@ -3271,6 +3335,7 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// ::= D1 # complete object destructor
// ::= D2 # base object destructor
//
+ // In addition, D5 is a comdat name with D1, D2 and, if virtual, D0 in it.
switch (T) {
case Dtor_Deleting:
Out << "D0";
@@ -3281,6 +3346,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
case Dtor_Base:
Out << "D2";
break;
+ case Dtor_Comdat:
+ Out << "D5";
+ break;
}
}
@@ -3363,7 +3431,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
// and pointer-to-function expressions are represented as a declaration not
// an expression. We compensate for it here to produce the correct mangling.
ValueDecl *D = A.getAsDecl();
- bool compensateMangling = !A.isDeclForReferenceParam();
+ bool compensateMangling = !A.getParamTypeForDecl()->isReferenceType();
if (compensateMangling) {
Out << 'X';
mangleOperatorName(OO_Amp, 1);
@@ -3674,7 +3742,7 @@ void ItaniumMangleContextImpl::mangleCXXName(const NamedDecl *D,
"Mangling declaration");
CXXNameMangler Mangler(*this, Out, D);
- return Mangler.mangle(D);
+ Mangler.mangle(D);
}
void ItaniumMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D,
@@ -3691,6 +3759,18 @@ void ItaniumMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D,
Mangler.mangle(D);
}
+void ItaniumMangleContextImpl::mangleCXXCtorComdat(const CXXConstructorDecl *D,
+ raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out, D, Ctor_Comdat);
+ Mangler.mangle(D);
+}
+
+void ItaniumMangleContextImpl::mangleCXXDtorComdat(const CXXDestructorDecl *D,
+ raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out, D, Dtor_Comdat);
+ Mangler.mangle(D);
+}
+
void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &Out) {
@@ -3851,3 +3931,4 @@ ItaniumMangleContext *
ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
return new ItaniumMangleContextImpl(Context, Diags);
}
+
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index fdc00e389350..1a061c4f6632 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -49,10 +49,11 @@ static void mangleFunctionBlock(MangleContext &Context,
void MangleContext::anchor() { }
-enum StdOrFastCC {
- SOF_OTHER,
- SOF_FAST,
- SOF_STD
+enum CCMangling {
+ CCM_Other,
+ CCM_Fast,
+ CCM_Vector,
+ CCM_Std
};
static bool isExternC(const NamedDecl *ND) {
@@ -61,20 +62,22 @@ static bool isExternC(const NamedDecl *ND) {
return cast<VarDecl>(ND)->isExternC();
}
-static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context,
- const NamedDecl *ND) {
+static CCMangling getCallingConvMangling(const ASTContext &Context,
+ const NamedDecl *ND) {
const TargetInfo &TI = Context.getTargetInfo();
const llvm::Triple &Triple = TI.getTriple();
- if (!Triple.isOSWindows() || Triple.getArch() != llvm::Triple::x86)
- return SOF_OTHER;
+ if (!Triple.isOSWindows() ||
+ !(Triple.getArch() == llvm::Triple::x86 ||
+ Triple.getArch() == llvm::Triple::x86_64))
+ return CCM_Other;
if (Context.getLangOpts().CPlusPlus && !isExternC(ND) &&
TI.getCXXABI() == TargetCXXABI::Microsoft)
- return SOF_OTHER;
+ return CCM_Other;
const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
if (!FD)
- return SOF_OTHER;
+ return CCM_Other;
QualType T = FD->getType();
const FunctionType *FT = T->castAs<FunctionType>();
@@ -82,19 +85,21 @@ static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context,
CallingConv CC = FT->getCallConv();
switch (CC) {
default:
- return SOF_OTHER;
+ return CCM_Other;
case CC_X86FastCall:
- return SOF_FAST;
+ return CCM_Fast;
case CC_X86StdCall:
- return SOF_STD;
+ return CCM_Std;
+ case CC_X86VectorCall:
+ return CCM_Vector;
}
}
bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
const ASTContext &ASTContext = getASTContext();
- StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D);
- if (CC != SOF_OTHER)
+ CCMangling CC = getCallingConvMangling(ASTContext, D);
+ if (CC != CCM_Other)
return true;
// In C, functions with no attributes never need to be mangled. Fastpath them.
@@ -131,28 +136,35 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
}
const ASTContext &ASTContext = getASTContext();
- StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D);
+ CCMangling CC = getCallingConvMangling(ASTContext, D);
bool MCXX = shouldMangleCXXName(D);
const TargetInfo &TI = Context.getTargetInfo();
- if (CC == SOF_OTHER || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) {
- mangleCXXName(D, Out);
+ if (CC == CCM_Other || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) {
+ if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
+ mangleObjCMethodName(OMD, Out);
+ else
+ mangleCXXName(D, Out);
return;
}
Out << '\01';
- if (CC == SOF_STD)
+ if (CC == CCM_Std)
Out << '_';
- else
+ else if (CC == CCM_Fast)
Out << '@';
if (!MCXX)
Out << D->getIdentifier()->getName();
+ else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
+ mangleObjCMethodName(OMD, Out);
else
mangleCXXName(D, Out);
const FunctionDecl *FD = cast<FunctionDecl>(D);
const FunctionType *FT = FD->getType()->castAs<FunctionType>();
const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT);
+ if (CC == CCM_Vector)
+ Out << '@';
Out << '@';
if (!Proto) {
Out << '0';
@@ -164,9 +176,11 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
if (!MD->isStatic())
++ArgWords;
for (const auto &AT : Proto->param_types())
- // Size should be aligned to DWORD boundary
- ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT), 32) / 32;
- Out << 4 * ArgWords;
+ // Size should be aligned to pointer size.
+ ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT),
+ TI.getPointerWidth(0)) /
+ TI.getPointerWidth(0);
+ Out << ((TI.getPointerWidth(0) / 8) * ArgWords);
}
void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
@@ -215,16 +229,28 @@ void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) {
mangleObjCMethodName(Method, Stream);
} else {
- const NamedDecl *ND = cast<NamedDecl>(DC);
- if (!shouldMangleDeclName(ND) && ND->getIdentifier())
- Stream << ND->getIdentifier()->getName();
- else {
- // FIXME: We were doing a mangleUnqualifiedName() before, but that's
- // a private member of a class that will soon itself be private to the
- // Itanium C++ ABI object. What should we do now? Right now, I'm just
- // calling the mangleName() method on the MangleContext; is there a
- // better way?
- mangleName(ND, Stream);
+ assert((isa<NamedDecl>(DC) || isa<BlockDecl>(DC)) &&
+ "expected a NamedDecl or BlockDecl");
+ if (isa<BlockDecl>(DC))
+ for (; DC && isa<BlockDecl>(DC); DC = DC->getParent())
+ (void) getBlockId(cast<BlockDecl>(DC), true);
+ assert((isa<TranslationUnitDecl>(DC) || isa<NamedDecl>(DC)) &&
+ "expected a TranslationUnitDecl or a NamedDecl");
+ if (const auto *CD = dyn_cast<CXXConstructorDecl>(DC))
+ mangleCtorBlock(CD, /*CT*/ Ctor_Complete, BD, Out);
+ else if (const auto *DD = dyn_cast<CXXDestructorDecl>(DC))
+ mangleDtorBlock(DD, /*DT*/ Dtor_Complete, BD, Out);
+ else if (auto ND = dyn_cast<NamedDecl>(DC)) {
+ if (!shouldMangleDeclName(ND) && ND->getIdentifier())
+ Stream << ND->getIdentifier()->getName();
+ else {
+ // FIXME: We were doing a mangleUnqualifiedName() before, but that's
+ // a private member of a class that will soon itself be private to the
+ // Itanium C++ ABI object. What should we do now? Right now, I'm just
+ // calling the mangleName() method on the MangleContext; is there a
+ // better way?
+ mangleName(ND, Stream);
+ }
}
}
Stream.flush();
diff --git a/lib/AST/MangleNumberingContext.cpp b/lib/AST/MangleNumberingContext.cpp
deleted file mode 100644
index 5f40f0347d0e..000000000000
--- a/lib/AST/MangleNumberingContext.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//===--- MangleNumberingContext.cpp - Context for mangling numbers --------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the LambdaMangleContext class, which keeps track of
-// the Itanium C++ ABI mangling numbers for lambda expressions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/MangleNumberingContext.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclCXX.h"
-
-using namespace clang;
-
-unsigned
-MangleNumberingContext::getManglingNumber(const CXXMethodDecl *CallOperator) {
- const FunctionProtoType *Proto
- = CallOperator->getType()->getAs<FunctionProtoType>();
- ASTContext &Context = CallOperator->getASTContext();
-
- QualType Key = Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(),
- FunctionProtoType::ExtProtoInfo());
- Key = Context.getCanonicalType(Key);
- return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
-}
-
-unsigned
-MangleNumberingContext::getManglingNumber(const BlockDecl *BD) {
- // FIXME: Compute a BlockPointerType? Not obvious how.
- const Type *Ty = nullptr;
- return ++ManglingNumbers[Ty];
-}
-
-unsigned
-MangleNumberingContext::getStaticLocalNumber(const VarDecl *VD) {
- // FIXME: Compute a BlockPointerType? Not obvious how.
- const Type *Ty = nullptr;
- return ++ManglingNumbers[Ty];
-}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 6870315b2160..0603d3b7b9b5 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -28,7 +28,28 @@ namespace {
/// \brief Numbers things which need to correspond across multiple TUs.
/// Typically these are things like static locals, lambdas, or blocks.
class MicrosoftNumberingContext : public MangleNumberingContext {
+ llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
+ unsigned LambdaManglingNumber;
+ unsigned StaticLocalNumber;
+
public:
+ MicrosoftNumberingContext()
+ : MangleNumberingContext(), LambdaManglingNumber(0),
+ StaticLocalNumber(0) {}
+
+ unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
+ return ++LambdaManglingNumber;
+ }
+
+ unsigned getManglingNumber(const BlockDecl *BD) override {
+ const Type *Ty = nullptr;
+ return ++ManglingNumbers[Ty];
+ }
+
+ unsigned getStaticLocalNumber(const VarDecl *VD) override {
+ return ++StaticLocalNumber;
+ }
+
unsigned getManglingNumber(const VarDecl *VD,
unsigned MSLocalManglingNumber) override {
return MSLocalManglingNumber;
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index e6a6d09b4845..72f90f67cbdf 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -27,7 +27,6 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/Support/MathExtras.h"
using namespace clang;
@@ -161,7 +160,7 @@ public:
unsigned &discriminator = Uniquifier[ND];
if (!discriminator)
discriminator = ++Discriminator[std::make_pair(DC, ND->getIdentifier())];
- disc = discriminator;
+ disc = discriminator + 1;
return true;
}
@@ -191,8 +190,8 @@ class MicrosoftCXXNameMangler {
const NamedDecl *Structor;
unsigned StructorType;
- typedef llvm::StringMap<unsigned> BackRefMap;
- BackRefMap NameBackReferences;
+ typedef llvm::SmallVector<std::string, 10> BackRefVec;
+ BackRefVec NameBackReferences;
typedef llvm::DenseMap<void *, unsigned> ArgBackRefMap;
ArgBackRefMap TypeBackReferences;
@@ -234,7 +233,7 @@ public:
QualifierMangleMode QMM = QMM_Mangle);
void mangleFunctionType(const FunctionType *T,
const FunctionDecl *D = nullptr,
- bool ForceInstMethod = false);
+ bool ForceThisQuals = false);
void mangleNestedName(const NamedDecl *ND);
private:
@@ -279,7 +278,8 @@ private:
void mangleTemplateArgs(const TemplateDecl *TD,
const TemplateArgumentList &TemplateArgs);
- void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA);
+ void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA,
+ const NamedDecl *Parm);
};
}
@@ -338,9 +338,7 @@ bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
bool
MicrosoftMangleContextImpl::shouldMangleStringLiteral(const StringLiteral *SL) {
- return SL->isAscii() || SL->isWide();
- // TODO: This needs to be updated when MSVC gains support for Unicode
- // literals.
+ return true;
}
void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
@@ -441,7 +439,7 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
mangleQualifiers(Ty.getQualifiers(), false);
} else {
mangleType(Ty, SR, QMM_Drop);
- mangleQualifiers(Ty.getLocalQualifiers(), false);
+ mangleQualifiers(Ty.getQualifiers(), false);
}
}
@@ -801,10 +799,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) {
// <postfix> ::= <unqualified-name> [<postfix>]
// ::= <substitution> [<postfix>]
- if (isLambda(ND))
- return;
-
- const DeclContext *DC = ND->getDeclContext();
+ const DeclContext *DC = getEffectiveDeclContext(ND);
while (!DC->isTranslationUnit()) {
if (isa<TagDecl>(ND) || isa<VarDecl>(ND)) {
@@ -856,6 +851,8 @@ void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// <operator-name> ::= ?_E # vector deleting destructor
// FIXME: Add a vector deleting dtor type. It goes in the vtable, so we need
// it.
+ case Dtor_Comdat:
+ llvm_unreachable("not expecting a COMDAT");
}
llvm_unreachable("Unsupported dtor type?");
}
@@ -994,22 +991,14 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
void MicrosoftCXXNameMangler::mangleSourceName(StringRef Name) {
// <source name> ::= <identifier> @
- BackRefMap::iterator Found;
- if (NameBackReferences.size() < 10) {
- size_t Size = NameBackReferences.size();
- bool Inserted;
- std::tie(Found, Inserted) =
- NameBackReferences.insert(std::make_pair(Name, Size));
- if (Inserted)
- Found = NameBackReferences.end();
- } else {
- Found = NameBackReferences.find(Name);
- }
-
+ BackRefVec::iterator Found =
+ std::find(NameBackReferences.begin(), NameBackReferences.end(), Name);
if (Found == NameBackReferences.end()) {
+ if (NameBackReferences.size() < 10)
+ NameBackReferences.push_back(Name);
Out << Name << '@';
} else {
- Out << Found->second;
+ Out << (Found - NameBackReferences.begin());
}
}
@@ -1025,7 +1014,7 @@ void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
// Templates have their own context for back references.
ArgBackRefMap OuterArgsContext;
- BackRefMap OuterTemplateContext;
+ BackRefVec OuterTemplateContext;
NameBackReferences.swap(OuterTemplateContext);
TypeBackReferences.swap(OuterArgsContext);
@@ -1051,8 +1040,10 @@ void MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
// Make sure booleans are encoded as 0/1.
if (IsBoolean && Value.getBoolValue())
mangleNumber(1);
- else
+ else if (Value.isSigned())
mangleNumber(Value.getSExtValue());
+ else
+ mangleNumber(Value.getZExtValue());
}
void MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
@@ -1104,12 +1095,18 @@ void MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
void MicrosoftCXXNameMangler::mangleTemplateArgs(
const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) {
// <template-args> ::= <template-arg>+
+ const TemplateParameterList *TPL = TD->getTemplateParameters();
+ assert(TPL->size() == TemplateArgs.size() &&
+ "size mismatch between args and parms!");
+
+ unsigned Idx = 0;
for (const TemplateArgument &TA : TemplateArgs.asArray())
- mangleTemplateArg(TD, TA);
+ mangleTemplateArg(TD, TA, TPL->getParam(Idx++));
}
void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
- const TemplateArgument &TA) {
+ const TemplateArgument &TA,
+ const NamedDecl *Parm) {
// <template-arg> ::= <type>
// ::= <integer-literal>
// ::= <member-data-pointer>
@@ -1142,7 +1139,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
else
mangle(FD, "$1?");
} else {
- mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?");
+ mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?");
}
break;
}
@@ -1172,18 +1169,33 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
case TemplateArgument::Pack: {
ArrayRef<TemplateArgument> TemplateArgs = TA.getPackAsArray();
if (TemplateArgs.empty()) {
- Out << "$S";
+ if (isa<TemplateTypeParmDecl>(Parm) ||
+ isa<TemplateTemplateParmDecl>(Parm))
+ Out << "$$V";
+ else if (isa<NonTypeTemplateParmDecl>(Parm))
+ Out << "$S";
+ else
+ llvm_unreachable("unexpected template parameter decl!");
} else {
for (const TemplateArgument &PA : TemplateArgs)
- mangleTemplateArg(TD, PA);
+ mangleTemplateArg(TD, PA, Parm);
}
break;
}
- case TemplateArgument::Template:
- mangleType(cast<TagDecl>(
- TA.getAsTemplate().getAsTemplateDecl()->getTemplatedDecl()));
+ case TemplateArgument::Template: {
+ const NamedDecl *ND =
+ TA.getAsTemplate().getAsTemplateDecl()->getTemplatedDecl();
+ if (const auto *TD = dyn_cast<TagDecl>(ND)) {
+ mangleType(TD);
+ } else if (isa<TypeAliasDecl>(ND)) {
+ Out << "$$Y";
+ mangleName(ND);
+ } else {
+ llvm_unreachable("unexpected template template NamedDecl!");
+ }
break;
}
+ }
}
void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
@@ -1473,6 +1485,8 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T,
case BuiltinType::Int128: Out << "_L"; break;
case BuiltinType::UInt128: Out << "_M"; break;
case BuiltinType::Bool: Out << "_N"; break;
+ case BuiltinType::Char16: Out << "_S"; break;
+ case BuiltinType::Char32: Out << "_U"; break;
case BuiltinType::WChar_S:
case BuiltinType::WChar_U: Out << "_W"; break;
@@ -1498,8 +1512,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T,
case BuiltinType::NullPtr: Out << "$$T"; break;
- case BuiltinType::Char16:
- case BuiltinType::Char32:
case BuiltinType::Half: {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
@@ -1518,8 +1530,13 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T,
// Structors only appear in decls, so at this point we know it's not a
// structor type.
// FIXME: This may not be lambda-friendly.
- Out << "$$A6";
- mangleFunctionType(T);
+ if (T->getTypeQuals() || T->getRefQualifier() != RQ_None) {
+ Out << "$$A8@@";
+ mangleFunctionType(T, /*D=*/nullptr, /*ForceThisQuals=*/true);
+ } else {
+ Out << "$$A6";
+ mangleFunctionType(T);
+ }
}
void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
SourceRange) {
@@ -1528,7 +1545,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
const FunctionDecl *D,
- bool ForceInstMethod) {
+ bool ForceThisQuals) {
// <function-type> ::= <this-cvr-qualifiers> <calling-convention>
// <return-type> <argument-list> <throw-spec>
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
@@ -1536,21 +1553,21 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
SourceRange Range;
if (D) Range = D->getSourceRange();
- bool IsStructor = false, IsInstMethod = ForceInstMethod;
+ bool IsStructor = false, HasThisQuals = ForceThisQuals;
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) {
if (MD->isInstance())
- IsInstMethod = true;
+ HasThisQuals = true;
if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
IsStructor = true;
}
// If this is a C++ instance method, mangle the CVR qualifiers for the
// this pointer.
- if (IsInstMethod) {
+ if (HasThisQuals) {
Qualifiers Quals = Qualifiers::fromCVRMask(Proto->getTypeQuals());
- manglePointerExtQualifiers(Quals, nullptr);
+ manglePointerExtQualifiers(Quals, /*PointeeType=*/nullptr);
mangleRefQualifier(Proto->getRefQualifier());
- mangleQualifiers(Quals, false);
+ mangleQualifiers(Quals, /*IsMember=*/false);
}
mangleCallingConvention(T);
@@ -1670,6 +1687,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
// ::= H # __export __stdcall
// ::= I # __fastcall
// ::= J # __export __fastcall
+ // ::= Q # __vectorcall
// The 'export' calling conventions are from a bygone era
// (*cough*Win16*cough*) when functions were declared for export with
// that keyword. (It didn't actually export them, it just made them so
@@ -1686,6 +1704,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
case CC_X86ThisCall: Out << 'E'; break;
case CC_X86StdCall: Out << 'G'; break;
case CC_X86FastCall: Out << 'I'; break;
+ case CC_X86VectorCall: Out << 'Q'; break;
}
}
void MicrosoftCXXNameMangler::mangleThrowSpecification(
@@ -2331,7 +2350,7 @@ void MicrosoftMangleContextImpl::mangleReferenceTemporary(const VarDecl *VD,
void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD,
raw_ostream &Out) {
- // TODO: This is not correct, especially with respect to MSVC2013. MSVC2013
+ // TODO: This is not correct, especially with respect to VS "14". VS "14"
// utilizes thread local variables to implement thread safe, re-entrant
// initialization for statics. They no longer differentiate between an
// externally visible and non-externally visible static with respect to
@@ -2420,14 +2439,10 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
Mangler.getStream() << "\01??_C@_";
// <char-type>: The "kind" of string literal is encoded into the mangled name.
- // TODO: This needs to be updated when MSVC gains support for unicode
- // literals.
- if (SL->isAscii())
- Mangler.getStream() << '0';
- else if (SL->isWide())
+ if (SL->isWide())
Mangler.getStream() << '1';
else
- llvm_unreachable("unexpected string literal kind!");
+ Mangler.getStream() << '0';
// <literal-length>: The next part of the mangled name consists of the length
// of the string.
@@ -2506,42 +2521,16 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
} else if (isLetter(Byte & 0x7f)) {
Mangler.getStream() << '?' << static_cast<char>(Byte & 0x7f);
} else {
- switch (Byte) {
- case ',':
- Mangler.getStream() << "?0";
- break;
- case '/':
- Mangler.getStream() << "?1";
- break;
- case '\\':
- Mangler.getStream() << "?2";
- break;
- case ':':
- Mangler.getStream() << "?3";
- break;
- case '.':
- Mangler.getStream() << "?4";
- break;
- case ' ':
- Mangler.getStream() << "?5";
- break;
- case '\n':
- Mangler.getStream() << "?6";
- break;
- case '\t':
- Mangler.getStream() << "?7";
- break;
- case '\'':
- Mangler.getStream() << "?8";
- break;
- case '-':
- Mangler.getStream() << "?9";
- break;
- default:
- Mangler.getStream() << "?$";
- Mangler.getStream() << static_cast<char>('A' + ((Byte >> 4) & 0xf));
- Mangler.getStream() << static_cast<char>('A' + (Byte & 0xf));
- break;
+ const char SpecialChars[] = {',', '/', '\\', ':', '.',
+ ' ', '\n', '\t', '\'', '-'};
+ const char *Pos =
+ std::find(std::begin(SpecialChars), std::end(SpecialChars), Byte);
+ if (Pos != std::end(SpecialChars)) {
+ Mangler.getStream() << '?' << (Pos - std::begin(SpecialChars));
+ } else {
+ Mangler.getStream() << "?$";
+ Mangler.getStream() << static_cast<char>('A' + ((Byte >> 4) & 0xf));
+ Mangler.getStream() << static_cast<char>('A' + (Byte & 0xf));
}
}
};
@@ -2550,7 +2539,10 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
unsigned NumCharsToMangle = std::min(32U, SL->getLength());
for (unsigned I = 0, E = NumCharsToMangle * SL->getCharByteWidth(); I != E;
++I)
- MangleByte(GetBigEndianByte(I));
+ if (SL->isWide())
+ MangleByte(GetBigEndianByte(I));
+ else
+ MangleByte(GetLittleEndianByte(I));
// Encode the NUL terminator if there is room.
if (NumCharsToMangle < 32)
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 986b3b53983d..3dc750a81787 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -10,6 +10,7 @@
#include "clang/AST/NSAPI.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -46,6 +47,10 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("stringWithUTF8String"));
break;
+ case NSStr_initWithUTF8String:
+ Sel = Ctx.Selectors.getUnarySelector(
+ &Ctx.Idents.get("initWithUTF8String"));
+ break;
case NSStr_stringWithCStringEncoding: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("stringWithCString"),
@@ -379,6 +384,32 @@ bool NSAPI::isObjCNSUIntegerType(QualType T) const {
return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
}
+StringRef NSAPI::GetNSIntegralKind(QualType T) const {
+ if (!Ctx.getLangOpts().ObjC1 || T.isNull())
+ return StringRef();
+
+ while (const TypedefType *TDT = T->getAs<TypedefType>()) {
+ StringRef NSIntegralResust =
+ llvm::StringSwitch<StringRef>(
+ TDT->getDecl()->getDeclName().getAsIdentifierInfo()->getName())
+ .Case("int8_t", "int8_t")
+ .Case("int16_t", "int16_t")
+ .Case("int32_t", "int32_t")
+ .Case("NSInteger", "NSInteger")
+ .Case("int64_t", "int64_t")
+ .Case("uint8_t", "uint8_t")
+ .Case("uint16_t", "uint16_t")
+ .Case("uint32_t", "uint32_t")
+ .Case("NSUInteger", "NSUInteger")
+ .Case("uint64_t", "uint64_t")
+ .Default(StringRef());
+ if (!NSIntegralResust.empty())
+ return NSIntegralResust;
+ T = TDT->desugar();
+ }
+ return StringRef();
+}
+
bool NSAPI::isObjCTypedef(QualType T,
StringRef name, IdentifierInfo *&II) const {
if (!Ctx.getLangOpts().ObjC1)
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 1f041aa49542..50a00502ca9f 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -66,7 +66,7 @@ NestedNameSpecifier::Create(const ASTContext &Context,
"Broken nested name specifier");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(StoredNamespaceOrAlias);
+ Mockup.Prefix.setInt(StoredDecl);
Mockup.Specifier = const_cast<NamespaceDecl *>(NS);
return FindOrInsert(Context, Mockup);
}
@@ -82,7 +82,7 @@ NestedNameSpecifier::Create(const ASTContext &Context,
"Broken nested name specifier");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(StoredNamespaceOrAlias);
+ Mockup.Prefix.setInt(StoredDecl);
Mockup.Specifier = Alias;
return FindOrInsert(Context, Mockup);
}
@@ -118,6 +118,16 @@ NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) {
return Context.GlobalNestedNameSpecifier;
}
+NestedNameSpecifier *
+NestedNameSpecifier::SuperSpecifier(const ASTContext &Context,
+ CXXRecordDecl *RD) {
+ NestedNameSpecifier Mockup;
+ Mockup.Prefix.setPointer(nullptr);
+ Mockup.Prefix.setInt(StoredDecl);
+ Mockup.Specifier = RD;
+ return FindOrInsert(Context, Mockup);
+}
+
NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
if (!Specifier)
return Global;
@@ -126,9 +136,12 @@ NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
case StoredIdentifier:
return Identifier;
- case StoredNamespaceOrAlias:
- return isa<NamespaceDecl>(static_cast<NamedDecl *>(Specifier))? Namespace
- : NamespaceAlias;
+ case StoredDecl: {
+ NamedDecl *ND = static_cast<NamedDecl *>(Specifier);
+ if (isa<CXXRecordDecl>(ND))
+ return Super;
+ return isa<NamespaceDecl>(ND) ? Namespace : NamespaceAlias;
+ }
case StoredTypeSpec:
return TypeSpec;
@@ -140,24 +153,29 @@ NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
llvm_unreachable("Invalid NNS Kind!");
}
-/// \brief Retrieve the namespace stored in this nested name
-/// specifier.
+/// \brief Retrieve the namespace stored in this nested name specifier.
NamespaceDecl *NestedNameSpecifier::getAsNamespace() const {
- if (Prefix.getInt() == StoredNamespaceOrAlias)
+ if (Prefix.getInt() == StoredDecl)
return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier));
return nullptr;
}
-/// \brief Retrieve the namespace alias stored in this nested name
-/// specifier.
+/// \brief Retrieve the namespace alias stored in this nested name specifier.
NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const {
- if (Prefix.getInt() == StoredNamespaceOrAlias)
+ if (Prefix.getInt() == StoredDecl)
return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier));
return nullptr;
}
+/// \brief Retrieve the record declaration stored in this nested name specifier.
+CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const {
+ if (Prefix.getInt() == StoredDecl)
+ return dyn_cast<CXXRecordDecl>(static_cast<NamedDecl *>(Specifier));
+
+ return nullptr;
+}
/// \brief Whether this nested name specifier refers to a dependent
/// type or not.
@@ -172,6 +190,15 @@ bool NestedNameSpecifier::isDependent() const {
case Global:
return false;
+ case Super: {
+ CXXRecordDecl *RD = static_cast<CXXRecordDecl *>(Specifier);
+ for (const auto &Base : RD->bases())
+ if (Base.getType()->isDependentType())
+ return true;
+
+ return false;
+ }
+
case TypeSpec:
case TypeSpecWithTemplate:
return getAsType()->isDependentType();
@@ -191,8 +218,9 @@ bool NestedNameSpecifier::isInstantiationDependent() const {
case Namespace:
case NamespaceAlias:
case Global:
+ case Super:
return false;
-
+
case TypeSpec:
case TypeSpecWithTemplate:
return getAsType()->isInstantiationDependentType();
@@ -209,6 +237,7 @@ bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
case Namespace:
case NamespaceAlias:
case Global:
+ case Super:
return false;
case TypeSpec:
@@ -246,6 +275,10 @@ NestedNameSpecifier::print(raw_ostream &OS,
case Global:
break;
+ case Super:
+ OS << "__super";
+ break;
+
case TypeSpecWithTemplate:
OS << "template ";
// Fall through to print the type.
@@ -304,6 +337,7 @@ NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
+ case NestedNameSpecifier::Super:
// The location of the identifier or namespace name.
Length += sizeof(unsigned);
break;
@@ -369,6 +403,7 @@ SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
+ case NestedNameSpecifier::Super:
return SourceRange(LoadSourceLocation(Data, Offset),
LoadSourceLocation(Data, Offset + sizeof(unsigned)));
@@ -552,6 +587,17 @@ void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context,
SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
}
+void NestedNameSpecifierLocBuilder::MakeSuper(ASTContext &Context,
+ CXXRecordDecl *RD,
+ SourceLocation SuperLoc,
+ SourceLocation ColonColonLoc) {
+ Representation = NestedNameSpecifier::SuperSpecifier(Context, RD);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(SuperLoc, Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context,
NestedNameSpecifier *Qualifier,
SourceRange R) {
@@ -583,6 +629,7 @@ void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context,
}
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
break;
}
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index b3deebaecfab..0d070a4bfbfc 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -636,23 +636,12 @@ protected:
HasOwnVFPtr(false),
FirstNearlyEmptyVBase(nullptr) {}
- /// Reset this RecordLayoutBuilder to a fresh state, using the given
- /// alignment as the initial alignment. This is used for the
- /// correct layout of vb-table pointers in MSVC.
- void resetWithTargetAlignment(CharUnits TargetAlignment) {
- const ASTContext &Context = this->Context;
- EmptySubobjectMap *EmptySubobjects = this->EmptySubobjects;
- this->~RecordLayoutBuilder();
- new (this) RecordLayoutBuilder(Context, EmptySubobjects);
- Alignment = UnpackedAlignment = TargetAlignment;
- }
-
void Layout(const RecordDecl *D);
void Layout(const CXXRecordDecl *D);
void Layout(const ObjCInterfaceDecl *D);
void LayoutFields(const RecordDecl *D);
- void LayoutField(const FieldDecl *D);
+ void LayoutField(const FieldDecl *D, bool InsertExtraPadding);
void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize,
bool FieldPacked, const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
@@ -1104,7 +1093,7 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
// Only lay out the virtual base if it's not an indirect primary base.
if (!IndirectPrimaryBase) {
// Only visit virtual bases once.
- if (!VisitedVirtualBases.insert(BaseDecl))
+ if (!VisitedVirtualBases.insert(BaseDecl).second)
continue;
const BaseSubobjectInfo *BaseInfo = VirtualBaseInfo.lookup(BaseDecl);
@@ -1331,7 +1320,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
// Layout each ivar sequentially.
for (const ObjCIvarDecl *IVD = D->all_declared_ivar_begin(); IVD;
IVD = IVD->getNextIvar())
- LayoutField(IVD);
+ LayoutField(IVD, false);
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
@@ -1341,8 +1330,22 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
- for (const auto *Field : D->fields())
- LayoutField(Field);
+ bool InsertExtraPadding = D->mayInsertExtraPadding(/*EmitRemark=*/true);
+ bool HasFlexibleArrayMember = D->hasFlexibleArrayMember();
+ for (auto I = D->field_begin(), End = D->field_end(); I != End; ++I) {
+ auto Next(I);
+ ++Next;
+ LayoutField(*I,
+ InsertExtraPadding && (Next != End || !HasFlexibleArrayMember));
+ }
+}
+
+// Rounds the specified size to have it a multiple of the char size.
+static uint64_t
+roundUpSizeToCharAlignment(uint64_t Size,
+ const ASTContext &Context) {
+ uint64_t CharAlignment = Context.getTargetInfo().getCharAlign();
+ return llvm::RoundUpToAlignment(Size, CharAlignment);
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
@@ -1382,7 +1385,9 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
if (IsUnion) {
- setDataSize(std::max(getDataSizeInBits(), FieldSize));
+ uint64_t RoundedFieldSize = roundUpSizeToCharAlignment(FieldSize,
+ Context);
+ setDataSize(std::max(getDataSizeInBits(), RoundedFieldSize));
FieldOffset = 0;
} else {
// The bitfield is allocated starting at the next offset aligned
@@ -1413,9 +1418,9 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t FieldSize = D->getBitWidthValue(Context);
- std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
- uint64_t TypeSize = FieldInfo.first;
- unsigned FieldAlign = FieldInfo.second;
+ TypeInfo FieldInfo = Context.getTypeInfo(D->getType());
+ uint64_t TypeSize = FieldInfo.Width;
+ unsigned FieldAlign = FieldInfo.Align;
// UnfilledBitsInLastUnit is the difference between the end of the
// last allocated bitfield (i.e. the first bit offset available for
@@ -1607,9 +1612,9 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// For unions, this is just a max operation, as usual.
if (IsUnion) {
- // FIXME: I think FieldSize should be TypeSize here.
- setDataSize(std::max(getDataSizeInBits(), FieldSize));
-
+ uint64_t RoundedFieldSize = roundUpSizeToCharAlignment(FieldSize,
+ Context);
+ setDataSize(std::max(getDataSizeInBits(), RoundedFieldSize));
// For non-zero-width bitfields in ms_struct structs, allocate a new
// storage unit if necessary.
} else if (IsMsStruct && FieldSize) {
@@ -1645,7 +1650,8 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
Context.toCharUnitsFromBits(UnpackedFieldAlign));
}
-void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
+void RecordLayoutBuilder::LayoutField(const FieldDecl *D,
+ bool InsertExtraPadding) {
if (D->isBitField()) {
LayoutBitField(D);
return;
@@ -1749,6 +1755,15 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
Context.toBits(UnpackedFieldOffset),
Context.toBits(UnpackedFieldAlign), FieldPacked, D);
+ if (InsertExtraPadding) {
+ CharUnits ASanAlignment = CharUnits::fromQuantity(8);
+ CharUnits ExtraSizeForAsan = ASanAlignment;
+ if (FieldSize % ASanAlignment)
+ ExtraSizeForAsan +=
+ ASanAlignment - CharUnits::fromQuantity(FieldSize % ASanAlignment);
+ FieldSize += ExtraSizeForAsan;
+ }
+
// Reserve space for this field.
uint64_t FieldSizeInBits = Context.toBits(FieldSize);
if (IsUnion)
@@ -2097,7 +2112,7 @@ static bool isMsLayout(const RecordDecl* D) {
// * There is a distinction between alignment and required alignment.
// __declspec(align) changes the required alignment of a struct. This
// alignment is _always_ obeyed, even in the presence of #pragma pack. A
-// record inherites required alignment from all of its fields an bases.
+// record inherits required alignment from all of its fields and bases.
// * __declspec(align) on bitfields has the effect of changing the bitfield's
// alignment instead of its required alignment. This is the only known way
// to make the alignment of a struct bigger than 8. Interestingly enough
@@ -2181,8 +2196,9 @@ public:
FieldOffsets.push_back(FieldOffset);
}
/// \brief Compute the set of virtual bases for which vtordisps are required.
- llvm::SmallPtrSet<const CXXRecordDecl *, 2>
- computeVtorDispSet(const CXXRecordDecl *RD);
+ void computeVtorDispSet(
+ llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet,
+ const CXXRecordDecl *RD) const;
const ASTContext &Context;
/// \brief The size of the record being laid out.
CharUnits Size;
@@ -2203,6 +2219,8 @@ public:
CharUnits CurrentBitfieldSize;
/// \brief Offset to the virtual base table pointer (if one exists).
CharUnits VBPtrOffset;
+ /// \brief Minimum record size possible.
+ CharUnits MinEmptyStructSize;
/// \brief The size and alignment info of a pointer.
ElementInfo PointerInfo;
/// \brief The primary base class (if one exists).
@@ -2260,12 +2278,18 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
MicrosoftRecordLayoutBuilder::ElementInfo
MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
const FieldDecl *FD) {
+ // Get the alignment of the field type's natural alignment, ignore any
+ // alignment attributes.
ElementInfo Info;
std::tie(Info.Size, Info.Alignment) =
- Context.getTypeInfoInChars(FD->getType());
- // Respect align attributes.
- CharUnits FieldRequiredAlignment =
+ Context.getTypeInfoInChars(FD->getType()->getUnqualifiedDesugaredType());
+ // Respect align attributes on the field.
+ CharUnits FieldRequiredAlignment =
Context.toCharUnitsFromBits(FD->getMaxAlignment());
+ // Respect align attributes on the type.
+ if (Context.isAlignmentRequired(FD->getType()))
+ FieldRequiredAlignment = std::max(
+ Context.getTypeAlignInChars(FD->getType()), FieldRequiredAlignment);
// Respect attributes applied to subobjects of the field.
if (FD->isBitField())
// For some reason __declspec align impacts alignment rather than required
@@ -2292,6 +2316,8 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
}
void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {
+ // For C record layout, zero-sized records always have size 4.
+ MinEmptyStructSize = CharUnits::fromQuantity(4);
initializeLayout(RD);
layoutFields(RD);
DataSize = Size = Size.RoundUpToAlignment(Alignment);
@@ -2301,6 +2327,8 @@ void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {
}
void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
+ // The C++ standard says that empty structs have size 1.
+ MinEmptyStructSize = CharUnits::One();
initializeLayout(RD);
initializeCXXLayout(RD);
layoutNonVirtualBases(RD);
@@ -2599,14 +2627,14 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
}
VtorDispAlignment = std::max(VtorDispAlignment, RequiredAlignment);
// Compute the vtordisp set.
- llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordispSet =
- computeVtorDispSet(RD);
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtorDispSet;
+ computeVtorDispSet(HasVtorDispSet, RD);
// Iterate through the virtual bases and lay them out.
const ASTRecordLayout *PreviousBaseLayout = nullptr;
for (const CXXBaseSpecifier &VBase : RD->vbases()) {
const CXXRecordDecl *BaseDecl = VBase.getType()->getAsCXXRecordDecl();
const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
- bool HasVtordisp = HasVtordispSet.count(BaseDecl);
+ bool HasVtordisp = HasVtorDispSet.count(BaseDecl) > 0;
// Insert padding between two bases if the left first one is zero sized or
// contains a zero sized subobject and the right is zero sized or one leads
// with a zero sized base. The padding between virtual bases is 4
@@ -2629,7 +2657,7 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
// Respect required alignment. Note that in 32-bit mode Required alignment
- // may be 0 nad cause size not to be updated.
+ // may be 0 and cause size not to be updated.
DataSize = Size;
if (!RequiredAlignment.isZero()) {
Alignment = std::max(Alignment, RequiredAlignment);
@@ -2639,11 +2667,15 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
RoundingAlignment = std::max(RoundingAlignment, RequiredAlignment);
Size = Size.RoundUpToAlignment(RoundingAlignment);
}
- // Zero-sized structures have size equal to their alignment.
if (Size.isZero()) {
EndsWithZeroSizedObject = true;
LeadsWithZeroSizedBase = true;
- Size = Alignment;
+ // Zero-sized structures have size equal to their alignment if a
+ // __declspec(align) came into play.
+ if (RequiredAlignment >= MinEmptyStructSize)
+ Size = Alignment;
+ else
+ Size = MinEmptyStructSize;
}
}
@@ -2665,10 +2697,9 @@ RequiresVtordisp(const llvm::SmallPtrSetImpl<const CXXRecordDecl *> &
return false;
}
-llvm::SmallPtrSet<const CXXRecordDecl *, 2>
-MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
- llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordispSet;
-
+void MicrosoftRecordLayoutBuilder::computeVtorDispSet(
+ llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtordispSet,
+ const CXXRecordDecl *RD) const {
// /vd2 or #pragma vtordisp(2): Always use vtordisps for virtual bases with
// vftables.
if (RD->getMSVtorDispMode() == MSVtorDispAttr::ForVFTable) {
@@ -2678,7 +2709,7 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
if (Layout.hasExtendableVFPtr())
HasVtordispSet.insert(BaseDecl);
}
- return HasVtordispSet;
+ return;
}
// If any of our bases need a vtordisp for this type, so do we. Check our
@@ -2695,7 +2726,7 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
// * #pragma vtordisp(0) or the /vd0 flag are in use.
if ((!RD->hasUserDeclaredConstructor() && !RD->hasUserDeclaredDestructor()) ||
RD->getMSVtorDispMode() == MSVtorDispAttr::Never)
- return HasVtordispSet;
+ return;
// /vd1 or #pragma vtordisp(1): Try to guess based on whether we think it's
// possible for a partially constructed object with virtual base overrides to
// escape a non-trivial constructor.
@@ -2706,9 +2737,9 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
// vtordisp.
llvm::SmallPtrSet<const CXXMethodDecl *, 8> Work;
llvm::SmallPtrSet<const CXXRecordDecl *, 2> BasesWithOverriddenMethods;
- // Seed the working set with our non-destructor virtual methods.
+ // Seed the working set with our non-destructor, non-pure virtual methods.
for (const CXXMethodDecl *MD : RD->methods())
- if (MD->isVirtual() && !isa<CXXDestructorDecl>(MD))
+ if (MD->isVirtual() && !isa<CXXDestructorDecl>(MD) && !MD->isPure())
Work.insert(MD);
while (!Work.empty()) {
const CXXMethodDecl *MD = *Work.begin();
@@ -2730,7 +2761,6 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
RequiresVtordisp(BasesWithOverriddenMethods, BaseDecl))
HasVtordispSet.insert(BaseDecl);
}
- return HasVtordispSet;
}
/// \brief Get or compute information about the layout of the specified record
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index a8483dc5bb99..68c7e7278432 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -104,6 +104,26 @@ Stmt *Stmt::IgnoreImplicit() {
return s;
}
+/// \brief Skip no-op (attributed, compound) container stmts and skip captured
+/// stmt at the top, if \a IgnoreCaptured is true.
+Stmt *Stmt::IgnoreContainers(bool IgnoreCaptured) {
+ Stmt *S = this;
+ if (IgnoreCaptured)
+ if (auto CapS = dyn_cast_or_null<CapturedStmt>(S))
+ S = CapS->getCapturedStmt();
+ while (true) {
+ if (auto AS = dyn_cast_or_null<AttributedStmt>(S))
+ S = AS->getSubStmt();
+ else if (auto CS = dyn_cast_or_null<CompoundStmt>(S)) {
+ if (CS->size() != 1)
+ break;
+ S = CS->body_back();
+ } else
+ break;
+ }
+ return S;
+}
+
/// \brief Strip off all label-like statements.
///
/// This will strip off label statements, case statements, attributed
@@ -254,7 +274,7 @@ SourceLocation Stmt::getLocEnd() const {
CompoundStmt::CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts,
SourceLocation LB, SourceLocation RB)
- : Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) {
+ : Stmt(CompoundStmtClass), LBraceLoc(LB), RBraceLoc(RB) {
CompoundStmtBits.NumStmts = Stmts.size();
assert(CompoundStmtBits.NumStmts == Stmts.size() &&
"NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!");
@@ -357,6 +377,11 @@ unsigned AsmStmt::getNumPlusOperands() const {
return Res;
}
+char GCCAsmStmt::AsmStringPiece::getModifier() const {
+ assert(isOperand() && "Only Operands can have modifiers.");
+ return isLetter(Str[0]) ? Str[0] : '\0';
+}
+
StringRef GCCAsmStmt::getClobber(unsigned i) const {
return getClobberStringLiteral(i)->getString();
}
@@ -517,17 +542,25 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
CurStringPiece.clear();
}
- // Handle %x4 and %x[foo] by capturing x as the modifier character.
- char Modifier = '\0';
+ // Handle operands that have asmSymbolicName (e.g., %x[foo]) and those that
+ // don't (e.g., %x4). 'x' following the '%' is the constraint modifier.
+
+ const char *Begin = CurPtr - 1; // Points to the character following '%'.
+ const char *Percent = Begin - 1; // Points to '%'.
+
if (isLetter(EscapedChar)) {
if (CurPtr == StrEnd) { // Premature end.
DiagOffs = CurPtr-StrStart-1;
return diag::err_asm_invalid_escape;
}
- Modifier = EscapedChar;
EscapedChar = *CurPtr++;
}
+ const TargetInfo &TI = C.getTargetInfo();
+ const SourceManager &SM = C.getSourceManager();
+ const LangOptions &LO = C.getLangOpts();
+
+ // Handle operands that don't have asmSymbolicName (e.g., %x4).
if (isDigit(EscapedChar)) {
// %n - Assembler operand n
unsigned N = 0;
@@ -543,11 +576,21 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
return diag::err_asm_invalid_operand_number;
}
- Pieces.push_back(AsmStringPiece(N, Modifier));
+ // Str contains "x4" (Operand without the leading %).
+ std::string Str(Begin, CurPtr - Begin);
+
+ // (BeginLoc, EndLoc) represents the range of the operand we are currently
+ // processing. Unlike Str, the range includes the leading '%'.
+ SourceLocation BeginLoc =
+ getAsmString()->getLocationOfByte(Percent - StrStart, SM, LO, TI);
+ SourceLocation EndLoc =
+ getAsmString()->getLocationOfByte(CurPtr - StrStart, SM, LO, TI);
+
+ Pieces.push_back(AsmStringPiece(N, Str, BeginLoc, EndLoc));
continue;
}
- // Handle %[foo], a symbolic operand reference.
+ // Handle operands that have asmSymbolicName (e.g., %x[foo]).
if (EscapedChar == '[') {
DiagOffs = CurPtr-StrStart-1;
@@ -566,7 +609,18 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
DiagOffs = CurPtr-StrStart;
return diag::err_asm_unknown_symbolic_operand_name;
}
- Pieces.push_back(AsmStringPiece(N, Modifier));
+
+ // Str contains "x[foo]" (Operand without the leading %).
+ std::string Str(Begin, NameEnd + 1 - Begin);
+
+ // (BeginLoc, EndLoc) represents the range of the operand we are currently
+ // processing. Unlike Str, the range includes the leading '%'.
+ SourceLocation BeginLoc =
+ getAsmString()->getLocationOfByte(Percent - StrStart, SM, LO, TI);
+ SourceLocation EndLoc =
+ getAsmString()->getLocationOfByte(NameEnd + 1 - StrStart, SM, LO, TI);
+
+ Pieces.push_back(AsmStringPiece(N, Str, BeginLoc, EndLoc));
CurPtr = NameEnd+1;
continue;
@@ -956,20 +1010,22 @@ Expr* ReturnStmt::getRetValue() {
return cast_or_null<Expr>(RetExpr);
}
-SEHTryStmt::SEHTryStmt(bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock,
- Stmt *Handler, int HandlerIndex, int HandlerParentIndex)
- : Stmt(SEHTryStmtClass), IsCXXTry(IsCXXTry), TryLoc(TryLoc),
- HandlerIndex(HandlerIndex), HandlerParentIndex(HandlerParentIndex) {
- Children[TRY] = TryBlock;
+SEHTryStmt::SEHTryStmt(bool IsCXXTry,
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler)
+ : Stmt(SEHTryStmtClass),
+ IsCXXTry(IsCXXTry),
+ TryLoc(TryLoc)
+{
+ Children[TRY] = TryBlock;
Children[HANDLER] = Handler;
}
-SEHTryStmt *SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry,
+SEHTryStmt* SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry,
SourceLocation TryLoc, Stmt *TryBlock,
- Stmt *Handler, int HandlerIndex,
- int HandlerParentIndex) {
- return new (C) SEHTryStmt(IsCXXTry, TryLoc, TryBlock, Handler, HandlerIndex,
- HandlerParentIndex);
+ Stmt *Handler) {
+ return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler);
}
SEHExceptStmt* SEHTryStmt::getExceptHandler() const {
@@ -1120,17 +1176,24 @@ StmtRange OMPClause::children() {
llvm_unreachable("unknown OMPClause");
}
-OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc,
- ArrayRef<Expr *> VL) {
+void OMPPrivateClause::setPrivateCopies(ArrayRef<Expr *> VL) {
+ assert(VL.size() == varlist_size() &&
+ "Number of private copies is not the same as the preallocated buffer");
+ std::copy(VL.begin(), VL.end(), varlist_end());
+}
+
+OMPPrivateClause *
+OMPPrivateClause::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL) {
+ // Allocate space for private variables and initializer expressions.
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
- OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc,
- EndLoc, VL.size());
+ 2 * sizeof(Expr *) * VL.size());
+ OMPPrivateClause *Clause =
+ new (Mem) OMPPrivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
+ Clause->setPrivateCopies(PrivateVL);
return Clause;
}
@@ -1138,23 +1201,35 @@ OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ 2 * sizeof(Expr *) * N);
return new (Mem) OMPPrivateClause(N);
}
-OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc,
- ArrayRef<Expr *> VL) {
+void OMPFirstprivateClause::setPrivateCopies(ArrayRef<Expr *> VL) {
+ assert(VL.size() == varlist_size() &&
+ "Number of private copies is not the same as the preallocated buffer");
+ std::copy(VL.begin(), VL.end(), varlist_end());
+}
+
+void OMPFirstprivateClause::setInits(ArrayRef<Expr *> VL) {
+ assert(VL.size() == varlist_size() &&
+ "Number of inits is not the same as the preallocated buffer");
+ std::copy(VL.begin(), VL.end(), getPrivateCopies().end());
+}
+
+OMPFirstprivateClause *
+OMPFirstprivateClause::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
+ ArrayRef<Expr *> InitVL) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
- OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc,
- LParenLoc,
- EndLoc,
- VL.size());
+ 3 * sizeof(Expr *) * VL.size());
+ OMPFirstprivateClause *Clause =
+ new (Mem) OMPFirstprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
+ Clause->setPrivateCopies(PrivateVL);
+ Clause->setInits(InitVL);
return Clause;
}
@@ -1162,7 +1237,7 @@ OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ 3 * sizeof(Expr *) * N);
return new (Mem) OMPFirstprivateClause(N);
}
@@ -1306,6 +1381,24 @@ void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) {
std::copy(Clauses.begin(), Clauses.end(), getClauses().begin());
}
+void OMPLoopDirective::setCounters(ArrayRef<Expr *> A) {
+ assert(A.size() == getCollapsedNumber() &&
+ "Number of loop counters is not the same as the collapsed number");
+ std::copy(A.begin(), A.end(), getCounters().begin());
+}
+
+void OMPLoopDirective::setUpdates(ArrayRef<Expr *> A) {
+ assert(A.size() == getCollapsedNumber() &&
+ "Number of counter updates is not the same as the collapsed number");
+ std::copy(A.begin(), A.end(), getUpdates().begin());
+}
+
+void OMPLoopDirective::setFinals(ArrayRef<Expr *> A) {
+ assert(A.size() == getCollapsedNumber() &&
+ "Number of counter finals is not the same as the collapsed number");
+ std::copy(A.begin(), A.end(), getFinals().begin());
+}
+
OMPReductionClause *OMPReductionClause::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
@@ -1348,6 +1441,21 @@ OMPFlushClause *OMPFlushClause::CreateEmpty(const ASTContext &C, unsigned N) {
return new (Mem) OMPFlushClause(N);
}
+const OMPClause *
+OMPExecutableDirective::getSingleClause(OpenMPClauseKind K) const {
+ auto ClauseFilter =
+ [=](const OMPClause *C) -> bool { return C->getClauseKind() == K; };
+ OMPExecutableDirective::filtered_clause_iterator<decltype(ClauseFilter)> I(
+ clauses(), ClauseFilter);
+
+ if (I) {
+ auto *Clause = *I;
+ assert(!++I && "There are at least 2 clauses of the specified kind");
+ return Clause;
+ }
+ return nullptr;
+}
+
OMPParallelDirective *OMPParallelDirective::Create(
const ASTContext &C,
SourceLocation StartLoc,
@@ -1378,15 +1486,27 @@ OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C,
OMPSimdDirective *
OMPSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, unsigned CollapsedNum,
- ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSimdDirective),
llvm::alignOf<OMPClause *>());
void *Mem =
- C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_simd));
OMPSimdDirective *Dir = new (Mem)
OMPSimdDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size());
Dir->setClauses(Clauses);
Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond, Exprs.SeparatedCond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
return Dir;
}
@@ -1397,22 +1517,42 @@ OMPSimdDirective *OMPSimdDirective::CreateEmpty(const ASTContext &C,
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSimdDirective),
llvm::alignOf<OMPClause *>());
void *Mem =
- C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_simd));
return new (Mem) OMPSimdDirective(CollapsedNum, NumClauses);
}
OMPForDirective *
OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, unsigned CollapsedNum,
- ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForDirective),
llvm::alignOf<OMPClause *>());
void *Mem =
- C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for));
OMPForDirective *Dir =
new (Mem) OMPForDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size());
Dir->setClauses(Clauses);
Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond, Exprs.SeparatedCond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
return Dir;
}
@@ -1423,10 +1563,57 @@ OMPForDirective *OMPForDirective::CreateEmpty(const ASTContext &C,
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForDirective),
llvm::alignOf<OMPClause *>());
void *Mem =
- C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for));
return new (Mem) OMPForDirective(CollapsedNum, NumClauses);
}
+OMPForSimdDirective *
+OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation EndLoc, unsigned CollapsedNum,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForSimdDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for_simd));
+ OMPForSimdDirective *Dir = new (Mem)
+ OMPForSimdDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond, Exprs.SeparatedCond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ return Dir;
+}
+
+OMPForSimdDirective *OMPForSimdDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForSimdDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for_simd));
+ return new (Mem) OMPForSimdDirective(CollapsedNum, NumClauses);
+}
+
OMPSectionsDirective *OMPSectionsDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
@@ -1537,19 +1724,36 @@ OMPCriticalDirective *OMPCriticalDirective::CreateEmpty(const ASTContext &C,
return new (Mem) OMPCriticalDirective();
}
-OMPParallelForDirective *
-OMPParallelForDirective::Create(const ASTContext &C, SourceLocation StartLoc,
- SourceLocation EndLoc, unsigned CollapsedNum,
- ArrayRef<OMPClause *> Clauses,
- Stmt *AssociatedStmt) {
+OMPParallelForDirective *OMPParallelForDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective),
llvm::alignOf<OMPClause *>());
- void *Mem =
- C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_parallel_for));
OMPParallelForDirective *Dir = new (Mem)
OMPParallelForDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size());
Dir->setClauses(Clauses);
Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond, Exprs.SeparatedCond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
return Dir;
}
@@ -1558,11 +1762,57 @@ OMPParallelForDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
unsigned CollapsedNum, EmptyShell) {
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective),
llvm::alignOf<OMPClause *>());
- void *Mem =
- C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_parallel_for));
return new (Mem) OMPParallelForDirective(CollapsedNum, NumClauses);
}
+OMPParallelForSimdDirective *OMPParallelForSimdDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForSimdDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_parallel_for_simd));
+ OMPParallelForSimdDirective *Dir = new (Mem) OMPParallelForSimdDirective(
+ StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond, Exprs.SeparatedCond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ return Dir;
+}
+
+OMPParallelForSimdDirective *
+OMPParallelForSimdDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForSimdDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_parallel_for_simd));
+ return new (Mem) OMPParallelForSimdDirective(CollapsedNum, NumClauses);
+}
+
OMPParallelSectionsDirective *OMPParallelSectionsDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
@@ -1678,3 +1928,103 @@ OMPFlushDirective *OMPFlushDirective::CreateEmpty(const ASTContext &C,
return new (Mem) OMPFlushDirective(NumClauses);
}
+OMPOrderedDirective *OMPOrderedDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPOrderedDirective),
+ llvm::alignOf<Stmt *>());
+ void *Mem = C.Allocate(Size + sizeof(Stmt *));
+ OMPOrderedDirective *Dir = new (Mem) OMPOrderedDirective(StartLoc, EndLoc);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPOrderedDirective *OMPOrderedDirective::CreateEmpty(const ASTContext &C,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPOrderedDirective),
+ llvm::alignOf<Stmt *>());
+ void *Mem = C.Allocate(Size + sizeof(Stmt *));
+ return new (Mem) OMPOrderedDirective();
+}
+
+OMPAtomicDirective *
+OMPAtomicDirective::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt, Expr *X, Expr *V, Expr *E) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ 4 * sizeof(Stmt *));
+ OMPAtomicDirective *Dir =
+ new (Mem) OMPAtomicDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setX(X);
+ Dir->setV(V);
+ Dir->setExpr(E);
+ return Dir;
+}
+
+OMPAtomicDirective *OMPAtomicDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + 4 * sizeof(Stmt *));
+ return new (Mem) OMPAtomicDirective(NumClauses);
+}
+
+OMPTargetDirective *OMPTargetDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTargetDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ OMPTargetDirective *Dir =
+ new (Mem) OMPTargetDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPTargetDirective *OMPTargetDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTargetDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPTargetDirective(NumClauses);
+}
+
+OMPTeamsDirective *OMPTeamsDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTeamsDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ OMPTeamsDirective *Dir =
+ new (Mem) OMPTeamsDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPTeamsDirective *OMPTeamsDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTeamsDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPTeamsDirective(NumClauses);
+}
+
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 1fdad9f4272c..927a679244b5 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -665,6 +665,22 @@ void OMPClausePrinter::VisitOMPMergeableClause(OMPMergeableClause *) {
OS << "mergeable";
}
+void OMPClausePrinter::VisitOMPReadClause(OMPReadClause *) { OS << "read"; }
+
+void OMPClausePrinter::VisitOMPWriteClause(OMPWriteClause *) { OS << "write"; }
+
+void OMPClausePrinter::VisitOMPUpdateClause(OMPUpdateClause *) {
+ OS << "update";
+}
+
+void OMPClausePrinter::VisitOMPCaptureClause(OMPCaptureClause *) {
+ OS << "capture";
+}
+
+void OMPClausePrinter::VisitOMPSeqCstClause(OMPSeqCstClause *) {
+ OS << "seq_cst";
+}
+
template<typename T>
void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) {
for (typename T::varlist_iterator I = Node->varlist_begin(),
@@ -820,6 +836,11 @@ void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) {
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPForSimdDirective(OMPForSimdDirective *Node) {
+ Indent() << "#pragma omp for simd ";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPSectionsDirective(OMPSectionsDirective *Node) {
Indent() << "#pragma omp sections ";
PrintOMPExecutableDirective(Node);
@@ -855,6 +876,12 @@ void StmtPrinter::VisitOMPParallelForDirective(OMPParallelForDirective *Node) {
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPParallelForSimdDirective(
+ OMPParallelForSimdDirective *Node) {
+ Indent() << "#pragma omp parallel for simd ";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPParallelSectionsDirective(
OMPParallelSectionsDirective *Node) {
Indent() << "#pragma omp parallel sections ";
@@ -886,6 +913,26 @@ void StmtPrinter::VisitOMPFlushDirective(OMPFlushDirective *Node) {
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPOrderedDirective(OMPOrderedDirective *Node) {
+ Indent() << "#pragma omp ordered";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPAtomicDirective(OMPAtomicDirective *Node) {
+ Indent() << "#pragma omp atomic ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPTargetDirective(OMPTargetDirective *Node) {
+ Indent() << "#pragma omp target ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPTeamsDirective(OMPTeamsDirective *Node) {
+ Indent() << "#pragma omp teams ";
+ PrintOMPExecutableDirective(Node);
+}
+
//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
@@ -957,28 +1004,7 @@ void StmtPrinter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) {
}
void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
- switch (Node->getIdentType()) {
- default:
- llvm_unreachable("unknown case");
- case PredefinedExpr::Func:
- OS << "__func__";
- break;
- case PredefinedExpr::Function:
- OS << "__FUNCTION__";
- break;
- case PredefinedExpr::FuncDName:
- OS << "__FUNCDNAME__";
- break;
- case PredefinedExpr::FuncSig:
- OS << "__FUNCSIG__";
- break;
- case PredefinedExpr::LFunction:
- OS << "L__FUNCTION__";
- break;
- case PredefinedExpr::PrettyFunction:
- OS << "__PRETTY_FUNCTION__";
- break;
- }
+ OS << PredefinedExpr::getIdentTypeName(Node->getIdentType());
}
void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
@@ -1716,6 +1742,8 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
case LCK_ByCopy:
OS << C->getCapturedVar()->getName();
break;
+ case LCK_VLAType:
+ llvm_unreachable("VLA type in explicit captures.");
}
if (C->isInitCapture())
@@ -1994,6 +2022,20 @@ void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){
PrintExpr(Node->GetTemporaryExpr());
}
+void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
+ OS << "(";
+ if (E->getLHS()) {
+ PrintExpr(E->getLHS());
+ OS << " " << BinaryOperator::getOpcodeStr(E->getOperator()) << " ";
+ }
+ OS << "...";
+ if (E->getRHS()) {
+ OS << " " << BinaryOperator::getOpcodeStr(E->getOperator()) << " ";
+ PrintExpr(E->getRHS());
+ }
+ OS << ")";
+}
+
// Obj-C
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
@@ -2138,6 +2180,11 @@ void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
PrintExpr(Node->getSourceExpr());
}
+void StmtPrinter::VisitTypoExpr(TypoExpr *Node) {
+ // TODO: Print something reasonable for a TypoExpr, if necessary.
+ assert(false && "Cannot print TypoExpr nodes");
+}
+
void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
OS << "__builtin_astype(";
PrintExpr(Node->getSrcExpr());
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index f44f25c96aba..d1f25d63b3f9 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -310,18 +310,38 @@ void OMPClauseProfiler::VisitOMPUntiedClause(const OMPUntiedClause *) {}
void OMPClauseProfiler::VisitOMPMergeableClause(const OMPMergeableClause *) {}
+void OMPClauseProfiler::VisitOMPReadClause(const OMPReadClause *) {}
+
+void OMPClauseProfiler::VisitOMPWriteClause(const OMPWriteClause *) {}
+
+void OMPClauseProfiler::VisitOMPUpdateClause(const OMPUpdateClause *) {}
+
+void OMPClauseProfiler::VisitOMPCaptureClause(const OMPCaptureClause *) {}
+
+void OMPClauseProfiler::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
+
template<typename T>
void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
- for (auto *I : Node->varlists())
- Profiler->VisitStmt(I);
+ for (auto *E : Node->varlists()) {
+ Profiler->VisitStmt(E);
+ }
}
void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->private_copies()) {
+ Profiler->VisitStmt(E);
+ }
}
-void OMPClauseProfiler::VisitOMPFirstprivateClause(
- const OMPFirstprivateClause *C) {
+void
+OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->private_copies()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->inits()) {
+ Profiler->VisitStmt(E);
+ }
}
void
OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
@@ -368,16 +388,24 @@ StmtProfiler::VisitOMPExecutableDirective(const OMPExecutableDirective *S) {
P.Visit(*I);
}
+void StmtProfiler::VisitOMPLoopDirective(const OMPLoopDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
void StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) {
VisitOMPExecutableDirective(S);
}
void StmtProfiler::VisitOMPSimdDirective(const OMPSimdDirective *S) {
- VisitOMPExecutableDirective(S);
+ VisitOMPLoopDirective(S);
}
void StmtProfiler::VisitOMPForDirective(const OMPForDirective *S) {
- VisitOMPExecutableDirective(S);
+ VisitOMPLoopDirective(S);
+}
+
+void StmtProfiler::VisitOMPForSimdDirective(const OMPForSimdDirective *S) {
+ VisitOMPLoopDirective(S);
}
void StmtProfiler::VisitOMPSectionsDirective(const OMPSectionsDirective *S) {
@@ -403,7 +431,12 @@ void StmtProfiler::VisitOMPCriticalDirective(const OMPCriticalDirective *S) {
void
StmtProfiler::VisitOMPParallelForDirective(const OMPParallelForDirective *S) {
- VisitOMPExecutableDirective(S);
+ VisitOMPLoopDirective(S);
+}
+
+void StmtProfiler::VisitOMPParallelForSimdDirective(
+ const OMPParallelForSimdDirective *S) {
+ VisitOMPLoopDirective(S);
}
void StmtProfiler::VisitOMPParallelSectionsDirective(
@@ -431,6 +464,22 @@ void StmtProfiler::VisitOMPFlushDirective(const OMPFlushDirective *S) {
VisitOMPExecutableDirective(S);
}
+void StmtProfiler::VisitOMPOrderedDirective(const OMPOrderedDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPAtomicDirective(const OMPAtomicDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPTargetDirective(const OMPTargetDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPTeamsDirective(const OMPTeamsDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
void StmtProfiler::VisitExpr(const Expr *S) {
VisitStmt(S);
}
@@ -452,6 +501,7 @@ void StmtProfiler::VisitPredefinedExpr(const PredefinedExpr *S) {
void StmtProfiler::VisitIntegerLiteral(const IntegerLiteral *S) {
VisitExpr(S);
S->getValue().Profile(ID);
+ ID.AddInteger(S->getType()->castAs<BuiltinType>()->getKind());
}
void StmtProfiler::VisitCharacterLiteral(const CharacterLiteral *S) {
@@ -464,6 +514,7 @@ void StmtProfiler::VisitFloatingLiteral(const FloatingLiteral *S) {
VisitExpr(S);
S->getValue().Profile(ID);
ID.AddBoolean(S->isExact());
+ ID.AddInteger(S->getType()->castAs<BuiltinType>()->getKind());
}
void StmtProfiler::VisitImaginaryLiteral(const ImaginaryLiteral *S) {
@@ -1018,6 +1069,8 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
VisitDecl(C->getCapturedVar());
ID.AddBoolean(C->isPackExpansion());
break;
+ case LCK_VLAType:
+ llvm_unreachable("VLA type in explicit captures.");
}
}
// Note: If we actually needed to be able to match lambda
@@ -1187,10 +1240,19 @@ void StmtProfiler::VisitMaterializeTemporaryExpr(
VisitExpr(S);
}
+void StmtProfiler::VisitCXXFoldExpr(const CXXFoldExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getOperator());
+}
+
void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
VisitExpr(E);
}
+void StmtProfiler::VisitTypoExpr(const TypoExpr *E) {
+ VisitExpr(E);
+}
+
void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) {
VisitExpr(S);
}
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index ac6a754fe733..f8b73cb8f89a 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -33,11 +33,26 @@ using namespace clang;
/// \param TemplArg the TemplateArgument instance to print.
///
/// \param Out the raw_ostream instance to use for printing.
+///
+/// \param Policy the printing policy for EnumConstantDecl printing.
static void printIntegral(const TemplateArgument &TemplArg,
- raw_ostream &Out) {
+ raw_ostream &Out, const PrintingPolicy& Policy) {
const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr();
const llvm::APSInt &Val = TemplArg.getAsIntegral();
+ if (const EnumType *ET = T->getAs<EnumType>()) {
+ for (const EnumConstantDecl* ECD : ET->getDecl()->enumerators()) {
+ // In Sema::CheckTemplateArugment, enum template arguments value are
+ // extended to the size of the integer underlying the enum type. This
+ // may create a size difference between the enum value and template
+ // argument value, requiring isSameValue here instead of operator==.
+ if (llvm::APSInt::isSameValue(ECD->getInitVal(), Val)) {
+ ECD->printQualifiedName(Out, Policy);
+ return;
+ }
+ }
+ }
+
if (T->isBooleanType()) {
Out << (Val.getBoolValue() ? "true" : "false");
} else if (T->isCharType()) {
@@ -90,7 +105,8 @@ bool TemplateArgument::isDependent() const {
llvm_unreachable("Should not have a NULL template argument");
case Type:
- return getAsType()->isDependentType();
+ return getAsType()->isDependentType() ||
+ isa<PackExpansionType>(getAsType());
case Template:
return getAsTemplate().isDependent();
@@ -111,7 +127,8 @@ bool TemplateArgument::isDependent() const {
return false;
case Expression:
- return (getAsExpr()->isTypeDependent() || getAsExpr()->isValueDependent());
+ return (getAsExpr()->isTypeDependent() || getAsExpr()->isValueDependent() ||
+ isa<PackExpansionExpr>(getAsExpr()));
case Pack:
for (const auto &P : pack_elements())
@@ -294,8 +311,7 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
return TypeOrValue.V == Other.TypeOrValue.V;
case Declaration:
- return getAsDecl() == Other.getAsDecl() &&
- isDeclForReferenceParam() && Other.isDeclForReferenceParam();
+ return getAsDecl() == Other.getAsDecl();
case Integral:
return getIntegralType() == Other.getIntegralType() &&
@@ -377,7 +393,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
break;
case Integral: {
- printIntegral(*this, Out);
+ printIntegral(*this, Out, Policy);
break;
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 167787430294..e4f364d04f86 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -70,7 +70,7 @@ bool QualType::isConstant(QualType T, ASTContext &Ctx) {
if (const ArrayType *AT = Ctx.getAsArrayType(T))
return AT->getElementType().isConstant(Ctx);
- return false;
+ return T.getAddressSpace() == LangAS::opencl_constant;
}
unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context,
@@ -378,9 +378,10 @@ bool Type::isInterfaceType() const {
return false;
}
bool Type::isStructureOrClassType() const {
- if (const RecordType *RT = getAs<RecordType>())
- return RT->getDecl()->isStruct() || RT->getDecl()->isClass() ||
- RT->getDecl()->isInterface();
+ if (const RecordType *RT = getAs<RecordType>()) {
+ RecordDecl *RD = RT->getDecl();
+ return RD->isStruct() || RD->isClass() || RD->isInterface();
+ }
return false;
}
bool Type::isVoidPointerType() const {
@@ -540,10 +541,13 @@ const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
}
CXXRecordDecl *Type::getAsCXXRecordDecl() const {
- if (const RecordType *RT = getAs<RecordType>())
- return dyn_cast<CXXRecordDecl>(RT->getDecl());
- else if (const InjectedClassNameType *Injected
- = getAs<InjectedClassNameType>())
+ return dyn_cast_or_null<CXXRecordDecl>(getAsTagDecl());
+}
+
+TagDecl *Type::getAsTagDecl() const {
+ if (const auto *TT = getAs<TagType>())
+ return cast<TagDecl>(TT->getDecl());
+ if (const auto *Injected = getAs<InjectedClassNameType>())
return Injected->getDecl();
return nullptr;
@@ -1147,7 +1151,7 @@ bool Type::isLiteralType(const ASTContext &Ctx) const {
// C++1y [basic.types]p10:
// A type is a literal type if it is:
// -- cv void; or
- if (Ctx.getLangOpts().CPlusPlus1y && isVoidType())
+ if (Ctx.getLangOpts().CPlusPlus14 && isVoidType())
return true;
// C++11 [basic.types]p10:
@@ -1577,6 +1581,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_X86FastCall: return "fastcall";
case CC_X86ThisCall: return "thiscall";
case CC_X86Pascal: return "pascal";
+ case CC_X86VectorCall: return "vectorcall";
case CC_X86_64Win64: return "ms_abi";
case CC_X86_64SysV: return "sysv_abi";
case CC_AAPCS: return "aapcs";
@@ -1591,18 +1596,21 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
QualType canonical,
const ExtProtoInfo &epi)
- : FunctionType(FunctionProto, result, epi.TypeQuals, canonical,
+ : FunctionType(FunctionProto, result, canonical,
result->isDependentType(),
result->isInstantiationDependentType(),
result->isVariablyModifiedType(),
result->containsUnexpandedParameterPack(), epi.ExtInfo),
- NumParams(params.size()), NumExceptions(epi.NumExceptions),
- ExceptionSpecType(epi.ExceptionSpecType),
+ NumParams(params.size()),
+ NumExceptions(epi.ExceptionSpec.Exceptions.size()),
+ ExceptionSpecType(epi.ExceptionSpec.Type),
HasAnyConsumedParams(epi.ConsumedParameters != nullptr),
- Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn),
- RefQualifier(epi.RefQualifier) {
+ Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn) {
assert(NumParams == params.size() && "function has too many parameters");
+ FunctionTypeBits.TypeQuals = epi.TypeQuals;
+ FunctionTypeBits.RefQualifier = epi.RefQualifier;
+
// Fill in the trailing argument array.
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
for (unsigned i = 0; i != NumParams; ++i) {
@@ -1620,36 +1628,38 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
if (getExceptionSpecType() == EST_Dynamic) {
// Fill in the exception array.
QualType *exnSlot = argSlot + NumParams;
- for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
- if (epi.Exceptions[i]->isDependentType())
- setDependent();
- else if (epi.Exceptions[i]->isInstantiationDependentType())
+ unsigned I = 0;
+ for (QualType ExceptionType : epi.ExceptionSpec.Exceptions) {
+ // Note that a dependent exception specification does *not* make
+ // a type dependent; it's not even part of the C++ type system.
+ if (ExceptionType->isInstantiationDependentType())
setInstantiationDependent();
-
- if (epi.Exceptions[i]->containsUnexpandedParameterPack())
+
+ if (ExceptionType->containsUnexpandedParameterPack())
setContainsUnexpandedParameterPack();
- exnSlot[i] = epi.Exceptions[i];
+ exnSlot[I++] = ExceptionType;
}
} else if (getExceptionSpecType() == EST_ComputedNoexcept) {
// Store the noexcept expression and context.
Expr **noexSlot = reinterpret_cast<Expr **>(argSlot + NumParams);
- *noexSlot = epi.NoexceptExpr;
-
- if (epi.NoexceptExpr) {
- if (epi.NoexceptExpr->isValueDependent()
- || epi.NoexceptExpr->isTypeDependent())
- setDependent();
- else if (epi.NoexceptExpr->isInstantiationDependent())
+ *noexSlot = epi.ExceptionSpec.NoexceptExpr;
+
+ if (epi.ExceptionSpec.NoexceptExpr) {
+ if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() ||
+ epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent())
setInstantiationDependent();
+
+ if (epi.ExceptionSpec.NoexceptExpr->containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
}
} else if (getExceptionSpecType() == EST_Uninstantiated) {
// Store the function decl from which we will resolve our
// exception specification.
FunctionDecl **slot =
reinterpret_cast<FunctionDecl **>(argSlot + NumParams);
- slot[0] = epi.ExceptionSpecDecl;
- slot[1] = epi.ExceptionSpecTemplate;
+ slot[0] = epi.ExceptionSpec.SourceDecl;
+ slot[1] = epi.ExceptionSpec.SourceTemplate;
// This exception specification doesn't make the type dependent, because
// it's not instantiated as part of instantiating the type.
} else if (getExceptionSpecType() == EST_Unevaluated) {
@@ -1657,7 +1667,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
// exception specification.
FunctionDecl **slot =
reinterpret_cast<FunctionDecl **>(argSlot + NumParams);
- slot[0] = epi.ExceptionSpecDecl;
+ slot[0] = epi.ExceptionSpec.SourceDecl;
}
if (epi.ConsumedParameters) {
@@ -1667,6 +1677,18 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
}
}
+bool FunctionProtoType::hasDependentExceptionSpec() const {
+ if (Expr *NE = getNoexceptExpr())
+ return NE->isValueDependent();
+ for (QualType ET : exceptions())
+ // A pack expansion with a non-dependent pattern is still dependent,
+ // because we don't know whether the pattern is in the exception spec
+ // or not (that depends on whether the pack has 0 expansions).
+ if (ET->isDependentType() || ET->getAs<PackExpansionType>())
+ return true;
+ return false;
+}
+
FunctionProtoType::NoexceptResult
FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const {
ExceptionSpecificationType est = getExceptionSpecType();
@@ -1755,20 +1777,21 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
assert(!(unsigned(epi.Variadic) & ~1) &&
!(unsigned(epi.TypeQuals) & ~255) &&
!(unsigned(epi.RefQualifier) & ~3) &&
- !(unsigned(epi.ExceptionSpecType) & ~7) &&
+ !(unsigned(epi.ExceptionSpec.Type) & ~15) &&
"Values larger than expected.");
ID.AddInteger(unsigned(epi.Variadic) +
(epi.TypeQuals << 1) +
(epi.RefQualifier << 9) +
- (epi.ExceptionSpecType << 11));
- if (epi.ExceptionSpecType == EST_Dynamic) {
- for (unsigned i = 0; i != epi.NumExceptions; ++i)
- ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());
- } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){
- epi.NoexceptExpr->Profile(ID, Context, false);
- } else if (epi.ExceptionSpecType == EST_Uninstantiated ||
- epi.ExceptionSpecType == EST_Unevaluated) {
- ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl());
+ (epi.ExceptionSpec.Type << 11));
+ if (epi.ExceptionSpec.Type == EST_Dynamic) {
+ for (QualType Ex : epi.ExceptionSpec.Exceptions)
+ ID.AddPointer(Ex.getAsOpaquePtr());
+ } else if (epi.ExceptionSpec.Type == EST_ComputedNoexcept &&
+ epi.ExceptionSpec.NoexceptExpr) {
+ epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, false);
+ } else if (epi.ExceptionSpec.Type == EST_Uninstantiated ||
+ epi.ExceptionSpec.Type == EST_Unevaluated) {
+ ID.AddPointer(epi.ExceptionSpec.SourceDecl->getCanonicalDecl());
}
if (epi.ConsumedParameters) {
for (unsigned i = 0; i != NumParams; ++i)
@@ -1909,6 +1932,7 @@ bool AttributedType::isCallingConv() const {
case attr_fastcall:
case attr_stdcall:
case attr_thiscall:
+ case attr_vectorcall:
case attr_pascal:
case attr_ms_abi:
case attr_sysv_abi:
@@ -1976,32 +2000,14 @@ anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N,
return false;
}
-#ifndef NDEBUG
-static bool
-anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N,
- bool &InstantiationDependent) {
- for (unsigned i = 0; i != N; ++i) {
- if (Args[i].isDependent()) {
- InstantiationDependent = true;
- return true;
- }
-
- if (Args[i].isInstantiationDependent())
- InstantiationDependent = true;
- }
- return false;
-}
-#endif
-
TemplateSpecializationType::
TemplateSpecializationType(TemplateName T,
const TemplateArgument *Args, unsigned NumArgs,
QualType Canon, QualType AliasedType)
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
- Canon.isNull()? T.isDependent() : Canon->isDependentType(),
- Canon.isNull()? T.isDependent()
- : Canon->isInstantiationDependentType(),
+ Canon.isNull()? true : Canon->isDependentType(),
+ Canon.isNull()? true : Canon->isInstantiationDependentType(),
false,
T.containsUnexpandedParameterPack()),
Template(T), NumArgs(NumArgs), TypeAlias(!AliasedType.isNull()) {
@@ -2011,18 +2017,11 @@ TemplateSpecializationType(TemplateName T,
T.getKind() == TemplateName::SubstTemplateTemplateParm ||
T.getKind() == TemplateName::SubstTemplateTemplateParmPack) &&
"Unexpected template name for TemplateSpecializationType");
- bool InstantiationDependent;
- (void)InstantiationDependent;
- assert((!Canon.isNull() ||
- T.isDependent() ||
- ::anyDependentTemplateArguments(Args, NumArgs,
- InstantiationDependent)) &&
- "No canonical type for non-dependent class template specialization");
TemplateArgument *TemplateArgs
= reinterpret_cast<TemplateArgument *>(this + 1);
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- // Update dependent and variably-modified bits.
+ // Update instantiation-dependent and variably-modified bits.
// 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:
@@ -2030,17 +2029,13 @@ TemplateSpecializationType(TemplateName T,
// U<T> is always non-dependent, irrespective of the type T.
// However, U<Ts> contains an unexpanded parameter pack, even though
// its expansion (and thus its desugared type) doesn't.
- if (Canon.isNull() && Args[Arg].isDependent())
- setDependent();
- else if (Args[Arg].isInstantiationDependent())
+ if (Args[Arg].isInstantiationDependent())
setInstantiationDependent();
-
if (Args[Arg].getKind() == TemplateArgument::Type &&
Args[Arg].getAsType()->isVariablyModifiedType())
setVariablyModified();
if (Args[Arg].containsUnexpandedParameterPack())
setContainsUnexpandedParameterPack();
-
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 208d695632a0..c069eb061739 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -312,6 +312,14 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
return TL;
}
+void TypeOfTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo>
+ ::initializeLocal(Context, Loc);
+ this->getLocalData()->UnderlyingTInfo = Context.getTrivialTypeSourceInfo(
+ getUnderlyingType(), Loc);
+}
+
void ElaboratedTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
setElaboratedKeywordLoc(Loc);
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 061473eb848d..e36fc175c449 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -673,6 +673,9 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
case CC_X86ThisCall:
OS << " __attribute__((thiscall))";
break;
+ case CC_X86VectorCall:
+ OS << " __attribute__((vectorcall))";
+ break;
case CC_X86Pascal:
OS << " __attribute__((pascal))";
break;
@@ -1235,6 +1238,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case AttributedType::attr_fastcall: OS << "fastcall"; break;
case AttributedType::attr_stdcall: OS << "stdcall"; break;
case AttributedType::attr_thiscall: OS << "thiscall"; break;
+ case AttributedType::attr_vectorcall: OS << "vectorcall"; break;
case AttributedType::attr_pascal: OS << "pascal"; break;
case AttributedType::attr_ms_abi: OS << "ms_abi"; break;
case AttributedType::attr_sysv_abi: OS << "sysv_abi"; break;
@@ -1428,18 +1432,6 @@ PrintTemplateArgumentList(raw_ostream &OS,
OS << '>';
}
-void QualType::dump(const char *msg) const {
- if (msg)
- llvm::errs() << msg << ": ";
- LangOptions LO;
- print(llvm::errs(), PrintingPolicy(LO), "identifier");
- llvm::errs() << '\n';
-}
-
-LLVM_DUMP_METHOD void QualType::dump() const { dump(nullptr); }
-
-LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); }
-
std::string Qualifiers::getAsString() const {
LangOptions LO;
return getAsString(PrintingPolicy(LO));
@@ -1498,6 +1490,9 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
case LangAS::opencl_constant:
OS << "__constant";
break;
+ case LangAS::opencl_generic:
+ OS << "__generic";
+ break;
default:
OS << "__attribute__((address_space(";
OS << addrspace;
diff --git a/lib/AST/VTTBuilder.cpp b/lib/AST/VTTBuilder.cpp
index c213d1cef6aa..53461ebbb812 100644
--- a/lib/AST/VTTBuilder.cpp
+++ b/lib/AST/VTTBuilder.cpp
@@ -105,7 +105,7 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
CharUnits BaseOffset;
if (I.isVirtual()) {
// Ignore virtual bases that we've already visited.
- if (!VBases.insert(BaseDecl))
+ if (!VBases.insert(BaseDecl).second)
continue;
BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
@@ -157,7 +157,7 @@ void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
// Check if this is a virtual base.
if (I.isVirtual()) {
// Check if we've seen this base before.
- if (!VBases.insert(BaseDecl))
+ if (!VBases.insert(BaseDecl).second)
continue;
CharUnits BaseOffset =
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index fa1127f58f9b..ddb1f057ac8e 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -64,7 +64,7 @@ public:
/// Method - The method decl of the overrider.
const CXXMethodDecl *Method;
- /// VirtualBase - The virtual base class subobject of this overridder.
+ /// VirtualBase - The virtual base class subobject of this overrider.
/// Note that this records the closest derived virtual base class subobject.
const CXXRecordDecl *VirtualBase;
@@ -389,7 +389,7 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
CharUnits BaseOffset;
if (B.isVirtual()) {
- if (!VisitedVirtualBases.insert(BaseDecl)) {
+ if (!VisitedVirtualBases.insert(BaseDecl).second) {
// We've visited this base before.
continue;
}
@@ -748,7 +748,7 @@ VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
// Check if this is a virtual base that we haven't visited before.
- if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl)) {
+ if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl).second) {
CharUnits Offset =
LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass;
@@ -1105,7 +1105,7 @@ namespace {
bool visit(const CXXMethodDecl *MD) {
// Don't recurse on this method if we've already collected it.
- return Methods->insert(MD);
+ return Methods->insert(MD).second;
}
};
}
@@ -1842,7 +1842,7 @@ void ItaniumVTableBuilder::DeterminePrimaryVirtualBases(
CharUnits BaseOffsetInLayoutClass;
if (B.isVirtual()) {
- if (!VBases.insert(BaseDecl))
+ if (!VBases.insert(BaseDecl).second)
continue;
const ASTRecordLayout &LayoutClassLayout =
@@ -1870,8 +1870,9 @@ void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
// Check if this base needs a vtable. (If it's virtual, not a primary base
// of some other class, and we haven't visited it before).
- if (B.isVirtual() && BaseDecl->isDynamicClass() &&
- !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) {
+ if (B.isVirtual() && BaseDecl->isDynamicClass() &&
+ !PrimaryVirtualBases.count(BaseDecl) &&
+ VBases.insert(BaseDecl).second) {
const ASTRecordLayout &MostDerivedClassLayout =
Context.getASTRecordLayout(MostDerivedClass);
CharUnits BaseOffset =
@@ -2390,6 +2391,7 @@ namespace {
// first vfptr whose table provides a compatible overridden method. In many
// cases, this permits the original vf-table entry to directly call
// the method instead of passing through a thunk.
+// See example before VFTableBuilder::ComputeThisOffset below.
//
// A compatible overridden method is one which does not have a non-trivial
// covariant-return adjustment.
@@ -2412,6 +2414,9 @@ namespace {
// a) a user-defined ctor/dtor
// and
// b) a method overriding a method in a virtual base.
+//
+// To get a better understanding of this code,
+// you might want to see examples in test/CodeGenCXX/microsoft-abi-vtables-*.cpp
class VFTableBuilder {
public:
@@ -2464,11 +2469,18 @@ private:
/// or used for vcalls in the most derived class.
bool Shadowed;
- MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex)
+ /// UsesExtraSlot - Indicates if this vftable slot was created because
+ /// any of the overridden slots required a return adjusting thunk.
+ bool UsesExtraSlot;
+
+ MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex,
+ bool UsesExtraSlot = false)
: VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex),
- Shadowed(false) {}
+ Shadowed(false), UsesExtraSlot(UsesExtraSlot) {}
- MethodInfo() : VBTableIndex(0), VFTableIndex(0), Shadowed(false) {}
+ MethodInfo()
+ : VBTableIndex(0), VFTableIndex(0), Shadowed(false),
+ UsesExtraSlot(false) {}
};
typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
@@ -2525,8 +2537,6 @@ private:
}
}
- bool NeedsReturnAdjustingThunk(const CXXMethodDecl *MD);
-
/// AddMethods - Add the methods of this base subobject and the relevant
/// subbases to the vftable we're currently laying out.
void AddMethods(BaseSubobject Base, unsigned BaseDepth,
@@ -2534,13 +2544,15 @@ private:
BasesSetVectorTy &VisitedBases);
void LayoutVFTable() {
- // FIXME: add support for RTTI when we have proper LLVM support for symbols
- // pointing to the middle of a section.
+ // RTTI data goes before all other entries.
+ if (HasRTTIComponent)
+ Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
BasesSetVectorTy VisitedBases;
AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, nullptr,
VisitedBases);
- assert(Components.size() && "vftable can't be empty");
+ assert((HasRTTIComponent ? Components.size() - 1 : Components.size()) &&
+ "vftable can't be empty");
assert(MethodVFTableLocations.empty());
for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
@@ -2561,13 +2573,6 @@ private:
}
}
- void ErrorUnsupported(StringRef Feature, SourceLocation Location) {
- clang::DiagnosticsEngine &Diags = Context.getDiagnostics();
- unsigned DiagID = Diags.getCustomDiagID(
- DiagnosticsEngine::Error, "v-table layout for %0 is not supported yet");
- Diags.Report(Context.getFullLoc(Location), DiagID) << Feature;
- }
-
public:
VFTableBuilder(MicrosoftVTableContext &VTables,
const CXXRecordDecl *MostDerivedClass, const VPtrInfo *Which)
@@ -2581,8 +2586,6 @@ public:
// definition of the vftable.
HasRTTIComponent = Context.getLangOpts().RTTIData &&
!MostDerivedClass->hasAttr<DLLImportAttr>();
- if (HasRTTIComponent)
- Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
LayoutVFTable();
@@ -2634,7 +2637,7 @@ struct InitialOverriddenDefinitionCollector {
if (OverriddenMD->size_overridden_methods() == 0)
Bases.insert(OverriddenMD->getParent());
// Don't recurse on this method if we've already collected it.
- return VisitedOverriddenMethods.insert(OverriddenMD);
+ return VisitedOverriddenMethods.insert(OverriddenMD).second;
}
};
@@ -2644,6 +2647,60 @@ static bool BaseInSet(const CXXBaseSpecifier *Specifier,
return Bases->count(Specifier->getType()->getAsCXXRecordDecl());
}
+// Let's study one class hierarchy as an example:
+// struct A {
+// virtual void f();
+// int x;
+// };
+//
+// struct B : virtual A {
+// virtual void f();
+// };
+//
+// Record layouts:
+// struct A:
+// 0 | (A vftable pointer)
+// 4 | int x
+//
+// struct B:
+// 0 | (B vbtable pointer)
+// 4 | struct A (virtual base)
+// 4 | (A vftable pointer)
+// 8 | int x
+//
+// Let's assume we have a pointer to the A part of an object of dynamic type B:
+// B b;
+// A *a = (A*)&b;
+// a->f();
+//
+// In this hierarchy, f() belongs to the vftable of A, so B::f() expects
+// "this" parameter to point at the A subobject, which is B+4.
+// In the B::f() prologue, it adjusts "this" back to B by subtracting 4,
+// performed as a *static* adjustment.
+//
+// Interesting thing happens when we alter the relative placement of A and B
+// subobjects in a class:
+// struct C : virtual B { };
+//
+// C c;
+// A *a = (A*)&c;
+// a->f();
+//
+// Respective record layout is:
+// 0 | (C vbtable pointer)
+// 4 | struct A (virtual base)
+// 4 | (A vftable pointer)
+// 8 | int x
+// 12 | struct B (virtual base)
+// 12 | (B vbtable pointer)
+//
+// The final overrider of f() in class C is still B::f(), so B+4 should be
+// passed as "this" to that code. However, "a" points at B-8, so the respective
+// vftable entry should hold a thunk that adds 12 to the "this" argument before
+// performing a tail call to B::f().
+//
+// With this example in mind, we can now calculate the 'this' argument offset
+// for the given method, relative to the beginning of the MostDerivedClass.
CharUnits
VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
InitialOverriddenDefinitionCollector Collector;
@@ -2723,6 +2780,104 @@ VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
return Ret;
}
+// Things are getting even more complex when the "this" adjustment has to
+// use a dynamic offset instead of a static one, or even two dynamic offsets.
+// This is sometimes required when a virtual call happens in the middle of
+// a non-most-derived class construction or destruction.
+//
+// Let's take a look at the following example:
+// struct A {
+// virtual void f();
+// };
+//
+// void foo(A *a) { a->f(); } // Knows nothing about siblings of A.
+//
+// struct B : virtual A {
+// virtual void f();
+// B() {
+// foo(this);
+// }
+// };
+//
+// struct C : virtual B {
+// virtual void f();
+// };
+//
+// Record layouts for these classes are:
+// struct A
+// 0 | (A vftable pointer)
+//
+// struct B
+// 0 | (B vbtable pointer)
+// 4 | (vtordisp for vbase A)
+// 8 | struct A (virtual base)
+// 8 | (A vftable pointer)
+//
+// struct C
+// 0 | (C vbtable pointer)
+// 4 | (vtordisp for vbase A)
+// 8 | struct A (virtual base) // A precedes B!
+// 8 | (A vftable pointer)
+// 12 | struct B (virtual base)
+// 12 | (B vbtable pointer)
+//
+// When one creates an object of type C, the C constructor:
+// - initializes all the vbptrs, then
+// - calls the A subobject constructor
+// (initializes A's vfptr with an address of A vftable), then
+// - calls the B subobject constructor
+// (initializes A's vfptr with an address of B vftable and vtordisp for A),
+// that in turn calls foo(), then
+// - initializes A's vfptr with an address of C vftable and zeroes out the
+// vtordisp
+// FIXME: if a structor knows it belongs to MDC, why doesn't it use a vftable
+// without vtordisp thunks?
+// FIXME: how are vtordisp handled in the presence of nooverride/final?
+//
+// When foo() is called, an object with a layout of class C has a vftable
+// referencing B::f() that assumes a B layout, so the "this" adjustments are
+// incorrect, unless an extra adjustment is done. This adjustment is called
+// "vtordisp adjustment". Vtordisp basically holds the difference between the
+// actual location of a vbase in the layout class and the location assumed by
+// the vftable of the class being constructed/destructed. Vtordisp is only
+// needed if "this" escapes a
+// structor (or we can't prove otherwise).
+// [i.e. vtordisp is a dynamic adjustment for a static adjustment, which is an
+// estimation of a dynamic adjustment]
+//
+// foo() gets a pointer to the A vbase and doesn't know anything about B or C,
+// so it just passes that pointer as "this" in a virtual call.
+// If there was no vtordisp, that would just dispatch to B::f().
+// However, B::f() assumes B+8 is passed as "this",
+// yet the pointer foo() passes along is B-4 (i.e. C+8).
+// An extra adjustment is needed, so we emit a thunk into the B vftable.
+// This vtordisp thunk subtracts the value of vtordisp
+// from the "this" argument (-12) before making a tailcall to B::f().
+//
+// Let's consider an even more complex example:
+// struct D : virtual B, virtual C {
+// D() {
+// foo(this);
+// }
+// };
+//
+// struct D
+// 0 | (D vbtable pointer)
+// 4 | (vtordisp for vbase A)
+// 8 | struct A (virtual base) // A precedes both B and C!
+// 8 | (A vftable pointer)
+// 12 | struct B (virtual base) // B precedes C!
+// 12 | (B vbtable pointer)
+// 16 | struct C (virtual base)
+// 16 | (C vbtable pointer)
+//
+// When D::D() calls foo(), we find ourselves in a thunk that should tailcall
+// to C::f(), which assumes C+8 as its "this" parameter. This time, foo()
+// passes along A, which is C-8. The A vtordisp holds
+// "D.vbptr[index_of_A] - offset_of_A_in_D"
+// and we statically know offset_of_A_in_D, so can get a pointer to D.
+// When we know it, we can make an extra vbtable lookup to locate the C vbase
+// and one extra static adjustment to calculate the expected value of C+8.
void VFTableBuilder::CalculateVtordispAdjustment(
FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset,
ThisAdjustment &TA) {
@@ -2740,9 +2895,9 @@ void VFTableBuilder::CalculateVtordispAdjustment(
// OK, now we know we need to use a vtordisp thunk.
// The implicit vtordisp field is located right before the vbase.
- CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
+ CharUnits OffsetOfVBaseWithVFPtr = VBaseMapEntry->second.VBaseOffset;
TA.Virtual.Microsoft.VtordispOffset =
- (VFPtrVBaseOffset - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4;
+ (OffsetOfVBaseWithVFPtr - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4;
// A simple vtordisp thunk will suffice if the final overrider is defined
// in either the most derived class or its non-virtual base.
@@ -2753,7 +2908,7 @@ void VFTableBuilder::CalculateVtordispAdjustment(
// Otherwise, we need to do use the dynamic offset of the final overrider
// in order to get "this" adjustment right.
TA.Virtual.Microsoft.VBPtrOffset =
- (VFPtrVBaseOffset + WhichVFPtr.NonVirtualOffset -
+ (OffsetOfVBaseWithVFPtr + WhichVFPtr.NonVirtualOffset -
MostDerivedClassLayout.getVBPtrOffset()).getQuantity();
TA.Virtual.Microsoft.VBOffsetOffset =
Context.getTypeSizeInChars(Context.IntTy).getQuantity() *
@@ -2789,24 +2944,6 @@ static void GroupNewVirtualOverloads(
VirtualMethods.append(Groups[I].rbegin(), Groups[I].rend());
}
-/// We need a return adjusting thunk for this method if its return type is
-/// not trivially convertible to the return type of any of its overridden
-/// methods.
-bool VFTableBuilder::NeedsReturnAdjustingThunk(const CXXMethodDecl *MD) {
- OverriddenMethodsSetTy OverriddenMethods;
- ComputeAllOverriddenMethods(MD, OverriddenMethods);
- for (OverriddenMethodsSetTy::iterator I = OverriddenMethods.begin(),
- E = OverriddenMethods.end();
- I != E; ++I) {
- const CXXMethodDecl *OverriddenMD = *I;
- BaseOffset Adjustment =
- ComputeReturnAdjustmentBaseOffset(Context, MD, OverriddenMD);
- if (!Adjustment.isEmpty())
- return true;
- }
- return false;
-}
-
static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD) {
for (const auto &B : RD->bases()) {
if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() == Base)
@@ -2866,20 +3003,21 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
for (unsigned I = 0, E = VirtualMethods.size(); I != E; ++I) {
const CXXMethodDecl *MD = VirtualMethods[I];
- FinalOverriders::OverriderInfo Overrider =
+ FinalOverriders::OverriderInfo FinalOverrider =
Overriders.getOverrider(MD, Base.getBaseOffset());
- const CXXMethodDecl *OverriderMD = Overrider.Method;
+ const CXXMethodDecl *FinalOverriderMD = FinalOverrider.Method;
const CXXMethodDecl *OverriddenMD =
FindNearestOverriddenMethod(MD, VisitedBases);
ThisAdjustment ThisAdjustmentOffset;
- bool ReturnAdjustingThunk = false;
- CharUnits ThisOffset = ComputeThisOffset(Overrider);
+ bool ReturnAdjustingThunk = false, ForceReturnAdjustmentMangling = false;
+ CharUnits ThisOffset = ComputeThisOffset(FinalOverrider);
ThisAdjustmentOffset.NonVirtual =
(ThisOffset - WhichVFPtr.FullOffsetInMDC).getQuantity();
- if ((OverriddenMD || OverriderMD != MD) &&
+ if ((OverriddenMD || FinalOverriderMD != MD) &&
WhichVFPtr.getVBaseWithVPtr())
- CalculateVtordispAdjustment(Overrider, ThisOffset, ThisAdjustmentOffset);
+ CalculateVtordispAdjustment(FinalOverrider, ThisOffset,
+ ThisAdjustmentOffset);
if (OverriddenMD) {
// If MD overrides anything in this vftable, we need to update the entries.
@@ -2892,7 +3030,16 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
- if (!NeedsReturnAdjustingThunk(MD)) {
+ // Let's check if the overrider requires any return adjustments.
+ // We must create a new slot if the MD's return type is not trivially
+ // convertible to the OverriddenMD's one.
+ // Once a chain of method overrides adds a return adjusting vftable slot,
+ // all subsequent overrides will also use an extra method slot.
+ ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset(
+ Context, MD, OverriddenMD).isEmpty() ||
+ OverriddenMethodInfo.UsesExtraSlot;
+
+ if (!ReturnAdjustingThunk) {
// No return adjustment needed - just replace the overridden method info
// with the current info.
MethodInfo MI(OverriddenMethodInfo.VBTableIndex,
@@ -2911,8 +3058,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
// Force a special name mangling for a return-adjusting thunk
// unless the method is the final overrider without this adjustment.
- ReturnAdjustingThunk =
- !(MD == OverriderMD && ThisAdjustmentOffset.isEmpty());
+ ForceReturnAdjustmentMangling =
+ !(MD == FinalOverriderMD && ThisAdjustmentOffset.isEmpty());
} else if (Base.getBaseOffset() != WhichVFPtr.FullOffsetInMDC ||
MD->size_overridden_methods()) {
// Skip methods that don't belong to the vftable of the current class,
@@ -2926,7 +3073,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
unsigned VBIndex =
LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0;
MethodInfo MI(VBIndex,
- HasRTTIComponent ? Components.size() - 1 : Components.size());
+ HasRTTIComponent ? Components.size() - 1 : Components.size(),
+ ReturnAdjustingThunk);
assert(!MethodInfoMap.count(MD) &&
"Should not have method info for this method yet!");
@@ -2936,12 +3084,12 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
// We don't want to do this for pure virtual member functions.
BaseOffset ReturnAdjustmentOffset;
ReturnAdjustment ReturnAdjustment;
- if (!OverriderMD->isPure()) {
+ if (!FinalOverriderMD->isPure()) {
ReturnAdjustmentOffset =
- ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
+ ComputeReturnAdjustmentBaseOffset(Context, FinalOverriderMD, MD);
}
if (!ReturnAdjustmentOffset.isEmpty()) {
- ReturnAdjustingThunk = true;
+ ForceReturnAdjustmentMangling = true;
ReturnAdjustment.NonVirtual =
ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
if (ReturnAdjustmentOffset.VirtualBase) {
@@ -2955,8 +3103,9 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
}
}
- AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
- ReturnAdjustingThunk ? MD : nullptr));
+ AddMethod(FinalOverriderMD,
+ ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
+ ForceReturnAdjustmentMangling ? MD : nullptr));
}
}
@@ -3039,10 +3188,8 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
if (MD->isPure())
Out << " [pure]";
- if (MD->isDeleted()) {
- ErrorUnsupported("deleted methods", MD->getLocation());
+ if (MD->isDeleted())
Out << " [deleted]";
- }
ThunkInfo Thunk = VTableThunks.lookup(I);
if (!Thunk.isEmpty())
@@ -3131,7 +3278,7 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
}
static bool setsIntersect(const llvm::SmallPtrSet<const CXXRecordDecl *, 4> &A,
- const ArrayRef<const CXXRecordDecl *> &B) {
+ ArrayRef<const CXXRecordDecl *> B) {
for (ArrayRef<const CXXRecordDecl *>::iterator I = B.begin(), E = B.end();
I != E; ++I) {
if (A.count(*I))
@@ -3201,10 +3348,6 @@ void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
if (P->MangledPath.empty() || P->MangledPath.back() != Base)
P->NextBaseToMangle = Base;
- // Keep track of the full path.
- // FIXME: Why do we need this?
- P->PathToBaseWithVPtr.insert(P->PathToBaseWithVPtr.begin(), Base);
-
// Keep track of which vtable the derived class is going to extend with
// new methods or bases. We append to either the vftable of our primary
// base, or the first non-virtual base that has a vbtable.
@@ -3292,6 +3435,58 @@ MicrosoftVTableContext::~MicrosoftVTableContext() {
llvm::DeleteContainerSeconds(VBaseInfo);
}
+static bool
+findPathForVPtr(ASTContext &Context, const ASTRecordLayout &MostDerivedLayout,
+ const CXXRecordDecl *RD, CharUnits Offset,
+ llvm::SmallPtrSetImpl<const CXXRecordDecl *> &VBasesSeen,
+ VPtrInfo::BasePath &FullPath, VPtrInfo *Info) {
+ if (RD == Info->BaseWithVPtr && Offset == Info->FullOffsetInMDC) {
+ Info->PathToBaseWithVPtr = FullPath;
+ return true;
+ }
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // Recurse with non-virtual bases first.
+ // FIXME: Does this need to be in layout order? Virtual bases will be in base
+ // specifier order, which isn't necessarily layout order.
+ SmallVector<CXXBaseSpecifier, 4> Bases(RD->bases_begin(), RD->bases_end());
+ std::stable_partition(Bases.begin(), Bases.end(),
+ [](CXXBaseSpecifier bs) { return !bs.isVirtual(); });
+
+ for (const auto &B : Bases) {
+ const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl();
+ CharUnits NewOffset;
+ if (!B.isVirtual())
+ NewOffset = Offset + Layout.getBaseClassOffset(Base);
+ else {
+ if (!VBasesSeen.insert(Base).second)
+ return false;
+ NewOffset = MostDerivedLayout.getVBaseClassOffset(Base);
+ }
+ FullPath.push_back(Base);
+ if (findPathForVPtr(Context, MostDerivedLayout, Base, NewOffset, VBasesSeen,
+ FullPath, Info))
+ return true;
+ FullPath.pop_back();
+ }
+ return false;
+}
+
+static void computeFullPathsForVFTables(ASTContext &Context,
+ const CXXRecordDecl *RD,
+ VPtrInfoVector &Paths) {
+ llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen;
+ const ASTRecordLayout &MostDerivedLayout = Context.getASTRecordLayout(RD);
+ VPtrInfo::BasePath FullPath;
+ for (VPtrInfo *Info : Paths) {
+ findPathForVPtr(Context, MostDerivedLayout, RD, CharUnits::Zero(),
+ VBasesSeen, FullPath, Info);
+ VBasesSeen.clear();
+ FullPath.clear();
+ }
+}
+
void MicrosoftVTableContext::computeVTableRelatedInformation(
const CXXRecordDecl *RD) {
assert(RD->isDynamicClass());
@@ -3304,6 +3499,7 @@ void MicrosoftVTableContext::computeVTableRelatedInformation(
VPtrInfoVector *VFPtrs = new VPtrInfoVector();
computeVTablePaths(/*ForVBTables=*/false, RD, *VFPtrs);
+ computeFullPathsForVFTables(Context, RD, *VFPtrs);
VFPtrLocations[RD] = VFPtrs;
MethodVFTableLocationsTy NewMethodLocations;
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index 23708e2ff0c7..fa7968a805c4 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -20,7 +20,11 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Timer.h"
#include <deque>
+#include <memory>
#include <set>
namespace clang {
@@ -53,7 +57,7 @@ static const unsigned MaxMemoizationEntries = 10000;
// FIXME: Benchmark whether memoization of non-pointer typed nodes
// provides enough benefit for the additional amount of code.
struct MatchKey {
- uint64_t MatcherID;
+ DynTypedMatcher::MatcherIDType MatcherID;
ast_type_traits::DynTypedNode Node;
BoundNodesTreeBuilder BoundNodes;
@@ -292,28 +296,33 @@ private:
class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
public ASTMatchFinder {
public:
- MatchASTVisitor(
- std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *
- MatcherCallbackPairs)
- : MatcherCallbackPairs(MatcherCallbackPairs), ActiveASTContext(nullptr) {}
+ MatchASTVisitor(const MatchFinder::MatchersByType *Matchers,
+ const MatchFinder::MatchFinderOptions &Options)
+ : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}
+
+ ~MatchASTVisitor() {
+ if (Options.CheckProfiling) {
+ Options.CheckProfiling->Records = std::move(TimeByBucket);
+ }
+ }
void onStartOfTranslationUnit() {
- for (std::vector<std::pair<internal::DynTypedMatcher,
- MatchCallback *> >::const_iterator
- I = MatcherCallbackPairs->begin(),
- E = MatcherCallbackPairs->end();
- I != E; ++I) {
- I->second->onStartOfTranslationUnit();
+ const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
+ TimeBucketRegion Timer;
+ for (MatchCallback *MC : Matchers->AllCallbacks) {
+ if (EnableCheckProfiling)
+ Timer.setBucket(&TimeByBucket[MC->getID()]);
+ MC->onStartOfTranslationUnit();
}
}
void onEndOfTranslationUnit() {
- for (std::vector<std::pair<internal::DynTypedMatcher,
- MatchCallback *> >::const_iterator
- I = MatcherCallbackPairs->begin(),
- E = MatcherCallbackPairs->end();
- I != E; ++I) {
- I->second->onEndOfTranslationUnit();
+ const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
+ TimeBucketRegion Timer;
+ for (MatchCallback *MC : Matchers->AllCallbacks) {
+ if (EnableCheckProfiling)
+ Timer.setBucket(&TimeByBucket[MC->getID()]);
+ MC->onEndOfTranslationUnit();
}
}
@@ -372,7 +381,7 @@ public:
BoundNodesTreeBuilder *Builder, int MaxDepth,
TraversalKind Traversal, BindKind Bind) {
// For AST-nodes that don't have an identity, we can't memoize.
- if (!Node.getMemoizationData())
+ if (!Node.getMemoizationData() || !Builder->isComparable())
return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
Bind);
@@ -392,9 +401,12 @@ public:
Result.Nodes = *Builder;
Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes,
MaxDepth, Traversal, Bind);
- ResultCache[Key] = Result;
- *Builder = Result.Nodes;
- return Result.ResultOfMatch;
+
+ MemoizedMatchResult &CachedResult = ResultCache[Key];
+ CachedResult = std::move(Result);
+
+ *Builder = CachedResult.Nodes;
+ return CachedResult.ResultOfMatch;
}
// Matches children or descendants of 'Node' with 'BaseMatcher'.
@@ -447,22 +459,27 @@ public:
// Matches all registered matchers on the given node and calls the
// result callback for every node that matches.
- void match(const ast_type_traits::DynTypedNode& Node) {
- for (std::vector<std::pair<internal::DynTypedMatcher,
- MatchCallback *> >::const_iterator
- I = MatcherCallbackPairs->begin(),
- E = MatcherCallbackPairs->end();
- I != E; ++I) {
- BoundNodesTreeBuilder Builder;
- if (I->first.matches(Node, this, &Builder)) {
- MatchVisitor Visitor(ActiveASTContext, I->second);
- Builder.visitMatches(&Visitor);
- }
+ void match(const ast_type_traits::DynTypedNode &Node) {
+ // FIXME: Improve this with a switch or a visitor pattern.
+ if (auto *N = Node.get<Decl>()) {
+ match(*N);
+ } else if (auto *N = Node.get<Stmt>()) {
+ match(*N);
+ } else if (auto *N = Node.get<Type>()) {
+ match(*N);
+ } else if (auto *N = Node.get<QualType>()) {
+ match(*N);
+ } else if (auto *N = Node.get<NestedNameSpecifier>()) {
+ match(*N);
+ } else if (auto *N = Node.get<NestedNameSpecifierLoc>()) {
+ match(*N);
+ } else if (auto *N = Node.get<TypeLoc>()) {
+ match(*N);
}
}
template <typename T> void match(const T &Node) {
- match(ast_type_traits::DynTypedNode::create(Node));
+ matchDispatch(&Node);
}
// Implements ASTMatchFinder::getASTContext.
@@ -475,6 +492,116 @@ public:
bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
private:
+ class TimeBucketRegion {
+ public:
+ TimeBucketRegion() : Bucket(nullptr) {}
+ ~TimeBucketRegion() { setBucket(nullptr); }
+
+ /// \brief Start timing for \p NewBucket.
+ ///
+ /// If there was a bucket already set, it will finish the timing for that
+ /// other bucket.
+ /// \p NewBucket will be timed until the next call to \c setBucket() or
+ /// until the \c TimeBucketRegion is destroyed.
+ /// If \p NewBucket is the same as the currently timed bucket, this call
+ /// does nothing.
+ void setBucket(llvm::TimeRecord *NewBucket) {
+ if (Bucket != NewBucket) {
+ auto Now = llvm::TimeRecord::getCurrentTime(true);
+ if (Bucket)
+ *Bucket += Now;
+ if (NewBucket)
+ *NewBucket -= Now;
+ Bucket = NewBucket;
+ }
+ }
+
+ private:
+ llvm::TimeRecord *Bucket;
+ };
+
+ /// \brief Runs all the \p Matchers on \p Node.
+ ///
+ /// Used by \c matchDispatch() below.
+ template <typename T, typename MC>
+ void matchWithoutFilter(const T &Node, const MC &Matchers) {
+ const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
+ TimeBucketRegion Timer;
+ for (const auto &MP : Matchers) {
+ if (EnableCheckProfiling)
+ Timer.setBucket(&TimeByBucket[MP.second->getID()]);
+ BoundNodesTreeBuilder Builder;
+ if (MP.first.matches(Node, this, &Builder)) {
+ MatchVisitor Visitor(ActiveASTContext, MP.second);
+ Builder.visitMatches(&Visitor);
+ }
+ }
+ }
+
+ void matchWithFilter(const ast_type_traits::DynTypedNode &DynNode) {
+ auto Kind = DynNode.getNodeKind();
+ auto it = MatcherFiltersMap.find(Kind);
+ const auto &Filter =
+ it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind);
+
+ if (Filter.empty())
+ return;
+
+ const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
+ TimeBucketRegion Timer;
+ auto &Matchers = this->Matchers->DeclOrStmt;
+ for (unsigned short I : Filter) {
+ auto &MP = Matchers[I];
+ if (EnableCheckProfiling)
+ Timer.setBucket(&TimeByBucket[MP.second->getID()]);
+ BoundNodesTreeBuilder Builder;
+ if (MP.first.matchesNoKindCheck(DynNode, this, &Builder)) {
+ MatchVisitor Visitor(ActiveASTContext, MP.second);
+ Builder.visitMatches(&Visitor);
+ }
+ }
+ }
+
+ const std::vector<unsigned short> &
+ getFilterForKind(ast_type_traits::ASTNodeKind Kind) {
+ auto &Filter = MatcherFiltersMap[Kind];
+ auto &Matchers = this->Matchers->DeclOrStmt;
+ assert((Matchers.size() < USHRT_MAX) && "Too many matchers.");
+ for (unsigned I = 0, E = Matchers.size(); I != E; ++I) {
+ if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
+ Filter.push_back(I);
+ }
+ }
+ return Filter;
+ }
+
+ /// @{
+ /// \brief Overloads to pair the different node types to their matchers.
+ void matchDispatch(const Decl *Node) {
+ return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node));
+ }
+ void matchDispatch(const Stmt *Node) {
+ return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node));
+ }
+
+ void matchDispatch(const Type *Node) {
+ matchWithoutFilter(QualType(Node, 0), Matchers->Type);
+ }
+ void matchDispatch(const TypeLoc *Node) {
+ matchWithoutFilter(*Node, Matchers->TypeLoc);
+ }
+ void matchDispatch(const QualType *Node) {
+ matchWithoutFilter(*Node, Matchers->Type);
+ }
+ void matchDispatch(const NestedNameSpecifier *Node) {
+ matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
+ }
+ void matchDispatch(const NestedNameSpecifierLoc *Node) {
+ matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
+ }
+ void matchDispatch(const void *) { /* Do nothing. */ }
+ /// @}
+
// Returns whether an ancestor of \p Node matches \p Matcher.
//
// The order of matching ((which can lead to different nodes being bound in
@@ -497,11 +624,7 @@ private:
assert(Node.getMemoizationData() &&
"Invariant broken: only nodes that support memoization may be "
"used in the parent map.");
- ASTContext::ParentVector Parents = ActiveASTContext->getParents(Node);
- if (Parents.empty()) {
- assert(false && "Found node that is not in the parent map.");
- return false;
- }
+
MatchKey Key;
Key.MatcherID = Matcher.getID();
Key.Node = Node;
@@ -514,9 +637,13 @@ private:
*Builder = I->second.Nodes;
return I->second.ResultOfMatch;
}
+
MemoizedMatchResult Result;
Result.ResultOfMatch = false;
Result.Nodes = *Builder;
+
+ const auto &Parents = ActiveASTContext->getParents(Node);
+ assert(!Parents.empty() && "Found node that is not in the parent map.");
if (Parents.size() == 1) {
// Only one parent - do recursive memoization.
const ast_type_traits::DynTypedNode Parent = Parents[0];
@@ -543,25 +670,24 @@ private:
break;
}
if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
- ASTContext::ParentVector Ancestors =
- ActiveASTContext->getParents(Queue.front());
- for (ASTContext::ParentVector::const_iterator I = Ancestors.begin(),
- E = Ancestors.end();
- I != E; ++I) {
+ for (const auto &Parent :
+ ActiveASTContext->getParents(Queue.front())) {
// Make sure we do not visit the same node twice.
// Otherwise, we'll visit the common ancestors as often as there
// are splits on the way down.
- if (Visited.insert(I->getMemoizationData()).second)
- Queue.push_back(*I);
+ if (Visited.insert(Parent.getMemoizationData()).second)
+ Queue.push_back(Parent);
}
}
Queue.pop_front();
}
}
- ResultCache[Key] = Result;
- *Builder = Result.Nodes;
- return Result.ResultOfMatch;
+ MemoizedMatchResult &CachedResult = ResultCache[Key];
+ CachedResult = std::move(Result);
+
+ *Builder = CachedResult.Nodes;
+ return CachedResult.ResultOfMatch;
}
// Implements a BoundNodesTree::Visitor that calls a MatchCallback with
@@ -588,22 +714,35 @@ private:
BoundNodesTreeBuilder *Builder) {
const Type *const CanonicalType =
ActiveASTContext->getCanonicalType(TypeNode);
- const std::set<const TypedefNameDecl *> &Aliases =
- TypeAliases[CanonicalType];
- for (std::set<const TypedefNameDecl*>::const_iterator
- It = Aliases.begin(), End = Aliases.end();
- It != End; ++It) {
+ for (const TypedefNameDecl *Alias : TypeAliases.lookup(CanonicalType)) {
BoundNodesTreeBuilder Result(*Builder);
- if (Matcher.matches(**It, this, &Result)) {
- *Builder = Result;
+ if (Matcher.matches(*Alias, this, &Result)) {
+ *Builder = std::move(Result);
return true;
}
}
return false;
}
- std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *const
- MatcherCallbackPairs;
+ /// \brief Bucket to record map.
+ ///
+ /// Used to get the appropriate bucket for each matcher.
+ llvm::StringMap<llvm::TimeRecord> TimeByBucket;
+
+ const MatchFinder::MatchersByType *Matchers;
+
+ /// \brief Filtered list of matcher indices for each matcher kind.
+ ///
+ /// \c Decl and \c Stmt toplevel matchers usually apply to a specific node
+ /// kind (and derived kinds) so it is a waste to try every matcher on every
+ /// node.
+ /// We precalculate a list of matchers that pass the toplevel restrict check.
+ /// This also allows us to skip the restrict check at matching time. See
+ /// use \c matchesNoKindCheck() above.
+ llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>>
+ MatcherFiltersMap;
+
+ const MatchFinder::MatchFinderOptions &Options;
ASTContext *ActiveASTContext;
// Maps a canonical type to its TypedefDecls.
@@ -680,7 +819,7 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
}
BoundNodesTreeBuilder Result(*Builder);
if (Base.matches(*ClassDecl, this, &Result)) {
- *Builder = Result;
+ *Builder = std::move(Result);
return true;
}
if (classIsDerivedFrom(ClassDecl, Base, Builder))
@@ -731,7 +870,8 @@ bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
match(NNS);
// We only match the nested name specifier here (as opposed to traversing it)
// because the traversal is already done in the parallel "Loc"-hierarchy.
- match(*NNS.getNestedNameSpecifier());
+ if (NNS.hasQualifier())
+ match(*NNS.getNestedNameSpecifier());
return
RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);
}
@@ -765,38 +905,45 @@ MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes,
MatchFinder::MatchCallback::~MatchCallback() {}
MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
-MatchFinder::MatchFinder() : ParsingDone(nullptr) {}
+MatchFinder::MatchFinder(MatchFinderOptions Options)
+ : Options(std::move(Options)), ParsingDone(nullptr) {}
MatchFinder::~MatchFinder() {}
void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.DeclOrStmt.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.AllCallbacks.push_back(Action);
}
void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.Type.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.AllCallbacks.push_back(Action);
}
void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.DeclOrStmt.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.AllCallbacks.push_back(Action);
}
void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.NestedNameSpecifier.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.AllCallbacks.push_back(Action);
}
void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.NestedNameSpecifierLoc.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.AllCallbacks.push_back(Action);
}
void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.TypeLoc.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.AllCallbacks.push_back(Action);
}
bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
@@ -823,19 +970,19 @@ bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
return false;
}
-ASTConsumer *MatchFinder::newASTConsumer() {
- return new internal::MatchASTConsumer(this, ParsingDone);
+std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() {
+ return llvm::make_unique<internal::MatchASTConsumer>(this, ParsingDone);
}
void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node,
ASTContext &Context) {
- internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
+ internal::MatchASTVisitor Visitor(&Matchers, Options);
Visitor.set_active_ast_context(&Context);
Visitor.match(Node);
}
void MatchFinder::matchAST(ASTContext &Context) {
- internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
+ internal::MatchASTVisitor Visitor(&Matchers, Options);
Visitor.set_active_ast_context(&Context);
Visitor.onStartOfTranslationUnit();
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
@@ -847,5 +994,7 @@ void MatchFinder::registerTestCallbackAfterParsing(
ParsingDone = NewParsingDone;
}
+StringRef MatchFinder::MatchCallback::getID() const { return "<unknown>"; }
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index 47b8b6d2f27a..2c482e38dc08 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -13,25 +13,219 @@
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ManagedStatic.h"
namespace clang {
namespace ast_matchers {
namespace internal {
+bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers);
+
+bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers);
+
+bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers);
+
+bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers);
+
+
void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
if (Bindings.empty())
Bindings.push_back(BoundNodesMap());
- for (unsigned i = 0, e = Bindings.size(); i != e; ++i) {
- ResultVisitor->visitMatch(BoundNodes(Bindings[i]));
+ for (BoundNodesMap &Binding : Bindings) {
+ ResultVisitor->visitMatch(BoundNodes(Binding));
}
}
-DynTypedMatcher::MatcherStorage::~MatcherStorage() {}
+namespace {
-void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
- for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) {
- Bindings.push_back(Other.Bindings[i]);
+typedef bool (*VariadicOperatorFunction)(
+ const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers);
+
+template <VariadicOperatorFunction Func>
+class VariadicMatcher : public DynMatcherInterface {
+public:
+ VariadicMatcher(std::vector<DynTypedMatcher> InnerMatchers)
+ : InnerMatchers(std::move(InnerMatchers)) {}
+
+ bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const override {
+ return Func(DynNode, Finder, Builder, InnerMatchers);
+ }
+
+private:
+ std::vector<DynTypedMatcher> InnerMatchers;
+};
+
+class IdDynMatcher : public DynMatcherInterface {
+ public:
+ IdDynMatcher(StringRef ID,
+ const IntrusiveRefCntPtr<DynMatcherInterface> &InnerMatcher)
+ : ID(ID), InnerMatcher(InnerMatcher) {}
+
+ bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const override {
+ bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder);
+ if (Result) Builder->setBinding(ID, DynNode);
+ return Result;
+ }
+
+ private:
+ const std::string ID;
+ const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher;
+};
+
+/// \brief A matcher that always returns true.
+///
+/// We only ever need one instance of this matcher, so we create a global one
+/// and reuse it to reduce the overhead of the matcher and increase the chance
+/// of cache hits.
+class TrueMatcherImpl : public DynMatcherInterface {
+public:
+ TrueMatcherImpl() {
+ Retain(); // Reference count will never become zero.
+ }
+ bool dynMatches(const ast_type_traits::DynTypedNode &, ASTMatchFinder *,
+ BoundNodesTreeBuilder *) const override {
+ return true;
+ }
+};
+static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance;
+
+} // namespace
+
+DynTypedMatcher DynTypedMatcher::constructVariadic(
+ DynTypedMatcher::VariadicOperator Op,
+ std::vector<DynTypedMatcher> InnerMatchers) {
+ assert(InnerMatchers.size() > 0 && "Array must not be empty.");
+ assert(std::all_of(InnerMatchers.begin(), InnerMatchers.end(),
+ [&InnerMatchers](const DynTypedMatcher &M) {
+ return InnerMatchers[0].SupportedKind.isSame(M.SupportedKind);
+ }) &&
+ "SupportedKind must match!");
+
+ auto SupportedKind = InnerMatchers[0].SupportedKind;
+ // We must relax the restrict kind here.
+ // The different operators might deal differently with a mismatch.
+ // Make it the same as SupportedKind, since that is the broadest type we are
+ // allowed to accept.
+ auto RestrictKind = SupportedKind;
+
+ switch (Op) {
+ case VO_AllOf:
+ // In the case of allOf() we must pass all the checks, so making
+ // RestrictKind the most restrictive can save us time. This way we reject
+ // invalid types earlier and we can elide the kind checks inside the
+ // matcher.
+ for (auto &IM : InnerMatchers) {
+ RestrictKind = ast_type_traits::ASTNodeKind::getMostDerivedType(
+ RestrictKind, IM.RestrictKind);
+ }
+ return DynTypedMatcher(
+ SupportedKind, RestrictKind,
+ new VariadicMatcher<AllOfVariadicOperator>(std::move(InnerMatchers)));
+
+ case VO_AnyOf:
+ return DynTypedMatcher(
+ SupportedKind, RestrictKind,
+ new VariadicMatcher<AnyOfVariadicOperator>(std::move(InnerMatchers)));
+
+ case VO_EachOf:
+ return DynTypedMatcher(
+ SupportedKind, RestrictKind,
+ new VariadicMatcher<EachOfVariadicOperator>(std::move(InnerMatchers)));
+
+ case VO_UnaryNot:
+ // FIXME: Implement the Not operator to take a single matcher instead of a
+ // vector.
+ return DynTypedMatcher(
+ SupportedKind, RestrictKind,
+ new VariadicMatcher<NotUnaryOperator>(std::move(InnerMatchers)));
}
+ llvm_unreachable("Invalid Op value.");
+}
+
+DynTypedMatcher DynTypedMatcher::trueMatcher(
+ ast_type_traits::ASTNodeKind NodeKind) {
+ return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance);
+}
+
+bool DynTypedMatcher::canMatchNodesOfKind(
+ ast_type_traits::ASTNodeKind Kind) const {
+ return RestrictKind.isBaseOf(Kind);
+}
+
+DynTypedMatcher DynTypedMatcher::dynCastTo(
+ const ast_type_traits::ASTNodeKind Kind) const {
+ auto Copy = *this;
+ Copy.SupportedKind = Kind;
+ Copy.RestrictKind =
+ ast_type_traits::ASTNodeKind::getMostDerivedType(Kind, RestrictKind);
+ return Copy;
+}
+
+bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
+ Implementation->dynMatches(DynNode, Finder, Builder)) {
+ return true;
+ }
+ // Delete all bindings when a matcher does not match.
+ // This prevents unexpected exposure of bound nodes in unmatches
+ // branches of the match tree.
+ Builder->removeBindings([](const BoundNodesMap &) { return true; });
+ return false;
+}
+
+bool DynTypedMatcher::matchesNoKindCheck(
+ const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ assert(RestrictKind.isBaseOf(DynNode.getNodeKind()));
+ if (Implementation->dynMatches(DynNode, Finder, Builder)) {
+ return true;
+ }
+ // Delete all bindings when a matcher does not match.
+ // This prevents unexpected exposure of bound nodes in unmatches
+ // branches of the match tree.
+ Builder->removeBindings([](const BoundNodesMap &) { return true; });
+ return false;
+}
+
+llvm::Optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const {
+ if (!AllowBind) return llvm::None;
+ auto Result = *this;
+ Result.Implementation = new IdDynMatcher(ID, Result.Implementation);
+ return Result;
+}
+
+bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const {
+ const auto From = getSupportedKind();
+ auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>();
+ auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>();
+ /// Mimic the implicit conversions of Matcher<>.
+ /// - From Matcher<Type> to Matcher<QualType>
+ if (From.isSame(TypeKind) && To.isSame(QualKind)) return true;
+ /// - From Matcher<Base> to Matcher<Derived>
+ return From.isBaseOf(To);
+}
+
+void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
+ Bindings.append(Other.Bindings.begin(), Other.Bindings.end());
}
bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
@@ -61,8 +255,8 @@ bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
// allOf leads to one matcher for each alternative in the first
// matcher combined with each alternative in the second matcher.
// Thus, we can reuse the same Builder.
- for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
- if (!InnerMatchers[i].matches(DynNode, Finder, Builder))
+ for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
+ if (!InnerMatcher.matchesNoKindCheck(DynNode, Finder, Builder))
return false;
}
return true;
@@ -74,14 +268,14 @@ bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ArrayRef<DynTypedMatcher> InnerMatchers) {
BoundNodesTreeBuilder Result;
bool Matched = false;
- for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
+ for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
BoundNodesTreeBuilder BuilderInner(*Builder);
- if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) {
+ if (InnerMatcher.matches(DynNode, Finder, &BuilderInner)) {
Matched = true;
Result.addMatch(BuilderInner);
}
}
- *Builder = Result;
+ *Builder = std::move(Result);
return Matched;
}
@@ -89,16 +283,62 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers) {
- for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
+ for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
BoundNodesTreeBuilder Result = *Builder;
- if (InnerMatchers[i].matches(DynNode, Finder, &Result)) {
- *Builder = Result;
+ if (InnerMatcher.matches(DynNode, Finder, &Result)) {
+ *Builder = std::move(Result);
return true;
}
}
return false;
}
+HasNameMatcher::HasNameMatcher(StringRef NameRef)
+ : UseUnqualifiedMatch(NameRef.find("::") == NameRef.npos), Name(NameRef) {
+ assert(!Name.empty());
+}
+
+bool HasNameMatcher::matchesNodeUnqualified(const NamedDecl &Node) const {
+ assert(UseUnqualifiedMatch);
+ if (Node.getIdentifier()) {
+ // Simple name.
+ return Name == Node.getName();
+ }
+ if (Node.getDeclName()) {
+ // Name needs to be constructed.
+ llvm::SmallString<128> NodeName;
+ llvm::raw_svector_ostream OS(NodeName);
+ Node.printName(OS);
+ return Name == OS.str();
+ }
+ return false;
+}
+
+bool HasNameMatcher::matchesNodeFull(const NamedDecl &Node) const {
+ llvm::SmallString<128> NodeName = StringRef("::");
+ llvm::raw_svector_ostream OS(NodeName);
+ Node.printQualifiedName(OS);
+ const StringRef FullName = OS.str();
+ const StringRef Pattern = Name;
+
+ if (Pattern.startswith("::"))
+ return FullName == Pattern;
+
+ return FullName.endswith(Pattern) &&
+ FullName.drop_back(Pattern.size()).endswith("::");
+}
+
+bool HasNameMatcher::matchesNode(const NamedDecl &Node) const {
+ // FIXME: There is still room for improvement, but it would require copying a
+ // lot of the logic from NamedDecl::printQualifiedName(). The benchmarks do
+ // not show like that extra complexity is needed right now.
+ if (UseUnqualifiedMatch) {
+ assert(matchesNodeUnqualified(Node) == matchesNodeFull(Node));
+ return matchesNodeUnqualified(Node);
+ }
+ return matchesNodeFull(Node);
+}
+
} // end namespace internal
} // end namespace ast_matchers
} // end namespace clang
diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h
index 6e144cd26ed9..b78bc0381990 100644
--- a/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -17,8 +17,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
-#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
+#ifndef LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H
+#define LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
@@ -30,48 +30,8 @@
namespace clang {
namespace ast_matchers {
namespace dynamic {
-
namespace internal {
-struct ArgKind {
- enum Kind {
- AK_Matcher,
- AK_Unsigned,
- AK_String
- };
- ArgKind(Kind K)
- : K(K) {}
- ArgKind(ast_type_traits::ASTNodeKind MatcherKind)
- : K(AK_Matcher), MatcherKind(MatcherKind) {}
-
- std::string asString() const {
- switch (getArgKind()) {
- case AK_Matcher:
- return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str();
- case AK_Unsigned:
- return "unsigned";
- case AK_String:
- return "string";
- }
- llvm_unreachable("unhandled ArgKind");
- }
-
- Kind getArgKind() const { return K; }
- ast_type_traits::ASTNodeKind getMatcherKind() const {
- assert(K == AK_Matcher);
- return MatcherKind;
- }
-
- bool operator<(const ArgKind &Other) const {
- if (K == AK_Matcher && Other.K == AK_Matcher)
- return MatcherKind < Other.MatcherKind;
- return K < Other.K;
- }
-
-private:
- Kind K;
- ast_type_traits::ASTNodeKind MatcherKind;
-};
/// \brief Helper template class to just from argument type to the right is/get
/// functions in VariantValue.
@@ -116,6 +76,27 @@ template <> struct ArgTypeTraits<unsigned> {
}
};
+template <> struct ArgTypeTraits<attr::Kind> {
+private:
+ static attr::Kind getAttrKind(llvm::StringRef AttrKind) {
+ return llvm::StringSwitch<attr::Kind>(AttrKind)
+#define ATTR(X) .Case("attr::" #X, attr:: X)
+#include "clang/Basic/AttrList.inc"
+ .Default(attr::Kind(-1));
+ }
+public:
+ static bool is(const VariantValue &Value) {
+ return Value.isString() &&
+ getAttrKind(Value.getString()) != attr::Kind(-1);
+ }
+ static attr::Kind get(const VariantValue &Value) {
+ return getAttrKind(Value.getString());
+ }
+ static ArgKind getKind() {
+ return ArgKind(ArgKind::AK_String);
+ }
+};
+
/// \brief Matcher descriptor interface.
///
/// Provides a \c create() method that constructs the matcher from the provided
@@ -161,16 +142,10 @@ inline bool isRetKindConvertibleTo(
ArrayRef<ast_type_traits::ASTNodeKind> RetKinds,
ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
ast_type_traits::ASTNodeKind *LeastDerivedKind) {
- for (ArrayRef<ast_type_traits::ASTNodeKind>::const_iterator
- i = RetKinds.begin(),
- e = RetKinds.end();
- i != e; ++i) {
- unsigned Distance;
- if (i->isBaseOf(Kind, &Distance)) {
- if (Specificity)
- *Specificity = 100 - Distance;
+ for (const ast_type_traits::ASTNodeKind &NodeKind : RetKinds) {
+ if (ArgKind(NodeKind).isConvertibleTo(Kind, Specificity)) {
if (LeastDerivedKind)
- *LeastDerivedKind = *i;
+ *LeastDerivedKind = NodeKind;
return true;
}
}
@@ -322,8 +297,8 @@ variadicMatcherDescriptor(StringRef MatcherName, const SourceRange &NameRange,
VariantMatcher Out;
if (!HasError) {
- Out = outvalueToVariantMatcher(
- Func(ArrayRef<const ArgT *>(InnerArgs, Args.size())));
+ Out = outvalueToVariantMatcher(Func(llvm::makeArrayRef(InnerArgs,
+ Args.size())));
}
for (size_t i = 0, e = Args.size(); i != e; ++i) {
@@ -498,7 +473,7 @@ private:
template <typename FromTypeList>
inline void collect(FromTypeList);
- const StringRef Name;
+ StringRef Name;
std::vector<MatcherDescriptor *> &Out;
};
@@ -581,15 +556,15 @@ private:
/// \brief Variadic operator marshaller function.
class VariadicOperatorMatcherDescriptor : public MatcherDescriptor {
public:
- typedef ast_matchers::internal::VariadicOperatorFunction VarFunc;
+ typedef DynTypedMatcher::VariadicOperator VarOp;
VariadicOperatorMatcherDescriptor(unsigned MinCount, unsigned MaxCount,
- VarFunc Func, StringRef MatcherName)
- : MinCount(MinCount), MaxCount(MaxCount), Func(Func),
+ VarOp Op, StringRef MatcherName)
+ : MinCount(MinCount), MaxCount(MaxCount), Op(Op),
MatcherName(MatcherName) {}
virtual VariantMatcher create(const SourceRange &NameRange,
ArrayRef<ParserValue> Args,
- Diagnostics *Error) const {
+ Diagnostics *Error) const override {
if (Args.size() < MinCount || MaxCount < Args.size()) {
const std::string MaxStr =
(MaxCount == UINT_MAX ? "" : Twine(MaxCount)).str();
@@ -609,17 +584,17 @@ public:
}
InnerArgs.push_back(Value.getMatcher());
}
- return VariantMatcher::VariadicOperatorMatcher(Func, std::move(InnerArgs));
+ return VariantMatcher::VariadicOperatorMatcher(Op, std::move(InnerArgs));
}
- bool isVariadic() const { return true; }
- unsigned getNumArgs() const { return 0; }
+ bool isVariadic() const override { return true; }
+ unsigned getNumArgs() const override { return 0; }
void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
- std::vector<ArgKind> &Kinds) const {
+ std::vector<ArgKind> &Kinds) const override {
Kinds.push_back(ThisKind);
}
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
- ast_type_traits::ASTNodeKind *LeastDerivedKind) const {
+ ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
if (Specificity)
*Specificity = 1;
if (LeastDerivedKind)
@@ -631,7 +606,7 @@ public:
private:
const unsigned MinCount;
const unsigned MaxCount;
- const VarFunc Func;
+ const VarOp Op;
const StringRef MatcherName;
};
@@ -724,7 +699,7 @@ MatcherDescriptor *
makeMatcherAutoMarshall(ast_matchers::internal::VariadicOperatorMatcherFunc<
MinCount, MaxCount> Func,
StringRef MatcherName) {
- return new VariadicOperatorMatcherDescriptor(MinCount, MaxCount, Func.Func,
+ return new VariadicOperatorMatcherDescriptor(MinCount, MaxCount, Func.Op,
MatcherName);
}
diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp
index 25629d99a7cc..9930c530c081 100644
--- a/lib/ASTMatchers/Dynamic/Parser.cpp
+++ b/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -17,6 +17,7 @@
#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ManagedStatic.h"
#include <string>
#include <vector>
@@ -258,8 +259,14 @@ private:
Parser::Sema::~Sema() {}
-VariantValue Parser::Sema::getNamedValue(StringRef Name) {
- return VariantValue();
+std::vector<ArgKind> Parser::Sema::getAcceptedCompletionTypes(
+ llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
+ return std::vector<ArgKind>();
+}
+
+std::vector<MatcherCompletion>
+Parser::Sema::getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) {
+ return std::vector<MatcherCompletion>();
}
struct Parser::ScopedContextEntry {
@@ -288,7 +295,9 @@ bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {
if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) {
// Parse as a named value.
- if (const VariantValue NamedValue = S->getNamedValue(NameToken.Text)) {
+ if (const VariantValue NamedValue =
+ NamedValues ? NamedValues->lookup(NameToken.Text)
+ : VariantValue()) {
*Value = NamedValue;
return true;
}
@@ -379,7 +388,7 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
Tokenizer->consumeNextToken(); // consume the period.
const TokenInfo BindToken = Tokenizer->consumeNextToken();
if (BindToken.Kind == TokenInfo::TK_CodeCompletion) {
- addCompletion(BindToken, "bind(\"", "bind");
+ addCompletion(BindToken, MatcherCompletion("bind(\"", "bind", 1));
return false;
}
@@ -427,13 +436,28 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
// If the prefix of this completion matches the completion token, add it to
// Completions minus the prefix.
-void Parser::addCompletion(const TokenInfo &CompToken, StringRef TypedText,
- StringRef Decl) {
- if (TypedText.size() >= CompToken.Text.size() &&
- TypedText.substr(0, CompToken.Text.size()) == CompToken.Text) {
- Completions.push_back(
- MatcherCompletion(TypedText.substr(CompToken.Text.size()), Decl));
+void Parser::addCompletion(const TokenInfo &CompToken,
+ const MatcherCompletion& Completion) {
+ if (StringRef(Completion.TypedText).startswith(CompToken.Text) &&
+ Completion.Specificity > 0) {
+ Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()),
+ Completion.MatcherDecl, Completion.Specificity);
+ }
+}
+
+std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
+ ArrayRef<ArgKind> AcceptedTypes) {
+ if (!NamedValues) return std::vector<MatcherCompletion>();
+ std::vector<MatcherCompletion> Result;
+ for (const auto &Entry : *NamedValues) {
+ unsigned Specificity;
+ if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {
+ std::string Decl =
+ (Entry.getValue().getTypeAsString() + " " + Entry.getKey()).str();
+ Result.emplace_back(Entry.getKey(), Decl, Specificity);
+ }
}
+ return Result;
}
void Parser::addExpressionCompletions() {
@@ -449,12 +473,13 @@ void Parser::addExpressionCompletions() {
return;
}
- std::vector<MatcherCompletion> RegCompletions =
- Registry::getCompletions(ContextStack);
- for (std::vector<MatcherCompletion>::iterator I = RegCompletions.begin(),
- E = RegCompletions.end();
- I != E; ++I) {
- addCompletion(CompToken, I->TypedText, I->MatcherDecl);
+ auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack);
+ for (const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) {
+ addCompletion(CompToken, Completion);
+ }
+
+ for (const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
+ addCompletion(CompToken, Completion);
}
}
@@ -494,9 +519,12 @@ bool Parser::parseExpressionImpl(VariantValue *Value) {
llvm_unreachable("Unknown token kind.");
}
+static llvm::ManagedStatic<Parser::RegistrySema> DefaultRegistrySema;
+
Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,
- Diagnostics *Error)
- : Tokenizer(Tokenizer), S(S), Error(Error) {}
+ const NamedValueMap *NamedValues, Diagnostics *Error)
+ : Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema),
+ NamedValues(NamedValues), Error(Error) {}
Parser::RegistrySema::~RegistrySema() {}
@@ -516,16 +544,22 @@ VariantMatcher Parser::RegistrySema::actOnMatcherExpression(
}
}
-bool Parser::parseExpression(StringRef Code, VariantValue *Value,
- Diagnostics *Error) {
- RegistrySema S;
- return parseExpression(Code, &S, Value, Error);
+std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes(
+ ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
+ return Registry::getAcceptedCompletionTypes(Context);
+}
+
+std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions(
+ ArrayRef<ArgKind> AcceptedTypes) {
+ return Registry::getMatcherCompletions(AcceptedTypes);
}
bool Parser::parseExpression(StringRef Code, Sema *S,
+ const NamedValueMap *NamedValues,
VariantValue *Value, Diagnostics *Error) {
CodeTokenizer Tokenizer(Code, Error);
- if (!Parser(&Tokenizer, S, Error).parseExpressionImpl(Value)) return false;
+ if (!Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value))
+ return false;
if (Tokenizer.peekNextToken().Kind != TokenInfo::TK_Eof) {
Error->addError(Tokenizer.peekNextToken().Range,
Error->ET_ParserTrailingCode);
@@ -535,28 +569,31 @@ bool Parser::parseExpression(StringRef Code, Sema *S,
}
std::vector<MatcherCompletion>
-Parser::completeExpression(StringRef Code, unsigned CompletionOffset) {
+Parser::completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S,
+ const NamedValueMap *NamedValues) {
Diagnostics Error;
CodeTokenizer Tokenizer(Code, &Error, CompletionOffset);
- RegistrySema S;
- Parser P(&Tokenizer, &S, &Error);
+ Parser P(&Tokenizer, S, NamedValues, &Error);
VariantValue Dummy;
P.parseExpressionImpl(&Dummy);
- return P.Completions;
-}
+ // Sort by specificity, then by name.
+ std::sort(P.Completions.begin(), P.Completions.end(),
+ [](const MatcherCompletion &A, const MatcherCompletion &B) {
+ if (A.Specificity != B.Specificity)
+ return A.Specificity > B.Specificity;
+ return A.TypedText < B.TypedText;
+ });
-llvm::Optional<DynTypedMatcher>
-Parser::parseMatcherExpression(StringRef Code, Diagnostics *Error) {
- RegistrySema S;
- return parseMatcherExpression(Code, &S, Error);
+ return P.Completions;
}
llvm::Optional<DynTypedMatcher>
-Parser::parseMatcherExpression(StringRef Code, Parser::Sema *S,
+Parser::parseMatcherExpression(StringRef Code, Sema *S,
+ const NamedValueMap *NamedValues,
Diagnostics *Error) {
VariantValue Value;
- if (!parseExpression(Code, S, &Value, Error))
+ if (!parseExpression(Code, S, NamedValues, &Value, Error))
return llvm::Optional<DynTypedMatcher>();
if (!Value.isMatcher()) {
Error->addError(SourceRange(), Error->ET_ParserNotAMatcher);
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index 4bc50a0f2a96..d550a89cad49 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -101,8 +101,8 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(argumentCountIs);
REGISTER_MATCHER(arraySubscriptExpr);
REGISTER_MATCHER(arrayType);
- REGISTER_MATCHER(asString);
REGISTER_MATCHER(asmStmt);
+ REGISTER_MATCHER(asString);
REGISTER_MATCHER(atomicType);
REGISTER_MATCHER(autoType);
REGISTER_MATCHER(binaryOperator);
@@ -111,7 +111,6 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(boolLiteral);
REGISTER_MATCHER(breakStmt);
REGISTER_MATCHER(builtinType);
- REGISTER_MATCHER(cStyleCastExpr);
REGISTER_MATCHER(callExpr);
REGISTER_MATCHER(caseStmt);
REGISTER_MATCHER(castExpr);
@@ -123,18 +122,20 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(compoundLiteralExpr);
REGISTER_MATCHER(compoundStmt);
REGISTER_MATCHER(conditionalOperator);
- REGISTER_MATCHER(constCastExpr);
REGISTER_MATCHER(constantArrayType);
+ REGISTER_MATCHER(constCastExpr);
REGISTER_MATCHER(constructExpr);
REGISTER_MATCHER(constructorDecl);
REGISTER_MATCHER(containsDeclaration);
REGISTER_MATCHER(continueStmt);
+ REGISTER_MATCHER(cStyleCastExpr);
REGISTER_MATCHER(ctorInitializer);
+ REGISTER_MATCHER(CUDAKernelCallExpr);
REGISTER_MATCHER(decl);
+ REGISTER_MATCHER(declaratorDecl);
REGISTER_MATCHER(declCountIs);
REGISTER_MATCHER(declRefExpr);
REGISTER_MATCHER(declStmt);
- REGISTER_MATCHER(declaratorDecl);
REGISTER_MATCHER(defaultArgExpr);
REGISTER_MATCHER(defaultStmt);
REGISTER_MATCHER(deleteExpr);
@@ -147,6 +148,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(enumConstantDecl);
REGISTER_MATCHER(enumDecl);
REGISTER_MATCHER(equalsBoundNode);
+ REGISTER_MATCHER(equalsIntegralValue);
REGISTER_MATCHER(explicitCastExpr);
REGISTER_MATCHER(expr);
REGISTER_MATCHER(exprWithCleanups);
@@ -160,10 +162,10 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(forRangeStmt);
REGISTER_MATCHER(forStmt);
REGISTER_MATCHER(friendDecl);
+ REGISTER_MATCHER(functionalCastExpr);
REGISTER_MATCHER(functionDecl);
REGISTER_MATCHER(functionTemplateDecl);
REGISTER_MATCHER(functionType);
- REGISTER_MATCHER(functionalCastExpr);
REGISTER_MATCHER(gotoStmt);
REGISTER_MATCHER(has);
REGISTER_MATCHER(hasAncestor);
@@ -175,19 +177,21 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasAnyUsingShadowDecl);
REGISTER_MATCHER(hasArgument);
REGISTER_MATCHER(hasArgumentOfType);
+ REGISTER_MATCHER(hasAttr);
REGISTER_MATCHER(hasBase);
REGISTER_MATCHER(hasBody);
REGISTER_MATCHER(hasCanonicalType);
REGISTER_MATCHER(hasCaseConstant);
REGISTER_MATCHER(hasCondition);
REGISTER_MATCHER(hasConditionVariableStatement);
- REGISTER_MATCHER(hasDeclContext);
REGISTER_MATCHER(hasDeclaration);
+ REGISTER_MATCHER(hasDeclContext);
REGISTER_MATCHER(hasDeducedType);
REGISTER_MATCHER(hasDescendant);
REGISTER_MATCHER(hasDestinationType);
REGISTER_MATCHER(hasEitherOperand);
REGISTER_MATCHER(hasElementType);
+ REGISTER_MATCHER(hasElse);
REGISTER_MATCHER(hasFalseExpression);
REGISTER_MATCHER(hasGlobalStorage);
REGISTER_MATCHER(hasImplicitDestinationType);
@@ -198,6 +202,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasLocalQualifiers);
REGISTER_MATCHER(hasLocalStorage);
REGISTER_MATCHER(hasLoopInit);
+ REGISTER_MATCHER(hasLoopVariable);
REGISTER_MATCHER(hasMethod);
REGISTER_MATCHER(hasName);
REGISTER_MATCHER(hasObjectExpression);
@@ -206,6 +211,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasParameter);
REGISTER_MATCHER(hasParent);
REGISTER_MATCHER(hasQualifier);
+ REGISTER_MATCHER(hasRangeInit);
REGISTER_MATCHER(hasRHS);
REGISTER_MATCHER(hasSingleDecl);
REGISTER_MATCHER(hasSize);
@@ -213,6 +219,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasSourceExpression);
REGISTER_MATCHER(hasTargetDecl);
REGISTER_MATCHER(hasTemplateArgument);
+ REGISTER_MATCHER(hasThen);
REGISTER_MATCHER(hasTrueExpression);
REGISTER_MATCHER(hasTypeLoc);
REGISTER_MATCHER(hasUnaryOperand);
@@ -230,22 +237,30 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isConst);
REGISTER_MATCHER(isConstQualified);
REGISTER_MATCHER(isDefinition);
+ REGISTER_MATCHER(isDeleted);
REGISTER_MATCHER(isExplicitTemplateSpecialization);
REGISTER_MATCHER(isExpr);
REGISTER_MATCHER(isExternC);
REGISTER_MATCHER(isImplicit);
+ REGISTER_MATCHER(isExpansionInFileMatching);
+ REGISTER_MATCHER(isExpansionInMainFile);
+ REGISTER_MATCHER(isInstantiated);
+ REGISTER_MATCHER(isExpansionInSystemHeader);
REGISTER_MATCHER(isInteger);
+ REGISTER_MATCHER(isIntegral);
+ REGISTER_MATCHER(isInTemplateInstantiation);
REGISTER_MATCHER(isListInitialization);
REGISTER_MATCHER(isOverride);
REGISTER_MATCHER(isPrivate);
REGISTER_MATCHER(isProtected);
REGISTER_MATCHER(isPublic);
+ REGISTER_MATCHER(isPure);
REGISTER_MATCHER(isTemplateInstantiation);
REGISTER_MATCHER(isVirtual);
REGISTER_MATCHER(isWritten);
- REGISTER_MATCHER(lValueReferenceType);
REGISTER_MATCHER(labelStmt);
REGISTER_MATCHER(lambdaExpr);
+ REGISTER_MATCHER(lValueReferenceType);
REGISTER_MATCHER(matchesName);
REGISTER_MATCHER(materializeTemporaryExpr);
REGISTER_MATCHER(member);
@@ -254,8 +269,8 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(memberPointerType);
REGISTER_MATCHER(methodDecl);
REGISTER_MATCHER(namedDecl);
- REGISTER_MATCHER(namesType);
REGISTER_MATCHER(namespaceDecl);
+ REGISTER_MATCHER(namesType);
REGISTER_MATCHER(nestedNameSpecifier);
REGISTER_MATCHER(nestedNameSpecifierLoc);
REGISTER_MATCHER(newExpr);
@@ -271,15 +286,16 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(pointee);
REGISTER_MATCHER(pointerType);
REGISTER_MATCHER(qualType);
- REGISTER_MATCHER(rValueReferenceType);
REGISTER_MATCHER(recordDecl);
REGISTER_MATCHER(recordType);
REGISTER_MATCHER(referenceType);
REGISTER_MATCHER(refersToDeclaration);
+ REGISTER_MATCHER(refersToIntegralType);
REGISTER_MATCHER(refersToType);
REGISTER_MATCHER(reinterpretCastExpr);
- REGISTER_MATCHER(returnStmt);
REGISTER_MATCHER(returns);
+ REGISTER_MATCHER(returnStmt);
+ REGISTER_MATCHER(rValueReferenceType);
REGISTER_MATCHER(sizeOfExpr);
REGISTER_MATCHER(specifiesNamespace);
REGISTER_MATCHER(specifiesType);
@@ -288,8 +304,11 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(staticCastExpr);
REGISTER_MATCHER(stmt);
REGISTER_MATCHER(stringLiteral);
+ REGISTER_MATCHER(substNonTypeTemplateParmExpr);
REGISTER_MATCHER(switchCase);
REGISTER_MATCHER(switchStmt);
+ REGISTER_MATCHER(templateArgument);
+ REGISTER_MATCHER(templateArgumentCountIs);
REGISTER_MATCHER(templateSpecializationType);
REGISTER_MATCHER(temporaryObjectExpr);
REGISTER_MATCHER(thisExpr);
@@ -298,8 +317,9 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(to);
REGISTER_MATCHER(tryStmt);
REGISTER_MATCHER(type);
- REGISTER_MATCHER(typeLoc);
+ REGISTER_MATCHER(typedefDecl);
REGISTER_MATCHER(typedefType);
+ REGISTER_MATCHER(typeLoc);
REGISTER_MATCHER(unaryExprOrTypeTraitExpr);
REGISTER_MATCHER(unaryOperator);
REGISTER_MATCHER(unaryTransformType);
@@ -308,8 +328,11 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(unresolvedUsingValueDecl);
REGISTER_MATCHER(userDefinedLiteral);
REGISTER_MATCHER(usingDecl);
+ REGISTER_MATCHER(usingDirectiveDecl);
+ REGISTER_MATCHER(valueDecl);
REGISTER_MATCHER(varDecl);
REGISTER_MATCHER(variableArrayType);
+ REGISTER_MATCHER(voidType);
REGISTER_MATCHER(whileStmt);
REGISTER_MATCHER(withInitializer);
}
@@ -353,77 +376,63 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
return OS;
}
-struct ReverseSpecificityThenName {
- bool operator()(const std::pair<unsigned, std::string> &A,
- const std::pair<unsigned, std::string> &B) const {
- return A.first > B.first || (A.first == B.first && A.second < B.second);
- }
-};
-
-}
+} // namespace
-std::vector<MatcherCompletion> Registry::getCompletions(
- ArrayRef<std::pair<MatcherCtor, unsigned> > Context) {
+std::vector<ArgKind> Registry::getAcceptedCompletionTypes(
+ ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
ASTNodeKind InitialTypes[] = {
- ASTNodeKind::getFromNodeKind<Decl>(),
- ASTNodeKind::getFromNodeKind<QualType>(),
- ASTNodeKind::getFromNodeKind<Type>(),
- ASTNodeKind::getFromNodeKind<Stmt>(),
- ASTNodeKind::getFromNodeKind<NestedNameSpecifier>(),
- ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>(),
- ASTNodeKind::getFromNodeKind<TypeLoc>()
- };
- ArrayRef<ASTNodeKind> InitialTypesRef(InitialTypes);
+ ASTNodeKind::getFromNodeKind<Decl>(),
+ ASTNodeKind::getFromNodeKind<QualType>(),
+ ASTNodeKind::getFromNodeKind<Type>(),
+ ASTNodeKind::getFromNodeKind<Stmt>(),
+ ASTNodeKind::getFromNodeKind<NestedNameSpecifier>(),
+ ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>(),
+ ASTNodeKind::getFromNodeKind<TypeLoc>()};
// Starting with the above seed of acceptable top-level matcher types, compute
// the acceptable type set for the argument indicated by each context element.
- std::set<ASTNodeKind> TypeSet(InitialTypesRef.begin(), InitialTypesRef.end());
- for (ArrayRef<std::pair<MatcherCtor, unsigned> >::iterator
- CtxI = Context.begin(),
- CtxE = Context.end();
- CtxI != CtxE; ++CtxI) {
- std::vector<internal::ArgKind> NextTypeSet;
- for (std::set<ASTNodeKind>::iterator I = TypeSet.begin(), E = TypeSet.end();
- I != E; ++I) {
- if (CtxI->first->isConvertibleTo(*I) &&
- (CtxI->first->isVariadic() ||
- CtxI->second < CtxI->first->getNumArgs()))
- CtxI->first->getArgKinds(*I, CtxI->second, NextTypeSet);
+ std::set<ArgKind> TypeSet(std::begin(InitialTypes), std::end(InitialTypes));
+ for (const auto &CtxEntry : Context) {
+ MatcherCtor Ctor = CtxEntry.first;
+ unsigned ArgNumber = CtxEntry.second;
+ std::vector<ArgKind> NextTypeSet;
+ for (const ArgKind &Kind : TypeSet) {
+ if (Kind.getArgKind() == Kind.AK_Matcher &&
+ Ctor->isConvertibleTo(Kind.getMatcherKind()) &&
+ (Ctor->isVariadic() || ArgNumber < Ctor->getNumArgs()))
+ Ctor->getArgKinds(Kind.getMatcherKind(), ArgNumber, NextTypeSet);
}
TypeSet.clear();
- for (std::vector<internal::ArgKind>::iterator I = NextTypeSet.begin(),
- E = NextTypeSet.end();
- I != E; ++I) {
- if (I->getArgKind() == internal::ArgKind::AK_Matcher)
- TypeSet.insert(I->getMatcherKind());
- }
+ TypeSet.insert(NextTypeSet.begin(), NextTypeSet.end());
}
+ return std::vector<ArgKind>(TypeSet.begin(), TypeSet.end());
+}
- typedef std::map<std::pair<unsigned, std::string>, MatcherCompletion,
- ReverseSpecificityThenName> CompletionsTy;
- CompletionsTy Completions;
+std::vector<MatcherCompletion>
+Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) {
+ std::vector<MatcherCompletion> Completions;
- // TypeSet now contains the list of acceptable types for the argument we are
- // completing. Search the registry for acceptable matchers.
+ // Search the registry for acceptable matchers.
for (ConstructorMap::const_iterator I = RegistryData->constructors().begin(),
E = RegistryData->constructors().end();
I != E; ++I) {
std::set<ASTNodeKind> RetKinds;
unsigned NumArgs = I->second->isVariadic() ? 1 : I->second->getNumArgs();
bool IsPolymorphic = I->second->isPolymorphic();
- std::vector<std::vector<internal::ArgKind> > ArgsKinds(NumArgs);
+ std::vector<std::vector<ArgKind>> ArgsKinds(NumArgs);
unsigned MaxSpecificity = 0;
- for (std::set<ASTNodeKind>::iterator TI = TypeSet.begin(),
- TE = TypeSet.end();
- TI != TE; ++TI) {
+ for (const ArgKind& Kind : AcceptedTypes) {
+ if (Kind.getArgKind() != Kind.AK_Matcher)
+ continue;
unsigned Specificity;
ASTNodeKind LeastDerivedKind;
- if (I->second->isConvertibleTo(*TI, &Specificity, &LeastDerivedKind)) {
+ if (I->second->isConvertibleTo(Kind.getMatcherKind(), &Specificity,
+ &LeastDerivedKind)) {
if (MaxSpecificity < Specificity)
MaxSpecificity = Specificity;
RetKinds.insert(LeastDerivedKind);
for (unsigned Arg = 0; Arg != NumArgs; ++Arg)
- I->second->getArgKinds(*TI, Arg, ArgsKinds[Arg]);
+ I->second->getArgKinds(Kind.getMatcherKind(), Arg, ArgsKinds[Arg]);
if (IsPolymorphic)
break;
}
@@ -437,24 +446,25 @@ std::vector<MatcherCompletion> Registry::getCompletions(
OS << "Matcher<T> " << I->first() << "(Matcher<T>";
} else {
OS << "Matcher<" << RetKinds << "> " << I->first() << "(";
- for (std::vector<std::vector<internal::ArgKind> >::iterator
- KI = ArgsKinds.begin(),
- KE = ArgsKinds.end();
- KI != KE; ++KI) {
- if (KI != ArgsKinds.begin())
+ for (const std::vector<ArgKind> &Arg : ArgsKinds) {
+ if (&Arg != &ArgsKinds[0])
OS << ", ";
- // This currently assumes that a matcher may not overload a
- // non-matcher, and all non-matcher overloads have identical
- // arguments.
- if ((*KI)[0].getArgKind() == internal::ArgKind::AK_Matcher) {
- std::set<ASTNodeKind> MatcherKinds;
- std::transform(
- KI->begin(), KI->end(),
- std::inserter(MatcherKinds, MatcherKinds.end()),
- std::mem_fun_ref(&internal::ArgKind::getMatcherKind));
+
+ bool FirstArgKind = true;
+ std::set<ASTNodeKind> MatcherKinds;
+ // Two steps. First all non-matchers, then matchers only.
+ for (const ArgKind &AK : Arg) {
+ if (AK.getArgKind() == ArgKind::AK_Matcher) {
+ MatcherKinds.insert(AK.getMatcherKind());
+ } else {
+ if (!FirstArgKind) OS << "|";
+ FirstArgKind = false;
+ OS << AK.asString();
+ }
+ }
+ if (!MatcherKinds.empty()) {
+ if (!FirstArgKind) OS << "|";
OS << "Matcher<" << MatcherKinds << ">";
- } else {
- OS << (*KI)[0].asString();
}
}
}
@@ -466,19 +476,14 @@ std::vector<MatcherCompletion> Registry::getCompletions(
TypedText += "(";
if (ArgsKinds.empty())
TypedText += ")";
- else if (ArgsKinds[0][0].getArgKind() == internal::ArgKind::AK_String)
+ else if (ArgsKinds[0][0].getArgKind() == ArgKind::AK_String)
TypedText += "\"";
- Completions[std::make_pair(MaxSpecificity, I->first())] =
- MatcherCompletion(TypedText, OS.str());
+ Completions.emplace_back(TypedText, OS.str(), MaxSpecificity);
}
}
- std::vector<MatcherCompletion> RetVal;
- for (CompletionsTy::iterator I = Completions.begin(), E = Completions.end();
- I != E; ++I)
- RetVal.push_back(I->second);
- return RetVal;
+ return Completions;
}
// static
diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp
index 18c989432f46..a88b70701234 100644
--- a/lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -20,26 +20,88 @@ namespace clang {
namespace ast_matchers {
namespace dynamic {
-VariantMatcher::MatcherOps::~MatcherOps() {}
+std::string ArgKind::asString() const {
+ switch (getArgKind()) {
+ case AK_Matcher:
+ return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str();
+ case AK_Unsigned:
+ return "unsigned";
+ case AK_String:
+ return "string";
+ }
+ llvm_unreachable("unhandled ArgKind");
+}
+
+bool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const {
+ if (K != To.K)
+ return false;
+ if (K != AK_Matcher) {
+ if (Specificity)
+ *Specificity = 1;
+ return true;
+ }
+ unsigned Distance;
+ if (!MatcherKind.isBaseOf(To.MatcherKind, &Distance))
+ return false;
+
+ if (Specificity)
+ *Specificity = 100 - Distance;
+ return true;
+}
+
+bool
+VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher,
+ bool &IsExactMatch) const {
+ IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind);
+ return Matcher.canConvertTo(NodeKind);
+}
+
+llvm::Optional<DynTypedMatcher>
+VariantMatcher::MatcherOps::constructVariadicOperator(
+ DynTypedMatcher::VariadicOperator Op,
+ ArrayRef<VariantMatcher> InnerMatchers) const {
+ std::vector<DynTypedMatcher> DynMatchers;
+ for (const auto &InnerMatcher : InnerMatchers) {
+ // Abort if any of the inner matchers can't be converted to
+ // Matcher<T>.
+ if (!InnerMatcher.Value)
+ return llvm::None;
+ llvm::Optional<DynTypedMatcher> Inner =
+ InnerMatcher.Value->getTypedMatcher(*this);
+ if (!Inner)
+ return llvm::None;
+ DynMatchers.push_back(*Inner);
+ }
+ return DynTypedMatcher::constructVariadic(Op, DynMatchers);
+}
+
VariantMatcher::Payload::~Payload() {}
class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
public:
SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {}
- virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
+ llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
return Matcher;
}
- virtual std::string getTypeAsString() const {
+ std::string getTypeAsString() const override {
return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">")
.str();
}
- virtual void makeTypedMatcher(MatcherOps &Ops) const {
+ llvm::Optional<DynTypedMatcher>
+ getTypedMatcher(const MatcherOps &Ops) const override {
bool Ignore;
if (Ops.canConstructFrom(Matcher, Ignore))
- Ops.constructFrom(Matcher);
+ return Matcher;
+ return llvm::None;
+ }
+
+ bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
+ unsigned *Specificity) const override {
+ return ArgKind(Matcher.getSupportedKind())
+ .isConvertibleTo(Kind, Specificity);
}
private:
@@ -51,15 +113,15 @@ public:
PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn)
: Matchers(std::move(MatchersIn)) {}
- virtual ~PolymorphicPayload() {}
+ ~PolymorphicPayload() override {}
- virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
+ llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
if (Matchers.size() != 1)
return llvm::Optional<DynTypedMatcher>();
return Matchers[0];
}
- virtual std::string getTypeAsString() const {
+ std::string getTypeAsString() const override {
std::string Inner;
for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
if (i != 0)
@@ -69,7 +131,8 @@ public:
return (Twine("Matcher<") + Inner + ">").str();
}
- virtual void makeTypedMatcher(MatcherOps &Ops) const {
+ llvm::Optional<DynTypedMatcher>
+ getTypedMatcher(const MatcherOps &Ops) const override {
bool FoundIsExact = false;
const DynTypedMatcher *Found = nullptr;
int NumFound = 0;
@@ -89,7 +152,23 @@ public:
}
// We only succeed if we found exactly one, or if we found an exact match.
if (Found && (FoundIsExact || NumFound == 1))
- Ops.constructFrom(*Found);
+ return *Found;
+ return llvm::None;
+ }
+
+ bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
+ unsigned *Specificity) const override {
+ unsigned MaxSpecificity = 0;
+ for (const DynTypedMatcher &Matcher : Matchers) {
+ unsigned ThisSpecificity;
+ if (ArgKind(Matcher.getSupportedKind())
+ .isConvertibleTo(Kind, &ThisSpecificity)) {
+ MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity);
+ }
+ }
+ if (Specificity)
+ *Specificity = MaxSpecificity;
+ return MaxSpecificity > 0;
}
const std::vector<DynTypedMatcher> Matchers;
@@ -97,15 +176,15 @@ public:
class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {
public:
- VariadicOpPayload(ast_matchers::internal::VariadicOperatorFunction Func,
+ VariadicOpPayload(DynTypedMatcher::VariadicOperator Op,
std::vector<VariantMatcher> Args)
- : Func(Func), Args(std::move(Args)) {}
+ : Op(Op), Args(std::move(Args)) {}
- virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
+ llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
return llvm::Optional<DynTypedMatcher>();
}
- virtual std::string getTypeAsString() const {
+ std::string getTypeAsString() const override {
std::string Inner;
for (size_t i = 0, e = Args.size(); i != e; ++i) {
if (i != 0)
@@ -115,12 +194,22 @@ public:
return Inner;
}
- virtual void makeTypedMatcher(MatcherOps &Ops) const {
- Ops.constructVariadicOperator(Func, Args);
+ llvm::Optional<DynTypedMatcher>
+ getTypedMatcher(const MatcherOps &Ops) const override {
+ return Ops.constructVariadicOperator(Op, Args);
+ }
+
+ bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
+ unsigned *Specificity) const override {
+ for (const VariantMatcher &Matcher : Args) {
+ if (!Matcher.isConvertibleTo(Kind, Specificity))
+ return false;
+ }
+ return true;
}
private:
- const ast_matchers::internal::VariadicOperatorFunction Func;
+ const DynTypedMatcher::VariadicOperator Op;
const std::vector<VariantMatcher> Args;
};
@@ -136,9 +225,9 @@ VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) {
}
VariantMatcher VariantMatcher::VariadicOperatorMatcher(
- ast_matchers::internal::VariadicOperatorFunction Func,
+ DynTypedMatcher::VariadicOperator Op,
std::vector<VariantMatcher> Args) {
- return VariantMatcher(new VariadicOpPayload(Func, std::move(Args)));
+ return VariantMatcher(new VariadicOpPayload(Op, std::move(Args)));
}
llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {
@@ -251,6 +340,43 @@ void VariantValue::setMatcher(const VariantMatcher &NewValue) {
Value.Matcher = new VariantMatcher(NewValue);
}
+bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const {
+ switch (Kind.getArgKind()) {
+ case ArgKind::AK_Unsigned:
+ if (!isUnsigned())
+ return false;
+ *Specificity = 1;
+ return true;
+
+ case ArgKind::AK_String:
+ if (!isString())
+ return false;
+ *Specificity = 1;
+ return true;
+
+ case ArgKind::AK_Matcher:
+ if (!isMatcher())
+ return false;
+ return getMatcher().isConvertibleTo(Kind.getMatcherKind(), Specificity);
+ }
+ llvm_unreachable("Invalid Type");
+}
+
+bool VariantValue::isConvertibleTo(ArrayRef<ArgKind> Kinds,
+ unsigned *Specificity) const {
+ unsigned MaxSpecificity = 0;
+ for (const ArgKind& Kind : Kinds) {
+ unsigned ThisSpecificity;
+ if (!isConvertibleTo(Kind, &ThisSpecificity))
+ continue;
+ MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity);
+ }
+ if (Specificity && MaxSpecificity > 0) {
+ *Specificity = MaxSpecificity;
+ }
+ return MaxSpecificity > 0;
+}
+
std::string VariantValue::getTypeAsString() const {
switch (Type) {
case VT_String: return "String";
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index 90d4b13b88be..be66f32e77be 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -69,8 +69,9 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
bool addTemporaryDtors,
bool synthesizeBodies,
bool addStaticInitBranch,
- bool addCXXNewAllocator)
- : SynthesizeBodies(synthesizeBodies)
+ bool addCXXNewAllocator,
+ CodeInjector *injector)
+ : Injector(injector), SynthesizeBodies(synthesizeBodies)
{
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
@@ -84,8 +85,8 @@ void AnalysisDeclContextManager::clear() {
llvm::DeleteContainerSeconds(Contexts);
}
-static BodyFarm &getBodyFarm(ASTContext &C) {
- static BodyFarm *BF = new BodyFarm(C);
+static BodyFarm &getBodyFarm(ASTContext &C, CodeInjector *injector = nullptr) {
+ static BodyFarm *BF = new BodyFarm(C, injector);
return *BF;
}
@@ -94,7 +95,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Stmt *Body = FD->getBody();
if (!Body && Manager && Manager->synthesizeBodies()) {
- Body = getBodyFarm(getASTContext()).getBody(FD);
+ Body = getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(FD);
if (Body)
IsAutosynthesized = true;
}
@@ -103,7 +104,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
Stmt *Body = MD->getBody();
if (!Body && Manager && Manager->synthesizeBodies()) {
- Body = getBodyFarm(getASTContext()).getBody(MD);
+ Body = getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(MD);
if (Body)
IsAutosynthesized = true;
}
@@ -128,6 +129,13 @@ bool AnalysisDeclContext::isBodyAutosynthesized() const {
return Tmp;
}
+bool AnalysisDeclContext::isBodyAutosynthesizedFromModelFile() const {
+ bool Tmp;
+ Stmt *Body = getBody(Tmp);
+ return Tmp && Body->getLocStart().isValid();
+}
+
+
const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getSelfDecl();
@@ -181,8 +189,7 @@ CFG *AnalysisDeclContext::getCFG() {
return getUnoptimizedCFG();
if (!builtCFG) {
- cfg.reset(CFG::buildCFG(D, getBody(),
- &D->getASTContext(), cfgBuildOptions));
+ cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), cfgBuildOptions);
// Even when the cfg is not successfully built, we don't
// want to try building it again.
builtCFG = true;
@@ -200,8 +207,8 @@ CFG *AnalysisDeclContext::getUnoptimizedCFG() {
if (!builtCompleteCFG) {
SaveAndRestore<bool> NotPrune(cfgBuildOptions.PruneTriviallyFalseEdges,
false);
- completeCFG.reset(CFG::buildCFG(D, getBody(), &D->getASTContext(),
- cfgBuildOptions));
+ completeCFG =
+ CFG::buildCFG(D, getBody(), &D->getASTContext(), cfgBuildOptions);
// Even when the cfg is not successfully built, we don't
// want to try building it again.
builtCompleteCFG = true;
@@ -474,7 +481,7 @@ public:
// Non-local variables are also directly modified.
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
if (!VD->hasLocalStorage()) {
- if (Visited.insert(VD))
+ if (Visited.insert(VD).second)
BEVals.push_back(VD, BC);
}
}
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 316a18b421b5..7d1b23575293 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/lib/Analysis/BodyFarm.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/CodeInjector.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -114,7 +115,7 @@ DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
/* QualifierLoc = */ NestedNameSpecifierLoc(),
/* TemplateKWLoc = */ SourceLocation(),
/* D = */ const_cast<VarDecl*>(D),
- /* isEnclosingLocal = */ false,
+ /* RefersToEnclosingVariableOrCapture = */ false,
/* NameLoc = */ SourceLocation(),
/* T = */ D->getType(),
/* VK = */ VK_LValue);
@@ -223,10 +224,8 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
PredicateTy);
// (3) Create the compound statement.
- Stmt *Stmts[2];
- Stmts[0] = B;
- Stmts[1] = CE;
- CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
+ Stmt *Stmts[] = { B, CE };
+ CompoundStmt *CS = M.makeCompound(Stmts);
// (4) Create the 'if' condition.
ImplicitCastExpr *LValToRval =
@@ -337,7 +336,7 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
: M.makeIntegralCast(BoolVal, ResultTy);
Stmts[1] = M.makeReturn(RetVal);
- CompoundStmt *Body = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
+ CompoundStmt *Body = M.makeCompound(Stmts);
// Construct the else clause.
BoolVal = M.makeObjCBool(false);
@@ -383,6 +382,7 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
}
if (FF) { Val = FF(C, D); }
+ else if (Injector) { Val = Injector->getBody(D); }
return Val.getValue();
}
diff --git a/lib/Analysis/BodyFarm.h b/lib/Analysis/BodyFarm.h
index 2d200fb755c1..91379437231d 100644
--- a/lib/Analysis/BodyFarm.h
+++ b/lib/Analysis/BodyFarm.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ANALYSIS_BODYFARM_H
-#define LLVM_CLANG_ANALYSIS_BODYFARM_H
+#ifndef LLVM_CLANG_LIB_ANALYSIS_BODYFARM_H
+#define LLVM_CLANG_LIB_ANALYSIS_BODYFARM_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
@@ -27,10 +27,11 @@ class FunctionDecl;
class ObjCMethodDecl;
class ObjCPropertyDecl;
class Stmt;
+class CodeInjector;
class BodyFarm {
public:
- BodyFarm(ASTContext &C) : C(C) {}
+ BodyFarm(ASTContext &C, CodeInjector *injector) : C(C), Injector(injector) {}
/// Factory method for creating bodies for ordinary functions.
Stmt *getBody(const FunctionDecl *D);
@@ -43,6 +44,7 @@ private:
ASTContext &C;
BodyMap Bodies;
+ CodeInjector *Injector;
};
}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 842a385fbcdb..d9073aa63b16 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -234,6 +234,12 @@ public:
}
};
+TryResult bothKnownTrue(TryResult R1, TryResult R2) {
+ if (!R1.isKnown() || !R2.isKnown())
+ return TryResult();
+ return TryResult(R1.isTrue() && R2.isTrue());
+}
+
class reverse_children {
llvm::SmallVector<Stmt *, 12> childrenBuf;
ArrayRef<Stmt*> children;
@@ -300,7 +306,7 @@ class CFGBuilder {
CFGBlock *SwitchTerminatedBlock;
CFGBlock *DefaultCaseBlock;
CFGBlock *TryTerminatedBlock;
-
+
// Current position in local scope.
LocalScope::const_iterator ScopePos;
@@ -343,7 +349,7 @@ public:
cachedEntry(nullptr), lastLookup(nullptr) {}
// buildCFG - Used by external clients to construct the CFG.
- CFG* buildCFG(const Decl *D, Stmt *Statement);
+ std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *Statement);
bool alwaysAdd(const Stmt *stmt);
@@ -410,16 +416,80 @@ private:
CFGBlock *VisitChildren(Stmt *S);
CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc);
+ /// When creating the CFG for temporary destructors, we want to mirror the
+ /// branch structure of the corresponding constructor calls.
+ /// Thus, while visiting a statement for temporary destructors, we keep a
+ /// context to keep track of the following information:
+ /// - whether a subexpression is executed unconditionally
+ /// - if a subexpression is executed conditionally, the first
+ /// CXXBindTemporaryExpr we encounter in that subexpression (which
+ /// corresponds to the last temporary destructor we have to call for this
+ /// subexpression) and the CFG block at that point (which will become the
+ /// successor block when inserting the decision point).
+ ///
+ /// That way, we can build the branch structure for temporary destructors as
+ /// follows:
+ /// 1. If a subexpression is executed unconditionally, we add the temporary
+ /// destructor calls to the current block.
+ /// 2. If a subexpression is executed conditionally, when we encounter a
+ /// CXXBindTemporaryExpr:
+ /// a) If it is the first temporary destructor call in the subexpression,
+ /// we remember the CXXBindTemporaryExpr and the current block in the
+ /// TempDtorContext; we start a new block, and insert the temporary
+ /// destructor call.
+ /// b) Otherwise, add the temporary destructor call to the current block.
+ /// 3. When we finished visiting a conditionally executed subexpression,
+ /// and we found at least one temporary constructor during the visitation
+ /// (2.a has executed), we insert a decision block that uses the
+ /// CXXBindTemporaryExpr as terminator, and branches to the current block
+ /// if the CXXBindTemporaryExpr was marked executed, and otherwise
+ /// branches to the stored successor.
+ struct TempDtorContext {
+ TempDtorContext()
+ : IsConditional(false), KnownExecuted(true), Succ(nullptr),
+ TerminatorExpr(nullptr) {}
+
+ TempDtorContext(TryResult KnownExecuted)
+ : IsConditional(true), KnownExecuted(KnownExecuted), Succ(nullptr),
+ TerminatorExpr(nullptr) {}
+
+ /// Returns whether we need to start a new branch for a temporary destructor
+ /// call. This is the case when the the temporary destructor is
+ /// conditionally executed, and it is the first one we encounter while
+ /// visiting a subexpression - other temporary destructors at the same level
+ /// will be added to the same block and are executed under the same
+ /// condition.
+ bool needsTempDtorBranch() const {
+ return IsConditional && !TerminatorExpr;
+ }
+
+ /// Remember the successor S of a temporary destructor decision branch for
+ /// the corresponding CXXBindTemporaryExpr E.
+ void setDecisionPoint(CFGBlock *S, CXXBindTemporaryExpr *E) {
+ Succ = S;
+ TerminatorExpr = E;
+ }
+
+ const bool IsConditional;
+ const TryResult KnownExecuted;
+ CFGBlock *Succ;
+ CXXBindTemporaryExpr *TerminatorExpr;
+ };
+
// Visitors to walk an AST and generate destructors of temporaries in
// full expression.
- CFGBlock *VisitForTemporaryDtors(Stmt *E, bool BindToTemporary = false);
- CFGBlock *VisitChildrenForTemporaryDtors(Stmt *E);
- CFGBlock *VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E);
- CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(CXXBindTemporaryExpr *E,
- bool BindToTemporary);
- CFGBlock *
- VisitConditionalOperatorForTemporaryDtors(AbstractConditionalOperator *E,
- bool BindToTemporary);
+ CFGBlock *VisitForTemporaryDtors(Stmt *E, bool BindToTemporary,
+ TempDtorContext &Context);
+ CFGBlock *VisitChildrenForTemporaryDtors(Stmt *E, TempDtorContext &Context);
+ CFGBlock *VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E,
+ TempDtorContext &Context);
+ CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(
+ CXXBindTemporaryExpr *E, bool BindToTemporary, TempDtorContext &Context);
+ CFGBlock *VisitConditionalOperatorForTemporaryDtors(
+ AbstractConditionalOperator *E, bool BindToTemporary,
+ TempDtorContext &Context);
+ void InsertTempDtorDecisionBlock(const TempDtorContext &Context,
+ CFGBlock *FalseSucc = nullptr);
// NYS == Not Yet Supported
CFGBlock *NYS() {
@@ -901,7 +971,7 @@ static const VariableArrayType *FindVA(const Type *t) {
/// body (compound statement). The ownership of the returned CFG is
/// transferred to the caller. If CFG construction fails, this method returns
/// NULL.
-CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
+std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
assert(cfg.get());
if (!Statement)
return nullptr;
@@ -973,7 +1043,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
// Create an empty entry block that has no predecessors.
cfg->setEntry(createBlock());
- return cfg.release();
+ return std::move(cfg);
}
/// createBlock - Used to lazily create blocks that are connected
@@ -1000,21 +1070,19 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
if (!BuildOpts.AddInitializers)
return Block;
- bool IsReference = false;
bool HasTemporaries = false;
// Destructors of temporaries in initialization expression should be called
// after initialization finishes.
Expr *Init = I->getInit();
if (Init) {
- if (FieldDecl *FD = I->getAnyMember())
- IsReference = FD->getType()->isReferenceType();
HasTemporaries = isa<ExprWithCleanups>(Init);
if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
// Generate destructors for temporaries in initialization expression.
+ TempDtorContext Context;
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
- IsReference);
+ /*BindToTemporary=*/false, Context);
}
}
@@ -1946,7 +2014,6 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
return Block;
}
- bool IsReference = false;
bool HasTemporaries = false;
// Guard static initializers under a branch.
@@ -1968,13 +2035,13 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
// after initialization finishes.
Expr *Init = VD->getInit();
if (Init) {
- IsReference = VD->getType()->isReferenceType();
HasTemporaries = isa<ExprWithCleanups>(Init);
if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
// Generate destructors for temporaries in initialization expression.
+ TempDtorContext Context;
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
- IsReference);
+ /*BindToTemporary=*/false, Context);
}
}
@@ -3354,7 +3421,8 @@ CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
if (BuildOpts.AddTemporaryDtors) {
// If adding implicit destructors visit the full expression for adding
// destructors of temporaries.
- VisitForTemporaryDtors(E->getSubExpr());
+ TempDtorContext Context;
+ VisitForTemporaryDtors(E->getSubExpr(), false, Context);
// Full expression has to be added as CFGStmt so it will be sequenced
// before destructors of it's temporaries.
@@ -3463,7 +3531,8 @@ CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
return addStmt(I->getTarget());
}
-CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary) {
+CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary,
+ TempDtorContext &Context) {
assert(BuildOpts.AddImplicitDtors && BuildOpts.AddTemporaryDtors);
tryAgain:
@@ -3473,32 +3542,52 @@ tryAgain:
}
switch (E->getStmtClass()) {
default:
- return VisitChildrenForTemporaryDtors(E);
+ return VisitChildrenForTemporaryDtors(E, Context);
case Stmt::BinaryOperatorClass:
- return VisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(E));
+ return VisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(E),
+ Context);
case Stmt::CXXBindTemporaryExprClass:
return VisitCXXBindTemporaryExprForTemporaryDtors(
- cast<CXXBindTemporaryExpr>(E), BindToTemporary);
+ cast<CXXBindTemporaryExpr>(E), BindToTemporary, Context);
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass:
return VisitConditionalOperatorForTemporaryDtors(
- cast<AbstractConditionalOperator>(E), BindToTemporary);
+ cast<AbstractConditionalOperator>(E), BindToTemporary, Context);
case Stmt::ImplicitCastExprClass:
// For implicit cast we want BindToTemporary to be passed further.
E = cast<CastExpr>(E)->getSubExpr();
goto tryAgain;
+ case Stmt::CXXFunctionalCastExprClass:
+ // For functional cast we want BindToTemporary to be passed further.
+ E = cast<CXXFunctionalCastExpr>(E)->getSubExpr();
+ goto tryAgain;
+
case Stmt::ParenExprClass:
E = cast<ParenExpr>(E)->getSubExpr();
goto tryAgain;
- case Stmt::MaterializeTemporaryExprClass:
- E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+ case Stmt::MaterializeTemporaryExprClass: {
+ const MaterializeTemporaryExpr* MTE = cast<MaterializeTemporaryExpr>(E);
+ BindToTemporary = (MTE->getStorageDuration() != SD_FullExpression);
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ // Find the expression whose lifetime needs to be extended.
+ E = const_cast<Expr *>(
+ cast<MaterializeTemporaryExpr>(E)
+ ->GetTemporaryExpr()
+ ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
+ // Visit the skipped comma operator left-hand sides for other temporaries.
+ for (const Expr *CommaLHS : CommaLHSs) {
+ VisitForTemporaryDtors(const_cast<Expr *>(CommaLHS),
+ /*BindToTemporary=*/false, Context);
+ }
goto tryAgain;
+ }
case Stmt::BlockExprClass:
// Don't recurse into blocks; their subexpressions don't get evaluated
@@ -3511,7 +3600,8 @@ tryAgain:
auto *LE = cast<LambdaExpr>(E);
CFGBlock *B = Block;
for (Expr *Init : LE->capture_inits()) {
- if (CFGBlock *R = VisitForTemporaryDtors(Init))
+ if (CFGBlock *R = VisitForTemporaryDtors(
+ Init, /*BindToTemporary=*/false, Context))
B = R;
}
return B;
@@ -3527,7 +3617,13 @@ tryAgain:
}
}
-CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) {
+CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E,
+ TempDtorContext &Context) {
+ if (isa<LambdaExpr>(E)) {
+ // Do not visit the children of lambdas; they have their own CFGs.
+ return Block;
+ }
+
// When visiting children for destructors we want to visit them in reverse
// order that they will appear in the CFG. Because the CFG is built
// bottom-up, this means we visit them in their natural order, which
@@ -3535,165 +3631,126 @@ CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) {
CFGBlock *B = Block;
for (Stmt::child_range I = E->children(); I; ++I) {
if (Stmt *Child = *I)
- if (CFGBlock *R = VisitForTemporaryDtors(Child))
+ if (CFGBlock *R = VisitForTemporaryDtors(Child, false, Context))
B = R;
}
return B;
}
-CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E) {
+CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
+ BinaryOperator *E, TempDtorContext &Context) {
if (E->isLogicalOp()) {
- // Destructors for temporaries in LHS expression should be called after
- // those for RHS expression. Even if this will unnecessarily create a block,
- // this block will be used at least by the full expression.
- autoCreateBlock();
- CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getLHS());
- if (badCFG)
- return nullptr;
-
- Succ = ConfluenceBlock;
- Block = nullptr;
- CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS());
-
- if (RHSBlock) {
- if (badCFG)
- return nullptr;
+ VisitForTemporaryDtors(E->getLHS(), false, Context);
+ TryResult RHSExecuted = tryEvaluateBool(E->getLHS());
+ if (RHSExecuted.isKnown() && E->getOpcode() == BO_LOr)
+ RHSExecuted.negate();
+
+ // We do not know at CFG-construction time whether the right-hand-side was
+ // executed, thus we add a branch node that depends on the temporary
+ // constructor call.
+ TempDtorContext RHSContext(
+ bothKnownTrue(Context.KnownExecuted, RHSExecuted));
+ VisitForTemporaryDtors(E->getRHS(), false, RHSContext);
+ InsertTempDtorDecisionBlock(RHSContext);
- // If RHS expression did produce destructors we need to connect created
- // blocks to CFG in same manner as for binary operator itself.
- CFGBlock *LHSBlock = createBlock(false);
- LHSBlock->setTerminator(CFGTerminator(E, true));
-
- // For binary operator LHS block is before RHS in list of predecessors
- // of ConfluenceBlock.
- std::reverse(ConfluenceBlock->pred_begin(),
- ConfluenceBlock->pred_end());
-
- // See if this is a known constant.
- TryResult KnownVal = tryEvaluateBool(E->getLHS());
- if (KnownVal.isKnown() && (E->getOpcode() == BO_LOr))
- KnownVal.negate();
-
- // Link LHSBlock with RHSBlock exactly the same way as for binary operator
- // itself.
- if (E->getOpcode() == BO_LOr) {
- addSuccessor(LHSBlock, KnownVal.isTrue() ? nullptr : ConfluenceBlock);
- addSuccessor(LHSBlock, KnownVal.isFalse() ? nullptr : RHSBlock);
- } else {
- assert (E->getOpcode() == BO_LAnd);
- addSuccessor(LHSBlock, KnownVal.isFalse() ? nullptr : RHSBlock);
- addSuccessor(LHSBlock, KnownVal.isTrue() ? nullptr : ConfluenceBlock);
- }
-
- Block = LHSBlock;
- return LHSBlock;
- }
-
- Block = ConfluenceBlock;
- return ConfluenceBlock;
+ return Block;
}
if (E->isAssignmentOp()) {
// For assignment operator (=) LHS expression is visited
// before RHS expression. For destructors visit them in reverse order.
- CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS());
- CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS());
+ CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), false, Context);
+ CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context);
return LHSBlock ? LHSBlock : RHSBlock;
}
// For any other binary operator RHS expression is visited before
// LHS expression (order of children). For destructors visit them in reverse
// order.
- CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS());
- CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS());
+ CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context);
+ CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), false, Context);
return RHSBlock ? RHSBlock : LHSBlock;
}
CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
- CXXBindTemporaryExpr *E, bool BindToTemporary) {
+ CXXBindTemporaryExpr *E, bool BindToTemporary, TempDtorContext &Context) {
// First add destructors for temporaries in subexpression.
- CFGBlock *B = VisitForTemporaryDtors(E->getSubExpr());
+ CFGBlock *B = VisitForTemporaryDtors(E->getSubExpr(), false, Context);
if (!BindToTemporary) {
// If lifetime of temporary is not prolonged (by assigning to constant
// reference) add destructor for it.
- // If the destructor is marked as a no-return destructor, we need to create
- // a new block for the destructor which does not have as a successor
- // anything built thus far. Control won't flow out of this block.
const CXXDestructorDecl *Dtor = E->getTemporary()->getDestructor();
+
if (Dtor->isNoReturn()) {
- Succ = B;
+ // If the destructor is marked as a no-return destructor, we need to
+ // create a new block for the destructor which does not have as a
+ // successor anything built thus far. Control won't flow out of this
+ // block.
+ if (B) Succ = B;
Block = createNoReturnBlock();
+ } else if (Context.needsTempDtorBranch()) {
+ // If we need to introduce a branch, we add a new block that we will hook
+ // up to a decision block later.
+ if (B) Succ = B;
+ Block = createBlock();
} else {
autoCreateBlock();
}
-
+ if (Context.needsTempDtorBranch()) {
+ Context.setDecisionPoint(Succ, E);
+ }
appendTemporaryDtor(Block, E);
+
B = Block;
}
return B;
}
-CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
- AbstractConditionalOperator *E, bool BindToTemporary) {
- // First add destructors for condition expression. Even if this will
- // unnecessarily create a block, this block will be used at least by the full
- // expression.
- autoCreateBlock();
- CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getCond());
- if (badCFG)
- return nullptr;
- if (BinaryConditionalOperator *BCO
- = dyn_cast<BinaryConditionalOperator>(E)) {
- ConfluenceBlock = VisitForTemporaryDtors(BCO->getCommon());
- if (badCFG)
- return nullptr;
- }
-
- // Try to add block with destructors for LHS expression.
- CFGBlock *LHSBlock = nullptr;
- Succ = ConfluenceBlock;
- Block = nullptr;
- LHSBlock = VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary);
- if (badCFG)
- return nullptr;
-
- // Try to add block with destructors for RHS expression;
- Succ = ConfluenceBlock;
- Block = nullptr;
- CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getFalseExpr(),
- BindToTemporary);
- if (badCFG)
- return nullptr;
-
- if (!RHSBlock && !LHSBlock) {
- // If neither LHS nor RHS expression had temporaries to destroy don't create
- // more blocks.
- Block = ConfluenceBlock;
- return Block;
+void CFGBuilder::InsertTempDtorDecisionBlock(const TempDtorContext &Context,
+ CFGBlock *FalseSucc) {
+ if (!Context.TerminatorExpr) {
+ // If no temporary was found, we do not need to insert a decision point.
+ return;
}
+ assert(Context.TerminatorExpr);
+ CFGBlock *Decision = createBlock(false);
+ Decision->setTerminator(CFGTerminator(Context.TerminatorExpr, true));
+ addSuccessor(Decision, Block, !Context.KnownExecuted.isFalse());
+ addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
+ !Context.KnownExecuted.isTrue());
+ Block = Decision;
+}
- Block = createBlock(false);
- Block->setTerminator(CFGTerminator(E, true));
- assert(Block->getTerminator().isTemporaryDtorsBranch());
-
- // See if this is a known constant.
- const TryResult &KnownVal = tryEvaluateBool(E->getCond());
-
- if (LHSBlock) {
- addSuccessor(Block, LHSBlock, !KnownVal.isFalse());
- } else if (KnownVal.isFalse()) {
- addSuccessor(Block, nullptr);
+CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
+ AbstractConditionalOperator *E, bool BindToTemporary,
+ TempDtorContext &Context) {
+ VisitForTemporaryDtors(E->getCond(), false, Context);
+ CFGBlock *ConditionBlock = Block;
+ CFGBlock *ConditionSucc = Succ;
+ TryResult ConditionVal = tryEvaluateBool(E->getCond());
+ TryResult NegatedVal = ConditionVal;
+ if (NegatedVal.isKnown()) NegatedVal.negate();
+
+ TempDtorContext TrueContext(
+ bothKnownTrue(Context.KnownExecuted, ConditionVal));
+ VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary, TrueContext);
+ CFGBlock *TrueBlock = Block;
+
+ Block = ConditionBlock;
+ Succ = ConditionSucc;
+ TempDtorContext FalseContext(
+ bothKnownTrue(Context.KnownExecuted, NegatedVal));
+ VisitForTemporaryDtors(E->getFalseExpr(), BindToTemporary, FalseContext);
+
+ if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
+ InsertTempDtorDecisionBlock(FalseContext, TrueBlock);
+ } else if (TrueContext.TerminatorExpr) {
+ Block = TrueBlock;
+ InsertTempDtorDecisionBlock(TrueContext);
} else {
- addSuccessor(Block, ConfluenceBlock);
- std::reverse(ConfluenceBlock->pred_begin(), ConfluenceBlock->pred_end());
+ InsertTempDtorDecisionBlock(FalseContext);
}
-
- if (!RHSBlock)
- RHSBlock = ConfluenceBlock;
-
- addSuccessor(Block, RHSBlock, !KnownVal.isTrue());
-
return Block;
}
@@ -3718,10 +3775,9 @@ CFGBlock *CFG::createBlock() {
return &back();
}
-/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
-/// CFG is returned to the caller.
-CFG* CFG::buildCFG(const Decl *D, Stmt *Statement, ASTContext *C,
- const BuildOptions &BO) {
+/// buildCFG - Constructs a CFG from an AST.
+std::unique_ptr<CFG> CFG::buildCFG(const Decl *D, Stmt *Statement,
+ ASTContext *C, const BuildOptions &BO) {
CFGBuilder Builder(C, BO);
return Builder.buildCFG(D, Statement);
}
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 461ffb0900bb..1df093d85098 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -11,6 +11,7 @@ add_clang_library(clangAnalysis
CallGraph.cpp
CocoaConventions.cpp
Consumed.cpp
+ CodeInjector.cpp
Dominators.cpp
FormatString.cpp
LiveVariables.cpp
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index f41a96d30ea5..91a8492eaa54 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -110,14 +110,13 @@ CallGraph::~CallGraph() {
bool CallGraph::includeInGraph(const Decl *D) {
assert(D);
- if (!D->getBody())
+ if (!D->hasBody())
return false;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
- if (!FD->isThisDeclarationADefinition() ||
- FD->isDependentContext())
+ if (FD->isDependentContext())
return false;
IdentifierInfo *II = FD->getIdentifier();
@@ -125,11 +124,6 @@ bool CallGraph::includeInGraph(const Decl *D) {
return false;
}
- if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
- if (!ID->isThisDeclarationADefinition())
- return false;
- }
-
return true;
}
@@ -152,6 +146,9 @@ CallGraphNode *CallGraph::getNode(const Decl *F) const {
}
CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
+ if (F && !isa<ObjCMethodDecl>(F))
+ F = F->getCanonicalDecl();
+
CallGraphNode *&Node = FunctionMap[F];
if (Node)
return Node;
diff --git a/lib/Analysis/CodeInjector.cpp b/lib/Analysis/CodeInjector.cpp
new file mode 100644
index 000000000000..76bf364444d1
--- /dev/null
+++ b/lib/Analysis/CodeInjector.cpp
@@ -0,0 +1,15 @@
+//===-- CodeInjector.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/CodeInjector.h"
+
+using namespace clang;
+
+CodeInjector::CodeInjector() {}
+CodeInjector::~CodeInjector() {}
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 851b97e5bc1d..8c663d856f6a 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -244,6 +244,8 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
++I;
lmKind = LengthModifier::AsInt3264;
break;
+ case 'w':
+ lmKind = LengthModifier::AsWide; ++I; break;
}
LengthModifier lm(lmPosition, lmKind);
FS.setLengthModifier(lm);
@@ -504,6 +506,8 @@ analyze_format_string::LengthModifier::toString() const {
return "a";
case AsMAllocate:
return "m";
+ case AsWide:
+ return "w";
case None:
return "";
}
@@ -550,6 +554,9 @@ const char *ConversionSpecifier::toString() const {
// GlibC specific specifiers.
case PrintErrno: return "m";
+
+ // MS specific specifiers.
+ case ZArg: return "Z";
}
return nullptr;
}
@@ -608,8 +615,21 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
return true;
// Handle most integer flags
- case LengthModifier::AsChar:
case LengthModifier::AsShort:
+ if (Target.getTriple().isOSMSVCRT()) {
+ switch (CS.getKind()) {
+ case ConversionSpecifier::cArg:
+ case ConversionSpecifier::CArg:
+ case ConversionSpecifier::sArg:
+ case ConversionSpecifier::SArg:
+ case ConversionSpecifier::ZArg:
+ return true;
+ default:
+ break;
+ }
+ }
+ // Fall through.
+ case LengthModifier::AsChar:
case LengthModifier::AsLongLong:
case LengthModifier::AsQuad:
case LengthModifier::AsIntMax:
@@ -632,7 +652,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
}
// Handle 'l' flag
- case LengthModifier::AsLong:
+ case LengthModifier::AsLong: // or AsWideChar
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
case ConversionSpecifier::DArg:
@@ -655,6 +675,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
case ConversionSpecifier::cArg:
case ConversionSpecifier::sArg:
case ConversionSpecifier::ScanListArg:
+ case ConversionSpecifier::ZArg:
return true;
default:
return false;
@@ -719,6 +740,17 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
default:
return false;
}
+ case LengthModifier::AsWide:
+ switch (CS.getKind()) {
+ case ConversionSpecifier::cArg:
+ case ConversionSpecifier::CArg:
+ case ConversionSpecifier::sArg:
+ case ConversionSpecifier::SArg:
+ case ConversionSpecifier::ZArg:
+ return Target.getTriple().isOSMSVCRT();
+ default:
+ return false;
+ }
}
llvm_unreachable("Invalid LengthModifier Kind!");
}
@@ -741,6 +773,7 @@ bool FormatSpecifier::hasStandardLengthModifier() const {
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
case LengthModifier::AsInt64:
+ case LengthModifier::AsWide:
return false;
}
llvm_unreachable("Invalid LengthModifier Kind!");
@@ -778,6 +811,7 @@ bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt)
case ConversionSpecifier::DArg:
case ConversionSpecifier::OArg:
case ConversionSpecifier::UArg:
+ case ConversionSpecifier::ZArg:
return false;
}
llvm_unreachable("Invalid ConversionSpecifier Kind!");
diff --git a/lib/Analysis/FormatStringParsing.h b/lib/Analysis/FormatStringParsing.h
index fba318042cb0..e1652964b8c2 100644
--- a/lib/Analysis/FormatStringParsing.h
+++ b/lib/Analysis/FormatStringParsing.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_CLANG_FORMAT_PARSING_H
-#define LLVM_CLANG_FORMAT_PARSING_H
+#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
+#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 3d6fc039fd77..86b679cb155b 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -82,7 +82,6 @@ namespace {
class LiveVariablesImpl {
public:
AnalysisDeclContext &analysisContext;
- std::vector<LiveVariables::LivenessValues> cfgBlockValues;
llvm::ImmutableSet<const Stmt *>::Factory SSetFact;
llvm::ImmutableSet<const VarDecl *>::Factory DSetFact;
llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness;
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 082a8327a346..146635b88702 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -54,7 +54,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
const char *E,
unsigned &argIndex,
const LangOptions &LO,
- const TargetInfo &Target) {
+ const TargetInfo &Target,
+ bool Warn) {
using namespace clang::analyze_format_string;
using namespace clang::analyze_printf;
@@ -83,7 +84,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
if (I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -93,7 +95,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
if (I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -118,7 +121,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
if (I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -129,7 +133,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
if (I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -137,7 +142,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
if (*I == '.') {
++I;
if (I == E) {
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -147,7 +153,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
if (I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
}
@@ -155,7 +162,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
// Look for the length modifier.
if (ParseLengthModifier(FS, I, E, LO) && I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -198,7 +206,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case '@': k = ConversionSpecifier::ObjCObjArg; break;
// Glibc specific.
case 'm': k = ConversionSpecifier::PrintErrno; break;
- // Apple-specific
+ // Apple-specific.
case 'D':
if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::DArg;
@@ -211,6 +219,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::UArg;
break;
+ // MS specific.
+ case 'Z':
+ if (Target.getTriple().isOSMSVCRT())
+ k = ConversionSpecifier::ZArg;
}
PrintfConversionSpecifier CS(conversionPosition, k);
FS.setConversionSpecifier(CS);
@@ -235,7 +247,7 @@ bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
- LO, Target);
+ LO, Target, true);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
@@ -253,6 +265,34 @@ bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
return false;
}
+bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
+ const char *E,
+ const LangOptions &LO,
+ const TargetInfo &Target) {
+
+ unsigned argIndex = 0;
+
+ // Keep looking for a %s format specifier until we have exhausted the string.
+ FormatStringHandler H;
+ while (I != E) {
+ const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
+ LO, Target, false);
+ // Did a fail-stop error of any kind occur when parsing the specifier?
+ // If so, don't do any more processing.
+ if (FSR.shouldStop())
+ return false;
+ // Did we exhaust the string or encounter an error that
+ // we can recover from?
+ if (!FSR.hasValue())
+ continue;
+ const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
+ // Return true if this a %s format specifier.
+ if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
+ return true;
+ }
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Methods on PrintfSpecifier.
//===----------------------------------------------------------------------===//
@@ -266,9 +306,14 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
if (CS.getKind() == ConversionSpecifier::cArg)
switch (LM.getKind()) {
- case LengthModifier::None: return Ctx.IntTy;
+ case LengthModifier::None:
+ return Ctx.IntTy;
case LengthModifier::AsLong:
+ case LengthModifier::AsWide:
return ArgType(ArgType::WIntTy, "wint_t");
+ case LengthModifier::AsShort:
+ if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
+ return Ctx.IntTy;
default:
return ArgType::Invalid();
}
@@ -303,6 +348,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t");
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
+ case LengthModifier::AsWide:
return ArgType::Invalid();
}
@@ -337,6 +383,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
return ArgType();
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
+ case LengthModifier::AsWide:
return ArgType::Invalid();
}
@@ -372,6 +419,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
case LengthModifier::AsInt64:
+ case LengthModifier::AsWide:
return ArgType::Invalid();
}
}
@@ -384,15 +432,23 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
"const unichar *");
return ArgType(ArgType::WCStrTy, "wchar_t *");
}
+ if (LM.getKind() == LengthModifier::AsWide)
+ return ArgType(ArgType::WCStrTy, "wchar_t *");
return ArgType::CStrTy;
case ConversionSpecifier::SArg:
if (IsObjCLiteral)
return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
"const unichar *");
+ if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
+ LM.getKind() == LengthModifier::AsShort)
+ return ArgType::CStrTy;
return ArgType(ArgType::WCStrTy, "wchar_t *");
case ConversionSpecifier::CArg:
if (IsObjCLiteral)
return ArgType(Ctx.UnsignedShortTy, "unichar");
+ if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
+ LM.getKind() == LengthModifier::AsShort)
+ return Ctx.IntTy;
return ArgType(Ctx.WideCharTy, "wchar_t");
case ConversionSpecifier::pArg:
return ArgType::CPointerTy;
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index b4a72a7f8006..8165b09f4080 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -13,15 +13,15 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/ReachableCode.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/StmtCXX.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/StmtCXX.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index ed286274950b..d484d8e828cb 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -257,6 +257,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsMAllocate:
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
+ case LengthModifier::AsWide:
return ArgType::Invalid();
}
@@ -295,6 +296,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsMAllocate:
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
+ case LengthModifier::AsWide:
return ArgType::Invalid();
}
@@ -326,10 +328,14 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::None:
return ArgType::PtrTo(ArgType::AnyCharTy);
case LengthModifier::AsLong:
+ case LengthModifier::AsWide:
return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
return ArgType::PtrTo(ArgType::CStrTy);
+ case LengthModifier::AsShort:
+ if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
+ return ArgType::PtrTo(ArgType::AnyCharTy);
default:
return ArgType::Invalid();
}
@@ -338,10 +344,14 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
// FIXME: Mac OS X specific?
switch (LM.getKind()) {
case LengthModifier::None:
+ case LengthModifier::AsWide:
return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
+ case LengthModifier::AsShort:
+ if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
+ return ArgType::PtrTo(ArgType::AnyCharTy);
default:
return ArgType::Invalid();
}
@@ -378,6 +388,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsMAllocate:
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
+ case LengthModifier::AsWide:
return ArgType::Invalid();
}
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 11df61f80fa0..a986c587f869 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -22,10 +22,10 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
+#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
#include "clang/Analysis/Analyses/ThreadSafetyLogical.h"
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
-#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
@@ -40,762 +40,111 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <ostream>
+#include <sstream>
#include <utility>
#include <vector>
-using namespace clang;
-using namespace thread_safety;
+
+namespace clang {
+namespace threadSafety {
// Key method definition
ThreadSafetyHandler::~ThreadSafetyHandler() {}
-namespace {
-
-/// SExpr implements a simple expression language that is used to store,
-/// compare, and pretty-print C++ expressions. Unlike a clang Expr, a SExpr
-/// does not capture surface syntax, and it does not distinguish between
-/// C++ concepts, like pointers and references, that have no real semantic
-/// differences. This simplicity allows SExprs to be meaningfully compared,
-/// e.g.
-/// (x) = x
-/// (*this).foo = this->foo
-/// *&a = a
-///
-/// Thread-safety analysis works by comparing lock expressions. Within the
-/// body of a function, an expression such as "x->foo->bar.mu" will resolve to
-/// a particular mutex object at run-time. Subsequent occurrences of the same
-/// expression (where "same" means syntactic equality) will refer to the same
-/// run-time object if three conditions hold:
-/// (1) Local variables in the expression, such as "x" have not changed.
-/// (2) Values on the heap that affect the expression have not changed.
-/// (3) The expression involves only pure function calls.
-///
-/// The current implementation assumes, but does not verify, that multiple uses
-/// of the same lock expression satisfies these criteria.
-class SExpr {
-private:
- enum ExprOp {
- EOP_Nop, ///< No-op
- EOP_Wildcard, ///< Matches anything.
- EOP_Universal, ///< Universal lock.
- EOP_This, ///< This keyword.
- EOP_NVar, ///< Named variable.
- EOP_LVar, ///< Local variable.
- EOP_Dot, ///< Field access
- EOP_Call, ///< Function call
- EOP_MCall, ///< Method call
- EOP_Index, ///< Array index
- EOP_Unary, ///< Unary operation
- EOP_Binary, ///< Binary operation
- EOP_Unknown ///< Catchall for everything else
- };
-
-
- class SExprNode {
- private:
- unsigned char Op; ///< Opcode of the root node
- unsigned char Flags; ///< Additional opcode-specific data
- unsigned short Sz; ///< Number of child nodes
- const void* Data; ///< Additional opcode-specific data
-
- public:
- SExprNode(ExprOp O, unsigned F, const void* D)
- : Op(static_cast<unsigned char>(O)),
- Flags(static_cast<unsigned char>(F)), Sz(1), Data(D)
- { }
-
- unsigned size() const { return Sz; }
- void setSize(unsigned S) { Sz = S; }
-
- ExprOp kind() const { return static_cast<ExprOp>(Op); }
-
- const NamedDecl* getNamedDecl() const {
- assert(Op == EOP_NVar || Op == EOP_LVar || Op == EOP_Dot);
- return reinterpret_cast<const NamedDecl*>(Data);
- }
-
- const NamedDecl* getFunctionDecl() const {
- assert(Op == EOP_Call || Op == EOP_MCall);
- return reinterpret_cast<const NamedDecl*>(Data);
- }
-
- bool isArrow() const { return Op == EOP_Dot && Flags == 1; }
- void setArrow(bool A) { Flags = A ? 1 : 0; }
-
- unsigned arity() const {
- switch (Op) {
- case EOP_Nop: return 0;
- case EOP_Wildcard: return 0;
- case EOP_Universal: return 0;
- case EOP_NVar: return 0;
- case EOP_LVar: return 0;
- case EOP_This: return 0;
- case EOP_Dot: return 1;
- case EOP_Call: return Flags+1; // First arg is function.
- case EOP_MCall: return Flags+1; // First arg is implicit obj.
- case EOP_Index: return 2;
- case EOP_Unary: return 1;
- case EOP_Binary: return 2;
- case EOP_Unknown: return Flags;
- }
- return 0;
- }
-
- bool operator==(const SExprNode& Other) const {
- // Ignore flags and size -- they don't matter.
- return (Op == Other.Op &&
- Data == Other.Data);
- }
-
- bool operator!=(const SExprNode& Other) const {
- return !(*this == Other);
- }
-
- bool matches(const SExprNode& Other) const {
- return (*this == Other) ||
- (Op == EOP_Wildcard) ||
- (Other.Op == EOP_Wildcard);
- }
- };
-
-
- /// \brief Encapsulates the lexical context of a function call. The lexical
- /// context includes the arguments to the call, including the implicit object
- /// argument. When an attribute containing a mutex expression is attached to
- /// a method, the expression may refer to formal parameters of the method.
- /// Actual arguments must be substituted for formal parameters to derive
- /// the appropriate mutex expression in the lexical context where the function
- /// is called. PrevCtx holds the context in which the arguments themselves
- /// should be evaluated; multiple calling contexts can be chained together
- /// by the lock_returned attribute.
- struct CallingContext {
- const NamedDecl* AttrDecl; // The decl to which the attribute is attached.
- const Expr* SelfArg; // Implicit object argument -- e.g. 'this'
- bool SelfArrow; // is Self referred to with -> or .?
- unsigned NumArgs; // Number of funArgs
- const Expr* const* FunArgs; // Function arguments
- CallingContext* PrevCtx; // The previous context; or 0 if none.
-
- CallingContext(const NamedDecl *D)
- : AttrDecl(D), SelfArg(nullptr), SelfArrow(false), NumArgs(0),
- FunArgs(nullptr), PrevCtx(nullptr) {}
- };
-
- typedef SmallVector<SExprNode, 4> NodeVector;
-
-private:
- // A SExpr is a list of SExprNodes in prefix order. The Size field allows
- // the list to be traversed as a tree.
- NodeVector NodeVec;
-
-private:
- unsigned make(ExprOp O, unsigned F = 0, const void *D = nullptr) {
- NodeVec.push_back(SExprNode(O, F, D));
- return NodeVec.size() - 1;
- }
-
- unsigned makeNop() {
- return make(EOP_Nop);
- }
-
- unsigned makeWildcard() {
- return make(EOP_Wildcard);
- }
-
- unsigned makeUniversal() {
- return make(EOP_Universal);
- }
-
- unsigned makeNamedVar(const NamedDecl *D) {
- return make(EOP_NVar, 0, D);
- }
-
- unsigned makeLocalVar(const NamedDecl *D) {
- return make(EOP_LVar, 0, D);
- }
-
- unsigned makeThis() {
- return make(EOP_This);
- }
-
- unsigned makeDot(const NamedDecl *D, bool Arrow) {
- return make(EOP_Dot, Arrow ? 1 : 0, D);
- }
-
- unsigned makeCall(unsigned NumArgs, const NamedDecl *D) {
- return make(EOP_Call, NumArgs, D);
- }
-
- // Grab the very first declaration of virtual method D
- const CXXMethodDecl* getFirstVirtualDecl(const CXXMethodDecl *D) {
- while (true) {
- D = D->getCanonicalDecl();
- CXXMethodDecl::method_iterator I = D->begin_overridden_methods(),
- E = D->end_overridden_methods();
- if (I == E)
- return D; // Method does not override anything
- D = *I; // FIXME: this does not work with multiple inheritance.
- }
- return nullptr;
- }
-
- unsigned makeMCall(unsigned NumArgs, const CXXMethodDecl *D) {
- return make(EOP_MCall, NumArgs, getFirstVirtualDecl(D));
- }
-
- unsigned makeIndex() {
- return make(EOP_Index);
- }
-
- unsigned makeUnary() {
- return make(EOP_Unary);
- }
-
- unsigned makeBinary() {
- return make(EOP_Binary);
- }
-
- unsigned makeUnknown(unsigned Arity) {
- return make(EOP_Unknown, Arity);
- }
-
- inline bool isCalleeArrow(const Expr *E) {
- const MemberExpr *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts());
- return ME ? ME->isArrow() : false;
- }
-
- /// Build an SExpr from the given C++ expression.
- /// Recursive function that terminates on DeclRefExpr.
- /// Note: this function merely creates a SExpr; it does not check to
- /// ensure that the original expression is a valid mutex expression.
- ///
- /// NDeref returns the number of Derefence and AddressOf operations
- /// preceding the Expr; this is used to decide whether to pretty-print
- /// SExprs with . or ->.
- unsigned buildSExpr(const Expr *Exp, CallingContext *CallCtx,
- int *NDeref = nullptr) {
- if (!Exp)
- return 0;
-
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) {
- const NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl());
- const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(ND);
- if (PV) {
- const FunctionDecl *FD =
- cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
- unsigned i = PV->getFunctionScopeIndex();
+class TILPrinter :
+ public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {};
- if (CallCtx && CallCtx->FunArgs &&
- FD == CallCtx->AttrDecl->getCanonicalDecl()) {
- // Substitute call arguments for references to function parameters
- assert(i < CallCtx->NumArgs);
- return buildSExpr(CallCtx->FunArgs[i], CallCtx->PrevCtx, NDeref);
- }
- // Map the param back to the param of the original function declaration.
- makeNamedVar(FD->getParamDecl(i));
- return 1;
- }
- // Not a function parameter -- just store the reference.
- makeNamedVar(ND);
- return 1;
- } else if (isa<CXXThisExpr>(Exp)) {
- // Substitute parent for 'this'
- if (CallCtx && CallCtx->SelfArg) {
- if (!CallCtx->SelfArrow && NDeref)
- // 'this' is a pointer, but self is not, so need to take address.
- --(*NDeref);
- return buildSExpr(CallCtx->SelfArg, CallCtx->PrevCtx, NDeref);
- }
- else {
- makeThis();
- return 1;
- }
- } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
- const NamedDecl *ND = ME->getMemberDecl();
- int ImplicitDeref = ME->isArrow() ? 1 : 0;
- unsigned Root = makeDot(ND, false);
- unsigned Sz = buildSExpr(ME->getBase(), CallCtx, &ImplicitDeref);
- NodeVec[Root].setArrow(ImplicitDeref > 0);
- NodeVec[Root].setSize(Sz + 1);
- return Sz + 1;
- } else if (const CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) {
- // When calling a function with a lock_returned attribute, replace
- // the function call with the expression in lock_returned.
- const CXXMethodDecl *MD = CMCE->getMethodDecl()->getMostRecentDecl();
- if (LockReturnedAttr* At = MD->getAttr<LockReturnedAttr>()) {
- CallingContext LRCallCtx(CMCE->getMethodDecl());
- LRCallCtx.SelfArg = CMCE->getImplicitObjectArgument();
- LRCallCtx.SelfArrow = isCalleeArrow(CMCE->getCallee());
- LRCallCtx.NumArgs = CMCE->getNumArgs();
- LRCallCtx.FunArgs = CMCE->getArgs();
- LRCallCtx.PrevCtx = CallCtx;
- return buildSExpr(At->getArg(), &LRCallCtx);
- }
- // Hack to treat smart pointers and iterators as pointers;
- // ignore any method named get().
- if (CMCE->getMethodDecl()->getNameAsString() == "get" &&
- CMCE->getNumArgs() == 0) {
- if (NDeref && isCalleeArrow(CMCE->getCallee()))
- ++(*NDeref);
- return buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx, NDeref);
- }
- unsigned NumCallArgs = CMCE->getNumArgs();
- unsigned Root = makeMCall(NumCallArgs, CMCE->getMethodDecl());
- unsigned Sz = buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx);
- const Expr* const* CallArgs = CMCE->getArgs();
- for (unsigned i = 0; i < NumCallArgs; ++i) {
- Sz += buildSExpr(CallArgs[i], CallCtx);
- }
- NodeVec[Root].setSize(Sz + 1);
- return Sz + 1;
- } else if (const CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
- const FunctionDecl *FD = CE->getDirectCallee()->getMostRecentDecl();
- if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) {
- CallingContext LRCallCtx(CE->getDirectCallee());
- LRCallCtx.NumArgs = CE->getNumArgs();
- LRCallCtx.FunArgs = CE->getArgs();
- LRCallCtx.PrevCtx = CallCtx;
- return buildSExpr(At->getArg(), &LRCallCtx);
- }
- // Treat smart pointers and iterators as pointers;
- // ignore the * and -> operators.
- if (const CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(CE)) {
- OverloadedOperatorKind k = OE->getOperator();
- if (k == OO_Star) {
- if (NDeref) ++(*NDeref);
- return buildSExpr(OE->getArg(0), CallCtx, NDeref);
- }
- else if (k == OO_Arrow) {
- return buildSExpr(OE->getArg(0), CallCtx, NDeref);
- }
- }
- unsigned NumCallArgs = CE->getNumArgs();
- unsigned Root = makeCall(NumCallArgs, nullptr);
- unsigned Sz = buildSExpr(CE->getCallee(), CallCtx);
- const Expr* const* CallArgs = CE->getArgs();
- for (unsigned i = 0; i < NumCallArgs; ++i) {
- Sz += buildSExpr(CallArgs[i], CallCtx);
- }
- NodeVec[Root].setSize(Sz+1);
- return Sz+1;
- } else if (const BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) {
- unsigned Root = makeBinary();
- unsigned Sz = buildSExpr(BOE->getLHS(), CallCtx);
- Sz += buildSExpr(BOE->getRHS(), CallCtx);
- NodeVec[Root].setSize(Sz);
- return Sz;
- } else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) {
- // Ignore & and * operators -- they're no-ops.
- // However, we try to figure out whether the expression is a pointer,
- // so we can use . and -> appropriately in error messages.
- if (UOE->getOpcode() == UO_Deref) {
- if (NDeref) ++(*NDeref);
- return buildSExpr(UOE->getSubExpr(), CallCtx, NDeref);
- }
- if (UOE->getOpcode() == UO_AddrOf) {
- if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(UOE->getSubExpr())) {
- if (DRE->getDecl()->isCXXInstanceMember()) {
- // This is a pointer-to-member expression, e.g. &MyClass::mu_.
- // We interpret this syntax specially, as a wildcard.
- unsigned Root = makeDot(DRE->getDecl(), false);
- makeWildcard();
- NodeVec[Root].setSize(2);
- return 2;
- }
- }
- if (NDeref) --(*NDeref);
- return buildSExpr(UOE->getSubExpr(), CallCtx, NDeref);
- }
- unsigned Root = makeUnary();
- unsigned Sz = buildSExpr(UOE->getSubExpr(), CallCtx);
- NodeVec[Root].setSize(Sz);
- return Sz;
- } else if (const ArraySubscriptExpr *ASE =
- dyn_cast<ArraySubscriptExpr>(Exp)) {
- unsigned Root = makeIndex();
- unsigned Sz = buildSExpr(ASE->getBase(), CallCtx);
- Sz += buildSExpr(ASE->getIdx(), CallCtx);
- NodeVec[Root].setSize(Sz);
- return Sz;
- } else if (const AbstractConditionalOperator *CE =
- dyn_cast<AbstractConditionalOperator>(Exp)) {
- unsigned Root = makeUnknown(3);
- unsigned Sz = buildSExpr(CE->getCond(), CallCtx);
- Sz += buildSExpr(CE->getTrueExpr(), CallCtx);
- Sz += buildSExpr(CE->getFalseExpr(), CallCtx);
- NodeVec[Root].setSize(Sz);
- return Sz;
- } else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) {
- unsigned Root = makeUnknown(3);
- unsigned Sz = buildSExpr(CE->getCond(), CallCtx);
- Sz += buildSExpr(CE->getLHS(), CallCtx);
- Sz += buildSExpr(CE->getRHS(), CallCtx);
- NodeVec[Root].setSize(Sz);
- return Sz;
- } else if (const CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
- return buildSExpr(CE->getSubExpr(), CallCtx, NDeref);
- } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
- return buildSExpr(PE->getSubExpr(), CallCtx, NDeref);
- } else if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Exp)) {
- return buildSExpr(EWC->getSubExpr(), CallCtx, NDeref);
- } else if (const CXXBindTemporaryExpr *E = dyn_cast<CXXBindTemporaryExpr>(Exp)) {
- return buildSExpr(E->getSubExpr(), CallCtx, NDeref);
- } else if (isa<CharacterLiteral>(Exp) ||
- isa<CXXNullPtrLiteralExpr>(Exp) ||
- isa<GNUNullExpr>(Exp) ||
- isa<CXXBoolLiteralExpr>(Exp) ||
- isa<FloatingLiteral>(Exp) ||
- isa<ImaginaryLiteral>(Exp) ||
- isa<IntegerLiteral>(Exp) ||
- isa<StringLiteral>(Exp) ||
- isa<ObjCStringLiteral>(Exp)) {
- makeNop();
- return 1; // FIXME: Ignore literals for now
- } else {
- makeNop();
- return 1; // Ignore. FIXME: mark as invalid expression?
- }
- }
-
- /// \brief Construct a SExpr from an expression.
- /// \param MutexExp The original mutex expression within an attribute
- /// \param DeclExp An expression involving the Decl on which the attribute
- /// occurs.
- /// \param D The declaration to which the lock/unlock attribute is attached.
- void buildSExprFromExpr(const Expr *MutexExp, const Expr *DeclExp,
- const NamedDecl *D, VarDecl *SelfDecl = nullptr) {
- CallingContext CallCtx(D);
-
- if (MutexExp) {
- if (const StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) {
- if (SLit->getString() == StringRef("*"))
- // The "*" expr is a universal lock, which essentially turns off
- // checks until it is removed from the lockset.
- makeUniversal();
- else
- // Ignore other string literals for now.
- makeNop();
- return;
- }
- }
-
- // If we are processing a raw attribute expression, with no substitutions.
- if (!DeclExp) {
- buildSExpr(MutexExp, nullptr);
- return;
- }
- // Examine DeclExp to find SelfArg and FunArgs, which are used to substitute
- // for formal parameters when we call buildMutexID later.
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
- CallCtx.SelfArg = ME->getBase();
- CallCtx.SelfArrow = ME->isArrow();
- } else if (const CXXMemberCallExpr *CE =
- dyn_cast<CXXMemberCallExpr>(DeclExp)) {
- CallCtx.SelfArg = CE->getImplicitObjectArgument();
- CallCtx.SelfArrow = isCalleeArrow(CE->getCallee());
- CallCtx.NumArgs = CE->getNumArgs();
- CallCtx.FunArgs = CE->getArgs();
- } else if (const CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
- CallCtx.NumArgs = CE->getNumArgs();
- CallCtx.FunArgs = CE->getArgs();
- } else if (const CXXConstructExpr *CE =
- dyn_cast<CXXConstructExpr>(DeclExp)) {
- CallCtx.SelfArg = nullptr; // Will be set below
- CallCtx.NumArgs = CE->getNumArgs();
- CallCtx.FunArgs = CE->getArgs();
- } else if (D && isa<CXXDestructorDecl>(D)) {
- // There's no such thing as a "destructor call" in the AST.
- CallCtx.SelfArg = DeclExp;
- }
+/// Issue a warning about an invalid lock expression
+static void warnInvalidLock(ThreadSafetyHandler &Handler,
+ const Expr *MutexExp, const NamedDecl *D,
+ const Expr *DeclExp, StringRef Kind) {
+ SourceLocation Loc;
+ if (DeclExp)
+ Loc = DeclExp->getExprLoc();
- // Hack to handle constructors, where self cannot be recovered from
- // the expression.
- if (SelfDecl && !CallCtx.SelfArg) {
- DeclRefExpr SelfDRE(SelfDecl, false, SelfDecl->getType(), VK_LValue,
- SelfDecl->getLocation());
- CallCtx.SelfArg = &SelfDRE;
-
- // If the attribute has no arguments, then assume the argument is "this".
- if (!MutexExp)
- buildSExpr(CallCtx.SelfArg, nullptr);
- else // For most attributes.
- buildSExpr(MutexExp, &CallCtx);
- return;
- }
-
- // If the attribute has no arguments, then assume the argument is "this".
- if (!MutexExp)
- buildSExpr(CallCtx.SelfArg, nullptr);
- else // For most attributes.
- buildSExpr(MutexExp, &CallCtx);
- }
-
- /// \brief Get index of next sibling of node i.
- unsigned getNextSibling(unsigned i) const {
- return i + NodeVec[i].size();
- }
-
-public:
- explicit SExpr(clang::Decl::EmptyShell e) { NodeVec.clear(); }
-
- /// \param MutexExp The original mutex expression within an attribute
- /// \param DeclExp An expression involving the Decl on which the attribute
- /// occurs.
- /// \param D The declaration to which the lock/unlock attribute is attached.
- /// Caller must check isValid() after construction.
- SExpr(const Expr *MutexExp, const Expr *DeclExp, const NamedDecl *D,
- VarDecl *SelfDecl = nullptr) {
- buildSExprFromExpr(MutexExp, DeclExp, D, SelfDecl);
- }
-
- /// Return true if this is a valid decl sequence.
- /// Caller must call this by hand after construction to handle errors.
- bool isValid() const {
- return !NodeVec.empty();
- }
-
- bool shouldIgnore() const {
- // Nop is a mutex that we have decided to deliberately ignore.
- assert(NodeVec.size() > 0 && "Invalid Mutex");
- return NodeVec[0].kind() == EOP_Nop;
- }
-
- bool isUniversal() const {
- assert(NodeVec.size() > 0 && "Invalid Mutex");
- return NodeVec[0].kind() == EOP_Universal;
- }
-
- /// Issue a warning about an invalid lock expression
- static void warnInvalidLock(ThreadSafetyHandler &Handler,
- const Expr *MutexExp, const Expr *DeclExp,
- const NamedDecl *D, StringRef Kind) {
- SourceLocation Loc;
- if (DeclExp)
- Loc = DeclExp->getExprLoc();
-
- // FIXME: add a note about the attribute location in MutexExp or D
- if (Loc.isValid())
- Handler.handleInvalidLockExp(Kind, Loc);
- }
-
- bool operator==(const SExpr &other) const {
- return NodeVec == other.NodeVec;
- }
-
- bool operator!=(const SExpr &other) const {
- return !(*this == other);
- }
-
- bool matches(const SExpr &Other, unsigned i = 0, unsigned j = 0) const {
- if (NodeVec[i].matches(Other.NodeVec[j])) {
- unsigned ni = NodeVec[i].arity();
- unsigned nj = Other.NodeVec[j].arity();
- unsigned n = (ni < nj) ? ni : nj;
- bool Result = true;
- unsigned ci = i+1; // first child of i
- unsigned cj = j+1; // first child of j
- for (unsigned k = 0; k < n;
- ++k, ci=getNextSibling(ci), cj = Other.getNextSibling(cj)) {
- Result = Result && matches(Other, ci, cj);
- }
- return Result;
- }
- return false;
- }
-
- // A partial match between a.mu and b.mu returns true a and b have the same
- // type (and thus mu refers to the same mutex declaration), regardless of
- // whether a and b are different objects or not.
- bool partiallyMatches(const SExpr &Other) const {
- if (NodeVec[0].kind() == EOP_Dot)
- return NodeVec[0].matches(Other.NodeVec[0]);
- return false;
- }
-
- /// \brief Pretty print a lock expression for use in error messages.
- std::string toString(unsigned i = 0) const {
- assert(isValid());
- if (i >= NodeVec.size())
- return "";
-
- const SExprNode* N = &NodeVec[i];
- switch (N->kind()) {
- case EOP_Nop:
- return "_";
- case EOP_Wildcard:
- return "(?)";
- case EOP_Universal:
- return "*";
- case EOP_This:
- return "this";
- case EOP_NVar:
- case EOP_LVar: {
- return N->getNamedDecl()->getNameAsString();
- }
- case EOP_Dot: {
- if (NodeVec[i+1].kind() == EOP_Wildcard) {
- std::string S = "&";
- S += N->getNamedDecl()->getQualifiedNameAsString();
- return S;
- }
- std::string FieldName = N->getNamedDecl()->getNameAsString();
- if (NodeVec[i+1].kind() == EOP_This)
- return FieldName;
+ // FIXME: add a note about the attribute location in MutexExp or D
+ if (Loc.isValid())
+ Handler.handleInvalidLockExp(Kind, Loc);
+}
- std::string S = toString(i+1);
- if (N->isArrow())
- return S + "->" + FieldName;
- else
- return S + "." + FieldName;
- }
- case EOP_Call: {
- std::string S = toString(i+1) + "(";
- unsigned NumArgs = N->arity()-1;
- unsigned ci = getNextSibling(i+1);
- for (unsigned k=0; k<NumArgs; ++k, ci = getNextSibling(ci)) {
- S += toString(ci);
- if (k+1 < NumArgs) S += ",";
- }
- S += ")";
- return S;
- }
- case EOP_MCall: {
- std::string S = "";
- if (NodeVec[i+1].kind() != EOP_This)
- S = toString(i+1) + ".";
- if (const NamedDecl *D = N->getFunctionDecl())
- S += D->getNameAsString() + "(";
- else
- S += "#(";
- unsigned NumArgs = N->arity()-1;
- unsigned ci = getNextSibling(i+1);
- for (unsigned k=0; k<NumArgs; ++k, ci = getNextSibling(ci)) {
- S += toString(ci);
- if (k+1 < NumArgs) S += ",";
- }
- S += ")";
- return S;
- }
- case EOP_Index: {
- std::string S1 = toString(i+1);
- std::string S2 = toString(i+1 + NodeVec[i+1].size());
- return S1 + "[" + S2 + "]";
- }
- case EOP_Unary: {
- std::string S = toString(i+1);
- return "#" + S;
- }
- case EOP_Binary: {
- std::string S1 = toString(i+1);
- std::string S2 = toString(i+1 + NodeVec[i+1].size());
- return "(" + S1 + "#" + S2 + ")";
- }
- case EOP_Unknown: {
- unsigned NumChildren = N->arity();
- if (NumChildren == 0)
- return "(...)";
- std::string S = "(";
- unsigned ci = i+1;
- for (unsigned j = 0; j < NumChildren; ++j, ci = getNextSibling(ci)) {
- S += toString(ci);
- if (j+1 < NumChildren) S += "#";
- }
- S += ")";
- return S;
- }
- }
- return "";
- }
-};
-/// \brief A short list of SExprs
-class MutexIDList : public SmallVector<SExpr, 3> {
+/// \brief A set of CapabilityInfo objects, which are compiled from the
+/// requires attributes on a function.
+class CapExprSet : public SmallVector<CapabilityExpr, 4> {
public:
/// \brief Push M onto list, but discard duplicates.
- void push_back_nodup(const SExpr& M) {
- if (end() == std::find(begin(), end(), M))
- push_back(M);
+ void push_back_nodup(const CapabilityExpr &CapE) {
+ iterator It = std::find_if(begin(), end(),
+ [=](const CapabilityExpr &CapE2) {
+ return CapE.equals(CapE2);
+ });
+ if (It == end())
+ push_back(CapE);
}
};
-/// \brief This is a helper class that stores info about the most recent
-/// accquire of a Lock.
-///
-/// The main body of the analysis maps MutexIDs to LockDatas.
-struct LockData {
- SourceLocation AcquireLoc;
-
- /// \brief LKind stores whether a lock is held shared or exclusively.
- /// Note that this analysis does not currently support either re-entrant
- /// locking or lock "upgrading" and "downgrading" between exclusive and
- /// shared.
- ///
- /// FIXME: add support for re-entrant locking and lock up/downgrading
- LockKind LKind;
- bool Asserted; // for asserted locks
- bool Managed; // for ScopedLockable objects
- SExpr UnderlyingMutex; // for ScopedLockable objects
-
- LockData(SourceLocation AcquireLoc, LockKind LKind, bool M=false,
- bool Asrt=false)
- : AcquireLoc(AcquireLoc), LKind(LKind), Asserted(Asrt), Managed(M),
- UnderlyingMutex(Decl::EmptyShell())
- {}
+class FactManager;
+class FactSet;
- LockData(SourceLocation AcquireLoc, LockKind LKind, const SExpr &Mu)
- : AcquireLoc(AcquireLoc), LKind(LKind), Asserted(false), Managed(false),
- UnderlyingMutex(Mu)
- {}
-
- bool operator==(const LockData &other) const {
- return AcquireLoc == other.AcquireLoc && LKind == other.LKind;
- }
-
- bool operator!=(const LockData &other) const {
- return !(*this == other);
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(AcquireLoc.getRawEncoding());
- ID.AddInteger(LKind);
- }
+/// \brief This is a helper class that stores a fact that is known at a
+/// particular point in program execution. Currently, a fact is a capability,
+/// along with additional information, such as where it was acquired, whether
+/// it is exclusive or shared, etc.
+///
+/// FIXME: this analysis does not currently support either re-entrant
+/// locking or lock "upgrading" and "downgrading" between exclusive and
+/// shared.
+class FactEntry : public CapabilityExpr {
+private:
+ LockKind LKind; ///< exclusive or shared
+ SourceLocation AcquireLoc; ///< where it was acquired.
+ bool Asserted; ///< true if the lock was asserted
+public:
+ FactEntry(const CapabilityExpr &CE, LockKind LK, SourceLocation Loc,
+ bool Asrt)
+ : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt) {}
+
+ virtual ~FactEntry() {}
+
+ LockKind kind() const { return LKind; }
+ SourceLocation loc() const { return AcquireLoc; }
+ bool asserted() const { return Asserted; }
+
+ virtual void
+ handleRemovalFromIntersection(const FactSet &FSet, FactManager &FactMan,
+ SourceLocation JoinLoc, LockErrorKind LEK,
+ ThreadSafetyHandler &Handler) const = 0;
+ virtual void handleUnlock(FactSet &FSet, FactManager &FactMan,
+ const CapabilityExpr &Cp, SourceLocation UnlockLoc,
+ bool FullyRemove, ThreadSafetyHandler &Handler,
+ StringRef DiagKind) const = 0;
+
+ // Return true if LKind >= LK, where exclusive > shared
bool isAtLeast(LockKind LK) {
- return (LK == LK_Shared) || (LKind == LK_Exclusive);
+ return (LKind == LK_Exclusive) || (LK == LK_Shared);
}
};
-/// \brief A FactEntry stores a single fact that is known at a particular point
-/// in the program execution. Currently, this is information regarding a lock
-/// that is held at that point.
-struct FactEntry {
- SExpr MutID;
- LockData LDat;
-
- FactEntry(const SExpr& M, const LockData& L)
- : MutID(M), LDat(L)
- { }
-};
-
-
typedef unsigned short FactID;
/// \brief FactManager manages the memory for all facts that are created during
/// the analysis of a single routine.
class FactManager {
private:
- std::vector<FactEntry> Facts;
+ std::vector<std::unique_ptr<FactEntry>> Facts;
public:
- FactID newLock(const SExpr& M, const LockData& L) {
- Facts.push_back(FactEntry(M,L));
+ FactID newFact(std::unique_ptr<FactEntry> Entry) {
+ Facts.push_back(std::move(Entry));
return static_cast<unsigned short>(Facts.size() - 1);
}
- const FactEntry& operator[](FactID F) const { return Facts[F]; }
- FactEntry& operator[](FactID F) { return Facts[F]; }
+ const FactEntry &operator[](FactID F) const { return *Facts[F]; }
+ FactEntry &operator[](FactID F) { return *Facts[F]; }
};
@@ -824,68 +173,73 @@ public:
bool isEmpty() const { return FactIDs.size() == 0; }
- FactID addLock(FactManager& FM, const SExpr& M, const LockData& L) {
- FactID F = FM.newLock(M, L);
+ // Return true if the set contains only negative facts
+ bool isEmpty(FactManager &FactMan) const {
+ for (FactID FID : *this) {
+ if (!FactMan[FID].negative())
+ return false;
+ }
+ return true;
+ }
+
+ void addLockByID(FactID ID) { FactIDs.push_back(ID); }
+
+ FactID addLock(FactManager &FM, std::unique_ptr<FactEntry> Entry) {
+ FactID F = FM.newFact(std::move(Entry));
FactIDs.push_back(F);
return F;
}
- bool removeLock(FactManager& FM, const SExpr& M) {
+ bool removeLock(FactManager& FM, const CapabilityExpr &CapE) {
unsigned n = FactIDs.size();
if (n == 0)
return false;
for (unsigned i = 0; i < n-1; ++i) {
- if (FM[FactIDs[i]].MutID.matches(M)) {
+ if (FM[FactIDs[i]].matches(CapE)) {
FactIDs[i] = FactIDs[n-1];
FactIDs.pop_back();
return true;
}
}
- if (FM[FactIDs[n-1]].MutID.matches(M)) {
+ if (FM[FactIDs[n-1]].matches(CapE)) {
FactIDs.pop_back();
return true;
}
return false;
}
- iterator findLockIter(FactManager &FM, const SExpr &M) {
+ iterator findLockIter(FactManager &FM, const CapabilityExpr &CapE) {
return std::find_if(begin(), end(), [&](FactID ID) {
- return FM[ID].MutID.matches(M);
+ return FM[ID].matches(CapE);
});
}
- LockData *findLock(FactManager &FM, const SExpr &M) const {
+ FactEntry *findLock(FactManager &FM, const CapabilityExpr &CapE) const {
auto I = std::find_if(begin(), end(), [&](FactID ID) {
- return FM[ID].MutID.matches(M);
+ return FM[ID].matches(CapE);
});
-
- return I != end() ? &FM[*I].LDat : nullptr;
+ return I != end() ? &FM[*I] : nullptr;
}
- LockData *findLockUniv(FactManager &FM, const SExpr &M) const {
+ FactEntry *findLockUniv(FactManager &FM, const CapabilityExpr &CapE) const {
auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool {
- const SExpr &Expr = FM[ID].MutID;
- return Expr.isUniversal() || Expr.matches(M);
+ return FM[ID].matchesUniv(CapE);
});
-
- return I != end() ? &FM[*I].LDat : nullptr;
+ return I != end() ? &FM[*I] : nullptr;
}
- FactEntry *findPartialMatch(FactManager &FM, const SExpr &M) const {
+ FactEntry *findPartialMatch(FactManager &FM,
+ const CapabilityExpr &CapE) const {
auto I = std::find_if(begin(), end(), [&](FactID ID) {
- return FM[ID].MutID.partiallyMatches(M);
+ return FM[ID].partiallyMatches(CapE);
});
-
return I != end() ? &FM[*I] : nullptr;
}
};
-/// A Lockset maps each SExpr (defined above) to information about how it has
-/// been locked.
-typedef llvm::ImmutableMap<SExpr, LockData> Lockset;
-typedef llvm::ImmutableMap<const NamedDecl*, unsigned> LocalVarContext;
+typedef llvm::ImmutableMap<const NamedDecl*, unsigned> LocalVarContext;
class LocalVariableMap;
/// A side (entry or exit) of a CFG node.
@@ -1404,29 +758,130 @@ static void findBlockLocations(CFG *CFGraph,
}
}
+class LockableFactEntry : public FactEntry {
+private:
+ bool Managed; ///< managed by ScopedLockable object
+
+public:
+ LockableFactEntry(const CapabilityExpr &CE, LockKind LK, SourceLocation Loc,
+ bool Mng = false, bool Asrt = false)
+ : FactEntry(CE, LK, Loc, Asrt), Managed(Mng) {}
+
+ void
+ handleRemovalFromIntersection(const FactSet &FSet, FactManager &FactMan,
+ SourceLocation JoinLoc, LockErrorKind LEK,
+ ThreadSafetyHandler &Handler) const override {
+ if (!Managed && !asserted() && !negative() && !isUniversal()) {
+ Handler.handleMutexHeldEndOfScope("mutex", toString(), loc(), JoinLoc,
+ LEK);
+ }
+ }
+
+ void handleUnlock(FactSet &FSet, FactManager &FactMan,
+ const CapabilityExpr &Cp, SourceLocation UnlockLoc,
+ bool FullyRemove, ThreadSafetyHandler &Handler,
+ StringRef DiagKind) const override {
+ FSet.removeLock(FactMan, Cp);
+ if (!Cp.negative()) {
+ FSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
+ !Cp, LK_Exclusive, UnlockLoc));
+ }
+ }
+};
+
+class ScopedLockableFactEntry : public FactEntry {
+private:
+ SmallVector<const til::SExpr *, 4> UnderlyingMutexes;
+
+public:
+ ScopedLockableFactEntry(const CapabilityExpr &CE, SourceLocation Loc,
+ const CapExprSet &Excl, const CapExprSet &Shrd)
+ : FactEntry(CE, LK_Exclusive, Loc, false) {
+ for (const auto &M : Excl)
+ UnderlyingMutexes.push_back(M.sexpr());
+ for (const auto &M : Shrd)
+ UnderlyingMutexes.push_back(M.sexpr());
+ }
+
+ void
+ handleRemovalFromIntersection(const FactSet &FSet, FactManager &FactMan,
+ SourceLocation JoinLoc, LockErrorKind LEK,
+ ThreadSafetyHandler &Handler) const override {
+ for (const til::SExpr *UnderlyingMutex : UnderlyingMutexes) {
+ if (FSet.findLock(FactMan, CapabilityExpr(UnderlyingMutex, false))) {
+ // If this scoped lock manages another mutex, and if the underlying
+ // mutex is still held, then warn about the underlying mutex.
+ Handler.handleMutexHeldEndOfScope(
+ "mutex", sx::toString(UnderlyingMutex), loc(), JoinLoc, LEK);
+ }
+ }
+ }
+
+ void handleUnlock(FactSet &FSet, FactManager &FactMan,
+ const CapabilityExpr &Cp, SourceLocation UnlockLoc,
+ bool FullyRemove, ThreadSafetyHandler &Handler,
+ StringRef DiagKind) const override {
+ assert(!Cp.negative() && "Managing object cannot be negative.");
+ for (const til::SExpr *UnderlyingMutex : UnderlyingMutexes) {
+ CapabilityExpr UnderCp(UnderlyingMutex, false);
+ auto UnderEntry = llvm::make_unique<LockableFactEntry>(
+ !UnderCp, LK_Exclusive, UnlockLoc);
+
+ if (FullyRemove) {
+ // We're destroying the managing object.
+ // Remove the underlying mutex if it exists; but don't warn.
+ if (FSet.findLock(FactMan, UnderCp)) {
+ FSet.removeLock(FactMan, UnderCp);
+ FSet.addLock(FactMan, std::move(UnderEntry));
+ }
+ } else {
+ // We're releasing the underlying mutex, but not destroying the
+ // managing object. Warn on dual release.
+ if (!FSet.findLock(FactMan, UnderCp)) {
+ Handler.handleUnmatchedUnlock(DiagKind, UnderCp.toString(),
+ UnlockLoc);
+ }
+ FSet.removeLock(FactMan, UnderCp);
+ FSet.addLock(FactMan, std::move(UnderEntry));
+ }
+ }
+ if (FullyRemove)
+ FSet.removeLock(FactMan, Cp);
+ }
+};
+
/// \brief Class which implements the core thread safety analysis routines.
class ThreadSafetyAnalyzer {
friend class BuildLockset;
+ llvm::BumpPtrAllocator Bpa;
+ threadSafety::til::MemRegionRef Arena;
+ threadSafety::SExprBuilder SxBuilder;
+
ThreadSafetyHandler &Handler;
+ const CXXMethodDecl *CurrentMethod;
LocalVariableMap LocalVarMap;
FactManager FactMan;
std::vector<CFGBlockInfo> BlockInfo;
public:
- ThreadSafetyAnalyzer(ThreadSafetyHandler &H) : Handler(H) {}
+ ThreadSafetyAnalyzer(ThreadSafetyHandler &H)
+ : Arena(&Bpa), SxBuilder(Arena), Handler(H) {}
+
+ bool inCurrentScope(const CapabilityExpr &CapE);
- void addLock(FactSet &FSet, const SExpr &Mutex, const LockData &LDat,
- StringRef DiagKind);
- void removeLock(FactSet &FSet, const SExpr &Mutex, SourceLocation UnlockLoc,
- bool FullyRemove, LockKind Kind, StringRef DiagKind);
+ void addLock(FactSet &FSet, std::unique_ptr<FactEntry> Entry,
+ StringRef DiagKind, bool ReqAttr = false);
+ void removeLock(FactSet &FSet, const CapabilityExpr &CapE,
+ SourceLocation UnlockLoc, bool FullyRemove, LockKind Kind,
+ StringRef DiagKind);
template <typename AttrType>
- void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
+ void getMutexIDs(CapExprSet &Mtxs, AttrType *Attr, Expr *Exp,
const NamedDecl *D, VarDecl *SelfDecl = nullptr);
template <class AttrType>
- void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
+ void getMutexIDs(CapExprSet &Mtxs, AttrType *Attr, Expr *Exp,
const NamedDecl *D,
const CFGBlock *PredBlock, const CFGBlock *CurrBlock,
Expr *BrE, bool Neg);
@@ -1530,94 +985,107 @@ ClassifyDiagnostic(const AttrTy *A) {
return "mutex";
}
+
+inline bool ThreadSafetyAnalyzer::inCurrentScope(const CapabilityExpr &CapE) {
+ if (!CurrentMethod)
+ return false;
+ if (auto *P = dyn_cast_or_null<til::Project>(CapE.sexpr())) {
+ auto *VD = P->clangDecl();
+ if (VD)
+ return VD->getDeclContext() == CurrentMethod->getDeclContext();
+ }
+ return false;
+}
+
+
/// \brief Add a new lock to the lockset, warning if the lock is already there.
-/// \param Mutex -- the Mutex expression for the lock
-/// \param LDat -- the LockData for the lock
-void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
- const LockData &LDat, StringRef DiagKind) {
- // FIXME: deal with acquired before/after annotations.
- // FIXME: Don't always warn when we have support for reentrant locks.
- if (Mutex.shouldIgnore())
+/// \param ReqAttr -- true if this is part of an initial Requires attribute.
+void ThreadSafetyAnalyzer::addLock(FactSet &FSet,
+ std::unique_ptr<FactEntry> Entry,
+ StringRef DiagKind, bool ReqAttr) {
+ if (Entry->shouldIgnore())
return;
- if (FSet.findLock(FactMan, Mutex)) {
- if (!LDat.Asserted)
- Handler.handleDoubleLock(DiagKind, Mutex.toString(), LDat.AcquireLoc);
+ if (!ReqAttr && !Entry->negative()) {
+ // look for the negative capability, and remove it from the fact set.
+ CapabilityExpr NegC = !*Entry;
+ FactEntry *Nen = FSet.findLock(FactMan, NegC);
+ if (Nen) {
+ FSet.removeLock(FactMan, NegC);
+ }
+ else {
+ if (inCurrentScope(*Entry) && !Entry->asserted())
+ Handler.handleNegativeNotHeld(DiagKind, Entry->toString(),
+ NegC.toString(), Entry->loc());
+ }
+ }
+
+ // FIXME: deal with acquired before/after annotations.
+ // FIXME: Don't always warn when we have support for reentrant locks.
+ if (FSet.findLock(FactMan, *Entry)) {
+ if (!Entry->asserted())
+ Handler.handleDoubleLock(DiagKind, Entry->toString(), Entry->loc());
} else {
- FSet.addLock(FactMan, Mutex, LDat);
+ FSet.addLock(FactMan, std::move(Entry));
}
}
/// \brief Remove a lock from the lockset, warning if the lock is not there.
-/// \param Mutex The lock expression corresponding to the lock to be removed
/// \param UnlockLoc The source location of the unlock (only used in error msg)
-void ThreadSafetyAnalyzer::removeLock(FactSet &FSet, const SExpr &Mutex,
+void ThreadSafetyAnalyzer::removeLock(FactSet &FSet, const CapabilityExpr &Cp,
SourceLocation UnlockLoc,
bool FullyRemove, LockKind ReceivedKind,
StringRef DiagKind) {
- if (Mutex.shouldIgnore())
+ if (Cp.shouldIgnore())
return;
- const LockData *LDat = FSet.findLock(FactMan, Mutex);
+ const FactEntry *LDat = FSet.findLock(FactMan, Cp);
if (!LDat) {
- Handler.handleUnmatchedUnlock(DiagKind, Mutex.toString(), UnlockLoc);
+ Handler.handleUnmatchedUnlock(DiagKind, Cp.toString(), UnlockLoc);
return;
}
// Generic lock removal doesn't care about lock kind mismatches, but
// otherwise diagnose when the lock kinds are mismatched.
- if (ReceivedKind != LK_Generic && LDat->LKind != ReceivedKind) {
- Handler.handleIncorrectUnlockKind(DiagKind, Mutex.toString(), LDat->LKind,
- ReceivedKind, UnlockLoc);
- return;
+ if (ReceivedKind != LK_Generic && LDat->kind() != ReceivedKind) {
+ Handler.handleIncorrectUnlockKind(DiagKind, Cp.toString(),
+ LDat->kind(), ReceivedKind, UnlockLoc);
}
- if (LDat->UnderlyingMutex.isValid()) {
- // This is scoped lockable object, which manages the real mutex.
- if (FullyRemove) {
- // We're destroying the managing object.
- // Remove the underlying mutex if it exists; but don't warn.
- if (FSet.findLock(FactMan, LDat->UnderlyingMutex))
- FSet.removeLock(FactMan, LDat->UnderlyingMutex);
- } else {
- // We're releasing the underlying mutex, but not destroying the
- // managing object. Warn on dual release.
- if (!FSet.findLock(FactMan, LDat->UnderlyingMutex)) {
- Handler.handleUnmatchedUnlock(
- DiagKind, LDat->UnderlyingMutex.toString(), UnlockLoc);
- }
- FSet.removeLock(FactMan, LDat->UnderlyingMutex);
- return;
- }
- }
- FSet.removeLock(FactMan, Mutex);
+ LDat->handleUnlock(FSet, FactMan, Cp, UnlockLoc, FullyRemove, Handler,
+ DiagKind);
}
/// \brief Extract the list of mutexIDs from the attribute on an expression,
/// and push them onto Mtxs, discarding any duplicates.
template <typename AttrType>
-void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
+void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *Attr,
Expr *Exp, const NamedDecl *D,
VarDecl *SelfDecl) {
if (Attr->args_size() == 0) {
// The mutex held is the "this" object.
- SExpr Mu(nullptr, Exp, D, SelfDecl);
- if (!Mu.isValid())
- SExpr::warnInvalidLock(Handler, nullptr, Exp, D,
- ClassifyDiagnostic(Attr));
- else
- Mtxs.push_back_nodup(Mu);
+ CapabilityExpr Cp = SxBuilder.translateAttrExpr(nullptr, D, Exp, SelfDecl);
+ if (Cp.isInvalid()) {
+ warnInvalidLock(Handler, nullptr, D, Exp, ClassifyDiagnostic(Attr));
+ return;
+ }
+ //else
+ if (!Cp.shouldIgnore())
+ Mtxs.push_back_nodup(Cp);
return;
}
for (const auto *Arg : Attr->args()) {
- SExpr Mu(Arg, Exp, D, SelfDecl);
- if (!Mu.isValid())
- SExpr::warnInvalidLock(Handler, Arg, Exp, D, ClassifyDiagnostic(Attr));
- else
- Mtxs.push_back_nodup(Mu);
+ CapabilityExpr Cp = SxBuilder.translateAttrExpr(Arg, D, Exp, SelfDecl);
+ if (Cp.isInvalid()) {
+ warnInvalidLock(Handler, nullptr, D, Exp, ClassifyDiagnostic(Attr));
+ continue;
+ }
+ //else
+ if (!Cp.shouldIgnore())
+ Mtxs.push_back_nodup(Cp);
}
}
@@ -1626,7 +1094,7 @@ void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
/// trylock applies to the given edge, then push them onto Mtxs, discarding
/// any duplicates.
template <class AttrType>
-void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
+void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *Attr,
Expr *Exp, const NamedDecl *D,
const CFGBlock *PredBlock,
const CFGBlock *CurrBlock,
@@ -1758,8 +1226,8 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
if(!FunDecl || !FunDecl->hasAttrs())
return;
- MutexIDList ExclusiveLocksToAdd;
- MutexIDList SharedLocksToAdd;
+ CapExprSet ExclusiveLocksToAdd;
+ CapExprSet SharedLocksToAdd;
// If the condition is a call to a Trylock function, then grab the attributes
for (auto *Attr : FunDecl->getAttrs()) {
@@ -1788,10 +1256,13 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
// Add and remove locks.
SourceLocation Loc = Exp->getExprLoc();
for (const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd)
- addLock(Result, ExclusiveLockToAdd, LockData(Loc, LK_Exclusive),
+ addLock(Result, llvm::make_unique<LockableFactEntry>(ExclusiveLockToAdd,
+ LK_Exclusive, Loc),
CapDiagKind);
for (const auto &SharedLockToAdd : SharedLocksToAdd)
- addLock(Result, SharedLockToAdd, LockData(Loc, LK_Shared), CapDiagKind);
+ addLock(Result, llvm::make_unique<LockableFactEntry>(SharedLockToAdd,
+ LK_Shared, Loc),
+ CapDiagKind);
}
/// \brief We use this class to visit different types of expressions in
@@ -1807,16 +1278,17 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
LocalVariableMap::Context LVarCtx;
unsigned CtxIndex;
- // Helper functions
-
+ // helper functions
void warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK,
Expr *MutexExp, ProtectedOperationKind POK,
- StringRef DiagKind);
+ StringRef DiagKind, SourceLocation Loc);
void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp,
StringRef DiagKind);
- void checkAccess(const Expr *Exp, AccessKind AK);
- void checkPtAccess(const Expr *Exp, AccessKind AK);
+ void checkAccess(const Expr *Exp, AccessKind AK,
+ ProtectedOperationKind POK = POK_VarAccess);
+ void checkPtAccess(const Expr *Exp, AccessKind AK,
+ ProtectedOperationKind POK = POK_VarAccess);
void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = nullptr);
@@ -1837,62 +1309,87 @@ public:
void VisitDeclStmt(DeclStmt *S);
};
+
/// \brief Warn if the LSet does not contain a lock sufficient to protect access
/// of at least the passed in AccessKind.
void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp,
AccessKind AK, Expr *MutexExp,
ProtectedOperationKind POK,
- StringRef DiagKind) {
+ StringRef DiagKind, SourceLocation Loc) {
LockKind LK = getLockKindFromAccessKind(AK);
- SExpr Mutex(MutexExp, Exp, D);
- if (!Mutex.isValid()) {
- SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D, DiagKind);
+ CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
+ if (Cp.isInvalid()) {
+ warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, DiagKind);
return;
- } else if (Mutex.shouldIgnore()) {
+ } else if (Cp.shouldIgnore()) {
+ return;
+ }
+
+ if (Cp.negative()) {
+ // Negative capabilities act like locks excluded
+ FactEntry *LDat = FSet.findLock(Analyzer->FactMan, !Cp);
+ if (LDat) {
+ Analyzer->Handler.handleFunExcludesLock(
+ DiagKind, D->getNameAsString(), (!Cp).toString(), Loc);
+ return;
+ }
+
+ // If this does not refer to a negative capability in the same class,
+ // then stop here.
+ if (!Analyzer->inCurrentScope(Cp))
+ return;
+
+ // Otherwise the negative requirement must be propagated to the caller.
+ LDat = FSet.findLock(Analyzer->FactMan, Cp);
+ if (!LDat) {
+ Analyzer->Handler.handleMutexNotHeld("", D, POK, Cp.toString(),
+ LK_Shared, Loc);
+ }
return;
}
- LockData* LDat = FSet.findLockUniv(Analyzer->FactMan, Mutex);
+ FactEntry* LDat = FSet.findLockUniv(Analyzer->FactMan, Cp);
bool NoError = true;
if (!LDat) {
// No exact match found. Look for a partial match.
- FactEntry* FEntry = FSet.findPartialMatch(Analyzer->FactMan, Mutex);
- if (FEntry) {
+ LDat = FSet.findPartialMatch(Analyzer->FactMan, Cp);
+ if (LDat) {
// Warn that there's no precise match.
- LDat = &FEntry->LDat;
- std::string PartMatchStr = FEntry->MutID.toString();
+ std::string PartMatchStr = LDat->toString();
StringRef PartMatchName(PartMatchStr);
- Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Mutex.toString(),
- LK, Exp->getExprLoc(),
- &PartMatchName);
+ Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.toString(),
+ LK, Loc, &PartMatchName);
} else {
// Warn that there's no match at all.
- Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Mutex.toString(),
- LK, Exp->getExprLoc());
+ Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.toString(),
+ LK, Loc);
}
NoError = false;
}
// Make sure the mutex we found is the right kind.
- if (NoError && LDat && !LDat->isAtLeast(LK))
- Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Mutex.toString(), LK,
- Exp->getExprLoc());
+ if (NoError && LDat && !LDat->isAtLeast(LK)) {
+ Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.toString(),
+ LK, Loc);
+ }
}
/// \brief Warn if the LSet contains the given lock.
void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr *Exp,
- Expr *MutexExp,
- StringRef DiagKind) {
- SExpr Mutex(MutexExp, Exp, D);
- if (!Mutex.isValid()) {
- SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D, DiagKind);
+ Expr *MutexExp, StringRef DiagKind) {
+ CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
+ if (Cp.isInvalid()) {
+ warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, DiagKind);
+ return;
+ } else if (Cp.shouldIgnore()) {
return;
}
- LockData* LDat = FSet.findLock(Analyzer->FactMan, Mutex);
- if (LDat)
+ FactEntry* LDat = FSet.findLock(Analyzer->FactMan, Cp);
+ if (LDat) {
Analyzer->Handler.handleFunExcludesLock(
- DiagKind, D->getNameAsString(), Mutex.toString(), Exp->getExprLoc());
+ DiagKind, D->getNameAsString(), Cp.toString(), Exp->getExprLoc());
+ }
}
/// \brief Checks guarded_by and pt_guarded_by attributes.
@@ -1900,43 +1397,62 @@ void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr *Exp,
/// marked with guarded_by, we must ensure the appropriate mutexes are held.
/// Similarly, we check if the access is to an expression that dereferences
/// a pointer marked with pt_guarded_by.
-void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK) {
+void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK,
+ ProtectedOperationKind POK) {
Exp = Exp->IgnoreParenCasts();
+ SourceLocation Loc = Exp->getExprLoc();
+
+ // Local variables of reference type cannot be re-assigned;
+ // map them to their initializer.
+ while (const auto *DRE = dyn_cast<DeclRefExpr>(Exp)) {
+ const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()->getCanonicalDecl());
+ if (VD && VD->isLocalVarDecl() && VD->getType()->isReferenceType()) {
+ if (const auto *E = VD->getInit()) {
+ Exp = E;
+ continue;
+ }
+ }
+ break;
+ }
+
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp)) {
// For dereferences
if (UO->getOpcode() == clang::UO_Deref)
- checkPtAccess(UO->getSubExpr(), AK);
+ checkPtAccess(UO->getSubExpr(), AK, POK);
return;
}
if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(Exp)) {
- checkPtAccess(AE->getLHS(), AK);
+ checkPtAccess(AE->getLHS(), AK, POK);
return;
}
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
if (ME->isArrow())
- checkPtAccess(ME->getBase(), AK);
+ checkPtAccess(ME->getBase(), AK, POK);
else
- checkAccess(ME->getBase(), AK);
+ checkAccess(ME->getBase(), AK, POK);
}
const ValueDecl *D = getValueDecl(Exp);
if (!D || !D->hasAttrs())
return;
- if (D->hasAttr<GuardedVarAttr>() && FSet.isEmpty())
- Analyzer->Handler.handleNoMutexHeld("mutex", D, POK_VarAccess, AK,
- Exp->getExprLoc());
+ if (D->hasAttr<GuardedVarAttr>() && FSet.isEmpty(Analyzer->FactMan)) {
+ Analyzer->Handler.handleNoMutexHeld("mutex", D, POK, AK, Loc);
+ }
for (const auto *I : D->specific_attrs<GuardedByAttr>())
- warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK_VarAccess,
- ClassifyDiagnostic(I));
+ warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK,
+ ClassifyDiagnostic(I), Loc);
}
+
/// \brief Checks pt_guarded_by and pt_guarded_var attributes.
-void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
+/// POK is the same operationKind that was passed to checkAccess.
+void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK,
+ ProtectedOperationKind POK) {
while (true) {
if (const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
Exp = PE->getSubExpr();
@@ -1946,7 +1462,7 @@ void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
if (CE->getCastKind() == CK_ArrayToPointerDecay) {
// If it's an actual array, and not a pointer, then it's elements
// are protected by GUARDED_BY, not PT_GUARDED_BY;
- checkAccess(CE->getSubExpr(), AK);
+ checkAccess(CE->getSubExpr(), AK, POK);
return;
}
Exp = CE->getSubExpr();
@@ -1955,17 +1471,21 @@ void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
break;
}
+ // Pass by reference warnings are under a different flag.
+ ProtectedOperationKind PtPOK = POK_VarDereference;
+ if (POK == POK_PassByRef) PtPOK = POK_PtPassByRef;
+
const ValueDecl *D = getValueDecl(Exp);
if (!D || !D->hasAttrs())
return;
- if (D->hasAttr<PtGuardedVarAttr>() && FSet.isEmpty())
- Analyzer->Handler.handleNoMutexHeld("mutex", D, POK_VarDereference, AK,
+ if (D->hasAttr<PtGuardedVarAttr>() && FSet.isEmpty(Analyzer->FactMan))
+ Analyzer->Handler.handleNoMutexHeld("mutex", D, PtPOK, AK,
Exp->getExprLoc());
for (auto const *I : D->specific_attrs<PtGuardedByAttr>())
- warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK_VarDereference,
- ClassifyDiagnostic(I));
+ warnIfMutexNotHeld(D, Exp, AK, I->getArg(), PtPOK,
+ ClassifyDiagnostic(I), Exp->getExprLoc());
}
/// \brief Process a function call, method call, constructor call,
@@ -1981,8 +1501,8 @@ void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
SourceLocation Loc = Exp->getExprLoc();
const AttrVec &ArgAttrs = D->getAttrs();
- MutexIDList ExclusiveLocksToAdd, SharedLocksToAdd;
- MutexIDList ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
+ CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd;
+ CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
StringRef CapDiagKind = "mutex";
for(unsigned i = 0; i < ArgAttrs.size(); ++i) {
@@ -2006,22 +1526,23 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
case attr::AssertExclusiveLock: {
AssertExclusiveLockAttr *A = cast<AssertExclusiveLockAttr>(At);
- MutexIDList AssertLocks;
+ CapExprSet AssertLocks;
Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
for (const auto &AssertLock : AssertLocks)
- Analyzer->addLock(FSet, AssertLock,
- LockData(Loc, LK_Exclusive, false, true),
+ Analyzer->addLock(FSet,
+ llvm::make_unique<LockableFactEntry>(
+ AssertLock, LK_Exclusive, Loc, false, true),
ClassifyDiagnostic(A));
break;
}
case attr::AssertSharedLock: {
AssertSharedLockAttr *A = cast<AssertSharedLockAttr>(At);
- MutexIDList AssertLocks;
+ CapExprSet AssertLocks;
Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
for (const auto &AssertLock : AssertLocks)
- Analyzer->addLock(FSet, AssertLock,
- LockData(Loc, LK_Shared, false, true),
+ Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
+ AssertLock, LK_Shared, Loc, false, true),
ClassifyDiagnostic(A));
break;
}
@@ -2045,7 +1566,8 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At);
for (auto *Arg : A->args())
warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, Arg,
- POK_FunctionCall, ClassifyDiagnostic(A));
+ POK_FunctionCall, ClassifyDiagnostic(A),
+ Exp->getExprLoc());
break;
}
@@ -2074,25 +1596,28 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
// Add locks.
for (const auto &M : ExclusiveLocksToAdd)
- Analyzer->addLock(FSet, M, LockData(Loc, LK_Exclusive, isScopedVar),
+ Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
+ M, LK_Exclusive, Loc, isScopedVar),
CapDiagKind);
for (const auto &M : SharedLocksToAdd)
- Analyzer->addLock(FSet, M, LockData(Loc, LK_Shared, isScopedVar),
+ Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
+ M, LK_Shared, Loc, isScopedVar),
CapDiagKind);
- // Add the managing object as a dummy mutex, mapped to the underlying mutex.
- // FIXME -- this doesn't work if we acquire multiple locks.
if (isScopedVar) {
+ // Add the managing object as a dummy mutex, mapped to the underlying mutex.
SourceLocation MLoc = VD->getLocation();
DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, VD->getLocation());
- SExpr SMutex(&DRE, nullptr, nullptr);
-
- for (const auto &M : ExclusiveLocksToAdd)
- Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Exclusive, M),
- CapDiagKind);
- for (const auto &M : SharedLocksToAdd)
- Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Shared, M),
- CapDiagKind);
+ // FIXME: does this store a pointer to DRE?
+ CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE, nullptr);
+
+ CapExprSet UnderlyingMutexes(ExclusiveLocksToAdd);
+ std::copy(SharedLocksToAdd.begin(), SharedLocksToAdd.end(),
+ std::back_inserter(UnderlyingMutexes));
+ Analyzer->addLock(FSet,
+ llvm::make_unique<ScopedLockableFactEntry>(
+ Scp, MLoc, ExclusiveLocksToAdd, SharedLocksToAdd),
+ CapDiagKind);
}
// Remove locks.
@@ -2149,6 +1674,9 @@ void BuildLockset::VisitCastExpr(CastExpr *CE) {
void BuildLockset::VisitCallExpr(CallExpr *Exp) {
+ bool ExamineArgs = true;
+ bool OperatorFun = false;
+
if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Exp)) {
MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee());
// ME can be null when calling a method pointer
@@ -2169,8 +1697,12 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) {
}
}
} else if (CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(Exp)) {
- switch (OE->getOperator()) {
+ OperatorFun = true;
+
+ auto OEop = OE->getOperator();
+ switch (OEop) {
case OO_Equal: {
+ ExamineArgs = false;
const Expr *Target = OE->getArg(0);
const Expr *Source = OE->getArg(1);
checkAccess(Target, AK_Written);
@@ -2182,16 +1714,53 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) {
case OO_Subscript: {
const Expr *Obj = OE->getArg(0);
checkAccess(Obj, AK_Read);
- checkPtAccess(Obj, AK_Read);
+ if (!(OEop == OO_Star && OE->getNumArgs() > 1)) {
+ // Grrr. operator* can be multiplication...
+ checkPtAccess(Obj, AK_Read);
+ }
break;
}
default: {
+ // TODO: get rid of this, and rely on pass-by-ref instead.
const Expr *Obj = OE->getArg(0);
checkAccess(Obj, AK_Read);
break;
}
}
}
+
+
+ if (ExamineArgs) {
+ if (FunctionDecl *FD = Exp->getDirectCallee()) {
+ unsigned Fn = FD->getNumParams();
+ unsigned Cn = Exp->getNumArgs();
+ unsigned Skip = 0;
+
+ unsigned i = 0;
+ if (OperatorFun) {
+ if (isa<CXXMethodDecl>(FD)) {
+ // First arg in operator call is implicit self argument,
+ // and doesn't appear in the FunctionDecl.
+ Skip = 1;
+ Cn--;
+ } else {
+ // Ignore the first argument of operators; it's been checked above.
+ i = 1;
+ }
+ }
+ // Ignore default arguments
+ unsigned n = (Fn < Cn) ? Fn : Cn;
+
+ for (; i < n; ++i) {
+ ParmVarDecl* Pvd = FD->getParamDecl(i);
+ Expr* Arg = Exp->getArg(i+Skip);
+ QualType Qt = Pvd->getType();
+ if (Qt->isReferenceType())
+ checkAccess(Arg, AK_Read, POK_PassByRef);
+ }
+ }
+ }
+
NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
if(!D || !D->hasAttrs())
return;
@@ -2254,62 +1823,40 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
// Find locks in FSet2 that conflict or are not in FSet1, and warn.
for (const auto &Fact : FSet2) {
- const SExpr &FSet2Mutex = FactMan[Fact].MutID;
- const LockData &LDat2 = FactMan[Fact].LDat;
- FactSet::iterator I1 = FSet1.findLockIter(FactMan, FSet2Mutex);
-
- if (I1 != FSet1.end()) {
- const LockData* LDat1 = &FactMan[*I1].LDat;
- if (LDat1->LKind != LDat2.LKind) {
- Handler.handleExclusiveAndShared("mutex", FSet2Mutex.toString(),
- LDat2.AcquireLoc, LDat1->AcquireLoc);
- if (Modify && LDat1->LKind != LK_Exclusive) {
+ const FactEntry *LDat1 = nullptr;
+ const FactEntry *LDat2 = &FactMan[Fact];
+ FactSet::iterator Iter1 = FSet1.findLockIter(FactMan, *LDat2);
+ if (Iter1 != FSet1.end()) LDat1 = &FactMan[*Iter1];
+
+ if (LDat1) {
+ if (LDat1->kind() != LDat2->kind()) {
+ Handler.handleExclusiveAndShared("mutex", LDat2->toString(),
+ LDat2->loc(), LDat1->loc());
+ if (Modify && LDat1->kind() != LK_Exclusive) {
// Take the exclusive lock, which is the one in FSet2.
- *I1 = Fact;
+ *Iter1 = Fact;
}
}
- else if (LDat1->Asserted && !LDat2.Asserted) {
+ else if (Modify && LDat1->asserted() && !LDat2->asserted()) {
// The non-asserted lock in FSet2 is the one we want to track.
- *I1 = Fact;
+ *Iter1 = Fact;
}
} else {
- if (LDat2.UnderlyingMutex.isValid()) {
- if (FSet2.findLock(FactMan, LDat2.UnderlyingMutex)) {
- // If this is a scoped lock that manages another mutex, and if the
- // underlying mutex is still held, then warn about the underlying
- // mutex.
- Handler.handleMutexHeldEndOfScope("mutex",
- LDat2.UnderlyingMutex.toString(),
- LDat2.AcquireLoc, JoinLoc, LEK1);
- }
- }
- else if (!LDat2.Managed && !FSet2Mutex.isUniversal() && !LDat2.Asserted)
- Handler.handleMutexHeldEndOfScope("mutex", FSet2Mutex.toString(),
- LDat2.AcquireLoc, JoinLoc, LEK1);
+ LDat2->handleRemovalFromIntersection(FSet2, FactMan, JoinLoc, LEK1,
+ Handler);
}
}
// Find locks in FSet1 that are not in FSet2, and remove them.
for (const auto &Fact : FSet1Orig) {
- const SExpr &FSet1Mutex = FactMan[Fact].MutID;
- const LockData &LDat1 = FactMan[Fact].LDat;
-
- if (!FSet2.findLock(FactMan, FSet1Mutex)) {
- if (LDat1.UnderlyingMutex.isValid()) {
- if (FSet1Orig.findLock(FactMan, LDat1.UnderlyingMutex)) {
- // If this is a scoped lock that manages another mutex, and if the
- // underlying mutex is still held, then warn about the underlying
- // mutex.
- Handler.handleMutexHeldEndOfScope("mutex",
- LDat1.UnderlyingMutex.toString(),
- LDat1.AcquireLoc, JoinLoc, LEK1);
- }
- }
- else if (!LDat1.Managed && !FSet1Mutex.isUniversal() && !LDat1.Asserted)
- Handler.handleMutexHeldEndOfScope("mutex", FSet1Mutex.toString(),
- LDat1.AcquireLoc, JoinLoc, LEK2);
+ const FactEntry *LDat1 = &FactMan[Fact];
+ const FactEntry *LDat2 = FSet2.findLock(FactMan, *LDat1);
+
+ if (!LDat2) {
+ LDat1->handleRemovalFromIntersection(FSet1Orig, FactMan, JoinLoc, LEK2,
+ Handler);
if (Modify)
- FSet1.removeLock(FactMan, FSet1Mutex);
+ FSet1.removeLock(FactMan, *LDat1);
}
}
}
@@ -2348,6 +1895,8 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
CFG *CFGraph = walker.getGraph();
const NamedDecl *D = walker.getDecl();
+ const FunctionDecl *CurrentFunction = dyn_cast<FunctionDecl>(D);
+ CurrentMethod = dyn_cast<CXXMethodDecl>(D);
if (D->hasAttr<NoThreadSafetyAnalysisAttr>())
return;
@@ -2361,6 +1910,8 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
if (isa<CXXDestructorDecl>(D))
return; // Don't check inside destructors.
+ Handler.enterFunction(CurrentFunction);
+
BlockInfo.resize(CFGraph->getNumBlockIDs(),
CFGBlockInfo::getEmptyBlockInfo(LocalVarMap));
@@ -2379,9 +1930,9 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// Fill in source locations for all CFGBlocks.
findBlockLocations(CFGraph, SortedGraph, BlockInfo);
- MutexIDList ExclusiveLocksAcquired;
- MutexIDList SharedLocksAcquired;
- MutexIDList LocksReleased;
+ CapExprSet ExclusiveLocksAcquired;
+ CapExprSet SharedLocksAcquired;
+ CapExprSet LocksReleased;
// Add locks from exclusive_locks_required and shared_locks_required
// to initial lockset. Also turn off checking for lock and unlock functions.
@@ -2391,8 +1942,8 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
FactSet &InitialLockset = BlockInfo[FirstBlock->getBlockID()].EntrySet;
const AttrVec &ArgAttrs = D->getAttrs();
- MutexIDList ExclusiveLocksToAdd;
- MutexIDList SharedLocksToAdd;
+ CapExprSet ExclusiveLocksToAdd;
+ CapExprSet SharedLocksToAdd;
StringRef CapDiagKind = "mutex";
SourceLocation Loc = D->getLocation();
@@ -2428,12 +1979,14 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
}
// FIXME -- Loc can be wrong here.
- for (const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd)
- addLock(InitialLockset, ExclusiveLockToAdd, LockData(Loc, LK_Exclusive),
- CapDiagKind);
- for (const auto &SharedLockToAdd : SharedLocksToAdd)
- addLock(InitialLockset, SharedLockToAdd, LockData(Loc, LK_Shared),
- CapDiagKind);
+ for (const auto &Mu : ExclusiveLocksToAdd)
+ addLock(InitialLockset,
+ llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc),
+ CapDiagKind, true);
+ for (const auto &Mu : SharedLocksToAdd)
+ addLock(InitialLockset,
+ llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc),
+ CapDiagKind, true);
}
for (const auto *CurrBlock : *SortedGraph) {
@@ -2602,11 +2155,11 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// issue the appropriate warning.
// FIXME: the location here is not quite right.
for (const auto &Lock : ExclusiveLocksAcquired)
- ExpectedExitSet.addLock(FactMan, Lock,
- LockData(D->getLocation(), LK_Exclusive));
+ ExpectedExitSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
+ Lock, LK_Exclusive, D->getLocation()));
for (const auto &Lock : SharedLocksAcquired)
- ExpectedExitSet.addLock(FactMan, Lock,
- LockData(D->getLocation(), LK_Shared));
+ ExpectedExitSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
+ Lock, LK_Shared, D->getLocation()));
for (const auto &Lock : LocksReleased)
ExpectedExitSet.removeLock(FactMan, Lock);
@@ -2616,13 +2169,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
LEK_LockedAtEndOfFunction,
LEK_NotLockedAtEndOfFunction,
false);
-}
-
-} // end anonymous namespace
+ Handler.leaveFunction(CurrentFunction);
+}
-namespace clang {
-namespace thread_safety {
/// \brief Check a function's CFG for thread-safety violations.
///
@@ -2647,4 +2197,4 @@ LockKind getLockKindFromAccessKind(AccessKind AK) {
llvm_unreachable("Unknown AccessKind");
}
-}} // end namespace clang::thread_safety
+}} // end namespace clang::threadSafety
diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp
index da88b78126fa..563e0590aacb 100644
--- a/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/lib/Analysis/ThreadSafetyCommon.cpp
@@ -28,7 +28,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-
#include <algorithm>
#include <climits>
#include <vector>
@@ -63,11 +62,9 @@ std::string getSourceLiteralString(const clang::Expr *CE) {
namespace til {
// Return true if E is a variable that points to an incomplete Phi node.
-static bool isIncompleteVar(const SExpr *E) {
- if (const auto *V = dyn_cast<Variable>(E)) {
- if (const auto *Ph = dyn_cast<Phi>(V->definition()))
- return Ph->status() == Phi::PH_Incomplete;
- }
+static bool isIncompletePhi(const SExpr *E) {
+ if (const auto *Ph = dyn_cast<Phi>(E))
+ return Ph->status() == Phi::PH_Incomplete;
return false;
}
@@ -91,6 +88,124 @@ til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
}
+
+inline bool isCalleeArrow(const Expr *E) {
+ const MemberExpr *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts());
+ return ME ? ME->isArrow() : false;
+}
+
+
+/// \brief Translate a clang expression in an attribute to a til::SExpr.
+/// Constructs the context from D, DeclExp, and SelfDecl.
+///
+/// \param AttrExp The expression to translate.
+/// \param D The declaration to which the attribute is attached.
+/// \param DeclExp An expression involving the Decl to which the attribute
+/// is attached. E.g. the call to a function.
+CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
+ const NamedDecl *D,
+ const Expr *DeclExp,
+ VarDecl *SelfDecl) {
+ // If we are processing a raw attribute expression, with no substitutions.
+ if (!DeclExp)
+ return translateAttrExpr(AttrExp, nullptr);
+
+ CallingContext Ctx(nullptr, D);
+
+ // Examine DeclExp to find SelfArg and FunArgs, which are used to substitute
+ // for formal parameters when we call buildMutexID later.
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
+ Ctx.SelfArg = ME->getBase();
+ Ctx.SelfArrow = ME->isArrow();
+ } else if (const CXXMemberCallExpr *CE =
+ dyn_cast<CXXMemberCallExpr>(DeclExp)) {
+ Ctx.SelfArg = CE->getImplicitObjectArgument();
+ Ctx.SelfArrow = isCalleeArrow(CE->getCallee());
+ Ctx.NumArgs = CE->getNumArgs();
+ Ctx.FunArgs = CE->getArgs();
+ } else if (const CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
+ Ctx.NumArgs = CE->getNumArgs();
+ Ctx.FunArgs = CE->getArgs();
+ } else if (const CXXConstructExpr *CE =
+ dyn_cast<CXXConstructExpr>(DeclExp)) {
+ Ctx.SelfArg = nullptr; // Will be set below
+ Ctx.NumArgs = CE->getNumArgs();
+ Ctx.FunArgs = CE->getArgs();
+ } else if (D && isa<CXXDestructorDecl>(D)) {
+ // There's no such thing as a "destructor call" in the AST.
+ Ctx.SelfArg = DeclExp;
+ }
+
+ // Hack to handle constructors, where self cannot be recovered from
+ // the expression.
+ if (SelfDecl && !Ctx.SelfArg) {
+ DeclRefExpr SelfDRE(SelfDecl, false, SelfDecl->getType(), VK_LValue,
+ SelfDecl->getLocation());
+ Ctx.SelfArg = &SelfDRE;
+
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (!AttrExp)
+ return translateAttrExpr(Ctx.SelfArg, nullptr);
+ else // For most attributes.
+ return translateAttrExpr(AttrExp, &Ctx);
+ }
+
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (!AttrExp)
+ return translateAttrExpr(Ctx.SelfArg, nullptr);
+ else // For most attributes.
+ return translateAttrExpr(AttrExp, &Ctx);
+}
+
+
+/// \brief Translate a clang expression in an attribute to a til::SExpr.
+// This assumes a CallingContext has already been created.
+CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
+ CallingContext *Ctx) {
+ if (!AttrExp)
+ return CapabilityExpr(nullptr, false);
+
+ if (auto* SLit = dyn_cast<StringLiteral>(AttrExp)) {
+ if (SLit->getString() == StringRef("*"))
+ // The "*" expr is a universal lock, which essentially turns off
+ // checks until it is removed from the lockset.
+ return CapabilityExpr(new (Arena) til::Wildcard(), false);
+ else
+ // Ignore other string literals for now.
+ return CapabilityExpr(nullptr, false);
+ }
+
+ bool Neg = false;
+ if (auto *OE = dyn_cast<CXXOperatorCallExpr>(AttrExp)) {
+ if (OE->getOperator() == OO_Exclaim) {
+ Neg = true;
+ AttrExp = OE->getArg(0);
+ }
+ }
+ else if (auto *UO = dyn_cast<UnaryOperator>(AttrExp)) {
+ if (UO->getOpcode() == UO_LNot) {
+ Neg = true;
+ AttrExp = UO->getSubExpr();
+ }
+ }
+
+ til::SExpr *E = translate(AttrExp, Ctx);
+
+ // Trap mutex expressions like nullptr, or 0.
+ // Any literal value is nonsense.
+ if (!E || isa<til::Literal>(E))
+ return CapabilityExpr(nullptr, false);
+
+ // Hack to deal with smart pointers -- strip off top-level pointer casts.
+ if (auto *CE = dyn_cast_or_null<til::Cast>(E)) {
+ if (CE->castOpcode() == til::CAST_objToPtr)
+ return CapabilityExpr(CE->expr(), Neg);
+ }
+ return CapabilityExpr(E, Neg);
+}
+
+
+
// Translate a clang statement or expression to a TIL expression.
// Also performs substitution of variables; Ctx provides the context.
// Dispatches on the type of S.
@@ -125,9 +240,10 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
case Stmt::ArraySubscriptExprClass:
return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);
case Stmt::ConditionalOperatorClass:
- return translateConditionalOperator(cast<ConditionalOperator>(S), Ctx);
+ return translateAbstractConditionalOperator(
+ cast<ConditionalOperator>(S), Ctx);
case Stmt::BinaryConditionalOperatorClass:
- return translateBinaryConditionalOperator(
+ return translateAbstractConditionalOperator(
cast<BinaryConditionalOperator>(S), Ctx);
// We treat these as no-ops
@@ -162,6 +278,7 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
}
+
til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
CallingContext *Ctx) {
const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
@@ -197,17 +314,75 @@ til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
}
+const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) {
+ if (auto *V = dyn_cast<til::Variable>(E))
+ return V->clangDecl();
+ if (auto *Ph = dyn_cast<til::Phi>(E))
+ return Ph->clangDecl();
+ if (auto *P = dyn_cast<til::Project>(E))
+ return P->clangDecl();
+ if (auto *L = dyn_cast<til::LiteralPtr>(E))
+ return L->clangDecl();
+ return 0;
+}
+
+bool hasCppPointerType(const til::SExpr *E) {
+ auto *VD = getValueDeclFromSExpr(E);
+ if (VD && VD->getType()->isPointerType())
+ return true;
+ if (auto *C = dyn_cast<til::Cast>(E))
+ return C->castOpcode() == til::CAST_objToPtr;
+
+ return false;
+}
+
+
+// Grab the very first declaration of virtual method D
+const CXXMethodDecl* getFirstVirtualDecl(const CXXMethodDecl *D) {
+ while (true) {
+ D = D->getCanonicalDecl();
+ CXXMethodDecl::method_iterator I = D->begin_overridden_methods(),
+ E = D->end_overridden_methods();
+ if (I == E)
+ return D; // Method does not override anything
+ D = *I; // FIXME: this does not work with multiple inheritance.
+ }
+ return nullptr;
+}
+
til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
CallingContext *Ctx) {
- til::SExpr *E = translate(ME->getBase(), Ctx);
- E = new (Arena) til::SApply(E);
- return new (Arena) til::Project(E, ME->getMemberDecl());
+ til::SExpr *BE = translate(ME->getBase(), Ctx);
+ til::SExpr *E = new (Arena) til::SApply(BE);
+
+ const ValueDecl *D = ME->getMemberDecl();
+ if (auto *VD = dyn_cast<CXXMethodDecl>(D))
+ D = getFirstVirtualDecl(VD);
+
+ til::Project *P = new (Arena) til::Project(E, D);
+ if (hasCppPointerType(BE))
+ P->setArrow(true);
+ return P;
}
til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
- CallingContext *Ctx) {
- // TODO -- Lock returned
+ CallingContext *Ctx,
+ const Expr *SelfE) {
+ if (CapabilityExprMode) {
+ // Handle LOCK_RETURNED
+ const FunctionDecl *FD = CE->getDirectCallee()->getMostRecentDecl();
+ if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) {
+ CallingContext LRCallCtx(Ctx);
+ LRCallCtx.AttrDecl = CE->getDirectCallee();
+ LRCallCtx.SelfArg = SelfE;
+ LRCallCtx.NumArgs = CE->getNumArgs();
+ LRCallCtx.FunArgs = CE->getArgs();
+ return const_cast<til::SExpr*>(
+ translateAttrExpr(At->getArg(), &LRCallCtx).sexpr());
+ }
+ }
+
til::SExpr *E = translate(CE->getCallee(), Ctx);
for (const auto *Arg : CE->arguments()) {
til::SExpr *A = translate(Arg, Ctx);
@@ -219,12 +394,31 @@ til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
const CXXMemberCallExpr *ME, CallingContext *Ctx) {
- return translateCallExpr(cast<CallExpr>(ME), Ctx);
+ if (CapabilityExprMode) {
+ // Ignore calls to get() on smart pointers.
+ if (ME->getMethodDecl()->getNameAsString() == "get" &&
+ ME->getNumArgs() == 0) {
+ auto *E = translate(ME->getImplicitObjectArgument(), Ctx);
+ return new (Arena) til::Cast(til::CAST_objToPtr, E);
+ // return E;
+ }
+ }
+ return translateCallExpr(cast<CallExpr>(ME), Ctx,
+ ME->getImplicitObjectArgument());
}
til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
+ if (CapabilityExprMode) {
+ // Ignore operator * and operator -> on smart pointers.
+ OverloadedOperatorKind k = OCE->getOperator();
+ if (k == OO_Star || k == OO_Arrow) {
+ auto *E = translate(OCE->getArg(0), Ctx);
+ return new (Arena) til::Cast(til::CAST_objToPtr, E);
+ // return E;
+ }
+ }
return translateCallExpr(cast<CallExpr>(OCE), Ctx);
}
@@ -238,8 +432,23 @@ til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
case UO_PreDec:
return new (Arena) til::Undefined(UO);
+ case UO_AddrOf: {
+ if (CapabilityExprMode) {
+ // interpret &Graph::mu_ as an existential.
+ if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(UO->getSubExpr())) {
+ if (DRE->getDecl()->isCXXInstanceMember()) {
+ // This is a pointer-to-member expression, e.g. &MyClass::mu_.
+ // We interpret this syntax specially, as a wildcard.
+ auto *W = new (Arena) til::Wildcard();
+ return new (Arena) til::Project(W, DRE->getDecl());
+ }
+ }
+ }
+ // otherwise, & is a no-op
+ return translate(UO->getSubExpr(), Ctx);
+ }
+
// We treat these as no-ops
- case UO_AddrOf:
case UO_Deref:
case UO_Plus:
return translate(UO->getSubExpr(), Ctx);
@@ -360,7 +569,9 @@ til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
return E0;
}
til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
- return new (Arena) til::Load(E0);
+ return E0;
+ // FIXME!! -- get Load working properly
+ // return new (Arena) til::Load(E0);
}
case CK_NoOp:
case CK_DerivedToBase:
@@ -373,6 +584,8 @@ til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
default: {
// FIXME: handle different kinds of casts.
til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ if (CapabilityExprMode)
+ return E0;
return new (Arena) til::Cast(til::CAST_none, E0);
}
}
@@ -389,15 +602,12 @@ SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
til::SExpr *
-SExprBuilder::translateConditionalOperator(const ConditionalOperator *C,
- CallingContext *Ctx) {
- return new (Arena) til::Undefined(C);
-}
-
-
-til::SExpr *SExprBuilder::translateBinaryConditionalOperator(
- const BinaryConditionalOperator *C, CallingContext *Ctx) {
- return new (Arena) til::Undefined(C);
+SExprBuilder::translateAbstractConditionalOperator(
+ const AbstractConditionalOperator *CO, CallingContext *Ctx) {
+ auto *C = translate(CO->getCond(), Ctx);
+ auto *T = translate(CO->getTrueExpr(), Ctx);
+ auto *E = translate(CO->getFalseExpr(), Ctx);
+ return new (Arena) til::IfThenElse(C, T, E);
}
@@ -430,16 +640,14 @@ SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
// If E is trivial returns E.
til::SExpr *SExprBuilder::addStatement(til::SExpr* E, const Stmt *S,
const ValueDecl *VD) {
- if (!E)
- return nullptr;
- if (til::ThreadSafetyTIL::isTrivial(E))
+ if (!E || !CurrentBB || E->block() || til::ThreadSafetyTIL::isTrivial(E))
return E;
-
- til::Variable *V = new (Arena) til::Variable(E, VD);
- CurrentInstructions.push_back(V);
+ if (VD)
+ E = new (Arena) til::Variable(E, VD);
+ CurrentInstructions.push_back(E);
if (S)
- insertStmt(S, V);
- return V;
+ insertStmt(S, E);
+ return E;
}
@@ -496,11 +704,11 @@ void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
unsigned ArgIndex = CurrentBlockInfo->ProcessedPredecessors;
assert(ArgIndex > 0 && ArgIndex < NPreds);
- til::Variable *V = dyn_cast<til::Variable>(CurrentLVarMap[i].second);
- if (V && V->getBlockID() == CurrentBB->blockID()) {
+ til::SExpr *CurrE = CurrentLVarMap[i].second;
+ if (CurrE->block() == CurrentBB) {
// We already have a Phi node in the current block,
// so just add the new variable to the Phi node.
- til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
+ til::Phi *Ph = dyn_cast<til::Phi>(CurrE);
assert(Ph && "Expecting Phi node.");
if (E)
Ph->values()[ArgIndex] = E;
@@ -509,27 +717,26 @@ void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
// Make a new phi node: phi(..., E)
// All phi args up to the current index are set to the current value.
- til::SExpr *CurrE = CurrentLVarMap[i].second;
til::Phi *Ph = new (Arena) til::Phi(Arena, NPreds);
Ph->values().setValues(NPreds, nullptr);
for (unsigned PIdx = 0; PIdx < ArgIndex; ++PIdx)
Ph->values()[PIdx] = CurrE;
if (E)
Ph->values()[ArgIndex] = E;
+ Ph->setClangDecl(CurrentLVarMap[i].first);
// If E is from a back-edge, or either E or CurrE are incomplete, then
// mark this node as incomplete; we may need to remove it later.
- if (!E || isIncompleteVar(E) || isIncompleteVar(CurrE)) {
+ if (!E || isIncompletePhi(E) || isIncompletePhi(CurrE)) {
Ph->setStatus(til::Phi::PH_Incomplete);
}
// Add Phi node to current block, and update CurrentLVarMap[i]
- auto *Var = new (Arena) til::Variable(Ph, CurrentLVarMap[i].first);
- CurrentArguments.push_back(Var);
+ CurrentArguments.push_back(Ph);
if (Ph->status() == til::Phi::PH_Incomplete)
- IncompleteArgs.push_back(Var);
+ IncompleteArgs.push_back(Ph);
CurrentLVarMap.makeWritable();
- CurrentLVarMap.elem(i).second = Var;
+ CurrentLVarMap.elem(i).second = Ph;
}
@@ -603,15 +810,13 @@ void SExprBuilder::mergePhiNodesBackEdge(const CFGBlock *Blk) {
unsigned ArgIndex = BBInfo[Blk->getBlockID()].ProcessedPredecessors;
assert(ArgIndex > 0 && ArgIndex < BB->numPredecessors());
- for (til::Variable *V : BB->arguments()) {
- til::Phi *Ph = dyn_cast_or_null<til::Phi>(V->definition());
+ for (til::SExpr *PE : BB->arguments()) {
+ til::Phi *Ph = dyn_cast_or_null<til::Phi>(PE);
assert(Ph && "Expecting Phi Node.");
assert(Ph->values()[ArgIndex] == nullptr && "Wrong index for back edge.");
- assert(V->clangDecl() && "No local variable for Phi node.");
- til::SExpr *E = lookupVarDecl(V->clangDecl());
+ til::SExpr *E = lookupVarDecl(Ph->clangDecl());
assert(E && "Couldn't find local variable for Phi node.");
-
Ph->values()[ArgIndex] = E;
}
}
@@ -631,7 +836,6 @@ void SExprBuilder::enterCFG(CFG *Cfg, const NamedDecl *D,
BB->reserveInstructions(B->size());
BlockMap[B->getBlockID()] = BB;
}
- CallCtx.reset(new SExprBuilder::CallingContext(D));
CurrentBB = lookupBlock(&Cfg->getEntry());
auto Parms = isa<ObjCMethodDecl>(D) ? cast<ObjCMethodDecl>(D)->parameters()
@@ -691,13 +895,13 @@ void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) {
// Push those arguments onto the basic block.
CurrentBB->arguments().reserve(
static_cast<unsigned>(CurrentArguments.size()), Arena);
- for (auto *V : CurrentArguments)
- CurrentBB->addArgument(V);
+ for (auto *A : CurrentArguments)
+ CurrentBB->addArgument(A);
}
void SExprBuilder::handleStatement(const Stmt *S) {
- til::SExpr *E = translate(S, CallCtx.get());
+ til::SExpr *E = translate(S, nullptr);
addStatement(E, S);
}
@@ -726,17 +930,16 @@ void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
til::BasicBlock *BB = *It ? lookupBlock(*It) : nullptr;
// TODO: set index
unsigned Idx = BB ? BB->findPredecessorIndex(CurrentBB) : 0;
- til::SExpr *Tm = new (Arena) til::Goto(BB, Idx);
+ auto *Tm = new (Arena) til::Goto(BB, Idx);
CurrentBB->setTerminator(Tm);
}
else if (N == 2) {
- til::SExpr *C = translate(B->getTerminatorCondition(true), CallCtx.get());
+ til::SExpr *C = translate(B->getTerminatorCondition(true), nullptr);
til::BasicBlock *BB1 = *It ? lookupBlock(*It) : nullptr;
++It;
til::BasicBlock *BB2 = *It ? lookupBlock(*It) : nullptr;
- unsigned Idx1 = BB1 ? BB1->findPredecessorIndex(CurrentBB) : 0;
- unsigned Idx2 = BB2 ? BB2->findPredecessorIndex(CurrentBB) : 0;
- til::SExpr *Tm = new (Arena) til::Branch(C, BB1, BB2, Idx1, Idx2);
+ // FIXME: make sure these arent' critical edges.
+ auto *Tm = new (Arena) til::Branch(C, BB1, BB2);
CurrentBB->setTerminator(Tm);
}
}
@@ -763,10 +966,9 @@ void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
void SExprBuilder::exitCFG(const CFGBlock *Last) {
- for (auto *V : IncompleteArgs) {
- til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
- if (Ph && Ph->status() == til::Phi::PH_Incomplete)
- simplifyIncompleteArg(V, Ph);
+ for (auto *Ph : IncompleteArgs) {
+ if (Ph->status() == til::Phi::PH_Incomplete)
+ simplifyIncompleteArg(Ph);
}
CurrentArguments.clear();
@@ -775,18 +977,15 @@ void SExprBuilder::exitCFG(const CFGBlock *Last) {
}
-
-class TILPrinter : public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {};
-
-
+/*
void printSCFG(CFGWalker &Walker) {
llvm::BumpPtrAllocator Bpa;
til::MemRegionRef Arena(&Bpa);
- SExprBuilder builder(Arena);
- til::SCFG *Cfg = builder.buildCFG(Walker);
- TILPrinter::print(Cfg, llvm::errs());
+ SExprBuilder SxBuilder(Arena);
+ til::SCFG *Scfg = SxBuilder.buildCFG(Walker);
+ TILPrinter::print(Scfg, llvm::errs());
}
-
+*/
} // end namespace threadSafety
diff --git a/lib/Analysis/ThreadSafetyTIL.cpp b/lib/Analysis/ThreadSafetyTIL.cpp
index f67cbb90e5ab..ebe374ea609d 100644
--- a/lib/Analysis/ThreadSafetyTIL.cpp
+++ b/lib/Analysis/ThreadSafetyTIL.cpp
@@ -48,12 +48,20 @@ StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op) {
}
+SExpr* Future::force() {
+ Status = FS_evaluating;
+ Result = compute();
+ Status = FS_done;
+ return Result;
+}
+
+
unsigned BasicBlock::addPredecessor(BasicBlock *Pred) {
unsigned Idx = Predecessors.size();
Predecessors.reserveCheck(1, Arena);
Predecessors.push_back(Pred);
- for (Variable *V : Args) {
- if (Phi* Ph = dyn_cast<Phi>(V->definition())) {
+ for (SExpr *E : Args) {
+ if (Phi* Ph = dyn_cast<Phi>(E)) {
Ph->values().reserveCheck(1, Arena);
Ph->values().push_back(nullptr);
}
@@ -61,93 +69,275 @@ unsigned BasicBlock::addPredecessor(BasicBlock *Pred) {
return Idx;
}
+
void BasicBlock::reservePredecessors(unsigned NumPreds) {
Predecessors.reserve(NumPreds, Arena);
- for (Variable *V : Args) {
- if (Phi* Ph = dyn_cast<Phi>(V->definition())) {
+ for (SExpr *E : Args) {
+ if (Phi* Ph = dyn_cast<Phi>(E)) {
Ph->values().reserve(NumPreds, Arena);
}
}
}
-void BasicBlock::renumberVars() {
- unsigned VID = 0;
- for (Variable *V : Args) {
- V->setID(BlockID, VID++);
- }
- for (Variable *V : Instrs) {
- V->setID(BlockID, VID++);
- }
-}
-void SCFG::renumberVars() {
- for (BasicBlock *B : Blocks) {
- B->renumberVars();
+// If E is a variable, then trace back through any aliases or redundant
+// Phi nodes to find the canonical definition.
+const SExpr *getCanonicalVal(const SExpr *E) {
+ while (true) {
+ if (auto *V = dyn_cast<Variable>(E)) {
+ if (V->kind() == Variable::VK_Let) {
+ E = V->definition();
+ continue;
+ }
+ }
+ if (const Phi *Ph = dyn_cast<Phi>(E)) {
+ if (Ph->status() == Phi::PH_SingleVal) {
+ E = Ph->values()[0];
+ continue;
+ }
+ }
+ break;
}
+ return E;
}
-
-
// If E is a variable, then trace back through any aliases or redundant
// Phi nodes to find the canonical definition.
-SExpr *getCanonicalVal(SExpr *E) {
- while (auto *V = dyn_cast<Variable>(E)) {
- SExpr *D;
- do {
+// The non-const version will simplify incomplete Phi nodes.
+SExpr *simplifyToCanonicalVal(SExpr *E) {
+ while (true) {
+ if (auto *V = dyn_cast<Variable>(E)) {
if (V->kind() != Variable::VK_Let)
return V;
- D = V->definition();
- auto *V2 = dyn_cast<Variable>(D);
- if (V2)
- V = V2;
- else
- break;
- } while (true);
-
- if (ThreadSafetyTIL::isTrivial(D))
- return D;
-
- if (Phi *Ph = dyn_cast<Phi>(D)) {
+ // Eliminate redundant variables, e.g. x = y, or x = 5,
+ // but keep anything more complicated.
+ if (til::ThreadSafetyTIL::isTrivial(V->definition())) {
+ E = V->definition();
+ continue;
+ }
+ return V;
+ }
+ if (auto *Ph = dyn_cast<Phi>(E)) {
if (Ph->status() == Phi::PH_Incomplete)
- simplifyIncompleteArg(V, Ph);
-
+ simplifyIncompleteArg(Ph);
+ // Eliminate redundant Phi nodes.
if (Ph->status() == Phi::PH_SingleVal) {
E = Ph->values()[0];
continue;
}
}
- return V;
+ return E;
}
- return E;
}
// Trace the arguments of an incomplete Phi node to see if they have the same
// canonical definition. If so, mark the Phi node as redundant.
// getCanonicalVal() will recursively call simplifyIncompletePhi().
-void simplifyIncompleteArg(Variable *V, til::Phi *Ph) {
+void simplifyIncompleteArg(til::Phi *Ph) {
assert(Ph && Ph->status() == Phi::PH_Incomplete);
// eliminate infinite recursion -- assume that this node is not redundant.
Ph->setStatus(Phi::PH_MultiVal);
- SExpr *E0 = getCanonicalVal(Ph->values()[0]);
+ SExpr *E0 = simplifyToCanonicalVal(Ph->values()[0]);
for (unsigned i=1, n=Ph->values().size(); i<n; ++i) {
- SExpr *Ei = getCanonicalVal(Ph->values()[i]);
- if (Ei == V)
+ SExpr *Ei = simplifyToCanonicalVal(Ph->values()[i]);
+ if (Ei == Ph)
continue; // Recursive reference to itself. Don't count.
if (Ei != E0) {
return; // Status is already set to MultiVal.
}
}
Ph->setStatus(Phi::PH_SingleVal);
- // Eliminate Redundant Phi node.
- V->setDefinition(Ph->values()[0]);
}
+// Renumbers the arguments and instructions to have unique, sequential IDs.
+int BasicBlock::renumberInstrs(int ID) {
+ for (auto *Arg : Args)
+ Arg->setID(this, ID++);
+ for (auto *Instr : Instrs)
+ Instr->setID(this, ID++);
+ TermInstr->setID(this, ID++);
+ return ID;
+}
+
+// Sorts the CFGs blocks using a reverse post-order depth-first traversal.
+// Each block will be written into the Blocks array in order, and its BlockID
+// will be set to the index in the array. Sorting should start from the entry
+// block, and ID should be the total number of blocks.
+int BasicBlock::topologicalSort(SimpleArray<BasicBlock*>& Blocks, int ID) {
+ if (Visited) return ID;
+ Visited = true;
+ for (auto *Block : successors())
+ ID = Block->topologicalSort(Blocks, ID);
+ // set ID and update block array in place.
+ // We may lose pointers to unreachable blocks.
+ assert(ID > 0);
+ BlockID = --ID;
+ Blocks[BlockID] = this;
+ return ID;
+}
+
+// Performs a reverse topological traversal, starting from the exit block and
+// following back-edges. The dominator is serialized before any predecessors,
+// which guarantees that all blocks are serialized after their dominator and
+// before their post-dominator (because it's a reverse topological traversal).
+// ID should be initially set to 0.
+//
+// This sort assumes that (1) dominators have been computed, (2) there are no
+// critical edges, and (3) the entry block is reachable from the exit block
+// and no blocks are accessable via traversal of back-edges from the exit that
+// weren't accessable via forward edges from the entry.
+int BasicBlock::topologicalFinalSort(SimpleArray<BasicBlock*>& Blocks, int ID) {
+ // Visited is assumed to have been set by the topologicalSort. This pass
+ // assumes !Visited means that we've visited this node before.
+ if (!Visited) return ID;
+ Visited = false;
+ if (DominatorNode.Parent)
+ ID = DominatorNode.Parent->topologicalFinalSort(Blocks, ID);
+ for (auto *Pred : Predecessors)
+ ID = Pred->topologicalFinalSort(Blocks, ID);
+ assert(static_cast<size_t>(ID) < Blocks.size());
+ BlockID = ID++;
+ Blocks[BlockID] = this;
+ return ID;
+}
+
+// Computes the immediate dominator of the current block. Assumes that all of
+// its predecessors have already computed their dominators. This is achieved
+// by visiting the nodes in topological order.
+void BasicBlock::computeDominator() {
+ BasicBlock *Candidate = nullptr;
+ // Walk backwards from each predecessor to find the common dominator node.
+ for (auto *Pred : Predecessors) {
+ // Skip back-edges
+ if (Pred->BlockID >= BlockID) continue;
+ // If we don't yet have a candidate for dominator yet, take this one.
+ if (Candidate == nullptr) {
+ Candidate = Pred;
+ continue;
+ }
+ // Walk the alternate and current candidate back to find a common ancestor.
+ auto *Alternate = Pred;
+ while (Alternate != Candidate) {
+ if (Candidate->BlockID > Alternate->BlockID)
+ Candidate = Candidate->DominatorNode.Parent;
+ else
+ Alternate = Alternate->DominatorNode.Parent;
+ }
+ }
+ DominatorNode.Parent = Candidate;
+ DominatorNode.SizeOfSubTree = 1;
+}
+
+// Computes the immediate post-dominator of the current block. Assumes that all
+// of its successors have already computed their post-dominators. This is
+// achieved visiting the nodes in reverse topological order.
+void BasicBlock::computePostDominator() {
+ BasicBlock *Candidate = nullptr;
+ // Walk back from each predecessor to find the common post-dominator node.
+ for (auto *Succ : successors()) {
+ // Skip back-edges
+ if (Succ->BlockID <= BlockID) continue;
+ // If we don't yet have a candidate for post-dominator yet, take this one.
+ if (Candidate == nullptr) {
+ Candidate = Succ;
+ continue;
+ }
+ // Walk the alternate and current candidate back to find a common ancestor.
+ auto *Alternate = Succ;
+ while (Alternate != Candidate) {
+ if (Candidate->BlockID < Alternate->BlockID)
+ Candidate = Candidate->PostDominatorNode.Parent;
+ else
+ Alternate = Alternate->PostDominatorNode.Parent;
+ }
+ }
+ PostDominatorNode.Parent = Candidate;
+ PostDominatorNode.SizeOfSubTree = 1;
+}
+
+
+// Renumber instructions in all blocks
+void SCFG::renumberInstrs() {
+ int InstrID = 0;
+ for (auto *Block : Blocks)
+ InstrID = Block->renumberInstrs(InstrID);
+}
+
+
+static inline void computeNodeSize(BasicBlock *B,
+ BasicBlock::TopologyNode BasicBlock::*TN) {
+ BasicBlock::TopologyNode *N = &(B->*TN);
+ if (N->Parent) {
+ BasicBlock::TopologyNode *P = &(N->Parent->*TN);
+ // Initially set ID relative to the (as yet uncomputed) parent ID
+ N->NodeID = P->SizeOfSubTree;
+ P->SizeOfSubTree += N->SizeOfSubTree;
+ }
+}
+
+static inline void computeNodeID(BasicBlock *B,
+ BasicBlock::TopologyNode BasicBlock::*TN) {
+ BasicBlock::TopologyNode *N = &(B->*TN);
+ if (N->Parent) {
+ BasicBlock::TopologyNode *P = &(N->Parent->*TN);
+ N->NodeID += P->NodeID; // Fix NodeIDs relative to starting node.
+ }
+}
+
+
+// Normalizes a CFG. Normalization has a few major components:
+// 1) Removing unreachable blocks.
+// 2) Computing dominators and post-dominators
+// 3) Topologically sorting the blocks into the "Blocks" array.
+void SCFG::computeNormalForm() {
+ // Topologically sort the blocks starting from the entry block.
+ int NumUnreachableBlocks = Entry->topologicalSort(Blocks, Blocks.size());
+ if (NumUnreachableBlocks > 0) {
+ // If there were unreachable blocks shift everything down, and delete them.
+ for (size_t I = NumUnreachableBlocks, E = Blocks.size(); I < E; ++I) {
+ size_t NI = I - NumUnreachableBlocks;
+ Blocks[NI] = Blocks[I];
+ Blocks[NI]->BlockID = NI;
+ // FIXME: clean up predecessor pointers to unreachable blocks?
+ }
+ Blocks.drop(NumUnreachableBlocks);
+ }
+
+ // Compute dominators.
+ for (auto *Block : Blocks)
+ Block->computeDominator();
+
+ // Once dominators have been computed, the final sort may be performed.
+ int NumBlocks = Exit->topologicalFinalSort(Blocks, 0);
+ assert(static_cast<size_t>(NumBlocks) == Blocks.size());
+ (void) NumBlocks;
+
+ // Renumber the instructions now that we have a final sort.
+ renumberInstrs();
+
+ // Compute post-dominators and compute the sizes of each node in the
+ // dominator tree.
+ for (auto *Block : Blocks.reverse()) {
+ Block->computePostDominator();
+ computeNodeSize(Block, &BasicBlock::DominatorNode);
+ }
+ // Compute the sizes of each node in the post-dominator tree and assign IDs in
+ // the dominator tree.
+ for (auto *Block : Blocks) {
+ computeNodeID(Block, &BasicBlock::DominatorNode);
+ computeNodeSize(Block, &BasicBlock::PostDominatorNode);
+ }
+ // Assign IDs in the post-dominator tree.
+ for (auto *Block : Blocks.reverse()) {
+ computeNodeID(Block, &BasicBlock::PostDominatorNode);
+ }
+}
+
} // end namespace til
} // end namespace threadSafety
} // end namespace clang
-
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index f5c786ac3456..61a259217d7d 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -360,13 +360,28 @@ void ClassifyRefs::classify(const Expr *E, Class C) {
// The result of a ?: could also be an lvalue.
E = E->IgnoreParens();
if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
- const Expr *TrueExpr = CO->getTrueExpr();
- if (!isa<OpaqueValueExpr>(TrueExpr))
- classify(TrueExpr, C);
+ classify(CO->getTrueExpr(), C);
classify(CO->getFalseExpr(), C);
return;
}
+ if (const BinaryConditionalOperator *BCO =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ classify(BCO->getFalseExpr(), C);
+ return;
+ }
+
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) {
+ classify(OVE->getSourceExpr(), C);
+ return;
+ }
+
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Comma)
+ classify(BO->getRHS(), C);
+ return;
+ }
+
FindVarResult Var = findVar(E, DC);
if (const DeclRefExpr *DRE = Var.getDeclRefExpr())
Classification[DRE] = std::max(Classification[DRE], C);
@@ -401,6 +416,17 @@ void ClassifyRefs::VisitUnaryOperator(UnaryOperator *UO) {
}
void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
+ // Classify arguments to std::move as used.
+ if (CE->getNumArgs() == 1) {
+ if (FunctionDecl *FD = CE->getDirectCallee()) {
+ if (FD->isInStdNamespace() && FD->getIdentifier() &&
+ FD->getIdentifier()->isStr("move")) {
+ classify(CE->getArg(0), Use);
+ return;
+ }
+ }
+ }
+
// If a value is passed by const reference to a function, we should not assume
// that it is initialized by the call, and we conservatively do not assume
// that it is used.
diff --git a/lib/Basic/Attributes.cpp b/lib/Basic/Attributes.cpp
index a05ad053db04..da9ac793f163 100644
--- a/lib/Basic/Attributes.cpp
+++ b/lib/Basic/Attributes.cpp
@@ -3,7 +3,7 @@
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
-bool clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
+int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
const IdentifierInfo *Attr, const llvm::Triple &T,
const LangOptions &LangOpts) {
StringRef Name = Attr->getName();
@@ -13,5 +13,5 @@ bool clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
#include "clang/Basic/AttrHasAttributeImpl.inc"
- return false;
+ return 0;
}
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 0df82b3bc906..50a06d9e7a42 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -1,8 +1,60 @@
set(LLVM_LINK_COMPONENTS
+ Core
MC
Support
)
+# Figure out if we can track VC revisions.
+function(find_first_existing_file out_var)
+ foreach(file ${ARGN})
+ if(EXISTS "${file}")
+ set(${out_var} "${file}" PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+endfunction()
+
+macro(find_first_existing_vc_file out_var path)
+ find_first_existing_file(${out_var}
+ "${path}/.git/logs/HEAD" # Git
+ "${path}/.svn/wc.db" # SVN 1.7
+ "${path}/.svn/entries" # SVN 1.6
+ )
+endmacro()
+
+find_first_existing_vc_file(llvm_vc "${LLVM_MAIN_SRC_DIR}")
+find_first_existing_vc_file(clang_vc "${CLANG_SOURCE_DIR}")
+
+# The VC revision include that we want to generate.
+set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc")
+
+set(get_svn_script "${LLVM_MAIN_SRC_DIR}/cmake/modules/GetSVN.cmake")
+
+if(DEFINED llvm_vc AND DEFINED clang_vc)
+ # Create custom target to generate the VC revision include.
+ add_custom_command(OUTPUT "${version_inc}"
+ DEPENDS "${llvm_vc}" "${clang_vc}" "${get_svn_script}"
+ COMMAND
+ ${CMAKE_COMMAND} "-DFIRST_SOURCE_DIR=${LLVM_MAIN_SRC_DIR}"
+ "-DFIRST_NAME=LLVM"
+ "-DSECOND_SOURCE_DIR=${CLANG_SOURCE_DIR}"
+ "-DSECOND_NAME=SVN"
+ "-DHEADER_FILE=${version_inc}"
+ -P "${get_svn_script}")
+
+ # Mark the generated header as being generated.
+ set_source_files_properties("${version_inc}"
+ PROPERTIES GENERATED TRUE
+ HEADER_FILE_ONLY TRUE)
+
+ # Tell Version.cpp that it needs to build with -DHAVE_SVN_VERSION_INC.
+ set_source_files_properties(Version.cpp
+ PROPERTIES COMPILE_DEFINITIONS "HAVE_SVN_VERSION_INC")
+else()
+ # Not producing a VC revision include.
+ set(version_inc)
+endif()
+
add_clang_library(clangBasic
Attributes.cpp
Builtins.cpp
@@ -17,6 +69,8 @@ add_clang_library(clangBasic
ObjCRuntime.cpp
OpenMPKinds.cpp
OperatorPrecedence.cpp
+ SanitizerBlacklist.cpp
+ Sanitizers.cpp
SourceLocation.cpp
SourceManager.cpp
TargetInfo.cpp
@@ -26,30 +80,6 @@ add_clang_library(clangBasic
VersionTuple.cpp
VirtualFileSystem.cpp
Warnings.cpp
+ ${version_inc}
)
-# Determine Subversion revision.
-# FIXME: This only gets updated when CMake is run, so this revision number
-# may be out-of-date!
-if( NOT IS_SYMLINK "${CLANG_SOURCE_DIR}" ) # See PR 8437
- find_package(Subversion)
-endif()
-if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn")
- set(FIRST_SOURCE_DIR ${LLVM_MAIN_SRC_DIR})
- set(FIRST_REPOSITORY LLVM_REPOSITORY)
- set(SECOND_SOURCE_DIR ${CLANG_SOURCE_DIR})
- set(SECOND_REPOSITORY SVN_REPOSITORY)
- set(HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc)
- include(GetSVN)
-
- # Mark the generated header as being generated.
- message(STATUS "Expecting header to go in ${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc")
- set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc
- PROPERTIES GENERATED TRUE
- HEADER_FILE_ONLY TRUE)
-
- # Tell Version.cpp that it needs to build with -DHAVE_SVN_VERSION_INC.
- set_source_files_properties(Version.cpp
- PROPERTIES COMPILE_DEFINITIONS "HAVE_SVN_VERSION_INC")
-
-endif()
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 4567e3267131..83228ad3c55d 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/Locale.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -33,13 +34,11 @@ static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
Output.append(Str.begin(), Str.end());
}
-
DiagnosticsEngine::DiagnosticsEngine(
- const IntrusiveRefCntPtr<DiagnosticIDs> &diags,
- DiagnosticOptions *DiagOpts,
- DiagnosticConsumer *client, bool ShouldOwnClient)
- : Diags(diags), DiagOpts(DiagOpts), Client(client),
- OwnsDiagClient(ShouldOwnClient), SourceMgr(nullptr) {
+ const IntrusiveRefCntPtr<DiagnosticIDs> &diags, DiagnosticOptions *DiagOpts,
+ DiagnosticConsumer *client, bool ShouldOwnClient)
+ : Diags(diags), DiagOpts(DiagOpts), Client(nullptr), SourceMgr(nullptr) {
+ setClient(client, ShouldOwnClient);
ArgToStringFn = DummyArgToStringFn;
ArgToStringCookie = nullptr;
@@ -64,17 +63,15 @@ DiagnosticsEngine::DiagnosticsEngine(
}
DiagnosticsEngine::~DiagnosticsEngine() {
- if (OwnsDiagClient)
- delete Client;
+ // If we own the diagnostic client, destroy it first so that it can access the
+ // engine from its destructor.
+ setClient(nullptr);
}
void DiagnosticsEngine::setClient(DiagnosticConsumer *client,
bool ShouldOwnClient) {
- if (OwnsDiagClient && Client)
- delete Client;
-
+ Owner.reset(ShouldOwnClient ? client : nullptr);
Client = client;
- OwnsDiagClient = ShouldOwnClient;
}
void DiagnosticsEngine::pushMappings(SourceLocation Loc) {
@@ -101,7 +98,6 @@ void DiagnosticsEngine::Reset() {
NumWarnings = 0;
NumErrors = 0;
- NumErrorsSuppressed = 0;
TrapNumErrorsOccurred = 0;
TrapNumUnrecoverableErrorsOccurred = 0;
@@ -232,13 +228,13 @@ bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
StringRef Group, diag::Severity Map,
SourceLocation Loc) {
// Get the diagnostics in this group.
- SmallVector<diag::kind, 8> GroupDiags;
+ SmallVector<diag::kind, 256> GroupDiags;
if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
return true;
// Set the mapping.
- for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i)
- setSeverity(GroupDiags[i], Map, Loc);
+ for (diag::kind Diag : GroupDiags)
+ setSeverity(Diag, Map, Loc);
return false;
}
@@ -634,6 +630,20 @@ void Diagnostic::
FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
SmallVectorImpl<char> &OutStr) const {
+ // When the diagnostic string is only "%0", the entire string is being given
+ // by an outside source. Remove unprintable characters from this string
+ // and skip all the other string processing.
+ if (DiagEnd - DiagStr == 2 && DiagStr[0] == '%' && DiagStr[1] == '0' &&
+ getArgKind(0) == DiagnosticsEngine::ak_std_string) {
+ const std::string &S = getArgStdStr(0);
+ for (char c : S) {
+ if (llvm::sys::locale::isPrint(c) || c == '\t') {
+ OutStr.push_back(c);
+ }
+ }
+ return;
+ }
+
/// FormattedArgs - Keep track of all of the arguments formatted by
/// ConvertArgToString and pass them into subsequent calls to
/// ConvertArgToString, allowing the implementation to avoid redundancies in
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index ec244ccda3cb..1c68375f3cdd 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -428,16 +428,9 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// Upgrade ignored diagnostics if -Weverything is enabled.
if (Diag.EnableAllWarnings && Result == diag::Severity::Ignored &&
- !Mapping.isUser())
+ !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
Result = diag::Severity::Warning;
- // Diagnostics of class REMARK are either printed as remarks or in case they
- // have been added to -Werror they are printed as errors.
- // FIXME: Disregarding user-requested remark mappings like this is bogus.
- if (Result == diag::Severity::Warning &&
- getBuiltinDiagClass(DiagID) == CLASS_REMARK)
- Result = diag::Severity::Remark;
-
// Ignore -pedantic diagnostics inside __extension__ blocks.
// (The diagnostics controlled by -pedantic are the extension diagnostics
// that are not enabled by default.)
@@ -613,9 +606,6 @@ StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor,
bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
Diagnostic Info(&Diag);
- if (Diag.SuppressAllDiagnostics)
- return false;
-
assert(Diag.getClient() && "DiagnosticClient not set!");
// Figure out the diagnostic level of this message.
@@ -623,6 +613,17 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
DiagnosticIDs::Level DiagLevel
= getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
+ // Update counts for DiagnosticErrorTrap even if a fatal error occurred
+ // or diagnostics are suppressed.
+ if (DiagLevel >= DiagnosticIDs::Error) {
+ ++Diag.TrapNumErrorsOccurred;
+ if (isUnrecoverable(DiagID))
+ ++Diag.TrapNumUnrecoverableErrorsOccurred;
+ }
+
+ if (Diag.SuppressAllDiagnostics)
+ return false;
+
if (DiagLevel != DiagnosticIDs::Note) {
// Record that a fatal error occurred only when we see a second
// non-note diagnostic. This allows notes to be attached to the
@@ -634,20 +635,12 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
Diag.LastDiagLevel = DiagLevel;
}
- // Update counts for DiagnosticErrorTrap even if a fatal error occurred.
- if (DiagLevel >= DiagnosticIDs::Error) {
- ++Diag.TrapNumErrorsOccurred;
- if (isUnrecoverable(DiagID))
- ++Diag.TrapNumUnrecoverableErrorsOccurred;
- }
-
// If a fatal error has already been emitted, silence all subsequent
// diagnostics.
if (Diag.FatalErrorOccurred) {
if (DiagLevel >= DiagnosticIDs::Error &&
Diag.Client->IncludeInDiagnosticCounts()) {
++Diag.NumErrors;
- ++Diag.NumErrorsSuppressed;
}
return false;
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 94210320bff7..214e0f35a52e 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -64,20 +64,20 @@ FileManager::~FileManager() {
delete VirtualDirectoryEntries[i];
}
-void FileManager::addStatCache(FileSystemStatCache *statCache,
+void FileManager::addStatCache(std::unique_ptr<FileSystemStatCache> statCache,
bool AtBeginning) {
assert(statCache && "No stat cache provided?");
if (AtBeginning || !StatCache.get()) {
- statCache->setNextStatCache(StatCache.release());
- StatCache.reset(statCache);
+ statCache->setNextStatCache(std::move(StatCache));
+ StatCache = std::move(statCache);
return;
}
FileSystemStatCache *LastCache = StatCache.get();
while (LastCache->getNextStatCache())
LastCache = LastCache->getNextStatCache();
-
- LastCache->setNextStatCache(statCache);
+
+ LastCache->setNextStatCache(std::move(statCache));
}
void FileManager::removeStatCache(FileSystemStatCache *statCache) {
@@ -86,7 +86,7 @@ void FileManager::removeStatCache(FileSystemStatCache *statCache) {
if (StatCache.get() == statCache) {
// This is the first stat cache.
- StatCache.reset(StatCache->takeNextStatCache());
+ StatCache = StatCache->takeNextStatCache();
return;
}
@@ -96,7 +96,7 @@ void FileManager::removeStatCache(FileSystemStatCache *statCache) {
PrevCache = PrevCache->getNextStatCache();
assert(PrevCache && "Stat cache not found for removal");
- PrevCache->setNextStatCache(statCache->getNextStatCache());
+ PrevCache->setNextStatCache(statCache->takeNextStatCache());
}
void FileManager::clearStatCaches() {
@@ -129,20 +129,20 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
if (DirName.empty())
return;
- llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
- SeenDirEntries.GetOrCreateValue(DirName);
+ auto &NamedDirEnt =
+ *SeenDirEntries.insert(std::make_pair(DirName, nullptr)).first;
// When caching a virtual directory, we always cache its ancestors
// at the same time. Therefore, if DirName is already in the cache,
// we don't need to recurse as its ancestors must also already be in
// the cache.
- if (NamedDirEnt.getValue())
+ if (NamedDirEnt.second)
return;
// Add the virtual directory to the cache.
DirectoryEntry *UDE = new DirectoryEntry;
- UDE->Name = NamedDirEnt.getKeyData();
- NamedDirEnt.setValue(UDE);
+ UDE->Name = NamedDirEnt.first().data();
+ NamedDirEnt.second = UDE;
VirtualDirectoryEntries.push_back(UDE);
// Recursively add the other ancestors.
@@ -170,23 +170,23 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
#endif
++NumDirLookups;
- llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
- SeenDirEntries.GetOrCreateValue(DirName);
+ auto &NamedDirEnt =
+ *SeenDirEntries.insert(std::make_pair(DirName, nullptr)).first;
// See if there was already an entry in the map. Note that the map
// contains both virtual and real directories.
- if (NamedDirEnt.getValue())
- return NamedDirEnt.getValue() == NON_EXISTENT_DIR ? nullptr
- : NamedDirEnt.getValue();
+ if (NamedDirEnt.second)
+ return NamedDirEnt.second == NON_EXISTENT_DIR ? nullptr
+ : NamedDirEnt.second;
++NumDirCacheMisses;
// By default, initialize it to invalid.
- NamedDirEnt.setValue(NON_EXISTENT_DIR);
+ NamedDirEnt.second = NON_EXISTENT_DIR;
// Get the null-terminated directory name as stored as the key of the
// SeenDirEntries map.
- const char *InterndDirName = NamedDirEnt.getKeyData();
+ const char *InterndDirName = NamedDirEnt.first().data();
// Check to see if the directory exists.
FileData Data;
@@ -203,7 +203,7 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
// Windows).
DirectoryEntry &UDE = UniqueRealDirs[Data.UniqueID];
- NamedDirEnt.setValue(&UDE);
+ NamedDirEnt.second = &UDE;
if (!UDE.getName()) {
// We don't have this directory yet, add it. We use the string
// key from the SeenDirEntries map as the string.
@@ -218,22 +218,22 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
++NumFileLookups;
// See if there is already an entry in the map.
- llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
- SeenFileEntries.GetOrCreateValue(Filename);
+ auto &NamedFileEnt =
+ *SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first;
// See if there is already an entry in the map.
- if (NamedFileEnt.getValue())
- return NamedFileEnt.getValue() == NON_EXISTENT_FILE
- ? nullptr : NamedFileEnt.getValue();
+ if (NamedFileEnt.second)
+ return NamedFileEnt.second == NON_EXISTENT_FILE ? nullptr
+ : NamedFileEnt.second;
++NumFileCacheMisses;
// By default, initialize it to invalid.
- NamedFileEnt.setValue(NON_EXISTENT_FILE);
+ NamedFileEnt.second = NON_EXISTENT_FILE;
// Get the null-terminated file name as stored as the key of the
// SeenFileEntries map.
- const char *InterndFileName = NamedFileEnt.getKeyData();
+ const char *InterndFileName = NamedFileEnt.first().data();
// Look up the directory for the file. When looking up something like
// sys/foo.h we'll discover all of the search directories that have a 'sys'
@@ -269,7 +269,21 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// This occurs when one dir is symlinked to another, for example.
FileEntry &UFE = UniqueRealFiles[Data.UniqueID];
- NamedFileEnt.setValue(&UFE);
+ NamedFileEnt.second = &UFE;
+
+ // If the name returned by getStatValue is different than Filename, re-intern
+ // the name.
+ if (Data.Name != Filename) {
+ auto &NamedFileEnt =
+ *SeenFileEntries.insert(std::make_pair(Data.Name, nullptr)).first;
+ if (!NamedFileEnt.second)
+ NamedFileEnt.second = &UFE;
+ else
+ assert(NamedFileEnt.second == &UFE &&
+ "filename from getStatValue() refers to wrong file");
+ InterndFileName = NamedFileEnt.first().data();
+ }
+
if (UFE.isValid()) { // Already have an entry with this inode, return it.
// FIXME: this hack ensures that if we look up a file by a virtual path in
@@ -281,11 +295,18 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
if (DirInfo != UFE.Dir && Data.IsVFSMapped)
UFE.Dir = DirInfo;
+ // Always update the name to use the last name by which a file was accessed.
+ // FIXME: Neither this nor always using the first name is correct; we want
+ // to switch towards a design where we return a FileName object that
+ // encapsulates both the name by which the file was accessed and the
+ // corresponding FileEntry.
+ UFE.Name = InterndFileName;
+
return &UFE;
}
// Otherwise, we don't have this file yet, add it.
- UFE.Name = Data.Name;
+ UFE.Name = InterndFileName;
UFE.Size = Data.Size;
UFE.ModTime = Data.ModTime;
UFE.Dir = DirInfo;
@@ -304,17 +325,17 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
++NumFileLookups;
// See if there is already an entry in the map.
- llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
- SeenFileEntries.GetOrCreateValue(Filename);
+ auto &NamedFileEnt =
+ *SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first;
// See if there is already an entry in the map.
- if (NamedFileEnt.getValue() && NamedFileEnt.getValue() != NON_EXISTENT_FILE)
- return NamedFileEnt.getValue();
+ if (NamedFileEnt.second && NamedFileEnt.second != NON_EXISTENT_FILE)
+ return NamedFileEnt.second;
++NumFileCacheMisses;
// By default, initialize it to invalid.
- NamedFileEnt.setValue(NON_EXISTENT_FILE);
+ NamedFileEnt.second = NON_EXISTENT_FILE;
addAncestorsAsVirtualDirs(Filename);
FileEntry *UFE = nullptr;
@@ -329,13 +350,13 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
// Check to see if the file exists. If so, drop the virtual file
FileData Data;
- const char *InterndFileName = NamedFileEnt.getKeyData();
+ const char *InterndFileName = NamedFileEnt.first().data();
if (getStatValue(InterndFileName, Data, true, nullptr) == 0) {
Data.Size = Size;
Data.ModTime = ModificationTime;
UFE = &UniqueRealFiles[Data.UniqueID];
- NamedFileEnt.setValue(UFE);
+ NamedFileEnt.second = UFE;
// If we had already opened this file, close it now so we don't
// leak the descriptor. We're not going to use the file
@@ -355,7 +376,7 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
if (!UFE) {
UFE = new FileEntry();
VirtualFileEntries.push_back(UFE);
- NamedFileEnt.setValue(UFE);
+ NamedFileEnt.second = UFE;
}
UFE->Name = InterndFileName;
@@ -379,12 +400,9 @@ void FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const {
path = NewPath;
}
-llvm::MemoryBuffer *FileManager::
-getBufferForFile(const FileEntry *Entry, std::string *ErrorStr,
- bool isVolatile, bool ShouldCloseOpenFile) {
- std::unique_ptr<llvm::MemoryBuffer> Result;
- std::error_code ec;
-
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile,
+ bool ShouldCloseOpenFile) {
uint64_t FileSize = Entry->getSize();
// If there's a high enough chance that the file have changed since we
// got its size, force a stat before opening it.
@@ -394,53 +412,36 @@ getBufferForFile(const FileEntry *Entry, std::string *ErrorStr,
const char *Filename = Entry->getName();
// If the file is already open, use the open file descriptor.
if (Entry->File) {
- ec = Entry->File->getBuffer(Filename, Result, FileSize,
- /*RequiresNullTerminator=*/true, isVolatile);
- if (ErrorStr)
- *ErrorStr = ec.message();
+ auto Result =
+ Entry->File->getBuffer(Filename, FileSize,
+ /*RequiresNullTerminator=*/true, isVolatile);
// FIXME: we need a set of APIs that can make guarantees about whether a
// FileEntry is open or not.
if (ShouldCloseOpenFile)
Entry->closeFile();
- return Result.release();
+ return Result;
}
// Otherwise, open the file.
- if (FileSystemOpts.WorkingDir.empty()) {
- ec = FS->getBufferForFile(Filename, Result, FileSize,
- /*RequiresNullTerminator=*/true, isVolatile);
- if (ec && ErrorStr)
- *ErrorStr = ec.message();
- return Result.release();
- }
+ if (FileSystemOpts.WorkingDir.empty())
+ return FS->getBufferForFile(Filename, FileSize,
+ /*RequiresNullTerminator=*/true, isVolatile);
SmallString<128> FilePath(Entry->getName());
FixupRelativePath(FilePath);
- ec = FS->getBufferForFile(FilePath.str(), Result, FileSize,
- /*RequiresNullTerminator=*/true, isVolatile);
- if (ec && ErrorStr)
- *ErrorStr = ec.message();
- return Result.release();
+ return FS->getBufferForFile(FilePath.str(), FileSize,
+ /*RequiresNullTerminator=*/true, isVolatile);
}
-llvm::MemoryBuffer *FileManager::
-getBufferForFile(StringRef Filename, std::string *ErrorStr) {
- std::unique_ptr<llvm::MemoryBuffer> Result;
- std::error_code ec;
- if (FileSystemOpts.WorkingDir.empty()) {
- ec = FS->getBufferForFile(Filename, Result);
- if (ec && ErrorStr)
- *ErrorStr = ec.message();
- return Result.release();
- }
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+FileManager::getBufferForFile(StringRef Filename) {
+ if (FileSystemOpts.WorkingDir.empty())
+ return FS->getBufferForFile(Filename);
SmallString<128> FilePath(Filename);
FixupRelativePath(FilePath);
- ec = FS->getBufferForFile(FilePath.c_str(), Result);
- if (ec && ErrorStr)
- *ErrorStr = ec.message();
- return Result.release();
+ return FS->getBufferForFile(FilePath.c_str());
}
/// getStatValue - Get the 'stat' information for the specified path,
@@ -512,15 +513,47 @@ void FileManager::modifyFileEntry(FileEntry *File,
File->ModTime = ModificationTime;
}
+/// Remove '.' path components from the given absolute path.
+/// \return \c true if any changes were made.
+// FIXME: Move this to llvm::sys::path.
+bool FileManager::removeDotPaths(SmallVectorImpl<char> &Path) {
+ using namespace llvm::sys;
+
+ SmallVector<StringRef, 16> ComponentStack;
+ StringRef P(Path.data(), Path.size());
+
+ // Skip the root path, then look for traversal in the components.
+ StringRef Rel = path::relative_path(P);
+ bool AnyDots = false;
+ for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) {
+ if (C == ".") {
+ AnyDots = true;
+ continue;
+ }
+ ComponentStack.push_back(C);
+ }
+
+ if (!AnyDots)
+ return false;
+
+ SmallString<256> Buffer = path::root_path(P);
+ for (StringRef C : ComponentStack)
+ path::append(Buffer, C);
+
+ Path.swap(Buffer);
+ return true;
+}
+
StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
// FIXME: use llvm::sys::fs::canonical() when it gets implemented
-#ifdef LLVM_ON_UNIX
llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
= CanonicalDirNames.find(Dir);
if (Known != CanonicalDirNames.end())
return Known->second;
StringRef CanonicalName(Dir->getName());
+
+#ifdef LLVM_ON_UNIX
char CanonicalNameBuf[PATH_MAX];
if (realpath(Dir->getName(), CanonicalNameBuf)) {
unsigned Len = strlen(CanonicalNameBuf);
@@ -528,12 +561,15 @@ StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
memcpy(Mem, CanonicalNameBuf, Len);
CanonicalName = StringRef(Mem, Len);
}
+#else
+ SmallString<256> CanonicalNameBuf(CanonicalName);
+ llvm::sys::fs::make_absolute(CanonicalNameBuf);
+ llvm::sys::path::native(CanonicalNameBuf);
+ removeDotPaths(CanonicalNameBuf);
+#endif
CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName));
return CanonicalName;
-#else
- return StringRef(Dir->getName());
-#endif
}
void FileManager::PrintStats() const {
diff --git a/lib/Basic/FileSystemStatCache.cpp b/lib/Basic/FileSystemStatCache.cpp
index 7515cfb440af..83e42bdb8483 100644
--- a/lib/Basic/FileSystemStatCache.cpp
+++ b/lib/Basic/FileSystemStatCache.cpp
@@ -78,21 +78,20 @@ bool FileSystemStatCache::get(const char *Path, FileData &Data, bool isFile,
//
// Because of this, check to see if the file exists with 'open'. If the
// open succeeds, use fstat to get the stat info.
- std::unique_ptr<vfs::File> OwnedFile;
- std::error_code EC = FS.openFileForRead(Path, OwnedFile);
+ auto OwnedFile = FS.openFileForRead(Path);
- if (EC) {
+ if (!OwnedFile) {
// If the open fails, our "stat" fails.
R = CacheMissing;
} else {
// Otherwise, the open succeeded. Do an fstat to get the information
// about the file. We'll end up returning the open file descriptor to the
// client to do what they please with it.
- llvm::ErrorOr<vfs::Status> Status = OwnedFile->status();
+ llvm::ErrorOr<vfs::Status> Status = (*OwnedFile)->status();
if (Status) {
R = CacheExists;
copyStatusToFileData(*Status, Data);
- *F = std::move(OwnedFile);
+ *F = std::move(*OwnedFile);
} else {
// fstat rarely fails. If it does, claim the initial open didn't
// succeed.
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 219845996323..613b43fce95f 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -110,49 +110,59 @@ namespace {
HALFSUPPORT = 0x04000,
KEYALL = (0xffff & ~KEYNOMS) // Because KEYNOMS is used to exclude.
};
+
+ /// \brief How a keyword is treated in the selected standard.
+ enum KeywordStatus {
+ KS_Disabled, // Disabled
+ KS_Extension, // Is an extension
+ KS_Enabled, // Enabled
+ KS_Future // Is a keyword in future standard
+ };
+}
+
+/// \brief Translates flags as specified in TokenKinds.def into keyword status
+/// in the given language standard.
+static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
+ unsigned Flags) {
+ if (Flags == KEYALL) return KS_Enabled;
+ if (LangOpts.CPlusPlus && (Flags & KEYCXX)) return KS_Enabled;
+ if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) return KS_Enabled;
+ if (LangOpts.C99 && (Flags & KEYC99)) return KS_Enabled;
+ if (LangOpts.GNUKeywords && (Flags & KEYGNU)) return KS_Extension;
+ if (LangOpts.MicrosoftExt && (Flags & KEYMS)) return KS_Extension;
+ if (LangOpts.Borland && (Flags & KEYBORLAND)) return KS_Extension;
+ if (LangOpts.Bool && (Flags & BOOLSUPPORT)) return KS_Enabled;
+ if (LangOpts.Half && (Flags & HALFSUPPORT)) return KS_Enabled;
+ if (LangOpts.WChar && (Flags & WCHARSUPPORT)) return KS_Enabled;
+ if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) return KS_Enabled;
+ if (LangOpts.OpenCL && (Flags & KEYOPENCL)) return KS_Enabled;
+ if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) return KS_Enabled;
+ if (LangOpts.C11 && (Flags & KEYC11)) return KS_Enabled;
+ // We treat bridge casts as objective-C keywords so we can warn on them
+ // in non-arc mode.
+ if (LangOpts.ObjC2 && (Flags & KEYARC)) return KS_Enabled;
+ if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) return KS_Future;
+ return KS_Disabled;
}
/// AddKeyword - This method is used to associate a token ID with specific
/// identifiers because they are language keywords. This causes the lexer to
/// automatically map matching identifiers to specialized token codes.
-///
-/// The C90/C99/CPP/CPP0x flags are set to 3 if the token is a keyword in a
-/// future language standard, set to 2 if the token should be enabled in the
-/// specified language, set to 1 if it is an extension in the specified
-/// language, and set to 0 if disabled in the specified language.
static void AddKeyword(StringRef Keyword,
tok::TokenKind TokenCode, unsigned Flags,
const LangOptions &LangOpts, IdentifierTable &Table) {
- unsigned AddResult = 0;
- if (Flags == KEYALL) AddResult = 2;
- else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2;
- else if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) AddResult = 2;
- else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
- else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1;
- else if (LangOpts.MicrosoftExt && (Flags & KEYMS)) AddResult = 1;
- else if (LangOpts.Borland && (Flags & KEYBORLAND)) AddResult = 1;
- else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
- else if (LangOpts.Half && (Flags & HALFSUPPORT)) AddResult = 2;
- else if (LangOpts.WChar && (Flags & WCHARSUPPORT)) AddResult = 2;
- else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
- else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
- else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
- else if (LangOpts.C11 && (Flags & KEYC11)) AddResult = 2;
- // We treat bridge casts as objective-C keywords so we can warn on them
- // in non-arc mode.
- else if (LangOpts.ObjC2 && (Flags & KEYARC)) AddResult = 2;
- else if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) AddResult = 3;
+ KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags);
// Don't add this keyword under MSVCCompat.
if (LangOpts.MSVCCompat && (Flags & KEYNOMS))
return;
// Don't add this keyword if disabled in this language.
- if (AddResult == 0) return;
+ if (AddResult == KS_Disabled) return;
IdentifierInfo &Info =
- Table.get(Keyword, AddResult == 3 ? tok::identifier : TokenCode);
- Info.setIsExtensionToken(AddResult == 1);
- Info.setIsCXX11CompatKeyword(AddResult == 3);
+ Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode);
+ Info.setIsExtensionToken(AddResult == KS_Extension);
+ Info.setIsCXX11CompatKeyword(AddResult == KS_Future);
}
/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
@@ -199,6 +209,31 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
LangOpts, *this);
}
+/// \brief Checks if the specified token kind represents a keyword in the
+/// specified language.
+/// \returns Status of the keyword in the language.
+static KeywordStatus getTokenKwStatus(const LangOptions &LangOpts,
+ tok::TokenKind K) {
+ switch (K) {
+#define KEYWORD(NAME, FLAGS) \
+ case tok::kw_##NAME: return getKeywordStatus(LangOpts, FLAGS);
+#include "clang/Basic/TokenKinds.def"
+ default: return KS_Disabled;
+ }
+}
+
+/// \brief Returns true if the identifier represents a keyword in the
+/// specified language.
+bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) {
+ switch (getTokenKwStatus(LangOpts, getTokenID())) {
+ case KS_Enabled:
+ case KS_Extension:
+ return true;
+ default:
+ return false;
+ }
+}
+
tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
// We use a perfect hash function here involving the length of the keyword,
// the first and third character. For preprocessor ID's there are no
@@ -428,6 +463,7 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
if (name == "retain") return OMF_retain;
if (name == "retainCount") return OMF_retainCount;
if (name == "self") return OMF_self;
+ if (name == "initialize") return OMF_initialize;
}
if (name == "performSelector") return OMF_performSelector;
@@ -486,6 +522,33 @@ ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
return OIT_None;
}
+ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) {
+ IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
+ if (!first) return SFF_None;
+
+ StringRef name = first->getName();
+
+ switch (name.front()) {
+ case 'a':
+ if (name == "appendFormat") return SFF_NSString;
+ break;
+
+ case 'i':
+ if (name == "initWithFormat") return SFF_NSString;
+ break;
+
+ case 'l':
+ if (name == "localizedStringWithFormat") return SFF_NSString;
+ break;
+
+ case 's':
+ if (name == "stringByAppendingFormat" ||
+ name == "stringWithFormat") return SFF_NSString;
+ break;
+ }
+ return SFF_None;
+}
+
namespace {
struct SelectorTableImpl {
llvm::FoldingSet<MultiKeywordSelector> Table;
diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp
index f8714b2389cb..dcbd22817111 100644
--- a/lib/Basic/LangOptions.cpp
+++ b/lib/Basic/LangOptions.cpp
@@ -14,14 +14,10 @@
using namespace clang;
-const SanitizerOptions SanitizerOptions::Disabled = {};
-
LangOptions::LangOptions() {
#define LANGOPT(Name, Bits, Default, Description) Name = Default;
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) set##Name(Default);
#include "clang/Basic/LangOptions.def"
-
- Sanitize = SanitizerOptions::Disabled;
}
void LangOptions::resetNonModularOptions() {
@@ -33,8 +29,10 @@ void LangOptions::resetNonModularOptions() {
// FIXME: This should not be reset; modules can be different with different
// sanitizer options (this affects __has_feature(address_sanitizer) etc).
- Sanitize = SanitizerOptions::Disabled;
+ Sanitize.clear();
+ SanitizerBlacklistFile.clear();
CurrentModule.clear();
+ ImplementationOfModule.clear();
}
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index f689c733d9c0..03f9bd3f329c 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -25,8 +25,8 @@
using namespace clang;
Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
- const FileEntry *File, bool IsFramework, bool IsExplicit)
- : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), ModuleMap(File),
+ bool IsFramework, bool IsExplicit)
+ : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), Directory(),
Umbrella(), ASTFile(nullptr), IsMissingRequirement(false),
IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework),
IsExplicit(IsExplicit), IsSystem(false), IsExternC(false),
@@ -70,9 +70,9 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
.Default(Target.hasFeature(Feature));
}
-bool
-Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
- Requirement &Req, HeaderDirective &MissingHeader) const {
+bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
+ Requirement &Req,
+ UnresolvedHeaderDirective &MissingHeader) const {
if (IsAvailable)
return true;
@@ -293,9 +293,12 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS << "explicit ";
OS << "module " << Name;
- if (IsSystem) {
+ if (IsSystem || IsExternC) {
OS.indent(Indent + 2);
- OS << " [system]";
+ if (IsSystem)
+ OS << " [system]";
+ if (IsExternC)
+ OS << " [extern_c]";
}
OS << " {\n";
@@ -338,30 +341,31 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS << "\n";
}
- for (unsigned I = 0, N = NormalHeaders.size(); I != N; ++I) {
- OS.indent(Indent + 2);
- OS << "header \"";
- OS.write_escaped(NormalHeaders[I]->getName());
- OS << "\"\n";
- }
-
- for (unsigned I = 0, N = ExcludedHeaders.size(); I != N; ++I) {
- OS.indent(Indent + 2);
- OS << "exclude header \"";
- OS.write_escaped(ExcludedHeaders[I]->getName());
- OS << "\"\n";
+ struct {
+ StringRef Prefix;
+ HeaderKind Kind;
+ } Kinds[] = {{"", HK_Normal},
+ {"textual ", HK_Textual},
+ {"private ", HK_Private},
+ {"private textual ", HK_PrivateTextual},
+ {"exclude ", HK_Excluded}};
+
+ for (auto &K : Kinds) {
+ for (auto &H : Headers[K.Kind]) {
+ OS.indent(Indent + 2);
+ OS << K.Prefix << "header \"";
+ OS.write_escaped(H.NameAsWritten);
+ OS << "\"\n";
+ }
}
- for (unsigned I = 0, N = PrivateHeaders.size(); I != N; ++I) {
- OS.indent(Indent + 2);
- OS << "private header \"";
- OS.write_escaped(PrivateHeaders[I]->getName());
- OS << "\"\n";
- }
-
for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end();
MI != MIEnd; ++MI)
- if (!(*MI)->IsInferred)
+ // Print inferred subframework modules so that we don't need to re-infer
+ // them (requires expensive directory iteration + stat calls) when we build
+ // the module. Regular inferred submodules are OK, as we need to look at all
+ // those header files anyway.
+ if (!(*MI)->IsInferred || (*MI)->IsFramework)
(*MI)->print(OS, Indent + 2);
for (unsigned I = 0, N = Exports.size(); I != N; ++I) {
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 06f010f7ceb4..6e98d48c27d3 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -46,6 +46,10 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
}
OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) {
+ // 'flush' clause cannot be specified explicitly, because this is an implicit
+ // clause for 'flush' directive. If the 'flush' clause is explicitly specified
+ // the Parser should generate a warning about extra tokens at the end of the
+ // directive.
if (Str == "flush")
return OMPC_unknown;
return llvm::StringSwitch<OpenMPClauseKind>(Str)
@@ -108,6 +112,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_untied:
case OMPC_mergeable:
case OMPC_flush:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -167,6 +176,11 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_untied:
case OMPC_mergeable:
case OMPC_flush:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -207,6 +221,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
}
break;
+ case OMPD_for_simd:
+ switch (CKind) {
+#define OPENMP_FOR_SIMD_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
case OMPD_sections:
switch (CKind) {
#define OPENMP_SECTIONS_CLAUSE(Name) \
@@ -237,6 +261,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
}
break;
+ case OMPD_parallel_for_simd:
+ switch (CKind) {
+#define OPENMP_PARALLEL_FOR_SIMD_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
case OMPD_parallel_sections:
switch (CKind) {
#define OPENMP_PARALLEL_SECTIONS_CLAUSE(Name) \
@@ -260,6 +294,36 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
case OMPD_flush:
return CKind == OMPC_flush;
break;
+ case OMPD_atomic:
+ switch (CKind) {
+#define OPENMP_ATOMIC_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_target:
+ switch (CKind) {
+#define OPENMP_TARGET_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_teams:
+ switch (CKind) {
+#define OPENMP_TEAMS_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
case OMPD_unknown:
case OMPD_threadprivate:
case OMPD_section:
@@ -268,29 +332,39 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
+ case OMPD_ordered:
break;
}
return false;
}
bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) {
- return DKind == OMPD_simd || DKind == OMPD_for ||
- DKind == OMPD_parallel_for; // TODO add next directives.
+ return DKind == OMPD_simd || DKind == OMPD_for || DKind == OMPD_for_simd ||
+ DKind == OMPD_parallel_for ||
+ DKind == OMPD_parallel_for_simd; // TODO add next directives.
}
bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) {
- return DKind == OMPD_for || DKind == OMPD_sections || DKind == OMPD_section ||
+ return DKind == OMPD_for || DKind == OMPD_for_simd ||
+ DKind == OMPD_sections || DKind == OMPD_section ||
DKind == OMPD_single || DKind == OMPD_parallel_for ||
+ DKind == OMPD_parallel_for_simd ||
DKind == OMPD_parallel_sections; // TODO add next directives.
}
bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_parallel || DKind == OMPD_parallel_for ||
+ DKind == OMPD_parallel_for_simd ||
DKind == OMPD_parallel_sections; // TODO add next directives.
}
+bool clang::isOpenMPTeamsDirective(OpenMPDirectiveKind DKind) {
+ return DKind == OMPD_teams; // TODO add next directives.
+}
+
bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) {
- return DKind == OMPD_simd; // TODO || DKind == OMPD_for_simd || ...
+ return DKind == OMPD_simd || DKind == OMPD_for_simd ||
+ DKind == OMPD_parallel_for_simd; // TODO add next directives.
}
bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) {
diff --git a/lib/Basic/SanitizerBlacklist.cpp b/lib/Basic/SanitizerBlacklist.cpp
new file mode 100644
index 000000000000..ea5b8d0da845
--- /dev/null
+++ b/lib/Basic/SanitizerBlacklist.cpp
@@ -0,0 +1,46 @@
+//===--- SanitizerBlacklist.cpp - Blacklist for sanitizers ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided blacklist used to disable/alter instrumentation done in
+// sanitizers.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/SanitizerBlacklist.h"
+
+using namespace clang;
+
+SanitizerBlacklist::SanitizerBlacklist(StringRef BlacklistPath,
+ SourceManager &SM)
+ : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPath)), SM(SM) {}
+
+bool SanitizerBlacklist::isBlacklistedGlobal(StringRef GlobalName,
+ StringRef Category) const {
+ return SCL->inSection("global", GlobalName, Category);
+}
+
+bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName,
+ StringRef Category) const {
+ return SCL->inSection("type", MangledTypeName, Category);
+}
+
+bool SanitizerBlacklist::isBlacklistedFunction(StringRef FunctionName) const {
+ return SCL->inSection("fun", FunctionName);
+}
+
+bool SanitizerBlacklist::isBlacklistedFile(StringRef FileName,
+ StringRef Category) const {
+ return SCL->inSection("src", FileName, Category);
+}
+
+bool SanitizerBlacklist::isBlacklistedLocation(SourceLocation Loc,
+ StringRef Category) const {
+ return !Loc.isInvalid() &&
+ isBlacklistedFile(SM.getFilename(SM.getFileLoc(Loc)), Category);
+}
+
diff --git a/lib/Basic/Sanitizers.cpp b/lib/Basic/Sanitizers.cpp
new file mode 100644
index 000000000000..e9aaa366e32b
--- /dev/null
+++ b/lib/Basic/Sanitizers.cpp
@@ -0,0 +1,35 @@
+//===--- Sanitizers.cpp - C Language Family Language Options ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the classes from Sanitizers.h
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/Sanitizers.h"
+
+using namespace clang;
+
+SanitizerSet::SanitizerSet() : Kinds(0) {}
+
+bool SanitizerSet::has(SanitizerKind K) const {
+ unsigned Bit = static_cast<unsigned>(K);
+ return Kinds & (1 << Bit);
+}
+
+void SanitizerSet::set(SanitizerKind K, bool Value) {
+ unsigned Bit = static_cast<unsigned>(K);
+ Kinds = Value ? (Kinds | (1 << Bit)) : (Kinds & ~(1 << Bit));
+}
+
+void SanitizerSet::clear() {
+ Kinds = 0;
+}
+
+bool SanitizerSet::empty() const {
+ return Kinds == 0;
+}
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index 0c06a48c123a..6b885a7bc806 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -132,13 +132,9 @@ const char *FullSourceLoc::getCharacterData(bool *Invalid) const {
return SrcMgr->getCharacterData(*this, Invalid);
}
-const llvm::MemoryBuffer* FullSourceLoc::getBuffer(bool *Invalid) const {
- assert(isValid());
- return SrcMgr->getBuffer(SrcMgr->getFileID(*this), Invalid);
-}
-
StringRef FullSourceLoc::getBufferData(bool *Invalid) const {
- return getBuffer(Invalid)->getBuffer();
+ assert(isValid());
+ return SrcMgr->getBuffer(SrcMgr->getFileID(*this), Invalid)->getBuffer();;
}
std::pair<FileID, unsigned> FullSourceLoc::getDecomposedLoc() const {
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 61dfe35e2257..305dcd43960c 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -94,11 +94,9 @@ llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
return Buffer.getPointer();
}
- std::string ErrorStr;
bool isVolatile = SM.userFilesAreVolatile() && !IsSystemFile;
- Buffer.setPointer(SM.getFileManager().getBufferForFile(ContentsEntry,
- &ErrorStr,
- isVolatile));
+ auto BufferOrError =
+ SM.getFileManager().getBufferForFile(ContentsEntry, isVolatile);
// If we were unable to open the file, then we are in an inconsistent
// situation where the content cache referenced a file which no longer
@@ -110,27 +108,30 @@ llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
// currently handle returning a null entry here. Ideally we should detect
// that we are in an inconsistent situation and error out as quickly as
// possible.
- if (!Buffer.getPointer()) {
- const StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
- Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(),
- "<invalid>"));
+ if (!BufferOrError) {
+ StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
+ Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(),
+ "<invalid>").release());
char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i)
Ptr[i] = FillStr[i % FillStr.size()];
if (Diag.isDiagnosticInFlight())
- Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
- ContentsEntry->getName(), ErrorStr);
- else
+ Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
+ ContentsEntry->getName(),
+ BufferOrError.getError().message());
+ else
Diag.Report(Loc, diag::err_cannot_open_file)
- << ContentsEntry->getName() << ErrorStr;
+ << ContentsEntry->getName() << BufferOrError.getError().message();
Buffer.setInt(Buffer.getInt() | InvalidFlag);
if (Invalid) *Invalid = true;
return Buffer.getPointer();
}
-
+
+ Buffer.setPointer(BufferOrError->release());
+
// Check that the file's size is the same as in the file entry (which may
// have come from a stat cache).
if (getRawBuffer()->getBufferSize() != (size_t)ContentsEntry->getSize()) {
@@ -176,17 +177,11 @@ llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
}
unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) {
- // Look up the filename in the string table, returning the pre-existing value
- // if it exists.
- llvm::StringMapEntry<unsigned> &Entry =
- FilenameIDs.GetOrCreateValue(Name, ~0U);
- if (Entry.getValue() != ~0U)
- return Entry.getValue();
-
- // Otherwise, assign this the next available ID.
- Entry.setValue(FilenamesByID.size());
- FilenamesByID.push_back(&Entry);
- return FilenamesByID.size()-1;
+ auto IterBool =
+ FilenameIDs.insert(std::make_pair(Name, FilenamesByID.size()));
+ if (IterBool.second)
+ FilenamesByID.push_back(&*IterBool.first);
+ return IterBool.first->second;
}
/// AddLineNote - Add a line note to the line table that indicates that there
@@ -373,8 +368,7 @@ SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr,
: Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
UserFilesAreVolatile(UserFilesAreVolatile),
ExternalSLocEntries(nullptr), LineTable(nullptr), NumLinearScans(0),
- NumBinaryProbes(0), FakeBufferForRecovery(nullptr),
- FakeContentCacheForRecovery(nullptr) {
+ NumBinaryProbes(0) {
clearIDTables();
Diag.setSourceManager(this);
}
@@ -398,9 +392,6 @@ SourceManager::~SourceManager() {
ContentCacheAlloc.Deallocate(I->second);
}
}
-
- delete FakeBufferForRecovery;
- delete FakeContentCacheForRecovery;
llvm::DeleteContainerSeconds(MacroArgsCacheMap);
}
@@ -460,13 +451,13 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt,
/// createMemBufferContentCache - Create a new ContentCache for the specified
/// memory buffer. This does no caching.
-const ContentCache *
-SourceManager::createMemBufferContentCache(llvm::MemoryBuffer *Buffer) {
+const ContentCache *SourceManager::createMemBufferContentCache(
+ std::unique_ptr<llvm::MemoryBuffer> Buffer) {
// Add a new ContentCache to the MemBufferInfos list and return it.
ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>();
new (Entry) ContentCache();
MemBufferInfos.push_back(Entry);
- Entry->setBuffer(Buffer);
+ Entry->setBuffer(std::move(Buffer));
return Entry;
}
@@ -505,10 +496,10 @@ SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries,
/// fake, non-empty buffer.
llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
if (!FakeBufferForRecovery)
- FakeBufferForRecovery
- = llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>");
-
- return FakeBufferForRecovery;
+ FakeBufferForRecovery =
+ llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>");
+
+ return FakeBufferForRecovery.get();
}
/// \brief As part of recovering from missing or changed content, produce a
@@ -516,11 +507,11 @@ llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
const SrcMgr::ContentCache *
SourceManager::getFakeContentCacheForRecovery() const {
if (!FakeContentCacheForRecovery) {
- FakeContentCacheForRecovery = new ContentCache();
+ FakeContentCacheForRecovery = llvm::make_unique<SrcMgr::ContentCache>();
FakeContentCacheForRecovery->replaceBuffer(getFakeBufferForRecovery(),
/*DoNotFree=*/true);
}
- return FakeContentCacheForRecovery;
+ return FakeContentCacheForRecovery.get();
}
/// \brief Returns the previous in-order FileID or an invalid FileID if there
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index aecf13b00854..6987cd71f3d7 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -338,6 +338,8 @@ bool TargetInfo::isValidGCCRegisterName(StringRef Name) const {
// Get rid of any register prefix.
Name = removeGCCRegisterPrefix(Name);
+ if (Name.empty())
+ return false;
getGCCRegNames(Names, NumNames);
@@ -457,7 +459,9 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
// Eventually, an unknown constraint should just be treated as 'g'.
return false;
}
+ break;
case '&': // early clobber.
+ Info.setEarlyClobber();
break;
case '%': // commutative.
// FIXME: Check that there is a another register after this one.
@@ -482,9 +486,12 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
if (Name[1] == '=' || Name[1] == '+')
Name++;
break;
+ case '#': // Ignore as constraint.
+ while (Name[1] && Name[1] != ',')
+ Name++;
+ break;
case '?': // Disparage slightly code.
case '!': // Disparage severely.
- case '#': // Ignore as constraint.
case '*': // Ignore for choosing register preferences.
break; // Pass them.
}
@@ -492,6 +499,11 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
Name++;
}
+ // Early clobber with a read-write constraint which doesn't permit registers
+ // is invalid.
+ if (Info.earlyClobber() && Info.isReadWrite() && !Info.allowsRegister())
+ return false;
+
// If a constraint allows neither memory nor register operands it contains
// only modifiers. Reject it.
return Info.allowsMemory() || Info.allowsRegister();
@@ -534,11 +546,17 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
default:
// Check if we have a matching constraint
if (*Name >= '0' && *Name <= '9') {
- unsigned i = *Name - '0';
+ const char *DigitStart = Name;
+ while (Name[1] >= '0' && Name[1] <= '9')
+ Name++;
+ const char *DigitEnd = Name;
+ unsigned i;
+ if (StringRef(DigitStart, DigitEnd - DigitStart + 1)
+ .getAsInteger(10, i))
+ return false;
// Check if matching constraint is out of bounds.
- if (i >= NumOutputs)
- return false;
+ if (i >= NumOutputs) return false;
// A number must refer to an output only operand.
if (OutputConstraints[i].isReadWrite())
@@ -569,6 +587,10 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
if (Info.hasTiedOperand() && Info.getTiedOperand() != Index)
return false;
+ // A number must refer to an output only operand.
+ if (OutputConstraints[Index].isReadWrite())
+ return false;
+
Info.setTiedOperand(Index, OutputConstraints[Index]);
break;
}
@@ -586,6 +608,8 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
case 'N':
case 'O':
case 'P':
+ if (!validateAsmConstraint(Name, Info))
+ return false;
break;
case 'r': // general register.
Info.setAllowsRegister();
@@ -608,9 +632,12 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
break;
case ',': // multiple alternative constraint. Ignore comma.
break;
+ case '#': // Ignore as constraint.
+ while (Name[1] && Name[1] != ',')
+ Name++;
+ break;
case '?': // Disparage slightly code.
case '!': // Disparage severely.
- case '#': // Ignore as constraint.
case '*': // Ignore for choosing register preferences.
break; // Pass them.
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 075f905cc359..4c64a02b5b8a 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -21,6 +21,7 @@
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
@@ -93,7 +94,8 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Builder.defineMacro("OBJC_NEW_PROPERTIES");
// AddressSanitizer doesn't play well with source fortification, which is on
// by default on Darwin.
- if (Opts.Sanitize.Address) Builder.defineMacro("_FORTIFY_SOURCE", "0");
+ if (Opts.Sanitize.has(SanitizerKind::Address))
+ Builder.defineMacro("_FORTIFY_SOURCE", "0");
if (!Opts.ObjCAutoRefCount) {
// __weak is always defined, for use in blocks and with objc pointers.
@@ -271,6 +273,12 @@ protected:
// On FreeBSD, wchar_t contains the number of the code point as
// used by the character set of the locale. These character sets are
// not necessarily a superset of ASCII.
+ //
+ // FIXME: This is wrong; the macro refers to the numerical values
+ // of wchar_t *literals*, which are not locale-dependent. However,
+ // FreeBSD systems apparently depend on us getting this wrong, and
+ // setting this to 1 is conforming even if all the basic source
+ // character literals have the same encoding as char and wchar_t.
Builder.defineMacro("__STDC_MB_MIGHT_NEQ_WC__", "1");
}
public:
@@ -315,7 +323,8 @@ protected:
Builder.defineMacro("_GNU_SOURCE");
}
public:
- KFreeBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
+ KFreeBSDTargetInfo(const llvm::Triple &Triple)
+ : OSTargetInfo<Target>(Triple) {
this->UserLabelPrefix = "";
}
};
@@ -516,27 +525,6 @@ public:
}
};
-// AuroraUX target
-template<typename Target>
-class AuroraUXTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- DefineStd(Builder, "sun", Opts);
- DefineStd(Builder, "unix", Opts);
- Builder.defineMacro("__ELF__");
- Builder.defineMacro("__svr4__");
- Builder.defineMacro("__SVR4");
- }
-public:
- AuroraUXTargetInfo(const llvm::Triple &Triple)
- : OSTargetInfo<Target>(Triple) {
- this->UserLabelPrefix = "";
- this->WCharType = this->SignedLong;
- // FIXME: WIntType should be SignedLong
- }
-};
-
// Solaris target
template<typename Target>
class SolarisTargetInfo : public OSTargetInfo<Target> {
@@ -551,8 +539,8 @@ protected:
// Solaris headers require _XOPEN_SOURCE to be set to 600 for C99 and
// newer, but to 500 for everything else. feature_test.h has a check to
// ensure that you are not using C99 with an old version of X/Open or C89
- // with a new version.
- if (Opts.C99 || Opts.C11)
+ // with a new version.
+ if (Opts.C99)
Builder.defineMacro("_XOPEN_SOURCE", "600");
else
Builder.defineMacro("_XOPEN_SOURCE", "500");
@@ -658,7 +646,8 @@ public:
// RegParmMax is inherited from the underlying architecture
this->LongDoubleFormat = &llvm::APFloat::IEEEdouble;
if (Triple.getArch() == llvm::Triple::arm) {
- this->DescriptionString = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S128";
+ this->DescriptionString =
+ "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128";
} else if (Triple.getArch() == llvm::Triple::x86) {
this->DescriptionString = "e-m:e-p:32:32-i64:64-n8:16:32-S128";
} else if (Triple.getArch() == llvm::Triple::x86_64) {
@@ -692,10 +681,14 @@ class PPCTargetInfo : public TargetInfo {
// Target cpu features.
bool HasVSX;
+ bool HasP8Vector;
+
+protected:
+ std::string ABI;
public:
PPCTargetInfo(const llvm::Triple &Triple)
- : TargetInfo(Triple), HasVSX(false) {
+ : TargetInfo(Triple), HasVSX(false), HasP8Vector(false) {
BigEndian = (Triple.getArch() != llvm::Triple::ppc64le);
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble;
@@ -781,6 +774,9 @@ public:
return CPUKnown;
}
+
+ StringRef getABI() const override { return ABI; }
+
void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const override {
Records = BuiltinInfo;
@@ -932,11 +928,10 @@ const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
#include "clang/Basic/BuiltinsPPC.def"
};
- /// handleTargetFeatures - Perform initialization based on the user
+/// handleTargetFeatures - Perform initialization based on the user
/// configured set of features.
bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
DiagnosticsEngine &Diags) {
- // Remember the maximum enabled sselevel.
for (unsigned i = 0, e = Features.size(); i !=e; ++i) {
// Ignore disabled features.
if (Features[i][0] == '-')
@@ -949,6 +944,11 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
continue;
}
+ if (Feature == "power8-vector") {
+ HasP8Vector = true;
+ continue;
+ }
+
// TODO: Finish this list and add an assert that we've handled them
// all.
}
@@ -976,13 +976,18 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
// Target properties.
if (getTriple().getArch() == llvm::Triple::ppc64le) {
Builder.defineMacro("_LITTLE_ENDIAN");
- Builder.defineMacro("_CALL_ELF","2");
} else {
if (getTriple().getOS() != llvm::Triple::NetBSD &&
getTriple().getOS() != llvm::Triple::OpenBSD)
Builder.defineMacro("_BIG_ENDIAN");
}
+ // ABI options.
+ if (ABI == "elfv1")
+ Builder.defineMacro("_CALL_ELF", "1");
+ if (ABI == "elfv2")
+ Builder.defineMacro("_CALL_ELF", "2");
+
// Subtarget options.
Builder.defineMacro("__NATURAL_ALIGNMENT__");
Builder.defineMacro("__REGISTER_PREFIX__", "");
@@ -1094,6 +1099,8 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasVSX)
Builder.defineMacro("__VSX__");
+ if (HasP8Vector)
+ Builder.defineMacro("__POWER8_VECTOR__");
// FIXME: The following are not yet generated here by Clang, but are
// generated by GCC:
@@ -1132,13 +1139,19 @@ void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
.Default(false);
Features["qpx"] = (CPU == "a2q");
+
+ if (!ABI.empty())
+ Features[ABI] = true;
}
bool PPCTargetInfo::hasFeature(StringRef Feature) const {
- return Feature == "powerpc";
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("powerpc", true)
+ .Case("vsx", HasVSX)
+ .Case("power8-vector", HasP8Vector)
+ .Default(false);
}
-
const char * const PPCTargetInfo::GCCRegNames[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
@@ -1287,17 +1300,26 @@ public:
IntMaxType = SignedLong;
Int64Type = SignedLong;
- if (getTriple().getOS() == llvm::Triple::FreeBSD) {
+ if ((Triple.getArch() == llvm::Triple::ppc64le)) {
+ DescriptionString = "e-m:e-i64:64-n32:64";
+ ABI = "elfv2";
+ } else {
+ DescriptionString = "E-m:e-i64:64-n32:64";
+ ABI = "elfv1";
+ }
+
+ switch (getTriple().getOS()) {
+ case llvm::Triple::FreeBSD:
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
- DescriptionString = "E-m:e-i64:64-n32:64";
- } else {
- if ((Triple.getArch() == llvm::Triple::ppc64le)) {
- DescriptionString = "e-m:e-i64:64-n32:64";
- } else {
- DescriptionString = "E-m:e-i64:64-n32:64";
- }
-}
+ break;
+ case llvm::Triple::NetBSD:
+ IntMaxType = SignedLongLong;
+ Int64Type = SignedLongLong;
+ break;
+ default:
+ break;
+ }
// PPC64 supports atomics up to 8 bytes.
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
@@ -1305,6 +1327,14 @@ public:
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::CharPtrBuiltinVaList;
}
+ // PPC64 Linux-specifc ABI options.
+ bool setABI(const std::string &Name) override {
+ if (Name == "elfv1" || Name == "elfv2") {
+ ABI = Name;
+ return true;
+ }
+ return false;
+ }
};
} // end anonymous namespace.
@@ -1317,7 +1347,7 @@ public:
: DarwinTargetInfo<PPC32TargetInfo>(Triple) {
HasAlignMac68kSupport = true;
BoolWidth = BoolAlign = 32; //XXX support -mone-byte-bool?
- PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726
+ PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726
LongLongAlign = 32;
SuitableAlign = 128;
DescriptionString = "E-m:o-p:32:32-f64:32:64-n32";
@@ -1344,6 +1374,8 @@ namespace {
1, // opencl_global
3, // opencl_local
4, // opencl_constant
+ // FIXME: generic has to be added to the target
+ 0, // opencl_generic
1, // cuda_device
4, // cuda_constant
3, // cuda_shared
@@ -1351,6 +1383,16 @@ namespace {
class NVPTXTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
static const Builtin::Info BuiltinInfo[];
+
+ // The GPU profiles supported by the NVPTX backend
+ enum GPUKind {
+ GK_NONE,
+ GK_SM20,
+ GK_SM21,
+ GK_SM30,
+ GK_SM35,
+ } GPU;
+
public:
NVPTXTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
BigEndian = false;
@@ -1361,11 +1403,34 @@ namespace {
// Define available target features
// These must be defined in sorted order!
NoAsmVariants = true;
+ // Set the default GPU to sm20
+ GPU = GK_SM20;
}
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
Builder.defineMacro("__PTX__");
Builder.defineMacro("__NVPTX__");
+ if (Opts.CUDAIsDevice) {
+ // Set __CUDA_ARCH__ for the GPU specified.
+ std::string CUDAArchCode;
+ switch (GPU) {
+ case GK_SM20:
+ CUDAArchCode = "200";
+ break;
+ case GK_SM21:
+ CUDAArchCode = "210";
+ break;
+ case GK_SM30:
+ CUDAArchCode = "300";
+ break;
+ case GK_SM35:
+ CUDAArchCode = "350";
+ break;
+ default:
+ llvm_unreachable("Unhandled target CPU");
+ }
+ Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode);
+ }
}
void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const override {
@@ -1384,8 +1449,9 @@ namespace {
Aliases = nullptr;
NumAliases = 0;
}
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
+ bool
+ validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
switch (*Name) {
default: return false;
case 'c':
@@ -1407,14 +1473,14 @@ namespace {
return TargetInfo::CharPtrBuiltinVaList;
}
bool setCPU(const std::string &Name) override {
- bool Valid = llvm::StringSwitch<bool>(Name)
- .Case("sm_20", true)
- .Case("sm_21", true)
- .Case("sm_30", true)
- .Case("sm_35", true)
- .Default(false);
+ GPU = llvm::StringSwitch<GPUKind>(Name)
+ .Case("sm_20", GK_SM20)
+ .Case("sm_21", GK_SM21)
+ .Case("sm_30", GK_SM30)
+ .Case("sm_35", GK_SM35)
+ .Default(GK_NONE);
- return Valid;
+ return GPU != GK_NONE;
}
};
@@ -1462,11 +1528,15 @@ static const unsigned R600AddrSpaceMap[] = {
1, // opencl_global
3, // opencl_local
2, // opencl_constant
+ 4, // opencl_generic
1, // cuda_device
2, // cuda_constant
3 // cuda_shared
};
+// If you edit the description strings, make sure you update
+// getPointerWidthV().
+
static const char *DescriptionStringR600 =
"e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128"
"-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64";
@@ -1506,6 +1576,20 @@ public:
UseAddrSpaceMapMangling = true;
}
+ uint64_t getPointerWidthV(unsigned AddrSpace) const override {
+ if (GPU <= GK_CAYMAN)
+ return 32;
+
+ switch(AddrSpace) {
+ default:
+ return 64;
+ case 0:
+ case 3:
+ case 5:
+ return 32;
+ }
+ }
+
const char * getClobbers() const override {
return "";
}
@@ -1573,6 +1657,7 @@ public:
.Case("pitcairn", GK_SOUTHERN_ISLANDS)
.Case("verde", GK_SOUTHERN_ISLANDS)
.Case("oland", GK_SOUTHERN_ISLANDS)
+ .Case("hainan", GK_SOUTHERN_ISLANDS)
.Case("bonaire", GK_SEA_ISLANDS)
.Case("kabini", GK_SEA_ISLANDS)
.Case("kaveri", GK_SEA_ISLANDS)
@@ -1669,16 +1754,19 @@ class X86TargetInfo : public TargetInfo {
bool HasPCLMUL;
bool HasLZCNT;
bool HasRDRND;
+ bool HasFSGSBASE;
bool HasBMI;
bool HasBMI2;
bool HasPOPCNT;
bool HasRTM;
bool HasPRFCHW;
bool HasRDSEED;
+ bool HasADX;
bool HasTBM;
bool HasFMA;
bool HasF16C;
- bool HasAVX512CD, HasAVX512ER, HasAVX512PF;
+ bool HasAVX512CD, HasAVX512ER, HasAVX512PF, HasAVX512DQ, HasAVX512BW,
+ HasAVX512VL;
bool HasSHA;
bool HasCX16;
@@ -1753,18 +1841,37 @@ class X86TargetInfo : public TargetInfo {
/// \name Atom
/// Atom processors
//@{
- CK_Atom,
+ CK_Bonnell,
CK_Silvermont,
//@}
/// \name Nehalem
/// Nehalem microarchitecture based processors.
- //@{
- CK_Corei7,
- CK_Corei7AVX,
- CK_CoreAVXi,
- CK_CoreAVX2,
- //@}
+ CK_Nehalem,
+
+ /// \name Westmere
+ /// Westmere microarchitecture based processors.
+ CK_Westmere,
+
+ /// \name Sandy Bridge
+ /// Sandy Bridge microarchitecture based processors.
+ CK_SandyBridge,
+
+ /// \name Ivy Bridge
+ /// Ivy Bridge microarchitecture based processors.
+ CK_IvyBridge,
+
+ /// \name Haswell
+ /// Haswell microarchitecture based processors.
+ CK_Haswell,
+
+ /// \name Broadwell
+ /// Broadwell microarchitecture based processors.
+ CK_Broadwell,
+
+ /// \name Skylake
+ /// Skylake microarchitecture based processors.
+ CK_Skylake,
/// \name Knights Landing
/// Knights Landing processor.
@@ -1820,6 +1927,7 @@ class X86TargetInfo : public TargetInfo {
/// This specification is deprecated and will be removed in the future.
/// Users should prefer \see CK_K8.
// FIXME: Warn on this when the CPU is set to it.
+ //@{
CK_x86_64,
//@}
@@ -1840,11 +1948,12 @@ public:
X86TargetInfo(const llvm::Triple &Triple)
: TargetInfo(Triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
XOPLevel(NoXOP), HasAES(false), HasPCLMUL(false), HasLZCNT(false),
- HasRDRND(false), HasBMI(false), HasBMI2(false), HasPOPCNT(false),
- HasRTM(false), HasPRFCHW(false), HasRDSEED(false), HasTBM(false),
- HasFMA(false), HasF16C(false), HasAVX512CD(false), HasAVX512ER(false),
- HasAVX512PF(false), HasSHA(false), HasCX16(false), CPU(CK_Generic),
- FPMath(FP_Default) {
+ HasRDRND(false), HasFSGSBASE(false), HasBMI(false), HasBMI2(false),
+ HasPOPCNT(false), HasRTM(false), HasPRFCHW(false), HasRDSEED(false),
+ HasADX(false), HasTBM(false), HasFMA(false), HasF16C(false),
+ HasAVX512CD(false), HasAVX512ER(false), HasAVX512PF(false),
+ HasAVX512DQ(false), HasAVX512BW(false), HasAVX512VL(false),
+ HasSHA(false), HasCX16(false), CPU(CK_Generic), FPMath(FP_Default) {
BigEndian = false;
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
@@ -1873,7 +1982,14 @@ public:
NumNames = llvm::array_lengthof(AddlRegNames);
}
bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override;
+ TargetInfo::ConstraintInfo &info) const override;
+
+ bool validateOutputSize(StringRef Constraint, unsigned Size) const override;
+
+ bool validateInputSize(StringRef Constraint, unsigned Size) const override;
+
+ virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const;
+
std::string convertConstraint(const char *&Constraint) const override;
const char *getClobbers() const override {
return "~{dirflag},~{fpsr},~{flags}";
@@ -1930,12 +2046,22 @@ public:
.Case("nocona", CK_Nocona)
.Case("core2", CK_Core2)
.Case("penryn", CK_Penryn)
- .Case("atom", CK_Atom)
- .Case("slm", CK_Silvermont)
- .Case("corei7", CK_Corei7)
- .Case("corei7-avx", CK_Corei7AVX)
- .Case("core-avx-i", CK_CoreAVXi)
- .Case("core-avx2", CK_CoreAVX2)
+ .Case("bonnell", CK_Bonnell)
+ .Case("atom", CK_Bonnell) // Legacy name.
+ .Case("silvermont", CK_Silvermont)
+ .Case("slm", CK_Silvermont) // Legacy name.
+ .Case("nehalem", CK_Nehalem)
+ .Case("corei7", CK_Nehalem) // Legacy name.
+ .Case("westmere", CK_Westmere)
+ .Case("sandybridge", CK_SandyBridge)
+ .Case("corei7-avx", CK_SandyBridge) // Legacy name.
+ .Case("ivybridge", CK_IvyBridge)
+ .Case("core-avx-i", CK_IvyBridge) // Legacy name.
+ .Case("haswell", CK_Haswell)
+ .Case("core-avx2", CK_Haswell) // Legacy name.
+ .Case("broadwell", CK_Broadwell)
+ .Case("skylake", CK_Skylake)
+ .Case("skx", CK_Skylake) // Legacy name.
.Case("knl", CK_KNL)
.Case("k6", CK_K6)
.Case("k6-2", CK_K6_2)
@@ -1952,6 +2078,7 @@ public:
.Case("k8-sse3", CK_K8SSE3)
.Case("opteron", CK_Opteron)
.Case("opteron-sse3", CK_OpteronSSE3)
+ .Case("barcelona", CK_AMDFAM10)
.Case("amdfam10", CK_AMDFAM10)
.Case("btver1", CK_BTVER1)
.Case("btver2", CK_BTVER2)
@@ -2008,12 +2135,15 @@ public:
case CK_Nocona:
case CK_Core2:
case CK_Penryn:
- case CK_Atom:
+ case CK_Bonnell:
case CK_Silvermont:
- case CK_Corei7:
- case CK_Corei7AVX:
- case CK_CoreAVXi:
- case CK_CoreAVX2:
+ case CK_Nehalem:
+ case CK_Westmere:
+ case CK_SandyBridge:
+ case CK_IvyBridge:
+ case CK_Haswell:
+ case CK_Broadwell:
+ case CK_Skylake:
case CK_KNL:
case CK_Athlon64:
case CK_Athlon64SSE3:
@@ -2041,8 +2171,9 @@ public:
// We accept all non-ARM calling conventions
return (CC == CC_X86ThisCall ||
CC == CC_X86FastCall ||
- CC == CC_X86StdCall ||
- CC == CC_C ||
+ CC == CC_X86StdCall ||
+ CC == CC_X86VectorCall ||
+ CC == CC_C ||
CC == CC_X86Pascal ||
CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
}
@@ -2082,10 +2213,13 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
break;
case CK_PentiumMMX:
case CK_Pentium2:
+ case CK_K6:
+ case CK_WinChipC6:
setFeatureEnabledImpl(Features, "mmx", true);
break;
case CK_Pentium3:
case CK_Pentium3M:
+ case CK_C3_2:
setFeatureEnabledImpl(Features, "sse", true);
break;
case CK_PentiumM:
@@ -2101,6 +2235,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_Core2:
+ case CK_Bonnell:
setFeatureEnabledImpl(Features, "ssse3", true);
setFeatureEnabledImpl(Features, "cx16", true);
break;
@@ -2108,44 +2243,40 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabledImpl(Features, "sse4.1", true);
setFeatureEnabledImpl(Features, "cx16", true);
break;
- case CK_Atom:
- setFeatureEnabledImpl(Features, "ssse3", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- break;
- case CK_Silvermont:
- setFeatureEnabledImpl(Features, "sse4.2", true);
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
- break;
- case CK_Corei7:
- setFeatureEnabledImpl(Features, "sse4.2", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- break;
- case CK_Corei7AVX:
- setFeatureEnabledImpl(Features, "avx", true);
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
- break;
- case CK_CoreAVXi:
- setFeatureEnabledImpl(Features, "avx", true);
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
- setFeatureEnabledImpl(Features, "rdrnd", true);
- setFeatureEnabledImpl(Features, "f16c", true);
- break;
- case CK_CoreAVX2:
+ case CK_Skylake:
+ setFeatureEnabledImpl(Features, "avx512f", true);
+ setFeatureEnabledImpl(Features, "avx512cd", true);
+ setFeatureEnabledImpl(Features, "avx512dq", true);
+ setFeatureEnabledImpl(Features, "avx512bw", true);
+ setFeatureEnabledImpl(Features, "avx512vl", true);
+ // FALLTHROUGH
+ case CK_Broadwell:
+ setFeatureEnabledImpl(Features, "rdseed", true);
+ setFeatureEnabledImpl(Features, "adx", true);
+ // FALLTHROUGH
+ case CK_Haswell:
setFeatureEnabledImpl(Features, "avx2", true);
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
setFeatureEnabledImpl(Features, "lzcnt", true);
- setFeatureEnabledImpl(Features, "rdrnd", true);
- setFeatureEnabledImpl(Features, "f16c", true);
setFeatureEnabledImpl(Features, "bmi", true);
setFeatureEnabledImpl(Features, "bmi2", true);
setFeatureEnabledImpl(Features, "rtm", true);
setFeatureEnabledImpl(Features, "fma", true);
+ // FALLTHROUGH
+ case CK_IvyBridge:
+ setFeatureEnabledImpl(Features, "rdrnd", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "fsgsbase", true);
+ // FALLTHROUGH
+ case CK_SandyBridge:
+ setFeatureEnabledImpl(Features, "avx", true);
+ // FALLTHROUGH
+ case CK_Westmere:
+ case CK_Silvermont:
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ // FALLTHROUGH
+ case CK_Nehalem:
+ setFeatureEnabledImpl(Features, "sse4.2", true);
setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_KNL:
@@ -2153,19 +2284,19 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabledImpl(Features, "avx512cd", true);
setFeatureEnabledImpl(Features, "avx512er", true);
setFeatureEnabledImpl(Features, "avx512pf", true);
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "rdseed", true);
+ setFeatureEnabledImpl(Features, "adx", true);
setFeatureEnabledImpl(Features, "lzcnt", true);
- setFeatureEnabledImpl(Features, "rdrnd", true);
- setFeatureEnabledImpl(Features, "f16c", true);
setFeatureEnabledImpl(Features, "bmi", true);
setFeatureEnabledImpl(Features, "bmi2", true);
setFeatureEnabledImpl(Features, "rtm", true);
setFeatureEnabledImpl(Features, "fma", true);
- break;
- case CK_K6:
- case CK_WinChipC6:
- setFeatureEnabledImpl(Features, "mmx", true);
+ setFeatureEnabledImpl(Features, "rdrnd", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "fsgsbase", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_K6_2:
case CK_K6_3:
@@ -2191,43 +2322,29 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabledImpl(Features, "sse2", true);
setFeatureEnabledImpl(Features, "3dnowa", true);
break;
+ case CK_AMDFAM10:
+ setFeatureEnabledImpl(Features, "sse4a", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "popcnt", true);
+ // FALLTHROUGH
case CK_K8SSE3:
case CK_OpteronSSE3:
case CK_Athlon64SSE3:
setFeatureEnabledImpl(Features, "sse3", true);
setFeatureEnabledImpl(Features, "3dnowa", true);
break;
- case CK_AMDFAM10:
- setFeatureEnabledImpl(Features, "sse3", true);
- setFeatureEnabledImpl(Features, "sse4a", true);
- setFeatureEnabledImpl(Features, "3dnowa", true);
- setFeatureEnabledImpl(Features, "lzcnt", true);
- setFeatureEnabledImpl(Features, "popcnt", true);
- break;
- case CK_BTVER1:
- setFeatureEnabledImpl(Features, "ssse3", true);
- setFeatureEnabledImpl(Features, "sse4a", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- setFeatureEnabledImpl(Features, "lzcnt", true);
- setFeatureEnabledImpl(Features, "popcnt", true);
- setFeatureEnabledImpl(Features, "prfchw", true);
- break;
case CK_BTVER2:
setFeatureEnabledImpl(Features, "avx", true);
- setFeatureEnabledImpl(Features, "sse4a", true);
- setFeatureEnabledImpl(Features, "lzcnt", true);
setFeatureEnabledImpl(Features, "aes", true);
setFeatureEnabledImpl(Features, "pclmul", true);
- setFeatureEnabledImpl(Features, "prfchw", true);
setFeatureEnabledImpl(Features, "bmi", true);
setFeatureEnabledImpl(Features, "f16c", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- break;
- case CK_BDVER1:
- setFeatureEnabledImpl(Features, "xop", true);
+ // FALLTHROUGH
+ case CK_BTVER1:
+ setFeatureEnabledImpl(Features, "ssse3", true);
+ setFeatureEnabledImpl(Features, "sse4a", true);
setFeatureEnabledImpl(Features, "lzcnt", true);
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "popcnt", true);
setFeatureEnabledImpl(Features, "prfchw", true);
setFeatureEnabledImpl(Features, "cx16", true);
break;
@@ -2235,22 +2352,24 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabledImpl(Features, "avx2", true);
setFeatureEnabledImpl(Features, "bmi2", true);
// FALLTHROUGH
- case CK_BDVER2:
case CK_BDVER3:
+ setFeatureEnabledImpl(Features, "fsgsbase", true);
+ // FALLTHROUGH
+ case CK_BDVER2:
+ setFeatureEnabledImpl(Features, "bmi", true);
+ setFeatureEnabledImpl(Features, "fma", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "tbm", true);
+ // FALLTHROUGH
+ case CK_BDVER1:
+ // xop implies avx, sse4a and fma4.
setFeatureEnabledImpl(Features, "xop", true);
setFeatureEnabledImpl(Features, "lzcnt", true);
setFeatureEnabledImpl(Features, "aes", true);
setFeatureEnabledImpl(Features, "pclmul", true);
setFeatureEnabledImpl(Features, "prfchw", true);
- setFeatureEnabledImpl(Features, "bmi", true);
- setFeatureEnabledImpl(Features, "fma", true);
- setFeatureEnabledImpl(Features, "f16c", true);
- setFeatureEnabledImpl(Features, "tbm", true);
setFeatureEnabledImpl(Features, "cx16", true);
break;
- case CK_C3_2:
- setFeatureEnabledImpl(Features, "sse", true);
- break;
}
}
@@ -2305,7 +2424,8 @@ void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features,
Features["avx2"] = false;
case AVX512F:
Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] =
- Features["avx512pf"] = false;
+ Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] =
+ Features["avx512vl"] = false;
}
}
@@ -2404,7 +2524,8 @@ void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
setSSELevel(Features, AVX2, Enabled);
} else if (Name == "avx512f") {
setSSELevel(Features, AVX512F, Enabled);
- } else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf") {
+ } else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf"
+ || Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl") {
if (Enabled)
setSSELevel(Features, AVX512F, Enabled);
} else if (Name == "fma") {
@@ -2457,6 +2578,11 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
continue;
}
+ if (Feature == "fsgsbase") {
+ HasFSGSBASE = true;
+ continue;
+ }
+
if (Feature == "bmi") {
HasBMI = true;
continue;
@@ -2487,6 +2613,11 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
continue;
}
+ if (Feature == "adx") {
+ HasADX = true;
+ continue;
+ }
+
if (Feature == "tbm") {
HasTBM = true;
continue;
@@ -2517,6 +2648,21 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
continue;
}
+ if (Feature == "avx512dq") {
+ HasAVX512DQ = true;
+ continue;
+ }
+
+ if (Feature == "avx512bw") {
+ HasAVX512BW = true;
+ continue;
+ }
+
+ if (Feature == "avx512vl") {
+ HasAVX512VL = true;
+ continue;
+ }
+
if (Feature == "sha") {
HasSHA = true;
continue;
@@ -2606,6 +2752,10 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__amd64");
Builder.defineMacro("__x86_64");
Builder.defineMacro("__x86_64__");
+ if (getTriple().getArchName() == "x86_64h") {
+ Builder.defineMacro("__x86_64h");
+ Builder.defineMacro("__x86_64h__");
+ }
} else {
DefineStd(Builder, "i386", Opts);
}
@@ -2668,18 +2818,30 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_Penryn:
defineCPUMacros(Builder, "core2");
break;
- case CK_Atom:
+ case CK_Bonnell:
defineCPUMacros(Builder, "atom");
break;
case CK_Silvermont:
defineCPUMacros(Builder, "slm");
break;
- case CK_Corei7:
- case CK_Corei7AVX:
- case CK_CoreAVXi:
- case CK_CoreAVX2:
+ case CK_Nehalem:
+ case CK_Westmere:
+ case CK_SandyBridge:
+ case CK_IvyBridge:
+ case CK_Haswell:
+ case CK_Broadwell:
+ // FIXME: Historically, we defined this legacy name, it would be nice to
+ // remove it at some point. We've never exposed fine-grained names for
+ // recent primary x86 CPUs, and we should keep it that way.
defineCPUMacros(Builder, "corei7");
break;
+ case CK_Skylake:
+ // FIXME: Historically, we defined this legacy name, it would be nice to
+ // remove it at some point. This is the only fine-grained CPU macro in the
+ // main intel CPU line, and it would be better to not have these and force
+ // people to use ISA macros.
+ defineCPUMacros(Builder, "skx");
+ break;
case CK_KNL:
defineCPUMacros(Builder, "knl");
break;
@@ -2766,6 +2928,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasRDRND)
Builder.defineMacro("__RDRND__");
+ if (HasFSGSBASE)
+ Builder.defineMacro("__FSGSBASE__");
+
if (HasBMI)
Builder.defineMacro("__BMI__");
@@ -2784,6 +2949,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasRDSEED)
Builder.defineMacro("__RDSEED__");
+ if (HasADX)
+ Builder.defineMacro("__ADX__");
+
if (HasTBM)
Builder.defineMacro("__TBM__");
@@ -2810,6 +2978,12 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__AVX512ER__");
if (HasAVX512PF)
Builder.defineMacro("__AVX512PF__");
+ if (HasAVX512DQ)
+ Builder.defineMacro("__AVX512DQ__");
+ if (HasAVX512BW)
+ Builder.defineMacro("__AVX512BW__");
+ if (HasAVX512VL)
+ Builder.defineMacro("__AVX512VL__");
if (HasSHA)
Builder.defineMacro("__SHA__");
@@ -2893,23 +3067,26 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("avx512cd", HasAVX512CD)
.Case("avx512er", HasAVX512ER)
.Case("avx512pf", HasAVX512PF)
+ .Case("avx512dq", HasAVX512DQ)
+ .Case("avx512bw", HasAVX512BW)
+ .Case("avx512vl", HasAVX512VL)
.Case("bmi", HasBMI)
.Case("bmi2", HasBMI2)
.Case("cx16", HasCX16)
.Case("f16c", HasF16C)
.Case("fma", HasFMA)
.Case("fma4", XOPLevel >= FMA4)
- .Case("tbm", HasTBM)
+ .Case("fsgsbase", HasFSGSBASE)
.Case("lzcnt", HasLZCNT)
- .Case("rdrnd", HasRDRND)
.Case("mm3dnow", MMX3DNowLevel >= AMD3DNow)
.Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon)
.Case("mmx", MMX3DNowLevel >= MMX)
.Case("pclmul", HasPCLMUL)
.Case("popcnt", HasPOPCNT)
- .Case("rtm", HasRTM)
.Case("prfchw", HasPRFCHW)
+ .Case("rdrnd", HasRDRND)
.Case("rdseed", HasRDSEED)
+ .Case("rtm", HasRTM)
.Case("sha", HasSHA)
.Case("sse", SSELevel >= SSE1)
.Case("sse2", SSELevel >= SSE2)
@@ -2918,6 +3095,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("sse4.1", SSELevel >= SSE41)
.Case("sse4.2", SSELevel >= SSE42)
.Case("sse4a", XOPLevel >= SSE4A)
+ .Case("tbm", HasTBM)
.Case("x86", true)
.Case("x86_32", getTriple().getArch() == llvm::Triple::x86)
.Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64)
@@ -2930,6 +3108,28 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const {
switch (*Name) {
default: return false;
+ case 'I':
+ Info.setRequiresImmediate(0, 31);
+ return true;
+ case 'J':
+ Info.setRequiresImmediate(0, 63);
+ return true;
+ case 'K':
+ Info.setRequiresImmediate(-128, 127);
+ return true;
+ case 'L':
+ // FIXME: properly analyze this constraint:
+ // must be one of 0xff, 0xffff, or 0xffffffff
+ return true;
+ case 'M':
+ Info.setRequiresImmediate(0, 3);
+ return true;
+ case 'N':
+ Info.setRequiresImmediate(0, 255);
+ return true;
+ case 'O':
+ Info.setRequiresImmediate(0, 127);
+ return true;
case 'Y': // first letter of a pair:
switch (*(Name+1)) {
default: return false;
@@ -2974,6 +3174,39 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
}
}
+bool X86TargetInfo::validateOutputSize(StringRef Constraint,
+ unsigned Size) const {
+ // Strip off constraint modifiers.
+ while (Constraint[0] == '=' ||
+ Constraint[0] == '+' ||
+ Constraint[0] == '&')
+ Constraint = Constraint.substr(1);
+
+ return validateOperandSize(Constraint, Size);
+}
+
+bool X86TargetInfo::validateInputSize(StringRef Constraint,
+ unsigned Size) const {
+ return validateOperandSize(Constraint, Size);
+}
+
+bool X86TargetInfo::validateOperandSize(StringRef Constraint,
+ unsigned Size) const {
+ switch (Constraint[0]) {
+ default: break;
+ case 'y':
+ return Size <= 64;
+ case 'f':
+ case 't':
+ case 'u':
+ return Size <= 128;
+ case 'x':
+ // 256-bit ymm registers can be used if target supports AVX.
+ return Size <= (SSELevel >= AVX ? 256U : 128U);
+ }
+
+ return true;
+}
std::string
X86TargetInfo::convertConstraint(const char *&Constraint) const {
@@ -3030,18 +3263,25 @@ public:
if (RegNo == 1) return 2;
return -1;
}
- bool validateInputSize(StringRef Constraint,
- unsigned Size) const override {
+ bool validateOperandSize(StringRef Constraint,
+ unsigned Size) const override {
switch (Constraint[0]) {
default: break;
+ case 'R':
+ case 'q':
+ case 'Q':
case 'a':
case 'b':
case 'c':
case 'd':
+ case 'S':
+ case 'D':
return Size <= 32;
+ case 'A':
+ return Size <= 64;
}
- return true;
+ return X86TargetInfo::validateOperandSize(Constraint, Size);
}
};
} // end anonymous namespace
@@ -3304,9 +3544,10 @@ public:
Int64Type = IsX32 ? SignedLongLong : SignedLong;
RegParmMax = 6;
+ // Pointers are 32-bit in x32.
DescriptionString = (IsX32)
- ? "e-m:e-" "p:32:32-" "i64:64-f80:128-n8:16:32:64-S128"
- : "e-m:e-" "i64:64-f80:128-n8:16:32:64-S128";
+ ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128"
+ : "e-m:e-i64:64-f80:128-n8:16:32:64-S128";
// Use fpret only for long double.
RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
@@ -3330,6 +3571,7 @@ public:
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
return (CC == CC_C ||
+ CC == CC_X86VectorCall ||
CC == CC_IntelOclBicc ||
CC == CC_X86_64Win64) ? CCCR_OK : CCCR_Warning;
}
@@ -3338,6 +3580,8 @@ public:
return CC_C;
}
+ // for x32 we need it here explicitly
+ bool hasInt128Type() const override { return true; }
};
} // end anonymous namespace
@@ -3367,6 +3611,7 @@ public:
}
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
return (CC == CC_C ||
+ CC == CC_X86VectorCall ||
CC == CC_IntelOclBicc ||
CC == CC_X86_64SysV) ? CCCR_OK : CCCR_Warning;
}
@@ -3404,6 +3649,10 @@ public:
DefineStd(Builder, "WIN64", Opts);
Builder.defineMacro("__MINGW64__");
addMinGWDefines(Opts, Builder);
+
+ // GCC defines this macro when it is using __gxx_personality_seh0.
+ if (!Opts.SjLjExceptions)
+ Builder.defineMacro("__SEH__");
}
};
} // end anonymous namespace
@@ -3417,7 +3666,7 @@ public:
MaxVectorAlign = 256;
// The 64-bit iOS simulator uses the builtin bool type for Objective-C.
llvm::Triple T = llvm::Triple(Triple);
- if (T.getOS() == llvm::Triple::IOS)
+ if (T.isiOS())
UseSignedCharForObjCBool = false;
DescriptionString = "e-m:o-i64:64-f80:128-n8:16:32:64-S128";
}
@@ -3492,6 +3741,14 @@ class ARMTargetInfo : public TargetInfo {
unsigned CRC : 1;
unsigned Crypto : 1;
+ // ACLE 6.5.1 Hardware floating point
+ enum {
+ HW_FP_HP = (1 << 1), /// half (16-bit)
+ HW_FP_SP = (1 << 2), /// single (32-bit)
+ HW_FP_DP = (1 << 3), /// double (64-bit)
+ };
+ uint32_t HW_FP;
+
static const Builtin::Info BuiltinInfo[];
static bool shouldUseInlineAtomic(const llvm::Triple &T) {
@@ -3531,8 +3788,8 @@ class ARMTargetInfo : public TargetInfo {
DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
const llvm::Triple &T = getTriple();
- // size_t is unsigned long on Darwin and NetBSD.
- if (T.isOSDarwin() || T.getOS() == llvm::Triple::NetBSD)
+ // size_t is unsigned long on MachO-derived environments and NetBSD.
+ if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD)
SizeType = UnsignedLong;
else
SizeType = UnsignedInt;
@@ -3555,42 +3812,27 @@ class ARMTargetInfo : public TargetInfo {
ZeroLengthBitfieldBoundary = 0;
- if (IsThumb) {
- // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
- // so set preferred for small types to 32.
- if (T.isOSBinFormatMachO()) {
- DescriptionString = BigEndian ?
- "E-m:o-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
- "v128:64:128-a:0:32-n32-S64" :
- "e-m:o-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
- "v128:64:128-a:0:32-n32-S64";
- } else if (T.isOSWindows()) {
- // FIXME: this is invalid for WindowsCE
- assert(!BigEndian && "Windows on ARM does not support big endian");
- DescriptionString = "e"
- "-m:e"
- "-p:32:32"
- "-i1:8:32-i8:8:32-i16:16:32-i64:64"
- "-v128:64:128"
- "-a:0:32"
- "-n32"
- "-S64";
- } else {
- DescriptionString = BigEndian ?
- "E-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
- "v128:64:128-a:0:32-n32-S64" :
- "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
- "v128:64:128-a:0:32-n32-S64";
- }
+ // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
+ // so set preferred for small types to 32.
+ if (T.isOSBinFormatMachO()) {
+ DescriptionString =
+ BigEndian ? "E-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+ : "e-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64";
+ } else if (T.isOSWindows()) {
+ // FIXME: this is invalid for WindowsCE
+ assert(!BigEndian && "Windows on ARM does not support big endian");
+ DescriptionString = "e"
+ "-m:e"
+ "-p:32:32"
+ "-i64:64"
+ "-v128:64:128"
+ "-a:0:32"
+ "-n32"
+ "-S64";
} else {
- if (T.isOSBinFormatMachO())
- DescriptionString = BigEndian ?
- "E-m:o-p:32:32-i64:64-v128:64:128-n32-S64" :
- "e-m:o-p:32:32-i64:64-v128:64:128-n32-S64";
- else
- DescriptionString = BigEndian ?
- "E-m:e-p:32:32-i64:64-v128:64:128-n32-S64" :
- "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64";
+ DescriptionString =
+ BigEndian ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+ : "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64";
}
// FIXME: Enumerated types are variable width in straight AAPCS.
@@ -3621,31 +3863,16 @@ class ARMTargetInfo : public TargetInfo {
/// gcc.
ZeroLengthBitfieldBoundary = 32;
- if (IsThumb) {
- // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
- // so set preferred for small types to 32.
- if (T.isOSBinFormatMachO())
- DescriptionString = BigEndian ?
- "E-m:o-p:32:32-i1:8:32-i8:8:32-i16:16:32-f64:32:64"
- "-v64:32:64-v128:32:128-a:0:32-n32-S32" :
- "e-m:o-p:32:32-i1:8:32-i8:8:32-i16:16:32-f64:32:64"
- "-v64:32:64-v128:32:128-a:0:32-n32-S32";
- else
- DescriptionString = BigEndian ?
- "E-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-f64:32:64"
- "-v64:32:64-v128:32:128-a:0:32-n32-S32" :
- "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-f64:32:64"
- "-v64:32:64-v128:32:128-a:0:32-n32-S32";
- } else {
- if (T.isOSBinFormatMachO())
- DescriptionString = BigEndian ?
- "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" :
- "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32";
- else
- DescriptionString = BigEndian ?
- "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" :
- "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32";
- }
+ if (T.isOSBinFormatMachO())
+ DescriptionString =
+ BigEndian
+ ? "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
+ : "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32";
+ else
+ DescriptionString =
+ BigEndian
+ ? "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
+ : "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32";
// FIXME: Override "preferred align" for double and long long.
}
@@ -3653,7 +3880,7 @@ class ARMTargetInfo : public TargetInfo {
public:
ARMTargetInfo(const llvm::Triple &Triple, bool IsBigEndian)
: TargetInfo(Triple), CPU("arm1136j-s"), FPMath(FP_Default),
- IsAAPCS(true) {
+ IsAAPCS(true), HW_FP(0) {
BigEndian = IsBigEndian;
switch (getTriple().getOS()) {
@@ -3672,7 +3899,45 @@ public:
// FIXME: Should we just treat this as a feature?
IsThumb = getTriple().getArchName().startswith("thumb");
- setABI("aapcs-linux");
+ // FIXME: This duplicates code from the driver that sets the -target-abi
+ // option - this code is used if -target-abi isn't passed and should
+ // be unified in some way.
+ if (Triple.isOSBinFormatMachO()) {
+ // The backend is hardwired to assume AAPCS for M-class processors, ensure
+ // the frontend matches that.
+ if (Triple.getEnvironment() == llvm::Triple::EABI ||
+ Triple.getOS() == llvm::Triple::UnknownOS ||
+ StringRef(CPU).startswith("cortex-m")) {
+ setABI("aapcs");
+ } else {
+ setABI("apcs-gnu");
+ }
+ } else if (Triple.isOSWindows()) {
+ // FIXME: this is invalid for WindowsCE
+ setABI("aapcs");
+ } else {
+ // Select the default based on the platform.
+ switch (Triple.getEnvironment()) {
+ case llvm::Triple::Android:
+ case llvm::Triple::GNUEABI:
+ case llvm::Triple::GNUEABIHF:
+ setABI("aapcs-linux");
+ break;
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::EABI:
+ setABI("aapcs");
+ break;
+ case llvm::Triple::GNU:
+ setABI("apcs-gnu");
+ break;
+ default:
+ if (Triple.getOS() == llvm::Triple::NetBSD)
+ setABI("apcs-gnu");
+ else
+ setABI("aapcs");
+ break;
+ }
+ }
// ARM targets default to using the ARM C++ ABI.
TheCXXABI.set(TargetCXXABI::GenericARM);
@@ -3683,8 +3948,8 @@ public:
MaxAtomicInlineWidth = 64;
// Do force alignment of members that follow zero length bitfields. If
- // 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
+ // 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.
UseZeroLengthBitfieldAlignment = true;
}
@@ -3708,16 +3973,10 @@ public:
}
void getDefaultFeatures(llvm::StringMap<bool> &Features) const override {
- if (IsAAPCS)
- Features["aapcs"] = true;
- else
- Features["apcs"] = true;
-
StringRef ArchName = getTriple().getArchName();
if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore")
Features["vfp2"] = true;
- else if (CPU == "cortex-a8" || CPU == "cortex-a9" ||
- CPU == "cortex-a9-mp") {
+ else if (CPU == "cortex-a8" || CPU == "cortex-a9") {
Features["vfp3"] = true;
Features["neon"] = true;
}
@@ -3726,7 +3985,7 @@ public:
Features["neon"] = true;
} else if (CPU == "swift" || CPU == "cortex-a7" ||
CPU == "cortex-a12" || CPU == "cortex-a15" ||
- CPU == "krait") {
+ CPU == "cortex-a17" || CPU == "krait") {
Features["vfp4"] = true;
Features["neon"] = true;
Features["hwdiv"] = true;
@@ -3752,7 +4011,7 @@ public:
ArchName == "thumbebv8a" || ArchName == "thumbebv8") {
Features["hwdiv"] = true;
Features["hwdiv-arm"] = true;
- } else if (CPU == "cortex-m3" || CPU == "cortex-m4") {
+ } else if (CPU == "cortex-m3" || CPU == "cortex-m4" || CPU == "cortex-m7") {
Features["hwdiv"] = true;
}
}
@@ -3764,29 +4023,38 @@ public:
Crypto = 0;
SoftFloat = SoftFloatABI = false;
HWDiv = 0;
- for (unsigned i = 0, e = Features.size(); i != e; ++i) {
- if (Features[i] == "+soft-float")
+
+ for (const auto &Feature : Features) {
+ if (Feature == "+soft-float") {
SoftFloat = true;
- else if (Features[i] == "+soft-float-abi")
+ } else if (Feature == "+soft-float-abi") {
SoftFloatABI = true;
- else if (Features[i] == "+vfp2")
+ } else if (Feature == "+vfp2") {
FPU |= VFP2FPU;
- else if (Features[i] == "+vfp3")
+ HW_FP = HW_FP_SP | HW_FP_DP;
+ } else if (Feature == "+vfp3") {
FPU |= VFP3FPU;
- else if (Features[i] == "+vfp4")
+ HW_FP = HW_FP_SP | HW_FP_DP;
+ } else if (Feature == "+vfp4") {
FPU |= VFP4FPU;
- else if (Features[i] == "+fp-armv8")
+ HW_FP = HW_FP_SP | HW_FP_DP | HW_FP_HP;
+ } else if (Feature == "+fp-armv8") {
FPU |= FPARMV8;
- else if (Features[i] == "+neon")
+ HW_FP = HW_FP_SP | HW_FP_DP | HW_FP_HP;
+ } else if (Feature == "+neon") {
FPU |= NeonFPU;
- else if (Features[i] == "+hwdiv")
+ HW_FP = HW_FP_SP | HW_FP_DP;
+ } else if (Feature == "+hwdiv") {
HWDiv |= HWDivThumb;
- else if (Features[i] == "+hwdiv-arm")
+ } else if (Feature == "+hwdiv-arm") {
HWDiv |= HWDivARM;
- else if (Features[i] == "+crc")
+ } else if (Feature == "+crc") {
CRC = 1;
- else if (Features[i] == "+crypto")
+ } else if (Feature == "+crypto") {
Crypto = 1;
+ } else if (Feature == "+fp-only-sp") {
+ HW_FP &= ~HW_FP_DP;
+ }
}
if (!(FPU & NeonFPU) && FPMath == FP_Neon) {
@@ -3800,13 +4068,13 @@ public:
Features.push_back("-neonfp");
// Remove front-end specific options which the backend handles differently.
- std::vector<std::string>::iterator it;
- it = std::find(Features.begin(), Features.end(), "+soft-float");
- if (it != Features.end())
- Features.erase(it);
- it = std::find(Features.begin(), Features.end(), "+soft-float-abi");
- if (it != Features.end())
- Features.erase(it);
+ const StringRef FrontEndFeatures[] = { "+soft-float", "+soft-float-abi" };
+ for (const auto &FEFeature : FrontEndFeatures) {
+ auto Feature = std::find(Features.begin(), Features.end(), FEFeature);
+ if (Feature != Features.end())
+ Features.erase(Feature);
+ }
+
return true;
}
@@ -3822,40 +4090,43 @@ public:
}
// FIXME: Should we actually have some table instead of these switches?
static const char *getCPUDefineSuffix(StringRef Name) {
- return llvm::StringSwitch<const char*>(Name)
- .Cases("arm8", "arm810", "4")
- .Cases("strongarm", "strongarm110", "strongarm1100", "strongarm1110", "4")
- .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "arm720t", "arm9", "4T")
- .Cases("arm9tdmi", "arm920", "arm920t", "arm922t", "arm940t", "4T")
- .Case("ep9312", "4T")
- .Cases("arm10tdmi", "arm1020t", "5T")
- .Cases("arm9e", "arm946e-s", "arm966e-s", "arm968e-s", "5TE")
- .Case("arm926ej-s", "5TEJ")
- .Cases("arm10e", "arm1020e", "arm1022e", "5TE")
- .Cases("xscale", "iwmmxt", "5TE")
- .Case("arm1136j-s", "6J")
- .Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
- .Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
- .Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
- .Cases("cortex-a5", "cortex-a7", "cortex-a8", "cortex-a9-mp", "7A")
- .Cases("cortex-a9", "cortex-a12", "cortex-a15", "krait", "7A")
- .Cases("cortex-r4", "cortex-r5", "7R")
- .Case("swift", "7S")
- .Case("cyclone", "8A")
- .Case("cortex-m3", "7M")
- .Case("cortex-m4", "7EM")
- .Case("cortex-m0", "6M")
- .Cases("cortex-a53", "cortex-a57", "8A")
- .Default(nullptr);
+ return llvm::StringSwitch<const char *>(Name)
+ .Cases("arm8", "arm810", "4")
+ .Cases("strongarm", "strongarm110", "strongarm1100", "strongarm1110",
+ "4")
+ .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "arm720t", "arm9", "4T")
+ .Cases("arm9tdmi", "arm920", "arm920t", "arm922t", "arm940t", "4T")
+ .Case("ep9312", "4T")
+ .Cases("arm10tdmi", "arm1020t", "5T")
+ .Cases("arm9e", "arm946e-s", "arm966e-s", "arm968e-s", "5TE")
+ .Case("arm926ej-s", "5TEJ")
+ .Cases("arm10e", "arm1020e", "arm1022e", "5TE")
+ .Cases("xscale", "iwmmxt", "5TE")
+ .Case("arm1136j-s", "6J")
+ .Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
+ .Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
+ .Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "7A")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait",
+ "7A")
+ .Cases("cortex-r4", "cortex-r5", "7R")
+ .Case("swift", "7S")
+ .Case("cyclone", "8A")
+ .Case("cortex-m3", "7M")
+ .Cases("cortex-m4", "cortex-m7", "7EM")
+ .Case("cortex-m0", "6M")
+ .Cases("cortex-a53", "cortex-a57", "8A")
+ .Default(nullptr);
}
static const char *getCPUProfile(StringRef Name) {
- return llvm::StringSwitch<const char*>(Name)
- .Cases("cortex-a5", "cortex-a7", "cortex-a8", "A")
- .Cases("cortex-a9", "cortex-a12", "cortex-a15", "krait", "A")
- .Cases("cortex-a53", "cortex-a57", "A")
- .Cases("cortex-m3", "cortex-m4", "cortex-m0", "M")
- .Cases("cortex-r4", "cortex-r5", "R")
- .Default("");
+ return llvm::StringSwitch<const char *>(Name)
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "A")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait",
+ "A")
+ .Cases("cortex-a53", "cortex-a57", "A")
+ .Cases("cortex-m3", "cortex-m4", "cortex-m0", "cortex-m7", "M")
+ .Cases("cortex-r4", "cortex-r5", "R")
+ .Default("");
}
bool setCPU(const std::string &Name) override {
if (!getCPUDefineSuffix(Name))
@@ -3895,9 +4166,8 @@ public:
StringRef CPUArch = getCPUDefineSuffix(CPU);
unsigned int CPUArchVer;
- if(CPUArch.substr(0, 1).getAsInteger<unsigned int>(10, CPUArchVer)) {
+ if (CPUArch.substr(0, 1).getAsInteger<unsigned int>(10, CPUArchVer))
llvm_unreachable("Invalid char for architecture version number");
- }
Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__");
// ACLE 6.4.1 ARM/Thumb instruction set architecture
@@ -3906,6 +4176,10 @@ public:
// __ARM_ARCH is defined as an integer value indicating the current ARM ISA
Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1));
+ if (CPUArch[0] >= '8') {
+ Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN");
+ Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING");
+ }
// __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA. It
// is not defined for the M-profile.
@@ -3931,6 +4205,10 @@ public:
if (!CPUProfile.empty())
Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'");
+ // ACLE 6.5.1 Hardware Floating Point
+ if (HW_FP)
+ Builder.defineMacro("__ARM_FP", "0x" + llvm::utohexstr(HW_FP));
+
// ACLE predefines.
Builder.defineMacro("__ARM_ACLE", "200");
@@ -4008,6 +4286,13 @@ public:
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
}
+
+ bool is5EOrAbove = (CPUArchVer >= 6 ||
+ (CPUArchVer == 5 &&
+ CPUArch.find('E') != StringRef::npos));
+ bool is32Bit = (!IsThumb || supportsThumb2(ArchName, CPUArch, CPUArchVer));
+ if (is5EOrAbove && is32Bit && (CPUProfile != "M" || CPUArch == "7EM"))
+ Builder.defineMacro("__ARM_FEATURE_DSP");
}
void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const override {
@@ -4032,6 +4317,13 @@ public:
case 'P': // VFP Floating point register double precision
Info.setAllowsRegister();
return true;
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ // FIXME
+ return true;
case 'Q': // A memory address that is a single base register.
Info.setAllowsMemory();
return true;
@@ -4068,8 +4360,9 @@ public:
}
return R;
}
- bool validateConstraintModifier(StringRef Constraint, const char Modifier,
- unsigned Size) const override {
+ bool
+ validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size,
+ std::string &SuggestedModifier) const override {
bool isOutput = (Constraint[0] == '=');
bool isInOut = (Constraint[0] == '+');
@@ -4297,7 +4590,8 @@ public:
: DarwinTargetInfo<ARMleTargetInfo>(Triple) {
HasAlignMac68kSupport = true;
// iOS always has 64-bit atomic instructions.
- // FIXME: This should be based off of the target features in ARMleTargetInfo.
+ // FIXME: This should be based off of the target features in
+ // ARMleTargetInfo.
MaxAtomicInlineWidth = 64;
// Darwin on iOS uses a variant of the ARM C++ ABI.
@@ -4361,7 +4655,7 @@ public:
}
StringRef getABI() const override { return ABI; }
- virtual bool setABI(const std::string &Name) {
+ bool setABI(const std::string &Name) override {
if (Name != "aapcs" && Name != "darwinpcs")
return false;
@@ -4369,7 +4663,7 @@ public:
return true;
}
- virtual bool setCPU(const std::string &Name) {
+ bool setCPU(const std::string &Name) override {
bool CPUKnown = llvm::StringSwitch<bool>(Name)
.Case("generic", true)
.Cases("cortex-a53", "cortex-a57", true)
@@ -4379,7 +4673,7 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ MacroBuilder &Builder) const override {
// Target identification.
Builder.defineMacro("__aarch64__");
@@ -4400,6 +4694,10 @@ public:
Builder.defineMacro("__ARM_FEATURE_CLZ");
Builder.defineMacro("__ARM_FEATURE_FMA");
Builder.defineMacro("__ARM_FEATURE_DIV");
+ Builder.defineMacro("__ARM_FEATURE_IDIV"); // As specified in ACLE
+ Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility
+ Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN");
+ Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING");
Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4");
@@ -4413,7 +4711,7 @@ public:
if (Opts.FastMath || Opts.FiniteMathOnly)
Builder.defineMacro("__ARM_FP_FAST");
- if ((Opts.C99 || Opts.C11) && !Opts.Freestanding)
+ if (Opts.C99 && !Opts.Freestanding)
Builder.defineMacro("__ARM_FP_FENV_ROUNDING");
Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4");
@@ -4435,12 +4733,12 @@ public:
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
+ unsigned &NumRecords) const override {
Records = BuiltinInfo;
NumRecords = clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin;
}
- virtual bool hasFeature(StringRef Feature) const {
+ bool hasFeature(StringRef Feature) const override {
return Feature == "aarch64" ||
Feature == "arm64" ||
(Feature == "neon" && FPU == NeonMode);
@@ -4465,19 +4763,20 @@ public:
return true;
}
- virtual bool isCLZForZeroUndef() const { return false; }
+ bool isCLZForZeroUndef() const override { return false; }
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::AArch64ABIBuiltinVaList;
}
virtual void getGCCRegNames(const char *const *&Names,
- unsigned &NumNames) const;
+ unsigned &NumNames) const override;
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const;
+ unsigned &NumAliases) const override;
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
+ virtual bool
+ validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
switch (*Name) {
default:
return false;
@@ -4500,11 +4799,11 @@ public:
Info.setAllowsRegister();
return true;
case 'U':
- // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes, whatever they may be
- // Utf: A memory address suitable for ldp/stp in TF mode, whatever it may be
- // Usa: An absolute symbolic address
- // Ush: The high part (bits 32:12) of a pc-relative symbolic address
- llvm_unreachable("FIXME: Unimplemented support for bizarre constraints");
+ // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes.
+ // Utf: A memory address suitable for ldp/stp in TF mode.
+ // Usa: An absolute symbolic address.
+ // Ush: The high part (bits 32:12) of a pc-relative symbolic address.
+ llvm_unreachable("FIXME: Unimplemented support for U* constraints.");
case 'z': // Zero register, wzr or xzr
Info.setAllowsRegister();
return true;
@@ -4515,9 +4814,40 @@ public:
return false;
}
- virtual const char *getClobbers() const { return ""; }
+ bool
+ validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size,
+ std::string &SuggestedModifier) const override {
+ // Strip off constraint modifiers.
+ while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
+ Constraint = Constraint.substr(1);
+
+ switch (Constraint[0]) {
+ default:
+ return true;
+ case 'z':
+ case 'r': {
+ switch (Modifier) {
+ case 'x':
+ case 'w':
+ // For now assume that the person knows what they're
+ // doing with the modifier.
+ return true;
+ default:
+ // By default an 'r' constraint will be in the 'x'
+ // registers.
+ if (Size == 64)
+ return true;
+
+ SuggestedModifier = "w";
+ return false;
+ }
+ }
+ }
+ }
+
+ const char *getClobbers() const override { return ""; }
- int getEHDataRegisterNumber(unsigned RegNo) const {
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
if (RegNo == 0)
return 0;
if (RegNo == 1)
@@ -4652,7 +4982,7 @@ public:
TheCXXABI.set(TargetCXXABI::iOS64);
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::CharPtrBuiltinVaList;
}
};
@@ -4857,6 +5187,16 @@ public:
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const override {
// FIXME: Implement!
+ switch (*Name) {
+ case 'I': // Signed 13-bit constant
+ case 'J': // Zero
+ case 'K': // 32-bit constant with the low 12 bits clear
+ case 'L': // A constant in the range supported by movcc (11-bit signed imm)
+ case 'M': // A constant in the range supported by movrcc (19-bit signed imm)
+ case 'N': // Same as 'K' but zext (required for SIMode)
+ case 'O': // The constant 4096
+ return true;
+ }
return false;
}
const char *getClobbers() const override {
@@ -4962,10 +5302,8 @@ public:
SparcTargetInfo::getTargetDefines(Opts, Builder);
Builder.defineMacro("__sparcv9");
Builder.defineMacro("__arch64__");
- // Solaris and its derivative AuroraUX don't need these variants, but the
- // BSDs do.
- if (getTriple().getOS() != llvm::Triple::Solaris &&
- getTriple().getOS() != llvm::Triple::AuroraUX) {
+ // Solaris doesn't need these variants, but the BSDs do.
+ if (getTriple().getOS() != llvm::Triple::Solaris) {
Builder.defineMacro("__sparc64__");
Builder.defineMacro("__sparc_v9__");
Builder.defineMacro("__sparcv9__");
@@ -4992,14 +5330,6 @@ public:
} // end anonymous namespace.
namespace {
-class AuroraUXSparcV8TargetInfo : public AuroraUXTargetInfo<SparcV8TargetInfo> {
-public:
- AuroraUXSparcV8TargetInfo(const llvm::Triple &Triple)
- : AuroraUXTargetInfo<SparcV8TargetInfo>(Triple) {
- SizeType = UnsignedInt;
- PtrDiffType = SignedInt;
- }
-};
class SolarisSparcV8TargetInfo : public SolarisTargetInfo<SparcV8TargetInfo> {
public:
SolarisSparcV8TargetInfo(const llvm::Triple &Triple)
@@ -5131,7 +5461,7 @@ namespace {
IntPtrType = SignedInt;
PtrDiffType = SignedInt;
SigAtomicType = SignedLong;
- DescriptionString = "e-m:e-p:16:16-i32:16:32-n8:16";
+ DescriptionString = "e-m:e-p:16:16-i32:16:32-a:16-n8:16";
}
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
@@ -5156,8 +5486,16 @@ namespace {
Aliases = nullptr;
NumAliases = 0;
}
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override {
+ bool
+ validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
+ // FIXME: implement
+ switch (*Name) {
+ case 'K': // the constant 1
+ case 'L': // constant -1^20 .. 1^19
+ case 'M': // constant 1-4:
+ return true;
+ }
// No target constraints for now.
return false;
}
@@ -5197,6 +5535,8 @@ namespace {
3, // opencl_global
4, // opencl_local
5, // opencl_constant
+ // FIXME: generic has to be added to the target
+ 0, // opencl_generic
0, // cuda_device
0, // cuda_constant
0 // cuda_shared
@@ -5443,7 +5783,6 @@ public:
switch (*Name) {
default:
return false;
-
case 'r': // CPU registers.
case 'd': // Equivalent to "r" unless generating MIPS16 code.
case 'y': // Equivalent to "r", backward compatibility only.
@@ -5453,6 +5792,15 @@ public:
case 'x': // hilo register pair
Info.setAllowsRegister();
return true;
+ case 'I': // Signed 16-bit constant
+ case 'J': // Integer 0
+ case 'K': // Unsigned 16-bit constant
+ case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui)
+ case 'M': // Constants not loadable via lui, addiu, or ori
+ case 'N': // Constant -1 to -65535
+ case 'O': // A signed 15-bit constant
+ case 'P': // A constant between 1 go 65535
+ return true;
case 'R': // An address that can be used in a non-macro load or store
Info.setAllowsMemory();
return true;
@@ -5460,8 +5808,28 @@ public:
}
const char *getClobbers() const override {
- // FIXME: Implement!
- return "";
+ // In GCC, $1 is not widely used in generated code (it's used only in a few
+ // specific situations), so there is no real need for users to add it to
+ // the clobbers list if they want to use it in their inline assembly code.
+ //
+ // In LLVM, $1 is treated as a normal GPR and is always allocatable during
+ // code generation, so using it in inline assembly without adding it to the
+ // clobbers list can cause conflicts between the inline assembly code and
+ // the surrounding generated code.
+ //
+ // Another problem is that LLVM is allowed to choose $1 for inline assembly
+ // operands, which will conflict with the ".set at" assembler option (which
+ // we use only for inline assembly, in order to maintain compatibility with
+ // GCC) and will also conflict with the user's usage of $1.
+ //
+ // The easiest way to avoid these conflicts and keep $1 as an allocatable
+ // register for generated code is to automatically clobber $1 for all inline
+ // assembly code.
+ //
+ // FIXME: We should automatically clobber $1 only for inline assembly code
+ // which actually uses it. This would allow LLVM to use $1 for inline
+ // assembly operands if the user's assembly code doesn't use it.
+ return "~{$1}";
}
bool handleTargetFeatures(std::vector<std::string> &Features,
@@ -5863,10 +6231,65 @@ void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
} // end anonymous namespace.
namespace {
+class Le64TargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+
+public:
+ Le64TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
+ BigEndian = false;
+ NoAsmVariants = true;
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ DescriptionString =
+ "e-m:e-v128:32-v16:16-v32:32-v96:32-n8:16:32:64-S128";
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ DefineStd(Builder, "unix", Opts);
+ defineCPUMacros(Builder, "le64", /*Tuning=*/false);
+ Builder.defineMacro("__ELF__");
+ }
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
+ Records = BuiltinInfo;
+ NumRecords = clang::Le64::LastTSBuiltin - Builtin::FirstTSBuiltin;
+ }
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::PNaClABIBuiltinVaList;
+ }
+ const char *getClobbers() const override { return ""; }
+ void getGCCRegNames(const char *const *&Names,
+ unsigned &NumNames) const override {
+ Names = nullptr;
+ NumNames = 0;
+ }
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {
+ Aliases = nullptr;
+ NumAliases = 0;
+ }
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ return false;
+ }
+
+ bool hasProtectedVisibility() const override { return false; }
+};
+} // end anonymous namespace.
+
+const Builtin::Info Le64TargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
+#include "clang/Basic/BuiltinsLe64.def"
+};
+
+namespace {
static const unsigned SPIRAddrSpaceMap[] = {
1, // opencl_global
3, // opencl_local
2, // opencl_constant
+ 4, // opencl_generic
0, // cuda_device
0, // cuda_constant
0 // cuda_shared
@@ -5902,8 +6325,9 @@ namespace {
}
void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const override {}
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override {
+ bool
+ validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
return true;
}
void getGCCRegAliases(const GCCRegAlias *&Aliases,
@@ -6031,11 +6455,12 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
return new HexagonTargetInfo(Triple);
case llvm::Triple::aarch64:
- case llvm::Triple::arm64:
if (Triple.isOSDarwin())
return new DarwinAArch64TargetInfo(Triple);
switch (os) {
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<AArch64leTargetInfo>(Triple);
case llvm::Triple::Linux:
return new LinuxTargetInfo<AArch64leTargetInfo>(Triple);
case llvm::Triple::NetBSD:
@@ -6045,8 +6470,9 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
}
case llvm::Triple::aarch64_be:
- case llvm::Triple::arm64_be:
switch (os) {
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<AArch64beTargetInfo>(Triple);
case llvm::Triple::Linux:
return new LinuxTargetInfo<AArch64beTargetInfo>(Triple);
case llvm::Triple::NetBSD:
@@ -6185,6 +6611,9 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
return nullptr;
}
+ case llvm::Triple::le64:
+ return new Le64TargetInfo(Triple);
+
case llvm::Triple::ppc:
if (Triple.isOSDarwin())
return new DarwinPPC32TargetInfo(Triple);
@@ -6232,6 +6661,7 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
case llvm::Triple::nvptx64:
return new NVPTX64TargetInfo(Triple);
+ case llvm::Triple::amdgcn:
case llvm::Triple::r600:
return new R600TargetInfo(Triple);
@@ -6239,8 +6669,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
switch (os) {
case llvm::Triple::Linux:
return new LinuxTargetInfo<SparcV8TargetInfo>(Triple);
- case llvm::Triple::AuroraUX:
- return new AuroraUXSparcV8TargetInfo(Triple);
case llvm::Triple::Solaris:
return new SolarisSparcV8TargetInfo(Triple);
case llvm::Triple::NetBSD:
@@ -6257,8 +6685,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
switch (os) {
case llvm::Triple::Linux:
return new LinuxTargetInfo<SparcV9TargetInfo>(Triple);
- case llvm::Triple::AuroraUX:
- return new AuroraUXTargetInfo<SparcV9TargetInfo>(Triple);
case llvm::Triple::Solaris:
return new SolarisTargetInfo<SparcV9TargetInfo>(Triple);
case llvm::Triple::NetBSD:
@@ -6287,8 +6713,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
return new DarwinI386TargetInfo(Triple);
switch (os) {
- case llvm::Triple::AuroraUX:
- return new AuroraUXTargetInfo<X86_32TargetInfo>(Triple);
case llvm::Triple::Linux:
return new LinuxTargetInfo<X86_32TargetInfo>(Triple);
case llvm::Triple::DragonFly:
@@ -6335,8 +6759,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
return new DarwinX86_64TargetInfo(Triple);
switch (os) {
- case llvm::Triple::AuroraUX:
- return new AuroraUXTargetInfo<X86_64TargetInfo>(Triple);
case llvm::Triple::Linux:
return new LinuxTargetInfo<X86_64TargetInfo>(Triple);
case llvm::Triple::DragonFly:
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 87ecac17649b..9e0b91a84894 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -36,7 +36,7 @@ std::string getClangRepositoryPath() {
// If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us
// pick up a tag in an SVN export, for example.
- StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_350/final/lib/Basic/Version.cpp $");
+ StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_360/rc1/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
diff --git a/lib/Basic/VersionTuple.cpp b/lib/Basic/VersionTuple.cpp
index 8b781ab0a304..aa43ae298e23 100644
--- a/lib/Basic/VersionTuple.cpp
+++ b/lib/Basic/VersionTuple.cpp
@@ -29,9 +29,9 @@ raw_ostream& clang::operator<<(raw_ostream &Out,
const VersionTuple &V) {
Out << V.getMajor();
if (Optional<unsigned> Minor = V.getMinor())
- Out << '.' << *Minor;
+ Out << (V.usesUnderscores() ? '_' : '.') << *Minor;
if (Optional<unsigned> Subminor = V.getSubminor())
- Out << '.' << *Subminor;
+ Out << (V.usesUnderscores() ? '_' : '.') << *Subminor;
return Out;
}
diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp
index a5c83b88af50..c89195e9326c 100644
--- a/lib/Basic/VirtualFileSystem.cpp
+++ b/lib/Basic/VirtualFileSystem.cpp
@@ -11,10 +11,10 @@
#include "clang/Basic/VirtualFileSystem.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -67,16 +67,14 @@ File::~File() {}
FileSystem::~FileSystem() {}
-std::error_code FileSystem::getBufferForFile(
- const llvm::Twine &Name, std::unique_ptr<MemoryBuffer> &Result,
- int64_t FileSize, bool RequiresNullTerminator, bool IsVolatile) {
- std::unique_ptr<File> F;
- if (std::error_code EC = openFileForRead(Name, F))
- return EC;
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
+ bool RequiresNullTerminator, bool IsVolatile) {
+ auto F = openFileForRead(Name);
+ if (!F)
+ return F.getError();
- std::error_code EC =
- F->getBuffer(Name, Result, FileSize, RequiresNullTerminator, IsVolatile);
- return EC;
+ return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
}
//===-----------------------------------------------------------------------===/
@@ -96,11 +94,10 @@ class RealFile : public File {
public:
~RealFile();
ErrorOr<Status> status() override;
- std::error_code getBuffer(const Twine &Name,
- std::unique_ptr<MemoryBuffer> &Result,
- int64_t FileSize = -1,
- bool RequiresNullTerminator = true,
- bool IsVolatile = false) override;
+ ErrorOr<std::unique_ptr<MemoryBuffer>>
+ getBuffer(const Twine &Name, int64_t FileSize = -1,
+ bool RequiresNullTerminator = true,
+ bool IsVolatile = false) override;
std::error_code close() override;
void setName(StringRef Name) override;
};
@@ -120,19 +117,12 @@ ErrorOr<Status> RealFile::status() {
return S;
}
-std::error_code RealFile::getBuffer(const Twine &Name,
- std::unique_ptr<MemoryBuffer> &Result,
- int64_t FileSize,
- bool RequiresNullTerminator,
- bool IsVolatile) {
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+RealFile::getBuffer(const Twine &Name, int64_t FileSize,
+ bool RequiresNullTerminator, bool IsVolatile) {
assert(FD != -1 && "cannot get buffer for closed file");
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
- MemoryBuffer::getOpenFile(FD, Name.str().c_str(), FileSize,
- RequiresNullTerminator, IsVolatile);
- if (std::error_code EC = BufferOrErr.getError())
- return EC;
- Result = std::move(BufferOrErr.get());
- return std::error_code();
+ return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
+ IsVolatile);
}
// FIXME: This is terrible, we need this for ::close.
@@ -161,8 +151,7 @@ namespace {
class RealFileSystem : public FileSystem {
public:
ErrorOr<Status> status(const Twine &Path) override;
- std::error_code openFileForRead(const Twine &Path,
- std::unique_ptr<File> &Result) override;
+ ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
};
} // end anonymous namespace
@@ -176,14 +165,14 @@ ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
return Result;
}
-std::error_code RealFileSystem::openFileForRead(const Twine &Name,
- std::unique_ptr<File> &Result) {
+ErrorOr<std::unique_ptr<File>>
+RealFileSystem::openFileForRead(const Twine &Name) {
int FD;
if (std::error_code EC = sys::fs::openFileForRead(Name, FD))
return EC;
- Result.reset(new RealFile(FD));
+ std::unique_ptr<File> Result(new RealFile(FD));
Result->setName(Name.str());
- return std::error_code();
+ return std::move(Result);
}
IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
@@ -252,14 +241,13 @@ ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
return make_error_code(llvm::errc::no_such_file_or_directory);
}
-std::error_code
-OverlayFileSystem::openFileForRead(const llvm::Twine &Path,
- std::unique_ptr<File> &Result) {
+ErrorOr<std::unique_ptr<File>>
+OverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
// FIXME: handle symlinks that cross file systems
for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
- std::error_code EC = (*I)->openFileForRead(Path, Result);
- if (!EC || EC != llvm::errc::no_such_file_or_directory)
- return EC;
+ auto Result = (*I)->openFileForRead(Path);
+ if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
+ return Result;
}
return make_error_code(llvm::errc::no_such_file_or_directory);
}
@@ -308,7 +296,7 @@ class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl {
}
CurrentEntry = *CurrentDirIter;
StringRef Name = llvm::sys::path::filename(CurrentEntry.getName());
- if (SeenNames.insert(Name))
+ if (SeenNames.insert(Name).second)
return EC; // name not seen before
}
llvm_unreachable("returned above");
@@ -514,16 +502,13 @@ public:
/// \brief Parses \p Buffer, which is expected to be in YAML format and
/// returns a virtual file system representing its contents.
- ///
- /// Takes ownership of \p Buffer.
- static VFSFromYAML *create(MemoryBuffer *Buffer,
+ static VFSFromYAML *create(std::unique_ptr<MemoryBuffer> Buffer,
SourceMgr::DiagHandlerTy DiagHandler,
void *DiagContext,
IntrusiveRefCntPtr<FileSystem> ExternalFS);
ErrorOr<Status> status(const Twine &Path) override;
- std::error_code openFileForRead(const Twine &Path,
- std::unique_ptr<File> &Result) override;
+ ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{
ErrorOr<Entry *> E = lookupPath(Dir);
@@ -865,13 +850,13 @@ DirectoryEntry::~DirectoryEntry() { llvm::DeleteContainerPointers(Contents); }
VFSFromYAML::~VFSFromYAML() { llvm::DeleteContainerPointers(Roots); }
-VFSFromYAML *VFSFromYAML::create(MemoryBuffer *Buffer,
+VFSFromYAML *VFSFromYAML::create(std::unique_ptr<MemoryBuffer> Buffer,
SourceMgr::DiagHandlerTy DiagHandler,
void *DiagContext,
IntrusiveRefCntPtr<FileSystem> ExternalFS) {
SourceMgr SM;
- yaml::Stream Stream(Buffer, SM);
+ yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
SM.setDiagHandler(DiagHandler, DiagContext);
yaml::document_iterator DI = Stream.begin();
@@ -971,9 +956,7 @@ ErrorOr<Status> VFSFromYAML::status(const Twine &Path) {
return status(Path, *Result);
}
-std::error_code
-VFSFromYAML::openFileForRead(const Twine &Path,
- std::unique_ptr<vfs::File> &Result) {
+ErrorOr<std::unique_ptr<File>> VFSFromYAML::openFileForRead(const Twine &Path) {
ErrorOr<Entry *> E = lookupPath(Path);
if (!E)
return E.getError();
@@ -982,21 +965,22 @@ VFSFromYAML::openFileForRead(const Twine &Path,
if (!F) // FIXME: errc::not_a_file?
return make_error_code(llvm::errc::invalid_argument);
- if (std::error_code EC =
- ExternalFS->openFileForRead(F->getExternalContentsPath(), Result))
- return EC;
+ auto Result = ExternalFS->openFileForRead(F->getExternalContentsPath());
+ if (!Result)
+ return Result;
if (!F->useExternalName(UseExternalNames))
- Result->setName(Path.str());
+ (*Result)->setName(Path.str());
- return std::error_code();
+ return Result;
}
IntrusiveRefCntPtr<FileSystem>
-vfs::getVFSFromYAML(MemoryBuffer *Buffer, SourceMgr::DiagHandlerTy DiagHandler,
- void *DiagContext,
+vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
+ SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext,
IntrusiveRefCntPtr<FileSystem> ExternalFS) {
- return VFSFromYAML::create(Buffer, DiagHandler, DiagContext, ExternalFS);
+ return VFSFromYAML::create(std::move(Buffer), DiagHandler, DiagContext,
+ ExternalFS);
}
UniqueID vfs::getNextVirtualUniqueID() {
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index d3ec46c4c4a1..7e7f7fa20679 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_ABIINFO_H
-#define CLANG_CODEGEN_ABIINFO_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_ABIINFO_H
+#define LLVM_CLANG_LIB_CODEGEN_ABIINFO_H
#include "clang/AST/Type.h"
#include "llvm/IR/CallingConv.h"
@@ -44,9 +44,12 @@ namespace clang {
CodeGen::CodeGenTypes &CGT;
protected:
llvm::CallingConv::ID RuntimeCC;
+ llvm::CallingConv::ID BuiltinCC;
public:
ABIInfo(CodeGen::CodeGenTypes &cgt)
- : CGT(cgt), RuntimeCC(llvm::CallingConv::C) {}
+ : CGT(cgt),
+ RuntimeCC(llvm::CallingConv::C),
+ BuiltinCC(llvm::CallingConv::C) {}
virtual ~ABIInfo();
@@ -62,6 +65,11 @@ namespace clang {
return RuntimeCC;
}
+ /// Return the calling convention to use for compiler builtins
+ llvm::CallingConv::ID getBuiltinCC() const {
+ return BuiltinCC;
+ }
+
virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const = 0;
/// EmitVAArg - Emit the target dependent code to load a value of
@@ -73,6 +81,15 @@ namespace clang {
// abstract this out.
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGen::CodeGenFunction &CGF) const = 0;
+
+ virtual bool isHomogeneousAggregateBaseType(QualType Ty) const;
+
+ virtual bool isHomogeneousAggregateSmallEnough(const Type *Base,
+ uint64_t Members) const;
+
+ bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
+ uint64_t &Members) const;
+
};
} // end namespace clang
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index cec48f35a2e9..25ecec586244 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -33,11 +33,13 @@
#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/SymbolRewriter.h"
#include <memory>
using namespace clang;
using namespace llvm;
@@ -61,7 +63,7 @@ private:
PassManager *getCodeGenPasses() const {
if (!CodeGenPasses) {
CodeGenPasses = new PassManager();
- CodeGenPasses->add(new DataLayoutPass(TheModule));
+ CodeGenPasses->add(new DataLayoutPass());
if (TM)
TM->addAnalysisPasses(*CodeGenPasses);
}
@@ -71,7 +73,7 @@ private:
PassManager *getPerModulePasses() const {
if (!PerModulePasses) {
PerModulePasses = new PassManager();
- PerModulePasses->add(new DataLayoutPass(TheModule));
+ PerModulePasses->add(new DataLayoutPass());
if (TM)
TM->addAnalysisPasses(*PerModulePasses);
}
@@ -81,7 +83,7 @@ private:
FunctionPassManager *getPerFunctionPasses() const {
if (!PerFunctionPasses) {
PerFunctionPasses = new FunctionPassManager(TheModule);
- PerFunctionPasses->add(new DataLayoutPass(TheModule));
+ PerFunctionPasses->add(new DataLayoutPass());
if (TM)
TM->addAnalysisPasses(*PerFunctionPasses);
}
@@ -121,7 +123,7 @@ public:
delete PerModulePasses;
delete PerFunctionPasses;
if (CodeGenOpts.DisableFree)
- BuryPointer(TM.release());
+ BuryPointer(std::move(TM));
}
std::unique_ptr<TargetMachine> TM;
@@ -178,6 +180,14 @@ static void addBoundsCheckingPass(const PassManagerBuilder &Builder,
PM.add(createBoundsCheckingPass());
}
+static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
+ PassManagerBase &PM) {
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper&>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ PM.add(createSanitizerCoverageModulePass(CGOpts.SanitizeCoverage));
+}
+
static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
PassManagerBase &PM) {
PM.add(createAddressSanitizerFunctionPass());
@@ -213,8 +223,27 @@ static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder,
PassManagerBase &PM) {
const PassManagerBuilderWrapper &BuilderWrapper =
static_cast<const PassManagerBuilderWrapper&>(Builder);
- const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
- PM.add(createDataFlowSanitizerPass(CGOpts.SanitizerBlacklistFile));
+ const LangOptions &LangOpts = BuilderWrapper.getLangOpts();
+ PM.add(createDataFlowSanitizerPass(LangOpts.SanitizerBlacklistFile));
+}
+
+static TargetLibraryInfo *createTLI(llvm::Triple &TargetTriple,
+ const CodeGenOptions &CodeGenOpts) {
+ TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
+ if (!CodeGenOpts.SimplifyLibCalls)
+ TLI->disableAllFunctions();
+ return TLI;
+}
+
+static void addSymbolRewriterPass(const CodeGenOptions &Opts,
+ PassManager *MPM) {
+ llvm::SymbolRewriter::RewriteDescriptorList DL;
+
+ llvm::SymbolRewriter::RewriteMapParser MapParser;
+ for (const auto &MapFile : Opts.RewriteMapFiles)
+ MapParser.parse(MapFile, &DL);
+
+ MPM->add(createRewriteSymbolsPass(DL));
}
void EmitAssemblyHelper::CreatePasses() {
@@ -238,6 +267,7 @@ void EmitAssemblyHelper::CreatePasses() {
PMBuilder.DisableTailCalls = CodeGenOpts.DisableTailCalls;
PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime;
PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops;
+ PMBuilder.MergeFunctions = CodeGenOpts.MergeFunctions;
PMBuilder.RerollLoops = CodeGenOpts.RerollLoops;
PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
@@ -257,35 +287,42 @@ void EmitAssemblyHelper::CreatePasses() {
addObjCARCOptPass);
}
- if (LangOpts.Sanitize.LocalBounds) {
+ if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds)) {
PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
addBoundsCheckingPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addBoundsCheckingPass);
}
- if (LangOpts.Sanitize.Address) {
+ if (CodeGenOpts.SanitizeCoverage) {
+ PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
+ addSanitizerCoveragePass);
+ PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
+ addSanitizerCoveragePass);
+ }
+
+ if (LangOpts.Sanitize.has(SanitizerKind::Address)) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addAddressSanitizerPasses);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addAddressSanitizerPasses);
}
- if (LangOpts.Sanitize.Memory) {
+ if (LangOpts.Sanitize.has(SanitizerKind::Memory)) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addMemorySanitizerPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addMemorySanitizerPass);
}
- if (LangOpts.Sanitize.Thread) {
+ if (LangOpts.Sanitize.has(SanitizerKind::Thread)) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addThreadSanitizerPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addThreadSanitizerPass);
}
- if (LangOpts.Sanitize.DataFlow) {
+ if (LangOpts.Sanitize.has(SanitizerKind::DataFlow)) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addDataFlowSanitizerPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
@@ -294,9 +331,7 @@ void EmitAssemblyHelper::CreatePasses() {
// Figure out TargetLibraryInfo.
Triple TargetTriple(TheModule->getTargetTriple());
- PMBuilder.LibraryInfo = new TargetLibraryInfo(TargetTriple);
- if (!CodeGenOpts.SimplifyLibCalls)
- PMBuilder.LibraryInfo->disableAllFunctions();
+ PMBuilder.LibraryInfo = createTLI(TargetTriple, CodeGenOpts);
switch (Inlining) {
case CodeGenOptions::NoInlining: break;
@@ -323,6 +358,8 @@ void EmitAssemblyHelper::CreatePasses() {
// Set up the per-module pass manager.
PassManager *MPM = getPerModulePasses();
+ if (!CodeGenOpts.RewriteMapFiles.empty())
+ addSymbolRewriterPass(CodeGenOpts, MPM);
if (CodeGenOpts.VerifyModule)
MPM->add(createDebugInfoVerifierPass());
@@ -343,6 +380,12 @@ void EmitAssemblyHelper::CreatePasses() {
MPM->add(createStripSymbolsPass(true));
}
+ if (CodeGenOpts.ProfileInstrGenerate) {
+ InstrProfOptions Options;
+ Options.NoRedZone = CodeGenOpts.DisableRedZone;
+ MPM->add(createInstrProfilingPass(Options));
+ }
+
PMBuilder.populateModulePassManager(*MPM);
}
@@ -418,6 +461,11 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
llvm::TargetOptions Options;
+ Options.ThreadModel =
+ llvm::StringSwitch<llvm::ThreadModel::Model>(CodeGenOpts.ThreadModel)
+ .Case("posix", llvm::ThreadModel::POSIX)
+ .Case("single", llvm::ThreadModel::Single);
+
if (CodeGenOpts.DisableIntegratedAS)
Options.DisableIntegratedAS = true;
@@ -476,7 +524,9 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
Options.MCOptions.MCUseDwarfDirectory = !CodeGenOpts.NoDwarfDirectoryAsm;
Options.MCOptions.MCNoExecStack = CodeGenOpts.NoExecStack;
+ Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings;
Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
+ Options.MCOptions.ABIName = TargetOpts.ABI;
TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
FeaturesStr, Options,
@@ -493,10 +543,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
// Add LibraryInfo.
llvm::Triple TargetTriple(TheModule->getTargetTriple());
- TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
- if (!CodeGenOpts.SimplifyLibCalls)
- TLI->disableAllFunctions();
- PM->add(TLI);
+ PM->add(createTLI(TargetTriple, CodeGenOpts));
// Add Target specific analysis passes.
TM->addAnalysisPasses(*PM);
@@ -600,8 +647,9 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
// If an optional clang TargetInfo description string was passed in, use it to
// verify the LLVM TargetMachine's DataLayout.
if (AsmHelper.TM && !TDesc.empty()) {
- std::string DLDesc =
- AsmHelper.TM->getDataLayout()->getStringRepresentation();
+ std::string DLDesc = AsmHelper.TM->getSubtargetImpl()
+ ->getDataLayout()
+ ->getStringRepresentation();
if (DLDesc != TDesc) {
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error, "backend data layout '%0' does not match "
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
index 89bde2ce20d9..daac174c8e0c 100644
--- a/lib/CodeGen/CGAtomic.cpp
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -46,23 +46,26 @@ namespace {
ASTContext &C = CGF.getContext();
- uint64_t valueAlignInBits;
- std::tie(ValueSizeInBits, valueAlignInBits) = C.getTypeInfo(ValueTy);
+ uint64_t ValueAlignInBits;
+ uint64_t AtomicAlignInBits;
+ TypeInfo ValueTI = C.getTypeInfo(ValueTy);
+ ValueSizeInBits = ValueTI.Width;
+ ValueAlignInBits = ValueTI.Align;
- uint64_t atomicAlignInBits;
- std::tie(AtomicSizeInBits, atomicAlignInBits) = C.getTypeInfo(AtomicTy);
+ TypeInfo AtomicTI = C.getTypeInfo(AtomicTy);
+ AtomicSizeInBits = AtomicTI.Width;
+ AtomicAlignInBits = AtomicTI.Align;
assert(ValueSizeInBits <= AtomicSizeInBits);
- assert(valueAlignInBits <= atomicAlignInBits);
+ assert(ValueAlignInBits <= AtomicAlignInBits);
- AtomicAlign = C.toCharUnitsFromBits(atomicAlignInBits);
- ValueAlign = C.toCharUnitsFromBits(valueAlignInBits);
+ AtomicAlign = C.toCharUnitsFromBits(AtomicAlignInBits);
+ ValueAlign = C.toCharUnitsFromBits(ValueAlignInBits);
if (lvalue.getAlignment().isZero())
lvalue.setAlignment(AtomicAlign);
- UseLibcall =
- (AtomicSizeInBits > uint64_t(C.toBits(lvalue.getAlignment())) ||
- AtomicSizeInBits > C.getTargetInfo().getMaxAtomicInlineWidth());
+ UseLibcall = !C.getTargetInfo().hasBuiltinAtomic(
+ AtomicSizeInBits, C.toBits(lvalue.getAlignment()));
}
QualType getAtomicType() const { return AtomicTy; }
@@ -70,7 +73,7 @@ namespace {
CharUnits getAtomicAlignment() const { return AtomicAlign; }
CharUnits getValueAlignment() const { return ValueAlign; }
uint64_t getAtomicSizeInBits() const { return AtomicSizeInBits; }
- uint64_t getValueSizeInBits() const { return AtomicSizeInBits; }
+ uint64_t getValueSizeInBits() const { return ValueSizeInBits; }
TypeEvaluationKind getEvaluationKind() const { return EvaluationKind; }
bool shouldUseLibcall() const { return UseLibcall; }
@@ -100,6 +103,12 @@ namespace {
AggValueSlot resultSlot,
SourceLocation loc) const;
+ /// \brief Converts a rvalue to integer value.
+ llvm::Value *convertRValueToInt(RValue RVal) const;
+
+ RValue convertIntToValue(llvm::Value *IntVal, AggValueSlot ResultSlot,
+ SourceLocation Loc) const;
+
/// Copy an atomic r-value into atomic-layout memory.
void emitCopyIntoMemory(RValue rvalue, LValue lvalue) const;
@@ -461,11 +470,19 @@ EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
static void
AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,
bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy,
- SourceLocation Loc) {
+ SourceLocation Loc, CharUnits SizeInChars) {
if (UseOptimizedLibcall) {
// Load value and pass it to the function directly.
unsigned Align = CGF.getContext().getTypeAlignInChars(ValTy).getQuantity();
- Val = CGF.EmitLoadOfScalar(Val, false, Align, ValTy, Loc);
+ int64_t SizeInBits = CGF.getContext().toBits(SizeInChars);
+ ValTy =
+ CGF.getContext().getIntTypeForBitwidth(SizeInBits, /*Signed=*/false);
+ llvm::Type *IPtrTy = llvm::IntegerType::get(CGF.getLLVMContext(),
+ SizeInBits)->getPointerTo();
+ Val = CGF.EmitLoadOfScalar(CGF.Builder.CreateBitCast(Val, IPtrTy), false,
+ Align, CGF.getContext().getPointerType(ValTy),
+ Loc);
+ // Coerce the value into an appropriately sized integer type.
Args.add(RValue::get(Val), ValTy);
} else {
// Non-optimized functions always take a reference.
@@ -576,8 +593,14 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
break;
}
- if (!E->getType()->isVoidType() && !Dest)
- Dest = CreateMemTemp(E->getType(), ".atomicdst");
+ QualType RValTy = E->getType().getUnqualifiedType();
+
+ auto GetDest = [&] {
+ if (!RValTy->isVoidType() && !Dest) {
+ Dest = CreateMemTemp(RValTy, ".atomicdst");
+ }
+ return Dest;
+ };
// Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
if (UseLibcall) {
@@ -634,7 +657,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
HaveRetTy = true;
Args.add(RValue::get(EmitCastToVoidPtr(Val1)), getContext().VoidPtrTy);
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val2, MemTy,
- E->getExprLoc());
+ E->getExprLoc(), sizeChars);
Args.add(RValue::get(Order), getContext().IntTy);
Order = OrderFail;
break;
@@ -646,7 +669,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
case AtomicExpr::AO__atomic_exchange:
LibCallName = "__atomic_exchange";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
- E->getExprLoc());
+ E->getExprLoc(), sizeChars);
break;
// void __atomic_store(size_t size, void *mem, void *val, int order)
// void __atomic_store_N(T *mem, T val, int order)
@@ -657,7 +680,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
RetTy = getContext().VoidTy;
HaveRetTy = true;
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
- E->getExprLoc());
+ E->getExprLoc(), sizeChars);
break;
// void __atomic_load(size_t size, void *mem, void *return, int order)
// T __atomic_load_N(T *mem, int order)
@@ -671,35 +694,35 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
case AtomicExpr::AO__atomic_fetch_add:
LibCallName = "__atomic_fetch_add";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, LoweredMemTy,
- E->getExprLoc());
+ E->getExprLoc(), sizeChars);
break;
// T __atomic_fetch_and_N(T *mem, T val, int order)
case AtomicExpr::AO__c11_atomic_fetch_and:
case AtomicExpr::AO__atomic_fetch_and:
LibCallName = "__atomic_fetch_and";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
- E->getExprLoc());
+ E->getExprLoc(), sizeChars);
break;
// T __atomic_fetch_or_N(T *mem, T val, int order)
case AtomicExpr::AO__c11_atomic_fetch_or:
case AtomicExpr::AO__atomic_fetch_or:
LibCallName = "__atomic_fetch_or";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
- E->getExprLoc());
+ E->getExprLoc(), sizeChars);
break;
// T __atomic_fetch_sub_N(T *mem, T val, int order)
case AtomicExpr::AO__c11_atomic_fetch_sub:
case AtomicExpr::AO__atomic_fetch_sub:
LibCallName = "__atomic_fetch_sub";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, LoweredMemTy,
- E->getExprLoc());
+ E->getExprLoc(), sizeChars);
break;
// T __atomic_fetch_xor_N(T *mem, T val, int order)
case AtomicExpr::AO__c11_atomic_fetch_xor:
case AtomicExpr::AO__atomic_fetch_xor:
LibCallName = "__atomic_fetch_xor";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
- E->getExprLoc());
+ E->getExprLoc(), sizeChars);
break;
default: return EmitUnsupportedRValue(E, "atomic library call");
}
@@ -711,29 +734,36 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
if (!HaveRetTy) {
if (UseOptimizedLibcall) {
// Value is returned directly.
- RetTy = MemTy;
+ // The function returns an appropriately sized integer type.
+ RetTy = getContext().getIntTypeForBitwidth(
+ getContext().toBits(sizeChars), /*Signed=*/false);
} else {
// Value is returned through parameter before the order.
RetTy = getContext().VoidTy;
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)), getContext().VoidPtrTy);
}
}
// order is always the last parameter
Args.add(RValue::get(Order),
getContext().IntTy);
- const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeFreeFunctionCall(RetTy, Args,
- FunctionType::ExtInfo(), RequiredArgs::All);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
- llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
- RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
- if (!RetTy->isVoidType())
+ RValue Res = emitAtomicLibcall(*this, LibCallName, RetTy, Args);
+ // The value is returned directly from the libcall.
+ if (HaveRetTy && !RetTy->isVoidType())
return Res;
- if (E->getType()->isVoidType())
+ // The value is returned via an explicit out param.
+ if (RetTy->isVoidType())
return RValue::get(nullptr);
- return convertTempToRValue(Dest, E->getType(), E->getExprLoc());
+ // The value is returned directly for optimized libcalls but the caller is
+ // expected an out-param.
+ if (UseOptimizedLibcall) {
+ llvm::Value *ResVal = Res.getScalarVal();
+ llvm::StoreInst *StoreDest = Builder.CreateStore(
+ ResVal,
+ Builder.CreateBitCast(GetDest(), ResVal->getType()->getPointerTo()));
+ StoreDest->setAlignment(Align);
+ }
+ return convertTempToRValue(Dest, RValTy, E->getExprLoc());
}
bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
@@ -743,13 +773,15 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
E->getOp() == AtomicExpr::AO__atomic_load ||
E->getOp() == AtomicExpr::AO__atomic_load_n;
- llvm::Type *IPtrTy =
- llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo();
- llvm::Value *OrigDest = Dest;
- Ptr = Builder.CreateBitCast(Ptr, IPtrTy);
- if (Val1) Val1 = Builder.CreateBitCast(Val1, IPtrTy);
- if (Val2) Val2 = Builder.CreateBitCast(Val2, IPtrTy);
- if (Dest && !E->isCmpXChg()) Dest = Builder.CreateBitCast(Dest, IPtrTy);
+ llvm::Type *ITy =
+ llvm::IntegerType::get(getLLVMContext(), Size * 8);
+ llvm::Value *OrigDest = GetDest();
+ Ptr = Builder.CreateBitCast(
+ Ptr, ITy->getPointerTo(Ptr->getType()->getPointerAddressSpace()));
+ if (Val1) Val1 = Builder.CreateBitCast(Val1, ITy->getPointerTo());
+ if (Val2) Val2 = Builder.CreateBitCast(Val2, ITy->getPointerTo());
+ if (Dest && !E->isCmpXChg())
+ Dest = Builder.CreateBitCast(Dest, ITy->getPointerTo());
if (isa<llvm::ConstantInt>(Order)) {
int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
@@ -786,9 +818,9 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
// enforce that in general.
break;
}
- if (E->getType()->isVoidType())
+ if (RValTy->isVoidType())
return RValue::get(nullptr);
- return convertTempToRValue(OrigDest, E->getType(), E->getExprLoc());
+ return convertTempToRValue(OrigDest, RValTy, E->getExprLoc());
}
// Long case, when Order isn't obviously constant.
@@ -854,9 +886,9 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
// Cleanup and return
Builder.SetInsertPoint(ContBB);
- if (E->getType()->isVoidType())
+ if (RValTy->isVoidType())
return RValue::get(nullptr);
- return convertTempToRValue(OrigDest, E->getType(), E->getExprLoc());
+ return convertTempToRValue(OrigDest, RValTy, E->getExprLoc());
}
llvm::Value *AtomicInfo::emitCastToAtomicIntPointer(llvm::Value *addr) const {
@@ -882,6 +914,45 @@ RValue AtomicInfo::convertTempToRValue(llvm::Value *addr,
return CGF.convertTempToRValue(addr, getValueType(), loc);
}
+RValue AtomicInfo::convertIntToValue(llvm::Value *IntVal,
+ AggValueSlot ResultSlot,
+ SourceLocation Loc) const {
+ // Try not to in some easy cases.
+ assert(IntVal->getType()->isIntegerTy() && "Expected integer value");
+ if (getEvaluationKind() == TEK_Scalar && !hasPadding()) {
+ auto *ValTy = CGF.ConvertTypeForMem(ValueTy);
+ if (ValTy->isIntegerTy()) {
+ assert(IntVal->getType() == ValTy && "Different integer types.");
+ return RValue::get(IntVal);
+ } else if (ValTy->isPointerTy())
+ return RValue::get(CGF.Builder.CreateIntToPtr(IntVal, ValTy));
+ else if (llvm::CastInst::isBitCastable(IntVal->getType(), ValTy))
+ return RValue::get(CGF.Builder.CreateBitCast(IntVal, ValTy));
+ }
+
+ // Create a temporary. This needs to be big enough to hold the
+ // atomic integer.
+ llvm::Value *Temp;
+ bool TempIsVolatile = false;
+ CharUnits TempAlignment;
+ if (getEvaluationKind() == TEK_Aggregate) {
+ assert(!ResultSlot.isIgnored());
+ Temp = ResultSlot.getAddr();
+ TempAlignment = getValueAlignment();
+ TempIsVolatile = ResultSlot.isVolatile();
+ } else {
+ Temp = CGF.CreateMemTemp(getAtomicType(), "atomic-temp");
+ TempAlignment = getAtomicAlignment();
+ }
+
+ // Slam the integer into the temporary.
+ llvm::Value *CastTemp = emitCastToAtomicIntPointer(Temp);
+ CGF.Builder.CreateAlignedStore(IntVal, CastTemp, TempAlignment.getQuantity())
+ ->setVolatile(TempIsVolatile);
+
+ return convertTempToRValue(Temp, ResultSlot, Loc);
+}
+
/// Emit a load from an l-value of atomic type. Note that the r-value
/// we produce is an r-value of the atomic *value* type.
RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
@@ -927,50 +998,12 @@ RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
if (src.getTBAAInfo())
CGM.DecorateInstruction(load, src.getTBAAInfo());
- // Okay, turn that back into the original value type.
- QualType valueType = atomics.getValueType();
- llvm::Value *result = load;
-
// If we're ignoring an aggregate return, don't do anything.
if (atomics.getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
return RValue::getAggregate(nullptr, false);
- // The easiest way to do this this is to go through memory, but we
- // try not to in some easy cases.
- if (atomics.getEvaluationKind() == TEK_Scalar && !atomics.hasPadding()) {
- llvm::Type *resultTy = CGM.getTypes().ConvertTypeForMem(valueType);
- if (isa<llvm::IntegerType>(resultTy)) {
- assert(result->getType() == resultTy);
- result = EmitFromMemory(result, valueType);
- } else if (isa<llvm::PointerType>(resultTy)) {
- result = Builder.CreateIntToPtr(result, resultTy);
- } else {
- result = Builder.CreateBitCast(result, resultTy);
- }
- return RValue::get(result);
- }
-
- // Create a temporary. This needs to be big enough to hold the
- // atomic integer.
- llvm::Value *temp;
- bool tempIsVolatile = false;
- CharUnits tempAlignment;
- if (atomics.getEvaluationKind() == TEK_Aggregate) {
- assert(!resultSlot.isIgnored());
- temp = resultSlot.getAddr();
- tempAlignment = atomics.getValueAlignment();
- tempIsVolatile = resultSlot.isVolatile();
- } else {
- temp = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp");
- tempAlignment = atomics.getAtomicAlignment();
- }
-
- // Slam the integer into the temporary.
- llvm::Value *castTemp = atomics.emitCastToAtomicIntPointer(temp);
- Builder.CreateAlignedStore(result, castTemp, tempAlignment.getQuantity())
- ->setVolatile(tempIsVolatile);
-
- return atomics.convertTempToRValue(temp, resultSlot, loc);
+ // Okay, turn that back into the original value type.
+ return atomics.convertIntToValue(load, resultSlot, loc);
}
@@ -1023,6 +1056,32 @@ llvm::Value *AtomicInfo::materializeRValue(RValue rvalue) const {
return temp;
}
+llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const {
+ // If we've got a scalar value of the right size, try to avoid going
+ // through memory.
+ if (RVal.isScalar() && !hasPadding()) {
+ llvm::Value *Value = RVal.getScalarVal();
+ if (isa<llvm::IntegerType>(Value->getType()))
+ return Value;
+ else {
+ llvm::IntegerType *InputIntTy =
+ llvm::IntegerType::get(CGF.getLLVMContext(), getValueSizeInBits());
+ if (isa<llvm::PointerType>(Value->getType()))
+ return CGF.Builder.CreatePtrToInt(Value, InputIntTy);
+ else if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy))
+ return CGF.Builder.CreateBitCast(Value, InputIntTy);
+ }
+ }
+ // Otherwise, we need to go through memory.
+ // Put the r-value in memory.
+ llvm::Value *Addr = materializeRValue(RVal);
+
+ // Cast the temporary to the atomic int type and pull a value out.
+ Addr = emitCastToAtomicIntPointer(Addr);
+ return CGF.Builder.CreateAlignedLoad(Addr,
+ getAtomicAlignment().getQuantity());
+}
+
/// Emit a store to an l-value of atomic type.
///
/// Note that the r-value is expected to be an r-value *of the atomic
@@ -1064,34 +1123,7 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
}
// Okay, we're doing this natively.
- llvm::Value *intValue;
-
- // If we've got a scalar value of the right size, try to avoid going
- // through memory.
- if (rvalue.isScalar() && !atomics.hasPadding()) {
- llvm::Value *value = rvalue.getScalarVal();
- if (isa<llvm::IntegerType>(value->getType())) {
- intValue = value;
- } else {
- llvm::IntegerType *inputIntTy =
- llvm::IntegerType::get(getLLVMContext(), atomics.getValueSizeInBits());
- if (isa<llvm::PointerType>(value->getType())) {
- intValue = Builder.CreatePtrToInt(value, inputIntTy);
- } else {
- intValue = Builder.CreateBitCast(value, inputIntTy);
- }
- }
-
- // Otherwise, we need to go through memory.
- } else {
- // Put the r-value in memory.
- llvm::Value *addr = atomics.materializeRValue(rvalue);
-
- // Cast the temporary to the atomic int type and pull a value out.
- addr = atomics.emitCastToAtomicIntPointer(addr);
- intValue = Builder.CreateAlignedLoad(addr,
- atomics.getAtomicAlignment().getQuantity());
- }
+ llvm::Value *intValue = atomics.convertRValueToInt(rvalue);
// Do the atomic store.
llvm::Value *addr = atomics.emitCastToAtomicIntPointer(dest.getAddress());
@@ -1108,6 +1140,74 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
CGM.DecorateInstruction(store, dest.getTBAAInfo());
}
+/// Emit a compare-and-exchange op for atomic type.
+///
+std::pair<RValue, RValue> CodeGenFunction::EmitAtomicCompareExchange(
+ LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
+ llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak,
+ AggValueSlot Slot) {
+ // If this is an aggregate r-value, it should agree in type except
+ // maybe for address-space qualification.
+ assert(!Expected.isAggregate() ||
+ Expected.getAggregateAddr()->getType()->getPointerElementType() ==
+ Obj.getAddress()->getType()->getPointerElementType());
+ assert(!Desired.isAggregate() ||
+ Desired.getAggregateAddr()->getType()->getPointerElementType() ==
+ Obj.getAddress()->getType()->getPointerElementType());
+ AtomicInfo Atomics(*this, Obj);
+
+ if (Failure >= Success)
+ // Don't assert on undefined behavior.
+ Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(Success);
+
+ auto Alignment = Atomics.getValueAlignment();
+ // Check whether we should use a library call.
+ if (Atomics.shouldUseLibcall()) {
+ auto *ExpectedAddr = Atomics.materializeRValue(Expected);
+ // Produce a source address.
+ auto *DesiredAddr = Atomics.materializeRValue(Desired);
+ // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
+ // void *desired, int success, int failure);
+ CallArgList Args;
+ Args.add(RValue::get(Atomics.getAtomicSizeValue()),
+ getContext().getSizeType());
+ Args.add(RValue::get(EmitCastToVoidPtr(Obj.getAddress())),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(ExpectedAddr)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(DesiredAddr)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(llvm::ConstantInt::get(IntTy, Success)),
+ getContext().IntTy);
+ Args.add(RValue::get(llvm::ConstantInt::get(IntTy, Failure)),
+ getContext().IntTy);
+ auto SuccessFailureRVal = emitAtomicLibcall(
+ *this, "__atomic_compare_exchange", getContext().BoolTy, Args);
+ auto *PreviousVal =
+ Builder.CreateAlignedLoad(ExpectedAddr, Alignment.getQuantity());
+ return std::make_pair(RValue::get(PreviousVal), SuccessFailureRVal);
+ }
+
+ // If we've got a scalar value of the right size, try to avoid going
+ // through memory.
+ auto *ExpectedIntVal = Atomics.convertRValueToInt(Expected);
+ auto *DesiredIntVal = Atomics.convertRValueToInt(Desired);
+
+ // Do the atomic store.
+ auto *Addr = Atomics.emitCastToAtomicIntPointer(Obj.getAddress());
+ auto *Inst = Builder.CreateAtomicCmpXchg(Addr, ExpectedIntVal, DesiredIntVal,
+ Success, Failure);
+ // Other decoration.
+ Inst->setVolatile(Obj.isVolatileQualified());
+ Inst->setWeak(IsWeak);
+
+ // Okay, turn that back into the original value type.
+ auto *PreviousVal = Builder.CreateExtractValue(Inst, /*Idxs=*/0);
+ auto *SuccessFailureVal = Builder.CreateExtractValue(Inst, /*Idxs=*/1);
+ return std::make_pair(Atomics.convertIntToValue(PreviousVal, Slot, Loc),
+ RValue::get(SuccessFailureVal));
+}
+
void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
AtomicInfo atomics(*this, dest);
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 72fde9dc55f1..b98460a9ddd8 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -545,6 +545,16 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
// multiple of alignment.
for (SmallVectorImpl<BlockLayoutChunk>::iterator
li = layout.begin(), le = layout.end(); li != le; ++li) {
+ if (endAlign < li->Alignment) {
+ // size may not be multiple of alignment. This can only happen with
+ // an over-aligned variable. We will be adding a padding field to
+ // make the size be multiple of alignment.
+ CharUnits padding = li->Alignment - endAlign;
+ elementTypes.push_back(llvm::ArrayType::get(CGM.Int8Ty,
+ padding.getQuantity()));
+ blockSize += padding;
+ endAlign = getLowBit(blockSize);
+ }
assert(endAlign >= li->Alignment);
li->setIndex(info, elementTypes.size());
elementTypes.push_back(li->Type);
@@ -782,9 +792,10 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// emission.
src = LocalDeclMap.lookup(variable);
if (!src) {
- DeclRefExpr declRef(const_cast<VarDecl *>(variable),
- /*refersToEnclosing*/ CI.isNested(), type,
- VK_LValue, SourceLocation());
+ DeclRefExpr declRef(
+ const_cast<VarDecl *>(variable),
+ /*RefersToEnclosingVariableOrCapture*/ CI.isNested(), type,
+ VK_LValue, SourceLocation());
src = EmitDeclRefLValue(&declRef).getAddress();
}
}
@@ -853,12 +864,15 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// We use one of these or the other depending on whether the
// reference is nested.
- DeclRefExpr declRef(const_cast<VarDecl*>(variable),
- /*refersToEnclosing*/ CI.isNested(), type,
- VK_LValue, SourceLocation());
+ DeclRefExpr declRef(const_cast<VarDecl *>(variable),
+ /*RefersToEnclosingVariableOrCapture*/ CI.isNested(),
+ type, VK_LValue, SourceLocation());
ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
&declRef, VK_RValue);
+ // FIXME: Pass a specific location for the expr init so that the store is
+ // attributed to a reasonable location - otherwise it may be attributed to
+ // locations of subexpressions in the initialization.
EmitExprAsInit(&l2r, &blockFieldPseudoVar,
MakeAddrLValue(blockField, type, align),
/*captured by init*/ false);
@@ -905,7 +919,7 @@ llvm::Type *CodeGenModule::getBlockDescriptorType() {
// };
BlockDescriptorType =
llvm::StructType::create("struct.__block_descriptor",
- UnsignedLongTy, UnsignedLongTy, NULL);
+ UnsignedLongTy, UnsignedLongTy, nullptr);
// Now form a pointer to that.
BlockDescriptorType = llvm::PointerType::getUnqual(BlockDescriptorType);
@@ -928,7 +942,7 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
GenericBlockLiteralType =
llvm::StructType::create("struct.__block_literal_generic",
VoidPtrTy, IntTy, IntTy, VoidPtrTy,
- BlockDescPtrTy, NULL);
+ BlockDescPtrTy, nullptr);
return GenericBlockLiteralType;
}
@@ -1093,6 +1107,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
CurGD = GD;
+
+ CurEHLocation = blockInfo.getBlockExpr()->getLocEnd();
BlockInfo = &blockInfo;
@@ -1162,7 +1178,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
Alloca->setAlignment(Align);
// Set the DebugLocation to empty, so the store is recognized as a
// frame setup instruction by llvm::DwarfDebug::beginFunction().
- NoLocation NL(*this, Builder);
+ ApplyDebugLocation NL(*this);
Builder.CreateAlignedStore(BlockPointer, Alloca, Align);
BlockPointerDbgLoc = Alloca;
}
@@ -1205,8 +1221,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
RegionCounter Cnt = getPGORegionCounter(blockDecl->getBody());
Cnt.beginRegion(Builder);
EmitStmt(blockDecl->getBody());
- PGO.emitInstrumentationData();
- PGO.destroyRegionCounters();
}
// Remember where we were...
@@ -1233,7 +1247,9 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
}
DI->EmitDeclareOfBlockDeclRefVariable(variable, BlockPointerDbgLoc,
- Builder, blockInfo);
+ Builder, blockInfo,
+ entry_ptr == entry->end()
+ ? nullptr : entry_ptr);
}
}
// Recover location if it was changed in the above loop.
@@ -1313,9 +1329,9 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
false,
false);
// Create a scope with an artificial location for the body of this function.
- ArtificialLocation AL(*this, Builder);
+ ApplyDebugLocation NL(*this);
StartFunction(FD, C.VoidTy, Fn, FI, args);
- AL.Emit();
+ ArtificialLocation AL(*this);
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1484,9 +1500,9 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
nullptr, SC_Static,
false, false);
// Create a scope with an artificial location for the body of this function.
- ArtificialLocation AL(*this, Builder);
+ ApplyDebugLocation NL(*this);
StartFunction(FD, C.VoidTy, Fn, FI, args);
- AL.Emit();
+ ArtificialLocation AL(*this);
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 0031e32c9daf..c4eed0d0e8eb 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CGBLOCKS_H
-#define CLANG_CODEGEN_CGBLOCKS_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H
+#define LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H
#include "CGBuilder.h"
#include "CGCall.h"
diff --git a/lib/CodeGen/CGBuilder.h b/lib/CodeGen/CGBuilder.h
index f113b970b7b7..72ba4faa3c7c 100644
--- a/lib/CodeGen/CGBuilder.h
+++ b/lib/CodeGen/CGBuilder.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CGBUILDER_H
-#define CLANG_CODEGEN_CGBUILDER_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
+#define LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
#include "llvm/IR/IRBuilder.h"
@@ -18,7 +18,7 @@ namespace CodeGen {
class CodeGenFunction;
/// \brief This is an IRBuilder insertion helper that forwards to
-/// CodeGenFunction::InsertHelper, which adds nesessary metadata to
+/// CodeGenFunction::InsertHelper, which adds necessary metadata to
/// instructions.
template <bool PreserveNames>
class CGBuilderInserter
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 4f68b347dbf0..635e34207de7 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -20,7 +20,9 @@
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
using namespace clang;
@@ -113,7 +115,8 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
llvm::AtomicRMWInst::BinOp Kind,
const CallExpr *E,
- Instruction::BinaryOps Op) {
+ Instruction::BinaryOps Op,
+ bool Invert = false) {
QualType T = E->getType();
assert(E->getArg(0)->getType()->isPointerType());
assert(CGF.getContext().hasSameUnqualifiedType(T,
@@ -138,36 +141,25 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
CGF.Builder.CreateAtomicRMW(Kind, Args[0], Args[1],
llvm::SequentiallyConsistent);
Result = CGF.Builder.CreateBinOp(Op, Result, Args[1]);
+ if (Invert)
+ Result = CGF.Builder.CreateBinOp(llvm::Instruction::Xor, Result,
+ llvm::ConstantInt::get(IntType, -1));
Result = EmitFromInt(CGF, Result, T, ValueType);
return RValue::get(Result);
}
-/// EmitFAbs - Emit a call to fabs/fabsf/fabsl, depending on the type of ValTy,
-/// which must be a scalar floating point type.
-static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
- const BuiltinType *ValTyP = ValTy->getAs<BuiltinType>();
- assert(ValTyP && "isn't scalar fp type!");
-
- StringRef FnName;
- switch (ValTyP->getKind()) {
- default: llvm_unreachable("Isn't a scalar fp type!");
- case BuiltinType::Float: FnName = "fabsf"; break;
- case BuiltinType::Double: FnName = "fabs"; break;
- case BuiltinType::LongDouble: FnName = "fabsl"; break;
- }
-
- // The prototype is something that takes and returns whatever V's type is.
- llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), V->getType(),
- false);
- llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName);
-
- return CGF.EmitNounwindRuntimeCall(Fn, V, "abs");
+/// EmitFAbs - Emit a call to @llvm.fabs().
+static Value *EmitFAbs(CodeGenFunction &CGF, Value *V) {
+ Value *F = CGF.CGM.getIntrinsic(Intrinsic::fabs, V->getType());
+ llvm::CallInst *Call = CGF.Builder.CreateCall(F, V);
+ Call->setDoesNotAccessMemory();
+ return Call;
}
static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn,
const CallExpr *E, llvm::Value *calleeValue) {
- return CGF.EmitCall(E->getCallee()->getType(), calleeValue, E->getLocStart(),
- ReturnValueSlot(), E->arg_begin(), E->arg_end(), Fn);
+ return CGF.EmitCall(E->getCallee()->getType(), calleeValue, E,
+ ReturnValueSlot(), Fn);
}
/// \brief Emit a call to llvm.{sadd,uadd,ssub,usub,smul,umul}.with.overflow.*
@@ -195,7 +187,8 @@ static llvm::Value *EmitOverflowIntrinsic(CodeGenFunction &CGF,
}
RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
- unsigned BuiltinID, const CallExpr *E) {
+ unsigned BuiltinID, const CallExpr *E,
+ ReturnValueSlot ReturnValue) {
// See if we can constant fold this builtin. If so, don't emit it at all.
Expr::EvalResult Result;
if (E->EvaluateAsRValue(Result, CGM.getContext()) &&
@@ -255,6 +248,21 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Result);
}
+ case Builtin::BI__builtin_fabs:
+ case Builtin::BI__builtin_fabsf:
+ case Builtin::BI__builtin_fabsl: {
+ Value *Arg1 = EmitScalarExpr(E->getArg(0));
+ Value *Result = EmitFAbs(*this, Arg1);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_fmod:
+ case Builtin::BI__builtin_fmodf:
+ case Builtin::BI__builtin_fmodl: {
+ Value *Arg1 = EmitScalarExpr(E->getArg(0));
+ Value *Arg2 = EmitScalarExpr(E->getArg(1));
+ Value *Result = Builder.CreateFRem(Arg1, Arg2, "fmod");
+ return RValue::get(Result);
+ }
case Builtin::BI__builtin_conj:
case Builtin::BI__builtin_conjf:
@@ -388,6 +396,27 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
"expval");
return RValue::get(Result);
}
+ case Builtin::BI__builtin_assume_aligned: {
+ Value *PtrValue = EmitScalarExpr(E->getArg(0));
+ Value *OffsetValue =
+ (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : nullptr;
+
+ Value *AlignmentValue = EmitScalarExpr(E->getArg(1));
+ ConstantInt *AlignmentCI = cast<ConstantInt>(AlignmentValue);
+ unsigned Alignment = (unsigned) AlignmentCI->getZExtValue();
+
+ EmitAlignmentAssumption(PtrValue, Alignment, OffsetValue);
+ return RValue::get(PtrValue);
+ }
+ case Builtin::BI__assume:
+ case Builtin::BI__builtin_assume: {
+ if (E->getArg(0)->HasSideEffects(getContext()))
+ return RValue::get(nullptr);
+
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ Value *FnAssume = CGM.getIntrinsic(Intrinsic::assume);
+ return RValue::get(Builder.CreateCall(FnAssume, ArgValue));
+ }
case Builtin::BI__builtin_bswap16:
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64: {
@@ -447,11 +476,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall(F));
}
case Builtin::BI__builtin_unreachable: {
- if (SanOpts->Unreachable) {
+ if (SanOpts.has(SanitizerKind::Unreachable)) {
SanitizerScope SanScope(this);
- EmitCheck(Builder.getFalse(), "builtin_unreachable",
- EmitCheckSourceLocation(E->getExprLoc()),
- ArrayRef<llvm::Value *>(), CRK_Unrecoverable);
+ EmitCheck(std::make_pair(static_cast<llvm::Value *>(Builder.getFalse()),
+ SanitizerKind::Unreachable),
+ "builtin_unreachable", EmitCheckSourceLocation(E->getExprLoc()),
+ None);
} else
Builder.CreateUnreachable();
@@ -515,7 +545,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_isinf: {
// isinf(x) --> fabs(x) == infinity
Value *V = EmitScalarExpr(E->getArg(0));
- V = EmitFAbs(*this, V, E->getArg(0)->getType());
+ V = EmitFAbs(*this, V);
V = Builder.CreateFCmpOEQ(V, ConstantFP::getInfinity(V->getType()),"isinf");
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
@@ -529,7 +559,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *V = EmitScalarExpr(E->getArg(0));
Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq");
- Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType());
+ Value *Abs = EmitFAbs(*this, V);
Value *IsLessThanInf =
Builder.CreateFCmpULT(Abs, ConstantFP::getInfinity(V->getType()),"isinf");
APFloat Smallest = APFloat::getSmallestNormalized(
@@ -547,7 +577,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *V = EmitScalarExpr(E->getArg(0));
Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq");
- Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType());
+ Value *Abs = EmitFAbs(*this, V);
Value *IsNotInf =
Builder.CreateFCmpUNE(Abs, ConstantFP::getInfinity(V->getType()),"isinf");
@@ -586,7 +616,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// if (fabs(V) == infinity) return FP_INFINITY
Builder.SetInsertPoint(NotNan);
- Value *VAbs = EmitFAbs(*this, V, E->getArg(5)->getType());
+ Value *VAbs = EmitFAbs(*this, V);
Value *IsInf =
Builder.CreateFCmpOEQ(VAbs, ConstantFP::getInfinity(V->getType()),
"isinf");
@@ -864,11 +894,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_fetch_and_or:
case Builtin::BI__sync_fetch_and_and:
case Builtin::BI__sync_fetch_and_xor:
+ case Builtin::BI__sync_fetch_and_nand:
case Builtin::BI__sync_add_and_fetch:
case Builtin::BI__sync_sub_and_fetch:
case Builtin::BI__sync_and_and_fetch:
case Builtin::BI__sync_or_and_fetch:
case Builtin::BI__sync_xor_and_fetch:
+ case Builtin::BI__sync_nand_and_fetch:
case Builtin::BI__sync_val_compare_and_swap:
case Builtin::BI__sync_bool_compare_and_swap:
case Builtin::BI__sync_lock_test_and_set:
@@ -905,6 +937,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_fetch_and_xor_8:
case Builtin::BI__sync_fetch_and_xor_16:
return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xor, E);
+ case Builtin::BI__sync_fetch_and_nand_1:
+ case Builtin::BI__sync_fetch_and_nand_2:
+ case Builtin::BI__sync_fetch_and_nand_4:
+ case Builtin::BI__sync_fetch_and_nand_8:
+ case Builtin::BI__sync_fetch_and_nand_16:
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Nand, E);
// Clang extensions: not overloaded yet.
case Builtin::BI__sync_fetch_and_min:
@@ -951,6 +989,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_xor_and_fetch_16:
return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Xor, E,
llvm::Instruction::Xor);
+ case Builtin::BI__sync_nand_and_fetch_1:
+ case Builtin::BI__sync_nand_and_fetch_2:
+ case Builtin::BI__sync_nand_and_fetch_4:
+ case Builtin::BI__sync_nand_and_fetch_8:
+ case Builtin::BI__sync_nand_and_fetch_16:
+ return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Nand, E,
+ llvm::Instruction::And, true);
case Builtin::BI__sync_val_compare_and_swap_1:
case Builtin::BI__sync_val_compare_and_swap_2:
@@ -1347,11 +1392,17 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Arg = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgTy = Arg->getType();
- if (ArgTy->isPPC_FP128Ty())
- break; // FIXME: I'm not sure what the right implementation is here.
int ArgWidth = ArgTy->getPrimitiveSizeInBits();
llvm::Type *ArgIntTy = llvm::IntegerType::get(C, ArgWidth);
Value *BCArg = Builder.CreateBitCast(Arg, ArgIntTy);
+ if (ArgTy->isPPC_FP128Ty()) {
+ // The higher-order double comes first, and so we need to truncate the
+ // pair to extract the overall sign. The order of the pair is the same
+ // in both little- and big-Endian modes.
+ ArgWidth >>= 1;
+ ArgIntTy = llvm::IntegerType::get(C, ArgWidth);
+ BCArg = Builder.CreateTrunc(BCArg, ArgIntTy);
+ }
Value *ZeroCmp = llvm::Constant::getNullValue(ArgIntTy);
Value *Result = Builder.CreateICmpSLT(BCArg, ZeroCmp);
return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType())));
@@ -1518,9 +1569,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__noop:
// __noop always evaluates to an integer literal zero.
return RValue::get(ConstantInt::get(IntTy, 0));
- case Builtin::BI__assume:
- // Until LLVM supports assumptions at the IR level, this becomes nothing.
- return RValue::get(nullptr);
+ case Builtin::BI__builtin_call_with_static_chain: {
+ const CallExpr *Call = cast<CallExpr>(E->getArg(0));
+ const Expr *Chain = E->getArg(1);
+ return EmitCall(Call->getCallee()->getType(),
+ EmitScalarExpr(Call->getCallee()), Call, ReturnValue,
+ Call->getCalleeDecl(), EmitScalarExpr(Chain));
+ }
case Builtin::BI_InterlockedExchange:
case Builtin::BI_InterlockedExchangePointer:
return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xchg, E);
@@ -1587,6 +1642,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
RMWI->setVolatile(true);
return RValue::get(RMWI);
}
+ case Builtin::BI__readfsdword: {
+ Value *IntToPtr =
+ Builder.CreateIntToPtr(EmitScalarExpr(E->getArg(0)),
+ llvm::PointerType::get(CGM.Int32Ty, 257));
+ LoadInst *Load =
+ Builder.CreateAlignedLoad(IntToPtr, /*Align=*/4, /*isVolatile=*/true);
+ return RValue::get(Load);
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
@@ -1690,8 +1753,6 @@ Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
return EmitARMBuiltinExpr(BuiltinID, E);
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
- case llvm::Triple::arm64:
- case llvm::Triple::arm64_be:
return EmitAArch64BuiltinExpr(BuiltinID, E);
case llvm::Triple::x86:
case llvm::Triple::x86_64:
@@ -1701,6 +1762,7 @@ Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
case llvm::Triple::ppc64le:
return EmitPPCBuiltinExpr(BuiltinID, E);
case llvm::Triple::r600:
+ case llvm::Triple::amdgcn:
return EmitR600BuiltinExpr(BuiltinID, E);
default:
return nullptr;
@@ -2005,8 +2067,12 @@ static NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP1(vld4q_lane_v, arm_neon_vld4lane, 0),
NEONMAP1(vld4q_v, arm_neon_vld4, 0),
NEONMAP2(vmax_v, arm_neon_vmaxu, arm_neon_vmaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vmaxnm_v, arm_neon_vmaxnm, Add1ArgType),
+ NEONMAP1(vmaxnmq_v, arm_neon_vmaxnm, Add1ArgType),
NEONMAP2(vmaxq_v, arm_neon_vmaxu, arm_neon_vmaxs, Add1ArgType | UnsignedAlts),
NEONMAP2(vmin_v, arm_neon_vminu, arm_neon_vmins, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vminnm_v, arm_neon_vminnm, Add1ArgType),
+ NEONMAP1(vminnmq_v, arm_neon_vminnm, Add1ArgType),
NEONMAP2(vminq_v, arm_neon_vminu, arm_neon_vmins, Add1ArgType | UnsignedAlts),
NEONMAP0(vmovl_v),
NEONMAP0(vmovn_v),
@@ -2042,6 +2108,8 @@ static NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP2(vqshl_v, arm_neon_vqshiftu, arm_neon_vqshifts, Add1ArgType | UnsignedAlts),
NEONMAP2(vqshlq_n_v, arm_neon_vqshiftu, arm_neon_vqshifts, UnsignedAlts),
NEONMAP2(vqshlq_v, arm_neon_vqshiftu, arm_neon_vqshifts, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vqshlu_n_v, arm_neon_vqshiftsu, 0),
+ NEONMAP1(vqshluq_n_v, arm_neon_vqshiftsu, 0),
NEONMAP2(vqsub_v, arm_neon_vqsubu, arm_neon_vqsubs, Add1ArgType | UnsignedAlts),
NEONMAP2(vqsubq_v, arm_neon_vqsubu, arm_neon_vqsubs, Add1ArgType | UnsignedAlts),
NEONMAP1(vraddhn_v, arm_neon_vraddhn, Add1ArgType),
@@ -2051,8 +2119,22 @@ static NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP1(vrecpsq_v, arm_neon_vrecps, Add1ArgType),
NEONMAP2(vrhadd_v, arm_neon_vrhaddu, arm_neon_vrhadds, Add1ArgType | UnsignedAlts),
NEONMAP2(vrhaddq_v, arm_neon_vrhaddu, arm_neon_vrhadds, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vrnd_v, arm_neon_vrintz, Add1ArgType),
+ NEONMAP1(vrnda_v, arm_neon_vrinta, Add1ArgType),
+ NEONMAP1(vrndaq_v, arm_neon_vrinta, Add1ArgType),
+ NEONMAP1(vrndm_v, arm_neon_vrintm, Add1ArgType),
+ NEONMAP1(vrndmq_v, arm_neon_vrintm, Add1ArgType),
+ NEONMAP1(vrndn_v, arm_neon_vrintn, Add1ArgType),
+ NEONMAP1(vrndnq_v, arm_neon_vrintn, Add1ArgType),
+ NEONMAP1(vrndp_v, arm_neon_vrintp, Add1ArgType),
+ NEONMAP1(vrndpq_v, arm_neon_vrintp, Add1ArgType),
+ NEONMAP1(vrndq_v, arm_neon_vrintz, Add1ArgType),
+ NEONMAP1(vrndx_v, arm_neon_vrintx, Add1ArgType),
+ NEONMAP1(vrndxq_v, arm_neon_vrintx, Add1ArgType),
NEONMAP2(vrshl_v, arm_neon_vrshiftu, arm_neon_vrshifts, Add1ArgType | UnsignedAlts),
NEONMAP2(vrshlq_v, arm_neon_vrshiftu, arm_neon_vrshifts, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vrshr_n_v, arm_neon_vrshiftu, arm_neon_vrshifts, UnsignedAlts),
+ NEONMAP2(vrshrq_n_v, arm_neon_vrshiftu, arm_neon_vrshifts, UnsignedAlts),
NEONMAP2(vrsqrte_v, arm_neon_vrsqrte, arm_neon_vrsqrte, 0),
NEONMAP2(vrsqrteq_v, arm_neon_vrsqrte, arm_neon_vrsqrte, 0),
NEONMAP1(vrsqrts_v, arm_neon_vrsqrts, Add1ArgType),
@@ -2173,6 +2255,8 @@ static NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP2(vqshl_v, aarch64_neon_uqshl, aarch64_neon_sqshl, Add1ArgType | UnsignedAlts),
NEONMAP2(vqshlq_n_v, aarch64_neon_uqshl, aarch64_neon_sqshl,UnsignedAlts),
NEONMAP2(vqshlq_v, aarch64_neon_uqshl, aarch64_neon_sqshl, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vqshlu_n_v, aarch64_neon_sqshlu, 0),
+ NEONMAP1(vqshluq_n_v, aarch64_neon_sqshlu, 0),
NEONMAP2(vqsub_v, aarch64_neon_uqsub, aarch64_neon_sqsub, Add1ArgType | UnsignedAlts),
NEONMAP2(vqsubq_v, aarch64_neon_uqsub, aarch64_neon_sqsub, Add1ArgType | UnsignedAlts),
NEONMAP1(vraddhn_v, aarch64_neon_raddhn, Add1ArgType),
@@ -2184,6 +2268,8 @@ static NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP2(vrhaddq_v, aarch64_neon_urhadd, aarch64_neon_srhadd, Add1ArgType | UnsignedAlts),
NEONMAP2(vrshl_v, aarch64_neon_urshl, aarch64_neon_srshl, Add1ArgType | UnsignedAlts),
NEONMAP2(vrshlq_v, aarch64_neon_urshl, aarch64_neon_srshl, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vrshr_n_v, aarch64_neon_urshl, aarch64_neon_srshl, UnsignedAlts),
+ NEONMAP2(vrshrq_n_v, aarch64_neon_urshl, aarch64_neon_srshl, UnsignedAlts),
NEONMAP2(vrsqrte_v, aarch64_neon_frsqrte, aarch64_neon_ursqrte, 0),
NEONMAP2(vrsqrteq_v, aarch64_neon_frsqrte, aarch64_neon_ursqrte, 0),
NEONMAP1(vrsqrts_v, aarch64_neon_frsqrts, Add1ArgType),
@@ -2828,6 +2914,10 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
case NEON::BI__builtin_neon_vqshlq_n_v:
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshl_n",
1, false);
+ case NEON::BI__builtin_neon_vqshlu_n_v:
+ case NEON::BI__builtin_neon_vqshluq_n_v:
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshlu_n",
+ 1, false);
case NEON::BI__builtin_neon_vrecpe_v:
case NEON::BI__builtin_neon_vrecpeq_v:
case NEON::BI__builtin_neon_vrsqrte_v:
@@ -2835,6 +2925,10 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
Int = Ty->isFPOrFPVectorTy() ? LLVMIntrinsic : AltLLVMIntrinsic;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, NameHint);
+ case NEON::BI__builtin_neon_vrshr_n_v:
+ case NEON::BI__builtin_neon_vrshrq_n_v:
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshr_n",
+ 1, true);
case NEON::BI__builtin_neon_vshl_n_v:
case NEON::BI__builtin_neon_vshlq_n_v:
Ops[1] = EmitNeonShiftVector(Ops[1], Ty, false);
@@ -3039,39 +3133,76 @@ static Value *packTBLDVectorList(CodeGenFunction &CGF, ArrayRef<Value *> Ops,
return CGF.EmitNeonCall(TblF, TblOps, Name);
}
-Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- unsigned HintID = static_cast<unsigned>(-1);
+Value *CodeGenFunction::GetValueForARMHint(unsigned BuiltinID) {
switch (BuiltinID) {
- default: break;
+ default:
+ return nullptr;
case ARM::BI__builtin_arm_nop:
- HintID = 0;
- break;
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_hint),
+ llvm::ConstantInt::get(Int32Ty, 0));
case ARM::BI__builtin_arm_yield:
case ARM::BI__yield:
- HintID = 1;
- break;
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_hint),
+ llvm::ConstantInt::get(Int32Ty, 1));
case ARM::BI__builtin_arm_wfe:
case ARM::BI__wfe:
- HintID = 2;
- break;
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_hint),
+ llvm::ConstantInt::get(Int32Ty, 2));
case ARM::BI__builtin_arm_wfi:
case ARM::BI__wfi:
- HintID = 3;
- break;
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_hint),
+ llvm::ConstantInt::get(Int32Ty, 3));
case ARM::BI__builtin_arm_sev:
case ARM::BI__sev:
- HintID = 4;
- break;
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_hint),
+ llvm::ConstantInt::get(Int32Ty, 4));
case ARM::BI__builtin_arm_sevl:
case ARM::BI__sevl:
- HintID = 5;
- break;
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_hint),
+ llvm::ConstantInt::get(Int32Ty, 5));
}
+}
- if (HintID != static_cast<unsigned>(-1)) {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_hint);
- return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
+Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ if (auto Hint = GetValueForARMHint(BuiltinID))
+ return Hint;
+
+ if (BuiltinID == ARM::BI__emit) {
+ bool IsThumb = getTarget().getTriple().getArch() == llvm::Triple::thumb;
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(VoidTy, /*Variadic=*/false);
+
+ APSInt Value;
+ if (!E->getArg(0)->EvaluateAsInt(Value, CGM.getContext()))
+ llvm_unreachable("Sema will ensure that the parameter is constant");
+
+ uint64_t ZExtValue = Value.zextOrTrunc(IsThumb ? 16 : 32).getZExtValue();
+
+ llvm::InlineAsm *Emit =
+ IsThumb ? InlineAsm::get(FTy, ".inst.n 0x" + utohexstr(ZExtValue), "",
+ /*SideEffects=*/true)
+ : InlineAsm::get(FTy, ".inst 0x" + utohexstr(ZExtValue), "",
+ /*SideEffects=*/true);
+
+ return Builder.CreateCall(Emit);
+ }
+
+ if (BuiltinID == ARM::BI__builtin_arm_dbg) {
+ Value *Option = EmitScalarExpr(E->getArg(0));
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_dbg), Option);
+ }
+
+ if (BuiltinID == ARM::BI__builtin_arm_prefetch) {
+ Value *Address = EmitScalarExpr(E->getArg(0));
+ Value *RW = EmitScalarExpr(E->getArg(1));
+ Value *IsData = EmitScalarExpr(E->getArg(2));
+
+ // Locality is not supported on ARM target
+ Value *Locality = llvm::ConstantInt::get(Int32Ty, 3);
+
+ Value *F = CGM.getIntrinsic(Intrinsic::prefetch);
+ return Builder.CreateCall4(F, Address, RW, Locality, IsData);
}
if (BuiltinID == ARM::BI__builtin_arm_rbit) {
@@ -3157,7 +3288,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex
? Intrinsic::arm_stlexd
: Intrinsic::arm_strexd);
- llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, NULL);
+ llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, nullptr);
Value *Tmp = CreateMemTemp(E->getArg(0)->getType());
Value *Val = EmitScalarExpr(E->getArg(0));
@@ -3393,7 +3524,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Many NEON builtins have identical semantics and uses in ARM and
// AArch64. Emit these in a single function.
- ArrayRef<NeonIntrinsicInfo> IntrinsicMap(ARMSIMDIntrinsicMap);
+ auto IntrinsicMap = makeArrayRef(ARMSIMDIntrinsicMap);
const NeonIntrinsicInfo *Builtin = findNeonIntrinsicInMap(
IntrinsicMap, BuiltinID, NEONSIMDIntrinsicsProvenSorted);
if (Builtin)
@@ -3500,10 +3631,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vqrshrun_n_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqrshiftnsu, Ty),
Ops, "vqrshrun_n", 1, true);
- case NEON::BI__builtin_neon_vqshlu_n_v:
- case NEON::BI__builtin_neon_vqshluq_n_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqshiftsu, Ty),
- Ops, "vqshlu", 1, false);
case NEON::BI__builtin_neon_vqshrn_n_v:
Int = usgn ? Intrinsic::arm_neon_vqshiftnu : Intrinsic::arm_neon_vqshiftns;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrn_n",
@@ -3518,10 +3645,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vrshrn_n_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrshiftn, Ty),
Ops, "vrshrn_n", 1, true);
- case NEON::BI__builtin_neon_vrshr_n_v:
- case NEON::BI__builtin_neon_vrshrq_n_v:
- Int = usgn ? Intrinsic::arm_neon_vrshiftu : Intrinsic::arm_neon_vrshifts;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshr_n", 1, true);
case NEON::BI__builtin_neon_vrsra_n_v:
case NEON::BI__builtin_neon_vrsraq_n_v:
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -3836,6 +3959,29 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
}
+ if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
+ Value *Address = EmitScalarExpr(E->getArg(0));
+ Value *RW = EmitScalarExpr(E->getArg(1));
+ Value *CacheLevel = EmitScalarExpr(E->getArg(2));
+ Value *RetentionPolicy = EmitScalarExpr(E->getArg(3));
+ Value *IsData = EmitScalarExpr(E->getArg(4));
+
+ Value *Locality = nullptr;
+ if (cast<llvm::ConstantInt>(RetentionPolicy)->isZero()) {
+ // Temporal fetch, needs to convert cache level to locality.
+ Locality = llvm::ConstantInt::get(Int32Ty,
+ -cast<llvm::ConstantInt>(CacheLevel)->getValue() + 3);
+ } else {
+ // Streaming fetch.
+ Locality = llvm::ConstantInt::get(Int32Ty, 0);
+ }
+
+ // FIXME: We need AArch64 specific LLVM intrinsic if we want to specify
+ // PLDL3STRM or PLDL2STRM.
+ Value *F = CGM.getIntrinsic(Intrinsic::prefetch);
+ return Builder.CreateCall4(F, Address, RW, Locality, IsData);
+ }
+
if (BuiltinID == AArch64::BI__builtin_arm_rbit) {
assert((getContext().getTypeSize(E->getType()) == 32) &&
"rbit of unusual size!");
@@ -3913,7 +4059,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex
? Intrinsic::aarch64_stlxp
: Intrinsic::aarch64_stxp);
- llvm::Type *STy = llvm::StructType::get(Int64Ty, Int64Ty, NULL);
+ llvm::Type *STy = llvm::StructType::get(Int64Ty, Int64Ty, nullptr);
Value *One = llvm::ConstantInt::get(Int32Ty, 1);
Value *Tmp = Builder.CreateAlloca(ConvertType(E->getArg(0)->getType()),
@@ -3994,7 +4140,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++)
Ops.push_back(EmitScalarExpr(E->getArg(i)));
- ArrayRef<NeonIntrinsicInfo> SISDMap(AArch64SISDIntrinsicMap);
+ auto SISDMap = makeArrayRef(AArch64SISDIntrinsicMap);
const NeonIntrinsicInfo *Builtin = findNeonIntrinsicInMap(
SISDMap, BuiltinID, AArch64SISDIntrinsicsProvenSorted);
@@ -4675,38 +4821,19 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_frecps, f64Type),
Ops, "vrecps");
}
- case NEON::BI__builtin_neon_vrshr_n_v:
- case NEON::BI__builtin_neon_vrshrq_n_v:
- // FIXME: this can be shared with 32-bit ARM, but not AArch64 at the
- // moment. After the final merge it should be added to
- // EmitCommonNeonBuiltinExpr.
- Int = usgn ? Intrinsic::aarch64_neon_urshl : Intrinsic::aarch64_neon_srshl;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshr_n", 1, true);
- case NEON::BI__builtin_neon_vqshlu_n_v:
- case NEON::BI__builtin_neon_vqshluq_n_v:
- // FIXME: AArch64 and ARM use different intrinsics for this, but are
- // essentially compatible. It should be in EmitCommonNeonBuiltinExpr after
- // the final merge.
- Int = Intrinsic::aarch64_neon_sqshlu;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshlu_n", 1, false);
case NEON::BI__builtin_neon_vqshrun_n_v:
- // FIXME: as above
Int = Intrinsic::aarch64_neon_sqshrun;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrun_n");
case NEON::BI__builtin_neon_vqrshrun_n_v:
- // FIXME: and again.
Int = Intrinsic::aarch64_neon_sqrshrun;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrun_n");
case NEON::BI__builtin_neon_vqshrn_n_v:
- // FIXME: guess
Int = usgn ? Intrinsic::aarch64_neon_uqshrn : Intrinsic::aarch64_neon_sqshrn;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrn_n");
case NEON::BI__builtin_neon_vrshrn_n_v:
- // FIXME: there might be a pattern here.
Int = Intrinsic::aarch64_neon_rshrn;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshrn_n");
case NEON::BI__builtin_neon_vqrshrn_n_v:
- // FIXME: another one
Int = usgn ? Intrinsic::aarch64_neon_uqrshrn : Intrinsic::aarch64_neon_sqrshrn;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n");
case NEON::BI__builtin_neon_vrnda_v:
@@ -5435,8 +5562,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateZExt(Ops[3],
llvm::IntegerType::get(getLLVMContext(), 64));
- Ops[1] = Builder.CreateCall(F,
- ArrayRef<Value*>(Ops).slice(1), "vld2_lane");
+ Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld2_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
@@ -5452,8 +5578,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateZExt(Ops[4],
llvm::IntegerType::get(getLLVMContext(), 64));
- Ops[1] = Builder.CreateCall(F,
- ArrayRef<Value*>(Ops).slice(1), "vld3_lane");
+ Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
@@ -5470,8 +5595,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
Ops[5] = Builder.CreateZExt(Ops[5],
llvm::IntegerType::get(getLLVMContext(), 64));
- Ops[1] = Builder.CreateCall(F,
- ArrayRef<Value*>(Ops).slice(1), "vld4_lane");
+ Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld4_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
@@ -5757,7 +5881,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q);
- return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr");
+ return Builder.CreateCall(F, makeArrayRef(Ops.data(), 2), "palignr");
}
// If palignr is shifting the pair of vectors more than 16 bytes, emit zero.
@@ -5787,7 +5911,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq);
- return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr");
+ return Builder.CreateCall(F, makeArrayRef(Ops.data(), 2), "palignr");
}
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
@@ -5825,7 +5949,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_avx2_psrl_dq);
- return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr");
+ return Builder.CreateCall(F, makeArrayRef(Ops.data(), 2), "palignr");
}
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
@@ -5839,8 +5963,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_movntdq256:
case X86::BI__builtin_ia32_movnti:
case X86::BI__builtin_ia32_movnti64: {
- llvm::MDNode *Node = llvm::MDNode::get(getLLVMContext(),
- Builder.getInt32(1));
+ llvm::MDNode *Node = llvm::MDNode::get(
+ getLLVMContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
// Convert the type of the pointer to a pointer to the stored type.
Value *BC = Builder.CreateBitCast(Ops[0],
@@ -5863,8 +5987,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// 3DNow!
case X86::BI__builtin_ia32_pswapdsf:
case X86::BI__builtin_ia32_pswapdsi: {
- const char *name = nullptr;
- Intrinsic::ID ID = Intrinsic::not_intrinsic;
+ const char *name;
+ Intrinsic::ID ID;
switch(BuiltinID) {
default: llvm_unreachable("Unsupported intrinsic!");
case X86::BI__builtin_ia32_pswapdsf:
@@ -5918,6 +6042,154 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Value *F = CGM.getIntrinsic(Intrinsic::x86_avx2_vbroadcasti128);
return Builder.CreateCall(F, Builder.CreateBitCast(VecTmp, Int8PtrTy));
}
+ // SSE comparison intrisics
+ case X86::BI__builtin_ia32_cmpeqps:
+ case X86::BI__builtin_ia32_cmpltps:
+ case X86::BI__builtin_ia32_cmpleps:
+ case X86::BI__builtin_ia32_cmpunordps:
+ case X86::BI__builtin_ia32_cmpneqps:
+ case X86::BI__builtin_ia32_cmpnltps:
+ case X86::BI__builtin_ia32_cmpnleps:
+ case X86::BI__builtin_ia32_cmpordps:
+ case X86::BI__builtin_ia32_cmpeqss:
+ case X86::BI__builtin_ia32_cmpltss:
+ case X86::BI__builtin_ia32_cmpless:
+ case X86::BI__builtin_ia32_cmpunordss:
+ case X86::BI__builtin_ia32_cmpneqss:
+ case X86::BI__builtin_ia32_cmpnltss:
+ case X86::BI__builtin_ia32_cmpnless:
+ case X86::BI__builtin_ia32_cmpordss:
+ case X86::BI__builtin_ia32_cmpeqpd:
+ case X86::BI__builtin_ia32_cmpltpd:
+ case X86::BI__builtin_ia32_cmplepd:
+ case X86::BI__builtin_ia32_cmpunordpd:
+ case X86::BI__builtin_ia32_cmpneqpd:
+ case X86::BI__builtin_ia32_cmpnltpd:
+ case X86::BI__builtin_ia32_cmpnlepd:
+ case X86::BI__builtin_ia32_cmpordpd:
+ case X86::BI__builtin_ia32_cmpeqsd:
+ case X86::BI__builtin_ia32_cmpltsd:
+ case X86::BI__builtin_ia32_cmplesd:
+ case X86::BI__builtin_ia32_cmpunordsd:
+ case X86::BI__builtin_ia32_cmpneqsd:
+ case X86::BI__builtin_ia32_cmpnltsd:
+ case X86::BI__builtin_ia32_cmpnlesd:
+ case X86::BI__builtin_ia32_cmpordsd:
+ // These exist so that the builtin that takes an immediate can be bounds
+ // checked by clang to avoid passing bad immediates to the backend. Since
+ // AVX has a larger immediate than SSE we would need separate builtins to
+ // do the different bounds checking. Rather than create a clang specific
+ // SSE only builtin, this implements eight separate builtins to match gcc
+ // implementation.
+
+ // Choose the immediate.
+ unsigned Imm;
+ switch (BuiltinID) {
+ default: llvm_unreachable("Unsupported intrinsic!");
+ case X86::BI__builtin_ia32_cmpeqps:
+ case X86::BI__builtin_ia32_cmpeqss:
+ case X86::BI__builtin_ia32_cmpeqpd:
+ case X86::BI__builtin_ia32_cmpeqsd:
+ Imm = 0;
+ break;
+ case X86::BI__builtin_ia32_cmpltps:
+ case X86::BI__builtin_ia32_cmpltss:
+ case X86::BI__builtin_ia32_cmpltpd:
+ case X86::BI__builtin_ia32_cmpltsd:
+ Imm = 1;
+ break;
+ case X86::BI__builtin_ia32_cmpleps:
+ case X86::BI__builtin_ia32_cmpless:
+ case X86::BI__builtin_ia32_cmplepd:
+ case X86::BI__builtin_ia32_cmplesd:
+ Imm = 2;
+ break;
+ case X86::BI__builtin_ia32_cmpunordps:
+ case X86::BI__builtin_ia32_cmpunordss:
+ case X86::BI__builtin_ia32_cmpunordpd:
+ case X86::BI__builtin_ia32_cmpunordsd:
+ Imm = 3;
+ break;
+ case X86::BI__builtin_ia32_cmpneqps:
+ case X86::BI__builtin_ia32_cmpneqss:
+ case X86::BI__builtin_ia32_cmpneqpd:
+ case X86::BI__builtin_ia32_cmpneqsd:
+ Imm = 4;
+ break;
+ case X86::BI__builtin_ia32_cmpnltps:
+ case X86::BI__builtin_ia32_cmpnltss:
+ case X86::BI__builtin_ia32_cmpnltpd:
+ case X86::BI__builtin_ia32_cmpnltsd:
+ Imm = 5;
+ break;
+ case X86::BI__builtin_ia32_cmpnleps:
+ case X86::BI__builtin_ia32_cmpnless:
+ case X86::BI__builtin_ia32_cmpnlepd:
+ case X86::BI__builtin_ia32_cmpnlesd:
+ Imm = 6;
+ break;
+ case X86::BI__builtin_ia32_cmpordps:
+ case X86::BI__builtin_ia32_cmpordss:
+ case X86::BI__builtin_ia32_cmpordpd:
+ case X86::BI__builtin_ia32_cmpordsd:
+ Imm = 7;
+ break;
+ }
+
+ // Choose the intrinsic ID.
+ const char *name;
+ Intrinsic::ID ID;
+ switch (BuiltinID) {
+ default: llvm_unreachable("Unsupported intrinsic!");
+ case X86::BI__builtin_ia32_cmpeqps:
+ case X86::BI__builtin_ia32_cmpltps:
+ case X86::BI__builtin_ia32_cmpleps:
+ case X86::BI__builtin_ia32_cmpunordps:
+ case X86::BI__builtin_ia32_cmpneqps:
+ case X86::BI__builtin_ia32_cmpnltps:
+ case X86::BI__builtin_ia32_cmpnleps:
+ case X86::BI__builtin_ia32_cmpordps:
+ name = "cmpps";
+ ID = Intrinsic::x86_sse_cmp_ps;
+ break;
+ case X86::BI__builtin_ia32_cmpeqss:
+ case X86::BI__builtin_ia32_cmpltss:
+ case X86::BI__builtin_ia32_cmpless:
+ case X86::BI__builtin_ia32_cmpunordss:
+ case X86::BI__builtin_ia32_cmpneqss:
+ case X86::BI__builtin_ia32_cmpnltss:
+ case X86::BI__builtin_ia32_cmpnless:
+ case X86::BI__builtin_ia32_cmpordss:
+ name = "cmpss";
+ ID = Intrinsic::x86_sse_cmp_ss;
+ break;
+ case X86::BI__builtin_ia32_cmpeqpd:
+ case X86::BI__builtin_ia32_cmpltpd:
+ case X86::BI__builtin_ia32_cmplepd:
+ case X86::BI__builtin_ia32_cmpunordpd:
+ case X86::BI__builtin_ia32_cmpneqpd:
+ case X86::BI__builtin_ia32_cmpnltpd:
+ case X86::BI__builtin_ia32_cmpnlepd:
+ case X86::BI__builtin_ia32_cmpordpd:
+ name = "cmppd";
+ ID = Intrinsic::x86_sse2_cmp_pd;
+ break;
+ case X86::BI__builtin_ia32_cmpeqsd:
+ case X86::BI__builtin_ia32_cmpltsd:
+ case X86::BI__builtin_ia32_cmplesd:
+ case X86::BI__builtin_ia32_cmpunordsd:
+ case X86::BI__builtin_ia32_cmpneqsd:
+ case X86::BI__builtin_ia32_cmpnltsd:
+ case X86::BI__builtin_ia32_cmpnlesd:
+ case X86::BI__builtin_ia32_cmpordsd:
+ name = "cmpsd";
+ ID = Intrinsic::x86_sse2_cmp_sd;
+ break;
+ }
+
+ Ops.push_back(llvm::ConstantInt::get(Int8Ty, Imm));
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, Ops, name);
}
}
@@ -5942,6 +6214,8 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
case PPC::BI__builtin_altivec_lvewx:
case PPC::BI__builtin_altivec_lvsl:
case PPC::BI__builtin_altivec_lvsr:
+ case PPC::BI__builtin_vsx_lxvd2x:
+ case PPC::BI__builtin_vsx_lxvw4x:
{
Ops[1] = Builder.CreateBitCast(Ops[1], Int8PtrTy);
@@ -5971,6 +6245,12 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
case PPC::BI__builtin_altivec_lvsr:
ID = Intrinsic::ppc_altivec_lvsr;
break;
+ case PPC::BI__builtin_vsx_lxvd2x:
+ ID = Intrinsic::ppc_vsx_lxvd2x;
+ break;
+ case PPC::BI__builtin_vsx_lxvw4x:
+ ID = Intrinsic::ppc_vsx_lxvw4x;
+ break;
}
llvm::Function *F = CGM.getIntrinsic(ID);
return Builder.CreateCall(F, Ops, "");
@@ -5982,6 +6262,8 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
case PPC::BI__builtin_altivec_stvebx:
case PPC::BI__builtin_altivec_stvehx:
case PPC::BI__builtin_altivec_stvewx:
+ case PPC::BI__builtin_vsx_stxvd2x:
+ case PPC::BI__builtin_vsx_stxvw4x:
{
Ops[2] = Builder.CreateBitCast(Ops[2], Int8PtrTy);
Ops[1] = Builder.CreateGEP(Ops[2], Ops[1]);
@@ -6004,6 +6286,12 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
case PPC::BI__builtin_altivec_stvewx:
ID = Intrinsic::ppc_altivec_stvewx;
break;
+ case PPC::BI__builtin_vsx_stxvd2x:
+ ID = Intrinsic::ppc_vsx_stxvd2x;
+ break;
+ case PPC::BI__builtin_vsx_stxvw4x:
+ ID = Intrinsic::ppc_vsx_stxvw4x;
+ break;
}
llvm::Function *F = CGM.getIntrinsic(ID);
return Builder.CreateCall(F, Ops, "");
@@ -6033,6 +6321,17 @@ static Value *emitTernaryFPBuiltin(CodeGenFunction &CGF,
return CGF.Builder.CreateCall3(F, Src0, Src1, Src2);
}
+// Emit an intrinsic that has 1 float or double operand, and 1 integer.
+static Value *emitFPIntBuiltin(CodeGenFunction &CGF,
+ const CallExpr *E,
+ unsigned IntrinsicID) {
+ llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
+ llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
+
+ Value *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
+ return CGF.Builder.CreateCall2(F, Src0, Src1);
+}
+
Value *CodeGenFunction::EmitR600BuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
switch (BuiltinID) {
@@ -6065,18 +6364,23 @@ Value *CodeGenFunction::EmitR600BuiltinExpr(unsigned BuiltinID,
return Result;
}
case R600::BI__builtin_amdgpu_div_fmas:
- case R600::BI__builtin_amdgpu_div_fmasf:
- return emitTernaryFPBuiltin(*this, E, Intrinsic::AMDGPU_div_fmas);
+ case R600::BI__builtin_amdgpu_div_fmasf: {
+ llvm::Value *Src0 = EmitScalarExpr(E->getArg(0));
+ llvm::Value *Src1 = EmitScalarExpr(E->getArg(1));
+ llvm::Value *Src2 = EmitScalarExpr(E->getArg(2));
+ llvm::Value *Src3 = EmitScalarExpr(E->getArg(3));
+
+ llvm::Value *F = CGM.getIntrinsic(Intrinsic::AMDGPU_div_fmas,
+ Src0->getType());
+ llvm::Value *Src3ToBool = Builder.CreateIsNotNull(Src3);
+ return Builder.CreateCall4(F, Src0, Src1, Src2, Src3ToBool);
+ }
case R600::BI__builtin_amdgpu_div_fixup:
case R600::BI__builtin_amdgpu_div_fixupf:
return emitTernaryFPBuiltin(*this, E, Intrinsic::AMDGPU_div_fixup);
case R600::BI__builtin_amdgpu_trig_preop:
- case R600::BI__builtin_amdgpu_trig_preopf: {
- Value *Src0 = EmitScalarExpr(E->getArg(0));
- Value *Src1 = EmitScalarExpr(E->getArg(1));
- Value *F = CGM.getIntrinsic(Intrinsic::AMDGPU_trig_preop, Src0->getType());
- return Builder.CreateCall2(F, Src0, Src1);
- }
+ case R600::BI__builtin_amdgpu_trig_preopf:
+ return emitFPIntBuiltin(*this, E, Intrinsic::AMDGPU_trig_preop);
case R600::BI__builtin_amdgpu_rcp:
case R600::BI__builtin_amdgpu_rcpf:
return emitUnaryFPBuiltin(*this, E, Intrinsic::AMDGPU_rcp);
@@ -6086,6 +6390,12 @@ Value *CodeGenFunction::EmitR600BuiltinExpr(unsigned BuiltinID,
case R600::BI__builtin_amdgpu_rsq_clamped:
case R600::BI__builtin_amdgpu_rsq_clampedf:
return emitUnaryFPBuiltin(*this, E, Intrinsic::AMDGPU_rsq_clamped);
+ case R600::BI__builtin_amdgpu_ldexp:
+ case R600::BI__builtin_amdgpu_ldexpf:
+ return emitFPIntBuiltin(*this, E, Intrinsic::AMDGPU_ldexp);
+ case R600::BI__builtin_amdgpu_class:
+ case R600::BI__builtin_amdgpu_classf:
+ return emitFPIntBuiltin(*this, E, Intrinsic::AMDGPU_class);
default:
return nullptr;
}
diff --git a/lib/CodeGen/CGCUDARuntime.cpp b/lib/CodeGen/CGCUDARuntime.cpp
index 29e0a91a63fe..014a5dbd46d6 100644
--- a/lib/CodeGen/CGCUDARuntime.cpp
+++ b/lib/CodeGen/CGCUDARuntime.cpp
@@ -45,8 +45,7 @@ RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
}
llvm::Value *Callee = CGF.EmitScalarExpr(E->getCallee());
- CGF.EmitCall(E->getCallee()->getType(), Callee, E->getLocStart(),
- ReturnValue, E->arg_begin(), E->arg_end(), TargetDecl);
+ CGF.EmitCall(E->getCallee()->getType(), Callee, E, ReturnValue, TargetDecl);
CGF.EmitBranch(ContBlock);
CGF.EmitBlock(ContBlock);
diff --git a/lib/CodeGen/CGCUDARuntime.h b/lib/CodeGen/CGCUDARuntime.h
index a99a67ae1ae7..8c162fb05ab9 100644
--- a/lib/CodeGen/CGCUDARuntime.h
+++ b/lib/CodeGen/CGCUDARuntime.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CUDARUNTIME_H
-#define CLANG_CODEGEN_CUDARUNTIME_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGCUDARUNTIME_H
+#define LLVM_CLANG_LIB_CODEGEN_CGCUDARUNTIME_H
namespace clang {
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 545c5ef9f827..9f0e67e42176 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -44,12 +44,13 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
if (!D->hasTrivialBody())
return true;
- // For exported destructors, we need a full definition.
- if (D->hasAttr<DLLExportAttr>())
- return true;
-
const CXXRecordDecl *Class = D->getParent();
+ // We are going to instrument this destructor, so give up even if it is
+ // currently empty.
+ if (Class->mayInsertExtraPadding())
+ return true;
+
// If we need to manipulate a VTT parameter, give up.
if (Class->getNumVBases()) {
// Extra Credit: passing extra parameters is perfectly safe
@@ -123,6 +124,11 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
if (!llvm::GlobalAlias::isValidLinkage(Linkage))
return true;
+ // Don't create a weak alias for a dllexport'd symbol.
+ if (AliasDecl.getDecl()->hasAttr<DLLExportAttr>() &&
+ llvm::GlobalValue::isWeakForLinker(Linkage))
+ return true;
+
llvm::GlobalValue::LinkageTypes TargetLinkage =
getFunctionLinkage(TargetDecl);
@@ -161,9 +167,9 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
}
if (!InEveryTU) {
- /// If we don't have a definition for the destructor yet, don't
- /// emit. We can't emit aliases to declarations; that's just not
- /// how aliases work.
+ // If we don't have a definition for the destructor yet, don't
+ // emit. We can't emit aliases to declarations; that's just not
+ // how aliases work.
if (Ref->isDeclaration())
return true;
}
@@ -191,114 +197,55 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
}
// Finally, set up the alias with its proper name and attributes.
- SetCommonAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
+ setAliasAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
return false;
}
-void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor,
- CXXCtorType ctorType) {
- if (!getTarget().getCXXABI().hasConstructorVariants()) {
- // If there are no constructor variants, always emit the complete destructor.
- ctorType = Ctor_Complete;
- } else if (!ctor->getParent()->getNumVBases() &&
- (ctorType == Ctor_Complete || ctorType == Ctor_Base)) {
- // The complete constructor is equivalent to the base constructor
- // for classes with no virtual bases. Try to emit it as an alias.
- bool ProducedAlias =
- !TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete),
- GlobalDecl(ctor, Ctor_Base), true);
- if (ctorType == Ctor_Complete && ProducedAlias)
- return;
- }
+llvm::Function *CodeGenModule::codegenCXXStructor(const CXXMethodDecl *MD,
+ StructorType Type) {
+ const CGFunctionInfo &FnInfo =
+ getTypes().arrangeCXXStructorDeclaration(MD, Type);
+ auto *Fn = cast<llvm::Function>(
+ getAddrOfCXXStructor(MD, Type, &FnInfo, nullptr, true));
- const CGFunctionInfo &fnInfo =
- getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType);
-
- auto *fn = cast<llvm::Function>(
- GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo, true));
- setFunctionLinkage(GlobalDecl(ctor, ctorType), fn);
-
- CodeGenFunction(*this).GenerateCode(GlobalDecl(ctor, ctorType), fn, fnInfo);
-
- setFunctionDefinitionAttributes(ctor, fn);
- SetLLVMFunctionAttributesForDefinition(ctor, fn);
-}
-
-llvm::GlobalValue *
-CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
- CXXCtorType ctorType,
- const CGFunctionInfo *fnInfo,
- bool DontDefer) {
- GlobalDecl GD(ctor, ctorType);
-
- StringRef name = getMangledName(GD);
- if (llvm::GlobalValue *existing = GetGlobalValue(name))
- return existing;
-
- if (!fnInfo)
- fnInfo = &getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType);
+ GlobalDecl GD;
+ if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ GD = GlobalDecl(DD, toCXXDtorType(Type));
+ } else {
+ const auto *CD = cast<CXXConstructorDecl>(MD);
+ GD = GlobalDecl(CD, toCXXCtorType(Type));
+ }
- llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo);
- return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
- /*ForVTable=*/false,
- DontDefer));
+ setFunctionLinkage(GD, Fn);
+ CodeGenFunction(*this).GenerateCode(GD, Fn, FnInfo);
+ setFunctionDefinitionAttributes(MD, Fn);
+ SetLLVMFunctionAttributesForDefinition(MD, Fn);
+ return Fn;
}
-void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
- CXXDtorType dtorType) {
- // The complete destructor is equivalent to the base destructor for
- // classes with no virtual bases, so try to emit it as an alias.
- if (!dtor->getParent()->getNumVBases() &&
- (dtorType == Dtor_Complete || dtorType == Dtor_Base)) {
- bool ProducedAlias =
- !TryEmitDefinitionAsAlias(GlobalDecl(dtor, Dtor_Complete),
- GlobalDecl(dtor, Dtor_Base), true);
- if (ProducedAlias) {
- if (dtorType == Dtor_Complete)
- return;
- if (dtor->isVirtual())
- getVTables().EmitThunks(GlobalDecl(dtor, Dtor_Complete));
- }
+llvm::GlobalValue *CodeGenModule::getAddrOfCXXStructor(
+ const CXXMethodDecl *MD, StructorType Type, const CGFunctionInfo *FnInfo,
+ llvm::FunctionType *FnType, bool DontDefer) {
+ GlobalDecl GD;
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
+ GD = GlobalDecl(CD, toCXXCtorType(Type));
+ } else {
+ auto *DD = dyn_cast<CXXDestructorDecl>(MD);
+ GD = GlobalDecl(DD, toCXXDtorType(Type));
}
- // The base destructor is equivalent to the base destructor of its
- // base class if there is exactly one non-virtual base class with a
- // non-trivial destructor, there are no fields with a non-trivial
- // destructor, and the body of the destructor is trivial.
- if (dtorType == Dtor_Base && !TryEmitBaseDestructorAsAlias(dtor))
- return;
+ StringRef Name = getMangledName(GD);
+ if (llvm::GlobalValue *Existing = GetGlobalValue(Name))
+ return Existing;
- const CGFunctionInfo &fnInfo =
- getTypes().arrangeCXXDestructor(dtor, dtorType);
-
- auto *fn = cast<llvm::Function>(
- GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo, nullptr, true));
- setFunctionLinkage(GlobalDecl(dtor, dtorType), fn);
-
- CodeGenFunction(*this).GenerateCode(GlobalDecl(dtor, dtorType), fn, fnInfo);
-
- setFunctionDefinitionAttributes(dtor, fn);
- SetLLVMFunctionAttributesForDefinition(dtor, fn);
-}
-
-llvm::GlobalValue *
-CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
- CXXDtorType dtorType,
- const CGFunctionInfo *fnInfo,
- llvm::FunctionType *fnType,
- bool DontDefer) {
- GlobalDecl GD(dtor, dtorType);
-
- StringRef name = getMangledName(GD);
- if (llvm::GlobalValue *existing = GetGlobalValue(name))
- return existing;
-
- if (!fnType) {
- if (!fnInfo) fnInfo = &getTypes().arrangeCXXDestructor(dtor, dtorType);
- fnType = getTypes().GetFunctionType(*fnInfo);
+ if (!FnType) {
+ if (!FnInfo)
+ FnInfo = &getTypes().arrangeCXXStructorDeclaration(MD, Type);
+ FnType = getTypes().GetFunctionType(*FnInfo);
}
- return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
+
+ return cast<llvm::Function>(GetOrCreateLLVMFunction(Name, FnType, GD,
/*ForVTable=*/false,
DontDefer));
}
@@ -360,8 +307,8 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
// -O does that. But need to support -O0 as well.
if (MD->isVirtual() && Type != Dtor_Base) {
// Compute the function type we're calling.
- const CGFunctionInfo &FInfo =
- CGM.getTypes().arrangeCXXDestructor(DD, Dtor_Complete);
+ const CGFunctionInfo &FInfo = CGM.getTypes().arrangeCXXStructorDeclaration(
+ DD, StructorType::Complete);
llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo);
return ::BuildAppleKextVirtualCall(*this, GlobalDecl(DD, Type), Ty, RD);
}
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 55ddd666c490..d31331de6868 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -246,17 +246,6 @@ llvm::Value *CGCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
return llvm::ConstantInt::get(CGF.SizeTy, 0);
}
-void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
- const VarDecl &D,
- llvm::Constant *dtor,
- llvm::Constant *addr) {
- if (D.getTLSKind())
- CGM.ErrorUnsupported(&D, "non-trivial TLS destruction");
-
- // The default behavior is to use atexit.
- CGF.registerGlobalDtorWithAtExit(D, dtor, addr);
-}
-
/// Returns the adjustment, in bytes, required for the given
/// member-pointer operation. Returns null if no adjustment is
/// required.
@@ -310,18 +299,6 @@ CGCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
return nullptr;
}
-void CGCXXABI::EmitThreadLocalInitFuncs(
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
- llvm::Function *InitFunc) {
-}
-
-LValue CGCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
- const VarDecl *VD,
- QualType LValType) {
- ErrorUnsupportedABI(CGF, "odr-use of thread_local global");
- return LValue();
-}
-
bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) {
return false;
}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 91e49707bae6..cc5c1b2e0ae6 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CXXABI_H
-#define CLANG_CODEGEN_CXXABI_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGCXXABI_H
+#define LLVM_CLANG_LIB_CODEGEN_CGCXXABI_H
#include "CodeGenFunction.h"
#include "clang/Basic/LLVM.h"
@@ -93,6 +93,8 @@ public:
/// when called virtually, and code generation does not support the case.
virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
+ virtual bool hasMostDerivedReturn(GlobalDecl GD) const { return false; }
+
/// If the C++ ABI requires the given type be returned in a particular way,
/// this method sets RetAI and returns true.
virtual bool classifyReturnType(CGFunctionInfo &FI) const = 0;
@@ -156,6 +158,15 @@ public:
/// (in the C++ sense) with an LLVM zeroinitializer.
virtual bool isZeroInitializable(const MemberPointerType *MPT);
+ /// Return whether or not a member pointers type is convertible to an IR type.
+ virtual bool isMemberPointerConvertible(const MemberPointerType *MPT) const {
+ return true;
+ }
+
+ virtual bool isTypeInfoCalculable(QualType Ty) const {
+ return !Ty->isIncompleteType();
+ }
+
/// Create a null member pointer of the given type.
virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
@@ -198,14 +209,11 @@ protected:
CharUnits getMemberPointerPathAdjustment(const APValue &MP);
public:
- /// Adjust the given non-null pointer to an object of polymorphic
- /// type to point to the complete object.
- ///
- /// The IR type of the result should be a pointer but is otherwise
- /// irrelevant.
- virtual llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
- llvm::Value *ptr,
- QualType type) = 0;
+ virtual void emitVirtualObjectDelete(CodeGenFunction &CGF,
+ const CXXDeleteExpr *DE,
+ llvm::Value *Ptr, QualType ElementType,
+ const CXXDestructorDecl *Dtor) = 0;
+ virtual void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) = 0;
virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;
@@ -236,20 +244,6 @@ public:
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) = 0;
- /// Build the signature of the given constructor variant by adding
- /// any required parameters. For convenience, ArgTys has been initialized
- /// with the type of 'this' and ResTy has been initialized with the type of
- /// 'this' if HasThisReturn(GlobalDecl(Ctor, T)) is true or 'void' otherwise
- /// (although both may be changed by the ABI).
- ///
- /// If there are ever any ABIs where the implicit parameters are
- /// intermixed with the formal parameters, we can address those
- /// then.
- virtual void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType T,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) = 0;
-
virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
const CXXRecordDecl *RD);
@@ -262,15 +256,11 @@ public:
/// Emit constructor variants required by this ABI.
virtual void EmitCXXConstructors(const CXXConstructorDecl *D) = 0;
- /// Build the signature of the given destructor variant by adding
- /// any required parameters. For convenience, ArgTys has been initialized
- /// with the type of 'this' and ResTy has been initialized with the type of
- /// 'this' if HasThisReturn(GlobalDecl(Dtor, T)) is true or 'void' otherwise
- /// (although both may be changed by the ABI).
- virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
- CXXDtorType T,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) = 0;
+ /// Build the signature of the given constructor or destructor variant by
+ /// adding any required parameters. For convenience, ArgTys has been
+ /// initialized with the type of 'this'.
+ virtual void buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
+ SmallVectorImpl<CanQualType> &ArgTys) = 0;
/// Returns true if the given destructor type should be emitted as a linkonce
/// delegating thunk, regardless of whether the dtor is defined in this TU or
@@ -368,11 +358,10 @@ public:
llvm::Type *Ty) = 0;
/// Emit the ABI-specific virtual destructor call.
- virtual void EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- SourceLocation CallLoc,
- llvm::Value *This) = 0;
+ virtual llvm::Value *
+ EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType, llvm::Value *This,
+ const CXXMemberCallExpr *CE) = 0;
virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF,
GlobalDecl GD,
@@ -397,6 +386,9 @@ public:
virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
RValue RV, QualType ResultType);
+ virtual size_t getSrcArgforCopyCtor(const CXXConstructorDecl *,
+ FunctionArgList &Args) const = 0;
+
/// Gets the pure virtual member call function.
virtual StringRef GetPureVirtualCallName() = 0;
@@ -490,30 +482,44 @@ public:
/// Emit code to force the execution of a destructor during global
/// teardown. The default implementation of this uses atexit.
///
- /// \param dtor - a function taking a single pointer argument
- /// \param addr - a pointer to pass to the destructor function.
+ /// \param Dtor - a function taking a single pointer argument
+ /// \param Addr - a pointer to pass to the destructor function.
virtual void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
- llvm::Constant *dtor, llvm::Constant *addr);
+ llvm::Constant *Dtor,
+ llvm::Constant *Addr) = 0;
/*************************** thread_local initialization ********************/
/// Emits ABI-required functions necessary to initialize thread_local
/// variables in this translation unit.
///
- /// \param Decls The thread_local declarations in this translation unit.
- /// \param InitFunc If this translation unit contains any non-constant
- /// initialization or non-trivial destruction for thread_local
- /// variables, a function to perform the initialization. Otherwise, 0.
+ /// \param CXXThreadLocals - The thread_local declarations in this translation
+ /// unit.
+ /// \param CXXThreadLocalInits - If this translation unit contains any
+ /// non-constant initialization or non-trivial destruction for
+ /// thread_local variables, a list of functions to perform the
+ /// initialization.
virtual void EmitThreadLocalInitFuncs(
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
- llvm::Function *InitFunc);
+ CodeGenModule &CGM,
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
+ CXXThreadLocals,
+ ArrayRef<llvm::Function *> CXXThreadLocalInits,
+ ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) = 0;
+
+ // Determine if references to thread_local global variables can be made
+ // directly or require access through a thread wrapper function.
+ virtual bool usesThreadWrapperFunction() const = 0;
/// Emit a reference to a non-local thread_local variable (including
/// triggering the initialization of all thread_local variables in its
/// translation unit).
virtual LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
const VarDecl *VD,
- QualType LValType);
+ QualType LValType) = 0;
+
+ /// Emit a single constructor/destructor with the given type from a C++
+ /// constructor Decl.
+ virtual void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) = 0;
};
// Create an instance of a C++ ABI class:
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 17c3354f93e9..6403fa99aa7b 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -47,7 +47,10 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS;
case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
case CC_IntelOclBicc: return llvm::CallingConv::Intel_OCL_BI;
- // TODO: add support for CC_X86Pascal to llvm
+ // TODO: Add support for __pascal to LLVM.
+ case CC_X86Pascal: return llvm::CallingConv::C;
+ // TODO: Add support for __vectorcall to LLVM.
+ case CC_X86VectorCall: return llvm::CallingConv::X86_VectorCall;
}
}
@@ -80,42 +83,25 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
// When translating an unprototyped function type, always use a
// variadic type.
return arrangeLLVMFunctionInfo(FTNP->getReturnType().getUnqualifiedType(),
- false, None, FTNP->getExtInfo(),
- RequiredArgs(0));
+ /*instanceMethod=*/false,
+ /*chainCall=*/false, None,
+ FTNP->getExtInfo(), RequiredArgs(0));
}
/// Arrange the LLVM function layout for a value of the given function
-/// type, on top of any implicit parameters already stored. Use the
-/// given ExtInfo instead of the ExtInfo from the function type.
-static const CGFunctionInfo &arrangeLLVMFunctionInfo(CodeGenTypes &CGT,
- bool IsInstanceMethod,
- SmallVectorImpl<CanQualType> &prefix,
- CanQual<FunctionProtoType> FTP,
- FunctionType::ExtInfo extInfo) {
+/// type, on top of any implicit parameters already stored.
+static const CGFunctionInfo &
+arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod,
+ SmallVectorImpl<CanQualType> &prefix,
+ CanQual<FunctionProtoType> FTP) {
RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, prefix.size());
// FIXME: Kill copy.
for (unsigned i = 0, e = FTP->getNumParams(); i != e; ++i)
prefix.push_back(FTP->getParamType(i));
CanQualType resultType = FTP->getReturnType().getUnqualifiedType();
- return CGT.arrangeLLVMFunctionInfo(resultType, IsInstanceMethod, prefix,
- extInfo, required);
-}
-
-/// Arrange the argument and result information for a free function (i.e.
-/// not a C++ or ObjC instance method) of the given type.
-static const CGFunctionInfo &arrangeFreeFunctionType(CodeGenTypes &CGT,
- SmallVectorImpl<CanQualType> &prefix,
- CanQual<FunctionProtoType> FTP) {
- return arrangeLLVMFunctionInfo(CGT, false, prefix, FTP, FTP->getExtInfo());
-}
-
-/// Arrange the argument and result information for a free function (i.e.
-/// not a C++ or ObjC instance method) of the given type.
-static const CGFunctionInfo &arrangeCXXMethodType(CodeGenTypes &CGT,
- SmallVectorImpl<CanQualType> &prefix,
- CanQual<FunctionProtoType> FTP) {
- FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- return arrangeLLVMFunctionInfo(CGT, true, prefix, FTP, extInfo);
+ return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod,
+ /*chainCall=*/false, prefix,
+ FTP->getExtInfo(), required);
}
/// Arrange the argument and result information for a value of the
@@ -123,7 +109,8 @@ static const CGFunctionInfo &arrangeCXXMethodType(CodeGenTypes &CGT,
const CGFunctionInfo &
CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> FTP) {
SmallVector<CanQualType, 16> argTypes;
- return ::arrangeFreeFunctionType(*this, argTypes, FTP);
+ return ::arrangeLLVMFunctionInfo(*this, /*instanceMethod=*/false, argTypes,
+ FTP);
}
static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
@@ -137,6 +124,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
if (D->hasAttr<ThisCallAttr>())
return CC_X86ThisCall;
+ if (D->hasAttr<VectorCallAttr>())
+ return CC_X86VectorCall;
+
if (D->hasAttr<PascalAttr>())
return CC_X86Pascal;
@@ -158,23 +148,6 @@ static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
return CC_C;
}
-static bool isAAPCSVFP(const CGFunctionInfo &FI, const TargetInfo &Target) {
- switch (FI.getEffectiveCallingConvention()) {
- case llvm::CallingConv::C:
- switch (Target.getTriple().getEnvironment()) {
- case llvm::Triple::EABIHF:
- case llvm::Triple::GNUEABIHF:
- return true;
- default:
- return false;
- }
- case llvm::CallingConv::ARM_AAPCS_VFP:
- return true;
- default:
- return false;
- }
-}
-
/// Arrange the argument and result information for a call to an
/// unknown C++ non-static member function of the given abstract type.
/// (Zero value of RD means we don't have any meaningful "this" argument type,
@@ -192,8 +165,9 @@ CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
else
argTypes.push_back(Context.VoidPtrTy);
- return ::arrangeCXXMethodType(*this, argTypes,
- FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
+ return ::arrangeLLVMFunctionInfo(
+ *this, true, argTypes,
+ FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
}
/// Arrange the argument and result information for a declaration or
@@ -216,31 +190,41 @@ CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) {
return arrangeFreeFunctionType(prototype);
}
-/// Arrange the argument and result information for a declaration
-/// or definition to the given constructor variant.
const CGFunctionInfo &
-CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
- CXXCtorType ctorKind) {
+CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
+ StructorType Type) {
+
SmallVector<CanQualType, 16> argTypes;
- argTypes.push_back(GetThisType(Context, D->getParent()));
+ argTypes.push_back(GetThisType(Context, MD->getParent()));
- GlobalDecl GD(D, ctorKind);
- CanQualType resultType =
- TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
+ GlobalDecl GD;
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
+ GD = GlobalDecl(CD, toCXXCtorType(Type));
+ } else {
+ auto *DD = dyn_cast<CXXDestructorDecl>(MD);
+ GD = GlobalDecl(DD, toCXXDtorType(Type));
+ }
- CanQual<FunctionProtoType> FTP = GetFormalType(D);
+ CanQual<FunctionProtoType> FTP = GetFormalType(MD);
// Add the formal parameters.
for (unsigned i = 0, e = FTP->getNumParams(); i != e; ++i)
argTypes.push_back(FTP->getParamType(i));
- TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);
+ TheCXXABI.buildStructorSignature(MD, Type, argTypes);
RequiredArgs required =
- (D->isVariadic() ? RequiredArgs(argTypes.size()) : RequiredArgs::All);
+ (MD->isVariadic() ? RequiredArgs(argTypes.size()) : RequiredArgs::All);
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo, required);
+ CanQualType resultType = TheCXXABI.HasThisReturn(GD)
+ ? argTypes.front()
+ : TheCXXABI.hasMostDerivedReturn(GD)
+ ? CGM.getContext().VoidPtrTy
+ : Context.VoidTy;
+ return arrangeLLVMFunctionInfo(resultType, /*instanceMethod=*/true,
+ /*chainCall=*/false, argTypes, extInfo,
+ required);
}
/// Arrange a call to a C++ method, passing the given arguments.
@@ -251,42 +235,22 @@ CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
unsigned ExtraArgs) {
// FIXME: Kill copy.
SmallVector<CanQualType, 16> ArgTypes;
- for (CallArgList::const_iterator i = args.begin(), e = args.end(); i != e;
- ++i)
- ArgTypes.push_back(Context.getCanonicalParamType(i->Ty));
+ for (const auto &Arg : args)
+ ArgTypes.push_back(Context.getCanonicalParamType(Arg.Ty));
CanQual<FunctionProtoType> FPT = GetFormalType(D);
RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs);
GlobalDecl GD(D, CtorKind);
- CanQualType ResultType =
- TheCXXABI.HasThisReturn(GD) ? ArgTypes.front() : Context.VoidTy;
+ CanQualType ResultType = TheCXXABI.HasThisReturn(GD)
+ ? ArgTypes.front()
+ : TheCXXABI.hasMostDerivedReturn(GD)
+ ? CGM.getContext().VoidPtrTy
+ : Context.VoidTy;
FunctionType::ExtInfo Info = FPT->getExtInfo();
- return arrangeLLVMFunctionInfo(ResultType, true, ArgTypes, Info, Required);
-}
-
-/// Arrange the argument and result information for a declaration,
-/// definition, or call to the given destructor variant. It so
-/// happens that all three cases produce the same information.
-const CGFunctionInfo &
-CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
- CXXDtorType dtorKind) {
- SmallVector<CanQualType, 2> argTypes;
- argTypes.push_back(GetThisType(Context, D->getParent()));
-
- GlobalDecl GD(D, dtorKind);
- CanQualType resultType =
- TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
-
- TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes);
-
- CanQual<FunctionProtoType> FTP = GetFormalType(D);
- assert(FTP->getNumParams() == 0 && "dtor with formal parameters");
- assert(FTP->isVariadic() == 0 && "dtor with formal parameters");
-
- FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo,
- RequiredArgs::All);
+ return arrangeLLVMFunctionInfo(ResultType, /*instanceMethod=*/true,
+ /*chainCall=*/false, ArgTypes, Info,
+ Required);
}
/// Arrange the argument and result information for the declaration or
@@ -305,8 +269,9 @@ CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) {
// non-variadic type.
if (isa<FunctionNoProtoType>(FTy)) {
CanQual<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>();
- return arrangeLLVMFunctionInfo(noProto->getReturnType(), false, None,
- noProto->getExtInfo(), RequiredArgs::All);
+ return arrangeLLVMFunctionInfo(
+ noProto->getReturnType(), /*instanceMethod=*/false,
+ /*chainCall=*/false, None, noProto->getExtInfo(), RequiredArgs::All);
}
assert(isa<FunctionProtoType>(FTy));
@@ -350,8 +315,9 @@ CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
RequiredArgs required =
(MD->isVariadic() ? RequiredArgs(argTys.size()) : RequiredArgs::All);
- return arrangeLLVMFunctionInfo(GetReturnType(MD->getReturnType()), false,
- argTys, einfo, required);
+ return arrangeLLVMFunctionInfo(
+ GetReturnType(MD->getReturnType()), /*instanceMethod=*/false,
+ /*chainCall=*/false, argTys, einfo, required);
}
const CGFunctionInfo &
@@ -360,14 +326,29 @@ CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
- return arrangeCXXConstructorDeclaration(CD, GD.getCtorType());
+ return arrangeCXXStructorDeclaration(CD, getFromCtorType(GD.getCtorType()));
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD))
- return arrangeCXXDestructor(DD, GD.getDtorType());
+ return arrangeCXXStructorDeclaration(DD, getFromDtorType(GD.getDtorType()));
return arrangeFunctionDeclaration(FD);
}
+/// Arrange a thunk that takes 'this' as the first parameter followed by
+/// varargs. Return a void pointer, regardless of the actual return type.
+/// The body of the thunk will end in a musttail call to a function of the
+/// correct type, and the caller will bitcast the function to the correct
+/// prototype.
+const CGFunctionInfo &
+CodeGenTypes::arrangeMSMemberPointerThunk(const CXXMethodDecl *MD) {
+ assert(MD->isVirtual() && "only virtual memptrs have thunks");
+ CanQual<FunctionProtoType> FTP = GetFormalType(MD);
+ CanQualType ArgTys[] = { GetThisType(Context, MD->getParent()) };
+ return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/false,
+ /*chainCall=*/false, ArgTys,
+ FTP->getExtInfo(), RequiredArgs(1));
+}
+
/// Arrange a call as unto a free function, except possibly with an
/// additional number of formal parameters considered required.
static const CGFunctionInfo &
@@ -375,7 +356,8 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
CodeGenModule &CGM,
const CallArgList &args,
const FunctionType *fnType,
- unsigned numExtraRequiredArgs) {
+ unsigned numExtraRequiredArgs,
+ bool chainCall) {
assert(args.size() >= numExtraRequiredArgs);
// In most cases, there are no optional arguments.
@@ -397,8 +379,13 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
required = RequiredArgs(args.size());
}
- return CGT.arrangeFreeFunctionCall(fnType->getReturnType(), args,
- fnType->getExtInfo(), required);
+ // FIXME: Kill copy.
+ SmallVector<CanQualType, 16> argTypes;
+ for (const auto &arg : args)
+ argTypes.push_back(CGT.getContext().getCanonicalParamType(arg.Ty));
+ return CGT.arrangeLLVMFunctionInfo(GetReturnType(fnType->getReturnType()),
+ /*instanceMethod=*/false, chainCall,
+ argTypes, fnType->getExtInfo(), required);
}
/// Figure out the rules for calling a function with the given formal
@@ -407,8 +394,10 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
/// target-dependent in crazy ways.
const CGFunctionInfo &
CodeGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
- const FunctionType *fnType) {
- return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 0);
+ const FunctionType *fnType,
+ bool chainCall) {
+ return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType,
+ chainCall ? 1 : 0, chainCall);
}
/// A block function call is essentially a free-function call with an
@@ -416,7 +405,8 @@ CodeGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
const CGFunctionInfo &
CodeGenTypes::arrangeBlockFunctionCall(const CallArgList &args,
const FunctionType *fnType) {
- return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 1);
+ return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 1,
+ /*chainCall=*/false);
}
const CGFunctionInfo &
@@ -426,11 +416,11 @@ CodeGenTypes::arrangeFreeFunctionCall(QualType resultType,
RequiredArgs required) {
// FIXME: Kill copy.
SmallVector<CanQualType, 16> argTypes;
- for (CallArgList::const_iterator i = args.begin(), e = args.end();
- i != e; ++i)
- argTypes.push_back(Context.getCanonicalParamType(i->Ty));
- return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, argTypes,
- info, required);
+ for (const auto &Arg : args)
+ argTypes.push_back(Context.getCanonicalParamType(Arg.Ty));
+ return arrangeLLVMFunctionInfo(
+ GetReturnType(resultType), /*instanceMethod=*/false,
+ /*chainCall=*/false, argTypes, info, required);
}
/// Arrange a call to a C++ method, passing the given arguments.
@@ -440,13 +430,13 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
RequiredArgs required) {
// FIXME: Kill copy.
SmallVector<CanQualType, 16> argTypes;
- for (CallArgList::const_iterator i = args.begin(), e = args.end();
- i != e; ++i)
- argTypes.push_back(Context.getCanonicalParamType(i->Ty));
+ for (const auto &Arg : args)
+ argTypes.push_back(Context.getCanonicalParamType(Arg.Ty));
FunctionType::ExtInfo info = FPT->getExtInfo();
- return arrangeLLVMFunctionInfo(GetReturnType(FPT->getReturnType()), true,
- argTypes, info, required);
+ return arrangeLLVMFunctionInfo(
+ GetReturnType(FPT->getReturnType()), /*instanceMethod=*/true,
+ /*chainCall=*/false, argTypes, info, required);
}
const CGFunctionInfo &CodeGenTypes::arrangeFreeFunctionDeclaration(
@@ -454,19 +444,20 @@ const CGFunctionInfo &CodeGenTypes::arrangeFreeFunctionDeclaration(
const FunctionType::ExtInfo &info, bool isVariadic) {
// FIXME: Kill copy.
SmallVector<CanQualType, 16> argTypes;
- for (FunctionArgList::const_iterator i = args.begin(), e = args.end();
- i != e; ++i)
- argTypes.push_back(Context.getCanonicalParamType((*i)->getType()));
+ for (auto Arg : args)
+ argTypes.push_back(Context.getCanonicalParamType(Arg->getType()));
RequiredArgs required =
(isVariadic ? RequiredArgs(args.size()) : RequiredArgs::All);
- return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, argTypes, info,
- required);
+ return arrangeLLVMFunctionInfo(
+ GetReturnType(resultType), /*instanceMethod=*/false,
+ /*chainCall=*/false, argTypes, info, required);
}
const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() {
- return arrangeLLVMFunctionInfo(getContext().VoidTy, false, None,
- FunctionType::ExtInfo(), RequiredArgs::All);
+ return arrangeLLVMFunctionInfo(
+ getContext().VoidTy, /*instanceMethod=*/false, /*chainCall=*/false,
+ None, FunctionType::ExtInfo(), RequiredArgs::All);
}
/// Arrange the argument and result information for an abstract value
@@ -474,22 +465,20 @@ const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() {
/// above functions ultimately defer to.
const CGFunctionInfo &
CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
- bool IsInstanceMethod,
+ bool instanceMethod,
+ bool chainCall,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs required) {
-#ifndef NDEBUG
- for (ArrayRef<CanQualType>::const_iterator
- I = argTypes.begin(), E = argTypes.end(); I != E; ++I)
- assert(I->isCanonicalAsParam());
-#endif
+ assert(std::all_of(argTypes.begin(), argTypes.end(),
+ std::mem_fun_ref(&CanQualType::isCanonicalAsParam)));
unsigned CC = ClangCallConvToLLVMCallConv(info.getCC());
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, IsInstanceMethod, info, required, resultType,
- argTypes);
+ CGFunctionInfo::Profile(ID, instanceMethod, chainCall, info, required,
+ resultType, argTypes);
void *insertPos = nullptr;
CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, insertPos);
@@ -497,11 +486,12 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
return *FI;
// Construct the function info. We co-allocate the ArgInfos.
- FI = CGFunctionInfo::create(CC, IsInstanceMethod, info, resultType, argTypes,
- required);
+ FI = CGFunctionInfo::create(CC, instanceMethod, chainCall, info,
+ resultType, argTypes, required);
FunctionInfos.InsertNode(FI, insertPos);
- bool inserted = FunctionsBeingProcessed.insert(FI); (void)inserted;
+ bool inserted = FunctionsBeingProcessed.insert(FI).second;
+ (void)inserted;
assert(inserted && "Recursively being processed?");
// Compute ABI information.
@@ -525,7 +515,8 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
}
CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
- bool IsInstanceMethod,
+ bool instanceMethod,
+ bool chainCall,
const FunctionType::ExtInfo &info,
CanQualType resultType,
ArrayRef<CanQualType> argTypes,
@@ -536,7 +527,8 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
FI->CallingConvention = llvmCC;
FI->EffectiveCallingConvention = llvmCC;
FI->ASTCallingConvention = info.getCC();
- FI->InstanceMethod = IsInstanceMethod;
+ FI->InstanceMethod = instanceMethod;
+ FI->ChainCall = chainCall;
FI->NoReturn = info.getNoReturn();
FI->ReturnsRetained = info.getProducesResult();
FI->Required = required;
@@ -552,13 +544,79 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
/***/
-void CodeGenTypes::GetExpandedTypes(QualType type,
- SmallVectorImpl<llvm::Type*> &expandedTypes) {
- if (const ConstantArrayType *AT = Context.getAsConstantArrayType(type)) {
- uint64_t NumElts = AT->getSize().getZExtValue();
- for (uint64_t Elt = 0; Elt < NumElts; ++Elt)
- GetExpandedTypes(AT->getElementType(), expandedTypes);
- } else if (const RecordType *RT = type->getAs<RecordType>()) {
+namespace {
+// ABIArgInfo::Expand implementation.
+
+// Specifies the way QualType passed as ABIArgInfo::Expand is expanded.
+struct TypeExpansion {
+ enum TypeExpansionKind {
+ // Elements of constant arrays are expanded recursively.
+ TEK_ConstantArray,
+ // Record fields are expanded recursively (but if record is a union, only
+ // the field with the largest size is expanded).
+ TEK_Record,
+ // For complex types, real and imaginary parts are expanded recursively.
+ TEK_Complex,
+ // All other types are not expandable.
+ TEK_None
+ };
+
+ const TypeExpansionKind Kind;
+
+ TypeExpansion(TypeExpansionKind K) : Kind(K) {}
+ virtual ~TypeExpansion() {}
+};
+
+struct ConstantArrayExpansion : TypeExpansion {
+ QualType EltTy;
+ uint64_t NumElts;
+
+ ConstantArrayExpansion(QualType EltTy, uint64_t NumElts)
+ : TypeExpansion(TEK_ConstantArray), EltTy(EltTy), NumElts(NumElts) {}
+ static bool classof(const TypeExpansion *TE) {
+ return TE->Kind == TEK_ConstantArray;
+ }
+};
+
+struct RecordExpansion : TypeExpansion {
+ SmallVector<const CXXBaseSpecifier *, 1> Bases;
+
+ SmallVector<const FieldDecl *, 1> Fields;
+
+ RecordExpansion(SmallVector<const CXXBaseSpecifier *, 1> &&Bases,
+ SmallVector<const FieldDecl *, 1> &&Fields)
+ : TypeExpansion(TEK_Record), Bases(Bases), Fields(Fields) {}
+ static bool classof(const TypeExpansion *TE) {
+ return TE->Kind == TEK_Record;
+ }
+};
+
+struct ComplexExpansion : TypeExpansion {
+ QualType EltTy;
+
+ ComplexExpansion(QualType EltTy) : TypeExpansion(TEK_Complex), EltTy(EltTy) {}
+ static bool classof(const TypeExpansion *TE) {
+ return TE->Kind == TEK_Complex;
+ }
+};
+
+struct NoExpansion : TypeExpansion {
+ NoExpansion() : TypeExpansion(TEK_None) {}
+ static bool classof(const TypeExpansion *TE) {
+ return TE->Kind == TEK_None;
+ }
+};
+} // namespace
+
+static std::unique_ptr<TypeExpansion>
+getTypeExpansion(QualType Ty, const ASTContext &Context) {
+ if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
+ return llvm::make_unique<ConstantArrayExpansion>(
+ AT->getElementType(), AT->getSize().getZExtValue());
+ }
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ SmallVector<const CXXBaseSpecifier *, 1> Bases;
+ SmallVector<const FieldDecl *, 1> Fields;
const RecordDecl *RD = RT->getDecl();
assert(!RD->hasFlexibleArrayMember() &&
"Cannot expand structure with flexible array.");
@@ -569,88 +627,178 @@ void CodeGenTypes::GetExpandedTypes(QualType type,
CharUnits UnionSize = CharUnits::Zero();
for (const auto *FD : RD->fields()) {
+ // Skip zero length bitfields.
+ if (FD->isBitField() && FD->getBitWidthValue(Context) == 0)
+ continue;
assert(!FD->isBitField() &&
"Cannot expand structure with bit-field members.");
- CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType());
+ CharUnits FieldSize = Context.getTypeSizeInChars(FD->getType());
if (UnionSize < FieldSize) {
UnionSize = FieldSize;
LargestFD = FD;
}
}
if (LargestFD)
- GetExpandedTypes(LargestFD->getType(), expandedTypes);
+ Fields.push_back(LargestFD);
} else {
- for (const auto *I : RD->fields()) {
- assert(!I->isBitField() &&
+ if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ assert(!CXXRD->isDynamicClass() &&
+ "cannot expand vtable pointers in dynamic classes");
+ for (const CXXBaseSpecifier &BS : CXXRD->bases())
+ Bases.push_back(&BS);
+ }
+
+ for (const auto *FD : RD->fields()) {
+ // Skip zero length bitfields.
+ if (FD->isBitField() && FD->getBitWidthValue(Context) == 0)
+ continue;
+ assert(!FD->isBitField() &&
"Cannot expand structure with bit-field members.");
- GetExpandedTypes(I->getType(), expandedTypes);
+ Fields.push_back(FD);
}
}
- } else if (const ComplexType *CT = type->getAs<ComplexType>()) {
- llvm::Type *EltTy = ConvertType(CT->getElementType());
- expandedTypes.push_back(EltTy);
- expandedTypes.push_back(EltTy);
- } else
- expandedTypes.push_back(ConvertType(type));
+ return llvm::make_unique<RecordExpansion>(std::move(Bases),
+ std::move(Fields));
+ }
+ if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
+ return llvm::make_unique<ComplexExpansion>(CT->getElementType());
+ }
+ return llvm::make_unique<NoExpansion>();
}
-llvm::Function::arg_iterator
-CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
- llvm::Function::arg_iterator AI) {
- assert(LV.isSimple() &&
- "Unexpected non-simple lvalue during struct expansion.");
+static int getExpansionSize(QualType Ty, const ASTContext &Context) {
+ auto Exp = getTypeExpansion(Ty, Context);
+ if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
+ return CAExp->NumElts * getExpansionSize(CAExp->EltTy, Context);
+ }
+ if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) {
+ int Res = 0;
+ for (auto BS : RExp->Bases)
+ Res += getExpansionSize(BS->getType(), Context);
+ for (auto FD : RExp->Fields)
+ Res += getExpansionSize(FD->getType(), Context);
+ return Res;
+ }
+ if (isa<ComplexExpansion>(Exp.get()))
+ return 2;
+ assert(isa<NoExpansion>(Exp.get()));
+ return 1;
+}
- if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) {
- unsigned NumElts = AT->getSize().getZExtValue();
- QualType EltTy = AT->getElementType();
- for (unsigned Elt = 0; Elt < NumElts; ++Elt) {
- llvm::Value *EltAddr = Builder.CreateConstGEP2_32(LV.getAddress(), 0, Elt);
- LValue LV = MakeAddrLValue(EltAddr, EltTy);
- AI = ExpandTypeFromArgs(EltTy, LV, AI);
+void
+CodeGenTypes::getExpandedTypes(QualType Ty,
+ SmallVectorImpl<llvm::Type *>::iterator &TI) {
+ auto Exp = getTypeExpansion(Ty, Context);
+ if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
+ for (int i = 0, n = CAExp->NumElts; i < n; i++) {
+ getExpandedTypes(CAExp->EltTy, TI);
}
- } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
- RecordDecl *RD = RT->getDecl();
- if (RD->isUnion()) {
- // Unions can be here only in degenerative cases - all the fields are same
- // after flattening. Thus we have to use the "largest" field.
- const FieldDecl *LargestFD = nullptr;
- CharUnits UnionSize = CharUnits::Zero();
+ } else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) {
+ for (auto BS : RExp->Bases)
+ getExpandedTypes(BS->getType(), TI);
+ for (auto FD : RExp->Fields)
+ getExpandedTypes(FD->getType(), TI);
+ } else if (auto CExp = dyn_cast<ComplexExpansion>(Exp.get())) {
+ llvm::Type *EltTy = ConvertType(CExp->EltTy);
+ *TI++ = EltTy;
+ *TI++ = EltTy;
+ } else {
+ assert(isa<NoExpansion>(Exp.get()));
+ *TI++ = ConvertType(Ty);
+ }
+}
- for (const auto *FD : RD->fields()) {
- assert(!FD->isBitField() &&
- "Cannot expand structure with bit-field members.");
- CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType());
- if (UnionSize < FieldSize) {
- UnionSize = FieldSize;
- LargestFD = FD;
- }
- }
- if (LargestFD) {
- // FIXME: What are the right qualifiers here?
- LValue SubLV = EmitLValueForField(LV, LargestFD);
- AI = ExpandTypeFromArgs(LargestFD->getType(), SubLV, AI);
- }
- } else {
- for (const auto *FD : RD->fields()) {
- QualType FT = FD->getType();
+void CodeGenFunction::ExpandTypeFromArgs(
+ QualType Ty, LValue LV, SmallVectorImpl<llvm::Argument *>::iterator &AI) {
+ assert(LV.isSimple() &&
+ "Unexpected non-simple lvalue during struct expansion.");
- // FIXME: What are the right qualifiers here?
- LValue SubLV = EmitLValueForField(LV, FD);
- AI = ExpandTypeFromArgs(FT, SubLV, AI);
- }
+ auto Exp = getTypeExpansion(Ty, getContext());
+ if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
+ for (int i = 0, n = CAExp->NumElts; i < n; i++) {
+ llvm::Value *EltAddr = Builder.CreateConstGEP2_32(LV.getAddress(), 0, i);
+ LValue LV = MakeAddrLValue(EltAddr, CAExp->EltTy);
+ ExpandTypeFromArgs(CAExp->EltTy, LV, AI);
+ }
+ } else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) {
+ llvm::Value *This = LV.getAddress();
+ for (const CXXBaseSpecifier *BS : RExp->Bases) {
+ // Perform a single step derived-to-base conversion.
+ llvm::Value *Base =
+ GetAddressOfBaseClass(This, Ty->getAsCXXRecordDecl(), &BS, &BS + 1,
+ /*NullCheckValue=*/false, SourceLocation());
+ LValue SubLV = MakeAddrLValue(Base, BS->getType());
+
+ // Recurse onto bases.
+ ExpandTypeFromArgs(BS->getType(), SubLV, AI);
}
- } else if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
- QualType EltTy = CT->getElementType();
+ for (auto FD : RExp->Fields) {
+ // FIXME: What are the right qualifiers here?
+ LValue SubLV = EmitLValueForField(LV, FD);
+ ExpandTypeFromArgs(FD->getType(), SubLV, AI);
+ }
+ } else if (auto CExp = dyn_cast<ComplexExpansion>(Exp.get())) {
llvm::Value *RealAddr = Builder.CreateStructGEP(LV.getAddress(), 0, "real");
- EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(RealAddr, EltTy));
+ EmitStoreThroughLValue(RValue::get(*AI++),
+ MakeAddrLValue(RealAddr, CExp->EltTy));
llvm::Value *ImagAddr = Builder.CreateStructGEP(LV.getAddress(), 1, "imag");
- EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(ImagAddr, EltTy));
+ EmitStoreThroughLValue(RValue::get(*AI++),
+ MakeAddrLValue(ImagAddr, CExp->EltTy));
} else {
- EmitStoreThroughLValue(RValue::get(AI), LV);
- ++AI;
+ assert(isa<NoExpansion>(Exp.get()));
+ EmitStoreThroughLValue(RValue::get(*AI++), LV);
}
+}
+
+void CodeGenFunction::ExpandTypeToArgs(
+ QualType Ty, RValue RV, llvm::FunctionType *IRFuncTy,
+ SmallVectorImpl<llvm::Value *> &IRCallArgs, unsigned &IRCallArgPos) {
+ auto Exp = getTypeExpansion(Ty, getContext());
+ if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
+ llvm::Value *Addr = RV.getAggregateAddr();
+ for (int i = 0, n = CAExp->NumElts; i < n; i++) {
+ llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, i);
+ RValue EltRV =
+ convertTempToRValue(EltAddr, CAExp->EltTy, SourceLocation());
+ ExpandTypeToArgs(CAExp->EltTy, EltRV, IRFuncTy, IRCallArgs, IRCallArgPos);
+ }
+ } else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) {
+ llvm::Value *This = RV.getAggregateAddr();
+ for (const CXXBaseSpecifier *BS : RExp->Bases) {
+ // Perform a single step derived-to-base conversion.
+ llvm::Value *Base =
+ GetAddressOfBaseClass(This, Ty->getAsCXXRecordDecl(), &BS, &BS + 1,
+ /*NullCheckValue=*/false, SourceLocation());
+ RValue BaseRV = RValue::getAggregate(Base);
+
+ // Recurse onto bases.
+ ExpandTypeToArgs(BS->getType(), BaseRV, IRFuncTy, IRCallArgs,
+ IRCallArgPos);
+ }
+
+ LValue LV = MakeAddrLValue(This, Ty);
+ for (auto FD : RExp->Fields) {
+ RValue FldRV = EmitRValueForField(LV, FD, SourceLocation());
+ ExpandTypeToArgs(FD->getType(), FldRV, IRFuncTy, IRCallArgs,
+ IRCallArgPos);
+ }
+ } else if (isa<ComplexExpansion>(Exp.get())) {
+ ComplexPairTy CV = RV.getComplexVal();
+ IRCallArgs[IRCallArgPos++] = CV.first;
+ IRCallArgs[IRCallArgPos++] = CV.second;
+ } else {
+ assert(isa<NoExpansion>(Exp.get()));
+ assert(RV.isScalar() &&
+ "Unexpected non-scalar rvalue during struct expansion.");
+
+ // Insert a bitcast as needed.
+ llvm::Value *V = RV.getScalarVal();
+ if (IRCallArgPos < IRFuncTy->getNumParams() &&
+ V->getType() != IRFuncTy->getParamType(IRCallArgPos))
+ V = Builder.CreateBitCast(V, IRFuncTy->getParamType(IRCallArgPos));
- return AI;
+ IRCallArgs[IRCallArgPos++] = V;
+ }
}
/// EnterStructPointerForCoercedAccess - Given a struct pointer that we are
@@ -667,11 +815,13 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr,
llvm::Type *FirstElt = SrcSTy->getElementType(0);
// If the first elt is at least as large as what we're looking for, or if the
- // first element is the same size as the whole struct, we can enter it.
+ // first element is the same size as the whole struct, we can enter it. The
+ // comparison must be made on the store size and not the alloca size. Using
+ // the alloca size may overstate the size of the load.
uint64_t FirstEltSize =
- CGF.CGM.getDataLayout().getTypeAllocSize(FirstElt);
+ CGF.CGM.getDataLayout().getTypeStoreSize(FirstElt);
if (FirstEltSize < DstSize &&
- FirstEltSize < CGF.CGM.getDataLayout().getTypeAllocSize(SrcSTy))
+ FirstEltSize < CGF.CGM.getDataLayout().getTypeStoreSize(SrcSTy))
return SrcPtr;
// GEP into the first element.
@@ -890,6 +1040,145 @@ static void CreateCoercedStore(llvm::Value *Src,
}
}
+namespace {
+
+/// Encapsulates information about the way function arguments from
+/// CGFunctionInfo should be passed to actual LLVM IR function.
+class ClangToLLVMArgMapping {
+ static const unsigned InvalidIndex = ~0U;
+ unsigned InallocaArgNo;
+ unsigned SRetArgNo;
+ unsigned TotalIRArgs;
+
+ /// Arguments of LLVM IR function corresponding to single Clang argument.
+ struct IRArgs {
+ unsigned PaddingArgIndex;
+ // Argument is expanded to IR arguments at positions
+ // [FirstArgIndex, FirstArgIndex + NumberOfArgs).
+ unsigned FirstArgIndex;
+ unsigned NumberOfArgs;
+
+ IRArgs()
+ : PaddingArgIndex(InvalidIndex), FirstArgIndex(InvalidIndex),
+ NumberOfArgs(0) {}
+ };
+
+ SmallVector<IRArgs, 8> ArgInfo;
+
+public:
+ ClangToLLVMArgMapping(const ASTContext &Context, const CGFunctionInfo &FI,
+ bool OnlyRequiredArgs = false)
+ : InallocaArgNo(InvalidIndex), SRetArgNo(InvalidIndex), TotalIRArgs(0),
+ ArgInfo(OnlyRequiredArgs ? FI.getNumRequiredArgs() : FI.arg_size()) {
+ construct(Context, FI, OnlyRequiredArgs);
+ }
+
+ bool hasInallocaArg() const { return InallocaArgNo != InvalidIndex; }
+ unsigned getInallocaArgNo() const {
+ assert(hasInallocaArg());
+ return InallocaArgNo;
+ }
+
+ bool hasSRetArg() const { return SRetArgNo != InvalidIndex; }
+ unsigned getSRetArgNo() const {
+ assert(hasSRetArg());
+ return SRetArgNo;
+ }
+
+ unsigned totalIRArgs() const { return TotalIRArgs; }
+
+ bool hasPaddingArg(unsigned ArgNo) const {
+ assert(ArgNo < ArgInfo.size());
+ return ArgInfo[ArgNo].PaddingArgIndex != InvalidIndex;
+ }
+ unsigned getPaddingArgNo(unsigned ArgNo) const {
+ assert(hasPaddingArg(ArgNo));
+ return ArgInfo[ArgNo].PaddingArgIndex;
+ }
+
+ /// Returns index of first IR argument corresponding to ArgNo, and their
+ /// quantity.
+ std::pair<unsigned, unsigned> getIRArgs(unsigned ArgNo) const {
+ assert(ArgNo < ArgInfo.size());
+ return std::make_pair(ArgInfo[ArgNo].FirstArgIndex,
+ ArgInfo[ArgNo].NumberOfArgs);
+ }
+
+private:
+ void construct(const ASTContext &Context, const CGFunctionInfo &FI,
+ bool OnlyRequiredArgs);
+};
+
+void ClangToLLVMArgMapping::construct(const ASTContext &Context,
+ const CGFunctionInfo &FI,
+ bool OnlyRequiredArgs) {
+ unsigned IRArgNo = 0;
+ bool SwapThisWithSRet = false;
+ const ABIArgInfo &RetAI = FI.getReturnInfo();
+
+ if (RetAI.getKind() == ABIArgInfo::Indirect) {
+ SwapThisWithSRet = RetAI.isSRetAfterThis();
+ SRetArgNo = SwapThisWithSRet ? 1 : IRArgNo++;
+ }
+
+ unsigned ArgNo = 0;
+ unsigned NumArgs = OnlyRequiredArgs ? FI.getNumRequiredArgs() : FI.arg_size();
+ for (CGFunctionInfo::const_arg_iterator I = FI.arg_begin(); ArgNo < NumArgs;
+ ++I, ++ArgNo) {
+ assert(I != FI.arg_end());
+ QualType ArgType = I->type;
+ const ABIArgInfo &AI = I->info;
+ // Collect data about IR arguments corresponding to Clang argument ArgNo.
+ auto &IRArgs = ArgInfo[ArgNo];
+
+ if (AI.getPaddingType())
+ IRArgs.PaddingArgIndex = IRArgNo++;
+
+ switch (AI.getKind()) {
+ case ABIArgInfo::Extend:
+ case ABIArgInfo::Direct: {
+ // FIXME: handle sseregparm someday...
+ llvm::StructType *STy = dyn_cast<llvm::StructType>(AI.getCoerceToType());
+ if (AI.isDirect() && AI.getCanBeFlattened() && STy) {
+ IRArgs.NumberOfArgs = STy->getNumElements();
+ } else {
+ IRArgs.NumberOfArgs = 1;
+ }
+ break;
+ }
+ case ABIArgInfo::Indirect:
+ IRArgs.NumberOfArgs = 1;
+ break;
+ case ABIArgInfo::Ignore:
+ case ABIArgInfo::InAlloca:
+ // ignore and inalloca doesn't have matching LLVM parameters.
+ IRArgs.NumberOfArgs = 0;
+ break;
+ case ABIArgInfo::Expand: {
+ IRArgs.NumberOfArgs = getExpansionSize(ArgType, Context);
+ break;
+ }
+ }
+
+ if (IRArgs.NumberOfArgs > 0) {
+ IRArgs.FirstArgIndex = IRArgNo;
+ IRArgNo += IRArgs.NumberOfArgs;
+ }
+
+ // Skip over the sret parameter when it comes second. We already handled it
+ // above.
+ if (IRArgNo == 1 && SwapThisWithSRet)
+ IRArgNo++;
+ }
+ assert(ArgNo == ArgInfo.size());
+
+ if (FI.usesInAlloca())
+ InallocaArgNo = IRArgNo++;
+
+ TotalIRArgs = IRArgNo;
+}
+} // namespace
+
/***/
bool CodeGenModule::ReturnTypeUsesSRet(const CGFunctionInfo &FI) {
@@ -936,14 +1225,12 @@ llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
llvm::FunctionType *
CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
-
- bool Inserted = FunctionsBeingProcessed.insert(&FI); (void)Inserted;
+
+ bool Inserted = FunctionsBeingProcessed.insert(&FI).second;
+ (void)Inserted;
assert(Inserted && "Recursively being processed?");
-
- bool SwapThisWithSRet = false;
- SmallVector<llvm::Type*, 8> argTypes;
- llvm::Type *resultType = nullptr;
+ llvm::Type *resultType = nullptr;
const ABIArgInfo &retAI = FI.getReturnInfo();
switch (retAI.getKind()) {
case ABIArgInfo::Expand:
@@ -969,13 +1256,6 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
case ABIArgInfo::Indirect: {
assert(!retAI.getIndirectAlign() && "Align unused on indirect return.");
resultType = llvm::Type::getVoidTy(getLLVMContext());
-
- QualType ret = FI.getReturnType();
- llvm::Type *ty = ConvertType(ret);
- unsigned addressSpace = Context.getTargetAddressSpace(ret);
- argTypes.push_back(llvm::PointerType::get(ty, addressSpace));
-
- SwapThisWithSRet = retAI.isSRetAfterThis();
break;
}
@@ -984,67 +1264,83 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
break;
}
- // Add in all of the required arguments.
- CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie;
- if (FI.isVariadic()) {
- ie = it + FI.getRequiredArgs().getNumRequiredArgs();
- } else {
- ie = FI.arg_end();
+ ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI, true);
+ SmallVector<llvm::Type*, 8> ArgTypes(IRFunctionArgs.totalIRArgs());
+
+ // Add type for sret argument.
+ if (IRFunctionArgs.hasSRetArg()) {
+ QualType Ret = FI.getReturnType();
+ llvm::Type *Ty = ConvertType(Ret);
+ unsigned AddressSpace = Context.getTargetAddressSpace(Ret);
+ ArgTypes[IRFunctionArgs.getSRetArgNo()] =
+ llvm::PointerType::get(Ty, AddressSpace);
+ }
+
+ // Add type for inalloca argument.
+ if (IRFunctionArgs.hasInallocaArg()) {
+ auto ArgStruct = FI.getArgStruct();
+ assert(ArgStruct);
+ ArgTypes[IRFunctionArgs.getInallocaArgNo()] = ArgStruct->getPointerTo();
}
- for (; it != ie; ++it) {
- const ABIArgInfo &argAI = it->info;
+
+ // Add in all of the required arguments.
+ unsigned ArgNo = 0;
+ CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
+ ie = it + FI.getNumRequiredArgs();
+ for (; it != ie; ++it, ++ArgNo) {
+ const ABIArgInfo &ArgInfo = it->info;
// Insert a padding type to ensure proper alignment.
- if (llvm::Type *PaddingType = argAI.getPaddingType())
- argTypes.push_back(PaddingType);
+ if (IRFunctionArgs.hasPaddingArg(ArgNo))
+ ArgTypes[IRFunctionArgs.getPaddingArgNo(ArgNo)] =
+ ArgInfo.getPaddingType();
+
+ unsigned FirstIRArg, NumIRArgs;
+ std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
- switch (argAI.getKind()) {
+ switch (ArgInfo.getKind()) {
case ABIArgInfo::Ignore:
case ABIArgInfo::InAlloca:
+ assert(NumIRArgs == 0);
break;
case ABIArgInfo::Indirect: {
+ assert(NumIRArgs == 1);
// indirect arguments are always on the stack, which is addr space #0.
llvm::Type *LTy = ConvertTypeForMem(it->type);
- argTypes.push_back(LTy->getPointerTo());
+ ArgTypes[FirstIRArg] = LTy->getPointerTo();
break;
}
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
- // 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.
- // We cannot do this for functions using the AAPCS calling convention,
- // as structures are treated differently by that calling convention.
- llvm::Type *argType = argAI.getCoerceToType();
+ // Fast-isel and the optimizer generally like scalar values better than
+ // FCAs, so we flatten them if this is safe to do for this argument.
+ llvm::Type *argType = ArgInfo.getCoerceToType();
llvm::StructType *st = dyn_cast<llvm::StructType>(argType);
- if (st && !isAAPCSVFP(FI, getTarget())) {
+ if (st && ArgInfo.isDirect() && ArgInfo.getCanBeFlattened()) {
+ assert(NumIRArgs == st->getNumElements());
for (unsigned i = 0, e = st->getNumElements(); i != e; ++i)
- argTypes.push_back(st->getElementType(i));
+ ArgTypes[FirstIRArg + i] = st->getElementType(i);
} else {
- argTypes.push_back(argType);
+ assert(NumIRArgs == 1);
+ ArgTypes[FirstIRArg] = argType;
}
break;
}
case ABIArgInfo::Expand:
- GetExpandedTypes(it->type, argTypes);
+ auto ArgTypesIter = ArgTypes.begin() + FirstIRArg;
+ getExpandedTypes(it->type, ArgTypesIter);
+ assert(ArgTypesIter == ArgTypes.begin() + FirstIRArg + NumIRArgs);
break;
}
}
- // Add the inalloca struct as the last parameter type.
- if (llvm::StructType *ArgStruct = FI.getArgStruct())
- argTypes.push_back(ArgStruct->getPointerTo());
-
- if (SwapThisWithSRet)
- std::swap(argTypes[0], argTypes[1]);
-
bool Erased = FunctionsBeingProcessed.erase(&FI); (void)Erased;
assert(Erased && "Not in set?");
-
- return llvm::FunctionType::get(resultType, argTypes, FI.isVariadic());
+
+ return llvm::FunctionType::get(resultType, ArgTypes, FI.isVariadic());
}
llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
@@ -1056,7 +1352,8 @@ llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
const CGFunctionInfo *Info;
if (isa<CXXDestructorDecl>(MD))
- Info = &arrangeCXXDestructor(cast<CXXDestructorDecl>(MD), GD.getDtorType());
+ Info =
+ &arrangeCXXStructorDeclaration(MD, getFromDtorType(GD.getDtorType()));
else
Info = &arrangeCXXMethodDeclaration(MD);
return GetFunctionType(*Info);
@@ -1069,6 +1366,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
bool AttrOnCallSite) {
llvm::AttrBuilder FuncAttrs;
llvm::AttrBuilder RetAttrs;
+ bool HasOptnone = false;
CallingConv = FI.getEffectiveCallingConvention();
@@ -1109,12 +1407,18 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
RetAttrs.addAttribute(llvm::Attribute::NoAlias);
if (TargetDecl->hasAttr<ReturnsNonNullAttr>())
RetAttrs.addAttribute(llvm::Attribute::NonNull);
+
+ HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
+ }
+
+ // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed.
+ if (!HasOptnone) {
+ if (CodeGenOpts.OptimizeSize)
+ FuncAttrs.addAttribute(llvm::Attribute::OptimizeForSize);
+ if (CodeGenOpts.OptimizeSize == 2)
+ FuncAttrs.addAttribute(llvm::Attribute::MinSize);
}
- if (CodeGenOpts.OptimizeSize)
- FuncAttrs.addAttribute(llvm::Attribute::OptimizeForSize);
- if (CodeGenOpts.OptimizeSize == 2)
- FuncAttrs.addAttribute(llvm::Attribute::MinSize);
if (CodeGenOpts.DisableRedZone)
FuncAttrs.addAttribute(llvm::Attribute::NoRedZone);
if (CodeGenOpts.NoImplicitFloat)
@@ -1156,9 +1460,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
FuncAttrs.addAttribute("no-realign-stack");
}
+ ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI);
+
QualType RetTy = FI.getReturnType();
- unsigned Index = 1;
- bool SwapThisWithSRet = false;
const ABIArgInfo &RetAI = FI.getReturnInfo();
switch (RetAI.getKind()) {
case ABIArgInfo::Extend:
@@ -1174,25 +1478,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
case ABIArgInfo::Ignore:
break;
- case ABIArgInfo::InAlloca: {
- // inalloca disables readnone and readonly
- FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
- .removeAttribute(llvm::Attribute::ReadNone);
- break;
- }
-
+ case ABIArgInfo::InAlloca:
case ABIArgInfo::Indirect: {
- llvm::AttrBuilder SRETAttrs;
- SRETAttrs.addAttribute(llvm::Attribute::StructRet);
- if (RetAI.getInReg())
- SRETAttrs.addAttribute(llvm::Attribute::InReg);
- SwapThisWithSRet = RetAI.isSRetAfterThis();
- PAL.push_back(llvm::AttributeSet::get(
- getLLVMContext(), SwapThisWithSRet ? 2 : Index, SRETAttrs));
-
- if (!SwapThisWithSRet)
- ++Index;
- // sret disables readnone and readonly
+ // inalloca and sret disable readnone and readonly
FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
.removeAttribute(llvm::Attribute::ReadNone);
break;
@@ -1211,28 +1499,44 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
RetAttrs.addAttribute(llvm::Attribute::NonNull);
}
- if (RetAttrs.hasAttributes())
- PAL.push_back(llvm::
- AttributeSet::get(getLLVMContext(),
- llvm::AttributeSet::ReturnIndex,
- RetAttrs));
+ // Attach return attributes.
+ if (RetAttrs.hasAttributes()) {
+ PAL.push_back(llvm::AttributeSet::get(
+ getLLVMContext(), llvm::AttributeSet::ReturnIndex, RetAttrs));
+ }
- for (const auto &I : FI.arguments()) {
- QualType ParamType = I.type;
- const ABIArgInfo &AI = I.info;
+ // Attach attributes to sret.
+ if (IRFunctionArgs.hasSRetArg()) {
+ llvm::AttrBuilder SRETAttrs;
+ SRETAttrs.addAttribute(llvm::Attribute::StructRet);
+ if (RetAI.getInReg())
+ SRETAttrs.addAttribute(llvm::Attribute::InReg);
+ PAL.push_back(llvm::AttributeSet::get(
+ getLLVMContext(), IRFunctionArgs.getSRetArgNo() + 1, SRETAttrs));
+ }
+
+ // Attach attributes to inalloca argument.
+ if (IRFunctionArgs.hasInallocaArg()) {
llvm::AttrBuilder Attrs;
+ Attrs.addAttribute(llvm::Attribute::InAlloca);
+ PAL.push_back(llvm::AttributeSet::get(
+ getLLVMContext(), IRFunctionArgs.getInallocaArgNo() + 1, Attrs));
+ }
- // Skip over the sret parameter when it comes second. We already handled it
- // above.
- if (Index == 2 && SwapThisWithSRet)
- ++Index;
+ unsigned ArgNo = 0;
+ for (CGFunctionInfo::const_arg_iterator I = FI.arg_begin(),
+ E = FI.arg_end();
+ I != E; ++I, ++ArgNo) {
+ QualType ParamType = I->type;
+ const ABIArgInfo &AI = I->info;
+ llvm::AttrBuilder Attrs;
- if (AI.getPaddingType()) {
+ // Add attribute for padding argument, if necessary.
+ if (IRFunctionArgs.hasPaddingArg(ArgNo)) {
if (AI.getPaddingInReg())
- PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index,
- llvm::Attribute::InReg));
- // Increment Index if there is padding.
- ++Index;
+ PAL.push_back(llvm::AttributeSet::get(
+ getLLVMContext(), IRFunctionArgs.getPaddingArgNo(ArgNo) + 1,
+ llvm::Attribute::InReg));
}
// 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
@@ -1245,24 +1549,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
else if (ParamType->isUnsignedIntegerOrEnumerationType())
Attrs.addAttribute(llvm::Attribute::ZExt);
// FALL THROUGH
- case ABIArgInfo::Direct: {
- if (AI.getInReg())
+ case ABIArgInfo::Direct:
+ if (ArgNo == 0 && FI.isChainCall())
+ Attrs.addAttribute(llvm::Attribute::Nest);
+ else if (AI.getInReg())
Attrs.addAttribute(llvm::Attribute::InReg);
-
- // FIXME: handle sseregparm someday...
-
- llvm::StructType *STy =
- dyn_cast<llvm::StructType>(AI.getCoerceToType());
- if (!isAAPCSVFP(FI, getTarget()) && STy) {
- unsigned Extra = STy->getNumElements()-1; // 1 will be added below.
- if (Attrs.hasAttributes())
- for (unsigned I = 0; I < Extra; ++I)
- PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index + I,
- Attrs));
- Index += Extra;
- }
break;
- }
+
case ABIArgInfo::Indirect:
if (AI.getInReg())
Attrs.addAttribute(llvm::Attribute::InReg);
@@ -1278,26 +1571,15 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
break;
case ABIArgInfo::Ignore:
- // Skip increment, no matching LLVM parameter.
+ case ABIArgInfo::Expand:
continue;
case ABIArgInfo::InAlloca:
// inalloca disables readnone and readonly.
FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
.removeAttribute(llvm::Attribute::ReadNone);
- // Skip increment, no matching LLVM parameter.
- continue;
-
- case ABIArgInfo::Expand: {
- SmallVector<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, types);
- Index += types.size();
continue;
}
- }
if (const auto *RefTy = ParamType->getAs<ReferenceType>()) {
QualType PTy = RefTy->getPointeeType();
@@ -1308,17 +1590,15 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
Attrs.addAttribute(llvm::Attribute::NonNull);
}
- if (Attrs.hasAttributes())
- PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index, Attrs));
- ++Index;
- }
-
- // Add the inalloca attribute to the trailing inalloca parameter if present.
- if (FI.usesInAlloca()) {
- llvm::AttrBuilder Attrs;
- Attrs.addAttribute(llvm::Attribute::InAlloca);
- PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index, Attrs));
+ if (Attrs.hasAttributes()) {
+ unsigned FirstIRArg, NumIRArgs;
+ std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
+ for (unsigned i = 0; i < NumIRArgs; i++)
+ PAL.push_back(llvm::AttributeSet::get(getLLVMContext(),
+ FirstIRArg + i + 1, Attrs));
+ }
}
+ assert(ArgNo == FI.arg_size());
if (FuncAttrs.hasAttributes())
PAL.push_back(llvm::
@@ -1347,9 +1627,41 @@ static llvm::Value *emitArgumentDemotion(CodeGenFunction &CGF,
return CGF.Builder.CreateFPCast(value, varType, "arg.unpromote");
}
+/// Returns the attribute (either parameter attribute, or function
+/// attribute), which declares argument ArgNo to be non-null.
+static const NonNullAttr *getNonNullAttr(const Decl *FD, const ParmVarDecl *PVD,
+ QualType ArgType, unsigned ArgNo) {
+ // FIXME: __attribute__((nonnull)) can also be applied to:
+ // - references to pointers, where the pointee is known to be
+ // nonnull (apparently a Clang extension)
+ // - transparent unions containing pointers
+ // In the former case, LLVM IR cannot represent the constraint. In
+ // the latter case, we have no guarantee that the transparent union
+ // is in fact passed as a pointer.
+ if (!ArgType->isAnyPointerType() && !ArgType->isBlockPointerType())
+ return nullptr;
+ // First, check attribute on parameter itself.
+ if (PVD) {
+ if (auto ParmNNAttr = PVD->getAttr<NonNullAttr>())
+ return ParmNNAttr;
+ }
+ // Check function attributes.
+ if (!FD)
+ return nullptr;
+ for (const auto *NNAttr : FD->specific_attrs<NonNullAttr>()) {
+ if (NNAttr->isNonNull(ArgNo))
+ return NNAttr;
+ }
+ return nullptr;
+}
+
void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Function *Fn,
const FunctionArgList &Args) {
+ if (CurCodeDecl && CurCodeDecl->hasAttr<NakedAttr>())
+ // Naked functions don't have prologues.
+ return;
+
// If this is an implicit-return-zero function, go ahead and
// initialize the return value. TODO: it might be nice to have
// a more general mechanism for this that didn't require synthesized
@@ -1366,39 +1678,31 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// FIXME: We no longer need the types from FunctionArgList; lift up and
// simplify.
- // Emit allocs for param decls. Give the LLVM Argument nodes names.
- llvm::Function::arg_iterator AI = Fn->arg_begin();
+ ClangToLLVMArgMapping IRFunctionArgs(CGM.getContext(), FI);
+ // Flattened function arguments.
+ SmallVector<llvm::Argument *, 16> FnArgs;
+ FnArgs.reserve(IRFunctionArgs.totalIRArgs());
+ for (auto &Arg : Fn->args()) {
+ FnArgs.push_back(&Arg);
+ }
+ assert(FnArgs.size() == IRFunctionArgs.totalIRArgs());
// If we're using inalloca, all the memory arguments are GEPs off of the last
// parameter, which is a pointer to the complete memory area.
llvm::Value *ArgStruct = nullptr;
- if (FI.usesInAlloca()) {
- llvm::Function::arg_iterator EI = Fn->arg_end();
- --EI;
- ArgStruct = EI;
+ if (IRFunctionArgs.hasInallocaArg()) {
+ ArgStruct = FnArgs[IRFunctionArgs.getInallocaArgNo()];
assert(ArgStruct->getType() == FI.getArgStruct()->getPointerTo());
}
- // Name the struct return parameter, which can come first or second.
- const ABIArgInfo &RetAI = FI.getReturnInfo();
- bool SwapThisWithSRet = false;
- if (RetAI.isIndirect()) {
- SwapThisWithSRet = RetAI.isSRetAfterThis();
- if (SwapThisWithSRet)
- ++AI;
+ // Name the struct return parameter.
+ if (IRFunctionArgs.hasSRetArg()) {
+ auto AI = FnArgs[IRFunctionArgs.getSRetArgNo()];
AI->setName("agg.result");
AI->addAttr(llvm::AttributeSet::get(getLLVMContext(), AI->getArgNo() + 1,
llvm::Attribute::NoAlias));
- if (SwapThisWithSRet)
- --AI; // Go back to the beginning for 'this'.
- else
- ++AI; // Skip the sret parameter.
}
- // Get the function-level nonnull attribute if it exists.
- const NonNullAttr *NNAtt =
- CurCodeDecl ? CurCodeDecl->getAttr<NonNullAttr>() : nullptr;
-
// Track if we received the parameter as a pointer (indirect, byval, or
// inalloca). If already have a pointer, EmitParmDecl doesn't need to copy it
// into a local alloca for us.
@@ -1413,9 +1717,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// we can push the cleanups in the correct order for the ABI.
assert(FI.arg_size() == Args.size() &&
"Mismatch between function signature & arguments.");
- unsigned ArgNo = 1;
+ unsigned ArgNo = 0;
CGFunctionInfo::const_arg_iterator info_it = FI.arg_begin();
- for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
+ for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i, ++info_it, ++ArgNo) {
const VarDecl *Arg = *i;
QualType Ty = info_it->type;
@@ -1424,20 +1728,21 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
bool isPromoted =
isa<ParmVarDecl>(Arg) && cast<ParmVarDecl>(Arg)->isKNRPromoted();
- // Skip the dummy padding argument.
- if (ArgI.getPaddingType())
- ++AI;
+ unsigned FirstIRArg, NumIRArgs;
+ std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
switch (ArgI.getKind()) {
case ABIArgInfo::InAlloca: {
+ assert(NumIRArgs == 0);
llvm::Value *V = Builder.CreateStructGEP(
ArgStruct, ArgI.getInAllocaFieldIndex(), Arg->getName());
ArgVals.push_back(ValueAndIsPtr(V, HavePointer));
- continue; // Don't increment AI!
+ break;
}
case ABIArgInfo::Indirect: {
- llvm::Value *V = AI;
+ assert(NumIRArgs == 1);
+ llvm::Value *V = FnArgs[FirstIRArg];
if (!hasScalarEvaluationKind(Ty)) {
// Aggregates and complex variables are accessed by reference. All we
@@ -1483,12 +1788,13 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (!isa<llvm::StructType>(ArgI.getCoerceToType()) &&
ArgI.getCoerceToType() == ConvertType(Ty) &&
ArgI.getDirectOffset() == 0) {
- assert(AI != Fn->arg_end() && "Argument mismatch!");
+ assert(NumIRArgs == 1);
+ auto AI = FnArgs[FirstIRArg];
llvm::Value *V = AI;
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) {
- if ((NNAtt && NNAtt->isNonNull(PVD->getFunctionScopeIndex())) ||
- PVD->hasAttr<NonNullAttr>())
+ if (getNonNullAttr(CurCodeDecl, PVD, PVD->getType(),
+ PVD->getFunctionScopeIndex()))
AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
AI->getArgNo() + 1,
llvm::Attribute::NonNull));
@@ -1527,6 +1833,25 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
AI->getArgNo() + 1,
llvm::Attribute::NonNull));
}
+
+ const auto *AVAttr = PVD->getAttr<AlignValueAttr>();
+ if (!AVAttr)
+ if (const auto *TOTy = dyn_cast<TypedefType>(OTy))
+ AVAttr = TOTy->getDecl()->getAttr<AlignValueAttr>();
+ if (AVAttr) {
+ llvm::Value *AlignmentValue =
+ EmitScalarExpr(AVAttr->getAlignment());
+ llvm::ConstantInt *AlignmentCI =
+ cast<llvm::ConstantInt>(AlignmentValue);
+ unsigned Alignment =
+ std::min((unsigned) AlignmentCI->getZExtValue(),
+ +llvm::Value::MaximumAlignment);
+
+ llvm::AttrBuilder Attrs;
+ Attrs.addAlignmentAttr(Alignment);
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
+ AI->getArgNo() + 1, Attrs));
+ }
}
if (Arg->getType().isRestrictQualified())
@@ -1581,13 +1906,11 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::PointerType::getUnqual(ArgI.getCoerceToType()));
}
- // If the coerce-to type is a first class aggregate, we flatten it and
- // pass the elements. Either way is semantically identical, but fast-isel
- // and the optimizer generally likes scalar values better than FCAs.
- // We cannot do this for functions using the AAPCS calling convention,
- // as structures are treated differently by that calling convention.
+ // Fast-isel and the optimizer generally like scalar values better than
+ // FCAs, so we flatten them if this is safe to do for this argument.
llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgI.getCoerceToType());
- if (!isAAPCSVFP(FI, getTarget()) && STy && STy->getNumElements() > 1) {
+ if (ArgI.isDirect() && ArgI.getCanBeFlattened() && STy &&
+ STy->getNumElements() > 1) {
uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(STy);
llvm::Type *DstTy =
cast<llvm::PointerType>(Ptr->getType())->getElementType();
@@ -1596,11 +1919,12 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (SrcSize <= DstSize) {
Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy));
+ assert(STy->getNumElements() == NumIRArgs);
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- assert(AI != Fn->arg_end() && "Argument mismatch!");
+ auto AI = FnArgs[FirstIRArg + i];
AI->setName(Arg->getName() + ".coerce" + Twine(i));
llvm::Value *EltPtr = Builder.CreateConstGEP2_32(Ptr, 0, i);
- Builder.CreateStore(AI++, EltPtr);
+ Builder.CreateStore(AI, EltPtr);
}
} else {
llvm::AllocaInst *TempAlloca =
@@ -1608,20 +1932,22 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
TempAlloca->setAlignment(AlignmentToUse);
llvm::Value *TempV = TempAlloca;
+ assert(STy->getNumElements() == NumIRArgs);
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- assert(AI != Fn->arg_end() && "Argument mismatch!");
+ auto AI = FnArgs[FirstIRArg + i];
AI->setName(Arg->getName() + ".coerce" + Twine(i));
llvm::Value *EltPtr = Builder.CreateConstGEP2_32(TempV, 0, i);
- Builder.CreateStore(AI++, EltPtr);
+ Builder.CreateStore(AI, EltPtr);
}
Builder.CreateMemCpy(Ptr, TempV, DstSize, AlignmentToUse);
}
} else {
// Simple case, just do a coerced store of the argument into the alloca.
- assert(AI != Fn->arg_end() && "Argument mismatch!");
+ assert(NumIRArgs == 1);
+ auto AI = FnArgs[FirstIRArg];
AI->setName(Arg->getName() + ".coerce");
- CreateCoercedStore(AI++, Ptr, /*DestIsVolatile=*/false, *this);
+ CreateCoercedStore(AI, Ptr, /*DestIsVolatile=*/false, *this);
}
@@ -1634,7 +1960,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
} else {
ArgVals.push_back(ValueAndIsPtr(V, HavePointer));
}
- continue; // Skip ++AI increment, already done.
+ break;
}
case ABIArgInfo::Expand: {
@@ -1645,17 +1971,20 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
CharUnits Align = getContext().getDeclAlign(Arg);
Alloca->setAlignment(Align.getQuantity());
LValue LV = MakeAddrLValue(Alloca, Ty, Align);
- llvm::Function::arg_iterator End = ExpandTypeFromArgs(Ty, LV, AI);
ArgVals.push_back(ValueAndIsPtr(Alloca, HavePointer));
- // Name the arguments used in expansion and increment AI.
- unsigned Index = 0;
- for (; AI != End; ++AI, ++Index)
- AI->setName(Arg->getName() + "." + Twine(Index));
- continue;
+ auto FnArgIter = FnArgs.begin() + FirstIRArg;
+ ExpandTypeFromArgs(Ty, LV, FnArgIter);
+ assert(FnArgIter == FnArgs.begin() + FirstIRArg + NumIRArgs);
+ for (unsigned i = 0, e = NumIRArgs; i != e; ++i) {
+ auto AI = FnArgs[FirstIRArg + i];
+ AI->setName(Arg->getName() + "." + Twine(i));
+ }
+ break;
}
case ABIArgInfo::Ignore:
+ assert(NumIRArgs == 0);
// Initialize the local variable appropriately.
if (!hasScalarEvaluationKind(Ty)) {
ArgVals.push_back(ValueAndIsPtr(CreateMemTemp(Ty), HavePointer));
@@ -1663,21 +1992,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Value *U = llvm::UndefValue::get(ConvertType(Arg->getType()));
ArgVals.push_back(ValueAndIsPtr(U, HaveValue));
}
-
- // Skip increment, no matching LLVM parameter.
- continue;
+ break;
}
-
- ++AI;
-
- if (ArgNo == 1 && SwapThisWithSRet)
- ++AI; // Skip the sret parameter.
}
- if (FI.usesInAlloca())
- ++AI;
- assert(AI == Fn->arg_end() && "Argument mismatch!");
-
if (getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
for (int I = Args.size() - 1; I >= 0; --I)
EmitParmDecl(*Args[I], ArgVals[I].getPointer(), ArgVals[I].getInt(),
@@ -1887,6 +2205,12 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
bool EmitRetDbgLoc,
SourceLocation EndLoc) {
+ if (CurCodeDecl && CurCodeDecl->hasAttr<NakedAttr>()) {
+ // Naked functions don't have epilogues.
+ Builder.CreateUnreachable();
+ return;
+ }
+
// Functions with no result always return void.
if (!ReturnValue) {
Builder.CreateRetVoid();
@@ -1998,7 +2322,26 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
llvm_unreachable("Invalid ABI kind for return argument");
}
- llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
+ llvm::Instruction *Ret;
+ if (RV) {
+ if (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute)) {
+ if (auto RetNNAttr = CurGD.getDecl()->getAttr<ReturnsNonNullAttr>()) {
+ SanitizerScope SanScope(this);
+ llvm::Value *Cond = Builder.CreateICmpNE(
+ RV, llvm::Constant::getNullValue(RV->getType()));
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(EndLoc),
+ EmitCheckSourceLocation(RetNNAttr->getLocation()),
+ };
+ EmitCheck(std::make_pair(Cond, SanitizerKind::ReturnsNonnullAttribute),
+ "nonnull_return", StaticData, None);
+ }
+ }
+ Ret = Builder.CreateRet(RV);
+ } else {
+ Ret = Builder.CreateRetVoid();
+ }
+
if (!RetDbgLoc.isUnknown())
Ret->setDebugLoc(RetDbgLoc);
}
@@ -2045,19 +2388,8 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
return args.add(RValue::get(Builder.CreateLoad(local)), type);
}
- if (isInAllocaArgument(CGM.getCXXABI(), type)) {
- AggValueSlot Slot = createPlaceholderSlot(*this, type);
- Slot.setExternallyDestructed();
-
- // FIXME: Either emit a copy constructor call, or figure out how to do
- // guaranteed tail calls with perfect forwarding in LLVM.
- CGM.ErrorUnsupported(param, "non-trivial argument copy for thunk");
- EmitNullInitialization(Slot.getAddr(), type);
-
- RValue RV = Slot.asRValue();
- args.add(RV, type);
- return;
- }
+ assert(!isInAllocaArgument(CGM.getCXXABI(), type) &&
+ "cannot emit delegate call arguments for inalloca arguments!");
args.add(convertTempToRValue(local, type, loc), type);
}
@@ -2317,10 +2649,36 @@ void CallArgList::freeArgumentMemory(CodeGenFunction &CGF) const {
}
}
+static void emitNonNullArgCheck(CodeGenFunction &CGF, RValue RV,
+ QualType ArgType, SourceLocation ArgLoc,
+ const FunctionDecl *FD, unsigned ParmNum) {
+ if (!CGF.SanOpts.has(SanitizerKind::NonnullAttribute) || !FD)
+ return;
+ auto PVD = ParmNum < FD->getNumParams() ? FD->getParamDecl(ParmNum) : nullptr;
+ unsigned ArgNo = PVD ? PVD->getFunctionScopeIndex() : ParmNum;
+ auto NNAttr = getNonNullAttr(FD, PVD, ArgType, ArgNo);
+ if (!NNAttr)
+ return;
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
+ assert(RV.isScalar());
+ llvm::Value *V = RV.getScalarVal();
+ llvm::Value *Cond =
+ CGF.Builder.CreateICmpNE(V, llvm::Constant::getNullValue(V->getType()));
+ llvm::Constant *StaticData[] = {
+ CGF.EmitCheckSourceLocation(ArgLoc),
+ CGF.EmitCheckSourceLocation(NNAttr->getLocation()),
+ llvm::ConstantInt::get(CGF.Int32Ty, ArgNo + 1),
+ };
+ CGF.EmitCheck(std::make_pair(Cond, SanitizerKind::NonnullAttribute),
+ "nonnull_arg", StaticData, None);
+}
+
void CodeGenFunction::EmitCallArgs(CallArgList &Args,
ArrayRef<QualType> ArgTypes,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd,
+ const FunctionDecl *CalleeDecl,
+ unsigned ParamsToSkip,
bool ForceColumnInfo) {
CGDebugInfo *DI = getDebugInfo();
SourceLocation CallLoc;
@@ -2344,6 +2702,8 @@ void CodeGenFunction::EmitCallArgs(CallArgList &Args,
for (int I = ArgTypes.size() - 1; I >= 0; --I) {
CallExpr::const_arg_iterator Arg = ArgBeg + I;
EmitCallArg(Args, *Arg, ArgTypes[I]);
+ emitNonNullArgCheck(*this, Args.back().RV, ArgTypes[I], Arg->getExprLoc(),
+ CalleeDecl, ParamsToSkip + I);
// Restore the debug location.
if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
}
@@ -2358,6 +2718,8 @@ void CodeGenFunction::EmitCallArgs(CallArgList &Args,
CallExpr::const_arg_iterator Arg = ArgBeg + I;
assert(Arg != ArgEnd);
EmitCallArg(Args, *Arg, ArgTypes[I]);
+ emitNonNullArgCheck(*this, Args.back().RV, ArgTypes[I], Arg->getExprLoc(),
+ CalleeDecl, ParamsToSkip + I);
// Restore the debug location.
if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
}
@@ -2457,6 +2819,24 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
args.add(EmitAnyExprToTemp(E), type);
}
+QualType CodeGenFunction::getVarArgType(const Expr *Arg) {
+ // System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC
+ // implicitly widens null pointer constants that are arguments to varargs
+ // functions to pointer-sized ints.
+ if (!getTarget().getTriple().isOSWindows())
+ return Arg->getType();
+
+ if (Arg->getType()->isIntegerType() &&
+ getContext().getTypeSize(Arg->getType()) <
+ getContext().getTargetInfo().getPointerWidth(0) &&
+ Arg->isNullPointerConstant(getContext(),
+ Expr::NPC_ValueDependentIsNotNull)) {
+ return getContext().getIntPtrType();
+ }
+
+ return Arg->getType();
+}
+
// In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC
// optimizer it can aggressively ignore unwind edges.
void
@@ -2471,7 +2851,7 @@ CodeGenFunction::AddObjCARCExceptionMetadata(llvm::Instruction *Inst) {
llvm::CallInst *
CodeGenFunction::EmitNounwindRuntimeCall(llvm::Value *callee,
const llvm::Twine &name) {
- return EmitNounwindRuntimeCall(callee, ArrayRef<llvm::Value*>(), name);
+ return EmitNounwindRuntimeCall(callee, None, name);
}
/// Emits a call to the given nounwind runtime function.
@@ -2489,7 +2869,7 @@ CodeGenFunction::EmitNounwindRuntimeCall(llvm::Value *callee,
llvm::CallInst *
CodeGenFunction::EmitRuntimeCall(llvm::Value *callee,
const llvm::Twine &name) {
- return EmitRuntimeCall(callee, ArrayRef<llvm::Value*>(), name);
+ return EmitRuntimeCall(callee, None, name);
}
/// Emits a simple call (never an invoke) to the given runtime
@@ -2528,7 +2908,7 @@ void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
llvm::CallSite
CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
const Twine &name) {
- return EmitRuntimeCallOrInvoke(callee, ArrayRef<llvm::Value*>(), name);
+ return EmitRuntimeCallOrInvoke(callee, None, name);
}
/// Emits a call or invoke instruction to the given runtime function.
@@ -2544,7 +2924,7 @@ CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
llvm::CallSite
CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
const Twine &Name) {
- return EmitCallOrInvoke(Callee, ArrayRef<llvm::Value *>(), Name);
+ return EmitCallOrInvoke(Callee, None, Name);
}
/// Emits a call or invoke instruction to the given function, depending
@@ -2572,73 +2952,6 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
return Inst;
}
-static void checkArgMatches(llvm::Value *Elt, unsigned &ArgNo,
- llvm::FunctionType *FTy) {
- if (ArgNo < FTy->getNumParams())
- assert(Elt->getType() == FTy->getParamType(ArgNo));
- else
- assert(FTy->isVarArg());
- ++ArgNo;
-}
-
-void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
- SmallVectorImpl<llvm::Value *> &Args,
- llvm::FunctionType *IRFuncTy) {
- if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) {
- unsigned NumElts = AT->getSize().getZExtValue();
- QualType EltTy = AT->getElementType();
- llvm::Value *Addr = RV.getAggregateAddr();
- for (unsigned Elt = 0; Elt < NumElts; ++Elt) {
- llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt);
- RValue EltRV = convertTempToRValue(EltAddr, EltTy, SourceLocation());
- ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy);
- }
- } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
- RecordDecl *RD = RT->getDecl();
- assert(RV.isAggregate() && "Unexpected rvalue during struct expansion");
- LValue LV = MakeAddrLValue(RV.getAggregateAddr(), Ty);
-
- if (RD->isUnion()) {
- const FieldDecl *LargestFD = nullptr;
- CharUnits UnionSize = CharUnits::Zero();
-
- for (const auto *FD : RD->fields()) {
- assert(!FD->isBitField() &&
- "Cannot expand structure with bit-field members.");
- CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType());
- if (UnionSize < FieldSize) {
- UnionSize = FieldSize;
- LargestFD = FD;
- }
- }
- if (LargestFD) {
- RValue FldRV = EmitRValueForField(LV, LargestFD, SourceLocation());
- ExpandTypeToArgs(LargestFD->getType(), FldRV, Args, IRFuncTy);
- }
- } else {
- for (const auto *FD : RD->fields()) {
- RValue FldRV = EmitRValueForField(LV, FD, SourceLocation());
- ExpandTypeToArgs(FD->getType(), FldRV, Args, IRFuncTy);
- }
- }
- } else if (Ty->isAnyComplexType()) {
- ComplexPairTy CV = RV.getComplexVal();
- Args.push_back(CV.first);
- Args.push_back(CV.second);
- } else {
- assert(RV.isScalar() &&
- "Unexpected non-scalar rvalue during struct expansion.");
-
- // Insert a bitcast as needed.
- llvm::Value *V = RV.getScalarVal();
- if (Args.size() < IRFuncTy->getNumParams() &&
- V->getType() != IRFuncTy->getParamType(Args.size()))
- V = Builder.CreateBitCast(V, IRFuncTy->getParamType(Args.size()));
-
- Args.push_back(V);
- }
-}
-
/// \brief Store a non-aggregate value to an address to initialize it. For
/// initialization, a non-atomic store will be used.
static void EmitInitStoreOfNonAggregate(CodeGenFunction &CGF, RValue Src,
@@ -2661,15 +2974,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
const Decl *TargetDecl,
llvm::Instruction **callOrInvoke) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.
- SmallVector<llvm::Value*, 16> Args;
// Handle struct-return functions by passing a pointer to the
// location that we would like to return into.
QualType RetTy = CallInfo.getReturnType();
const ABIArgInfo &RetAI = CallInfo.getReturnInfo();
- // IRArgNo - Keep track of the argument number in the callee we're looking at.
- unsigned IRArgNo = 0;
llvm::FunctionType *IRFuncTy =
cast<llvm::FunctionType>(
cast<llvm::PointerType>(Callee->getType())->getElementType());
@@ -2691,22 +3001,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
ArgMemory = AI;
}
+ ClangToLLVMArgMapping IRFunctionArgs(CGM.getContext(), CallInfo);
+ SmallVector<llvm::Value *, 16> IRCallArgs(IRFunctionArgs.totalIRArgs());
+
// If the call returns a temporary with struct return, create a temporary
// alloca to hold the result, unless one is given to us.
llvm::Value *SRetPtr = nullptr;
- bool SwapThisWithSRet = false;
if (RetAI.isIndirect() || RetAI.isInAlloca()) {
SRetPtr = ReturnValue.getValue();
if (!SRetPtr)
SRetPtr = CreateMemTemp(RetTy);
- if (RetAI.isIndirect()) {
- Args.push_back(SRetPtr);
- SwapThisWithSRet = RetAI.isSRetAfterThis();
- if (SwapThisWithSRet)
- IRArgNo = 1;
- checkArgMatches(SRetPtr, IRArgNo, IRFuncTy);
- if (SwapThisWithSRet)
- IRArgNo = 0;
+ if (IRFunctionArgs.hasSRetArg()) {
+ IRCallArgs[IRFunctionArgs.getSRetArgNo()] = SRetPtr;
} else {
llvm::Value *Addr =
Builder.CreateStructGEP(ArgMemory, RetAI.getInAllocaFieldIndex());
@@ -2716,26 +3022,26 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
assert(CallInfo.arg_size() == CallArgs.size() &&
"Mismatch between function signature & arguments.");
+ unsigned ArgNo = 0;
CGFunctionInfo::const_arg_iterator info_it = CallInfo.arg_begin();
for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end();
- I != E; ++I, ++info_it) {
+ I != E; ++I, ++info_it, ++ArgNo) {
const ABIArgInfo &ArgInfo = info_it->info;
RValue RV = I->RV;
- // Skip 'sret' if it came second.
- if (IRArgNo == 1 && SwapThisWithSRet)
- ++IRArgNo;
-
CharUnits TypeAlign = getContext().getTypeAlignInChars(I->Ty);
// Insert a padding argument to ensure proper alignment.
- if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) {
- Args.push_back(llvm::UndefValue::get(PaddingType));
- ++IRArgNo;
- }
+ if (IRFunctionArgs.hasPaddingArg(ArgNo))
+ IRCallArgs[IRFunctionArgs.getPaddingArgNo(ArgNo)] =
+ llvm::UndefValue::get(ArgInfo.getPaddingType());
+
+ unsigned FirstIRArg, NumIRArgs;
+ std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
switch (ArgInfo.getKind()) {
case ABIArgInfo::InAlloca: {
+ assert(NumIRArgs == 0);
assert(getTarget().getTriple().getArch() == llvm::Triple::x86);
if (RV.isAggregate()) {
// Replace the placeholder with the appropriate argument slot GEP.
@@ -2761,22 +3067,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
LValue argLV = MakeAddrLValue(Addr, I->Ty, TypeAlign);
EmitInitStoreOfNonAggregate(*this, RV, argLV);
}
- break; // Don't increment IRArgNo!
+ break;
}
case ABIArgInfo::Indirect: {
+ assert(NumIRArgs == 1);
if (RV.isScalar() || RV.isComplex()) {
// Make a temporary alloca to pass the argument.
llvm::AllocaInst *AI = CreateMemTemp(I->Ty);
if (ArgInfo.getIndirectAlign() > AI->getAlignment())
AI->setAlignment(ArgInfo.getIndirectAlign());
- Args.push_back(AI);
+ IRCallArgs[FirstIRArg] = AI;
- LValue argLV = MakeAddrLValue(Args.back(), I->Ty, TypeAlign);
+ LValue argLV = MakeAddrLValue(AI, I->Ty, TypeAlign);
EmitInitStoreOfNonAggregate(*this, RV, argLV);
-
- // Validate argument match.
- checkArgMatches(AI, IRArgNo, IRFuncTy);
} else {
// We want to avoid creating an unnecessary temporary+copy here;
// however, we need one in three cases:
@@ -2790,8 +3094,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
unsigned Align = ArgInfo.getIndirectAlign();
const llvm::DataLayout *TD = &CGM.getDataLayout();
const unsigned RVAddrSpace = Addr->getType()->getPointerAddressSpace();
- const unsigned ArgAddrSpace = (IRArgNo < IRFuncTy->getNumParams() ?
- IRFuncTy->getParamType(IRArgNo)->getPointerAddressSpace() : 0);
+ const unsigned ArgAddrSpace =
+ (FirstIRArg < IRFuncTy->getNumParams()
+ ? IRFuncTy->getParamType(FirstIRArg)->getPointerAddressSpace()
+ : 0);
if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) ||
(ArgInfo.getIndirectByVal() && TypeAlign.getQuantity() < Align &&
llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align) ||
@@ -2800,23 +3106,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::AllocaInst *AI = CreateMemTemp(I->Ty);
if (Align > AI->getAlignment())
AI->setAlignment(Align);
- Args.push_back(AI);
+ IRCallArgs[FirstIRArg] = AI;
EmitAggregateCopy(AI, Addr, I->Ty, RV.isVolatileQualified());
-
- // Validate argument match.
- checkArgMatches(AI, IRArgNo, IRFuncTy);
} else {
// Skip the extra memcpy call.
- Args.push_back(Addr);
-
- // Validate argument match.
- checkArgMatches(Addr, IRArgNo, IRFuncTy);
+ IRCallArgs[FirstIRArg] = Addr;
}
}
break;
}
case ABIArgInfo::Ignore:
+ assert(NumIRArgs == 0);
break;
case ABIArgInfo::Extend:
@@ -2824,20 +3125,24 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) &&
ArgInfo.getCoerceToType() == ConvertType(info_it->type) &&
ArgInfo.getDirectOffset() == 0) {
+ assert(NumIRArgs == 1);
llvm::Value *V;
if (RV.isScalar())
V = RV.getScalarVal();
else
V = Builder.CreateLoad(RV.getAggregateAddr());
-
+
+ // We might have to widen integers, but we should never truncate.
+ if (ArgInfo.getCoerceToType() != V->getType() &&
+ V->getType()->isIntegerTy())
+ V = Builder.CreateZExt(V, ArgInfo.getCoerceToType());
+
// If the argument doesn't match, perform a bitcast to coerce it. This
// can happen due to trivial type mismatches.
- if (IRArgNo < IRFuncTy->getNumParams() &&
- V->getType() != IRFuncTy->getParamType(IRArgNo))
- V = Builder.CreateBitCast(V, IRFuncTy->getParamType(IRArgNo));
- Args.push_back(V);
-
- checkArgMatches(V, IRArgNo, IRFuncTy);
+ if (FirstIRArg < IRFuncTy->getNumParams() &&
+ V->getType() != IRFuncTy->getParamType(FirstIRArg))
+ V = Builder.CreateBitCast(V, IRFuncTy->getParamType(FirstIRArg));
+ IRCallArgs[FirstIRArg] = V;
break;
}
@@ -2859,14 +3164,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
- // If the coerce-to type is a first class aggregate, we flatten it and
- // pass the elements. Either way is semantically identical, but fast-isel
- // and the optimizer generally likes scalar values better than FCAs.
- // We cannot do this for functions using the AAPCS calling convention,
- // as structures are treated differently by that calling convention.
+ // Fast-isel and the optimizer generally like scalar values better than
+ // FCAs, so we flatten them if this is safe to do for this argument.
llvm::StructType *STy =
dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType());
- if (STy && !isAAPCSVFP(CallInfo, getTarget())) {
+ if (STy && ArgInfo.isDirect() && ArgInfo.getCanBeFlattened()) {
llvm::Type *SrcTy =
cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
@@ -2886,38 +3188,32 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::PointerType::getUnqual(STy));
}
+ assert(NumIRArgs == STy->getNumElements());
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
llvm::Value *EltPtr = Builder.CreateConstGEP2_32(SrcPtr, 0, i);
llvm::LoadInst *LI = Builder.CreateLoad(EltPtr);
// We don't know what we're loading from.
LI->setAlignment(1);
- Args.push_back(LI);
-
- // Validate argument match.
- checkArgMatches(LI, IRArgNo, IRFuncTy);
+ IRCallArgs[FirstIRArg + i] = LI;
}
} else {
// In the simple case, just pass the coerced loaded value.
- Args.push_back(CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(),
- *this));
-
- // Validate argument match.
- checkArgMatches(Args.back(), IRArgNo, IRFuncTy);
+ assert(NumIRArgs == 1);
+ IRCallArgs[FirstIRArg] =
+ CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(), *this);
}
break;
}
case ABIArgInfo::Expand:
- ExpandTypeToArgs(I->Ty, RV, Args, IRFuncTy);
- IRArgNo = Args.size();
+ unsigned IRArgPos = FirstIRArg;
+ ExpandTypeToArgs(I->Ty, RV, IRFuncTy, IRCallArgs, IRArgPos);
+ assert(IRArgPos == FirstIRArg + NumIRArgs);
break;
}
}
- if (SwapThisWithSRet)
- std::swap(Args[0], Args[1]);
-
if (ArgMemory) {
llvm::Value *Arg = ArgMemory;
if (CallInfo.isVariadic()) {
@@ -2948,7 +3244,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Arg = Builder.CreateBitCast(Arg, LastParamTy);
}
}
- Args.push_back(Arg);
+ assert(IRFunctionArgs.hasInallocaArg());
+ IRCallArgs[IRFunctionArgs.getInallocaArgNo()] = Arg;
}
if (!CallArgs.getCleanupsToDeactivate().empty())
@@ -2967,7 +3264,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (CE->getOpcode() == llvm::Instruction::BitCast &&
ActualFT->getReturnType() == CurFT->getReturnType() &&
ActualFT->getNumParams() == CurFT->getNumParams() &&
- ActualFT->getNumParams() == Args.size() &&
+ ActualFT->getNumParams() == IRCallArgs.size() &&
(CurFT->isVarArg() || !ActualFT->isVarArg())) {
bool ArgsMatch = true;
for (unsigned i = 0, e = ActualFT->getNumParams(); i != e; ++i)
@@ -2984,6 +3281,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
}
+ assert(IRCallArgs.size() == IRFuncTy->getNumParams() || IRFuncTy->isVarArg());
+ for (unsigned i = 0; i < IRCallArgs.size(); ++i) {
+ // Inalloca argument can have different type.
+ if (IRFunctionArgs.hasInallocaArg() &&
+ i == IRFunctionArgs.getInallocaArgNo())
+ continue;
+ if (i < IRFuncTy->getNumParams())
+ assert(IRCallArgs[i]->getType() == IRFuncTy->getParamType(i));
+ }
+
unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList,
@@ -2998,10 +3305,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::CallSite CS;
if (!InvokeDest) {
- CS = Builder.CreateCall(Callee, Args);
+ CS = Builder.CreateCall(Callee, IRCallArgs);
} else {
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
- CS = Builder.CreateInvoke(Callee, Cont, InvokeDest, Args);
+ CS = Builder.CreateInvoke(Callee, Cont, InvokeDest, IRCallArgs);
EmitBlock(Cont);
}
if (callOrInvoke)
@@ -3050,75 +3357,92 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// lexical order, so deactivate it and run it manually here.
CallArgs.freeArgumentMemory(*this);
- switch (RetAI.getKind()) {
- case ABIArgInfo::InAlloca:
- case ABIArgInfo::Indirect:
- return convertTempToRValue(SRetPtr, RetTy, SourceLocation());
+ RValue Ret = [&] {
+ switch (RetAI.getKind()) {
+ case ABIArgInfo::InAlloca:
+ case ABIArgInfo::Indirect:
+ return convertTempToRValue(SRetPtr, RetTy, SourceLocation());
- case ABIArgInfo::Ignore:
- // If we are ignoring an argument that had a result, make sure to
- // construct the appropriate return value for our caller.
- return GetUndefRValue(RetTy);
+ case ABIArgInfo::Ignore:
+ // If we are ignoring an argument that had a result, make sure to
+ // construct the appropriate return value for our caller.
+ return GetUndefRValue(RetTy);
- case ABIArgInfo::Extend:
- case ABIArgInfo::Direct: {
- llvm::Type *RetIRTy = ConvertType(RetTy);
- if (RetAI.getCoerceToType() == RetIRTy && RetAI.getDirectOffset() == 0) {
- switch (getEvaluationKind(RetTy)) {
- case TEK_Complex: {
- llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
- llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
- return RValue::getComplex(std::make_pair(Real, Imag));
- }
- case TEK_Aggregate: {
- llvm::Value *DestPtr = ReturnValue.getValue();
- bool DestIsVolatile = ReturnValue.isVolatile();
+ case ABIArgInfo::Extend:
+ case ABIArgInfo::Direct: {
+ llvm::Type *RetIRTy = ConvertType(RetTy);
+ if (RetAI.getCoerceToType() == RetIRTy && RetAI.getDirectOffset() == 0) {
+ switch (getEvaluationKind(RetTy)) {
+ case TEK_Complex: {
+ llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
+ llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
+ return RValue::getComplex(std::make_pair(Real, Imag));
+ }
+ case TEK_Aggregate: {
+ llvm::Value *DestPtr = ReturnValue.getValue();
+ bool DestIsVolatile = ReturnValue.isVolatile();
- if (!DestPtr) {
- DestPtr = CreateMemTemp(RetTy, "agg.tmp");
- DestIsVolatile = false;
+ if (!DestPtr) {
+ DestPtr = CreateMemTemp(RetTy, "agg.tmp");
+ DestIsVolatile = false;
+ }
+ BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false);
+ return RValue::getAggregate(DestPtr);
}
- BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false);
- return RValue::getAggregate(DestPtr);
- }
- case TEK_Scalar: {
- // If the argument doesn't match, perform a bitcast to coerce it. This
- // can happen due to trivial type mismatches.
- llvm::Value *V = CI;
- if (V->getType() != RetIRTy)
- V = Builder.CreateBitCast(V, RetIRTy);
- return RValue::get(V);
+ case TEK_Scalar: {
+ // If the argument doesn't match, perform a bitcast to coerce it. This
+ // can happen due to trivial type mismatches.
+ llvm::Value *V = CI;
+ if (V->getType() != RetIRTy)
+ V = Builder.CreateBitCast(V, RetIRTy);
+ return RValue::get(V);
+ }
+ }
+ llvm_unreachable("bad evaluation kind");
}
+
+ llvm::Value *DestPtr = ReturnValue.getValue();
+ bool DestIsVolatile = ReturnValue.isVolatile();
+
+ if (!DestPtr) {
+ DestPtr = CreateMemTemp(RetTy, "coerce");
+ DestIsVolatile = false;
}
- llvm_unreachable("bad evaluation kind");
- }
- llvm::Value *DestPtr = ReturnValue.getValue();
- bool DestIsVolatile = ReturnValue.isVolatile();
+ // If the value is offset in memory, apply the offset now.
+ llvm::Value *StorePtr = DestPtr;
+ if (unsigned Offs = RetAI.getDirectOffset()) {
+ StorePtr = Builder.CreateBitCast(StorePtr, Builder.getInt8PtrTy());
+ StorePtr = Builder.CreateConstGEP1_32(StorePtr, Offs);
+ StorePtr = Builder.CreateBitCast(StorePtr,
+ llvm::PointerType::getUnqual(RetAI.getCoerceToType()));
+ }
+ CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
- if (!DestPtr) {
- DestPtr = CreateMemTemp(RetTy, "coerce");
- DestIsVolatile = false;
+ return convertTempToRValue(DestPtr, RetTy, SourceLocation());
}
- // If the value is offset in memory, apply the offset now.
- llvm::Value *StorePtr = DestPtr;
- if (unsigned Offs = RetAI.getDirectOffset()) {
- StorePtr = Builder.CreateBitCast(StorePtr, Builder.getInt8PtrTy());
- StorePtr = Builder.CreateConstGEP1_32(StorePtr, Offs);
- StorePtr = Builder.CreateBitCast(StorePtr,
- llvm::PointerType::getUnqual(RetAI.getCoerceToType()));
+ case ABIArgInfo::Expand:
+ llvm_unreachable("Invalid ABI kind for return argument");
}
- CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
- return convertTempToRValue(DestPtr, RetTy, SourceLocation());
- }
+ llvm_unreachable("Unhandled ABIArgInfo::Kind");
+ } ();
- case ABIArgInfo::Expand:
- llvm_unreachable("Invalid ABI kind for return argument");
+ if (Ret.isScalar() && TargetDecl) {
+ if (const auto *AA = TargetDecl->getAttr<AssumeAlignedAttr>()) {
+ llvm::Value *OffsetValue = nullptr;
+ if (const auto *Offset = AA->getOffset())
+ OffsetValue = EmitScalarExpr(Offset);
+
+ llvm::Value *Alignment = EmitScalarExpr(AA->getAlignment());
+ llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(Alignment);
+ EmitAlignmentAssumption(Ret.getScalarVal(), AlignmentCI->getZExtValue(),
+ OffsetValue);
+ }
}
- llvm_unreachable("Unhandled ABIArgInfo::Kind");
+ return Ret;
}
/* VarArg handling */
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 9510a1cd5461..b228733fb8ce 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CGCALL_H
-#define CLANG_CODEGEN_CGCALL_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGCALL_H
+#define LLVM_CLANG_LIB_CODEGEN_CGCALL_H
#include "CGValue.h"
#include "EHScopeStack.h"
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 9427de14d704..92c694a76de7 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -134,12 +134,11 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ptr,
return ptr;
}
-llvm::Value *
-CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
- const CXXRecordDecl *Derived,
- CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd,
- bool NullCheckValue) {
+llvm::Value *CodeGenFunction::GetAddressOfBaseClass(
+ llvm::Value *Value, const CXXRecordDecl *Derived,
+ CastExpr::path_const_iterator PathBegin,
+ CastExpr::path_const_iterator PathEnd, bool NullCheckValue,
+ SourceLocation Loc) {
assert(PathBegin != PathEnd && "Base path should not be empty!");
CastExpr::path_const_iterator Start = PathBegin;
@@ -176,9 +175,16 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
llvm::Type *BasePtrTy =
ConvertType((PathEnd[-1])->getType())->getPointerTo();
+ QualType DerivedTy = getContext().getRecordType(Derived);
+ CharUnits DerivedAlign = getContext().getTypeAlignInChars(DerivedTy);
+
// If the static offset is zero and we don't have a virtual step,
// just do a bitcast; null checks are unnecessary.
if (NonVirtualOffset.isZero() && !VBase) {
+ if (sanitizePerformTypeCheck()) {
+ EmitTypeCheck(TCK_Upcast, Loc, Value, DerivedTy, DerivedAlign,
+ !NullCheckValue);
+ }
return Builder.CreateBitCast(Value, BasePtrTy);
}
@@ -197,6 +203,11 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
EmitBlock(notNullBB);
}
+ if (sanitizePerformTypeCheck()) {
+ EmitTypeCheck(VBase ? TCK_UpcastToVirtualBase : TCK_Upcast, Loc, Value,
+ DerivedTy, DerivedAlign, true);
+ }
+
// Compute the virtual offset.
llvm::Value *VirtualOffset = nullptr;
if (VBase) {
@@ -533,6 +544,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
CXXCtorInitializer *MemberInit,
const CXXConstructorDecl *Constructor,
FunctionArgList &Args) {
+ ApplyDebugLocation Loc(CGF, MemberInit->getMemberLocation());
assert(MemberInit->isAnyMemberInitializer() &&
"Must have member initializer!");
assert(MemberInit->getInit() && "Must have initializer!");
@@ -569,9 +581,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(MemberInit->getInit());
if (BaseElementTy.isPODType(CGF.getContext()) ||
(CE && CE->getConstructor()->isTrivial())) {
- // Find the source pointer. We know it's the last argument because
- // we know we're in an implicit copy constructor.
- unsigned SrcArgIndex = Args.size() - 1;
+ unsigned SrcArgIndex =
+ CGF.CGM.getCXXABI().getSrcArgforCopyCtor(Constructor, Args);
llvm::Value *SrcPtr
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex]));
LValue ThisRHSLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy);
@@ -587,12 +598,13 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
ArrayRef<VarDecl *> ArrayIndexes;
if (MemberInit->getNumArrayIndices())
ArrayIndexes = MemberInit->getArrayIndexes();
+ ApplyDebugLocation DL(CGF, MemberInit->getMemberLocation());
CGF.EmitInitializerForField(Field, LHS, MemberInit->getInit(), ArrayIndexes);
}
-void CodeGenFunction::EmitInitializerForField(FieldDecl *Field,
- LValue LHS, Expr *Init,
- ArrayRef<VarDecl *> ArrayIndexes) {
+void CodeGenFunction::EmitInitializerForField(
+ FieldDecl *Field, LValue LHS, Expr *Init,
+ ArrayRef<VarDecl *> ArrayIndexes) {
QualType FieldType = Field->getType();
switch (getEvaluationKind(FieldType)) {
case TEK_Scalar:
@@ -692,8 +704,74 @@ static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor) {
return true;
}
+// Emit code in ctor (Prologue==true) or dtor (Prologue==false)
+// to poison the extra field paddings inserted under
+// -fsanitize-address-field-padding=1|2.
+void CodeGenFunction::EmitAsanPrologueOrEpilogue(bool Prologue) {
+ ASTContext &Context = getContext();
+ const CXXRecordDecl *ClassDecl =
+ Prologue ? cast<CXXConstructorDecl>(CurGD.getDecl())->getParent()
+ : cast<CXXDestructorDecl>(CurGD.getDecl())->getParent();
+ if (!ClassDecl->mayInsertExtraPadding()) return;
+
+ struct SizeAndOffset {
+ uint64_t Size;
+ uint64_t Offset;
+ };
+
+ unsigned PtrSize = CGM.getDataLayout().getPointerSizeInBits();
+ const ASTRecordLayout &Info = Context.getASTRecordLayout(ClassDecl);
+
+ // Populate sizes and offsets of fields.
+ SmallVector<SizeAndOffset, 16> SSV(Info.getFieldCount());
+ for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i)
+ SSV[i].Offset =
+ Context.toCharUnitsFromBits(Info.getFieldOffset(i)).getQuantity();
+
+ size_t NumFields = 0;
+ for (const auto *Field : ClassDecl->fields()) {
+ const FieldDecl *D = Field;
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(D->getType());
+ CharUnits FieldSize = FieldInfo.first;
+ assert(NumFields < SSV.size());
+ SSV[NumFields].Size = D->isBitField() ? 0 : FieldSize.getQuantity();
+ NumFields++;
+ }
+ assert(NumFields == SSV.size());
+ if (SSV.size() <= 1) return;
+
+ // We will insert calls to __asan_* run-time functions.
+ // LLVM AddressSanitizer pass may decide to inline them later.
+ llvm::Type *Args[2] = {IntPtrTy, IntPtrTy};
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, Args, false);
+ llvm::Constant *F = CGM.CreateRuntimeFunction(
+ FTy, Prologue ? "__asan_poison_intra_object_redzone"
+ : "__asan_unpoison_intra_object_redzone");
+
+ llvm::Value *ThisPtr = LoadCXXThis();
+ ThisPtr = Builder.CreatePtrToInt(ThisPtr, IntPtrTy);
+ uint64_t TypeSize = Info.getNonVirtualSize().getQuantity();
+ // For each field check if it has sufficient padding,
+ // if so (un)poison it with a call.
+ for (size_t i = 0; i < SSV.size(); i++) {
+ uint64_t AsanAlignment = 8;
+ uint64_t NextField = i == SSV.size() - 1 ? TypeSize : SSV[i + 1].Offset;
+ uint64_t PoisonSize = NextField - SSV[i].Offset - SSV[i].Size;
+ uint64_t EndOffset = SSV[i].Offset + SSV[i].Size;
+ if (PoisonSize < AsanAlignment || !SSV[i].Size ||
+ (NextField % AsanAlignment) != 0)
+ continue;
+ Builder.CreateCall2(
+ F, Builder.CreateAdd(ThisPtr, Builder.getIntN(PtrSize, EndOffset)),
+ Builder.getIntN(PtrSize, PoisonSize));
+ }
+}
+
/// EmitConstructorBody - Emits the body of the current constructor.
void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
+ EmitAsanPrologueOrEpilogue(true);
const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl());
CXXCtorType CtorType = CurGD.getCtorType();
@@ -705,13 +783,13 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
// delegation optimization.
if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) &&
CGM.getTarget().getCXXABI().hasConstructorVariants()) {
- if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitLocation(Builder, Ctor->getLocEnd());
EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args, Ctor->getLocEnd());
return;
}
- Stmt *Body = Ctor->getBody();
+ const FunctionDecl *Definition = 0;
+ Stmt *Body = Ctor->getBody(Definition);
+ assert(Definition == Ctor && "emitting wrong constructor body");
// Enter the function-try-block before the constructor prologue if
// applicable.
@@ -755,18 +833,16 @@ namespace {
class CopyingValueRepresentation {
public:
explicit CopyingValueRepresentation(CodeGenFunction &CGF)
- : CGF(CGF), SO(*CGF.SanOpts), OldSanOpts(CGF.SanOpts) {
- SO.Bool = false;
- SO.Enum = false;
- CGF.SanOpts = &SO;
+ : CGF(CGF), OldSanOpts(CGF.SanOpts) {
+ CGF.SanOpts.set(SanitizerKind::Bool, false);
+ CGF.SanOpts.set(SanitizerKind::Enum, false);
}
~CopyingValueRepresentation() {
CGF.SanOpts = OldSanOpts;
}
private:
CodeGenFunction &CGF;
- SanitizerOptions SO;
- const SanitizerOptions *OldSanOpts;
+ SanitizerSet OldSanOpts;
};
}
@@ -780,7 +856,10 @@ namespace {
FirstField(nullptr), LastField(nullptr), FirstFieldOffset(0),
LastFieldOffset(0), LastAddedFieldIndex(0) {}
- static bool isMemcpyableField(FieldDecl *F) {
+ bool isMemcpyableField(FieldDecl *F) const {
+ // Never memcpy fields when we are adding poisoned paddings.
+ if (CGF.getContext().getLangOpts().SanitizeAddressFieldPadding)
+ return false;
Qualifiers Qual = F->getType().getQualifiers();
if (Qual.hasVolatile() || Qual.hasObjCLifetime())
return false;
@@ -794,13 +873,13 @@ namespace {
addNextField(F);
}
- CharUnits getMemcpySize() const {
+ CharUnits getMemcpySize(uint64_t FirstByteOffset) const {
unsigned LastFieldSize =
LastField->isBitField() ?
LastField->getBitWidthValue(CGF.getContext()) :
CGF.getContext().getTypeSize(LastField->getType());
uint64_t MemcpySizeBits =
- LastFieldOffset + LastFieldSize - FirstFieldOffset +
+ LastFieldOffset + LastFieldSize - FirstByteOffset +
CGF.getContext().getCharWidth() - 1;
CharUnits MemcpySize =
CGF.getContext().toCharUnitsFromBits(MemcpySizeBits);
@@ -816,19 +895,31 @@ namespace {
CharUnits Alignment;
+ uint64_t FirstByteOffset;
if (FirstField->isBitField()) {
const CGRecordLayout &RL =
CGF.getTypes().getCGRecordLayout(FirstField->getParent());
const CGBitFieldInfo &BFInfo = RL.getBitFieldInfo(FirstField);
Alignment = CharUnits::fromQuantity(BFInfo.StorageAlignment);
+ // FirstFieldOffset is not appropriate for bitfields,
+ // it won't tell us what the storage offset should be and thus might not
+ // be properly aligned.
+ //
+ // Instead calculate the storage offset using the offset of the field in
+ // the struct type.
+ const llvm::DataLayout &DL = CGF.CGM.getDataLayout();
+ FirstByteOffset =
+ DL.getStructLayout(RL.getLLVMType())
+ ->getElementOffsetInBits(RL.getLLVMFieldNo(FirstField));
} else {
Alignment = CGF.getContext().getDeclAlign(FirstField);
+ FirstByteOffset = FirstFieldOffset;
}
- assert((CGF.getContext().toCharUnitsFromBits(FirstFieldOffset) %
+ assert((CGF.getContext().toCharUnitsFromBits(FirstByteOffset) %
Alignment) == 0 && "Bad field alignment.");
- CharUnits MemcpySize = getMemcpySize();
+ CharUnits MemcpySize = getMemcpySize(FirstByteOffset);
QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
llvm::Value *ThisPtr = CGF.LoadCXXThis();
LValue DestLV = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
@@ -912,11 +1003,12 @@ namespace {
private:
/// Get source argument for copy constructor. Returns null if not a copy
- /// constructor.
- static const VarDecl* getTrivialCopySource(const CXXConstructorDecl *CD,
+ /// constructor.
+ static const VarDecl *getTrivialCopySource(CodeGenFunction &CGF,
+ const CXXConstructorDecl *CD,
FunctionArgList &Args) {
if (CD->isCopyOrMoveConstructor() && CD->isDefaulted())
- return Args[Args.size() - 1];
+ return Args[CGF.CGM.getCXXABI().getSrcArgforCopyCtor(CD, Args)];
return nullptr;
}
@@ -947,7 +1039,7 @@ namespace {
public:
ConstructorMemcpyizer(CodeGenFunction &CGF, const CXXConstructorDecl *CD,
FunctionArgList &Args)
- : FieldMemcpyizer(CGF, CD->getParent(), getTrivialCopySource(CD, Args)),
+ : FieldMemcpyizer(CGF, CD->getParent(), getTrivialCopySource(CGF, CD, Args)),
ConstructorDecl(CD),
MemcpyableCtor(CD->isDefaulted() &&
CD->isCopyOrMoveConstructor() &&
@@ -1279,6 +1371,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
bool isTryBody = (Body && isa<CXXTryStmt>(Body));
if (isTryBody)
EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true);
+ EmitAsanPrologueOrEpilogue(false);
// Enter the epilogue cleanups.
RunCleanupsScope DtorEpilogue(*this);
@@ -1289,6 +1382,9 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// we'd introduce *two* handler blocks. In the Microsoft ABI, we
// always delegate because we might not have a definition in this TU.
switch (DtorType) {
+ case Dtor_Comdat:
+ llvm_unreachable("not expecting a COMDAT");
+
case Dtor_Deleting: llvm_unreachable("already handled deleting case");
case Dtor_Complete:
@@ -1515,19 +1611,14 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
/// \param arrayBegin an arrayType*
/// \param zeroInitialize true if each element should be
/// zero-initialized before it is constructed
-void
-CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
- const ConstantArrayType *arrayType,
- llvm::Value *arrayBegin,
- CallExpr::const_arg_iterator argBegin,
- CallExpr::const_arg_iterator argEnd,
- bool zeroInitialize) {
+void CodeGenFunction::EmitCXXAggrConstructorCall(
+ const CXXConstructorDecl *ctor, const ConstantArrayType *arrayType,
+ llvm::Value *arrayBegin, const CXXConstructExpr *E, bool zeroInitialize) {
QualType elementType;
llvm::Value *numElements =
emitArrayLength(arrayType, elementType, arrayBegin);
- EmitCXXAggrConstructorCall(ctor, numElements, arrayBegin,
- argBegin, argEnd, zeroInitialize);
+ EmitCXXAggrConstructorCall(ctor, numElements, arrayBegin, E, zeroInitialize);
}
/// EmitCXXAggrConstructorCall - Emit a loop to call a particular
@@ -1539,13 +1630,11 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
/// \param arrayBegin a T*, where T is the type constructed by ctor
/// \param zeroInitialize true if each element should be
/// zero-initialized before it is constructed
-void
-CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
- llvm::Value *numElements,
- llvm::Value *arrayBegin,
- CallExpr::const_arg_iterator argBegin,
- CallExpr::const_arg_iterator argEnd,
- bool zeroInitialize) {
+void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
+ llvm::Value *numElements,
+ llvm::Value *arrayBegin,
+ const CXXConstructExpr *E,
+ bool zeroInitialize) {
// It's legal for numElements to be zero. This can happen both
// dynamically, because x can be zero in 'new A[x]', and statically,
@@ -1608,8 +1697,8 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
pushRegularPartialArrayCleanup(arrayBegin, cur, type, *destroyer);
}
- EmitCXXConstructorCall(ctor, Ctor_Complete, /*ForVirtualBase=*/ false,
- /*Delegating=*/false, cur, argBegin, argEnd);
+ EmitCXXConstructorCall(ctor, Ctor_Complete, /*ForVirtualBase=*/false,
+ /*Delegating=*/false, cur, E);
}
// Go to the next element.
@@ -1640,29 +1729,27 @@ void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF,
/*Delegating=*/false, addr);
}
-void
-CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
+void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ bool ForVirtualBase,
+ bool Delegating, llvm::Value *This,
+ const CXXConstructExpr *E) {
// If this is a trivial constructor, just emit what's needed.
- if (D->isTrivial()) {
- if (ArgBeg == ArgEnd) {
+ if (D->isTrivial() && !D->getParent()->mayInsertExtraPadding()) {
+ if (E->getNumArgs() == 0) {
// Trivial default constructor, no codegen required.
assert(D->isDefaultConstructor() &&
"trivial 0-arg ctor not a default ctor");
return;
}
- assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor");
+ assert(E->getNumArgs() == 1 && "unexpected argcount for trivial ctor");
assert(D->isCopyOrMoveConstructor() &&
"trivial 1-arg ctor not a copy/move ctor");
- const Expr *E = (*ArgBeg);
- QualType Ty = E->getType();
- llvm::Value *Src = EmitLValue(E).getAddress();
+ const Expr *Arg = E->getArg(0);
+ QualType Ty = Arg->getType();
+ llvm::Value *Src = EmitLValue(Arg).getAddress();
EmitAggregateCopy(This, Src, Ty);
return;
}
@@ -1681,14 +1768,14 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
// Add the rest of the user-supplied arguments.
const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
- EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
+ EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end(), E->getConstructor());
// Insert any ABI-specific implicit constructor arguments.
unsigned ExtraArgs = CGM.getCXXABI().addImplicitConstructorArgs(
*this, D, Type, ForVirtualBase, Delegating, Args);
// Emit the call.
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
+ llvm::Value *Callee = CGM.getAddrOfCXXStructor(D, getFromCtorType(Type));
const CGFunctionInfo &Info =
CGM.getTypes().arrangeCXXConstructorCall(Args, D, Type, ExtraArgs);
EmitCall(Info, Callee, ReturnValueSlot(), Args, D);
@@ -1697,16 +1784,16 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
void
CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
llvm::Value *This, llvm::Value *Src,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
- if (D->isTrivial()) {
- assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor");
+ const CXXConstructExpr *E) {
+ if (D->isTrivial() &&
+ !D->getParent()->mayInsertExtraPadding()) {
+ assert(E->getNumArgs() == 1 && "unexpected argcount for trivial ctor");
assert(D->isCopyOrMoveConstructor() &&
"trivial 1-arg ctor not a copy/move ctor");
- EmitAggregateCopy(This, Src, (*ArgBeg)->getType());
+ EmitAggregateCopy(This, Src, E->arg_begin()->getType());
return;
}
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, clang::Ctor_Complete);
+ llvm::Value *Callee = CGM.getAddrOfCXXStructor(D, StructorType::Complete);
assert(D->isInstance() &&
"Trying to emit a member call expr on a static method!");
@@ -1724,8 +1811,8 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
Args.add(RValue::get(Src), QT);
// Skip over first argument (Src).
- EmitCallArgs(Args, FPT->isVariadic(), FPT->param_type_begin() + 1,
- FPT->param_type_end(), ArgBeg + 1, ArgEnd);
+ EmitCallArgs(Args, FPT, E->arg_begin() + 1, E->arg_end(), E->getConstructor(),
+ /*ParamsToSkip*/ 1);
EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, RequiredArgs::All),
Callee, ReturnValueSlot(), Args, D);
@@ -1766,8 +1853,10 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
EmitDelegateCallArg(DelegateArgs, param, Loc);
}
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
- EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
+ llvm::Value *Callee =
+ CGM.getAddrOfCXXStructor(Ctor, getFromCtorType(CtorType));
+ EmitCall(CGM.getTypes()
+ .arrangeCXXStructorDeclaration(Ctor, getFromCtorType(CtorType)),
Callee, ReturnValueSlot(), DelegateArgs, Ctor);
}
@@ -1894,10 +1983,14 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
NonVirtualOffset,
VirtualOffset);
- // Finally, store the address point.
- llvm::Type *AddressPointPtrTy =
- VTableAddressPoint->getType()->getPointerTo();
- VTableField = Builder.CreateBitCast(VTableField, AddressPointPtrTy);
+ // Finally, store the address point. Use the same LLVM types as the field to
+ // support optimization.
+ llvm::Type *VTablePtrTy =
+ llvm::FunctionType::get(CGM.Int32Ty, /*isVarArg=*/true)
+ ->getPointerTo()
+ ->getPointerTo();
+ VTableField = Builder.CreateBitCast(VTableField, VTablePtrTy->getPointerTo());
+ VTableAddressPoint = Builder.CreateBitCast(VTableAddressPoint, VTablePtrTy);
llvm::StoreInst *Store = Builder.CreateStore(VTableAddressPoint, VTableField);
CGM.DecorateInstruction(Store, CGM.getTBAAInfoForVTablePtr());
}
@@ -1934,7 +2027,7 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
if (I.isVirtual()) {
// Check if we've visited this virtual base before.
- if (!VBases.insert(BaseDecl))
+ if (!VBases.insert(BaseDecl).second)
continue;
const ASTRecordLayout &Layout =
@@ -2075,20 +2168,6 @@ CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base,
return false;
}
-llvm::Value *
-CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
- const CXXMethodDecl *MD,
- llvm::Value *This) {
- llvm::FunctionType *fnType =
- CGM.getTypes().GetFunctionType(
- CGM.getTypes().arrangeCXXMethodDeclaration(MD));
-
- if (MD->isVirtual() && !CanDevirtualizeMemberFunctionCall(E->getArg(0), MD))
- return CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, fnType);
-
- return CGM.GetAddrOfFunction(MD, fnType);
-}
-
void CodeGenFunction::EmitForwardingCallToLambda(
const CXXMethodDecl *callOperator,
CallArgList &callArgs) {
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index ed9f96df7987..18ed3e543d20 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -184,7 +184,7 @@ void EHScopeStack::popCleanup() {
StartOfData += Cleanup.getAllocatedSize();
// Destroy the cleanup.
- Cleanup.~EHCleanupScope();
+ Cleanup.Destroy();
// Check whether we can shrink the branch-fixups stack.
if (!BranchFixups.empty()) {
@@ -301,7 +301,8 @@ static void ResolveAllBranchFixups(CodeGenFunction &CGF,
}
// Don't add this case to the switch statement twice.
- if (!CasesAdded.insert(Fixup.Destination)) continue;
+ if (!CasesAdded.insert(Fixup.Destination).second)
+ continue;
Switch->addCase(CGF.Builder.getInt32(Fixup.DestinationIndex),
Fixup.Destination);
@@ -357,7 +358,7 @@ void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) {
continue;
// Don't process the same optimistic branch block twice.
- if (!ModifiedOptimisticBlocks.insert(BranchBB))
+ if (!ModifiedOptimisticBlocks.insert(BranchBB).second)
continue;
llvm::SwitchInst *Switch = TransitionToCleanupSwitch(*this, BranchBB);
@@ -860,10 +861,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// Emit the EH cleanup if required.
if (RequiresEHCleanup) {
- CGDebugInfo *DI = getDebugInfo();
- SaveAndRestoreLocation AutoRestoreLocation(*this, Builder);
- if (DI)
- DI->EmitLocation(Builder, CurEHLocation);
+ ApplyDebugLocation AutoRestoreLocation(*this, CurEHLocation);
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
diff --git a/lib/CodeGen/CGCleanup.h b/lib/CodeGen/CGCleanup.h
index 1d4606f13669..dd156c696ad3 100644
--- a/lib/CodeGen/CGCleanup.h
+++ b/lib/CodeGen/CGCleanup.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CGCLEANUP_H
-#define CLANG_CODEGEN_CGCLEANUP_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H
+#define LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H
#include "EHScopeStack.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -280,9 +280,11 @@ public:
assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow");
}
- ~EHCleanupScope() {
+ void Destroy() {
delete ExtInfo;
}
+ // Objects of EHCleanupScope are not destructed. Use Destroy().
+ ~EHCleanupScope() LLVM_DELETED_FUNCTION;
bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; }
llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
@@ -341,7 +343,7 @@ public:
void addBranchAfter(llvm::ConstantInt *Index,
llvm::BasicBlock *Block) {
struct ExtInfo &ExtInfo = getExtInfo();
- if (ExtInfo.Branches.insert(Block))
+ if (ExtInfo.Branches.insert(Block).second)
ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
}
@@ -376,7 +378,7 @@ public:
///
/// \return true if the branch-through was new to this scope
bool addBranchThrough(llvm::BasicBlock *Block) {
- return getExtInfo().Branches.insert(Block);
+ return getExtInfo().Branches.insert(Block).second;
}
/// Determines if this cleanup scope has any branch throughs.
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 048c8f8f3674..978e1bb5b81f 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -52,64 +52,59 @@ CGDebugInfo::~CGDebugInfo() {
"Region stack mismatch, stack not empty!");
}
-SaveAndRestoreLocation::SaveAndRestoreLocation(CodeGenFunction &CGF,
- CGBuilderTy &B)
- : DI(CGF.getDebugInfo()), Builder(B) {
- if (DI) {
- SavedLoc = DI->getLocation();
- DI->CurLoc = SourceLocation();
+ArtificialLocation::ArtificialLocation(CodeGenFunction &CGF)
+ : ApplyDebugLocation(CGF) {
+ if (auto *DI = CGF.getDebugInfo()) {
+ // Construct a location that has a valid scope, but no line info.
+ assert(!DI->LexicalBlockStack.empty());
+ llvm::DIDescriptor Scope(DI->LexicalBlockStack.back());
+ CGF.Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(0, 0, Scope));
}
}
-SaveAndRestoreLocation::~SaveAndRestoreLocation() {
- if (DI)
- DI->EmitLocation(Builder, SavedLoc);
-}
-
-NoLocation::NoLocation(CodeGenFunction &CGF, CGBuilderTy &B)
- : SaveAndRestoreLocation(CGF, B) {
- if (DI)
- Builder.SetCurrentDebugLocation(llvm::DebugLoc());
-}
-
-NoLocation::~NoLocation() {
- if (DI)
- assert(Builder.getCurrentDebugLocation().isUnknown());
-}
-
-ArtificialLocation::ArtificialLocation(CodeGenFunction &CGF, CGBuilderTy &B)
- : SaveAndRestoreLocation(CGF, B) {
- if (DI)
- Builder.SetCurrentDebugLocation(llvm::DebugLoc());
+ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF,
+ SourceLocation TemporaryLocation,
+ bool ForceColumnInfo)
+ : CGF(CGF) {
+ if (auto *DI = CGF.getDebugInfo()) {
+ OriginalLocation = CGF.Builder.getCurrentDebugLocation();
+ if (TemporaryLocation.isInvalid())
+ CGF.Builder.SetCurrentDebugLocation(llvm::DebugLoc());
+ else
+ DI->EmitLocation(CGF.Builder, TemporaryLocation, ForceColumnInfo);
+ }
}
-void ArtificialLocation::Emit() {
- if (DI) {
- // Sync the Builder.
- DI->EmitLocation(Builder, SavedLoc);
- DI->CurLoc = SourceLocation();
- // Construct a location that has a valid scope, but no line info.
- assert(!DI->LexicalBlockStack.empty());
- llvm::DIDescriptor Scope(DI->LexicalBlockStack.back());
- Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(0, 0, Scope));
+ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc)
+ : CGF(CGF) {
+ if (CGF.getDebugInfo()) {
+ OriginalLocation = CGF.Builder.getCurrentDebugLocation();
+ if (!Loc.isUnknown())
+ CGF.Builder.SetCurrentDebugLocation(Loc);
}
}
-ArtificialLocation::~ArtificialLocation() {
- if (DI)
- assert(Builder.getCurrentDebugLocation().getLine() == 0);
+ApplyDebugLocation::~ApplyDebugLocation() {
+ // Query CGF so the location isn't overwritten when location updates are
+ // temporarily disabled (for C++ default function arguments)
+ if (CGF.getDebugInfo())
+ CGF.Builder.SetCurrentDebugLocation(OriginalLocation);
}
+/// ArtificialLocation - An RAII object that temporarily switches to
+/// an artificial debug location that has a valid scope, but no line
void CGDebugInfo::setLocation(SourceLocation Loc) {
// If the new location isn't valid return.
- if (Loc.isInvalid()) return;
+ if (Loc.isInvalid())
+ return;
CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc);
// If we've changed files in the middle of a lexical scope go ahead
// and create a new lexical scope with file node if it's different
// from the one in the scope.
- if (LexicalBlockStack.empty()) return;
+ if (LexicalBlockStack.empty())
+ return;
SourceManager &SM = CGM.getContext().getSourceManager();
llvm::DIScope Scope(LexicalBlockStack.back());
@@ -120,18 +115,17 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
if (Scope.isLexicalBlockFile()) {
llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(Scope);
- llvm::DIDescriptor D
- = DBuilder.createLexicalBlockFile(LBF.getScope(),
- getOrCreateFile(CurLoc));
+ llvm::DIDescriptor D = DBuilder.createLexicalBlockFile(
+ LBF.getScope(), getOrCreateFile(CurLoc));
llvm::MDNode *N = D;
LexicalBlockStack.pop_back();
- LexicalBlockStack.push_back(N);
+ LexicalBlockStack.emplace_back(N);
} else if (Scope.isLexicalBlock() || Scope.isSubprogram()) {
- llvm::DIDescriptor D
- = DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc));
+ llvm::DIDescriptor D =
+ DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc));
llvm::MDNode *N = D;
LexicalBlockStack.pop_back();
- LexicalBlockStack.push_back(N);
+ LexicalBlockStack.emplace_back(N);
}
}
@@ -140,10 +134,9 @@ llvm::DIScope CGDebugInfo::getContextDescriptor(const Decl *Context) {
if (!Context)
return TheCU;
- llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
- I = RegionMap.find(Context);
+ auto I = RegionMap.find(Context);
if (I != RegionMap.end()) {
- llvm::Value *V = I->second;
+ llvm::Metadata *V = I->second;
return llvm::DIScope(dyn_cast_or_null<llvm::MDNode>(V));
}
@@ -154,7 +147,7 @@ llvm::DIScope CGDebugInfo::getContextDescriptor(const Decl *Context) {
if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context))
if (!RDecl->isDependentType())
return getOrCreateType(CGM.getContext().getTypeDeclType(RDecl),
- getOrCreateMainFile());
+ getOrCreateMainFile());
return TheCU;
}
@@ -162,10 +155,10 @@ llvm::DIScope CGDebugInfo::getContextDescriptor(const Decl *Context) {
/// name is constructed on demand (e.g. C++ destructor) then the name
/// is stored on the side.
StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
- assert (FD && "Invalid FunctionDecl!");
+ assert(FD && "Invalid FunctionDecl!");
IdentifierInfo *FII = FD->getIdentifier();
- FunctionTemplateSpecializationInfo *Info
- = FD->getTemplateSpecializationInfo();
+ FunctionTemplateSpecializationInfo *Info =
+ FD->getTemplateSpecializationInfo();
if (!Info && FII)
return FII->getName();
@@ -194,20 +187,20 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
OS << (OMD->isInstanceMethod() ? '-' : '+') << '[';
const DeclContext *DC = OMD->getDeclContext();
if (const ObjCImplementationDecl *OID =
- dyn_cast<const ObjCImplementationDecl>(DC)) {
- OS << OID->getName();
+ dyn_cast<const ObjCImplementationDecl>(DC)) {
+ OS << OID->getName();
} else if (const ObjCInterfaceDecl *OID =
- dyn_cast<const ObjCInterfaceDecl>(DC)) {
- OS << OID->getName();
+ dyn_cast<const ObjCInterfaceDecl>(DC)) {
+ OS << OID->getName();
} else if (const ObjCCategoryImplDecl *OCD =
- dyn_cast<const ObjCCategoryImplDecl>(DC)){
- OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' <<
- OCD->getIdentifier()->getNameStart() << ')';
+ dyn_cast<const ObjCCategoryImplDecl>(DC)) {
+ OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '('
+ << OCD->getIdentifier()->getNameStart() << ')';
} else if (isa<ObjCProtocolDecl>(DC)) {
// We can extract the type of the class from the self pointer.
- if (ImplicitParamDecl* SelfDecl = OMD->getSelfDecl()) {
+ if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) {
QualType ClassTy =
- cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
+ cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
ClassTy.print(OS, PrintingPolicy(LangOptions()));
}
}
@@ -223,8 +216,7 @@ StringRef CGDebugInfo::getSelectorName(Selector S) {
}
/// getClassName - Get class name including template argument list.
-StringRef
-CGDebugInfo::getClassName(const RecordDecl *RD) {
+StringRef CGDebugInfo::getClassName(const RecordDecl *RD) {
// quick optimization to avoid having to intern strings that are already
// stored reliably elsewhere
if (!isa<ClassTemplateSpecializationDecl>(RD))
@@ -256,18 +248,17 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
// Cache the results.
const char *fname = PLoc.getFilename();
- llvm::DenseMap<const char *, llvm::WeakVH>::iterator it =
- DIFileCache.find(fname);
+ auto it = DIFileCache.find(fname);
if (it != DIFileCache.end()) {
// Verify that the information still exists.
- if (llvm::Value *V = it->second)
+ if (llvm::Metadata *V = it->second)
return llvm::DIFile(cast<llvm::MDNode>(V));
}
llvm::DIFile F = DBuilder.createFile(PLoc.getFilename(), getCurrentDirname());
- DIFileCache[fname] = F;
+ DIFileCache[fname].reset(F);
return F;
}
@@ -283,7 +274,7 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
return 0;
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
- return PLoc.isValid()? PLoc.getLine() : 0;
+ return PLoc.isValid() ? PLoc.getLine() : 0;
}
/// getColumnNumber - Get column number for the location.
@@ -297,7 +288,7 @@ unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) {
return 0;
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
- return PLoc.isValid()? PLoc.getColumn() : 0;
+ return PLoc.isValid() ? PLoc.getColumn() : 0;
}
StringRef CGDebugInfo::getCurrentDirname() {
@@ -388,8 +379,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
StringRef BTName;
switch (BT->getKind()) {
#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) \
- case BuiltinType::Id:
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
llvm_unreachable("Unexpected builtin type");
@@ -425,8 +415,10 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
DBuilder.createStructType(TheCU, "objc_object", getOrCreateMainFile(),
0, 0, 0, 0, llvm::DIType(), llvm::DIArray());
- ObjTy.setTypeArray(DBuilder.getOrCreateArray(&*DBuilder.createMemberType(
- ObjTy, "isa", getOrCreateMainFile(), 0, Size, 0, 0, 0, ISATy)));
+ DBuilder.replaceArrays(
+ ObjTy,
+ DBuilder.getOrCreateArray(&*DBuilder.createMemberType(
+ ObjTy, "isa", getOrCreateMainFile(), 0, Size, 0, 0, 0, ISATy)));
return ObjTy;
}
case BuiltinType::ObjCSel: {
@@ -438,8 +430,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
}
case BuiltinType::OCLImage1d:
- return getOrCreateStructPtrType("opencl_image1d_t",
- OCLImage1dDITy);
+ return getOrCreateStructPtrType("opencl_image1d_t", OCLImage1dDITy);
case BuiltinType::OCLImage1dArray:
return getOrCreateStructPtrType("opencl_image1d_array_t",
OCLImage1dArrayDITy);
@@ -447,53 +438,71 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
return getOrCreateStructPtrType("opencl_image1d_buffer_t",
OCLImage1dBufferDITy);
case BuiltinType::OCLImage2d:
- return getOrCreateStructPtrType("opencl_image2d_t",
- OCLImage2dDITy);
+ return getOrCreateStructPtrType("opencl_image2d_t", OCLImage2dDITy);
case BuiltinType::OCLImage2dArray:
return getOrCreateStructPtrType("opencl_image2d_array_t",
OCLImage2dArrayDITy);
case BuiltinType::OCLImage3d:
- return getOrCreateStructPtrType("opencl_image3d_t",
- OCLImage3dDITy);
+ return getOrCreateStructPtrType("opencl_image3d_t", OCLImage3dDITy);
case BuiltinType::OCLSampler:
- return DBuilder.createBasicType("opencl_sampler_t",
- CGM.getContext().getTypeSize(BT),
- CGM.getContext().getTypeAlign(BT),
- llvm::dwarf::DW_ATE_unsigned);
+ return DBuilder.createBasicType(
+ "opencl_sampler_t", CGM.getContext().getTypeSize(BT),
+ CGM.getContext().getTypeAlign(BT), llvm::dwarf::DW_ATE_unsigned);
case BuiltinType::OCLEvent:
- return getOrCreateStructPtrType("opencl_event_t",
- OCLEventDITy);
+ return getOrCreateStructPtrType("opencl_event_t", OCLEventDITy);
case BuiltinType::UChar:
- case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break;
+ case BuiltinType::Char_U:
+ Encoding = llvm::dwarf::DW_ATE_unsigned_char;
+ break;
case BuiltinType::Char_S:
- case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break;
+ case BuiltinType::SChar:
+ Encoding = llvm::dwarf::DW_ATE_signed_char;
+ break;
case BuiltinType::Char16:
- case BuiltinType::Char32: Encoding = llvm::dwarf::DW_ATE_UTF; break;
+ case BuiltinType::Char32:
+ Encoding = llvm::dwarf::DW_ATE_UTF;
+ break;
case BuiltinType::UShort:
case BuiltinType::UInt:
case BuiltinType::UInt128:
case BuiltinType::ULong:
case BuiltinType::WChar_U:
- case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break;
+ case BuiltinType::ULongLong:
+ Encoding = llvm::dwarf::DW_ATE_unsigned;
+ break;
case BuiltinType::Short:
case BuiltinType::Int:
case BuiltinType::Int128:
case BuiltinType::Long:
case BuiltinType::WChar_S:
- case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break;
- case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break;
+ case BuiltinType::LongLong:
+ Encoding = llvm::dwarf::DW_ATE_signed;
+ break;
+ case BuiltinType::Bool:
+ Encoding = llvm::dwarf::DW_ATE_boolean;
+ break;
case BuiltinType::Half:
case BuiltinType::Float:
case BuiltinType::LongDouble:
- case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break;
+ case BuiltinType::Double:
+ Encoding = llvm::dwarf::DW_ATE_float;
+ break;
}
switch (BT->getKind()) {
- case BuiltinType::Long: BTName = "long int"; break;
- case BuiltinType::LongLong: BTName = "long long int"; break;
- case BuiltinType::ULong: BTName = "long unsigned int"; break;
- case BuiltinType::ULongLong: BTName = "long long unsigned int"; break;
+ case BuiltinType::Long:
+ BTName = "long int";
+ break;
+ case BuiltinType::LongLong:
+ BTName = "long long int";
+ break;
+ case BuiltinType::ULong:
+ BTName = "long unsigned int";
+ break;
+ case BuiltinType::ULongLong:
+ BTName = "long long unsigned int";
+ break;
default:
BTName = BT->getName(CGM.getLangOpts());
break;
@@ -501,8 +510,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(BT);
uint64_t Align = CGM.getContext().getTypeAlign(BT);
- llvm::DIType DbgTy =
- DBuilder.createBasicType(BTName, Size, Align, Encoding);
+ llvm::DIType DbgTy = DBuilder.createBasicType(BTName, Size, Align, Encoding);
return DbgTy;
}
@@ -515,7 +523,7 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty) {
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DIType DbgTy =
- DBuilder.createBasicType("complex", Size, Align, Encoding);
+ DBuilder.createBasicType("complex", Size, Align, Encoding);
return DbgTy;
}
@@ -564,25 +572,23 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
// whereas 'id<protocol>' is treated as an ObjCPointerType. For the
// debug info, we want to emit 'id' in both cases.
if (Ty->isObjCQualifiedIdType())
- return getOrCreateType(CGM.getContext().getObjCIdType(), Unit);
+ return getOrCreateType(CGM.getContext().getObjCIdType(), Unit);
- llvm::DIType DbgTy =
- CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
- Ty->getPointeeType(), Unit);
+ llvm::DIType DbgTy = CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type,
+ Ty, Ty->getPointeeType(), Unit);
return DbgTy;
}
-llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty,
- llvm::DIFile Unit) {
+llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty, llvm::DIFile Unit) {
return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
Ty->getPointeeType(), Unit);
}
/// In C++ mode, types have linkage, so we can rely on the ODR and
/// on their mangled names, if they're external.
-static SmallString<256>
-getUniqueTagTypeName(const TagType *Ty, CodeGenModule &CGM,
- llvm::DICompileUnit TheCU) {
+static SmallString<256> getUniqueTagTypeName(const TagType *Ty,
+ CodeGenModule &CGM,
+ llvm::DICompileUnit TheCU) {
SmallString<256> FullName;
// FIXME: ODR should apply to ObjC++ exactly the same wasy it does to C++.
// For now, only apply ODR with C++.
@@ -627,7 +633,9 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
llvm::DICompositeType RetTy = DBuilder.createReplaceableForwardDecl(
Tag, RDName, Ctx, DefUnit, Line, 0, 0, 0, FullName);
- ReplaceMap.push_back(std::make_pair(Ty, static_cast<llvm::Value *>(RetTy)));
+ ReplaceMap.emplace_back(
+ std::piecewise_construct, std::make_tuple(Ty),
+ std::make_tuple(static_cast<llvm::Metadata *>(RetTy)));
return RetTy;
}
@@ -666,7 +674,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
if (BlockLiteralGeneric)
return BlockLiteralGeneric;
- SmallVector<llvm::Value *, 8> EltTys;
+ SmallVector<llvm::Metadata *, 8> EltTys;
llvm::DIType FieldTy;
QualType FType;
uint64_t FieldSize, FieldOffset;
@@ -685,9 +693,9 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
unsigned Flags = llvm::DIDescriptor::FlagAppleBlock;
unsigned LineNo = getLineNumber(CurLoc);
- EltTy = DBuilder.createStructType(Unit, "__block_descriptor",
- Unit, LineNo, FieldOffset, 0,
- Flags, llvm::DIType(), Elements);
+ EltTy = DBuilder.createStructType(Unit, "__block_descriptor", Unit, LineNo,
+ FieldOffset, 0, Flags, llvm::DIType(),
+ Elements);
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(Ty);
@@ -700,50 +708,52 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
FType = CGM.getContext().IntTy;
EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset));
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ FType = CGM.getContext().getPointerType(Ty->getPointeeType());
EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset));
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = DescTy;
FieldSize = CGM.getContext().getTypeSize(Ty);
FieldAlign = CGM.getContext().getTypeAlign(Ty);
- FieldTy = DBuilder.createMemberType(Unit, "__descriptor", Unit,
- LineNo, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
+ FieldTy =
+ DBuilder.createMemberType(Unit, "__descriptor", Unit, LineNo, FieldSize,
+ FieldAlign, FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
Elements = DBuilder.getOrCreateArray(EltTys);
- EltTy = DBuilder.createStructType(Unit, "__block_literal_generic",
- Unit, LineNo, FieldOffset, 0,
- Flags, llvm::DIType(), Elements);
+ EltTy = DBuilder.createStructType(Unit, "__block_literal_generic", Unit,
+ LineNo, FieldOffset, 0, Flags,
+ llvm::DIType(), Elements);
BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size);
return BlockLiteralGeneric;
}
-llvm::DIType CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, llvm::DIFile Unit) {
+llvm::DIType CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
+ llvm::DIFile Unit) {
assert(Ty->isTypeAlias());
llvm::DIType Src = getOrCreateType(Ty->getAliasedType(), Unit);
SmallString<128> NS;
llvm::raw_svector_ostream OS(NS);
- Ty->getTemplateName().print(OS, CGM.getContext().getPrintingPolicy(), /*qualified*/ false);
+ Ty->getTemplateName().print(OS, CGM.getContext().getPrintingPolicy(),
+ /*qualified*/ false);
TemplateSpecializationType::PrintTemplateArgumentList(
OS, Ty->getArgs(), Ty->getNumArgs(),
CGM.getContext().getPrintingPolicy());
- TypeAliasDecl *AliasDecl =
- cast<TypeAliasTemplateDecl>(Ty->getTemplateName().getAsTemplateDecl())
- ->getTemplatedDecl();
+ TypeAliasDecl *AliasDecl = cast<TypeAliasTemplateDecl>(
+ Ty->getTemplateName().getAsTemplateDecl())->getTemplatedDecl();
SourceLocation Loc = AliasDecl->getLocation();
llvm::DIFile File = getOrCreateFile(Loc);
unsigned Line = getLineNumber(Loc);
- llvm::DIDescriptor Ctxt = getContextDescriptor(cast<Decl>(AliasDecl->getDeclContext()));
+ llvm::DIDescriptor Ctxt =
+ getContextDescriptor(cast<Decl>(AliasDecl->getDeclContext()));
return DBuilder.createTypedef(Src, internString(OS.str()), File, Line, Ctxt);
}
@@ -760,15 +770,15 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) {
const TypedefNameDecl *TyDecl = Ty->getDecl();
llvm::DIDescriptor TypedefContext =
- getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
+ getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
- return
- DBuilder.createTypedef(Src, TyDecl->getName(), File, Line, TypedefContext);
+ return DBuilder.createTypedef(Src, TyDecl->getName(), File, Line,
+ TypedefContext);
}
llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
llvm::DIFile Unit) {
- SmallVector<llvm::Value *, 16> EltTys;
+ SmallVector<llvm::Metadata *, 16> EltTys;
// Add the result type at least.
EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit));
@@ -784,49 +794,66 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
EltTys.push_back(DBuilder.createUnspecifiedParameter());
}
- llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(EltTys);
+ llvm::DITypeArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys);
return DBuilder.createSubroutineType(Unit, EltTypeArray);
}
+/// Convert an AccessSpecifier into the corresponding DIDescriptor flag.
+/// As an optimization, return 0 if the access specifier equals the
+/// default for the containing type.
+static unsigned getAccessFlag(AccessSpecifier Access, const RecordDecl *RD) {
+ AccessSpecifier Default = clang::AS_none;
+ if (RD && RD->isClass())
+ Default = clang::AS_private;
+ else if (RD && (RD->isStruct() || RD->isUnion()))
+ Default = clang::AS_public;
-llvm::DIType CGDebugInfo::createFieldType(StringRef name,
- QualType type,
- uint64_t sizeInBitsOverride,
- SourceLocation loc,
- AccessSpecifier AS,
- uint64_t offsetInBits,
- llvm::DIFile tunit,
- llvm::DIScope scope) {
+ if (Access == Default)
+ return 0;
+
+ switch (Access) {
+ case clang::AS_private:
+ return llvm::DIDescriptor::FlagPrivate;
+ case clang::AS_protected:
+ return llvm::DIDescriptor::FlagProtected;
+ case clang::AS_public:
+ return llvm::DIDescriptor::FlagPublic;
+ case clang::AS_none:
+ return 0;
+ }
+ llvm_unreachable("unexpected access enumerator");
+}
+
+llvm::DIType CGDebugInfo::createFieldType(
+ StringRef name, QualType type, uint64_t sizeInBitsOverride,
+ SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits,
+ llvm::DIFile tunit, llvm::DIScope scope, const RecordDecl *RD) {
llvm::DIType debugType = getOrCreateType(type, tunit);
// Get the location for the field.
llvm::DIFile file = getOrCreateFile(loc);
unsigned line = getLineNumber(loc);
- uint64_t sizeInBits = 0;
- unsigned alignInBits = 0;
+ uint64_t SizeInBits = 0;
+ unsigned AlignInBits = 0;
if (!type->isIncompleteArrayType()) {
- std::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type);
+ TypeInfo TI = CGM.getContext().getTypeInfo(type);
+ SizeInBits = TI.Width;
+ AlignInBits = TI.Align;
if (sizeInBitsOverride)
- sizeInBits = sizeInBitsOverride;
+ SizeInBits = sizeInBitsOverride;
}
- unsigned flags = 0;
- if (AS == clang::AS_private)
- flags |= llvm::DIDescriptor::FlagPrivate;
- else if (AS == clang::AS_protected)
- flags |= llvm::DIDescriptor::FlagProtected;
-
- return DBuilder.createMemberType(scope, name, file, line, sizeInBits,
- alignInBits, offsetInBits, flags, debugType);
+ unsigned flags = getAccessFlag(AS, RD);
+ return DBuilder.createMemberType(scope, name, file, line, SizeInBits,
+ AlignInBits, offsetInBits, flags, debugType);
}
/// CollectRecordLambdaFields - Helper for CollectRecordFields.
-void CGDebugInfo::
-CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
- SmallVectorImpl<llvm::Value *> &elements,
- llvm::DIType RecordTy) {
+void CGDebugInfo::CollectRecordLambdaFields(
+ const CXXRecordDecl *CXXDecl, SmallVectorImpl<llvm::Metadata *> &elements,
+ llvm::DIType RecordTy) {
// For C++11 Lambdas a Field will be the same as a Capture, but the Capture
// has the name and the location of the variable so we should iterate over
// both concurrently.
@@ -834,7 +861,8 @@ CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
RecordDecl::field_iterator Field = CXXDecl->field_begin();
unsigned fieldno = 0;
for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
- E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
+ E = CXXDecl->captures_end();
+ I != E; ++I, ++Field, ++fieldno) {
const LambdaCapture &C = *I;
if (C.capturesVariable()) {
VarDecl *V = C.getCapturedVar();
@@ -845,23 +873,22 @@ CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext());
assert(SizeInBitsOverride && "found named 0-width bitfield");
}
- llvm::DIType fieldType
- = createFieldType(VName, Field->getType(), SizeInBitsOverride,
- C.getLocation(), Field->getAccess(),
- layout.getFieldOffset(fieldno), VUnit, RecordTy);
+ llvm::DIType fieldType = createFieldType(
+ VName, Field->getType(), SizeInBitsOverride, C.getLocation(),
+ Field->getAccess(), layout.getFieldOffset(fieldno), VUnit, RecordTy,
+ CXXDecl);
elements.push_back(fieldType);
- } else {
+ } else if (C.capturesThis()) {
// TODO: Need to handle 'this' in some way by probably renaming the
// this of the lambda class and having a field member of 'this' or
// by using AT_object_pointer for the function and having that be
// used as 'this' for semantic references.
- assert(C.capturesThis() && "Field that isn't captured and isn't this?");
FieldDecl *f = *Field;
llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
QualType type = f->getType();
- llvm::DIType fieldType
- = createFieldType("this", type, 0, f->getLocation(), f->getAccess(),
- layout.getFieldOffset(fieldno), VUnit, RecordTy);
+ llvm::DIType fieldType = createFieldType(
+ "this", type, 0, f->getLocation(), f->getAccess(),
+ layout.getFieldOffset(fieldno), VUnit, RecordTy, CXXDecl);
elements.push_back(fieldType);
}
@@ -869,11 +896,12 @@ CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
}
/// Helper for CollectRecordFields.
-llvm::DIDerivedType
-CGDebugInfo::CreateRecordStaticField(const VarDecl *Var,
- llvm::DIType RecordTy) {
+llvm::DIDerivedType CGDebugInfo::CreateRecordStaticField(const VarDecl *Var,
+ llvm::DIType RecordTy,
+ const RecordDecl *RD) {
// Create the descriptor for the static variable, with or without
// constant initializers.
+ Var = Var->getCanonicalDecl();
llvm::DIFile VUnit = getOrCreateFile(Var->getLocation());
llvm::DIType VTy = getOrCreateType(Var->getType(), VUnit);
@@ -890,25 +918,18 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var,
}
}
- unsigned Flags = 0;
- AccessSpecifier Access = Var->getAccess();
- if (Access == clang::AS_private)
- Flags |= llvm::DIDescriptor::FlagPrivate;
- else if (Access == clang::AS_protected)
- Flags |= llvm::DIDescriptor::FlagProtected;
-
+ unsigned Flags = getAccessFlag(Var->getAccess(), RD);
llvm::DIDerivedType GV = DBuilder.createStaticMemberType(
RecordTy, VName, VUnit, LineNumber, VTy, Flags, C);
- StaticDataMemberCache[Var->getCanonicalDecl()] = llvm::WeakVH(GV);
+ StaticDataMemberCache[Var->getCanonicalDecl()].reset(GV);
return GV;
}
/// CollectRecordNormalField - Helper for CollectRecordFields.
-void CGDebugInfo::
-CollectRecordNormalField(const FieldDecl *field, uint64_t OffsetInBits,
- llvm::DIFile tunit,
- SmallVectorImpl<llvm::Value *> &elements,
- llvm::DIType RecordTy) {
+void CGDebugInfo::CollectRecordNormalField(
+ const FieldDecl *field, uint64_t OffsetInBits, llvm::DIFile tunit,
+ SmallVectorImpl<llvm::Metadata *> &elements, llvm::DIType RecordTy,
+ const RecordDecl *RD) {
StringRef name = field->getName();
QualType type = field->getType();
@@ -922,20 +943,19 @@ CollectRecordNormalField(const FieldDecl *field, uint64_t OffsetInBits,
assert(SizeInBitsOverride && "found named 0-width bitfield");
}
- llvm::DIType fieldType
- = createFieldType(name, type, SizeInBitsOverride,
- field->getLocation(), field->getAccess(),
- OffsetInBits, tunit, RecordTy);
+ llvm::DIType fieldType =
+ createFieldType(name, type, SizeInBitsOverride, field->getLocation(),
+ field->getAccess(), OffsetInBits, tunit, RecordTy, RD);
elements.push_back(fieldType);
}
/// CollectRecordFields - A helper function to collect debug info for
/// record fields. This is used while creating debug info entry for a Record.
-void CGDebugInfo::CollectRecordFields(const RecordDecl *record,
- llvm::DIFile tunit,
- SmallVectorImpl<llvm::Value *> &elements,
- llvm::DICompositeType RecordTy) {
+void CGDebugInfo::CollectRecordFields(
+ const RecordDecl *record, llvm::DIFile tunit,
+ SmallVectorImpl<llvm::Metadata *> &elements,
+ llvm::DICompositeType RecordTy) {
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(record);
if (CXXDecl && CXXDecl->isLambda())
@@ -951,18 +971,19 @@ void CGDebugInfo::CollectRecordFields(const RecordDecl *record,
for (const auto *I : record->decls())
if (const auto *V = dyn_cast<VarDecl>(I)) {
// Reuse the existing static member declaration if one exists
- llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator MI =
- StaticDataMemberCache.find(V->getCanonicalDecl());
+ auto MI = StaticDataMemberCache.find(V->getCanonicalDecl());
if (MI != StaticDataMemberCache.end()) {
assert(MI->second &&
"Static data member declaration should still exist");
elements.push_back(
llvm::DIDerivedType(cast<llvm::MDNode>(MI->second)));
- } else
- elements.push_back(CreateRecordStaticField(V, RecordTy));
+ } else {
+ auto Field = CreateRecordStaticField(V, RecordTy, record);
+ elements.push_back(Field);
+ }
} else if (const auto *field = dyn_cast<FieldDecl>(I)) {
- CollectRecordNormalField(field, layout.getFieldOffset(fieldNo),
- tunit, elements, RecordTy);
+ CollectRecordNormalField(field, layout.getFieldOffset(fieldNo), tunit,
+ elements, RecordTy, record);
// Bump field number for next field.
++fieldNo;
@@ -986,11 +1007,11 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DICompositeType CGDebugInfo::getOrCreateInstanceMethodType(
QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile Unit) {
// Add "this" pointer.
- llvm::DIArray Args = llvm::DICompositeType(
+ llvm::DITypeArray Args = llvm::DISubroutineType(
getOrCreateType(QualType(Func, 0), Unit)).getTypeArray();
- assert (Args.getNumElements() && "Invalid number of arguments!");
+ assert(Args.getNumElements() && "Invalid number of arguments!");
- SmallVector<llvm::Value *, 16> Elts;
+ SmallVector<llvm::Metadata *, 16> Elts;
// First element is always return type. For 'void' functions it is NULL.
Elts.push_back(Args.getElement(0));
@@ -1006,8 +1027,8 @@ llvm::DICompositeType CGDebugInfo::getOrCreateInstanceMethodType(
uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy);
llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit);
llvm::DIType ThisPtrType =
- DBuilder.createPointerType(PointeeType, Size, Align);
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ DBuilder.createPointerType(PointeeType, Size, Align);
+ TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType);
// TODO: This and the artificial type below are misleading, the
// types aren't artificial the argument is, but the current
// metadata doesn't represent that.
@@ -1015,7 +1036,7 @@ llvm::DICompositeType CGDebugInfo::getOrCreateInstanceMethodType(
Elts.push_back(ThisPtrType);
} else {
llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit);
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType);
ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
Elts.push_back(ThisPtrType);
}
@@ -1024,7 +1045,7 @@ llvm::DICompositeType CGDebugInfo::getOrCreateInstanceMethodType(
for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i)
Elts.push_back(Args.getElement(i));
- llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
+ llvm::DITypeArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts);
unsigned Flags = 0;
if (Func->getExtProtoInfo().RefQualifier == RQ_LValue)
@@ -1049,10 +1070,9 @@ static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
/// a single member function GlobalDecl.
llvm::DISubprogram
CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
- llvm::DIFile Unit,
- llvm::DIType RecordTy) {
+ llvm::DIFile Unit, llvm::DIType RecordTy) {
bool IsCtorOrDtor =
- isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
+ isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
StringRef MethodName = getFunctionName(Method);
llvm::DICompositeType MethodTy = getOrCreateMethodType(Method, Unit);
@@ -1096,16 +1116,12 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
unsigned Flags = 0;
if (Method->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
- AccessSpecifier Access = Method->getAccess();
- if (Access == clang::AS_private)
- Flags |= llvm::DIDescriptor::FlagPrivate;
- else if (Access == clang::AS_protected)
- Flags |= llvm::DIDescriptor::FlagProtected;
+ Flags |= getAccessFlag(Method->getAccess(), Method->getParent());
if (const CXXConstructorDecl *CXXC = dyn_cast<CXXConstructorDecl>(Method)) {
if (CXXC->isExplicit())
Flags |= llvm::DIDescriptor::FlagExplicit;
} else if (const CXXConversionDecl *CXXC =
- dyn_cast<CXXConversionDecl>(Method)) {
+ dyn_cast<CXXConversionDecl>(Method)) {
if (CXXC->isExplicit())
Flags |= llvm::DIDescriptor::FlagExplicit;
}
@@ -1117,16 +1133,13 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
Flags |= llvm::DIDescriptor::FlagRValueReference;
llvm::DIArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
- llvm::DISubprogram SP =
- DBuilder.createMethod(RecordTy, MethodName, MethodLinkageName,
- MethodDefUnit, MethodLine,
- MethodTy, /*isLocalToUnit=*/false,
- /* isDefinition=*/ false,
- Virtuality, VIndex, ContainingType,
- Flags, CGM.getLangOpts().Optimize, nullptr,
- TParamsArray);
+ llvm::DISubprogram SP = DBuilder.createMethod(
+ RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine,
+ MethodTy, /*isLocalToUnit=*/false,
+ /* isDefinition=*/false, Virtuality, VIndex, ContainingType, Flags,
+ CGM.getLangOpts().Optimize, nullptr, TParamsArray);
- SPCache[Method->getCanonicalDecl()] = llvm::WeakVH(SP);
+ SPCache[Method->getCanonicalDecl()].reset(SP);
return SP;
}
@@ -1134,53 +1147,49 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
/// CollectCXXMemberFunctions - A helper function to collect debug info for
/// C++ member functions. This is used while creating debug info entry for
/// a Record.
-void CGDebugInfo::
-CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
- SmallVectorImpl<llvm::Value *> &EltTys,
- llvm::DIType RecordTy) {
+void CGDebugInfo::CollectCXXMemberFunctions(
+ const CXXRecordDecl *RD, llvm::DIFile Unit,
+ SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType RecordTy) {
// Since we want more than just the individual member decls if we
// have templated functions iterate over every declaration to gather
// the functions.
- for(const auto *I : RD->decls()) {
- if (const auto *Method = dyn_cast<CXXMethodDecl>(I)) {
- // Reuse the existing member function declaration if it exists.
- // It may be associated with the declaration of the type & should be
- // reused as we're building the definition.
- //
- // This situation can arise in the vtable-based debug info reduction where
- // implicit members are emitted in a non-vtable TU.
- llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator MI =
- SPCache.find(Method->getCanonicalDecl());
- if (MI == SPCache.end()) {
- // If the member is implicit, lazily create it when we see the
- // definition, not before. (an ODR-used implicit default ctor that's
- // never actually code generated should not produce debug info)
- if (!Method->isImplicit())
- EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
- } else
- EltTys.push_back(MI->second);
- } else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(I)) {
- // Add any template specializations that have already been seen. Like
- // implicit member functions, these may have been added to a declaration
- // in the case of vtable-based debug info reduction.
- for (const auto *SI : FTD->specializations()) {
- llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator MI =
- SPCache.find(cast<CXXMethodDecl>(SI)->getCanonicalDecl());
- if (MI != SPCache.end())
- EltTys.push_back(MI->second);
- }
- }
+ for (const auto *I : RD->decls()) {
+ const auto *Method = dyn_cast<CXXMethodDecl>(I);
+ // If the member is implicit, don't add it to the member list. This avoids
+ // the member being added to type units by LLVM, while still allowing it
+ // to be emitted into the type declaration/reference inside the compile
+ // unit.
+ // FIXME: Handle Using(Shadow?)Decls here to create
+ // DW_TAG_imported_declarations inside the class for base decls brought into
+ // derived classes. GDB doesn't seem to notice/leverage these when I tried
+ // it, so I'm not rushing to fix this. (GCC seems to produce them, if
+ // referenced)
+ if (!Method || Method->isImplicit())
+ continue;
+
+ if (Method->getType()->getAs<FunctionProtoType>()->getContainedAutoType())
+ continue;
+
+ // Reuse the existing member function declaration if it exists.
+ // It may be associated with the declaration of the type & should be
+ // reused as we're building the definition.
+ //
+ // This situation can arise in the vtable-based debug info reduction where
+ // implicit members are emitted in a non-vtable TU.
+ auto MI = SPCache.find(Method->getCanonicalDecl());
+ EltTys.push_back(MI == SPCache.end()
+ ? CreateCXXMemberFunction(Method, Unit, RecordTy)
+ : static_cast<llvm::Metadata *>(MI->second));
}
}
/// CollectCXXBases - A helper function to collect debug info for
/// C++ base classes. This is used while creating debug info entry for
/// a Record.
-void CGDebugInfo::
-CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
- SmallVectorImpl<llvm::Value *> &EltTys,
- llvm::DIType RecordTy) {
+void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
+ SmallVectorImpl<llvm::Metadata *> &EltTys,
+ llvm::DIType RecordTy) {
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
for (const auto &BI : RD->bases()) {
@@ -1188,40 +1197,40 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
uint64_t BaseOffset;
const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(BI.getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(BI.getType()->getAs<RecordType>()->getDecl());
if (BI.isVirtual()) {
- // virtual base offset offset is -ve. The code generator emits dwarf
- // expression where it expects +ve number.
- BaseOffset =
- 0 - CGM.getItaniumVTableContext()
- .getVirtualBaseOffsetOffset(RD, Base).getQuantity();
+ if (CGM.getTarget().getCXXABI().isItaniumFamily()) {
+ // virtual base offset offset is -ve. The code generator emits dwarf
+ // expression where it expects +ve number.
+ BaseOffset = 0 - CGM.getItaniumVTableContext()
+ .getVirtualBaseOffsetOffset(RD, Base)
+ .getQuantity();
+ } else {
+ // In the MS ABI, store the vbtable offset, which is analogous to the
+ // vbase offset offset in Itanium.
+ BaseOffset =
+ 4 * CGM.getMicrosoftVTableContext().getVBTableIndex(RD, Base);
+ }
BFlags = llvm::DIDescriptor::FlagVirtual;
} else
BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base));
// FIXME: Inconsistent units for BaseOffset. It is in bytes when
// BI->isVirtual() and bits when not.
- AccessSpecifier Access = BI.getAccessSpecifier();
- if (Access == clang::AS_private)
- BFlags |= llvm::DIDescriptor::FlagPrivate;
- else if (Access == clang::AS_protected)
- BFlags |= llvm::DIDescriptor::FlagProtected;
-
- llvm::DIType DTy =
- DBuilder.createInheritance(RecordTy,
- getOrCreateType(BI.getType(), Unit),
- BaseOffset, BFlags);
+ BFlags |= getAccessFlag(BI.getAccessSpecifier(), RD);
+ llvm::DIType DTy = DBuilder.createInheritance(
+ RecordTy, getOrCreateType(BI.getType(), Unit), BaseOffset, BFlags);
EltTys.push_back(DTy);
}
}
/// CollectTemplateParams - A helper function to collect template parameters.
-llvm::DIArray CGDebugInfo::
-CollectTemplateParams(const TemplateParameterList *TPList,
- ArrayRef<TemplateArgument> TAList,
- llvm::DIFile Unit) {
- SmallVector<llvm::Value *, 16> TemplateParams;
+llvm::DIArray
+CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList,
+ ArrayRef<TemplateArgument> TAList,
+ llvm::DIFile Unit) {
+ SmallVector<llvm::Metadata *, 16> TemplateParams;
for (unsigned i = 0, e = TAList.size(); i != e; ++i) {
const TemplateArgument &TA = TAList[i];
StringRef Name;
@@ -1244,46 +1253,41 @@ CollectTemplateParams(const TemplateParameterList *TPList,
} break;
case TemplateArgument::Declaration: {
const ValueDecl *D = TA.getAsDecl();
- bool InstanceMember = D->isCXXInstanceMember();
- QualType T = InstanceMember
- ? CGM.getContext().getMemberPointerType(
- D->getType(), cast<RecordDecl>(D->getDeclContext())
- ->getTypeForDecl())
- : CGM.getContext().getPointerType(D->getType());
+ QualType T = TA.getParamTypeForDecl().getDesugaredType(CGM.getContext());
llvm::DIType TTy = getOrCreateType(T, Unit);
- llvm::Value *V = nullptr;
+ llvm::Constant *V = nullptr;
+ const CXXMethodDecl *MD;
// Variable pointer template parameters have a value that is the address
// of the variable.
- if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ if (const auto *VD = dyn_cast<VarDecl>(D))
V = CGM.GetAddrOfGlobalVar(VD);
// Member function pointers have special support for building them, though
// this is currently unsupported in LLVM CodeGen.
- if (InstanceMember) {
- if (const CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(D))
- V = CGM.getCXXABI().EmitMemberPointer(method);
- } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ else if ((MD = dyn_cast<CXXMethodDecl>(D)) && MD->isInstance())
+ V = CGM.getCXXABI().EmitMemberPointer(MD);
+ else if (const auto *FD = dyn_cast<FunctionDecl>(D))
V = CGM.GetAddrOfFunction(FD);
// Member data pointers have special handling too to compute the fixed
// offset within the object.
- if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) {
+ else if (const auto *MPT = dyn_cast<MemberPointerType>(T.getTypePtr())) {
// These five lines (& possibly the above member function pointer
// handling) might be able to be refactored to use similar code in
// CodeGenModule::getMemberPointerConstant
uint64_t fieldOffset = CGM.getContext().getFieldOffset(D);
CharUnits chars =
- CGM.getContext().toCharUnitsFromBits((int64_t) fieldOffset);
- V = CGM.getCXXABI().EmitMemberDataPointer(
- cast<MemberPointerType>(T.getTypePtr()), chars);
+ CGM.getContext().toCharUnitsFromBits((int64_t)fieldOffset);
+ V = CGM.getCXXABI().EmitMemberDataPointer(MPT, chars);
}
llvm::DITemplateValueParameter TVP =
- DBuilder.createTemplateValueParameter(TheCU, Name, TTy,
- V->stripPointerCasts());
+ DBuilder.createTemplateValueParameter(
+ TheCU, Name, TTy,
+ cast_or_null<llvm::Constant>(V->stripPointerCasts()));
TemplateParams.push_back(TVP);
} break;
case TemplateArgument::NullPtr: {
QualType T = TA.getNullPtrType();
llvm::DIType TTy = getOrCreateType(T, Unit);
- llvm::Value *V = nullptr;
+ llvm::Constant *V = nullptr;
// Special case member data pointer null values since they're actually -1
// instead of zero.
if (const MemberPointerType *MPT =
@@ -1298,33 +1302,34 @@ CollectTemplateParams(const TemplateParameterList *TPList,
if (!V)
V = llvm::ConstantInt::get(CGM.Int8Ty, 0);
llvm::DITemplateValueParameter TVP =
- DBuilder.createTemplateValueParameter(TheCU, Name, TTy, V);
+ DBuilder.createTemplateValueParameter(TheCU, Name, TTy,
+ cast<llvm::Constant>(V));
TemplateParams.push_back(TVP);
} break;
case TemplateArgument::Template: {
- llvm::DITemplateValueParameter TVP =
- DBuilder.createTemplateTemplateParameter(
- TheCU, Name, llvm::DIType(),
- TA.getAsTemplate().getAsTemplateDecl()
- ->getQualifiedNameAsString());
+ llvm::DITemplateValueParameter
+ TVP = DBuilder.createTemplateTemplateParameter(
+ TheCU, Name, llvm::DIType(),
+ TA.getAsTemplate().getAsTemplateDecl()->getQualifiedNameAsString());
TemplateParams.push_back(TVP);
} break;
case TemplateArgument::Pack: {
- llvm::DITemplateValueParameter TVP =
- DBuilder.createTemplateParameterPack(
- TheCU, Name, llvm::DIType(),
- CollectTemplateParams(nullptr, TA.getPackAsArray(), Unit));
+ llvm::DITemplateValueParameter TVP = DBuilder.createTemplateParameterPack(
+ TheCU, Name, llvm::DIType(),
+ CollectTemplateParams(nullptr, TA.getPackAsArray(), Unit));
TemplateParams.push_back(TVP);
} break;
case TemplateArgument::Expression: {
const Expr *E = TA.getAsExpr();
QualType T = E->getType();
- llvm::Value *V = CGM.EmitConstantExpr(E, T);
+ if (E->isGLValue())
+ T = CGM.getContext().getLValueReferenceType(T);
+ llvm::Constant *V = CGM.EmitConstantExpr(E, T);
assert(V && "Expression in template argument isn't constant");
llvm::DIType TTy = getOrCreateType(T, Unit);
llvm::DITemplateValueParameter TVP =
- DBuilder.createTemplateValueParameter(TheCU, Name, TTy,
- V->stripPointerCasts());
+ DBuilder.createTemplateValueParameter(
+ TheCU, Name, TTy, cast<llvm::Constant>(V->stripPointerCasts()));
TemplateParams.push_back(TVP);
} break;
// And the following should never occur:
@@ -1339,13 +1344,13 @@ CollectTemplateParams(const TemplateParameterList *TPList,
/// CollectFunctionTemplateParams - A helper function to collect debug
/// info for function template parameters.
-llvm::DIArray CGDebugInfo::
-CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) {
+llvm::DIArray CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD,
+ llvm::DIFile Unit) {
if (FD->getTemplatedKind() ==
FunctionDecl::TK_FunctionTemplateSpecialization) {
- const TemplateParameterList *TList =
- FD->getTemplateSpecializationInfo()->getTemplate()
- ->getTemplateParameters();
+ const TemplateParameterList *TList = FD->getTemplateSpecializationInfo()
+ ->getTemplate()
+ ->getTemplateParameters();
return CollectTemplateParams(
TList, FD->getTemplateSpecializationArgs()->asArray(), Unit);
}
@@ -1354,13 +1359,12 @@ CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) {
/// CollectCXXTemplateParams - A helper function to collect debug info for
/// template parameters.
-llvm::DIArray CGDebugInfo::
-CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TSpecial,
- llvm::DIFile Unit) {
+llvm::DIArray CGDebugInfo::CollectCXXTemplateParams(
+ const ClassTemplateSpecializationDecl *TSpecial, llvm::DIFile Unit) {
// Always get the full list of parameters, not just the ones from
// the specialization.
TemplateParameterList *TPList =
- TSpecial->getSpecializedTemplate()->getTemplateParameters();
+ TSpecial->getSpecializedTemplate()->getTemplateParameters();
const TemplateArgumentList &TAList = TSpecial->getTemplateArgs();
return CollectTemplateParams(TPList, TAList.asArray(), Unit);
}
@@ -1373,12 +1377,12 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
ASTContext &Context = CGM.getContext();
/* Function type */
- llvm::Value *STy = getOrCreateType(Context.IntTy, Unit);
- llvm::DIArray SElements = DBuilder.getOrCreateArray(STy);
+ llvm::Metadata *STy = getOrCreateType(Context.IntTy, Unit);
+ llvm::DITypeArray SElements = DBuilder.getOrCreateTypeArray(STy);
llvm::DIType SubTy = DBuilder.createSubroutineType(Unit, SElements);
unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
- llvm::DIType vtbl_ptr_type = DBuilder.createPointerType(SubTy, Size, 0,
- "__vtbl_ptr_type");
+ llvm::DIType vtbl_ptr_type =
+ DBuilder.createPointerType(SubTy, Size, 0, "__vtbl_ptr_type");
VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size);
return VTablePtrType;
}
@@ -1389,12 +1393,10 @@ StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
return internString("_vptr$", RD->getNameAsString());
}
-
/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate
/// debug info entry in EltTys vector.
-void CGDebugInfo::
-CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
- SmallVectorImpl<llvm::Value *> &EltTys) {
+void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
+ SmallVectorImpl<llvm::Metadata *> &EltTys) {
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
// If there is a primary base then it will hold vtable info.
@@ -1406,11 +1408,9 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
return;
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
- llvm::DIType VPTR
- = DBuilder.createMemberType(Unit, getVTableName(RD), Unit,
- 0, Size, 0, 0,
- llvm::DIDescriptor::FlagArtificial,
- getOrCreateVTablePtrType(Unit));
+ llvm::DIType VPTR = DBuilder.createMemberType(
+ Unit, getVTableName(RD), Unit, 0, Size, 0, 0,
+ llvm::DIDescriptor::FlagArtificial, getOrCreateVTablePtrType(Unit));
EltTys.push_back(VPTR);
}
@@ -1436,15 +1436,14 @@ void CGDebugInfo::completeType(const EnumDecl *ED) {
if (DebugKind <= CodeGenOptions::DebugLineTablesOnly)
return;
QualType Ty = CGM.getContext().getEnumType(ED);
- void* TyPtr = Ty.getAsOpaquePtr();
+ void *TyPtr = Ty.getAsOpaquePtr();
auto I = TypeCache.find(TyPtr);
if (I == TypeCache.end() ||
- !llvm::DIType(cast<llvm::MDNode>(static_cast<llvm::Value *>(I->second)))
- .isForwardDecl())
+ !llvm::DIType(cast<llvm::MDNode>(I->second)).isForwardDecl())
return;
llvm::DIType Res = CreateTypeDefinition(Ty->castAs<EnumType>());
assert(!Res.isForwardDecl());
- TypeCache[TyPtr] = Res;
+ TypeCache[TyPtr].reset(Res);
}
void CGDebugInfo::completeType(const RecordDecl *RD) {
@@ -1471,15 +1470,14 @@ void CGDebugInfo::completeClassData(const RecordDecl *RD) {
if (DebugKind <= CodeGenOptions::DebugLineTablesOnly)
return;
QualType Ty = CGM.getContext().getRecordType(RD);
- void* TyPtr = Ty.getAsOpaquePtr();
+ void *TyPtr = Ty.getAsOpaquePtr();
auto I = TypeCache.find(TyPtr);
if (I != TypeCache.end() &&
- !llvm::DIType(cast<llvm::MDNode>(static_cast<llvm::Value *>(I->second)))
- .isForwardDecl())
+ !llvm::DIType(cast<llvm::MDNode>(I->second)).isForwardDecl())
return;
llvm::DIType Res = CreateTypeDefinition(Ty->castAs<RecordType>());
assert(!Res.isForwardDecl());
- TypeCache[TyPtr] = Res;
+ TypeCache[TyPtr].reset(Res);
}
static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I,
@@ -1563,11 +1561,11 @@ llvm::DIType CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {
CollectContainingType(CXXDecl, FwdDecl);
// Push the struct on region stack.
- LexicalBlockStack.push_back(&*FwdDecl);
- RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
+ LexicalBlockStack.emplace_back(&*FwdDecl);
+ RegionMap[Ty->getDecl()].reset(FwdDecl);
// Convert all the elements.
- SmallVector<llvm::Value *, 16> EltTys;
+ SmallVector<llvm::Metadata *, 16> EltTys;
// what about nested types?
// Note: The split of CXXDecl information here is intentional, the
@@ -1589,9 +1587,9 @@ llvm::DIType CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {
RegionMap.erase(Ty->getDecl());
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- FwdDecl.setTypeArray(Elements);
+ DBuilder.replaceArrays(FwdDecl, Elements);
- RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
+ RegionMap[Ty->getDecl()].reset(FwdDecl);
return FwdDecl;
}
@@ -1602,7 +1600,6 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCObjectType *Ty,
return getOrCreateType(Ty->getBaseType(), Unit);
}
-
/// \return true if Getter has the default name for the property PD.
static bool hasDefaultGetterName(const ObjCPropertyDecl *PD,
const ObjCMethodDecl *Getter) {
@@ -1612,7 +1609,7 @@ static bool hasDefaultGetterName(const ObjCPropertyDecl *PD,
assert(Getter->getDeclName().isObjCZeroArgSelector());
return PD->getName() ==
- Getter->getDeclName().getObjCSelector().getNameForSlot(0);
+ Getter->getDeclName().getObjCSelector().getNameForSlot(0);
}
/// \return true if Setter has the default name for the property PD.
@@ -1624,7 +1621,7 @@ static bool hasDefaultSetterName(const ObjCPropertyDecl *PD,
assert(Setter->getDeclName().isObjCOneArgSelector());
return SelectorTable::constructSetterName(PD->getName()) ==
- Setter->getDeclName().getObjCSelector().getNameForSlot(0);
+ Setter->getDeclName().getObjCSelector().getNameForSlot(0);
}
/// CreateType - get objective-c interface type.
@@ -1650,11 +1647,11 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
return FwdDecl;
}
-
return CreateTypeDefinition(Ty, Unit);
}
-llvm::DIType CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile Unit) {
+llvm::DIType CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
+ llvm::DIFile Unit) {
ObjCInterfaceDecl *ID = Ty->getDecl();
llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation());
unsigned Line = getLineNumber(ID->getLocation());
@@ -1668,30 +1665,28 @@ llvm::DIType CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm
if (ID->getImplementation())
Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
- llvm::DICompositeType RealDecl =
- DBuilder.createStructType(Unit, ID->getName(), DefUnit,
- Line, Size, Align, Flags,
- llvm::DIType(), llvm::DIArray(), RuntimeLang);
+ llvm::DICompositeType RealDecl = DBuilder.createStructType(
+ Unit, ID->getName(), DefUnit, Line, Size, Align, Flags, llvm::DIType(),
+ llvm::DIArray(), RuntimeLang);
QualType QTy(Ty, 0);
- TypeCache[QTy.getAsOpaquePtr()] = RealDecl;
+ TypeCache[QTy.getAsOpaquePtr()].reset(RealDecl);
// Push the struct on region stack.
- LexicalBlockStack.push_back(static_cast<llvm::MDNode*>(RealDecl));
- RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
+ LexicalBlockStack.emplace_back(static_cast<llvm::MDNode *>(RealDecl));
+ RegionMap[Ty->getDecl()].reset(RealDecl);
// Convert all the elements.
- SmallVector<llvm::Value *, 16> EltTys;
+ SmallVector<llvm::Metadata *, 16> EltTys;
ObjCInterfaceDecl *SClass = ID->getSuperClass();
if (SClass) {
llvm::DIType SClassTy =
- getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
+ getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
if (!SClassTy.isValid())
return llvm::DIType();
- llvm::DIType InhTag =
- DBuilder.createInheritance(RealDecl, SClassTy, 0, 0);
+ llvm::DIType InhTag = DBuilder.createInheritance(RealDecl, SClassTy, 0, 0);
EltTys.push_back(InhTag);
}
@@ -1702,15 +1697,13 @@ llvm::DIType CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm
unsigned PLine = getLineNumber(Loc);
ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
- llvm::MDNode *PropertyNode =
- DBuilder.createObjCProperty(PD->getName(),
- PUnit, PLine,
- hasDefaultGetterName(PD, Getter) ? "" :
- getSelectorName(PD->getGetterName()),
- hasDefaultSetterName(PD, Setter) ? "" :
- getSelectorName(PD->getSetterName()),
- PD->getPropertyAttributes(),
- getOrCreateType(PD->getType(), PUnit));
+ llvm::MDNode *PropertyNode = DBuilder.createObjCProperty(
+ PD->getName(), PUnit, PLine,
+ hasDefaultGetterName(PD, Getter) ? ""
+ : getSelectorName(PD->getGetterName()),
+ hasDefaultSetterName(PD, Setter) ? ""
+ : getSelectorName(PD->getSetterName()),
+ PD->getPropertyAttributes(), getOrCreateType(PD->getType(), PUnit));
EltTys.push_back(PropertyNode);
}
@@ -1750,8 +1743,8 @@ llvm::DIType CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm
// non-fragile ABI. For bitfields, use the bit offset into the first
// byte of storage of the bitfield. For other fields, use zero.
if (Field->isBitField()) {
- FieldOffset = CGM.getObjCRuntime().ComputeBitfieldBitOffset(
- CGM, ID, Field);
+ FieldOffset =
+ CGM.getObjCRuntime().ComputeBitfieldBitOffset(CGM, ID, Field);
FieldOffset %= CGM.getContext().getCharWidth();
} else {
FieldOffset = 0;
@@ -1765,38 +1758,38 @@ llvm::DIType CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm
Flags = llvm::DIDescriptor::FlagProtected;
else if (Field->getAccessControl() == ObjCIvarDecl::Private)
Flags = llvm::DIDescriptor::FlagPrivate;
+ else if (Field->getAccessControl() == ObjCIvarDecl::Public)
+ Flags = llvm::DIDescriptor::FlagPublic;
llvm::MDNode *PropertyNode = nullptr;
if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
if (ObjCPropertyImplDecl *PImpD =
- ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
+ ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) {
SourceLocation Loc = PD->getLocation();
llvm::DIFile PUnit = getOrCreateFile(Loc);
unsigned PLine = getLineNumber(Loc);
ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
- PropertyNode =
- DBuilder.createObjCProperty(PD->getName(),
- PUnit, PLine,
- hasDefaultGetterName(PD, Getter) ? "" :
- getSelectorName(PD->getGetterName()),
- hasDefaultSetterName(PD, Setter) ? "" :
- getSelectorName(PD->getSetterName()),
- PD->getPropertyAttributes(),
- getOrCreateType(PD->getType(), PUnit));
+ PropertyNode = DBuilder.createObjCProperty(
+ PD->getName(), PUnit, PLine,
+ hasDefaultGetterName(PD, Getter) ? "" : getSelectorName(
+ PD->getGetterName()),
+ hasDefaultSetterName(PD, Setter) ? "" : getSelectorName(
+ PD->getSetterName()),
+ PD->getPropertyAttributes(),
+ getOrCreateType(PD->getType(), PUnit));
}
}
}
- FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit,
- FieldLine, FieldSize, FieldAlign,
- FieldOffset, Flags, FieldTy,
- PropertyNode);
+ FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit, FieldLine,
+ FieldSize, FieldAlign, FieldOffset, Flags,
+ FieldTy, PropertyNode);
EltTys.push_back(FieldTy);
}
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- RealDecl.setTypeArray(Elements);
+ DBuilder.replaceArrays(RealDecl, Elements);
LexicalBlockStack.pop_back();
return RealDecl;
@@ -1810,7 +1803,7 @@ llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) {
// Use Count == -1 to express such arrays.
Count = -1;
- llvm::Value *Subscript = DBuilder.getOrCreateSubrange(0, Count);
+ llvm::Metadata *Subscript = DBuilder.getOrCreateSubrange(0, Count);
llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscript);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
@@ -1819,8 +1812,7 @@ llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) {
return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray);
}
-llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
- llvm::DIFile Unit) {
+llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DIFile Unit) {
uint64_t Size;
uint64_t Align;
@@ -1828,7 +1820,7 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(Ty)) {
Size = 0;
Align =
- CGM.getContext().getTypeAlign(CGM.getContext().getBaseElementType(VAT));
+ CGM.getContext().getTypeAlign(CGM.getContext().getBaseElementType(VAT));
} else if (Ty->isIncompleteArrayType()) {
Size = 0;
if (Ty->getElementType()->isIncompleteType())
@@ -1847,7 +1839,7 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
// Add the dimensions of the array. FIXME: This loses CV qualifiers from
// interior arrays, do we care? Why aren't nested arrays represented the
// obvious/recursive way?
- SmallVector<llvm::Value *, 8> Subscripts;
+ SmallVector<llvm::Metadata *, 8> Subscripts;
QualType EltTy(Ty, 0);
while ((Ty = dyn_cast<ArrayType>(EltTy))) {
// If the number of elements is known, then count is that number. Otherwise,
@@ -1857,7 +1849,7 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
// struct foo {
// int x[0];
// };
- int64_t Count = -1; // Count == -1 is an unbounded array.
+ int64_t Count = -1; // Count == -1 is an unbounded array.
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
Count = CAT->getSize().getZExtValue();
@@ -1868,22 +1860,21 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts);
- llvm::DIType DbgTy =
- DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit),
- SubscriptArray);
+ llvm::DIType DbgTy = DBuilder.createArrayType(
+ Size, Align, getOrCreateType(EltTy, Unit), SubscriptArray);
return DbgTy;
}
llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty,
llvm::DIFile Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type,
- Ty, Ty->getPointeeType(), Unit);
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type, Ty,
+ Ty->getPointeeType(), Unit);
}
llvm::DIType CGDebugInfo::CreateType(const RValueReferenceType *Ty,
llvm::DIFile Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type,
- Ty, Ty->getPointeeType(), Unit);
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type, Ty,
+ Ty->getPointeeType(), Unit);
}
llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
@@ -1891,18 +1882,19 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
llvm::DIType ClassType = getOrCreateType(QualType(Ty->getClass(), 0), U);
if (!Ty->getPointeeType()->isFunctionType())
return DBuilder.createMemberPointerType(
- getOrCreateType(Ty->getPointeeType(), U), ClassType);
+ getOrCreateType(Ty->getPointeeType(), U), ClassType,
+ CGM.getContext().getTypeSize(Ty));
const FunctionProtoType *FPT =
- Ty->getPointeeType()->getAs<FunctionProtoType>();
- return DBuilder.createMemberPointerType(getOrCreateInstanceMethodType(
- CGM.getContext().getPointerType(QualType(Ty->getClass(),
- FPT->getTypeQuals())),
- FPT, U), ClassType);
+ Ty->getPointeeType()->getAs<FunctionProtoType>();
+ return DBuilder.createMemberPointerType(
+ getOrCreateInstanceMethodType(CGM.getContext().getPointerType(QualType(
+ Ty->getClass(), FPT->getTypeQuals())),
+ FPT, U),
+ ClassType, CGM.getContext().getTypeSize(Ty));
}
-llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
- llvm::DIFile U) {
+llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile U) {
// Ignore the atomic wrapping
// FIXME: What is the correct representation?
return getOrCreateType(Ty->getValueType(), U);
@@ -1931,7 +1923,9 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumType *Ty) {
llvm::DIType RetTy = DBuilder.createReplaceableForwardDecl(
llvm::dwarf::DW_TAG_enumeration_type, EDName, EDContext, DefUnit, Line,
0, Size, Align, FullName);
- ReplaceMap.push_back(std::make_pair(Ty, static_cast<llvm::Value *>(RetTy)));
+ ReplaceMap.emplace_back(
+ std::piecewise_construct, std::make_tuple(Ty),
+ std::make_tuple(static_cast<llvm::Metadata *>(RetTy)));
return RetTy;
}
@@ -1950,12 +1944,11 @@ llvm::DIType CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) {
SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
// Create DIEnumerator elements for each enumerator.
- SmallVector<llvm::Value *, 16> Enumerators;
+ SmallVector<llvm::Metadata *, 16> Enumerators;
ED = ED->getDefinition();
for (const auto *Enum : ED->enumerators()) {
- Enumerators.push_back(
- DBuilder.createEnumerator(Enum->getName(),
- Enum->getInitVal().getSExtValue()));
+ Enumerators.push_back(DBuilder.createEnumerator(
+ Enum->getName(), Enum->getInitVal().getSExtValue()));
}
// Return a CompositeType for the enum itself.
@@ -1964,13 +1957,13 @@ llvm::DIType CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) {
llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
unsigned Line = getLineNumber(ED->getLocation());
llvm::DIDescriptor EnumContext =
- getContextDescriptor(cast<Decl>(ED->getDeclContext()));
- llvm::DIType ClassTy = ED->isFixed() ?
- getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType();
+ getContextDescriptor(cast<Decl>(ED->getDeclContext()));
+ llvm::DIType ClassTy = ED->isFixed()
+ ? getOrCreateType(ED->getIntegerType(), DefUnit)
+ : llvm::DIType();
llvm::DIType DbgTy =
- DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line,
- Size, Align, EltArray,
- ClassTy, FullName);
+ DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line,
+ Size, Align, EltArray, ClassTy, FullName);
return DbgTy;
}
@@ -1991,7 +1984,8 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
if (Spec->isTypeAlias())
return C.getQualifiedType(T.getTypePtr(), Quals);
T = Spec->desugar();
- break; }
+ break;
+ }
case Type::TypeOfExpr:
T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
break;
@@ -2018,8 +2012,7 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
break;
case Type::Auto:
QualType DT = cast<AutoType>(T)->getDeducedType();
- if (DT.isNull())
- return T;
+ assert(!DT.isNull() && "Undeduced types shouldn't reach here.");
T = DT;
break;
}
@@ -2039,7 +2032,7 @@ llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
auto it = TypeCache.find(Ty.getAsOpaquePtr());
if (it != TypeCache.end()) {
// Verify that the debug info still exists.
- if (llvm::Value *V = it->second)
+ if (llvm::Metadata *V = it->second)
return llvm::DIType(cast<llvm::MDNode>(V));
}
@@ -2071,10 +2064,10 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
// Otherwise create the type.
llvm::DIType Res = CreateTypeNode(Ty, Unit);
- void* TyPtr = Ty.getAsOpaquePtr();
+ void *TyPtr = Ty.getAsOpaquePtr();
// And update the type cache.
- TypeCache[TyPtr] = Res;
+ TypeCache[TyPtr].reset(Res);
return Res;
}
@@ -2096,8 +2089,8 @@ unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl *ID) {
ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) {
switch (Ty->getTypeClass()) {
case Type::ObjCObjectPointer:
- return getObjCInterfaceDecl(cast<ObjCObjectPointerType>(Ty)
- ->getPointeeType());
+ return getObjCInterfaceDecl(
+ cast<ObjCObjectPointerType>(Ty)->getPointeeType());
case Type::ObjCInterface:
return cast<ObjCInterfaceType>(Ty)->getDecl();
default:
@@ -2111,8 +2104,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
if (Ty.hasLocalQualifiers())
return CreateQualifiedType(Ty, Unit);
- const char *Diag = nullptr;
-
// Work out details of type.
switch (Ty->getTypeClass()) {
#define TYPE(Class, Base)
@@ -2172,6 +2163,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
case Type::TemplateSpecialization:
return CreateType(cast<TemplateSpecializationType>(Ty), Unit);
+ case Type::Auto:
case Type::Attributed:
case Type::Elaborated:
case Type::Paren:
@@ -2181,18 +2173,10 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
case Type::Decltype:
case Type::UnaryTransform:
case Type::PackExpansion:
- llvm_unreachable("type should have been unwrapped!");
- case Type::Auto:
- Diag = "auto";
break;
}
- assert(Diag && "Fall through without a diagnostic?");
- unsigned DiagID = CGM.getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "debug information for %0 is not yet supported");
- CGM.getDiags().Report(DiagID)
- << Diag;
- return llvm::DIType();
+ llvm_unreachable("type should have been unwrapped!");
}
/// getOrCreateLimitedType - Get the type from the cache or create a new
@@ -2206,7 +2190,8 @@ llvm::DIType CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty,
// We may have cached a forward decl when we could have created
// a non-forward decl. Go ahead and create a non-forward decl
// now.
- if (T && !T.isForwardDecl()) return T;
+ if (T && !T.isForwardDecl())
+ return T;
// Otherwise create the type.
llvm::DICompositeType Res = CreateLimitedType(Ty);
@@ -2214,10 +2199,10 @@ llvm::DIType CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty,
// Propagate members from the declaration to the definition
// CreateType(const RecordType*) will overwrite this with the members in the
// correct order if the full type is needed.
- Res.setTypeArray(T.getTypeArray());
+ DBuilder.replaceArrays(Res, T.getElements());
// And update the type cache.
- TypeCache[QTy.getAsOpaquePtr()] = Res;
+ TypeCache[QTy.getAsOpaquePtr()].reset(Res);
return Res;
}
@@ -2237,7 +2222,7 @@ llvm::DICompositeType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
// just return that.
llvm::DICompositeType T(getTypeOrNull(CGM.getContext().getRecordType(RD)));
if (T && (!T.isForwardDecl() || !RD->getDefinition()))
- return T;
+ return T;
// If this is just a forward or incomplete declaration, construct an
// appropriately marked node and just return it.
@@ -2252,29 +2237,26 @@ llvm::DICompositeType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
if (RD->isUnion())
- RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, llvm::DIArray(), 0,
- FullName);
+ RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line, Size,
+ Align, 0, llvm::DIArray(), 0, FullName);
else if (RD->isClass()) {
// FIXME: This could be a struct type giving a default visibility different
// than C++ class type, but needs llvm metadata changes first.
- RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, 0, llvm::DIType(),
- llvm::DIArray(), llvm::DIType(),
- llvm::DIArray(), FullName);
+ RealDecl = DBuilder.createClassType(
+ RDContext, RDName, DefUnit, Line, Size, Align, 0, 0, llvm::DIType(),
+ llvm::DIArray(), llvm::DIType(), llvm::DIArray(), FullName);
} else
- RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, llvm::DIType(),
- llvm::DIArray(), 0, llvm::DIType(),
- FullName);
+ RealDecl = DBuilder.createStructType(
+ RDContext, RDName, DefUnit, Line, Size, Align, 0, llvm::DIType(),
+ llvm::DIArray(), 0, llvm::DIType(), FullName);
- RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
+ RegionMap[Ty->getDecl()].reset(RealDecl);
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl);
if (const ClassTemplateSpecializationDecl *TSpecial =
dyn_cast<ClassTemplateSpecializationDecl>(RD))
- RealDecl.setTypeArray(llvm::DIArray(),
- CollectCXXTemplateParams(TSpecial, DefUnit));
+ DBuilder.replaceArrays(RealDecl, llvm::DIArray(),
+ CollectCXXTemplateParams(TSpecial, DefUnit));
return RealDecl;
}
@@ -2299,24 +2281,148 @@ void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD,
} else if (RD->isDynamicClass())
ContainingType = RealDecl;
- RealDecl.setContainingType(ContainingType);
+ DBuilder.replaceVTableHolder(RealDecl, ContainingType);
}
/// CreateMemberType - Create new member and increase Offset by FType's size.
llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
- StringRef Name,
- uint64_t *Offset) {
+ StringRef Name, uint64_t *Offset) {
llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
uint64_t FieldSize = CGM.getContext().getTypeSize(FType);
unsigned FieldAlign = CGM.getContext().getTypeAlign(FType);
- llvm::DIType Ty = DBuilder.createMemberType(Unit, Name, Unit, 0,
- FieldSize, FieldAlign,
- *Offset, 0, FieldTy);
+ llvm::DIType Ty = DBuilder.createMemberType(Unit, Name, Unit, 0, FieldSize,
+ FieldAlign, *Offset, 0, FieldTy);
*Offset += FieldSize;
return Ty;
}
-llvm::DIScope CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
+void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD,
+ llvm::DIFile Unit,
+ StringRef &Name, StringRef &LinkageName,
+ llvm::DIDescriptor &FDContext,
+ llvm::DIArray &TParamsArray,
+ unsigned &Flags) {
+ const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+ Name = getFunctionName(FD);
+ // Use mangled name as linkage name for C/C++ functions.
+ if (FD->hasPrototype()) {
+ LinkageName = CGM.getMangledName(GD);
+ Flags |= llvm::DIDescriptor::FlagPrototyped;
+ }
+ // No need to replicate the linkage name if it isn't different from the
+ // subprogram name, no need to have it at all unless coverage is enabled or
+ // debug is set to more than just line tables.
+ if (LinkageName == Name ||
+ (!CGM.getCodeGenOpts().EmitGcovArcs &&
+ !CGM.getCodeGenOpts().EmitGcovNotes &&
+ DebugKind <= CodeGenOptions::DebugLineTablesOnly))
+ LinkageName = StringRef();
+
+ if (DebugKind >= CodeGenOptions::LimitedDebugInfo) {
+ 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));
+ // Collect template parameters.
+ TParamsArray = CollectFunctionTemplateParams(FD, Unit);
+ }
+}
+
+void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile &Unit,
+ unsigned &LineNo, QualType &T,
+ StringRef &Name, StringRef &LinkageName,
+ llvm::DIDescriptor &VDContext) {
+ Unit = getOrCreateFile(VD->getLocation());
+ LineNo = getLineNumber(VD->getLocation());
+
+ setLocation(VD->getLocation());
+
+ T = VD->getType();
+ if (T->isIncompleteArrayType()) {
+ // CodeGen turns int[] into int[1] so we'll do the same here.
+ llvm::APInt ConstVal(32, 1);
+ QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
+
+ T = CGM.getContext().getConstantArrayType(ET, ConstVal,
+ ArrayType::Normal, 0);
+ }
+
+ Name = VD->getName();
+ if (VD->getDeclContext() && !isa<FunctionDecl>(VD->getDeclContext()) &&
+ !isa<ObjCMethodDecl>(VD->getDeclContext()))
+ LinkageName = CGM.getMangledName(VD);
+ if (LinkageName == Name)
+ LinkageName = StringRef();
+
+ // Since we emit declarations (DW_AT_members) for static members, place the
+ // definition of those static members in the namespace they were declared in
+ // in the source code (the lexical decl context).
+ // FIXME: Generalize this for even non-member global variables where the
+ // declaration and definition may have different lexical decl contexts, once
+ // we have support for emitting declarations of (non-member) global variables.
+ VDContext = getContextDescriptor(
+ dyn_cast<Decl>(VD->isStaticDataMember() ? VD->getLexicalDeclContext()
+ : VD->getDeclContext()));
+}
+
+llvm::DISubprogram
+CGDebugInfo::getFunctionForwardDeclaration(const FunctionDecl *FD) {
+ llvm::DIArray TParamsArray;
+ StringRef Name, LinkageName;
+ unsigned Flags = 0;
+ SourceLocation Loc = FD->getLocation();
+ llvm::DIFile Unit = getOrCreateFile(Loc);
+ llvm::DIDescriptor DContext(Unit);
+ unsigned Line = getLineNumber(Loc);
+
+ collectFunctionDeclProps(FD, Unit, Name, LinkageName, DContext,
+ TParamsArray, Flags);
+ // Build function type.
+ SmallVector<QualType, 16> ArgTypes;
+ for (const ParmVarDecl *Parm: FD->parameters())
+ ArgTypes.push_back(Parm->getType());
+ QualType FnType =
+ CGM.getContext().getFunctionType(FD->getReturnType(), ArgTypes,
+ FunctionProtoType::ExtProtoInfo());
+ llvm::DISubprogram SP =
+ DBuilder.createTempFunctionFwdDecl(DContext, Name, LinkageName, Unit, Line,
+ getOrCreateFunctionType(FD, FnType, Unit),
+ !FD->isExternallyVisible(),
+ false /*declaration*/, 0, Flags,
+ CGM.getLangOpts().Optimize, nullptr,
+ TParamsArray, getFunctionDeclaration(FD));
+ const FunctionDecl *CanonDecl = cast<FunctionDecl>(FD->getCanonicalDecl());
+ FwdDeclReplaceMap.emplace_back(
+ std::piecewise_construct, std::make_tuple(CanonDecl),
+ std::make_tuple(static_cast<llvm::Metadata *>(SP)));
+ return SP;
+}
+
+llvm::DIGlobalVariable
+CGDebugInfo::getGlobalVariableForwardDeclaration(const VarDecl *VD) {
+ QualType T;
+ StringRef Name, LinkageName;
+ SourceLocation Loc = VD->getLocation();
+ llvm::DIFile Unit = getOrCreateFile(Loc);
+ llvm::DIDescriptor DContext(Unit);
+ unsigned Line = getLineNumber(Loc);
+
+ collectVarDeclProps(VD, Unit, Line, T, Name, LinkageName, DContext);
+ llvm::DIGlobalVariable GV =
+ DBuilder.createTempGlobalVariableFwdDecl(DContext, Name, LinkageName, Unit,
+ Line, getOrCreateType(T, Unit),
+ !VD->isExternallyVisible(),
+ nullptr, nullptr);
+ FwdDeclReplaceMap.emplace_back(
+ std::piecewise_construct,
+ std::make_tuple(cast<VarDecl>(VD->getCanonicalDecl())),
+ std::make_tuple(static_cast<llvm::Metadata *>(GV)));
+ return GV;
+}
+
+llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
// We only need a declaration (not a definition) of the type - so use whatever
// we would otherwise do to get a type for a pointee. (forward declarations in
// limited debug info, full definitions (if the type definition is available)
@@ -2324,19 +2430,19 @@ llvm::DIScope CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
if (const TypeDecl *TD = dyn_cast<TypeDecl>(D))
return getOrCreateType(CGM.getContext().getTypeDeclType(TD),
getOrCreateFile(TD->getLocation()));
- // Otherwise fall back to a fairly rudimentary cache of existing declarations.
- // This doesn't handle providing declarations (for functions or variables) for
- // entities without definitions in this TU, nor when the definition proceeds
- // the call to this function.
- // FIXME: This should be split out into more specific maps with support for
- // emitting forward declarations and merging definitions with declarations,
- // the same way as we do for types.
- llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator I =
- DeclCache.find(D->getCanonicalDecl());
- if (I == DeclCache.end())
- return llvm::DIScope();
- llvm::Value *V = I->second;
- return llvm::DIScope(dyn_cast_or_null<llvm::MDNode>(V));
+ auto I = DeclCache.find(D->getCanonicalDecl());
+
+ if (I != DeclCache.end())
+ return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(I->second));
+
+ // No definition for now. Emit a forward definition that might be
+ // merged with a potential upcoming definition.
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ return getFunctionForwardDeclaration(FD);
+ else if (const auto *VD = dyn_cast<VarDecl>(D))
+ return getGlobalVariableForwardDeclaration(VD);
+
+ return llvm::DIDescriptor();
}
/// getFunctionDeclaration - Return debug info descriptor to describe method
@@ -2346,13 +2452,13 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
return llvm::DISubprogram();
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD) return llvm::DISubprogram();
+ if (!FD)
+ return llvm::DISubprogram();
// Setup context.
llvm::DIScope S = getContextDescriptor(cast<Decl>(D->getDeclContext()));
- llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
- MI = SPCache.find(FD->getCanonicalDecl());
+ auto MI = SPCache.find(FD->getCanonicalDecl());
if (MI == SPCache.end()) {
if (const CXXMethodDecl *MD =
dyn_cast<CXXMethodDecl>(FD->getCanonicalDecl())) {
@@ -2363,18 +2469,15 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
}
}
if (MI != SPCache.end()) {
- llvm::Value *V = MI->second;
- llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V));
+ llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(MI->second));
if (SP.isSubprogram() && !SP.isDefinition())
return SP;
}
for (auto NextFD : FD->redecls()) {
- llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
- MI = SPCache.find(NextFD->getCanonicalDecl());
+ auto MI = SPCache.find(NextFD->getCanonicalDecl());
if (MI != SPCache.end()) {
- llvm::Value *V = MI->second;
- llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V));
+ llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(MI->second));
if (SP.isSubprogram() && !SP.isDefinition())
return SP;
}
@@ -2392,13 +2495,14 @@ llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
// llvm::DISubprogram::Verify() would return false, and
// subprogram DIE will miss DW_AT_decl_file and
// DW_AT_decl_line fields.
- return DBuilder.createSubroutineType(F, DBuilder.getOrCreateArray(None));
+ return DBuilder.createSubroutineType(F,
+ DBuilder.getOrCreateTypeArray(None));
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
return getOrCreateMethodType(Method, F);
if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) {
// Add "self" and "_cmd"
- SmallVector<llvm::Value *, 16> Elts;
+ SmallVector<llvm::Metadata *, 16> Elts;
// First element is always return type. For 'void' functions it is NULL.
QualType ResultTy = OMethod->getReturnType();
@@ -2406,7 +2510,7 @@ llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
// Replace the instancetype keyword with the actual type.
if (ResultTy == CGM.getContext().getObjCInstanceType())
ResultTy = CGM.getContext().getPointerType(
- QualType(OMethod->getClassInterface()->getTypeForDecl(), 0));
+ QualType(OMethod->getClassInterface()->getTypeForDecl(), 0));
Elts.push_back(getOrCreateType(ResultTy, F));
// "self" pointer is always first argument.
@@ -2419,8 +2523,11 @@ llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
// Get rest of the arguments.
for (const auto *PI : OMethod->params())
Elts.push_back(getOrCreateType(PI->getType(), F));
+ // Variadic methods need a special marker at the end of the type list.
+ if (OMethod->isVariadic())
+ Elts.push_back(DBuilder.createUnspecifiedParameter());
- llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
+ llvm::DITypeArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts);
return DBuilder.createSubroutineType(F, EltTypeArray);
}
@@ -2428,13 +2535,13 @@ llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
// unspecified parameter.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
if (FD->isVariadic()) {
- SmallVector<llvm::Value *, 16> EltTys;
+ SmallVector<llvm::Metadata *, 16> EltTys;
EltTys.push_back(getOrCreateType(FD->getReturnType(), F));
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FnType))
for (unsigned i = 0, e = FPT->getNumParams(); i != e; ++i)
EltTys.push_back(getOrCreateType(FPT->getParamType(i), F));
EltTys.push_back(DBuilder.createUnspecifiedParameter());
- llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(EltTys);
+ llvm::DITypeArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys);
return DBuilder.createSubroutineType(F, EltTypeArray);
}
@@ -2442,12 +2549,9 @@ llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
}
/// EmitFunctionStart - Constructs the debug code for entering a function.
-void CGDebugInfo::EmitFunctionStart(GlobalDecl GD,
- SourceLocation Loc,
- SourceLocation ScopeLoc,
- QualType FnType,
- llvm::Function *Fn,
- CGBuilderTy &Builder) {
+void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
+ SourceLocation ScopeLoc, QualType FnType,
+ llvm::Function *Fn, CGBuilderTy &Builder) {
StringRef Name;
StringRef LinkageName;
@@ -2466,44 +2570,18 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD,
LinkageName = Fn->getName();
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// If there is a DISubprogram for this function available then use it.
- llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
- FI = SPCache.find(FD->getCanonicalDecl());
+ auto FI = SPCache.find(FD->getCanonicalDecl());
if (FI != SPCache.end()) {
- llvm::Value *V = FI->second;
- llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(V));
+ llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(FI->second));
if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) {
llvm::MDNode *SPN = SP;
- LexicalBlockStack.push_back(SPN);
- RegionMap[D] = llvm::WeakVH(SP);
+ LexicalBlockStack.emplace_back(SPN);
+ RegionMap[D].reset(SP);
return;
}
}
- Name = getFunctionName(FD);
- // Use mangled name as linkage name for C/C++ functions.
- if (FD->hasPrototype()) {
- LinkageName = CGM.getMangledName(GD);
- Flags |= llvm::DIDescriptor::FlagPrototyped;
- }
- // No need to replicate the linkage name if it isn't different from the
- // subprogram name, no need to have it at all unless coverage is enabled or
- // debug is set to more than just line tables.
- if (LinkageName == Name ||
- (!CGM.getCodeGenOpts().EmitGcovArcs &&
- !CGM.getCodeGenOpts().EmitGcovNotes &&
- DebugKind <= CodeGenOptions::DebugLineTablesOnly))
- LinkageName = StringRef();
-
- if (DebugKind >= CodeGenOptions::LimitedDebugInfo) {
- 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));
-
- // Collect template parameters.
- TParamsArray = CollectFunctionTemplateParams(FD, Unit);
- }
+ collectFunctionDeclProps(GD, Unit, Name, LinkageName, FDContext,
+ TParamsArray, Flags);
} else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
Name = getObjCMethodName(OMD);
Flags |= llvm::DIDescriptor::FlagPrototyped;
@@ -2529,22 +2607,23 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD,
// FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for
// all subprograms instead of the actual context since subprogram definitions
// are emitted as CU level entities by the backend.
- llvm::DISubprogram SP =
- DBuilder.createFunction(FDContext, Name, LinkageName, Unit, LineNo,
- getOrCreateFunctionType(D, FnType, Unit),
- Fn->hasInternalLinkage(), true /*definition*/,
- ScopeLine, Flags,
- CGM.getLangOpts().Optimize, Fn, TParamsArray,
- getFunctionDeclaration(D));
- if (HasDecl)
- DeclCache.insert(std::make_pair(D->getCanonicalDecl(), llvm::WeakVH(SP)));
+ llvm::DISubprogram SP = DBuilder.createFunction(
+ FDContext, Name, LinkageName, Unit, LineNo,
+ getOrCreateFunctionType(D, FnType, Unit), Fn->hasInternalLinkage(),
+ true /*definition*/, ScopeLine, Flags, CGM.getLangOpts().Optimize, Fn,
+ TParamsArray, getFunctionDeclaration(D));
+ // We might get here with a VarDecl in the case we're generating
+ // code for the initialization of globals. Do not record these decls
+ // as they will overwrite the actual VarDecl Decl in the cache.
+ if (HasDecl && isa<FunctionDecl>(D))
+ DeclCache[D->getCanonicalDecl()].reset(static_cast<llvm::Metadata *>(SP));
// Push the function onto the lexical block stack.
llvm::MDNode *SPN = SP;
- LexicalBlockStack.push_back(SPN);
+ LexicalBlockStack.emplace_back(SPN);
if (HasDecl)
- RegionMap[D] = llvm::WeakVH(SP);
+ RegionMap[D].reset(SP);
}
/// EmitLocation - Emit metadata to indicate a change in line/column
@@ -2555,38 +2634,25 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc,
// Update our current location
setLocation(Loc);
- if (CurLoc.isInvalid() || CurLoc.isMacroID()) return;
-
- // Don't bother if things are the same as last time.
- SourceManager &SM = CGM.getContext().getSourceManager();
- if (CurLoc == PrevLoc ||
- SM.getExpansionLoc(CurLoc) == SM.getExpansionLoc(PrevLoc))
- // New Builder may not be in sync with CGDebugInfo.
- if (!Builder.getCurrentDebugLocation().isUnknown() &&
- Builder.getCurrentDebugLocation().getScope(CGM.getLLVMContext()) ==
- LexicalBlockStack.back())
- return;
-
- // Update last state.
- PrevLoc = CurLoc;
+ if (CurLoc.isInvalid() || CurLoc.isMacroID())
+ return;
llvm::MDNode *Scope = LexicalBlockStack.back();
- Builder.SetCurrentDebugLocation(llvm::DebugLoc::get
- (getLineNumber(CurLoc),
- getColumnNumber(CurLoc, ForceColumnInfo),
- Scope));
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(
+ getLineNumber(CurLoc), getColumnNumber(CurLoc, ForceColumnInfo), Scope));
}
/// CreateLexicalBlock - Creates a new lexical block node and pushes it on
/// the stack.
void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
+ llvm::MDNode *Back = nullptr;
+ if (!LexicalBlockStack.empty())
+ Back = LexicalBlockStack.back().get();
llvm::DIDescriptor D = DBuilder.createLexicalBlock(
- llvm::DIDescriptor(LexicalBlockStack.empty() ? nullptr
- : LexicalBlockStack.back()),
- getOrCreateFile(CurLoc), getLineNumber(CurLoc), getColumnNumber(CurLoc),
- 0);
+ llvm::DIDescriptor(Back), getOrCreateFile(CurLoc), getLineNumber(CurLoc),
+ getColumnNumber(CurLoc));
llvm::MDNode *DN = D;
- LexicalBlockStack.push_back(DN);
+ LexicalBlockStack.emplace_back(DN);
}
/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative
@@ -2596,13 +2662,15 @@ void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder,
// Set our current location.
setLocation(Loc);
+ // Emit a line table change for the current location inside the new scope.
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(
+ getLineNumber(Loc), getColumnNumber(Loc), LexicalBlockStack.back()));
+
+ if (DebugKind <= CodeGenOptions::DebugLineTablesOnly)
+ return;
+
// Create a new lexical block and push it on the stack.
CreateLexicalBlock(Loc);
-
- // Emit a line table change for the current location inside the new scope.
- Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(Loc),
- getColumnNumber(Loc),
- LexicalBlockStack.back()));
}
/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative
@@ -2614,6 +2682,9 @@ void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder,
// Provide an entry in the line table for the end of the block.
EmitLocation(Builder, Loc);
+ if (DebugKind <= CodeGenOptions::DebugLineTablesOnly)
+ return;
+
LexicalBlockStack.pop_back();
}
@@ -2624,8 +2695,11 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch");
// Pop all regions for this function.
- while (LexicalBlockStack.size() != RCount)
- EmitLexicalBlockEnd(Builder, CurLoc);
+ while (LexicalBlockStack.size() != RCount) {
+ // Provide an entry in the line table for the end of the block.
+ EmitLocation(Builder, CurLoc);
+ LexicalBlockStack.pop_back();
+ }
FnBeginRegionCount.pop_back();
}
@@ -2634,7 +2708,7 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
uint64_t *XOffset) {
- SmallVector<llvm::Value *, 5> EltTys;
+ SmallVector<llvm::Metadata *, 5> EltTys;
QualType FType;
uint64_t FieldSize, FieldOffset;
unsigned FieldAlign;
@@ -2653,31 +2727,29 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD);
if (HasCopyAndDispose) {
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper",
- &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper",
- &FieldOffset));
+ EltTys.push_back(
+ CreateMemberType(Unit, FType, "__copy_helper", &FieldOffset));
+ EltTys.push_back(
+ CreateMemberType(Unit, FType, "__destroy_helper", &FieldOffset));
}
bool HasByrefExtendedLayout;
Qualifiers::ObjCLifetime Lifetime;
- if (CGM.getContext().getByrefLifetime(Type,
- Lifetime, HasByrefExtendedLayout)
- && HasByrefExtendedLayout) {
+ if (CGM.getContext().getByrefLifetime(Type, Lifetime,
+ HasByrefExtendedLayout) &&
+ HasByrefExtendedLayout) {
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- EltTys.push_back(CreateMemberType(Unit, FType,
- "__byref_variable_layout",
- &FieldOffset));
+ EltTys.push_back(
+ CreateMemberType(Unit, FType, "__byref_variable_layout", &FieldOffset));
}
CharUnits Align = CGM.getContext().getDeclAlign(VD);
if (Align > CGM.getContext().toCharUnitsFromBits(
- CGM.getTarget().getPointerAlign(0))) {
- CharUnits FieldOffsetInBytes
- = CGM.getContext().toCharUnitsFromBits(FieldOffset);
- CharUnits AlignedOffsetInBytes
- = FieldOffsetInBytes.RoundUpToAlignment(Align);
- CharUnits NumPaddingBytes
- = AlignedOffsetInBytes - FieldOffsetInBytes;
+ CGM.getTarget().getPointerAlign(0))) {
+ CharUnits FieldOffsetInBytes =
+ CGM.getContext().toCharUnitsFromBits(FieldOffset);
+ CharUnits AlignedOffsetInBytes =
+ FieldOffsetInBytes.RoundUpToAlignment(Align);
+ CharUnits NumPaddingBytes = AlignedOffsetInBytes - FieldOffsetInBytes;
if (NumPaddingBytes.isPositive()) {
llvm::APInt pad(32, NumPaddingBytes.getQuantity());
@@ -2693,9 +2765,8 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
FieldAlign = CGM.getContext().toBits(Align);
*XOffset = FieldOffset;
- FieldTy = DBuilder.createMemberType(Unit, VD->getName(), Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
+ FieldTy = DBuilder.createMemberType(Unit, VD->getName(), Unit, 0, FieldSize,
+ FieldAlign, FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
@@ -2709,8 +2780,8 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
/// EmitDeclare - Emit local variable declaration debug info.
void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::dwarf::LLVMConstants Tag,
- llvm::Value *Storage,
- unsigned ArgNo, CGBuilderTy &Builder) {
+ llvm::Value *Storage, unsigned ArgNo,
+ CGBuilderTy &Builder) {
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
@@ -2760,29 +2831,26 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::dwarf::LLVMConstants Tag,
if (!Name.empty()) {
if (VD->hasAttr<BlocksAttr>()) {
CharUnits offset = CharUnits::fromQuantity(32);
- SmallVector<llvm::Value *, 9> addr;
- llvm::Type *Int64Ty = CGM.Int64Ty;
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
+ SmallVector<int64_t, 9> addr;
+ addr.push_back(llvm::dwarf::DW_OP_plus);
// offset of __forwarding field
offset = CGM.getContext().toCharUnitsFromBits(
- CGM.getTarget().getPointerWidth(0));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
+ CGM.getTarget().getPointerWidth(0));
+ addr.push_back(offset.getQuantity());
+ addr.push_back(llvm::dwarf::DW_OP_deref);
+ addr.push_back(llvm::dwarf::DW_OP_plus);
// offset of x field
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
- addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
+ addr.push_back(offset.getQuantity());
// Create the descriptor for the variable.
- llvm::DIVariable D =
- DBuilder.createComplexVariable(Tag,
- llvm::DIDescriptor(Scope),
- VD->getName(), Unit, Line, Ty,
- addr, ArgNo);
+ llvm::DIVariable D = DBuilder.createLocalVariable(
+ Tag, llvm::DIDescriptor(Scope), VD->getName(), Unit, Line, Ty, ArgNo);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
+ DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr),
+ Builder.GetInsertBlock());
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
return;
} else if (isa<VariableArrayType>(VD->getType()))
@@ -2801,15 +2869,13 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::dwarf::LLVMConstants Tag,
continue;
// Use VarDecl's Tag, Scope and Line number.
- llvm::DIVariable D =
- DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
- FieldName, Unit, Line, FieldTy,
- CGM.getLangOpts().Optimize, Flags,
- ArgNo);
+ llvm::DIVariable D = DBuilder.createLocalVariable(
+ Tag, llvm::DIDescriptor(Scope), FieldName, Unit, Line, FieldTy,
+ CGM.getLangOpts().Optimize, Flags, ArgNo);
// Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
+ llvm::Instruction *Call = DBuilder.insertDeclare(
+ Storage, D, DBuilder.createExpression(), Builder.GetInsertBlock());
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
}
return;
@@ -2817,14 +2883,13 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::dwarf::LLVMConstants Tag,
}
// Create the descriptor for the variable.
- llvm::DIVariable D =
- DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
- Name, Unit, Line, Ty,
- CGM.getLangOpts().Optimize, Flags, ArgNo);
+ llvm::DIVariable D = DBuilder.createLocalVariable(
+ Tag, llvm::DIDescriptor(Scope), Name, Unit, Line, Ty,
+ CGM.getLangOpts().Optimize, Flags, ArgNo);
// Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
+ llvm::Instruction *Call = DBuilder.insertDeclare(
+ Storage, D, DBuilder.createExpression(), Builder.GetInsertBlock());
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
}
@@ -2844,14 +2909,14 @@ void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
llvm::DIType CGDebugInfo::CreateSelfType(const QualType &QualTy,
llvm::DIType Ty) {
llvm::DIType CachedTy = getTypeOrNull(QualTy);
- if (CachedTy) Ty = CachedTy;
+ if (CachedTy)
+ Ty = CachedTy;
return DBuilder.createObjectPointerType(Ty);
}
-void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
- llvm::Value *Storage,
- CGBuilderTy &Builder,
- const CGBlockInfo &blockInfo) {
+void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
+ const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder,
+ const CGBlockInfo &blockInfo, llvm::Instruction *InsertPoint) {
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
@@ -2880,40 +2945,42 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
const llvm::DataLayout &target = CGM.getDataLayout();
CharUnits offset = CharUnits::fromQuantity(
- target.getStructLayout(blockInfo.StructureType)
+ target.getStructLayout(blockInfo.StructureType)
->getElementOffset(blockInfo.getCapture(VD).getIndex()));
- SmallVector<llvm::Value *, 9> addr;
- llvm::Type *Int64Ty = CGM.Int64Ty;
+ SmallVector<int64_t, 9> addr;
if (isa<llvm::AllocaInst>(Storage))
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
+ addr.push_back(llvm::dwarf::DW_OP_deref);
+ addr.push_back(llvm::dwarf::DW_OP_plus);
+ addr.push_back(offset.getQuantity());
if (isByRef) {
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
+ addr.push_back(llvm::dwarf::DW_OP_deref);
+ addr.push_back(llvm::dwarf::DW_OP_plus);
// offset of __forwarding field
- offset = CGM.getContext()
- .toCharUnitsFromBits(target.getPointerSizeInBits(0));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
+ offset =
+ CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits(0));
+ addr.push_back(offset.getQuantity());
+ addr.push_back(llvm::dwarf::DW_OP_deref);
+ addr.push_back(llvm::dwarf::DW_OP_plus);
// offset of x field
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
- addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
+ addr.push_back(offset.getQuantity());
}
// Create the descriptor for the variable.
llvm::DIVariable D =
- DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable,
+ DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_auto_variable,
llvm::DIDescriptor(LexicalBlockStack.back()),
- VD->getName(), Unit, Line, Ty, addr);
+ VD->getName(), Unit, Line, Ty);
// Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column,
- LexicalBlockStack.back()));
+ llvm::Instruction *Call = InsertPoint ?
+ DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr),
+ InsertPoint)
+ : DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr),
+ Builder.GetInsertBlock());
+ Call->setDebugLoc(
+ llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back()));
}
/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
@@ -2926,17 +2993,18 @@ void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
}
namespace {
- struct BlockLayoutChunk {
- uint64_t OffsetInBits;
- const BlockDecl::Capture *Capture;
- };
- bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
- return l.OffsetInBits < r.OffsetInBits;
- }
+struct BlockLayoutChunk {
+ uint64_t OffsetInBits;
+ const BlockDecl::Capture *Capture;
+};
+bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
+ return l.OffsetInBits < r.OffsetInBits;
+}
}
void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
llvm::Value *Arg,
+ unsigned ArgNo,
llvm::Value *LocalAddr,
CGBuilderTy &Builder) {
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
@@ -2953,9 +3021,9 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
getContextDescriptor(cast<Decl>(blockDecl->getDeclContext()));
const llvm::StructLayout *blockLayout =
- CGM.getDataLayout().getStructLayout(block.StructureType);
+ CGM.getDataLayout().getStructLayout(block.StructureType);
- SmallVector<llvm::Value*, 16> fields;
+ SmallVector<llvm::Metadata *, 16> fields;
fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public,
blockLayout->getElementOffsetInBits(0),
tunit, tunit));
@@ -2965,16 +3033,16 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
fields.push_back(createFieldType("__reserved", C.IntTy, 0, loc, AS_public,
blockLayout->getElementOffsetInBits(2),
tunit, tunit));
- fields.push_back(createFieldType("__FuncPtr", C.VoidPtrTy, 0, loc, AS_public,
+ auto *FnTy = block.getBlockExpr()->getFunctionType();
+ auto FnPtrType = CGM.getContext().getPointerType(FnTy->desugar());
+ fields.push_back(createFieldType("__FuncPtr", FnPtrType, 0, loc, AS_public,
blockLayout->getElementOffsetInBits(3),
tunit, tunit));
- fields.push_back(createFieldType("__descriptor",
- C.getPointerType(block.NeedsCopyDispose ?
- C.getBlockDescriptorExtendedType() :
- C.getBlockDescriptorType()),
- 0, loc, AS_public,
- blockLayout->getElementOffsetInBits(4),
- tunit, tunit));
+ fields.push_back(createFieldType(
+ "__descriptor", C.getPointerType(block.NeedsCopyDispose
+ ? C.getBlockDescriptorExtendedType()
+ : C.getBlockDescriptorType()),
+ 0, loc, AS_public, blockLayout->getElementOffsetInBits(4), tunit, tunit));
// We want to sort the captures by offset, not because DWARF
// requires this, but because we're paranoid about debuggers.
@@ -2984,7 +3052,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
if (blockDecl->capturesCXXThis()) {
BlockLayoutChunk chunk;
chunk.OffsetInBits =
- blockLayout->getElementOffsetInBits(block.CXXThisIndex);
+ blockLayout->getElementOffsetInBits(block.CXXThisIndex);
chunk.Capture = nullptr;
chunks.push_back(chunk);
}
@@ -3000,7 +3068,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
BlockLayoutChunk chunk;
chunk.OffsetInBits =
- blockLayout->getElementOffsetInBits(captureInfo.getIndex());
+ blockLayout->getElementOffsetInBits(captureInfo.getIndex());
chunk.Capture = &capture;
chunks.push_back(chunk);
}
@@ -3008,15 +3076,16 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
// Sort by offset.
llvm::array_pod_sort(chunks.begin(), chunks.end());
- for (SmallVectorImpl<BlockLayoutChunk>::iterator
- i = chunks.begin(), e = chunks.end(); i != e; ++i) {
+ for (SmallVectorImpl<BlockLayoutChunk>::iterator i = chunks.begin(),
+ e = chunks.end();
+ i != e; ++i) {
uint64_t offsetInBits = i->OffsetInBits;
const BlockDecl::Capture *capture = i->Capture;
// If we have a null capture, this must be the C++ 'this' capture.
if (!capture) {
const CXXMethodDecl *method =
- cast<CXXMethodDecl>(blockDecl->getNonClosureContext());
+ cast<CXXMethodDecl>(blockDecl->getNonClosureContext());
QualType type = method->getThisType(C);
fields.push_back(createFieldType("this", type, 0, loc, AS_public,
@@ -3029,33 +3098,33 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
llvm::DIType fieldType;
if (capture->isByRef()) {
- std::pair<uint64_t,unsigned> ptrInfo = C.getTypeInfo(C.VoidPtrTy);
+ TypeInfo PtrInfo = C.getTypeInfo(C.VoidPtrTy);
// FIXME: this creates a second copy of this type!
uint64_t xoffset;
fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset);
- fieldType = DBuilder.createPointerType(fieldType, ptrInfo.first);
- fieldType = DBuilder.createMemberType(tunit, name, tunit, line,
- ptrInfo.first, ptrInfo.second,
- offsetInBits, 0, fieldType);
+ fieldType = DBuilder.createPointerType(fieldType, PtrInfo.Width);
+ fieldType =
+ DBuilder.createMemberType(tunit, name, tunit, line, PtrInfo.Width,
+ PtrInfo.Align, offsetInBits, 0, fieldType);
} else {
- fieldType = createFieldType(name, variable->getType(), 0,
- loc, AS_public, offsetInBits, tunit, tunit);
+ fieldType = createFieldType(name, variable->getType(), 0, loc, AS_public,
+ offsetInBits, tunit, tunit);
}
fields.push_back(fieldType);
}
SmallString<36> typeName;
- llvm::raw_svector_ostream(typeName)
- << "__block_literal_" << CGM.getUniqueBlockCount();
+ llvm::raw_svector_ostream(typeName) << "__block_literal_"
+ << CGM.getUniqueBlockCount();
llvm::DIArray fieldsArray = DBuilder.getOrCreateArray(fields);
llvm::DIType type =
- DBuilder.createStructType(tunit, typeName.str(), tunit, line,
- CGM.getContext().toBits(block.BlockSize),
- CGM.getContext().toBits(block.BlockAlign),
- 0, llvm::DIType(), fieldsArray);
+ DBuilder.createStructType(tunit, typeName.str(), tunit, line,
+ CGM.getContext().toBits(block.BlockSize),
+ CGM.getContext().toBits(block.BlockAlign), 0,
+ llvm::DIType(), fieldsArray);
type = DBuilder.createPointerType(type, CGM.PointerWidthInBits);
// Get overall information about the block.
@@ -3063,24 +3132,22 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
llvm::MDNode *scope = LexicalBlockStack.back();
// Create the descriptor for the parameter.
- llvm::DIVariable debugVar =
- DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable,
- llvm::DIDescriptor(scope),
- Arg->getName(), tunit, line, type,
- CGM.getLangOpts().Optimize, flags,
- cast<llvm::Argument>(Arg)->getArgNo() + 1);
+ llvm::DIVariable debugVar = DBuilder.createLocalVariable(
+ llvm::dwarf::DW_TAG_arg_variable, llvm::DIDescriptor(scope),
+ Arg->getName(), tunit, line, type, CGM.getLangOpts().Optimize, flags,
+ ArgNo);
if (LocalAddr) {
// Insert an llvm.dbg.value into the current block.
- llvm::Instruction *DbgVal =
- DBuilder.insertDbgValueIntrinsic(LocalAddr, 0, debugVar,
- Builder.GetInsertBlock());
+ llvm::Instruction *DbgVal = DBuilder.insertDbgValueIntrinsic(
+ LocalAddr, 0, debugVar, DBuilder.createExpression(),
+ Builder.GetInsertBlock());
DbgVal->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
}
// Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *DbgDecl =
- DBuilder.insertDeclare(Arg, debugVar, Builder.GetInsertBlock());
+ llvm::Instruction *DbgDecl = DBuilder.insertDeclare(
+ Arg, debugVar, DBuilder.createExpression(), Builder.GetInsertBlock());
DbgDecl->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
}
@@ -3090,8 +3157,7 @@ llvm::DIDerivedType
CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {
if (!D->isStaticDataMember())
return llvm::DIDerivedType();
- llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator MI =
- StaticDataMemberCache.find(D->getCanonicalDecl());
+ auto MI = StaticDataMemberCache.find(D->getCanonicalDecl());
if (MI != StaticDataMemberCache.end()) {
assert(MI->second && "Static data member declaration should still exist");
return llvm::DIDerivedType(cast<llvm::MDNode>(MI->second));
@@ -3099,10 +3165,9 @@ CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {
// If the member wasn't found in the cache, lazily construct and add it to the
// type (used when a limited form of the type is emitted).
- llvm::DICompositeType Ctxt(
- getContextDescriptor(cast<Decl>(D->getDeclContext())));
- llvm::DIDerivedType T = CreateRecordStaticField(D, Ctxt);
- return T;
+ auto DC = D->getDeclContext();
+ llvm::DICompositeType Ctxt(getContextDescriptor(cast<Decl>(DC)));
+ return CreateRecordStaticField(D, Ctxt, cast<RecordDecl>(DC));
}
/// Recursively collect all of the member fields of a global anonymous decl and
@@ -3128,10 +3193,9 @@ CGDebugInfo::CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile Unit,
continue;
}
// Use VarDecl's Tag, Scope and Line number.
- GV = DBuilder.createStaticVariable(DContext, FieldName, LinkageName, Unit,
- LineNo, FieldTy,
- Var->hasInternalLinkage(), Var,
- llvm::DIDerivedType());
+ GV = DBuilder.createGlobalVariable(
+ DContext, FieldName, LinkageName, Unit, LineNo, FieldTy,
+ Var->hasInternalLinkage(), Var, llvm::DIDerivedType());
}
return GV;
}
@@ -3141,32 +3205,12 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *D) {
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
// Create global variable debug descriptor.
- llvm::DIFile Unit = getOrCreateFile(D->getLocation());
- unsigned LineNo = getLineNumber(D->getLocation());
-
- setLocation(D->getLocation());
-
- QualType T = D->getType();
- if (T->isIncompleteArrayType()) {
-
- // CodeGen turns int[] into int[1] so we'll do the same here.
- llvm::APInt ConstVal(32, 1);
- QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
-
- T = CGM.getContext().getConstantArrayType(ET, ConstVal,
- ArrayType::Normal, 0);
- }
-
- StringRef DeclName = D->getName();
- StringRef LinkageName;
- if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext()) &&
- !isa<ObjCMethodDecl>(D->getDeclContext()))
- LinkageName = Var->getName();
- if (LinkageName == DeclName)
- LinkageName = StringRef();
-
- llvm::DIDescriptor DContext =
- getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
+ llvm::DIFile Unit;
+ llvm::DIDescriptor DContext;
+ unsigned LineNo;
+ StringRef DeclName, LinkageName;
+ QualType T;
+ collectVarDeclProps(D, Unit, LineNo, T, DeclName, LinkageName, DContext);
// Attempt to store one global variable for the declaration - even if we
// emit a lot of fields.
@@ -3177,15 +3221,16 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
// to find the name of any field in the union.
if (T->isUnionType() && DeclName.empty()) {
const RecordDecl *RD = cast<RecordType>(T)->getDecl();
- assert(RD->isAnonymousStructOrUnion() && "unnamed non-anonymous struct or union?");
+ assert(RD->isAnonymousStructOrUnion() &&
+ "unnamed non-anonymous struct or union?");
GV = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext);
} else {
- GV = DBuilder.createStaticVariable(
+ GV = DBuilder.createGlobalVariable(
DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
Var->hasInternalLinkage(), Var,
getOrCreateStaticDataMemberDeclarationOrNull(D));
}
- DeclCache.insert(std::make_pair(D->getCanonicalDecl(), llvm::WeakVH(GV)));
+ DeclCache[D->getCanonicalDecl()].reset(static_cast<llvm::Metadata *>(GV));
}
/// EmitGlobalVariable - Emit global variable's debug info.
@@ -3208,16 +3253,25 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
if (isa<FunctionDecl>(VD->getDeclContext()))
return;
VD = cast<ValueDecl>(VD->getCanonicalDecl());
- auto pair = DeclCache.insert(std::make_pair(VD, llvm::WeakVH()));
- if (!pair.second)
+ auto *VarD = cast<VarDecl>(VD);
+ if (VarD->isStaticDataMember()) {
+ auto *RD = cast<RecordDecl>(VarD->getDeclContext());
+ getContextDescriptor(RD);
+ // Ensure that the type is retained even though it's otherwise unreferenced.
+ RetainedTypes.push_back(
+ CGM.getContext().getRecordType(RD).getAsOpaquePtr());
return;
+ }
+
llvm::DIDescriptor DContext =
getContextDescriptor(dyn_cast<Decl>(VD->getDeclContext()));
- llvm::DIGlobalVariable GV = DBuilder.createStaticVariable(
+
+ auto &GV = DeclCache[VD];
+ if (GV)
+ return;
+ GV.reset(DBuilder.createGlobalVariable(
DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty,
- true, Init,
- getOrCreateStaticDataMemberDeclarationOrNull(cast<VarDecl>(VD)));
- pair.first->second = llvm::WeakVH(GV);
+ true, Init, getOrCreateStaticDataMemberDeclarationOrNull(VarD)));
}
llvm::DIScope CGDebugInfo::getCurrentContextDescriptor(const Decl *D) {
@@ -3243,7 +3297,7 @@ void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
// Emitting one decl is sufficient - debuggers can detect that this is an
// overloaded name & provide lookup for all the overloads.
const UsingShadowDecl &USD = **UD.shadow_begin();
- if (llvm::DIScope Target =
+ if (llvm::DIDescriptor Target =
getDeclarationOrDefinition(USD.getUnderlyingDecl()))
DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(USD.getDeclContext())), Target,
@@ -3254,7 +3308,7 @@ llvm::DIImportedEntity
CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
if (CGM.getCodeGenOpts().getDebugInfo() < CodeGenOptions::LimitedDebugInfo)
return llvm::DIImportedEntity(nullptr);
- llvm::WeakVH &VH = NamespaceAliasCache[&NA];
+ auto &VH = NamespaceAliasCache[&NA];
if (VH)
return llvm::DIImportedEntity(cast<llvm::MDNode>(VH));
llvm::DIImportedEntity R(nullptr);
@@ -3270,7 +3324,7 @@ CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
getOrCreateNameSpace(cast<NamespaceDecl>(NA.getAliasedNamespace())),
getLineNumber(NA.getLocation()), NA.getName());
- VH = R;
+ VH.reset(R);
return R;
}
@@ -3279,8 +3333,7 @@ CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
llvm::DINameSpace
CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
NSDecl = NSDecl->getCanonicalDecl();
- llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH>::iterator I =
- NameSpaceCache.find(NSDecl);
+ auto I = NameSpaceCache.find(NSDecl);
if (I != NameSpaceCache.end())
return llvm::DINameSpace(cast<llvm::MDNode>(I->second));
@@ -3290,7 +3343,7 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()));
llvm::DINameSpace NS =
DBuilder.createNameSpace(Context, NSDecl->getName(), FileD, LineNo);
- NameSpaceCache[NSDecl] = llvm::WeakVH(NS);
+ NameSpaceCache[NSDecl].reset(NS);
return NS;
}
@@ -3318,6 +3371,24 @@ void CGDebugInfo::finalize() {
Ty.replaceAllUsesWith(CGM.getLLVMContext(), RepTy);
}
+ for (const auto &p : FwdDeclReplaceMap) {
+ assert(p.second);
+ llvm::DIDescriptor FwdDecl(cast<llvm::MDNode>(p.second));
+ llvm::Metadata *Repl;
+
+ auto it = DeclCache.find(p.first);
+ // If there has been no definition for the declaration, call RAUW
+ // with ourselves, that will destroy the temporary MDNode and
+ // replace it with a standard one, avoiding leaking memory.
+ if (it == DeclCache.end())
+ Repl = p.second;
+ else
+ Repl = it->second;
+
+ FwdDecl.replaceAllUsesWith(CGM.getLLVMContext(),
+ llvm::DIDescriptor(cast<llvm::MDNode>(Repl)));
+ }
+
// We keep our own list of retained types, because we need to look
// up the final type in the type cache.
for (std::vector<void *>::const_iterator RI = RetainedTypes.begin(),
@@ -3326,3 +3397,11 @@ void CGDebugInfo::finalize() {
DBuilder.finalize();
}
+
+void CGDebugInfo::EmitExplicitCastType(QualType Ty) {
+ if (CGM.getCodeGenOpts().getDebugInfo() < CodeGenOptions::LimitedDebugInfo)
+ return;
+ llvm::DIType DieTy = getOrCreateType(Ty, getOrCreateMainFile());
+ // Don't ignore in case of explicit cast where it is referenced indirectly.
+ DBuilder.retainType(DieTy);
+}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index fc3f434991fa..0be032c1d790 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CGDEBUGINFO_H
-#define CLANG_CODEGEN_CGDEBUGINFO_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGDEBUGINFO_H
+#define LLVM_CLANG_LIB_CODEGEN_CGDEBUGINFO_H
#include "CGBuilder.h"
#include "clang/AST/Expr.h"
@@ -53,7 +53,7 @@ class CGDebugInfo {
const CodeGenOptions::DebugInfoKind DebugKind;
llvm::DIBuilder DBuilder;
llvm::DICompileUnit TheCU;
- SourceLocation CurLoc, PrevLoc;
+ SourceLocation CurLoc;
llvm::DIType VTablePtrType;
llvm::DIType ClassTy;
llvm::DICompositeType ObjTy;
@@ -65,7 +65,7 @@ class CGDebugInfo {
llvm::DIType BlockLiteralGeneric;
/// TypeCache - Cache of previously constructed Types.
- llvm::DenseMap<const void *, llvm::WeakVH> TypeCache;
+ llvm::DenseMap<const void *, llvm::TrackingMDRef> TypeCache;
struct ObjCInterfaceCacheEntry {
const ObjCInterfaceType *Type;
@@ -85,11 +85,16 @@ class CGDebugInfo {
/// ReplaceMap - Cache of forward declared types to RAUW at the end of
/// compilation.
- std::vector<std::pair<const TagType *, llvm::WeakVH>> ReplaceMap;
+ std::vector<std::pair<const TagType *, llvm::TrackingMDRef>> ReplaceMap;
+
+ /// \brief Cache of replaceable forward declarartions (functions and
+ /// variables) to RAUW at the end of compilation.
+ std::vector<std::pair<const DeclaratorDecl *, llvm::TrackingMDRef>>
+ FwdDeclReplaceMap;
// LexicalBlockStack - Keep track of our current nested lexical block.
- std::vector<llvm::TrackingVH<llvm::MDNode> > LexicalBlockStack;
- llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap;
+ std::vector<llvm::TrackingMDNodeRef> LexicalBlockStack;
+ llvm::DenseMap<const Decl *, llvm::TrackingMDRef> RegionMap;
// FnBeginRegionCount - Keep track of LexicalBlockStack counter at the
// beginning of a function. This is used to pop unbalanced regions at
// the end of a function.
@@ -100,14 +105,15 @@ class CGDebugInfo {
llvm::BumpPtrAllocator DebugInfoNames;
StringRef CWDName;
- llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache;
- llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
+ llvm::DenseMap<const char *, llvm::TrackingMDRef> DIFileCache;
+ llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> SPCache;
/// \brief Cache declarations relevant to DW_TAG_imported_declarations (C++
/// using declarations) that aren't covered by other more specific caches.
- llvm::DenseMap<const Decl *, llvm::WeakVH> DeclCache;
- llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
- llvm::DenseMap<const NamespaceAliasDecl *, llvm::WeakVH> NamespaceAliasCache;
- llvm::DenseMap<const Decl *, llvm::WeakVH> StaticDataMemberCache;
+ llvm::DenseMap<const Decl *, llvm::TrackingMDRef> DeclCache;
+ llvm::DenseMap<const NamespaceDecl *, llvm::TrackingMDRef> NameSpaceCache;
+ llvm::DenseMap<const NamespaceAliasDecl *, llvm::TrackingMDRef>
+ NamespaceAliasCache;
+ llvm::DenseMap<const Decl *, llvm::TrackingMDRef> StaticDataMemberCache;
/// Helper functions for getOrCreateType.
unsigned Checksum(const ObjCInterfaceDecl *InterfaceDecl);
@@ -158,14 +164,12 @@ class CGDebugInfo {
llvm::DIFile F,
llvm::DIType RecordTy);
- void CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
- llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &E,
+ void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, llvm::DIFile F,
+ SmallVectorImpl<llvm::Metadata *> &E,
llvm::DIType T);
- void CollectCXXBases(const CXXRecordDecl *Decl,
- llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &EltTys,
+ void CollectCXXBases(const CXXRecordDecl *Decl, llvm::DIFile F,
+ SmallVectorImpl<llvm::Metadata *> &EltTys,
llvm::DIType RecordTy);
llvm::DIArray
@@ -180,27 +184,29 @@ class CGDebugInfo {
llvm::DIType createFieldType(StringRef name, QualType type,
uint64_t sizeInBitsOverride, SourceLocation loc,
- AccessSpecifier AS, uint64_t offsetInBits,
+ AccessSpecifier AS,
+ uint64_t offsetInBits,
llvm::DIFile tunit,
- llvm::DIScope scope);
+ llvm::DIScope scope,
+ const RecordDecl* RD = nullptr);
// Helpers for collecting fields of a record.
void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
- SmallVectorImpl<llvm::Value *> &E,
+ SmallVectorImpl<llvm::Metadata *> &E,
llvm::DIType RecordTy);
llvm::DIDerivedType CreateRecordStaticField(const VarDecl *Var,
- llvm::DIType RecordTy);
+ llvm::DIType RecordTy,
+ const RecordDecl* RD);
void CollectRecordNormalField(const FieldDecl *Field, uint64_t OffsetInBits,
llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &E,
- llvm::DIType RecordTy);
+ SmallVectorImpl<llvm::Metadata *> &E,
+ llvm::DIType RecordTy, const RecordDecl *RD);
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &E,
+ SmallVectorImpl<llvm::Metadata *> &E,
llvm::DICompositeType RecordTy);
- void CollectVTableInfo(const CXXRecordDecl *Decl,
- llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &EltTys);
+ void CollectVTableInfo(const CXXRecordDecl *Decl, llvm::DIFile F,
+ SmallVectorImpl<llvm::Metadata *> &EltTys);
// CreateLexicalBlock - Create a new lexical block node and push it on
// the stack.
@@ -255,7 +261,8 @@ public:
void EmitDeclareOfBlockDeclRefVariable(const VarDecl *variable,
llvm::Value *storage,
CGBuilderTy &Builder,
- const CGBlockInfo &blockInfo);
+ const CGBlockInfo &blockInfo,
+ llvm::Instruction *InsertPoint = 0);
/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
/// variable declaration.
@@ -266,7 +273,7 @@ public:
/// llvm.dbg.declare for the block-literal argument to a block
/// invocation function.
void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- llvm::Value *Arg,
+ llvm::Value *Arg, unsigned ArgNo,
llvm::Value *LocalAddr,
CGBuilderTy &Builder);
@@ -279,6 +286,9 @@ public:
/// \brief - Emit C++ using directive.
void EmitUsingDirective(const UsingDirectiveDecl &UD);
+ /// EmitExplicitCastType - Emit the type explicitly casted to.
+ void EmitExplicitCastType(QualType Ty);
+
/// \brief - Emit C++ using declaration.
void EmitUsingDecl(const UsingDecl &UD);
@@ -356,9 +366,9 @@ private:
llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
StringRef Name, uint64_t *Offset);
- /// \brief Retrieve the DIScope, if any, for the canonical form of this
+ /// \brief Retrieve the DIDescriptor, if any, for the canonical form of this
/// declaration.
- llvm::DIScope getDeclarationOrDefinition(const Decl *D);
+ llvm::DIDescriptor getDeclarationOrDefinition(const Decl *D);
/// getFunctionDeclaration - Return debug info descriptor to describe method
/// declaration for the given method definition.
@@ -369,6 +379,14 @@ private:
llvm::DIDerivedType
getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D);
+ /// \brief Create a DISubprogram describing the forward
+ /// decalration represented in the given FunctionDecl.
+ llvm::DISubprogram getFunctionForwardDeclaration(const FunctionDecl *FD);
+
+ /// \brief Create a DIGlobalVariable describing the forward
+ /// decalration represented in the given VarDecl.
+ llvm::DIGlobalVariable getGlobalVariableForwardDeclaration(const VarDecl *VD);
+
/// Return a global variable that represents one of the collection of
/// global variables created for an anonmyous union.
llvm::DIGlobalVariable
@@ -404,6 +422,21 @@ private:
/// \param Force Assume DebugColumnInfo option is true.
unsigned getColumnNumber(SourceLocation Loc, bool Force=false);
+ /// \brief Collect various properties of a FunctionDecl.
+ /// \param GD A GlobalDecl whose getDecl() must return a FunctionDecl.
+ void collectFunctionDeclProps(GlobalDecl GD,
+ llvm::DIFile Unit,
+ StringRef &Name, StringRef &LinkageName,
+ llvm::DIDescriptor &FDContext,
+ llvm::DIArray &TParamsArray,
+ unsigned &Flags);
+
+ /// \brief Collect various properties of a VarDecl.
+ void collectVarDeclProps(const VarDecl *VD, llvm::DIFile &Unit,
+ unsigned &LineNo, QualType &T,
+ StringRef &Name, StringRef &LinkageName,
+ llvm::DIDescriptor &VDContext);
+
/// internString - Allocate a copy of \p A using the DebugInfoNames allocator
/// and return a reference to it. If multiple arguments are given the strings
/// are concatenated.
@@ -415,27 +448,17 @@ private:
}
};
-/// SaveAndRestoreLocation - An RAII object saves the current location
-/// and automatically restores it to the original value.
-class SaveAndRestoreLocation {
+class ApplyDebugLocation {
protected:
- SourceLocation SavedLoc;
- CGDebugInfo *DI;
- CGBuilderTy &Builder;
-public:
- SaveAndRestoreLocation(CodeGenFunction &CGF, CGBuilderTy &B);
- /// Autorestore everything back to normal.
- ~SaveAndRestoreLocation();
-};
+ llvm::DebugLoc OriginalLocation;
+ CodeGenFunction &CGF;
-/// NoLocation - An RAII object that temporarily disables debug
-/// locations. This is useful for emitting instructions that should be
-/// counted towards the function prologue.
-class NoLocation : public SaveAndRestoreLocation {
public:
- NoLocation(CodeGenFunction &CGF, CGBuilderTy &B);
- /// Autorestore everything back to normal.
- ~NoLocation();
+ ApplyDebugLocation(CodeGenFunction &CGF,
+ SourceLocation TemporaryLocation = SourceLocation(),
+ bool ForceColumnInfo = false);
+ ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc);
+ ~ApplyDebugLocation();
};
/// ArtificialLocation - An RAII object that temporarily switches to
@@ -449,16 +472,9 @@ public:
/// This is necessary because passing an empty SourceLocation to
/// CGDebugInfo::setLocation() will result in the last valid location
/// being reused.
-class ArtificialLocation : public SaveAndRestoreLocation {
+class ArtificialLocation : public ApplyDebugLocation {
public:
- ArtificialLocation(CodeGenFunction &CGF, CGBuilderTy &B);
-
- /// Set the current location to line 0, but within the current scope
- /// (= the top of the LexicalBlockStack).
- void Emit();
-
- /// Autorestore everything back to normal.
- ~ArtificialLocation();
+ ArtificialLocation(CodeGenFunction &CGF);
};
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 91f804193049..766d2aa6ffb8 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -146,60 +146,71 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
return EmitAutoVarDecl(D);
}
-static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
- const char *Separator) {
- CodeGenModule &CGM = CGF.CGM;
-
- if (CGF.getLangOpts().CPlusPlus)
+static std::string getStaticDeclName(CodeGenModule &CGM, const VarDecl &D) {
+ if (CGM.getLangOpts().CPlusPlus)
return CGM.getMangledName(&D).str();
- StringRef ContextName;
- if (!CGF.CurFuncDecl) {
- // Better be in a block declared in global scope.
- const NamedDecl *ND = cast<NamedDecl>(&D);
- const DeclContext *DC = ND->getDeclContext();
- if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC))
- ContextName = CGM.getBlockMangledName(GlobalDecl(), BD);
- else
- llvm_unreachable("Unknown context for block static var decl");
- } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl))
+ // If this isn't C++, we don't need a mangled name, just a pretty one.
+ assert(!D.isExternallyVisible() && "name shouldn't matter");
+ std::string ContextName;
+ const DeclContext *DC = D.getDeclContext();
+ if (const auto *FD = dyn_cast<FunctionDecl>(DC))
ContextName = CGM.getMangledName(FD);
- else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
- ContextName = CGF.CurFn->getName();
+ else if (const auto *BD = dyn_cast<BlockDecl>(DC))
+ ContextName = CGM.getBlockMangledName(GlobalDecl(), BD);
+ else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(DC))
+ ContextName = OMD->getSelector().getAsString();
else
llvm_unreachable("Unknown context for static var decl");
- return ContextName.str() + Separator + D.getNameAsString();
+ ContextName += "." + D.getNameAsString();
+ return ContextName;
}
-llvm::Constant *
-CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
- const char *Separator,
- llvm::GlobalValue::LinkageTypes Linkage) {
+llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
+ const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage) {
+ // In general, we don't always emit static var decls once before we reference
+ // them. It is possible to reference them before emitting the function that
+ // contains them, and it is possible to emit the containing function multiple
+ // times.
+ if (llvm::Constant *ExistingGV = StaticLocalDeclMap[&D])
+ return ExistingGV;
+
QualType Ty = D.getType();
assert(Ty->isConstantSizeType() && "VLAs can't be static");
// Use the label if the variable is renamed with the asm-label extension.
std::string Name;
if (D.hasAttr<AsmLabelAttr>())
- Name = CGM.getMangledName(&D);
+ Name = getMangledName(&D);
else
- Name = GetStaticDeclName(*this, D, Separator);
+ Name = getStaticDeclName(*this, D);
- llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
+ llvm::Type *LTy = getTypes().ConvertTypeForMem(Ty);
unsigned AddrSpace =
- CGM.GetGlobalVarAddressSpace(&D, CGM.getContext().getTargetAddressSpace(Ty));
+ GetGlobalVarAddressSpace(&D, getContext().getTargetAddressSpace(Ty));
+
+ // Local address space cannot have an initializer.
+ llvm::Constant *Init = nullptr;
+ if (Ty.getAddressSpace() != LangAS::opencl_local)
+ Init = EmitNullConstant(Ty);
+ else
+ Init = llvm::UndefValue::get(LTy);
+
llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), LTy,
+ new llvm::GlobalVariable(getModule(), LTy,
Ty.isConstant(getContext()), Linkage,
- CGM.EmitNullConstant(D.getType()), Name, nullptr,
+ Init, Name, nullptr,
llvm::GlobalVariable::NotThreadLocal,
AddrSpace);
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
- CGM.setGlobalVisibility(GV, &D);
+ setGlobalVisibility(GV, &D);
+
+ if (supportsCOMDAT() && GV->isWeakForLinker())
+ GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
if (D.getTLSKind())
- CGM.setTLSMode(GV, D);
+ setTLSMode(GV, D);
if (D.isExternallyVisible()) {
if (D.hasAttr<DLLImportAttr>())
@@ -209,13 +220,44 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
}
// Make sure the result is of the correct type.
- unsigned ExpectedAddrSpace = CGM.getContext().getTargetAddressSpace(Ty);
+ unsigned ExpectedAddrSpace = getContext().getTargetAddressSpace(Ty);
+ llvm::Constant *Addr = GV;
if (AddrSpace != ExpectedAddrSpace) {
llvm::PointerType *PTy = llvm::PointerType::get(LTy, ExpectedAddrSpace);
- return llvm::ConstantExpr::getAddrSpaceCast(GV, PTy);
+ Addr = llvm::ConstantExpr::getAddrSpaceCast(GV, PTy);
}
- return GV;
+ setStaticLocalDeclAddress(&D, Addr);
+
+ // Ensure that the static local gets initialized by making sure the parent
+ // function gets emitted eventually.
+ const Decl *DC = cast<Decl>(D.getDeclContext());
+
+ // We can't name blocks or captured statements directly, so try to emit their
+ // parents.
+ if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC)) {
+ DC = DC->getNonClosureContext();
+ // FIXME: Ensure that global blocks get emitted.
+ if (!DC)
+ return Addr;
+ }
+
+ GlobalDecl GD;
+ if (const auto *CD = dyn_cast<CXXConstructorDecl>(DC))
+ GD = GlobalDecl(CD, Ctor_Base);
+ else if (const auto *DD = dyn_cast<CXXDestructorDecl>(DC))
+ GD = GlobalDecl(DD, Dtor_Base);
+ else if (const auto *FD = dyn_cast<FunctionDecl>(DC))
+ GD = GlobalDecl(FD);
+ else {
+ // Don't do anything for Obj-C method decls or global closures. We should
+ // never defer them.
+ assert(isa<ObjCMethodDecl>(DC) && "unexpected parent code decl");
+ }
+ if (GD.getDecl())
+ (void)GetAddrOfGlobal(GD);
+
+ return Addr;
}
/// hasNontrivialDestruction - Determine whether a type's destruction is
@@ -298,16 +340,11 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
// Check to see if we already have a global variable for this
// declaration. This can happen when double-emitting function
// bodies, e.g. with complete and base constructors.
- llvm::Constant *addr =
- CGM.getStaticLocalDeclAddress(&D);
-
- if (!addr)
- addr = CreateStaticVarDecl(D, ".", Linkage);
+ llvm::Constant *addr = CGM.getOrCreateStaticVarDecl(D, Linkage);
// Store into LocalDeclMap before generating initializer to handle
// circular references.
DMEntry = addr;
- CGM.setStaticLocalDeclAddress(&D, addr);
// We can't have a VLA here, but we can have a pointer to a VLA,
// even though that doesn't really make any sense.
@@ -345,7 +382,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
DMEntry = castedAddr;
CGM.setStaticLocalDeclAddress(&D, castedAddr);
- CGM.reportGlobalToASan(var, D);
+ CGM.getSanitizerMetadata()->reportGlobalToASan(var, D);
// Emit global variable debug descriptor for static vars.
CGDebugInfo *DI = getDebugInfo();
@@ -562,10 +599,8 @@ static void drillIntoBlockVariable(CodeGenFunction &CGF,
lvalue.setAddress(CGF.BuildBlockByrefAddress(lvalue.getAddress(), var));
}
-void CodeGenFunction::EmitScalarInit(const Expr *init,
- const ValueDecl *D,
- LValue lvalue,
- bool capturedByInit) {
+void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
+ LValue lvalue, bool capturedByInit) {
Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime();
if (!lifetime) {
llvm::Value *value = EmitScalarExpr(init);
@@ -1035,7 +1070,7 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) {
/// \brief Determine whether the given initializer is trivial in the sense
/// that it requires no code to be generated.
-static bool isTrivialInitializer(const Expr *Init) {
+bool CodeGenFunction::isTrivialInitializer(const Expr *Init) {
if (!Init)
return true;
@@ -1055,6 +1090,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
if (emission.wasEmittedAsGlobal()) return;
const VarDecl &D = *emission.Variable;
+ ApplyDebugLocation DL(*this, D.getLocation());
QualType type = D.getType();
// If this local has an initializer, emit it now.
@@ -1129,7 +1165,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
} else {
// Otherwise, create a temporary global with the initializer then
// memcpy from the global to the alloca.
- std::string Name = GetStaticDeclName(*this, D, ".");
+ std::string Name = getStaticDeclName(CGM, D);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), constant->getType(), true,
llvm::GlobalValue::PrivateLinkage,
@@ -1158,10 +1194,8 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
/// \param alignment the alignment of the address
/// \param capturedByInit true if the variable is a __block variable
/// whose address is potentially changed by the initializer
-void CodeGenFunction::EmitExprAsInit(const Expr *init,
- const ValueDecl *D,
- LValue lvalue,
- bool capturedByInit) {
+void CodeGenFunction::EmitExprAsInit(const Expr *init, const ValueDecl *D,
+ LValue lvalue, bool capturedByInit) {
QualType type = D->getType();
if (type->isReferenceType()) {
@@ -1636,7 +1670,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
if (CGM.getCodeGenOpts().getDebugInfo()
>= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
- DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, LocalAddr, Builder);
+ DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, ArgNo,
+ LocalAddr, Builder);
}
}
@@ -1656,7 +1691,9 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
DeclPtr = Arg->getType() == IRTy ? Arg : Builder.CreateBitCast(Arg, IRTy,
D.getName());
// Push a destructor cleanup for this parameter if the ABI requires it.
- if (!IsScalar &&
+ // Don't push a cleanup in a thunk for a method that will also emit a
+ // cleanup.
+ if (!IsScalar && !CurFuncIsThunk &&
getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
if (RD && RD->hasNonTrivialDestructor())
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 94cfe211601f..3b379b7d258b 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -14,6 +14,7 @@
#include "CodeGenFunction.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
+#include "CGOpenMPRuntime.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Intrinsics.h"
@@ -96,7 +97,7 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
assert(!record->hasTrivialDestructor());
CXXDestructorDecl *dtor = record->getDestructor();
- function = CGM.GetAddrOfCXXDestructor(dtor, Dtor_Complete);
+ function = CGM.getAddrOfCXXStructor(dtor, StructorType::Complete);
argument = llvm::ConstantExpr::getBitCast(
addr, CGF.getTypes().ConvertType(type)->getPointerTo());
@@ -139,6 +140,10 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
QualType T = D.getType();
if (!T->isReferenceType()) {
+ if (getLangOpts().OpenMP && D.hasAttr<OMPThreadPrivateDeclAttr>())
+ (void)CGM.getOpenMPRuntime().EmitOMPThreadPrivateVarDefinition(
+ &D, DeclPtr, D.getAttr<OMPThreadPrivateDeclAttr>()->getLocation(),
+ PerformInit, this);
if (PerformInit)
EmitDeclInit(*this, D, DeclPtr);
if (CGM.isTypeConstant(D.getType(), true))
@@ -155,17 +160,11 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T);
}
-static llvm::Function *
-CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
- llvm::FunctionType *ty,
- const Twine &name,
- bool TLS = false);
-
/// Create a stub function, suitable for being passed to atexit,
/// which passes the given address to the given destructor function.
-static llvm::Constant *createAtExitStub(CodeGenModule &CGM, const VarDecl &VD,
- llvm::Constant *dtor,
- llvm::Constant *addr) {
+llvm::Constant *CodeGenFunction::createAtExitStub(const VarDecl &VD,
+ llvm::Constant *dtor,
+ llvm::Constant *addr) {
// Get the destructor function type, void(*)(void).
llvm::FunctionType *ty = llvm::FunctionType::get(CGM.VoidTy, false);
SmallString<256> FnName;
@@ -173,8 +172,8 @@ static llvm::Constant *createAtExitStub(CodeGenModule &CGM, const VarDecl &VD,
llvm::raw_svector_ostream Out(FnName);
CGM.getCXXABI().getMangleContext().mangleDynamicAtExitDestructor(&VD, Out);
}
- llvm::Function *fn =
- CreateGlobalInitOrDestructFunction(CGM, ty, FnName.str());
+ llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(ty, FnName.str(),
+ VD.getLocation());
CodeGenFunction CGF(CGM);
@@ -198,7 +197,7 @@ void CodeGenFunction::registerGlobalDtorWithAtExit(const VarDecl &VD,
llvm::Constant *dtor,
llvm::Constant *addr) {
// Create a function which calls the destructor.
- llvm::Constant *dtorStub = createAtExitStub(CGM, VD, dtor, addr);
+ llvm::Constant *dtorStub = createAtExitStub(VD, dtor, addr);
// extern "C" int atexit(void (*f)(void));
llvm::FunctionType *atexitTy =
@@ -226,31 +225,28 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
}
-static llvm::Function *
-CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
- llvm::FunctionType *FTy,
- const Twine &Name, bool TLS) {
+llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
+ llvm::FunctionType *FTy, const Twine &Name, SourceLocation Loc, bool TLS) {
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
- Name, &CGM.getModule());
- if (!CGM.getLangOpts().AppleKext && !TLS) {
+ Name, &getModule());
+ if (!getLangOpts().AppleKext && !TLS) {
// Set the section if needed.
- if (const char *Section =
- CGM.getTarget().getStaticInitSectionSpecifier())
+ if (const char *Section = getTarget().getStaticInitSectionSpecifier())
Fn->setSection(Section);
}
- Fn->setCallingConv(CGM.getRuntimeCC());
+ Fn->setCallingConv(getRuntimeCC());
- if (!CGM.getLangOpts().Exceptions)
+ if (!getLangOpts().Exceptions)
Fn->setDoesNotThrow();
- if (!CGM.getSanitizerBlacklist().isIn(*Fn)) {
- if (CGM.getLangOpts().Sanitize.Address)
+ if (!isInSanitizerBlacklist(Fn, Loc)) {
+ if (getLangOpts().Sanitize.has(SanitizerKind::Address))
Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
- if (CGM.getLangOpts().Sanitize.Thread)
+ if (getLangOpts().Sanitize.has(SanitizerKind::Thread))
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
- if (CGM.getLangOpts().Sanitize.Memory)
+ if (getLangOpts().Sanitize.has(SanitizerKind::Memory))
Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
}
@@ -271,15 +267,7 @@ void CodeGenModule::EmitPointerToInitFunc(const VarDecl *D,
addUsedGlobal(PtrArray);
// If the GV is already in a comdat group, then we have to join it.
- llvm::Comdat *C = GV->getComdat();
-
- // LinkOnce and Weak linkage are lowered down to a single-member comdat group.
- // Make an explicit group so we can join it.
- if (!C && (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage())) {
- C = TheModule.getOrInsertComdat(GV->getName());
- GV->setComdat(C);
- }
- if (C)
+ if (llvm::Comdat *C = GV->getComdat())
PtrArray->setComdat(C);
}
@@ -296,11 +284,15 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
// Create a variable initialization function.
llvm::Function *Fn =
- CreateGlobalInitOrDestructFunction(*this, FTy, FnName.str());
+ CreateGlobalInitOrDestructFunction(FTy, FnName.str(), D->getLocation());
auto *ISA = D->getAttr<InitSegAttr>();
CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
PerformInit);
+
+ llvm::GlobalVariable *COMDATKey =
+ supportsCOMDAT() && D->isExternallyVisible() ? Addr : nullptr;
+
if (D->getTLSKind()) {
// FIXME: Should we support init_priority for thread_local?
// FIXME: Ideally, initialization of instantiated thread_local static data
@@ -309,6 +301,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
// FIXME: We only need to register one __cxa_thread_atexit function for the
// entire TU.
CXXThreadLocalInits.push_back(Fn);
+ CXXThreadLocalInitVars.push_back(Addr);
} else if (PerformInit && ISA) {
EmitPointerToInitFunc(D, Addr, Fn, ISA);
DelayedCXXInitPosition.erase(D);
@@ -316,8 +309,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
OrderGlobalInits Key(IPA->getPriority(), PrioritizedCXXGlobalInits.size());
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
DelayedCXXInitPosition.erase(D);
- } else if (D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization &&
- D->getTemplateSpecializationKind() != TSK_Undeclared) {
+ } else if (isTemplateInstantiation(D->getTemplateSpecializationKind())) {
// C++ [basic.start.init]p2:
// Definitions of explicitly specialized class template static data
// members have ordered initialization. Other class template static data
@@ -326,11 +318,17 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
//
// As a consequence, we can put them into their own llvm.global_ctors entry.
//
- // In addition, put the initializer into a COMDAT group with the global
- // being initialized. On most platforms, this is a minor startup time
- // optimization. In the MS C++ ABI, there are no guard variables, so this
- // COMDAT key is required for correctness.
- AddGlobalCtor(Fn, 65535, Addr);
+ // If the global is externally visible, put the initializer into a COMDAT
+ // group with the global being initialized. On most platforms, this is a
+ // minor startup time optimization. In the MS C++ ABI, there are no guard
+ // variables, so this COMDAT key is required for correctness.
+ AddGlobalCtor(Fn, 65535, COMDATKey);
+ DelayedCXXInitPosition.erase(D);
+ } else if (D->hasAttr<SelectAnyAttr>()) {
+ // SelectAny globals will be comdat-folded. Put the initializer into a
+ // COMDAT group associated with the global, so the initializers get folded
+ // too.
+ AddGlobalCtor(Fn, 65535, COMDATKey);
DelayedCXXInitPosition.erase(D);
} else {
llvm::DenseMap<const Decl *, unsigned>::iterator I =
@@ -346,23 +344,11 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
}
void CodeGenModule::EmitCXXThreadLocalInitFunc() {
- llvm::Function *InitFn = nullptr;
- if (!CXXThreadLocalInits.empty()) {
- // Generate a guarded initialization function.
- llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
- InitFn = CreateGlobalInitOrDestructFunction(*this, FTy, "__tls_init",
- /*TLS*/ true);
- llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
- getModule(), Int8Ty, false, llvm::GlobalVariable::InternalLinkage,
- llvm::ConstantInt::get(Int8Ty, 0), "__tls_guard");
- Guard->setThreadLocal(true);
- CodeGenFunction(*this)
- .GenerateCXXGlobalInitFunc(InitFn, CXXThreadLocalInits, Guard);
- }
-
- getCXXABI().EmitThreadLocalInitFuncs(CXXThreadLocals, InitFn);
+ getCXXABI().EmitThreadLocalInitFuncs(
+ *this, CXXThreadLocals, CXXThreadLocalInits, CXXThreadLocalInitVars);
CXXThreadLocalInits.clear();
+ CXXThreadLocalInitVars.clear();
CXXThreadLocals.clear();
}
@@ -379,7 +365,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
// Create our global initialization function.
if (!PrioritizedCXXGlobalInits.empty()) {
- SmallVector<llvm::Constant*, 8> LocalCXXGlobalInits;
+ SmallVector<llvm::Function *, 8> LocalCXXGlobalInits;
llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
PrioritizedCXXGlobalInits.end());
// Iterate over "chunks" of ctors with same priority and emit each chunk
@@ -398,10 +384,9 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
std::string PrioritySuffix = llvm::utostr(Priority);
// Priority is always <= 65535 (enforced by sema).
PrioritySuffix = std::string(6-PrioritySuffix.size(), '0')+PrioritySuffix;
- llvm::Function *Fn =
- CreateGlobalInitOrDestructFunction(*this, FTy,
- "_GLOBAL__I_" + PrioritySuffix);
-
+ llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
+ FTy, "_GLOBAL__I_" + PrioritySuffix);
+
for (; I < PrioE; ++I)
LocalCXXGlobalInits.push_back(I->second);
@@ -409,21 +394,27 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
AddGlobalCtor(Fn, Priority);
}
}
-
- // Include the filename in the symbol name. Including "sub_" matches gcc and
- // makes sure these symbols appear lexicographically behind the symbols with
- // priority emitted above.
+
+ SmallString<128> FileName;
SourceManager &SM = Context.getSourceManager();
- SmallString<128> FileName(llvm::sys::path::filename(
- SM.getFileEntryForID(SM.getMainFileID())->getName()));
+ if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
+ // Include the filename in the symbol name. Including "sub_" matches gcc and
+ // makes sure these symbols appear lexicographically behind the symbols with
+ // priority emitted above.
+ FileName = llvm::sys::path::filename(MainFile->getName());
+ } else {
+ FileName = SmallString<128>("<null>");
+ }
+
for (size_t i = 0; i < FileName.size(); ++i) {
// Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
// to be the set of C preprocessing numbers.
if (!isPreprocessingNumberBody(FileName[i]))
FileName[i] = '_';
}
+
llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
- *this, FTy, llvm::Twine("_GLOBAL__sub_I_", FileName));
+ FTy, llvm::Twine("_GLOBAL__sub_I_", FileName));
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits);
AddGlobalCtor(Fn);
@@ -439,8 +430,7 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
// Create our global destructor function.
- llvm::Function *Fn =
- CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__D_a");
+ llvm::Function *Fn = CreateGlobalInitOrDestructFunction(FTy, "_GLOBAL__D_a");
CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, CXXGlobalDtors);
AddGlobalDtor(Fn);
@@ -455,6 +445,8 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
if (D->hasAttr<NoDebugAttr>())
DebugInfo = nullptr; // disable debug info indefinitely for this function
+ CurEHLocation = D->getLocStart();
+
StartFunction(GlobalDecl(D), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
FunctionArgList(), D->getLocation(),
@@ -474,14 +466,14 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
void
CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
- ArrayRef<llvm::Constant *> Decls,
+ ArrayRef<llvm::Function *> Decls,
llvm::GlobalVariable *Guard) {
{
- ArtificialLocation AL(*this, Builder);
+ ApplyDebugLocation NL(*this);
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(), FunctionArgList());
// Emit an artificial location for this function.
- AL.Emit();
+ ArtificialLocation AL(*this);
llvm::BasicBlock *ExitBlock = nullptr;
if (Guard) {
@@ -528,11 +520,11 @@ void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
&DtorsAndObjects) {
{
- ArtificialLocation AL(*this, Builder);
+ ApplyDebugLocation NL(*this);
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(), FunctionArgList());
// Emit an artificial location for this function.
- AL.Emit();
+ ArtificialLocation AL(*this);
// Emit the dtors, in reverse order from construction.
for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
@@ -561,8 +553,10 @@ llvm::Function *CodeGenFunction::generateDestroyHelper(
const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
getContext().VoidTy, args, FunctionType::ExtInfo(), /*variadic=*/false);
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
- llvm::Function *fn =
- CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
+ llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(
+ FTy, "__cxx_global_array_dtor", VD->getLocation());
+
+ CurEHLocation = VD->getLocStart();
StartFunction(VD, getContext().VoidTy, fn, FI, args);
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 1bbda5cbf09c..cb8eb8fa490c 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
+#include "CGCXXABI.h"
#include "CGCleanup.h"
#include "CGObjCRuntime.h"
#include "TargetInfo.h"
@@ -52,15 +53,6 @@ static llvm::Constant *getThrowFn(CodeGenModule &CGM) {
return CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
}
-static llvm::Constant *getReThrowFn(CodeGenModule &CGM) {
- // void __cxa_rethrow();
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
-
- return CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
-}
-
static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) {
// void *__cxa_get_exception_ptr(void*);
@@ -134,15 +126,17 @@ namespace {
// This function must have prototype void(void*).
const char *CatchallRethrowFn;
- static const EHPersonality &get(const LangOptions &Lang);
+ static const EHPersonality &get(CodeGenModule &CGM);
static const EHPersonality GNU_C;
static const EHPersonality GNU_C_SJLJ;
+ static const EHPersonality GNU_C_SEH;
static const EHPersonality GNU_ObjC;
static const EHPersonality GNUstep_ObjC;
static const EHPersonality GNU_ObjCXX;
static const EHPersonality NeXT_ObjC;
static const EHPersonality GNU_CPlusPlus;
static const EHPersonality GNU_CPlusPlus_SJLJ;
+ static const EHPersonality GNU_CPlusPlus_SEH;
};
}
@@ -150,28 +144,42 @@ const EHPersonality EHPersonality::GNU_C = { "__gcc_personality_v0", nullptr };
const EHPersonality
EHPersonality::GNU_C_SJLJ = { "__gcc_personality_sj0", nullptr };
const EHPersonality
+EHPersonality::GNU_C_SEH = { "__gcc_personality_seh0", nullptr };
+const EHPersonality
EHPersonality::NeXT_ObjC = { "__objc_personality_v0", nullptr };
const EHPersonality
EHPersonality::GNU_CPlusPlus = { "__gxx_personality_v0", nullptr };
const EHPersonality
EHPersonality::GNU_CPlusPlus_SJLJ = { "__gxx_personality_sj0", nullptr };
const EHPersonality
+EHPersonality::GNU_CPlusPlus_SEH = { "__gxx_personality_seh0", nullptr };
+const EHPersonality
EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"};
const EHPersonality
EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr };
const EHPersonality
EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr };
-static const EHPersonality &getCPersonality(const LangOptions &L) {
+/// On Win64, use libgcc's SEH personality function. We fall back to dwarf on
+/// other platforms, unless the user asked for SjLj exceptions.
+static bool useLibGCCSEHPersonality(const llvm::Triple &T) {
+ return T.isOSWindows() && T.getArch() == llvm::Triple::x86_64;
+}
+
+static const EHPersonality &getCPersonality(const llvm::Triple &T,
+ const LangOptions &L) {
if (L.SjLjExceptions)
return EHPersonality::GNU_C_SJLJ;
+ else if (useLibGCCSEHPersonality(T))
+ return EHPersonality::GNU_C_SEH;
return EHPersonality::GNU_C;
}
-static const EHPersonality &getObjCPersonality(const LangOptions &L) {
+static const EHPersonality &getObjCPersonality(const llvm::Triple &T,
+ const LangOptions &L) {
switch (L.ObjCRuntime.getKind()) {
case ObjCRuntime::FragileMacOSX:
- return getCPersonality(L);
+ return getCPersonality(T, L);
case ObjCRuntime::MacOSX:
case ObjCRuntime::iOS:
return EHPersonality::NeXT_ObjC;
@@ -186,16 +194,19 @@ static const EHPersonality &getObjCPersonality(const LangOptions &L) {
llvm_unreachable("bad runtime kind");
}
-static const EHPersonality &getCXXPersonality(const LangOptions &L) {
+static const EHPersonality &getCXXPersonality(const llvm::Triple &T,
+ const LangOptions &L) {
if (L.SjLjExceptions)
return EHPersonality::GNU_CPlusPlus_SJLJ;
- else
- return EHPersonality::GNU_CPlusPlus;
+ else if (useLibGCCSEHPersonality(T))
+ return EHPersonality::GNU_CPlusPlus_SEH;
+ return EHPersonality::GNU_CPlusPlus;
}
/// Determines the personality function to use when both C++
/// and Objective-C exceptions are being caught.
-static const EHPersonality &getObjCXXPersonality(const LangOptions &L) {
+static const EHPersonality &getObjCXXPersonality(const llvm::Triple &T,
+ const LangOptions &L) {
switch (L.ObjCRuntime.getKind()) {
// The ObjC personality defers to the C++ personality for non-ObjC
// handlers. Unlike the C++ case, we use the same personality
@@ -207,7 +218,7 @@ static const EHPersonality &getObjCXXPersonality(const LangOptions &L) {
// In the fragile ABI, just use C++ exception handling and hope
// they're not doing crazy exception mixing.
case ObjCRuntime::FragileMacOSX:
- return getCXXPersonality(L);
+ return getCXXPersonality(T, L);
// The GCC runtime's personality function inherently doesn't support
// mixed EH. Use the C++ personality just to avoid returning null.
@@ -220,15 +231,17 @@ static const EHPersonality &getObjCXXPersonality(const LangOptions &L) {
llvm_unreachable("bad runtime kind");
}
-const EHPersonality &EHPersonality::get(const LangOptions &L) {
+const EHPersonality &EHPersonality::get(CodeGenModule &CGM) {
+ const llvm::Triple &T = CGM.getTarget().getTriple();
+ const LangOptions &L = CGM.getLangOpts();
if (L.CPlusPlus && L.ObjC1)
- return getObjCXXPersonality(L);
+ return getObjCXXPersonality(T, L);
else if (L.CPlusPlus)
- return getCXXPersonality(L);
+ return getCXXPersonality(T, L);
else if (L.ObjC1)
- return getObjCPersonality(L);
+ return getObjCPersonality(T, L);
else
- return getCPersonality(L);
+ return getCPersonality(T, L);
}
static llvm::Constant *getPersonalityFn(CodeGenModule &CGM,
@@ -305,8 +318,9 @@ void CodeGenModule::SimplifyPersonality() {
if (!LangOpts.ObjCRuntime.isNeXTFamily())
return;
- const EHPersonality &ObjCXX = EHPersonality::get(LangOpts);
- const EHPersonality &CXX = getCXXPersonality(LangOpts);
+ const EHPersonality &ObjCXX = EHPersonality::get(*this);
+ const EHPersonality &CXX =
+ getCXXPersonality(getTarget().getTriple(), LangOpts);
if (&ObjCXX == &CXX)
return;
@@ -403,14 +417,8 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() {
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
bool KeepInsertionPoint) {
- if (CGM.getTarget().getTriple().isWindowsMSVCEnvironment()) {
- ErrorUnsupported(E, "throw expression");
- return;
- }
-
if (!E->getSubExpr()) {
- EmitNoreturnRuntimeCallOrInvoke(getReThrowFn(CGM),
- ArrayRef<llvm::Value*>());
+ CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/true);
// throw is an expression, and the expression emitters expect us
// to leave ourselves at a valid insertion point.
@@ -420,6 +428,11 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
return;
}
+ if (CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment()) {
+ ErrorUnsupported(E, "throw expression");
+ return;
+ }
+
QualType ThrowType = E->getSubExpr()->getType();
if (ThrowType->isObjCObjectPointerType()) {
@@ -457,7 +470,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
if (!Record->hasTrivialDestructor()) {
CXXDestructorDecl *DtorD = Record->getDestructor();
- Dtor = CGM.GetAddrOfCXXDestructor(DtorD, Dtor_Complete);
+ Dtor = CGM.getAddrOfCXXStructor(DtorD, StructorType::Complete);
Dtor = llvm::ConstantExpr::getBitCast(Dtor, Int8PtrTy);
}
}
@@ -576,7 +589,7 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
}
void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
- if (CGM.getTarget().getTriple().isWindowsMSVCEnvironment()) {
+ if (CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment()) {
ErrorUnsupported(&S, "try statement");
return;
}
@@ -601,8 +614,9 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
// existing compilers do, and it's not clear that the standard
// personality routine is capable of doing this right. See C++ DR 388:
// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
- QualType CaughtType = C->getCaughtType();
- CaughtType = CaughtType.getNonReferenceType().getUnqualifiedType();
+ Qualifiers CaughtTypeQuals;
+ QualType CaughtType = CGM.getContext().getUnqualifiedArrayType(
+ C->getCaughtType().getNonReferenceType(), CaughtTypeQuals);
llvm::Constant *TypeInfo = nullptr;
if (CaughtType->isObjCObjectPointerType())
@@ -720,18 +734,16 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Save the current IR generation state.
CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP();
- SaveAndRestoreLocation AutoRestoreLocation(*this, Builder);
- if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitLocation(Builder, CurEHLocation);
+ ApplyDebugLocation AutoRestoreLocation(*this, CurEHLocation);
- const EHPersonality &personality = EHPersonality::get(getLangOpts());
+ const EHPersonality &personality = EHPersonality::get(CGM);
// Create and configure the landing pad.
llvm::BasicBlock *lpad = createBasicBlock("lpad");
EmitBlock(lpad);
llvm::LandingPadInst *LPadInst =
- Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, NULL),
+ Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, nullptr),
getOpaquePersonalityFn(CGM, personality), 0);
llvm::Value *LPadExn = Builder.CreateExtractValue(LPadInst, 0);
@@ -795,7 +807,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
}
// Check whether we already have a handler for this type.
- if (catchTypes.insert(handler.Type))
+ if (catchTypes.insert(handler.Type).second)
// If not, add it directly to the landingpad.
LPadInst->addClause(handler.Type);
}
@@ -1259,7 +1271,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
// constructor function-try-block's catch handler (p14), so this
// really only applies to destructors.
if (doImplicitRethrow && HaveInsertPoint()) {
- EmitRuntimeCallOrInvoke(getReThrowFn(CGM));
+ CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/false);
Builder.CreateUnreachable();
Builder.ClearInsertionPoint();
}
@@ -1541,9 +1553,9 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
Builder.SetInsertPoint(TerminateLandingPad);
// Tell the backend that this is a landing pad.
- const EHPersonality &Personality = EHPersonality::get(CGM.getLangOpts());
+ const EHPersonality &Personality = EHPersonality::get(CGM);
llvm::LandingPadInst *LPadInst =
- Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, NULL),
+ Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, nullptr),
getOpaquePersonalityFn(CGM, Personality), 0);
LPadInst->addClause(getCatchAllValue(*this));
@@ -1600,7 +1612,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
EHResumeBlock = createBasicBlock("eh.resume");
Builder.SetInsertPoint(EHResumeBlock);
- const EHPersonality &Personality = EHPersonality::get(CGM.getLangOpts());
+ const EHPersonality &Personality = EHPersonality::get(CGM);
// This can always be a call because we necessarily didn't find
// anything on the EH stack which needs our help.
@@ -1619,7 +1631,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
llvm::Value *Sel = getSelectorFromSlot();
llvm::Type *LPadType = llvm::StructType::get(Exn->getType(),
- Sel->getType(), NULL);
+ Sel->getType(), nullptr);
llvm::Value *LPadVal = llvm::UndefValue::get(LPadType);
LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val");
LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val");
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 512b323ba109..ce7679c836e4 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -16,14 +16,16 @@
#include "CGCall.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
+#include "CGOpenMPRuntime.h"
#include "CGRecordLayout.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/Attr.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
@@ -209,7 +211,6 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
case SD_Automatic:
case SD_FullExpression:
- assert(!ObjCARCReferenceLifetimeType->isArrayType());
CodeGenFunction::Destroyer *Destroy;
CleanupKind CleanupKind;
if (Lifetime == Qualifiers::OCL_Strong) {
@@ -267,8 +268,8 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
dyn_cast_or_null<VarDecl>(M->getExtendingDecl()));
CleanupArg = llvm::Constant::getNullValue(CGF.Int8PtrTy);
} else {
- CleanupFn =
- CGF.CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
+ CleanupFn = CGF.CGM.getAddrOfCXXStructor(ReferenceTemporaryDtor,
+ StructorType::Complete);
CleanupArg = cast<llvm::Constant>(ReferenceTemporary);
}
CGF.CGM.getCXXABI().registerGlobalDtor(
@@ -312,15 +313,16 @@ createReferenceTemporary(CodeGenFunction &CGF,
llvm_unreachable("unknown storage duration");
}
-LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
- const MaterializeTemporaryExpr *M) {
+LValue CodeGenFunction::
+EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
const Expr *E = M->GetTemporaryExpr();
+ // FIXME: ideally this would use EmitAnyExprToMem, however, we cannot do so
+ // as that will cause the lifetime adjustment to be lost for ARC
if (getLangOpts().ObjCAutoRefCount &&
M->getType()->isObjCLifetimeType() &&
M->getType().getObjCLifetime() != Qualifiers::OCL_None &&
M->getType().getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
- // FIXME: Fold this into the general case below.
llvm::Value *Object = createReferenceTemporary(*this, M, E);
LValue RefTempDst = MakeAddrLValue(Object, M->getType());
@@ -331,7 +333,21 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
Var->setInitializer(CGM.EmitNullConstant(E->getType()));
}
- EmitScalarInit(E, M->getExtendingDecl(), RefTempDst, false);
+ switch (getEvaluationKind(E->getType())) {
+ default: llvm_unreachable("expected scalar or aggregate expression");
+ case TEK_Scalar:
+ EmitScalarInit(E, M->getExtendingDecl(), RefTempDst, false);
+ break;
+ case TEK_Aggregate: {
+ CharUnits Alignment = getContext().getTypeAlignInChars(E->getType());
+ EmitAggExpr(E, AggValueSlot::forAddr(Object, Alignment,
+ E->getType().getQualifiers(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
+ break;
+ }
+ }
pushTemporaryCleanup(*this, M, E, Object);
return RefTempDst;
@@ -341,8 +357,8 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
SmallVector<SubobjectAdjustment, 2> Adjustments;
E = E->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
- for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
- EmitIgnoredExpr(CommaLHSs[I]);
+ for (const auto &Ignored : CommaLHSs)
+ EmitIgnoredExpr(Ignored);
if (const auto *opaque = dyn_cast<OpaqueValueExpr>(E)) {
if (opaque->getType()->isRecordType()) {
@@ -376,7 +392,7 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
GetAddressOfBaseClass(Object, Adjustment.DerivedToBase.DerivedClass,
Adjustment.DerivedToBase.BasePath->path_begin(),
Adjustment.DerivedToBase.BasePath->path_end(),
- /*NullCheckValue=*/ false);
+ /*NullCheckValue=*/ false, E->getExprLoc());
break;
case SubobjectAdjustment::FieldAdjustment: {
@@ -442,13 +458,15 @@ static llvm::Value *emitHash16Bytes(CGBuilderTy &Builder, llvm::Value *Low,
}
bool CodeGenFunction::sanitizePerformTypeCheck() const {
- return SanOpts->Null | SanOpts->Alignment | SanOpts->ObjectSize |
- SanOpts->Vptr;
+ return SanOpts.has(SanitizerKind::Null) |
+ SanOpts.has(SanitizerKind::Alignment) |
+ SanOpts.has(SanitizerKind::ObjectSize) |
+ SanOpts.has(SanitizerKind::Vptr);
}
void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
- llvm::Value *Address,
- QualType Ty, CharUnits Alignment) {
+ llvm::Value *Address, QualType Ty,
+ CharUnits Alignment, bool SkipNullCheck) {
if (!sanitizePerformTypeCheck())
return;
@@ -460,26 +478,30 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
SanitizerScope SanScope(this);
- llvm::Value *Cond = nullptr;
+ SmallVector<std::pair<llvm::Value *, SanitizerKind>, 3> Checks;
llvm::BasicBlock *Done = nullptr;
- if (SanOpts->Null || TCK == TCK_DowncastPointer) {
+ bool AllowNullPointers = TCK == TCK_DowncastPointer || TCK == TCK_Upcast ||
+ TCK == TCK_UpcastToVirtualBase;
+ if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) &&
+ !SkipNullCheck) {
// The glvalue must not be an empty glvalue.
- Cond = Builder.CreateICmpNE(
+ llvm::Value *IsNonNull = Builder.CreateICmpNE(
Address, llvm::Constant::getNullValue(Address->getType()));
- if (TCK == TCK_DowncastPointer) {
- // When performing a pointer downcast, it's OK if the value is null.
+ if (AllowNullPointers) {
+ // When performing pointer casts, it's OK if the value is null.
// Skip the remaining checks in that case.
Done = createBasicBlock("null");
llvm::BasicBlock *Rest = createBasicBlock("not.null");
- Builder.CreateCondBr(Cond, Rest, Done);
+ Builder.CreateCondBr(IsNonNull, Rest, Done);
EmitBlock(Rest);
- Cond = nullptr;
+ } else {
+ Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::Null));
}
}
- if (SanOpts->ObjectSize && !Ty->isIncompleteType()) {
+ if (SanOpts.has(SanitizerKind::ObjectSize) && !Ty->isIncompleteType()) {
uint64_t Size = getContext().getTypeSizeInChars(Ty).getQuantity();
// The glvalue must refer to a large enough storage region.
@@ -493,12 +515,12 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::Value *LargeEnough =
Builder.CreateICmpUGE(Builder.CreateCall2(F, CastAddr, Min),
llvm::ConstantInt::get(IntPtrTy, Size));
- Cond = Cond ? Builder.CreateAnd(Cond, LargeEnough) : LargeEnough;
+ Checks.push_back(std::make_pair(LargeEnough, SanitizerKind::ObjectSize));
}
uint64_t AlignVal = 0;
- if (SanOpts->Alignment) {
+ if (SanOpts.has(SanitizerKind::Alignment)) {
AlignVal = Alignment.getQuantity();
if (!Ty->isIncompleteType() && !AlignVal)
AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity();
@@ -510,18 +532,18 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::ConstantInt::get(IntPtrTy, AlignVal - 1));
llvm::Value *Aligned =
Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
- Cond = Cond ? Builder.CreateAnd(Cond, Aligned) : Aligned;
+ Checks.push_back(std::make_pair(Aligned, SanitizerKind::Alignment));
}
}
- if (Cond) {
+ if (Checks.size() > 0) {
llvm::Constant *StaticData[] = {
EmitCheckSourceLocation(Loc),
EmitCheckTypeDescriptor(Ty),
llvm::ConstantInt::get(SizeTy, AlignVal),
llvm::ConstantInt::get(Int8Ty, TCK)
};
- EmitCheck(Cond, "type_mismatch", StaticData, Address, CRK_Recoverable);
+ EmitCheck(Checks, "type_mismatch", StaticData, Address);
}
// If possible, check that the vptr indicates that there is a subobject of
@@ -533,9 +555,10 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
// -- the [pointer or glvalue] is used to access a non-static data member
// or call a non-static member function
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- if (SanOpts->Vptr &&
+ if (SanOpts.has(SanitizerKind::Vptr) &&
(TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
- TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference) &&
+ TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference ||
+ TCK == TCK_UpcastToVirtualBase) &&
RD && RD->hasDefinition() && RD->isDynamicClass()) {
// Compute a hash of the mangled name of the type.
//
@@ -548,7 +571,8 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
Out);
// Blacklist based on the mangled type.
- if (!CGM.getSanitizerBlacklist().isBlacklistedType(Out.str())) {
+ if (!CGM.getContext().getSanitizerBlacklist().isBlacklistedType(
+ Out.str())) {
llvm::hash_code TypeHash = hash_value(Out.str());
// Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
@@ -577,6 +601,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
// hard work of checking whether the vptr is for an object of the right
// type. This will either fill in the cache and return, or produce a
// diagnostic.
+ llvm::Value *EqualHash = Builder.CreateICmpEQ(CacheVal, Hash);
llvm::Constant *StaticData[] = {
EmitCheckSourceLocation(Loc),
EmitCheckTypeDescriptor(Ty),
@@ -584,9 +609,8 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::ConstantInt::get(Int8Ty, TCK)
};
llvm::Value *DynamicData[] = { Address, Hash };
- EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash),
- "dynamic_type_cache_miss", StaticData, DynamicData,
- CRK_AlwaysRecoverable);
+ EmitCheck(std::make_pair(EqualHash, SanitizerKind::Vptr),
+ "dynamic_type_cache_miss", StaticData, DynamicData);
}
}
@@ -654,7 +678,7 @@ static llvm::Value *getArrayIndexingBound(
void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
llvm::Value *Index, QualType IndexType,
bool Accessed) {
- assert(SanOpts->ArrayBounds &&
+ assert(SanOpts.has(SanitizerKind::ArrayBounds) &&
"should not be called unless adding bounds checks");
SanitizerScope SanScope(this);
@@ -674,7 +698,8 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
};
llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexVal, BoundVal)
: Builder.CreateICmpULE(IndexVal, BoundVal);
- EmitCheck(Check, "out_of_bounds", StaticData, Index, CRK_Recoverable);
+ EmitCheck(std::make_pair(Check, SanitizerKind::ArrayBounds), "out_of_bounds",
+ StaticData, Index);
}
@@ -711,7 +736,6 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
return isPre ? IncVal : InVal;
}
-
//===----------------------------------------------------------------------===//
// LValue Expression Emission
//===----------------------------------------------------------------------===//
@@ -757,7 +781,7 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
LValue LV;
- if (SanOpts->ArrayBounds && isa<ArraySubscriptExpr>(E))
+ if (SanOpts.has(SanitizerKind::ArrayBounds) && isa<ArraySubscriptExpr>(E))
LV = EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E), /*Accessed*/true);
else
LV = EmitLValue(E);
@@ -1130,8 +1154,11 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
CGM.DecorateInstruction(Load, TBAAPath, false/*ConvertTypeToTag*/);
}
- if ((SanOpts->Bool && hasBooleanRepresentation(Ty)) ||
- (SanOpts->Enum && Ty->getAs<EnumType>())) {
+ bool NeedsBoolCheck =
+ SanOpts.has(SanitizerKind::Bool) && hasBooleanRepresentation(Ty);
+ bool NeedsEnumCheck =
+ SanOpts.has(SanitizerKind::Enum) && Ty->getAs<EnumType>();
+ if (NeedsBoolCheck || NeedsEnumCheck) {
SanitizerScope SanScope(this);
llvm::APInt Min, End;
if (getRangeForType(*this, Ty, Min, End, true)) {
@@ -1151,8 +1178,9 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
EmitCheckSourceLocation(Loc),
EmitCheckTypeDescriptor(Ty)
};
- EmitCheck(Check, "load_invalid_value", StaticArgs, EmitCheckValue(Load),
- CRK_Recoverable);
+ SanitizerKind Kind = NeedsEnumCheck ? SanitizerKind::Enum : SanitizerKind::Bool;
+ EmitCheck(std::make_pair(Check, Kind), "load_invalid_value", StaticArgs,
+ EmitCheckValue(Load));
}
} else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
@@ -1361,12 +1389,34 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
return RValue::get(Vec);
}
+/// @brief Generates lvalue for partial ext_vector access.
+llvm::Value *CodeGenFunction::EmitExtVectorElementLValue(LValue LV) {
+ llvm::Value *VectorAddress = LV.getExtVectorAddr();
+ const VectorType *ExprVT = LV.getType()->getAs<VectorType>();
+ QualType EQT = ExprVT->getElementType();
+ llvm::Type *VectorElementTy = CGM.getTypes().ConvertType(EQT);
+ llvm::Type *VectorElementPtrToTy = VectorElementTy->getPointerTo();
+
+ llvm::Value *CastToPointerElement =
+ Builder.CreateBitCast(VectorAddress,
+ VectorElementPtrToTy, "conv.ptr.element");
+
+ const llvm::Constant *Elts = LV.getExtVectorElts();
+ unsigned ix = getAccessedFieldNo(0, Elts);
+
+ llvm::Value *VectorBasePtrPlusIx =
+ Builder.CreateInBoundsGEP(CastToPointerElement,
+ llvm::ConstantInt::get(SizeTy, ix), "add.ptr");
+
+ return VectorBasePtrPlusIx;
+}
+
/// @brief Load of global gamed gegisters are always calls to intrinsics.
RValue CodeGenFunction::EmitLoadOfGlobalRegLValue(LValue LV) {
assert((LV.getType()->isIntegerType() || LV.getType()->isPointerType()) &&
"Bad type for register variable");
- llvm::MDNode *RegName = dyn_cast<llvm::MDNode>(LV.getGlobalReg());
- assert(RegName && "Register LValue is not metadata");
+ llvm::MDNode *RegName = cast<llvm::MDNode>(
+ cast<llvm::MetadataAsValue>(LV.getGlobalReg())->getMetadata());
// We accept integer and pointer types only
llvm::Type *OrigTy = CGM.getTypes().ConvertType(LV.getType());
@@ -1376,7 +1426,8 @@ RValue CodeGenFunction::EmitLoadOfGlobalRegLValue(LValue LV) {
llvm::Type *Types[] = { Ty };
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::read_register, Types);
- llvm::Value *Call = Builder.CreateCall(F, RegName);
+ llvm::Value *Call = Builder.CreateCall(
+ F, llvm::MetadataAsValue::get(Ty->getContext(), RegName));
if (OrigTy->isPointerTy())
Call = Builder.CreateIntToPtr(Call, OrigTy);
return RValue::get(Call);
@@ -1626,7 +1677,8 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
void CodeGenFunction::EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst) {
assert((Dst.getType()->isIntegerType() || Dst.getType()->isPointerType()) &&
"Bad type for register variable");
- llvm::MDNode *RegName = dyn_cast<llvm::MDNode>(Dst.getGlobalReg());
+ llvm::MDNode *RegName = cast<llvm::MDNode>(
+ cast<llvm::MetadataAsValue>(Dst.getGlobalReg())->getMetadata());
assert(RegName && "Register LValue is not metadata");
// We accept integer and pointer types only
@@ -1640,7 +1692,8 @@ void CodeGenFunction::EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst) {
llvm::Value *Value = Src.getScalarVal();
if (OrigTy->isPointerTy())
Value = Builder.CreatePtrToInt(Value, Ty);
- Builder.CreateCall2(F, RegName, Value);
+ Builder.CreateCall2(F, llvm::MetadataAsValue::get(Ty->getContext(), RegName),
+ Value);
}
// setObjCGCLValueClass - sets class of the lvalue for the purpose of
@@ -1751,12 +1804,21 @@ EmitBitCastOfLValueToProperType(CodeGenFunction &CGF,
return CGF.Builder.CreateBitCast(V, IRType->getPointerTo(AS), Name);
}
+static LValue EmitThreadPrivateVarDeclLValue(
+ CodeGenFunction &CGF, const VarDecl *VD, QualType T, llvm::Value *V,
+ llvm::Type *RealVarTy, CharUnits Alignment, SourceLocation Loc) {
+ V = CGF.CGM.getOpenMPRuntime().getOMPAddrOfThreadPrivate(CGF, VD, V, Loc);
+ V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy);
+ return CGF.MakeAddrLValue(V, T, Alignment);
+}
+
static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
const Expr *E, const VarDecl *VD) {
QualType T = E->getType();
// If it's thread_local, emit a call to its wrapper function instead.
- if (VD->getTLSKind() == VarDecl::TLS_Dynamic)
+ if (VD->getTLSKind() == VarDecl::TLS_Dynamic &&
+ CGF.CGM.getCXXABI().usesThreadWrapperFunction())
return CGF.CGM.getCXXABI().EmitThreadLocalVarDeclLValue(CGF, VD, T);
llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
@@ -1764,6 +1826,11 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy);
CharUnits Alignment = CGF.getContext().getDeclAlign(VD);
LValue LV;
+ // Emit reference to the private copy of the variable if it is an OpenMP
+ // threadprivate variable.
+ if (CGF.getLangOpts().OpenMP && VD->hasAttr<OMPThreadPrivateDeclAttr>())
+ return EmitThreadPrivateVarDeclLValue(CGF, VD, T, V, RealVarTy, Alignment,
+ E->getExprLoc());
if (VD->getType()->isReferenceType()) {
llvm::LoadInst *LI = CGF.Builder.CreateLoad(V);
LI->setAlignment(Alignment.getQuantity());
@@ -1821,10 +1888,12 @@ static LValue EmitGlobalNamedRegister(const VarDecl *VD,
if (M->getNumOperands() == 0) {
llvm::MDString *Str = llvm::MDString::get(CGM.getLLVMContext(),
Asm->getLabel());
- llvm::Value *Ops[] = { Str };
+ llvm::Metadata *Ops[] = {Str};
M->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops));
}
- return LValue::MakeGlobalReg(M->getOperand(0), VD->getType(), Alignment);
+ return LValue::MakeGlobalReg(
+ llvm::MetadataAsValue::get(CGM.getLLVMContext(), M->getOperand(0)),
+ VD->getType(), Alignment);
}
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
@@ -1850,6 +1919,22 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
// FIXME: Eventually we will want to emit vector element references.
return MakeAddrLValue(Val, T, Alignment);
}
+
+ // Check for captured variables.
+ if (E->refersToEnclosingVariableOrCapture()) {
+ if (auto *FD = LambdaCaptureFields.lookup(VD))
+ return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
+ else if (CapturedStmtInfo) {
+ if (auto *V = LocalDeclMap.lookup(VD))
+ return MakeAddrLValue(V, T, Alignment);
+ else
+ return EmitCapturedFieldLValue(*this, CapturedStmtInfo->lookup(VD),
+ CapturedStmtInfo->getContextValue());
+ }
+ assert(isa<BlockDecl>(CurCodeDecl));
+ return MakeAddrLValue(GetAddrOfBlockDecl(VD, VD->hasAttr<BlocksAttr>()),
+ T, Alignment);
+ }
}
// FIXME: We should be able to assert this for FunctionDecls as well!
@@ -1874,22 +1959,14 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
llvm::Value *V = LocalDeclMap.lookup(VD);
if (!V && VD->isStaticLocal())
- V = CGM.getStaticLocalDeclAddress(VD);
-
- // Use special handling for lambdas.
- if (!V) {
- if (FieldDecl *FD = LambdaCaptureFields.lookup(VD)) {
- return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
- } else if (CapturedStmtInfo) {
- if (const FieldDecl *FD = CapturedStmtInfo->lookup(VD))
- return EmitCapturedFieldLValue(*this, FD,
- CapturedStmtInfo->getContextValue());
- }
+ V = CGM.getOrCreateStaticVarDecl(
+ *VD, CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false));
- assert(isa<BlockDecl>(CurCodeDecl) && E->refersToEnclosingLocal());
- return MakeAddrLValue(GetAddrOfBlockDecl(VD, isBlockVariable),
- T, Alignment);
- }
+ // Check if variable is threadprivate.
+ if (V && getLangOpts().OpenMP && VD->hasAttr<OMPThreadPrivateDeclAttr>())
+ return EmitThreadPrivateVarDeclLValue(
+ *this, VD, T, V, getTypes().ConvertTypeForMem(VD->getType()),
+ Alignment, E->getExprLoc());
assert(V && "DeclRefExpr not entered in LocalDeclMap?");
@@ -2001,86 +2078,21 @@ LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) {
E->getType());
}
-static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
- SmallString<32>& Target) {
- Target.resize(CharByteWidth * (Source.size() + 1));
- char *ResultPtr = &Target[0];
- const UTF8 *ErrorPtr;
- bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr);
- (void)success;
- assert(success);
- Target.resize(ResultPtr - &Target[0]);
-}
-
LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
- switch (E->getIdentType()) {
- default:
- return EmitUnsupportedLValue(E, "predefined expression");
-
- case PredefinedExpr::Func:
- case PredefinedExpr::Function:
- case PredefinedExpr::LFunction:
- case PredefinedExpr::FuncDName:
- case PredefinedExpr::FuncSig:
- case PredefinedExpr::PrettyFunction: {
- PredefinedExpr::IdentType IdentType = E->getIdentType();
- std::string GVName;
-
- // FIXME: We should use the string literal mangling for the Microsoft C++
- // ABI so that strings get merged.
- switch (IdentType) {
- default: llvm_unreachable("Invalid type");
- case PredefinedExpr::Func: GVName = "__func__."; break;
- case PredefinedExpr::Function: GVName = "__FUNCTION__."; break;
- case PredefinedExpr::FuncDName: GVName = "__FUNCDNAME__."; break;
- case PredefinedExpr::FuncSig: GVName = "__FUNCSIG__."; break;
- case PredefinedExpr::LFunction: GVName = "L__FUNCTION__."; break;
- case PredefinedExpr::PrettyFunction: GVName = "__PRETTY_FUNCTION__."; break;
- }
-
- StringRef FnName = CurFn->getName();
- if (FnName.startswith("\01"))
- FnName = FnName.substr(1);
- GVName += FnName;
-
- // If this is outside of a function use the top level decl.
- const Decl *CurDecl = CurCodeDecl;
- if (!CurDecl || isa<VarDecl>(CurDecl))
- CurDecl = getContext().getTranslationUnitDecl();
-
- const Type *ElemType = E->getType()->getArrayElementTypeNoTypeQual();
- std::string FunctionName;
- if (isa<BlockDecl>(CurDecl)) {
- // Blocks use the mangled function name.
- // FIXME: ComputeName should handle blocks.
- FunctionName = FnName.str();
- } else if (isa<CapturedDecl>(CurDecl)) {
- // For a captured statement, the function name is its enclosing
- // function name not the one compiler generated.
- FunctionName = PredefinedExpr::ComputeName(IdentType, CurDecl);
- } else {
- FunctionName = PredefinedExpr::ComputeName(IdentType, CurDecl);
- assert(cast<ConstantArrayType>(E->getType())->getSize() - 1 ==
- FunctionName.size() &&
- "Computed __func__ length differs from type!");
- }
-
- llvm::Constant *C;
- if (ElemType->isWideCharType()) {
- SmallString<32> RawChars;
- ConvertUTF8ToWideString(
- getContext().getTypeSizeInChars(ElemType).getQuantity(), FunctionName,
- RawChars);
- StringLiteral *SL = StringLiteral::Create(
- getContext(), RawChars, StringLiteral::Wide,
- /*Pascal = */ false, E->getType(), E->getLocation());
- C = CGM.GetAddrOfConstantStringFromLiteral(SL);
- } else {
- C = CGM.GetAddrOfConstantCString(FunctionName, GVName.c_str(), 1);
- }
+ auto SL = E->getFunctionName();
+ assert(SL != nullptr && "No StringLiteral name in PredefinedExpr");
+ StringRef FnName = CurFn->getName();
+ if (FnName.startswith("\01"))
+ FnName = FnName.substr(1);
+ StringRef NameItems[] = {
+ PredefinedExpr::getIdentTypeName(E->getIdentType()), FnName};
+ std::string GVName = llvm::join(NameItems, NameItems + 2, ".");
+ if (CurCodeDecl && isa<BlockDecl>(CurCodeDecl)) {
+ auto C = CGM.GetAddrOfConstantCString(FnName, GVName.c_str(), 1);
return MakeAddrLValue(C, E->getType());
}
- }
+ auto C = CGM.GetAddrOfConstantStringFromLiteral(SL, GVName);
+ return MakeAddrLValue(C, E->getType());
}
/// Emit a type description suitable for use by a runtime sanitizer library. The
@@ -2115,7 +2127,7 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype,
(intptr_t)T.getAsOpaquePtr(),
StringRef(), StringRef(), None, Buffer,
- ArrayRef<intptr_t>());
+ None);
llvm::Constant *Components[] = {
Builder.getInt16(TypeKind), Builder.getInt16(TypeInfo),
@@ -2127,7 +2139,7 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
CGM.getModule(), Descriptor->getType(),
/*isConstant=*/true, llvm::GlobalVariable::PrivateLinkage, Descriptor);
GV->setUnnamedAddr(true);
- CGM.disableSanitizerForGlobal(GV);
+ CGM.getSanitizerMetadata()->disableSanitizerForGlobal(GV);
// Remember the descriptor for this type.
CGM.setTypeDescriptorInMap(T, GV);
@@ -2177,7 +2189,7 @@ llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
PresumedLoc PLoc = getContext().getSourceManager().getPresumedLoc(Loc);
if (PLoc.isValid()) {
auto FilenameGV = CGM.GetAddrOfConstantCString(PLoc.getFilename(), ".src");
- CGM.disableSanitizerForGlobal(FilenameGV);
+ CGM.getSanitizerMetadata()->disableSanitizerForGlobal(FilenameGV);
Filename = FilenameGV;
Line = PLoc.getLine();
Column = PLoc.getColumn();
@@ -2192,39 +2204,126 @@ llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
return llvm::ConstantStruct::getAnon(Data);
}
-void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
- ArrayRef<llvm::Constant *> StaticArgs,
- ArrayRef<llvm::Value *> DynamicArgs,
- CheckRecoverableKind RecoverKind) {
- assert(SanOpts != &SanitizerOptions::Disabled);
- assert(IsSanitizerScope);
+namespace {
+/// \brief Specify under what conditions this check can be recovered
+enum class CheckRecoverableKind {
+ /// Always terminate program execution if this check fails.
+ Unrecoverable,
+ /// Check supports recovering, runtime has both fatal (noreturn) and
+ /// non-fatal handlers for this check.
+ Recoverable,
+ /// Runtime conditionally aborts, always need to support recovery.
+ AlwaysRecoverable
+};
+}
- if (CGM.getCodeGenOpts().SanitizeUndefinedTrapOnError) {
- assert (RecoverKind != CRK_AlwaysRecoverable &&
- "Runtime call required for AlwaysRecoverable kind!");
- return EmitTrapCheck(Checked);
+static CheckRecoverableKind getRecoverableKind(SanitizerKind Kind) {
+ switch (Kind) {
+ case SanitizerKind::Vptr:
+ return CheckRecoverableKind::AlwaysRecoverable;
+ case SanitizerKind::Return:
+ case SanitizerKind::Unreachable:
+ return CheckRecoverableKind::Unrecoverable;
+ default:
+ return CheckRecoverableKind::Recoverable;
}
+}
- llvm::BasicBlock *Cont = createBasicBlock("cont");
+static void emitCheckHandlerCall(CodeGenFunction &CGF,
+ llvm::FunctionType *FnType,
+ ArrayRef<llvm::Value *> FnArgs,
+ StringRef CheckName,
+ CheckRecoverableKind RecoverKind, bool IsFatal,
+ llvm::BasicBlock *ContBB) {
+ assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable);
+ bool NeedsAbortSuffix =
+ IsFatal && RecoverKind != CheckRecoverableKind::Unrecoverable;
+ std::string FnName = ("__ubsan_handle_" + CheckName +
+ (NeedsAbortSuffix ? "_abort" : "")).str();
+ bool MayReturn =
+ !IsFatal || RecoverKind == CheckRecoverableKind::AlwaysRecoverable;
- llvm::BasicBlock *Handler = createBasicBlock("handler." + CheckName);
+ llvm::AttrBuilder B;
+ if (!MayReturn) {
+ B.addAttribute(llvm::Attribute::NoReturn)
+ .addAttribute(llvm::Attribute::NoUnwind);
+ }
+ B.addAttribute(llvm::Attribute::UWTable);
- llvm::Instruction *Branch = Builder.CreateCondBr(Checked, Cont, Handler);
+ llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(
+ FnType, FnName,
+ llvm::AttributeSet::get(CGF.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex, B));
+ llvm::CallInst *HandlerCall = CGF.EmitNounwindRuntimeCall(Fn, FnArgs);
+ if (!MayReturn) {
+ HandlerCall->setDoesNotReturn();
+ CGF.Builder.CreateUnreachable();
+ } else {
+ CGF.Builder.CreateBr(ContBB);
+ }
+}
+void CodeGenFunction::EmitCheck(
+ ArrayRef<std::pair<llvm::Value *, SanitizerKind>> Checked,
+ StringRef CheckName, ArrayRef<llvm::Constant *> StaticArgs,
+ ArrayRef<llvm::Value *> DynamicArgs) {
+ assert(IsSanitizerScope);
+ assert(Checked.size() > 0);
+
+ llvm::Value *FatalCond = nullptr;
+ llvm::Value *RecoverableCond = nullptr;
+ for (int i = 0, n = Checked.size(); i < n; ++i) {
+ llvm::Value *Check = Checked[i].first;
+ llvm::Value *&Cond =
+ CGM.getCodeGenOpts().SanitizeRecover.has(Checked[i].second)
+ ? RecoverableCond
+ : FatalCond;
+ Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check;
+ }
+
+ llvm::Value *JointCond;
+ if (FatalCond && RecoverableCond)
+ JointCond = Builder.CreateAnd(FatalCond, RecoverableCond);
+ else
+ JointCond = FatalCond ? FatalCond : RecoverableCond;
+ assert(JointCond);
+
+ CheckRecoverableKind RecoverKind = getRecoverableKind(Checked[0].second);
+ assert(SanOpts.has(Checked[0].second));
+#ifndef NDEBUG
+ for (int i = 1, n = Checked.size(); i < n; ++i) {
+ assert(RecoverKind == getRecoverableKind(Checked[i].second) &&
+ "All recoverable kinds in a single check must be same!");
+ assert(SanOpts.has(Checked[i].second));
+ }
+#endif
+
+ if (CGM.getCodeGenOpts().SanitizeUndefinedTrapOnError) {
+ assert(RecoverKind != CheckRecoverableKind::AlwaysRecoverable &&
+ "Runtime call required for AlwaysRecoverable kind!");
+ // Assume that -fsanitize-undefined-trap-on-error overrides
+ // -fsanitize-recover= options, as we can only print meaningful error
+ // message and recover if we have a runtime support.
+ return EmitTrapCheck(JointCond);
+ }
+
+ llvm::BasicBlock *Cont = createBasicBlock("cont");
+ llvm::BasicBlock *Handlers = createBasicBlock("handler." + CheckName);
+ llvm::Instruction *Branch = Builder.CreateCondBr(JointCond, Cont, Handlers);
// Give hint that we very much don't expect to execute the handler
// Value chosen to match UR_NONTAKEN_WEIGHT, see BranchProbabilityInfo.cpp
llvm::MDBuilder MDHelper(getLLVMContext());
llvm::MDNode *Node = MDHelper.createBranchWeights((1U << 20) - 1, 1);
Branch->setMetadata(llvm::LLVMContext::MD_prof, Node);
+ EmitBlock(Handlers);
- EmitBlock(Handler);
-
+ // Emit handler arguments and create handler function type.
llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
auto *InfoPtr =
new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false,
llvm::GlobalVariable::PrivateLinkage, Info);
InfoPtr->setUnnamedAddr(true);
- CGM.disableSanitizerForGlobal(InfoPtr);
+ CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
SmallVector<llvm::Value *, 4> Args;
SmallVector<llvm::Type *, 4> ArgTypes;
@@ -2241,34 +2340,27 @@ void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
ArgTypes.push_back(IntPtrTy);
}
- bool Recover = RecoverKind == CRK_AlwaysRecoverable ||
- (RecoverKind == CRK_Recoverable &&
- CGM.getCodeGenOpts().SanitizeRecover);
-
llvm::FunctionType *FnType =
llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false);
- llvm::AttrBuilder B;
- if (!Recover) {
- B.addAttribute(llvm::Attribute::NoReturn)
- .addAttribute(llvm::Attribute::NoUnwind);
- }
- B.addAttribute(llvm::Attribute::UWTable);
- // Checks that have two variants use a suffix to differentiate them
- bool NeedsAbortSuffix = RecoverKind != CRK_Unrecoverable &&
- !CGM.getCodeGenOpts().SanitizeRecover;
- std::string FunctionName = ("__ubsan_handle_" + CheckName +
- (NeedsAbortSuffix? "_abort" : "")).str();
- llvm::Value *Fn = CGM.CreateRuntimeFunction(
- FnType, FunctionName,
- llvm::AttributeSet::get(getLLVMContext(),
- llvm::AttributeSet::FunctionIndex, B));
- llvm::CallInst *HandlerCall = EmitNounwindRuntimeCall(Fn, Args);
- if (Recover) {
- Builder.CreateBr(Cont);
+ if (!FatalCond || !RecoverableCond) {
+ // Simple case: we need to generate a single handler call, either
+ // fatal, or non-fatal.
+ emitCheckHandlerCall(*this, FnType, Args, CheckName, RecoverKind,
+ (FatalCond != nullptr), Cont);
} else {
- HandlerCall->setDoesNotReturn();
- Builder.CreateUnreachable();
+ // Emit two handler calls: first one for set of unrecoverable checks,
+ // another one for recoverable.
+ llvm::BasicBlock *NonFatalHandlerBB =
+ createBasicBlock("non_fatal." + CheckName);
+ llvm::BasicBlock *FatalHandlerBB = createBasicBlock("fatal." + CheckName);
+ Builder.CreateCondBr(FatalCond, NonFatalHandlerBB, FatalHandlerBB);
+ EmitBlock(FatalHandlerBB);
+ emitCheckHandlerCall(*this, FnType, Args, CheckName, RecoverKind, true,
+ NonFatalHandlerBB);
+ EmitBlock(NonFatalHandlerBB);
+ emitCheckHandlerCall(*this, FnType, Args, CheckName, RecoverKind, false,
+ Cont);
}
EmitBlock(Cont);
@@ -2318,12 +2410,13 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
QualType IdxTy = E->getIdx()->getType();
bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
- if (SanOpts->ArrayBounds)
+ if (SanOpts.has(SanitizerKind::ArrayBounds))
EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed);
// If the base is a vector type, then we are forming a vector element lvalue
// with this subscript.
- if (E->getBase()->getType()->isVectorType()) {
+ if (E->getBase()->getType()->isVectorType() &&
+ !isa<ExtVectorElementExpr>(E->getBase())) {
// Emit the vector as an lvalue to get its address.
LValue LHS = EmitLValue(E->getBase());
assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
@@ -2339,8 +2432,17 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
// size is a VLA or Objective-C interface.
llvm::Value *Address = nullptr;
CharUnits ArrayAlignment;
- if (const VariableArrayType *vla =
- getContext().getAsVariableArrayType(E->getType())) {
+ if (isa<ExtVectorElementExpr>(E->getBase())) {
+ LValue LV = EmitLValue(E->getBase());
+ Address = EmitExtVectorElementLValue(LV);
+ Address = Builder.CreateInBoundsGEP(Address, Idx, "arrayidx");
+ const VectorType *ExprVT = LV.getType()->getAs<VectorType>();
+ QualType EQT = ExprVT->getElementType();
+ return MakeAddrLValue(Address, EQT,
+ getContext().getTypeAlignInChars(EQT));
+ }
+ else if (const VariableArrayType *vla =
+ getContext().getAsVariableArrayType(E->getType())) {
// The base must be a pointer, which is not an aggregate. Emit
// it. It needs to be emitted first in case it's what captures
// the VLA bounds.
@@ -2879,10 +2981,9 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
llvm::Value *This = LV.getAddress();
// Perform the derived-to-base conversion
- llvm::Value *Base =
- GetAddressOfBaseClass(This, DerivedClassDecl,
- E->path_begin(), E->path_end(),
- /*NullCheckValue=*/false);
+ llvm::Value *Base = GetAddressOfBaseClass(
+ This, DerivedClassDecl, E->path_begin(), E->path_end(),
+ /*NullCheckValue=*/false, E->getExprLoc());
return MakeAddrLValue(Base, E->getType());
}
@@ -2958,18 +3059,15 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) {
- if (CGDebugInfo *DI = getDebugInfo()) {
- SourceLocation Loc = E->getLocStart();
- // Force column info to be generated so we can differentiate
- // multiple call sites on the same line in the debug info.
- // FIXME: This is insufficient. Two calls coming from the same macro
- // expansion will still get the same line/column and break debug info. It's
- // possible that LLVM can be fixed to not rely on this uniqueness, at which
- // point this workaround can be removed.
- const FunctionDecl* Callee = E->getDirectCallee();
- bool ForceColumnInfo = Callee && Callee->isInlineSpecified();
- DI->EmitLocation(Builder, Loc, ForceColumnInfo);
- }
+ // Force column info to be generated so we can differentiate
+ // multiple call sites on the same line in the debug info.
+ // FIXME: This is insufficient. Two calls coming from the same macro
+ // expansion will still get the same line/column and break debug info. It's
+ // possible that LLVM can be fixed to not rely on this uniqueness, at which
+ // point this workaround can be removed.
+ ApplyDebugLocation DL(*this, E->getLocStart(),
+ E->getDirectCallee() &&
+ E->getDirectCallee()->isInlineSpecified());
// Builtins never have block type.
if (E->getCallee()->getType()->isBlockPointerType())
@@ -2984,7 +3082,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
const Decl *TargetDecl = E->getCalleeDecl();
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
if (unsigned builtinID = FD->getBuiltinID())
- return EmitBuiltinExpr(FD, builtinID, E);
+ return EmitBuiltinExpr(FD, builtinID, E, ReturnValue);
}
if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(E))
@@ -3046,8 +3144,8 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
}
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
- return EmitCall(E->getCallee()->getType(), Callee, E->getLocStart(),
- ReturnValue, E->arg_begin(), E->arg_end(), TargetDecl);
+ return EmitCall(E->getCallee()->getType(), Callee, E, ReturnValue,
+ TargetDecl);
}
LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
@@ -3218,11 +3316,8 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
}
RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
- SourceLocation CallLoc,
- ReturnValueSlot ReturnValue,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd,
- const Decl *TargetDecl) {
+ const CallExpr *E, ReturnValueSlot ReturnValue,
+ const Decl *TargetDecl, llvm::Value *Chain) {
// Get the actual function type. The callee type will always be a pointer to
// function type or a block pointer type.
assert(CalleeType->isFunctionPointerType() &&
@@ -3243,7 +3338,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
if (const FunctionDecl* FD = dyn_cast_or_null<const FunctionDecl>(TargetDecl))
ForceColumnInfo = FD->isInlineSpecified();
- if (getLangOpts().CPlusPlus && SanOpts->Function &&
+ if (getLangOpts().CPlusPlus && SanOpts.has(SanitizerKind::Function) &&
(!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
if (llvm::Constant *PrefixSig =
CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
@@ -3275,14 +3370,11 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
llvm::Value *CalleeRTTIMatch =
Builder.CreateICmpEQ(CalleeRTTI, FTRTTIConst);
llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(CallLoc),
+ EmitCheckSourceLocation(E->getLocStart()),
EmitCheckTypeDescriptor(CalleeType)
};
- EmitCheck(CalleeRTTIMatch,
- "function_type_mismatch",
- StaticData,
- Callee,
- CRK_Recoverable);
+ EmitCheck(std::make_pair(CalleeRTTIMatch, SanitizerKind::Function),
+ "function_type_mismatch", StaticData, Callee);
Builder.CreateBr(Cont);
EmitBlock(Cont);
@@ -3290,11 +3382,15 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
}
CallArgList Args;
- EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd,
+ if (Chain)
+ Args.add(RValue::get(Builder.CreateBitCast(Chain, CGM.VoidPtrTy)),
+ CGM.getContext().VoidPtrTy);
+ EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), E->arg_begin(),
+ E->arg_end(), E->getDirectCallee(), /*ParamsToSkip*/ 0,
ForceColumnInfo);
- const CGFunctionInfo &FnInfo =
- CGM.getTypes().arrangeFreeFunctionCall(Args, FnType);
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall(
+ Args, FnType, /*isChainCall=*/Chain);
// C99 6.5.2.2p6:
// If the expression that denotes the called function has a type
@@ -3313,7 +3409,10 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
// through an unprototyped function type works like a *non-variadic*
// call. The way we make this work is to cast to the exact type
// of the promoted arguments.
- if (isa<FunctionNoProtoType>(FnType)) {
+ //
+ // Chain calls use this same code path to add the invisible chain parameter
+ // to the function type.
+ if (isa<FunctionNoProtoType>(FnType) || Chain) {
llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo);
CalleeTy = CalleeTy->getPointerTo();
Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast");
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 7aacee4d6ba1..6d63b3ae9cf8 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -24,29 +24,28 @@
using namespace clang;
using namespace CodeGen;
-RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
- SourceLocation CallLoc,
- llvm::Value *Callee,
- ReturnValueSlot ReturnValue,
- llvm::Value *This,
- llvm::Value *ImplicitParam,
- QualType ImplicitParamTy,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
+static RequiredArgs commonEmitCXXMemberOrOperatorCall(
+ CodeGenFunction &CGF, const CXXMethodDecl *MD, llvm::Value *Callee,
+ ReturnValueSlot ReturnValue, llvm::Value *This, llvm::Value *ImplicitParam,
+ QualType ImplicitParamTy, const CallExpr *CE, CallArgList &Args) {
+ assert(CE == nullptr || isa<CXXMemberCallExpr>(CE) ||
+ isa<CXXOperatorCallExpr>(CE));
assert(MD->isInstance() &&
- "Trying to emit a member call expr on a static method!");
+ "Trying to emit a member or operator call expr on a static method!");
// C++11 [class.mfct.non-static]p2:
// If a non-static member function of a class X is called for an object that
// is not of type X, or of a type derived from X, the behavior is undefined.
- EmitTypeCheck(isa<CXXConstructorDecl>(MD) ? TCK_ConstructorCall
- : TCK_MemberCall,
- CallLoc, This, getContext().getRecordType(MD->getParent()));
-
- CallArgList Args;
+ SourceLocation CallLoc;
+ if (CE)
+ CallLoc = CE->getExprLoc();
+ CGF.EmitTypeCheck(
+ isa<CXXConstructorDecl>(MD) ? CodeGenFunction::TCK_ConstructorCall
+ : CodeGenFunction::TCK_MemberCall,
+ CallLoc, This, CGF.getContext().getRecordType(MD->getParent()));
// Push the this ptr.
- Args.add(RValue::get(This), MD->getThisType(getContext()));
+ Args.add(RValue::get(This), MD->getThisType(CGF.getContext()));
// If there is an implicit parameter (e.g. VTT), emit it.
if (ImplicitParam) {
@@ -55,14 +54,45 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size());
-
+
// And the rest of the call args.
- EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
+ if (CE) {
+ // Special case: skip first argument of CXXOperatorCall (it is "this").
+ unsigned ArgsToSkip = isa<CXXOperatorCallExpr>(CE) ? 1 : 0;
+ CGF.EmitCallArgs(Args, FPT, CE->arg_begin() + ArgsToSkip, CE->arg_end(),
+ CE->getDirectCallee());
+ } else {
+ assert(
+ FPT->getNumParams() == 0 &&
+ "No CallExpr specified for function with non-zero number of arguments");
+ }
+ return required;
+}
+RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
+ const CXXMethodDecl *MD, llvm::Value *Callee, ReturnValueSlot ReturnValue,
+ llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy,
+ const CallExpr *CE) {
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+ CallArgList Args;
+ RequiredArgs required = commonEmitCXXMemberOrOperatorCall(
+ *this, MD, Callee, ReturnValue, This, ImplicitParam, ImplicitParamTy, CE,
+ Args);
return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required),
Callee, ReturnValue, Args, MD);
}
+RValue CodeGenFunction::EmitCXXStructorCall(
+ const CXXMethodDecl *MD, llvm::Value *Callee, ReturnValueSlot ReturnValue,
+ llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy,
+ const CallExpr *CE, StructorType Type) {
+ CallArgList Args;
+ commonEmitCXXMemberOrOperatorCall(*this, MD, Callee, ReturnValue, This,
+ ImplicitParam, ImplicitParamTy, CE, Args);
+ return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(MD, Type),
+ Callee, ReturnValue, Args, MD);
+}
+
static CXXRecordDecl *getCXXRecord(const Expr *E) {
QualType T = E->getType();
if (const PointerType *PTy = T->getAs<PointerType>())
@@ -86,14 +116,27 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
if (MD->isStatic()) {
// The method is static, emit it as we would a regular call.
llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
- return EmitCall(getContext().getPointerType(MD->getType()), Callee,
- CE->getLocStart(), ReturnValue, CE->arg_begin(),
- CE->arg_end());
+ return EmitCall(getContext().getPointerType(MD->getType()), Callee, CE,
+ ReturnValue);
}
- // Compute the object pointer.
+ bool HasQualifier = ME->hasQualifier();
+ NestedNameSpecifier *Qualifier = HasQualifier ? ME->getQualifier() : nullptr;
+ bool IsArrow = ME->isArrow();
const Expr *Base = ME->getBase();
- bool CanUseVirtualCall = MD->isVirtual() && !ME->hasQualifier();
+
+ return EmitCXXMemberOrOperatorMemberCallExpr(
+ CE, MD, ReturnValue, HasQualifier, Qualifier, IsArrow, Base);
+}
+
+RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
+ const CallExpr *CE, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue,
+ bool HasQualifier, NestedNameSpecifier *Qualifier, bool IsArrow,
+ const Expr *Base) {
+ assert(isa<CXXMemberCallExpr>(CE) || isa<CXXOperatorCallExpr>(CE));
+
+ // Compute the object pointer.
+ bool CanUseVirtualCall = MD->isVirtual() && !HasQualifier;
const CXXMethodDecl *DevirtualizedMethod = nullptr;
if (CanUseVirtualCall && CanDevirtualizeMemberFunctionCall(Base, MD)) {
@@ -102,7 +145,15 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
assert(DevirtualizedMethod);
const CXXRecordDecl *DevirtualizedClass = DevirtualizedMethod->getParent();
const Expr *Inner = Base->ignoreParenBaseCasts();
- if (getCXXRecord(Inner) == DevirtualizedClass)
+ if (DevirtualizedMethod->getReturnType().getCanonicalType() !=
+ MD->getReturnType().getCanonicalType())
+ // If the return types are not the same, this might be a case where more
+ // code needs to run to compensate for it. For example, the derived
+ // method might return a type that inherits form from the return
+ // type of MD and has a prefix.
+ // For now we just avoid devirtualizing these covariant cases.
+ DevirtualizedMethod = nullptr;
+ else if (getCXXRecord(Inner) == DevirtualizedClass)
// If the class of the Inner expression is where the dynamic method
// is defined, build the this pointer from it.
Base = Inner;
@@ -113,19 +164,10 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
// we don't have support for that yet, so do a virtual call.
DevirtualizedMethod = nullptr;
}
- // If the return types are not the same, this might be a case where more
- // code needs to run to compensate for it. For example, the derived
- // method might return a type that inherits form from the return
- // type of MD and has a prefix.
- // For now we just avoid devirtualizing these covariant cases.
- if (DevirtualizedMethod &&
- DevirtualizedMethod->getReturnType().getCanonicalType() !=
- MD->getReturnType().getCanonicalType())
- DevirtualizedMethod = nullptr;
}
llvm::Value *This;
- if (ME->isArrow())
+ if (IsArrow)
This = EmitScalarExpr(Base);
else
This = EmitLValue(Base).getAddress();
@@ -137,34 +179,40 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
cast<CXXConstructorDecl>(MD)->isDefaultConstructor())
return RValue::get(nullptr);
- if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) {
- // We don't like to generate the trivial copy/move assignment operator
- // when it isn't necessary; just produce the proper effect here.
- llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
- EmitAggregateAssign(This, RHS, CE->getType());
- return RValue::get(This);
- }
-
- if (isa<CXXConstructorDecl>(MD) &&
- cast<CXXConstructorDecl>(MD)->isCopyOrMoveConstructor()) {
- // Trivial move and copy ctor are the same.
- llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
- EmitSynthesizedCXXCopyCtorCall(cast<CXXConstructorDecl>(MD), This, RHS,
- CE->arg_begin(), CE->arg_end());
- return RValue::get(This);
+ if (!MD->getParent()->mayInsertExtraPadding()) {
+ if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) {
+ // We don't like to generate the trivial copy/move assignment operator
+ // when it isn't necessary; just produce the proper effect here.
+ // Special case: skip first argument of CXXOperatorCall (it is "this").
+ unsigned ArgsToSkip = isa<CXXOperatorCallExpr>(CE) ? 1 : 0;
+ llvm::Value *RHS =
+ EmitLValue(*(CE->arg_begin() + ArgsToSkip)).getAddress();
+ EmitAggregateAssign(This, RHS, CE->getType());
+ return RValue::get(This);
+ }
+
+ if (isa<CXXConstructorDecl>(MD) &&
+ cast<CXXConstructorDecl>(MD)->isCopyOrMoveConstructor()) {
+ // Trivial move and copy ctor are the same.
+ assert(CE->getNumArgs() == 1 && "unexpected argcount for trivial ctor");
+ llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
+ EmitAggregateCopy(This, RHS, CE->arg_begin()->getType());
+ return RValue::get(This);
+ }
+ llvm_unreachable("unknown trivial member function");
}
- llvm_unreachable("unknown trivial member function");
}
// Compute the function type we're calling.
- const CXXMethodDecl *CalleeDecl = DevirtualizedMethod ? DevirtualizedMethod : MD;
+ const CXXMethodDecl *CalleeDecl =
+ DevirtualizedMethod ? DevirtualizedMethod : MD;
const CGFunctionInfo *FInfo = nullptr;
- if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(CalleeDecl))
- FInfo = &CGM.getTypes().arrangeCXXDestructor(Dtor,
- Dtor_Complete);
- else if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(CalleeDecl))
- FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor,
- Ctor_Complete);
+ if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(CalleeDecl))
+ FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration(
+ Dtor, StructorType::Complete);
+ else if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(CalleeDecl))
+ FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration(
+ Ctor, StructorType::Complete);
else
FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(CalleeDecl);
@@ -184,22 +232,21 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
"Destructor shouldn't have explicit parameters");
assert(ReturnValue.isNull() && "Destructor shouldn't have return value");
if (UseVirtualCall) {
- CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor, Dtor_Complete,
- CE->getExprLoc(), This);
+ CGM.getCXXABI().EmitVirtualDestructorCall(
+ *this, Dtor, Dtor_Complete, This, cast<CXXMemberCallExpr>(CE));
} else {
- if (getLangOpts().AppleKext &&
- MD->isVirtual() &&
- ME->hasQualifier())
- Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
+ if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier)
+ Callee = BuildAppleKextVirtualCall(MD, Qualifier, Ty);
else if (!DevirtualizedMethod)
- Callee = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete, FInfo, Ty);
+ Callee =
+ CGM.getAddrOfCXXStructor(Dtor, StructorType::Complete, FInfo, Ty);
else {
const CXXDestructorDecl *DDtor =
cast<CXXDestructorDecl>(DevirtualizedMethod);
Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty);
}
- EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
- /*ImplicitParam=*/nullptr, QualType(), nullptr,nullptr);
+ EmitCXXMemberOrOperatorCall(MD, Callee, ReturnValue, This,
+ /*ImplicitParam=*/nullptr, QualType(), CE);
}
return RValue::get(nullptr);
}
@@ -209,10 +256,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
} else if (UseVirtualCall) {
Callee = CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, Ty);
} else {
- if (getLangOpts().AppleKext &&
- MD->isVirtual() &&
- ME->hasQualifier())
- Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
+ if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier)
+ Callee = BuildAppleKextVirtualCall(MD, Qualifier, Ty);
else if (!DevirtualizedMethod)
Callee = CGM.GetAddrOfFunction(MD, Ty);
else {
@@ -225,9 +270,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
*this, MD, This, UseVirtualCall);
}
- return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
- /*ImplicitParam=*/nullptr, QualType(),
- CE->arg_begin(), CE->arg_end());
+ return EmitCXXMemberOrOperatorCall(MD, Callee, ReturnValue, This,
+ /*ImplicitParam=*/nullptr, QualType(), CE);
}
RValue
@@ -275,7 +319,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, 1);
// And the rest of the call args
- EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
+ EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end(), E->getDirectCallee());
return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required),
Callee, ReturnValue, Args);
}
@@ -286,21 +330,9 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
ReturnValueSlot ReturnValue) {
assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
- LValue LV = EmitLValue(E->getArg(0));
- llvm::Value *This = LV.getAddress();
-
- if ((MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) &&
- MD->isTrivial()) {
- llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
- QualType Ty = E->getType();
- EmitAggregateAssign(This, Src, Ty);
- return RValue::get(This);
- }
-
- llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
- return EmitCXXMemberCall(MD, E->getExprLoc(), Callee, ReturnValue, This,
- /*ImplicitParam=*/nullptr, QualType(),
- E->arg_begin() + 1, E->arg_end());
+ return EmitCXXMemberOrOperatorMemberCallExpr(
+ E, MD, ReturnValue, /*HasQualifier=*/false, /*Qualifier=*/nullptr,
+ /*IsArrow=*/false, E->getArg(0));
}
RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
@@ -392,8 +424,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
if (const ConstantArrayType *arrayType
= getContext().getAsConstantArrayType(E->getType())) {
- EmitCXXAggrConstructorCall(CD, arrayType, Dest.getAddr(),
- E->arg_begin(), E->arg_end());
+ EmitCXXAggrConstructorCall(CD, arrayType, Dest.getAddr(), E);
} else {
CXXCtorType Type = Ctor_Complete;
bool ForVirtualBase = false;
@@ -420,7 +451,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
// Call the constructor.
EmitCXXConstructorCall(CD, Type, ForVirtualBase, Delegating, Dest.getAddr(),
- E->arg_begin(), E->arg_end());
+ E);
}
}
@@ -445,7 +476,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtor(llvm::Value *Dest,
assert(!getContext().getAsConstantArrayType(E->getType())
&& "EmitSynthesizedCXXCopyCtor - Copied-in Array");
- EmitSynthesizedCXXCopyCtorCall(CD, Dest, Src, E->arg_begin(), E->arg_end());
+ EmitSynthesizedCXXCopyCtorCall(CD, Dest, Src, E);
}
static CharUnits CalculateCookiePadding(CodeGenFunction &CGF,
@@ -726,9 +757,8 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
switch (CGF.getEvaluationKind(AllocType)) {
case TEK_Scalar:
- CGF.EmitScalarInit(Init, nullptr, CGF.MakeAddrLValue(NewPtr, AllocType,
- Alignment),
- false);
+ CGF.EmitScalarInit(Init, nullptr,
+ CGF.MakeAddrLValue(NewPtr, AllocType, Alignment), false);
return;
case TEK_Complex:
CGF.EmitComplexExprIntoLValue(Init, CGF.MakeAddrLValue(NewPtr, AllocType,
@@ -895,8 +925,7 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
NumElements = Builder.CreateSub(
NumElements,
llvm::ConstantInt::get(NumElements->getType(), InitListElements));
- EmitCXXAggrConstructorCall(Ctor, NumElements, CurPtr,
- CCE->arg_begin(), CCE->arg_end(),
+ EmitCXXAggrConstructorCall(Ctor, NumElements, CurPtr, CCE,
CCE->requiresZeroInitialization());
return;
}
@@ -987,6 +1016,7 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
llvm::Value *NewPtr,
llvm::Value *NumElements,
llvm::Value *AllocSizeWithoutCookie) {
+ ApplyDebugLocation DL(CGF, E->getStartLoc());
if (E->isArray())
CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements,
AllocSizeWithoutCookie);
@@ -1003,9 +1033,9 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
llvm::Instruction *CallOrInvoke;
llvm::Value *CalleeAddr = CGF.CGM.GetAddrOfFunction(Callee);
RValue RV =
- CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(Args, CalleeType),
- CalleeAddr, ReturnValueSlot(), Args,
- Callee, &CallOrInvoke);
+ CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(
+ Args, CalleeType, /*chainCall=*/false),
+ CalleeAddr, ReturnValueSlot(), Args, Callee, &CallOrInvoke);
/// C++1y [expr.new]p10:
/// [In a new-expression,] an implementation is allowed to omit a call
@@ -1226,15 +1256,14 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
llvm::Value *allocSize =
EmitCXXNewAllocSize(*this, E, minElements, numElements,
allocSizeWithoutCookie);
-
+
allocatorArgs.add(RValue::get(allocSize), sizeType);
// We start at 1 here because the first argument (the allocation size)
// has already been emitted.
- EmitCallArgs(allocatorArgs, allocatorType->isVariadic(),
- allocatorType->param_type_begin() + 1,
- allocatorType->param_type_end(), E->placement_arg_begin(),
- E->placement_arg_end());
+ EmitCallArgs(allocatorArgs, allocatorType, E->placement_arg_begin(),
+ E->placement_arg_end(), /* CalleeDecl */ nullptr,
+ /*ParamsToSkip*/ 1);
// Emit the allocation call. If the allocator is a global placement
// operator, just "inline" it directly.
@@ -1386,12 +1415,19 @@ namespace {
};
}
+void
+CodeGenFunction::pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete,
+ llvm::Value *CompletePtr,
+ QualType ElementType) {
+ EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup, CompletePtr,
+ OperatorDelete, ElementType);
+}
+
/// Emit the code for deleting a single object.
static void EmitObjectDelete(CodeGenFunction &CGF,
- const FunctionDecl *OperatorDelete,
+ const CXXDeleteExpr *DE,
llvm::Value *Ptr,
- QualType ElementType,
- bool UseGlobalDelete) {
+ QualType ElementType) {
// Find the destructor for the type, if applicable. If the
// destructor is virtual, we'll just emit the vcall and return.
const CXXDestructorDecl *Dtor = nullptr;
@@ -1401,29 +1437,8 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
Dtor = RD->getDestructor();
if (Dtor->isVirtual()) {
- if (UseGlobalDelete) {
- // If we're supposed to call the global delete, make sure we do so
- // even if the destructor throws.
-
- // Derive the complete-object pointer, which is what we need
- // to pass to the deallocation function.
- llvm::Value *completePtr =
- CGF.CGM.getCXXABI().adjustToCompleteObject(CGF, Ptr, ElementType);
-
- CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
- completePtr, OperatorDelete,
- ElementType);
- }
-
- // FIXME: Provide a source location here.
- CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
- CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType,
- SourceLocation(), Ptr);
-
- if (UseGlobalDelete) {
- CGF.PopCleanupBlock();
- }
-
+ CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType,
+ Dtor);
return;
}
}
@@ -1432,6 +1447,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
// Make sure that we call delete even if the dtor throws.
// This doesn't have to a conditional cleanup because we're going
// to pop it off in a second.
+ const FunctionDecl *OperatorDelete = DE->getOperatorDelete();
CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
Ptr, OperatorDelete, ElementType);
@@ -1608,8 +1624,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
if (E->isArrayForm()) {
EmitArrayDelete(*this, E, Ptr, DeleteTy);
} else {
- EmitObjectDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy,
- E->isGlobalDelete());
+ EmitObjectDelete(*this, E, Ptr, DeleteTy);
}
EmitBlock(DeleteEnd);
@@ -1800,19 +1815,23 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
void CodeGenFunction::EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Slot) {
RunCleanupsScope Scope(*this);
- LValue SlotLV = MakeAddrLValue(Slot.getAddr(), E->getType(),
- Slot.getAlignment());
+ LValue SlotLV =
+ MakeAddrLValue(Slot.getAddr(), E->getType(), Slot.getAlignment());
CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
for (LambdaExpr::capture_init_iterator i = E->capture_init_begin(),
e = E->capture_init_end();
i != e; ++i, ++CurField) {
// Emit initialization
-
LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField);
- ArrayRef<VarDecl *> ArrayIndexes;
- if (CurField->getType()->isArrayType())
- ArrayIndexes = E->getCaptureInitIndexVars(i);
- EmitInitializerForField(*CurField, LV, *i, ArrayIndexes);
+ if (CurField->hasCapturedVLAType()) {
+ auto VAT = CurField->getCapturedVLAType();
+ EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV);
+ } else {
+ ArrayRef<VarDecl *> ArrayIndexes;
+ if (CurField->getType()->isArrayType())
+ ArrayIndexes = E->getCaptureInitIndexVars(i);
+ EmitInitializerForField(*CurField, LV, *i, ArrayIndexes);
+ }
}
}
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 7244b9e4d1eb..1580bbe6a294 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -15,9 +15,13 @@
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Metadata.h"
#include <algorithm>
using namespace clang;
using namespace CodeGen;
@@ -142,7 +146,7 @@ public:
// FIXME: CompoundLiteralExpr
- ComplexPairTy EmitCast(CastExpr::CastKind CK, Expr *Op, QualType DestTy);
+ ComplexPairTy EmitCast(CastKind CK, Expr *Op, QualType DestTy);
ComplexPairTy VisitImplicitCastExpr(ImplicitCastExpr *E) {
// Unlike for scalars, we don't have to worry about function->ptr demotion
// here.
@@ -230,6 +234,9 @@ public:
ComplexPairTy EmitBinMul(const BinOpInfo &Op);
ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
+ ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName,
+ const BinOpInfo &Op);
+
ComplexPairTy VisitBinAdd(const BinaryOperator *E) {
return EmitBinAdd(EmitBinOps(E));
}
@@ -326,8 +333,7 @@ ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue,
/// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer.
-void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val,
- LValue lvalue,
+void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue,
bool isInit) {
if (lvalue.getType()->isAtomicType())
return CGF.EmitAtomicStore(RValue::getComplex(Val), lvalue, isInit);
@@ -410,7 +416,7 @@ ComplexPairTy ComplexExprEmitter::EmitScalarToComplexCast(llvm::Value *Val,
return ComplexPairTy(Val, llvm::Constant::getNullValue(Val->getType()));
}
-ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
+ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
QualType DestTy) {
switch (CK) {
case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
@@ -528,9 +534,15 @@ ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
if (Op.LHS.first->getType()->isFloatingPointTy()) {
ResR = Builder.CreateFAdd(Op.LHS.first, Op.RHS.first, "add.r");
- ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i");
+ if (Op.LHS.second && Op.RHS.second)
+ ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i");
+ else
+ ResI = Op.LHS.second ? Op.LHS.second : Op.RHS.second;
+ assert(ResI && "Only one operand may be real!");
} else {
ResR = Builder.CreateAdd(Op.LHS.first, Op.RHS.first, "add.r");
+ assert(Op.LHS.second && Op.RHS.second &&
+ "Both operands of integer complex operators must be complex!");
ResI = Builder.CreateAdd(Op.LHS.second, Op.RHS.second, "add.i");
}
return ComplexPairTy(ResR, ResI);
@@ -539,63 +551,222 @@ ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) {
llvm::Value *ResR, *ResI;
if (Op.LHS.first->getType()->isFloatingPointTy()) {
- ResR = Builder.CreateFSub(Op.LHS.first, Op.RHS.first, "sub.r");
- ResI = Builder.CreateFSub(Op.LHS.second, Op.RHS.second, "sub.i");
+ ResR = Builder.CreateFSub(Op.LHS.first, Op.RHS.first, "sub.r");
+ if (Op.LHS.second && Op.RHS.second)
+ ResI = Builder.CreateFSub(Op.LHS.second, Op.RHS.second, "sub.i");
+ else
+ ResI = Op.LHS.second ? Op.LHS.second
+ : Builder.CreateFNeg(Op.RHS.second, "sub.i");
+ assert(ResI && "Only one operand may be real!");
} else {
- ResR = Builder.CreateSub(Op.LHS.first, Op.RHS.first, "sub.r");
+ ResR = Builder.CreateSub(Op.LHS.first, Op.RHS.first, "sub.r");
+ assert(Op.LHS.second && Op.RHS.second &&
+ "Both operands of integer complex operators must be complex!");
ResI = Builder.CreateSub(Op.LHS.second, Op.RHS.second, "sub.i");
}
return ComplexPairTy(ResR, ResI);
}
+/// \brief Emit a libcall for a binary operation on complex types.
+ComplexPairTy ComplexExprEmitter::EmitComplexBinOpLibCall(StringRef LibCallName,
+ const BinOpInfo &Op) {
+ CallArgList Args;
+ Args.add(RValue::get(Op.LHS.first),
+ Op.Ty->castAs<ComplexType>()->getElementType());
+ Args.add(RValue::get(Op.LHS.second),
+ Op.Ty->castAs<ComplexType>()->getElementType());
+ Args.add(RValue::get(Op.RHS.first),
+ Op.Ty->castAs<ComplexType>()->getElementType());
+ Args.add(RValue::get(Op.RHS.second),
+ Op.Ty->castAs<ComplexType>()->getElementType());
+
+ // We *must* use the full CG function call building logic here because the
+ // complex type has special ABI handling. We also should not forget about
+ // special calling convention which may be used for compiler builtins.
+ const CGFunctionInfo &FuncInfo =
+ CGF.CGM.getTypes().arrangeFreeFunctionCall(
+ Op.Ty, Args, FunctionType::ExtInfo(/* No CC here - will be added later */),
+ RequiredArgs::All);
+ llvm::FunctionType *FTy = CGF.CGM.getTypes().GetFunctionType(FuncInfo);
+ llvm::Constant *Func = CGF.CGM.CreateBuiltinFunction(FTy, LibCallName);
+ llvm::Instruction *Call;
+
+ RValue Res = CGF.EmitCall(FuncInfo, Func, ReturnValueSlot(), Args,
+ nullptr, &Call);
+ cast<llvm::CallInst>(Call)->setCallingConv(CGF.CGM.getBuiltinCC());
+ cast<llvm::CallInst>(Call)->setDoesNotThrow();
+
+ return Res.getComplexVal();
+}
+
+/// \brief Lookup the libcall name for a given floating point type complex
+/// multiply.
+static StringRef getComplexMultiplyLibCallName(llvm::Type *Ty) {
+ switch (Ty->getTypeID()) {
+ default:
+ llvm_unreachable("Unsupported floating point type!");
+ case llvm::Type::HalfTyID:
+ return "__mulhc3";
+ case llvm::Type::FloatTyID:
+ return "__mulsc3";
+ case llvm::Type::DoubleTyID:
+ return "__muldc3";
+ case llvm::Type::PPC_FP128TyID:
+ return "__multc3";
+ case llvm::Type::X86_FP80TyID:
+ return "__mulxc3";
+ case llvm::Type::FP128TyID:
+ return "__multc3";
+ }
+}
+// See C11 Annex G.5.1 for the semantics of multiplicative operators on complex
+// typed values.
ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
using llvm::Value;
Value *ResR, *ResI;
+ llvm::MDBuilder MDHelper(CGF.getLLVMContext());
if (Op.LHS.first->getType()->isFloatingPointTy()) {
- Value *ResRl = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul.rl");
- Value *ResRr = Builder.CreateFMul(Op.LHS.second, Op.RHS.second,"mul.rr");
- ResR = Builder.CreateFSub(ResRl, ResRr, "mul.r");
+ // The general formulation is:
+ // (a + ib) * (c + id) = (a * c - b * d) + i(a * d + b * c)
+ //
+ // But we can fold away components which would be zero due to a real
+ // operand according to C11 Annex G.5.1p2.
+ // FIXME: C11 also provides for imaginary types which would allow folding
+ // still more of this within the type system.
+
+ if (Op.LHS.second && Op.RHS.second) {
+ // If both operands are complex, emit the core math directly, and then
+ // test for NaNs. If we find NaNs in the result, we delegate to a libcall
+ // to carefully re-compute the correct infinity representation if
+ // possible. The expectation is that the presence of NaNs here is
+ // *extremely* rare, and so the cost of the libcall is almost irrelevant.
+ // This is good, because the libcall re-computes the core multiplication
+ // exactly the same as we do here and re-tests for NaNs in order to be
+ // a generic complex*complex libcall.
+
+ // First compute the four products.
+ Value *AC = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul_ac");
+ Value *BD = Builder.CreateFMul(Op.LHS.second, Op.RHS.second, "mul_bd");
+ Value *AD = Builder.CreateFMul(Op.LHS.first, Op.RHS.second, "mul_ad");
+ Value *BC = Builder.CreateFMul(Op.LHS.second, Op.RHS.first, "mul_bc");
+
+ // The real part is the difference of the first two, the imaginary part is
+ // the sum of the second.
+ ResR = Builder.CreateFSub(AC, BD, "mul_r");
+ ResI = Builder.CreateFAdd(AD, BC, "mul_i");
+
+ // Emit the test for the real part becoming NaN and create a branch to
+ // handle it. We test for NaN by comparing the number to itself.
+ Value *IsRNaN = Builder.CreateFCmpUNO(ResR, ResR, "isnan_cmp");
+ llvm::BasicBlock *ContBB = CGF.createBasicBlock("complex_mul_cont");
+ llvm::BasicBlock *INaNBB = CGF.createBasicBlock("complex_mul_imag_nan");
+ llvm::Instruction *Branch = Builder.CreateCondBr(IsRNaN, INaNBB, ContBB);
+ llvm::BasicBlock *OrigBB = Branch->getParent();
+
+ // Give hint that we very much don't expect to see NaNs.
+ // Value chosen to match UR_NONTAKEN_WEIGHT, see BranchProbabilityInfo.cpp
+ llvm::MDNode *BrWeight = MDHelper.createBranchWeights(1, (1U << 20) - 1);
+ Branch->setMetadata(llvm::LLVMContext::MD_prof, BrWeight);
+
+ // Now test the imaginary part and create its branch.
+ CGF.EmitBlock(INaNBB);
+ Value *IsINaN = Builder.CreateFCmpUNO(ResI, ResI, "isnan_cmp");
+ llvm::BasicBlock *LibCallBB = CGF.createBasicBlock("complex_mul_libcall");
+ Branch = Builder.CreateCondBr(IsINaN, LibCallBB, ContBB);
+ Branch->setMetadata(llvm::LLVMContext::MD_prof, BrWeight);
+
+ // Now emit the libcall on this slowest of the slow paths.
+ CGF.EmitBlock(LibCallBB);
+ Value *LibCallR, *LibCallI;
+ std::tie(LibCallR, LibCallI) = EmitComplexBinOpLibCall(
+ getComplexMultiplyLibCallName(Op.LHS.first->getType()), Op);
+ Builder.CreateBr(ContBB);
+
+ // Finally continue execution by phi-ing together the different
+ // computation paths.
+ CGF.EmitBlock(ContBB);
+ llvm::PHINode *RealPHI = Builder.CreatePHI(ResR->getType(), 3, "real_mul_phi");
+ RealPHI->addIncoming(ResR, OrigBB);
+ RealPHI->addIncoming(ResR, INaNBB);
+ RealPHI->addIncoming(LibCallR, LibCallBB);
+ llvm::PHINode *ImagPHI = Builder.CreatePHI(ResI->getType(), 3, "imag_mul_phi");
+ ImagPHI->addIncoming(ResI, OrigBB);
+ ImagPHI->addIncoming(ResI, INaNBB);
+ ImagPHI->addIncoming(LibCallI, LibCallBB);
+ return ComplexPairTy(RealPHI, ImagPHI);
+ }
+ assert((Op.LHS.second || Op.RHS.second) &&
+ "At least one operand must be complex!");
+
+ // If either of the operands is a real rather than a complex, the
+ // imaginary component is ignored when computing the real component of the
+ // result.
+ ResR = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul.rl");
- Value *ResIl = Builder.CreateFMul(Op.LHS.second, Op.RHS.first, "mul.il");
- Value *ResIr = Builder.CreateFMul(Op.LHS.first, Op.RHS.second, "mul.ir");
- ResI = Builder.CreateFAdd(ResIl, ResIr, "mul.i");
+ ResI = Op.LHS.second
+ ? Builder.CreateFMul(Op.LHS.second, Op.RHS.first, "mul.il")
+ : Builder.CreateFMul(Op.LHS.first, Op.RHS.second, "mul.ir");
} else {
+ assert(Op.LHS.second && Op.RHS.second &&
+ "Both operands of integer complex operators must be complex!");
Value *ResRl = Builder.CreateMul(Op.LHS.first, Op.RHS.first, "mul.rl");
- Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second,"mul.rr");
- ResR = Builder.CreateSub(ResRl, ResRr, "mul.r");
+ Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second, "mul.rr");
+ ResR = Builder.CreateSub(ResRl, ResRr, "mul.r");
Value *ResIl = Builder.CreateMul(Op.LHS.second, Op.RHS.first, "mul.il");
Value *ResIr = Builder.CreateMul(Op.LHS.first, Op.RHS.second, "mul.ir");
- ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i");
+ ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i");
}
return ComplexPairTy(ResR, ResI);
}
+// See C11 Annex G.5.1 for the semantics of multiplicative operators on complex
+// typed values.
ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
llvm::Value *DSTr, *DSTi;
- if (Op.LHS.first->getType()->isFloatingPointTy()) {
- // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
- llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr); // a*c
- llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi); // b*d
- llvm::Value *Tmp3 = Builder.CreateFAdd(Tmp1, Tmp2); // ac+bd
-
- llvm::Value *Tmp4 = Builder.CreateFMul(RHSr, RHSr); // c*c
- llvm::Value *Tmp5 = Builder.CreateFMul(RHSi, RHSi); // d*d
- llvm::Value *Tmp6 = Builder.CreateFAdd(Tmp4, Tmp5); // cc+dd
-
- llvm::Value *Tmp7 = Builder.CreateFMul(LHSi, RHSr); // b*c
- llvm::Value *Tmp8 = Builder.CreateFMul(LHSr, RHSi); // a*d
- llvm::Value *Tmp9 = Builder.CreateFSub(Tmp7, Tmp8); // bc-ad
+ if (LHSr->getType()->isFloatingPointTy()) {
+ // If we have a complex operand on the RHS, we delegate to a libcall to
+ // handle all of the complexities and minimize underflow/overflow cases.
+ //
+ // FIXME: We would be able to avoid the libcall in many places if we
+ // supported imaginary types in addition to complex types.
+ if (RHSi) {
+ BinOpInfo LibCallOp = Op;
+ // If LHS was a real, supply a null imaginary part.
+ if (!LHSi)
+ LibCallOp.LHS.second = llvm::Constant::getNullValue(LHSr->getType());
+
+ StringRef LibCallName;
+ switch (LHSr->getType()->getTypeID()) {
+ default:
+ llvm_unreachable("Unsupported floating point type!");
+ case llvm::Type::HalfTyID:
+ return EmitComplexBinOpLibCall("__divhc3", LibCallOp);
+ case llvm::Type::FloatTyID:
+ return EmitComplexBinOpLibCall("__divsc3", LibCallOp);
+ case llvm::Type::DoubleTyID:
+ return EmitComplexBinOpLibCall("__divdc3", LibCallOp);
+ case llvm::Type::PPC_FP128TyID:
+ return EmitComplexBinOpLibCall("__divtc3", LibCallOp);
+ case llvm::Type::X86_FP80TyID:
+ return EmitComplexBinOpLibCall("__divxc3", LibCallOp);
+ case llvm::Type::FP128TyID:
+ return EmitComplexBinOpLibCall("__divtc3", LibCallOp);
+ }
+ }
+ assert(LHSi && "Can have at most one non-complex operand!");
- DSTr = Builder.CreateFDiv(Tmp3, Tmp6);
- DSTi = Builder.CreateFDiv(Tmp9, Tmp6);
+ DSTr = Builder.CreateFDiv(LHSr, RHSr);
+ DSTi = Builder.CreateFDiv(LHSi, RHSr);
} else {
+ assert(Op.LHS.second && Op.RHS.second &&
+ "Both operands of integer complex operators must be complex!");
// (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr); // a*c
llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi); // b*d
@@ -626,8 +797,15 @@ ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
BinOpInfo Ops;
- Ops.LHS = Visit(E->getLHS());
- Ops.RHS = Visit(E->getRHS());
+ if (E->getLHS()->getType()->isRealFloatingType())
+ Ops.LHS = ComplexPairTy(CGF.EmitScalarExpr(E->getLHS()), nullptr);
+ else
+ Ops.LHS = Visit(E->getLHS());
+ if (E->getRHS()->getType()->isRealFloatingType())
+ Ops.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr);
+ else
+ Ops.RHS = Visit(E->getRHS());
+
Ops.Ty = E->getType();
return Ops;
}
@@ -647,12 +825,19 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E,
// __block variables need to have the rhs evaluated first, plus this should
// improve codegen a little.
OpInfo.Ty = E->getComputationResultType();
+ QualType ComplexElementTy = cast<ComplexType>(OpInfo.Ty)->getElementType();
// The RHS should have been converted to the computation type.
- assert(OpInfo.Ty->isAnyComplexType());
- assert(CGF.getContext().hasSameUnqualifiedType(OpInfo.Ty,
- E->getRHS()->getType()));
- OpInfo.RHS = Visit(E->getRHS());
+ if (E->getRHS()->getType()->isRealFloatingType()) {
+ assert(
+ CGF.getContext()
+ .hasSameUnqualifiedType(ComplexElementTy, E->getRHS()->getType()));
+ OpInfo.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr);
+ } else {
+ assert(CGF.getContext()
+ .hasSameUnqualifiedType(OpInfo.Ty, E->getRHS()->getType()));
+ OpInfo.RHS = Visit(E->getRHS());
+ }
LValue LHS = CGF.EmitLValue(E->getLHS());
@@ -662,7 +847,15 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E,
OpInfo.LHS = EmitComplexToComplexCast(LHSVal, LHSTy, OpInfo.Ty);
} else {
llvm::Value *LHSVal = CGF.EmitLoadOfScalar(LHS, E->getExprLoc());
- OpInfo.LHS = EmitScalarToComplexCast(LHSVal, LHSTy, OpInfo.Ty);
+ // For floating point real operands we can directly pass the scalar form
+ // to the binary operator emission and potentially get more efficient code.
+ if (LHSTy->isRealFloatingType()) {
+ if (!CGF.getContext().hasSameUnqualifiedType(ComplexElementTy, LHSTy))
+ LHSVal = CGF.EmitScalarConversion(LHSVal, LHSTy, ComplexElementTy);
+ OpInfo.LHS = ComplexPairTy(LHSVal, nullptr);
+ } else {
+ OpInfo.LHS = EmitScalarToComplexCast(LHSVal, LHSTy, OpInfo.Ty);
+ }
}
// Expand the binary operator.
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index b508dcb446fb..54f7eee6791e 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -104,16 +104,7 @@ AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst) {
// Round up the field offset to the alignment of the field type.
CharUnits AlignedNextFieldOffsetInChars =
- NextFieldOffsetInChars.RoundUpToAlignment(FieldAlignment);
-
- if (AlignedNextFieldOffsetInChars > FieldOffsetInChars) {
- assert(!Packed && "Alignment is wrong even with a packed struct!");
-
- // Convert the struct to a packed struct.
- ConvertStructToPacked();
-
- AlignedNextFieldOffsetInChars = NextFieldOffsetInChars;
- }
+ NextFieldOffsetInChars.RoundUpToAlignment(FieldAlignment);
if (AlignedNextFieldOffsetInChars < FieldOffsetInChars) {
// We need to append padding.
@@ -122,6 +113,24 @@ AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst) {
assert(NextFieldOffsetInChars == FieldOffsetInChars &&
"Did not add enough padding!");
+ AlignedNextFieldOffsetInChars =
+ NextFieldOffsetInChars.RoundUpToAlignment(FieldAlignment);
+ }
+
+ if (AlignedNextFieldOffsetInChars > FieldOffsetInChars) {
+ assert(!Packed && "Alignment is wrong even with a packed struct!");
+
+ // Convert the struct to a packed struct.
+ ConvertStructToPacked();
+
+ // After we pack the struct, we may need to insert padding.
+ if (NextFieldOffsetInChars < FieldOffsetInChars) {
+ // We need to append padding.
+ AppendPadding(FieldOffsetInChars - NextFieldOffsetInChars);
+
+ assert(NextFieldOffsetInChars == FieldOffsetInChars &&
+ "Did not add enough padding!");
+ }
AlignedNextFieldOffsetInChars = NextFieldOffsetInChars;
}
@@ -486,10 +495,14 @@ llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) {
// No tail padding is necessary.
} else {
// Append tail padding if necessary.
- AppendTailPadding(LayoutSizeInChars);
-
CharUnits LLVMSizeInChars =
- NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment);
+ NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment);
+
+ if (LLVMSizeInChars != LayoutSizeInChars)
+ AppendTailPadding(LayoutSizeInChars);
+
+ LLVMSizeInChars =
+ NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment);
// Check if we need to convert the struct to a packed struct.
if (NextFieldOffsetInChars <= LayoutSizeInChars &&
@@ -501,7 +514,10 @@ llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) {
"Converting to packed did not help!");
}
- assert(LayoutSizeInChars == NextFieldOffsetInChars &&
+ LLVMSizeInChars =
+ NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment);
+
+ assert(LayoutSizeInChars == LLVMSizeInChars &&
"Tail padding mismatch!");
}
@@ -734,6 +750,20 @@ public:
// initialise any elements that have not been initialised explicitly
unsigned NumInitableElts = std::min(NumInitElements, NumElements);
+ // Initialize remaining array elements.
+ // FIXME: This doesn't handle member pointers correctly!
+ llvm::Constant *fillC;
+ if (Expr *filler = ILE->getArrayFiller())
+ fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF);
+ else
+ fillC = llvm::Constant::getNullValue(ElemTy);
+ if (!fillC)
+ return nullptr;
+
+ // Try to use a ConstantAggregateZero if we can.
+ if (fillC->isNullValue() && !NumInitableElts)
+ return llvm::ConstantAggregateZero::get(AType);
+
// Copy initializer elements.
std::vector<llvm::Constant*> Elts;
Elts.reserve(NumInitableElts + NumElements);
@@ -748,15 +778,6 @@ public:
Elts.push_back(C);
}
- // Initialize remaining array elements.
- // FIXME: This doesn't handle member pointers correctly!
- llvm::Constant *fillC;
- if (Expr *filler = ILE->getArrayFiller())
- fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF);
- else
- fillC = llvm::Constant::getNullValue(ElemTy);
- if (!fillC)
- return nullptr;
RewriteType |= (fillC->getType() != ElemTy);
Elts.resize(NumElements, fillC);
@@ -869,7 +890,8 @@ public:
if (VD->isFileVarDecl() || VD->hasExternalStorage())
return CGM.GetAddrOfGlobalVar(VD);
else if (VD->isLocalVarDecl())
- return CGM.getStaticLocalDeclAddress(VD);
+ return CGM.getOrCreateStaticVarDecl(
+ *VD, CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false));
}
}
return nullptr;
@@ -1126,13 +1148,14 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
// FIXME: the target may want to specify that this is packed.
llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
Complex[1]->getType(),
- NULL);
+ nullptr);
return llvm::ConstantStruct::get(STy, Complex);
}
case APValue::Float: {
const llvm::APFloat &Init = Value.getFloat();
if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf &&
- !Context.getLangOpts().NativeHalfType)
+ !Context.getLangOpts().NativeHalfType &&
+ !Context.getLangOpts().HalfArgsAndReturns)
return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt());
else
return llvm::ConstantFP::get(VMContext, Init);
@@ -1148,7 +1171,7 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
// FIXME: the target may want to specify that this is packed.
llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
Complex[1]->getType(),
- NULL);
+ nullptr);
return llvm::ConstantStruct::get(STy, Complex);
}
case APValue::Vector: {
@@ -1189,9 +1212,6 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
unsigned NumElements = Value.getArraySize();
unsigned NumInitElts = Value.getArrayInitializedElts();
- std::vector<llvm::Constant*> Elts;
- Elts.reserve(NumElements);
-
// Emit array filler, if there is one.
llvm::Constant *Filler = nullptr;
if (Value.hasArrayFiller())
@@ -1199,7 +1219,18 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
CAT->getElementType(), CGF);
// Emit initializer elements.
- llvm::Type *CommonElementType = nullptr;
+ llvm::Type *CommonElementType =
+ getTypes().ConvertType(CAT->getElementType());
+
+ // Try to use a ConstantAggregateZero if we can.
+ if (Filler && Filler->isNullValue() && !NumInitElts) {
+ llvm::ArrayType *AType =
+ llvm::ArrayType::get(CommonElementType, NumElements);
+ return llvm::ConstantAggregateZero::get(AType);
+ }
+
+ std::vector<llvm::Constant*> Elts;
+ Elts.reserve(NumElements);
for (unsigned I = 0; I < NumElements; ++I) {
llvm::Constant *C = Filler;
if (I < NumInitElts)
@@ -1268,83 +1299,6 @@ CodeGenModule::getMemberPointerConstant(const UnaryOperator *uo) {
return getCXXABI().EmitMemberDataPointer(type, chars);
}
-static void
-FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
- SmallVectorImpl<llvm::Constant *> &Elements,
- uint64_t StartOffset) {
- assert(StartOffset % CGM.getContext().getCharWidth() == 0 &&
- "StartOffset not byte aligned!");
-
- if (CGM.getTypes().isZeroInitializable(T))
- return;
-
- if (const ConstantArrayType *CAT =
- CGM.getContext().getAsConstantArrayType(T)) {
- QualType ElementTy = CAT->getElementType();
- uint64_t ElementSize = CGM.getContext().getTypeSize(ElementTy);
-
- for (uint64_t I = 0, E = CAT->getSize().getZExtValue(); I != E; ++I) {
- FillInNullDataMemberPointers(CGM, ElementTy, Elements,
- StartOffset + I * ElementSize);
- }
- } else if (const RecordType *RT = T->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
-
- // Go through all bases and fill in any null pointer to data members.
- for (const auto &I : RD->bases()) {
- if (I.isVirtual()) {
- // Ignore virtual bases.
- continue;
- }
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
-
- // Ignore empty bases.
- if (BaseDecl->isEmpty())
- continue;
-
- // Ignore bases that don't have any pointer to data members.
- if (CGM.getTypes().isZeroInitializable(BaseDecl))
- continue;
-
- uint64_t BaseOffset =
- CGM.getContext().toBits(Layout.getBaseClassOffset(BaseDecl));
- FillInNullDataMemberPointers(CGM, I.getType(),
- Elements, StartOffset + BaseOffset);
- }
-
- // Visit all fields.
- unsigned FieldNo = 0;
- for (RecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end(); I != E; ++I, ++FieldNo) {
- QualType FieldType = I->getType();
-
- if (CGM.getTypes().isZeroInitializable(FieldType))
- continue;
-
- uint64_t FieldOffset = StartOffset + Layout.getFieldOffset(FieldNo);
- FillInNullDataMemberPointers(CGM, FieldType, Elements, FieldOffset);
- }
- } else {
- assert(T->isMemberPointerType() && "Should only see member pointers here!");
- assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
- "Should only see pointers to data members here!");
-
- CharUnits StartIndex = CGM.getContext().toCharUnitsFromBits(StartOffset);
- CharUnits EndIndex = StartIndex + CGM.getContext().getTypeSizeInChars(T);
-
- // FIXME: hardcodes Itanium member pointer representation!
- llvm::Constant *NegativeOne =
- llvm::ConstantInt::get(CGM.Int8Ty, -1ULL, /*isSigned*/true);
-
- // Fill in the null data member pointer.
- for (CharUnits I = StartIndex; I != EndIndex; ++I)
- Elements[I.getQuantity()] = NegativeOne;
- }
-}
-
static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
llvm::Type *baseType,
const CXXRecordDecl *base);
@@ -1433,32 +1387,8 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
if (baseLayout.isZeroInitializableAsBase())
return llvm::Constant::getNullValue(baseType);
- // If the base type is a struct, we can just use its null constant.
- if (isa<llvm::StructType>(baseType)) {
- return EmitNullConstant(CGM, base, /*complete*/ false);
- }
-
- // Otherwise, some bases are represented as arrays of i8 if the size
- // of the base is smaller than its corresponding LLVM type. Figure
- // out how many elements this base array has.
- llvm::ArrayType *baseArrayType = cast<llvm::ArrayType>(baseType);
- unsigned numBaseElements = baseArrayType->getNumElements();
-
- // Fill in null data member pointers.
- SmallVector<llvm::Constant *, 16> baseElements(numBaseElements);
- FillInNullDataMemberPointers(CGM, CGM.getContext().getTypeDeclType(base),
- baseElements, 0);
-
- // Now go through all other elements and zero them out.
- if (numBaseElements) {
- llvm::Constant *i8_zero = llvm::Constant::getNullValue(CGM.Int8Ty);
- for (unsigned i = 0; i != numBaseElements; ++i) {
- if (!baseElements[i])
- baseElements[i] = i8_zero;
- }
- }
-
- return llvm::ConstantArray::get(baseArrayType, baseElements);
+ // Otherwise, we can just use its null constant.
+ return EmitNullConstant(CGM, base, /*asCompleteObject=*/false);
}
llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
@@ -1489,9 +1419,7 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
assert(T->isMemberPointerType() && "Should only see member pointers here!");
assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
"Should only see pointers to data members here!");
-
- // Itanium C++ ABI 2.3:
- // A NULL pointer is represented as -1.
+
return getCXXABI().EmitNullMemberPointer(T->castAs<MemberPointerType>());
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 140e9aa3445f..a9cbf05da104 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -85,18 +85,54 @@ public:
return CGF.EmitCheckedLValue(E, TCK);
}
- void EmitBinOpCheck(Value *Check, const BinOpInfo &Info);
+ void EmitBinOpCheck(ArrayRef<std::pair<Value *, SanitizerKind>> Checks,
+ const BinOpInfo &Info);
Value *EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
return CGF.EmitLoadOfLValue(LV, Loc).getScalarVal();
}
+ void EmitLValueAlignmentAssumption(const Expr *E, Value *V) {
+ const AlignValueAttr *AVAttr = nullptr;
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+ const ValueDecl *VD = DRE->getDecl();
+
+ if (VD->getType()->isReferenceType()) {
+ if (const auto *TTy =
+ dyn_cast<TypedefType>(VD->getType().getNonReferenceType()))
+ AVAttr = TTy->getDecl()->getAttr<AlignValueAttr>();
+ } else {
+ // Assumptions for function parameters are emitted at the start of the
+ // function, so there is no need to repeat that here.
+ if (isa<ParmVarDecl>(VD))
+ return;
+
+ AVAttr = VD->getAttr<AlignValueAttr>();
+ }
+ }
+
+ if (!AVAttr)
+ if (const auto *TTy =
+ dyn_cast<TypedefType>(E->getType()))
+ AVAttr = TTy->getDecl()->getAttr<AlignValueAttr>();
+
+ if (!AVAttr)
+ return;
+
+ Value *AlignmentValue = CGF.EmitScalarExpr(AVAttr->getAlignment());
+ llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(AlignmentValue);
+ CGF.EmitAlignmentAssumption(V, AlignmentCI->getZExtValue());
+ }
+
/// EmitLoadOfLValue - Given an expression with complex type that represents a
/// value l-value, this method emits the address of the l-value, then loads
/// and returns the result.
Value *EmitLoadOfLValue(const Expr *E) {
- return EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::TCK_Load),
- E->getExprLoc());
+ Value *V = EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::TCK_Load),
+ E->getExprLoc());
+
+ EmitLValueAlignmentAssumption(E, V);
+ return V;
}
/// EmitConversionToBool - Convert the specified expression value to a
@@ -160,6 +196,7 @@ public:
//===--------------------------------------------------------------------===//
Value *Visit(Expr *E) {
+ ApplyDebugLocation DL(CGF, E->getLocStart());
return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E);
}
@@ -274,6 +311,10 @@ public:
Value *VisitExplicitCastExpr(ExplicitCastExpr *E) {
if (E->getType()->isVariablyModifiedType())
CGF.EmitVariablyModifiedType(E->getType());
+
+ if (CGDebugInfo *DI = CGF.getDebugInfo())
+ DI->EmitExplicitCastType(E->getType());
+
return VisitCastExpr(E);
}
Value *VisitCastExpr(CastExpr *E);
@@ -282,7 +323,10 @@ public:
if (E->getCallReturnType()->isReferenceType())
return EmitLoadOfLValue(E);
- return CGF.EmitCallExpr(E).getScalarVal();
+ Value *V = CGF.EmitCallExpr(E).getScalarVal();
+
+ EmitLValueAlignmentAssumption(E, V);
+ return V;
}
Value *VisitStmtExpr(const StmtExpr *E);
@@ -410,7 +454,7 @@ public:
case LangOptions::SOB_Defined:
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
case LangOptions::SOB_Undefined:
- if (!CGF.SanOpts->SignedIntegerOverflow)
+ if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
// Fall through.
case LangOptions::SOB_Trapping:
@@ -418,7 +462,8 @@ public:
}
}
- if (Ops.Ty->isUnsignedIntegerType() && CGF.SanOpts->UnsignedIntegerOverflow)
+ if (Ops.Ty->isUnsignedIntegerType() &&
+ CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow))
return EmitOverflowCheckedBinOp(Ops);
if (Ops.LHS->getType()->isFPOrFPVectorTy())
@@ -682,8 +727,8 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
CGF.EmitCheckTypeDescriptor(OrigSrcType),
CGF.EmitCheckTypeDescriptor(DstType)
};
- CGF.EmitCheck(Check, "float_cast_overflow", StaticArgs, OrigSrc,
- CodeGenFunction::CRK_Recoverable);
+ CGF.EmitCheck(std::make_pair(Check, SanitizerKind::FloatCastOverflow),
+ "float_cast_overflow", StaticArgs, OrigSrc);
}
/// EmitScalarConversion - Emit a conversion from the specified type to the
@@ -701,7 +746,8 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
llvm::Type *SrcTy = Src->getType();
// If casting to/from storage-only half FP, use special intrinsics.
- if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
+ if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
+ !CGF.getContext().getLangOpts().HalfArgsAndReturns) {
Src = Builder.CreateCall(
CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
CGF.CGM.FloatTy),
@@ -767,13 +813,14 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// An overflowing conversion has undefined behavior if either the source type
// or the destination type is a floating-point type.
- if (CGF.SanOpts->FloatCastOverflow &&
+ if (CGF.SanOpts.has(SanitizerKind::FloatCastOverflow) &&
(OrigSrcType->isFloatingType() || DstType->isFloatingType()))
EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType,
DstTy);
// Cast to half via float
- if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType)
+ if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
+ !CGF.getContext().getLangOpts().HalfArgsAndReturns)
DstTy = CGF.FloatTy;
if (isa<llvm::IntegerType>(SrcTy)) {
@@ -839,8 +886,10 @@ Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
/// \brief Emit a sanitization check for the given "binary" operation (which
/// might actually be a unary increment which has been lowered to a binary
-/// operation). The check passes if \p Check, which is an \c i1, is \c true.
-void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
+/// operation). The check passes if all values in \p Checks (which are \c i1),
+/// are \c true.
+void ScalarExprEmitter::EmitBinOpCheck(
+ ArrayRef<std::pair<Value *, SanitizerKind>> Checks, const BinOpInfo &Info) {
assert(CGF.IsSanitizerScope);
StringRef CheckName;
SmallVector<llvm::Constant *, 4> StaticData;
@@ -870,7 +919,7 @@ void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
CheckName = "divrem_overflow";
StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty));
} else {
- // Signed arithmetic overflow (+, -, *).
+ // Arithmetic overflow (+, -, *).
switch (Opcode) {
case BO_Add: CheckName = "add_overflow"; break;
case BO_Sub: CheckName = "sub_overflow"; break;
@@ -883,8 +932,7 @@ void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
DynamicData.push_back(Info.RHS);
}
- CGF.EmitCheck(Check, CheckName, StaticData, DynamicData,
- CodeGenFunction::CRK_Recoverable);
+ CGF.EmitCheck(Checks, CheckName, StaticData, DynamicData);
}
//===----------------------------------------------------------------------===//
@@ -1076,7 +1124,7 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
Value *Idx = Visit(E->getIdx());
QualType IdxTy = E->getIdx()->getType();
- if (CGF.SanOpts->ArrayBounds)
+ if (CGF.SanOpts.has(SanitizerKind::ArrayBounds))
CGF.EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, /*Accessed*/true);
return Builder.CreateExtractElement(Base, Idx, "vecext");
@@ -1304,8 +1352,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
llvm::Type *DstTy = ConvertType(DestTy);
if (SrcTy->isPtrOrPtrVectorTy() && DstTy->isPtrOrPtrVectorTy() &&
SrcTy->getPointerAddressSpace() != DstTy->getPointerAddressSpace()) {
- llvm::Type *MidTy = CGF.CGM.getDataLayout().getIntPtrType(SrcTy);
- return Builder.CreateIntToPtr(Builder.CreatePtrToInt(Src, MidTy), DstTy);
+ llvm_unreachable("wrong cast for pointers in different address spaces"
+ "(must be an address space cast)!");
}
return Builder.CreateBitCast(Src, DstTy);
}
@@ -1344,9 +1392,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
E->getType()->getPointeeCXXRecordDecl();
assert(DerivedClassDecl && "DerivedToBase arg isn't a C++ object pointer!");
- return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl,
- CE->path_begin(), CE->path_end(),
- ShouldNullCheckClassCastValue(CE));
+ return CGF.GetAddressOfBaseClass(
+ Visit(E), DerivedClassDecl, CE->path_begin(), CE->path_end(),
+ ShouldNullCheckClassCastValue(CE), CE->getExprLoc());
}
case CK_Dynamic: {
Value *V = Visit(const_cast<Expr*>(E));
@@ -1364,8 +1412,11 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
// anything here.
if (!E->getType()->isVariableArrayType()) {
assert(isa<llvm::PointerType>(V->getType()) && "Expected pointer");
- assert(isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType())
- ->getElementType()) &&
+ V = CGF.Builder.CreatePointerCast(
+ V, ConvertType(E->getType())->getPointerTo(
+ V->getType()->getPointerAddressSpace()));
+
+ assert(isa<llvm::ArrayType>(V->getType()->getPointerElementType()) &&
"Expected pointer to array");
V = Builder.CreateStructGEP(V, 0, "arraydecay");
}
@@ -1528,7 +1579,7 @@ EmitAddConsiderOverflowBehavior(const UnaryOperator *E,
case LangOptions::SOB_Defined:
return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec");
case LangOptions::SOB_Undefined:
- if (!CGF.SanOpts->SignedIntegerOverflow)
+ if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec");
// Fall through.
case LangOptions::SOB_Trapping:
@@ -1576,9 +1627,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// checking, and fall into the slow path with the atomic cmpxchg loop.
if (!type->isBooleanType() && type->isIntegerType() &&
!(type->isUnsignedIntegerType() &&
- CGF.SanOpts->UnsignedIntegerOverflow) &&
+ CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) &&
CGF.getLangOpts().getSignedOverflowBehavior() !=
- LangOptions::SOB_Trapping) {
+ LangOptions::SOB_Trapping) {
llvm::AtomicRMWInst::BinOp aop = isInc ? llvm::AtomicRMWInst::Add :
llvm::AtomicRMWInst::Sub;
llvm::Instruction::BinaryOps op = isInc ? llvm::Instruction::Add :
@@ -1627,7 +1678,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (CanOverflow && type->isSignedIntegerOrEnumerationType()) {
value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
} else if (CanOverflow && type->isUnsignedIntegerType() &&
- CGF.SanOpts->UnsignedIntegerOverflow) {
+ CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {
BinOpInfo BinOp;
BinOp.LHS = value;
BinOp.RHS = llvm::ConstantInt::get(value->getType(), 1, false);
@@ -1691,7 +1742,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Add the inc/dec to the real part.
llvm::Value *amt;
- if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
+ if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
+ !CGF.getContext().getLangOpts().HalfArgsAndReturns) {
// Another special case: half FP increment should be done via float
value = Builder.CreateCall(
CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
@@ -1714,7 +1766,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
}
value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec");
- if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType)
+ if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
+ !CGF.getContext().getLangOpts().HalfArgsAndReturns)
value = Builder.CreateCall(
CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16,
CGF.CGM.FloatTy),
@@ -1740,11 +1793,11 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (atomicPHI) {
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
- llvm::Value *pair = Builder.CreateAtomicCmpXchg(
- LV.getAddress(), atomicPHI, CGF.EmitToMemory(value, type),
- llvm::SequentiallyConsistent, llvm::SequentiallyConsistent);
- llvm::Value *old = Builder.CreateExtractValue(pair, 0);
- llvm::Value *success = Builder.CreateExtractValue(pair, 1);
+ auto Pair = CGF.EmitAtomicCompareExchange(
+ LV, RValue::get(atomicPHI), RValue::get(CGF.EmitToMemory(value, type)),
+ E->getExprLoc());
+ llvm::Value *old = Pair.first.getScalarVal();
+ llvm::Value *success = Pair.second.getScalarVal();
atomicPHI->addIncoming(old, opBB);
Builder.CreateCondBr(success, contBB, opBB);
Builder.SetInsertPoint(contBB);
@@ -2019,10 +2072,10 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
if (const AtomicType *atomicTy = LHSTy->getAs<AtomicType>()) {
QualType type = atomicTy->getValueType();
if (!type->isBooleanType() && type->isIntegerType() &&
- !(type->isUnsignedIntegerType() &&
- CGF.SanOpts->UnsignedIntegerOverflow) &&
- CGF.getLangOpts().getSignedOverflowBehavior() !=
- LangOptions::SOB_Trapping) {
+ !(type->isUnsignedIntegerType() &&
+ CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) &&
+ CGF.getLangOpts().getSignedOverflowBehavior() !=
+ LangOptions::SOB_Trapping) {
llvm::AtomicRMWInst::BinOp aop = llvm::AtomicRMWInst::BAD_BINOP;
switch (OpInfo.Opcode) {
// We don't have atomicrmw operands for *, %, /, <<, >>
@@ -2084,11 +2137,11 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
if (atomicPHI) {
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
- llvm::Value *pair = Builder.CreateAtomicCmpXchg(
- LHSLV.getAddress(), atomicPHI, CGF.EmitToMemory(Result, LHSTy),
- llvm::SequentiallyConsistent, llvm::SequentiallyConsistent);
- llvm::Value *old = Builder.CreateExtractValue(pair, 0);
- llvm::Value *success = Builder.CreateExtractValue(pair, 1);
+ auto Pair = CGF.EmitAtomicCompareExchange(
+ LHSLV, RValue::get(atomicPHI),
+ RValue::get(CGF.EmitToMemory(Result, LHSTy)), E->getExprLoc());
+ llvm::Value *old = Pair.first.getScalarVal();
+ llvm::Value *success = Pair.second.getScalarVal();
atomicPHI->addIncoming(old, opBB);
Builder.CreateCondBr(success, contBB, opBB);
Builder.SetInsertPoint(contBB);
@@ -2131,12 +2184,14 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) {
- llvm::Value *Cond = nullptr;
+ SmallVector<std::pair<llvm::Value *, SanitizerKind>, 2> Checks;
- if (CGF.SanOpts->IntegerDivideByZero)
- Cond = Builder.CreateICmpNE(Ops.RHS, Zero);
+ if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero)) {
+ Checks.push_back(std::make_pair(Builder.CreateICmpNE(Ops.RHS, Zero),
+ SanitizerKind::IntegerDivideByZero));
+ }
- if (CGF.SanOpts->SignedIntegerOverflow &&
+ if (CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) &&
Ops.Ty->hasSignedIntegerRepresentation()) {
llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
@@ -2146,26 +2201,29 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
llvm::Value *LHSCmp = Builder.CreateICmpNE(Ops.LHS, IntMin);
llvm::Value *RHSCmp = Builder.CreateICmpNE(Ops.RHS, NegOne);
- llvm::Value *Overflow = Builder.CreateOr(LHSCmp, RHSCmp, "or");
- Cond = Cond ? Builder.CreateAnd(Cond, Overflow, "and") : Overflow;
+ llvm::Value *NotOverflow = Builder.CreateOr(LHSCmp, RHSCmp, "or");
+ Checks.push_back(
+ std::make_pair(NotOverflow, SanitizerKind::SignedIntegerOverflow));
}
- if (Cond)
- EmitBinOpCheck(Cond, Ops);
+ if (Checks.size() > 0)
+ EmitBinOpCheck(Checks, Ops);
}
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
{
CodeGenFunction::SanitizerScope SanScope(&CGF);
- if ((CGF.SanOpts->IntegerDivideByZero ||
- CGF.SanOpts->SignedIntegerOverflow) &&
+ if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) ||
+ CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) &&
Ops.Ty->isIntegerType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
- } else if (CGF.SanOpts->FloatDivideByZero &&
+ } else if (CGF.SanOpts.has(SanitizerKind::FloatDivideByZero) &&
Ops.Ty->isRealFloatingType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
+ llvm::Value *NonZero = Builder.CreateFCmpUNE(Ops.RHS, Zero);
+ EmitBinOpCheck(std::make_pair(NonZero, SanitizerKind::FloatDivideByZero),
+ Ops);
}
}
@@ -2189,7 +2247,7 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
// Rem in C can't be a floating point type: C99 6.5.5p2.
- if (CGF.SanOpts->IntegerDivideByZero) {
+ if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero)) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
@@ -2248,9 +2306,12 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
if (handlerName->empty()) {
// If the signed-integer-overflow sanitizer is enabled, emit a call to its
// runtime. Otherwise, this is a -ftrapv check, so just emit a trap.
- if (!isSigned || CGF.SanOpts->SignedIntegerOverflow) {
+ if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
- EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
+ llvm::Value *NotOverflow = Builder.CreateNot(overflow);
+ SanitizerKind Kind = isSigned ? SanitizerKind::SignedIntegerOverflow
+ : SanitizerKind::UnsignedIntegerOverflow;
+ EmitBinOpCheck(std::make_pair(NotOverflow, Kind), Ops);
} else
CGF.EmitTrapCheck(Builder.CreateNot(overflow));
return result;
@@ -2336,7 +2397,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
if (isSubtraction)
index = CGF.Builder.CreateNeg(index, "idx.neg");
- if (CGF.SanOpts->ArrayBounds)
+ if (CGF.SanOpts.has(SanitizerKind::ArrayBounds))
CGF.EmitBoundsCheck(op.E, pointerOperand, index, indexOperand->getType(),
/*Accessed*/ false);
@@ -2476,7 +2537,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(op.LHS, op.RHS, "add");
case LangOptions::SOB_Undefined:
- if (!CGF.SanOpts->SignedIntegerOverflow)
+ if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
// Fall through.
case LangOptions::SOB_Trapping:
@@ -2484,7 +2545,8 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
}
}
- if (op.Ty->isUnsignedIntegerType() && CGF.SanOpts->UnsignedIntegerOverflow)
+ if (op.Ty->isUnsignedIntegerType() &&
+ CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow))
return EmitOverflowCheckedBinOp(op);
if (op.LHS->getType()->isFPOrFPVectorTy()) {
@@ -2506,7 +2568,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
case LangOptions::SOB_Defined:
return Builder.CreateSub(op.LHS, op.RHS, "sub");
case LangOptions::SOB_Undefined:
- if (!CGF.SanOpts->SignedIntegerOverflow)
+ if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
// Fall through.
case LangOptions::SOB_Trapping:
@@ -2514,7 +2576,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
}
}
- if (op.Ty->isUnsignedIntegerType() && CGF.SanOpts->UnsignedIntegerOverflow)
+ if (op.Ty->isUnsignedIntegerType() &&
+ CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow))
return EmitOverflowCheckedBinOp(op);
if (op.LHS->getType()->isFPOrFPVectorTy()) {
@@ -2601,7 +2664,7 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.SanOpts->Shift && !CGF.getLangOpts().OpenCL &&
+ if (CGF.SanOpts.has(SanitizerKind::Shift) && !CGF.getLangOpts().OpenCL &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS);
@@ -2638,7 +2701,7 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
Valid = P;
}
- EmitBinOpCheck(Valid, Ops);
+ EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::Shift), Ops);
}
// OpenCL 6.3j: shift values are effectively % word size of LHS.
if (CGF.getLangOpts().OpenCL)
@@ -2654,10 +2717,12 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.SanOpts->Shift && !CGF.getLangOpts().OpenCL &&
+ if (CGF.SanOpts.has(SanitizerKind::Shift) && !CGF.getLangOpts().OpenCL &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
- EmitBinOpCheck(Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS)), Ops);
+ llvm::Value *Valid =
+ Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS));
+ EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::Shift), Ops);
}
// OpenCL 6.3j: shift values are effectively % word size of LHS.
@@ -2708,6 +2773,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
TestAndClearIgnoreResultAssign();
Value *Result;
QualType LHSTy = E->getLHS()->getType();
+ QualType RHSTy = E->getRHS()->getType();
if (const MemberPointerType *MPT = LHSTy->getAs<MemberPointerType>()) {
assert(E->getOpcode() == BO_EQ ||
E->getOpcode() == BO_NE);
@@ -2715,7 +2781,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
Value *RHS = CGF.EmitScalarExpr(E->getRHS());
Result = CGF.CGM.getCXXABI().EmitMemberPointerComparison(
CGF, LHS, RHS, MPT, E->getOpcode() == BO_NE);
- } else if (!LHSTy->isAnyComplexType()) {
+ } else if (!LHSTy->isAnyComplexType() && !RHSTy->isAnyComplexType()) {
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
@@ -2803,10 +2869,28 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
} else {
// Complex Comparison: can only be an equality comparison.
- CodeGenFunction::ComplexPairTy LHS = CGF.EmitComplexExpr(E->getLHS());
- CodeGenFunction::ComplexPairTy RHS = CGF.EmitComplexExpr(E->getRHS());
-
- QualType CETy = LHSTy->getAs<ComplexType>()->getElementType();
+ CodeGenFunction::ComplexPairTy LHS, RHS;
+ QualType CETy;
+ if (auto *CTy = LHSTy->getAs<ComplexType>()) {
+ LHS = CGF.EmitComplexExpr(E->getLHS());
+ CETy = CTy->getElementType();
+ } else {
+ LHS.first = Visit(E->getLHS());
+ LHS.second = llvm::Constant::getNullValue(LHS.first->getType());
+ CETy = LHSTy;
+ }
+ if (auto *CTy = RHSTy->getAs<ComplexType>()) {
+ RHS = CGF.EmitComplexExpr(E->getRHS());
+ assert(CGF.getContext().hasSameUnqualifiedType(CETy,
+ CTy->getElementType()) &&
+ "The element types must always match.");
+ (void)CTy;
+ } else {
+ RHS.first = Visit(E->getRHS());
+ RHS.second = llvm::Constant::getNullValue(RHS.first->getType());
+ assert(CGF.getContext().hasSameUnqualifiedType(CETy, RHSTy) &&
+ "The element types must always match.");
+ }
Value *ResultR, *ResultI;
if (CETy->isRealFloatingType()) {
@@ -2959,7 +3043,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// Emit an unconditional branch from this block to ContBlock.
{
// There is no need to emit line number for unconditional branch.
- SuppressDebugLocation S(Builder);
+ ApplyDebugLocation DL(CGF);
CGF.EmitBlock(ContBlock);
}
// Insert an entry into the phi node for the edge with the value of RHSCond.
@@ -3232,8 +3316,12 @@ Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
llvm::Value *Val = Builder.CreateLoad(ArgPtr);
// If EmitVAArg promoted the type, we must truncate it.
- if (ArgTy != Val->getType())
- Val = Builder.CreateTrunc(Val, ArgTy);
+ if (ArgTy != Val->getType()) {
+ if (ArgTy->isPointerTy() && !Val->getType()->isPointerTy())
+ Val = Builder.CreateIntToPtr(Val, ArgTy);
+ else
+ Val = Builder.CreateTrunc(Val, ArgTy);
+ }
return Val;
}
diff --git a/lib/CodeGen/CGLoopInfo.cpp b/lib/CodeGen/CGLoopInfo.cpp
index a273f1d4dda8..89f43c281590 100644
--- a/lib/CodeGen/CGLoopInfo.cpp
+++ b/lib/CodeGen/CGLoopInfo.cpp
@@ -24,40 +24,39 @@ static MDNode *createMetadata(LLVMContext &Ctx, const LoopAttributes &Attrs) {
Attrs.VectorizerEnable == LoopAttributes::VecUnspecified)
return nullptr;
- SmallVector<Value *, 4> Args;
+ SmallVector<Metadata *, 4> Args;
// Reserve operand 0 for loop id self reference.
MDNode *TempNode = MDNode::getTemporary(Ctx, None);
Args.push_back(TempNode);
// Setting vectorizer.width
if (Attrs.VectorizerWidth > 0) {
- Value *Vals[] = { MDString::get(Ctx, "llvm.loop.vectorize.width"),
- ConstantInt::get(Type::getInt32Ty(Ctx),
- Attrs.VectorizerWidth) };
+ Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.vectorize.width"),
+ ConstantAsMetadata::get(ConstantInt::get(
+ Type::getInt32Ty(Ctx), Attrs.VectorizerWidth))};
Args.push_back(MDNode::get(Ctx, Vals));
}
// Setting vectorizer.unroll
if (Attrs.VectorizerUnroll > 0) {
- Value *Vals[] = { MDString::get(Ctx, "llvm.loop.interleave.count"),
- ConstantInt::get(Type::getInt32Ty(Ctx),
- Attrs.VectorizerUnroll) };
+ Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.interleave.count"),
+ ConstantAsMetadata::get(ConstantInt::get(
+ Type::getInt32Ty(Ctx), Attrs.VectorizerUnroll))};
Args.push_back(MDNode::get(Ctx, Vals));
}
// Setting vectorizer.enable
if (Attrs.VectorizerEnable != LoopAttributes::VecUnspecified) {
- Value *Vals[] = { MDString::get(Ctx, "llvm.loop.vectorize.enable"),
- ConstantInt::get(Type::getInt1Ty(Ctx),
- (Attrs.VectorizerEnable ==
- LoopAttributes::VecEnable)) };
+ Metadata *Vals[] = {
+ MDString::get(Ctx, "llvm.loop.vectorize.enable"),
+ ConstantAsMetadata::get(ConstantInt::get(
+ Type::getInt1Ty(Ctx),
+ (Attrs.VectorizerEnable == LoopAttributes::VecEnable)))};
Args.push_back(MDNode::get(Ctx, Vals));
}
- MDNode *LoopID = MDNode::get(Ctx, Args);
- assert(LoopID->use_empty() && "LoopID should not be used");
-
// Set the first operand to itself.
+ MDNode *LoopID = MDNode::get(Ctx, Args);
LoopID->replaceOperandWith(0, LoopID);
MDNode::deleteTemporary(TempNode);
return LoopID;
diff --git a/lib/CodeGen/CGLoopInfo.h b/lib/CodeGen/CGLoopInfo.h
index 2f6f172e047a..b1693996507e 100644
--- a/lib/CodeGen/CGLoopInfo.h
+++ b/lib/CodeGen/CGLoopInfo.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CGLOOPINFO_H
-#define CLANG_CODEGEN_CGLOOPINFO_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGLOOPINFO_H
+#define LLVM_CLANG_LIB_CODEGEN_CGLOOPINFO_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
@@ -133,4 +133,4 @@ private:
} // end namespace CodeGen
} // end namespace clang
-#endif // CLANG_CODEGEN_CGLOOPINFO_H
+#endif
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 8ca80808e007..34c6d94f8817 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -60,7 +60,6 @@ llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
llvm::Value *
CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
// Generate the correct selector for this literal's concrete type.
- const Expr *SubExpr = E->getSubExpr();
// Get the method.
const ObjCMethodDecl *BoxingMethod = E->getBoxingMethod();
assert(BoxingMethod && "BoxingMethod is null");
@@ -73,12 +72,9 @@ CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
const ObjCInterfaceDecl *ClassDecl = BoxingMethod->getClassInterface();
llvm::Value *Receiver = Runtime.GetClass(*this, ClassDecl);
-
- const ParmVarDecl *argDecl = *BoxingMethod->param_begin();
- QualType ArgQT = argDecl->getType().getUnqualifiedType();
- RValue RV = EmitAnyExpr(SubExpr);
+
CallArgList Args;
- Args.add(RV, ArgQT);
+ EmitCallArgs(Args, BoxingMethod, E->arg_begin(), E->arg_end());
RValue result = Runtime.GenerateMessageSend(
*this, ReturnValueSlot(), BoxingMethod->getReturnType(), Sel, Receiver,
@@ -461,8 +457,8 @@ struct FinishARCDealloc : EHScopeStack::Cleanup {
/// the LLVM function and sets the other context used by
/// CodeGenFunction.
void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD,
- SourceLocation StartLoc) {
+ const ObjCContainerDecl *CD) {
+ SourceLocation StartLoc = OMD->getLocStart();
FunctionArgList args;
// Check if we should generate debug info for this method.
if (OMD->hasAttr<NoDebugAttr>())
@@ -480,6 +476,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
args.push_back(PI);
CurGD = OMD;
+ CurEHLocation = OMD->getLocEnd();
StartFunction(OMD, OMD->getReturnType(), Fn, FI, args,
OMD->getLocation(), StartLoc);
@@ -501,15 +498,13 @@ static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
/// 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(), OMD->getLocStart());
+ StartObjCMethod(OMD, OMD->getClassInterface());
PGO.assignRegionCounters(OMD, CurFn);
assert(isa<CompoundStmt>(OMD->getBody()));
RegionCounter Cnt = getPGORegionCounter(OMD->getBody());
Cnt.beginRegion(Builder);
EmitCompoundStmtWithoutScope(*cast<CompoundStmt>(OMD->getBody()));
FinishFunction(OMD->getBodyRBrace());
- PGO.emitInstrumentationData();
- PGO.destroyRegionCounters();
}
/// emitStructGetterCall - Call the runtime function to load a property
@@ -744,12 +739,12 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
/// is illegal within a category.
void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
- llvm::Constant *AtomicHelperFn =
- GenerateObjCAtomicGetterCopyHelperFunction(PID);
+ llvm::Constant *AtomicHelperFn =
+ CodeGenFunction(CGM).GenerateObjCAtomicGetterCopyHelperFunction(PID);
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
- StartObjCMethod(OMD, IMP->getClassInterface(), OMD->getLocStart());
+ StartObjCMethod(OMD, IMP->getClassInterface());
generateObjCGetterBody(IMP, PID, OMD, AtomicHelperFn);
@@ -1273,12 +1268,12 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
/// is illegal within a category.
void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
- llvm::Constant *AtomicHelperFn =
- GenerateObjCAtomicSetterCopyHelperFunction(PID);
+ llvm::Constant *AtomicHelperFn =
+ CodeGenFunction(CGM).GenerateObjCAtomicSetterCopyHelperFunction(PID);
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)");
- StartObjCMethod(OMD, IMP->getClassInterface(), OMD->getLocStart());
+ StartObjCMethod(OMD, IMP->getClassInterface());
generateObjCSetterBody(IMP, PID, AtomicHelperFn);
@@ -1356,7 +1351,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
ObjCMethodDecl *MD,
bool ctor) {
MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
- StartObjCMethod(MD, IMP->getClassInterface(), MD->getLocStart());
+ StartObjCMethod(MD, IMP->getClassInterface());
// Emit .cxx_construct.
if (ctor) {
@@ -1757,7 +1752,7 @@ void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) {
llvm::Constant *&fn = CGM.getARCEntrypoints().clang_arc_use;
if (!fn) {
llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGM.VoidTy, ArrayRef<llvm::Type*>(), true);
+ llvm::FunctionType::get(CGM.VoidTy, None, true);
fn = CGM.CreateRuntimeFunction(fnType, "clang.arc.use");
}
@@ -1940,9 +1935,8 @@ llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value,
= cast<llvm::CallInst>(result->stripPointerCasts());
assert(call->getCalledValue() == CGM.getARCEntrypoints().objc_retainBlock);
- SmallVector<llvm::Value*,1> args;
call->setMetadata("clang.arc.copy_on_escape",
- llvm::MDNode::get(Builder.getContext(), args));
+ llvm::MDNode::get(Builder.getContext(), None));
}
return result;
@@ -1984,8 +1978,8 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
"clang.arc.retainAutoreleasedReturnValueMarker");
assert(metadata->getNumOperands() <= 1);
if (metadata->getNumOperands() == 0) {
- llvm::Value *string = llvm::MDString::get(getLLVMContext(), assembly);
- metadata->addOperand(llvm::MDNode::get(getLLVMContext(), string));
+ metadata->addOperand(llvm::MDNode::get(
+ getLLVMContext(), llvm::MDString::get(getLLVMContext(), assembly)));
}
}
}
@@ -2018,9 +2012,8 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value,
llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
if (precise == ARCImpreciseLifetime) {
- SmallVector<llvm::Value*,1> args;
call->setMetadata("clang.imprecise_release",
- llvm::MDNode::get(Builder.getContext(), args));
+ llvm::MDNode::get(Builder.getContext(), None));
}
}
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 619a66ab4a69..c0dc3b8002d8 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -58,7 +58,7 @@ class LazyRuntimeFunction {
/// Initialises the lazy function with the name, return type, and the types
/// of the arguments.
- END_WITH_NULL
+ LLVM_END_WITH_NULL
void init(CodeGenModule *Mod, const char *name,
llvm::Type *RetTy, ...) {
CGM =Mod;
@@ -391,8 +391,8 @@ private:
///
/// This structure is used by both classes and categories, and contains a next
/// pointer allowing them to be chained together in a linked list.
- llvm::Constant *GenerateMethodList(const StringRef &ClassName,
- const StringRef &CategoryName,
+ llvm::Constant *GenerateMethodList(StringRef ClassName,
+ StringRef CategoryName,
ArrayRef<Selector> MethodSels,
ArrayRef<llvm::Constant *> MethodTypes,
bool isClassMethodList);
@@ -875,8 +875,8 @@ void CGObjCGNU::EmitClassRef(const std::string &className) {
llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef);
}
-static std::string SymbolNameForMethod(const StringRef &ClassName,
- const StringRef &CategoryName, const Selector MethodName,
+static std::string SymbolNameForMethod( StringRef ClassName,
+ StringRef CategoryName, const Selector MethodName,
bool isClassMethod) {
std::string MethodNameColonStripped = MethodName.getAsString();
std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
@@ -1296,11 +1296,11 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd, MSI);
imp = EnforceType(Builder, imp, MSI.MessengerType);
- llvm::Value *impMD[] = {
+ llvm::Metadata *impMD[] = {
llvm::MDString::get(VMContext, Sel.getAsString()),
llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()),
- llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsClassMessage)
- };
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ llvm::Type::getInt1Ty(VMContext), IsClassMessage))};
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
llvm::Instruction *call;
@@ -1371,12 +1371,11 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
cmd = EnforceType(Builder, cmd, SelectorTy);
Receiver = EnforceType(Builder, Receiver, IdTy);
- llvm::Value *impMD[] = {
- llvm::MDString::get(VMContext, Sel.getAsString()),
- llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""),
- llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext),
- Class!=nullptr)
- };
+ llvm::Metadata *impMD[] = {
+ llvm::MDString::get(VMContext, Sel.getAsString()),
+ llvm::MDString::get(VMContext, Class ? Class->getNameAsString() : ""),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ llvm::Type::getInt1Ty(VMContext), Class != nullptr))};
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
CallArgList ActualArgs;
@@ -1463,8 +1462,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
/// Generates a MethodList. Used in construction of a objc_class and
/// objc_category structures.
llvm::Constant *CGObjCGNU::
-GenerateMethodList(const StringRef &ClassName,
- const StringRef &CategoryName,
+GenerateMethodList(StringRef ClassName,
+ StringRef CategoryName,
ArrayRef<Selector> MethodSels,
ArrayRef<llvm::Constant *> MethodTypes,
bool isClassMethodList) {
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 6f0979d06c53..f91e8e15b039 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -106,7 +106,7 @@ private:
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
llvm::Type *longDoubleType = llvm::Type::getX86_FP80Ty(VMContext);
llvm::Type *resultType =
- llvm::StructType::get(longDoubleType, longDoubleType, NULL);
+ llvm::StructType::get(longDoubleType, longDoubleType, nullptr);
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(resultType,
params, true),
@@ -244,9 +244,9 @@ public:
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(IdType, false, Params,
- FunctionType::ExtInfo(),
- RequiredArgs::All));
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(
+ IdType, false, false, Params, FunctionType::ExtInfo(),
+ RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
@@ -264,10 +264,9 @@ public:
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
- Params,
- FunctionType::ExtInfo(),
- RequiredArgs::All));
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(
+ Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(),
+ RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
@@ -291,10 +290,9 @@ public:
Params.push_back(IdType);
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
- Params,
- FunctionType::ExtInfo(),
- RequiredArgs::All));
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(
+ Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(),
+ RequiredArgs::All));
const char *name;
if (atomic && copy)
name = "objc_setProperty_atomic_copy";
@@ -319,10 +317,9 @@ public:
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
- Params,
- FunctionType::ExtInfo(),
- RequiredArgs::All));
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(
+ Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(),
+ RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
}
@@ -339,7 +336,7 @@ public:
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, false,
Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
@@ -353,10 +350,9 @@ public:
SmallVector<CanQualType,1> Params;
Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
- Params,
- FunctionType::ExtInfo(),
- RequiredArgs::All));
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(
+ Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(),
+ RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
@@ -2446,11 +2442,11 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
printf("\n");
}
}
-
- llvm::GlobalVariable * Entry =
- CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
- llvm::ConstantDataArray::getString(VMContext, BitMap,false),
- "__TEXT,__objc_classname,cstring_literals", 1, true);
+
+ llvm::GlobalVariable *Entry = CreateMetadataVar(
+ "OBJC_CLASS_NAME_",
+ llvm::ConstantDataArray::getString(VMContext, BitMap, false),
+ "__TEXT,__objc_classname,cstring_literals", 1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -2553,14 +2549,6 @@ llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
return GetOrEmitProtocolRef(PD);
}
-static void assertPrivateName(const llvm::GlobalValue *GV) {
- StringRef NameRef = GV->getName();
- (void)NameRef;
- assert(NameRef[0] == '\01' && (NameRef[1] == 'L' || NameRef[1] == 'l'));
- assert(GV->getVisibility() == llvm::GlobalValue::DefaultVisibility);
- assert(GV->hasPrivateLinkage());
-}
-
/*
// Objective-C 1.0 extensions
struct _objc_protocol {
@@ -2624,19 +2612,17 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
OptMethodTypesExt.begin(), OptMethodTypesExt.end());
llvm::Constant *Values[] = {
- EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods,
- MethodTypesExt),
- GetClassName(PD->getObjCRuntimeNameAsString()),
- EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getName(),
- PD->protocol_begin(),
- PD->protocol_end()),
- EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_" + PD->getName(),
- "__OBJC,__cat_inst_meth,regular,no_dead_strip",
- InstanceMethods),
- EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_" + PD->getName(),
- "__OBJC,__cat_cls_meth,regular,no_dead_strip",
- ClassMethods)
- };
+ EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods,
+ MethodTypesExt),
+ GetClassName(PD->getObjCRuntimeNameAsString()),
+ EmitProtocolList("OBJC_PROTOCOL_REFS_" + PD->getName(),
+ PD->protocol_begin(), PD->protocol_end()),
+ EmitMethodDescList("OBJC_PROTOCOL_INSTANCE_METHODS_" + PD->getName(),
+ "__OBJC,__cat_inst_meth,regular,no_dead_strip",
+ InstanceMethods),
+ EmitMethodDescList("OBJC_PROTOCOL_CLASS_METHODS_" + PD->getName(),
+ "__OBJC,__cat_cls_meth,regular,no_dead_strip",
+ ClassMethods)};
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
Values);
@@ -2645,18 +2631,15 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
assert(Entry->hasPrivateLinkage());
Entry->setInitializer(Init);
} else {
- Entry =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false,
- llvm::GlobalValue::PrivateLinkage,
- Init,
- "\01L_OBJC_PROTOCOL_" + PD->getName());
+ Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy,
+ false, llvm::GlobalValue::PrivateLinkage,
+ Init, "OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
// FIXME: Is this necessary? Why only for protocol?
Entry->setAlignment(4);
Protocols[PD->getIdentifier()] = Entry;
}
- assertPrivateName(Entry);
CGM.addCompilerUsedGlobal(Entry);
return Entry;
@@ -2669,16 +2652,13 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
// We use the initializer as a marker of whether this is a forward
// reference or not. At module finalization we add the empty
// contents for protocols which were referenced but never defined.
- Entry =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false,
- llvm::GlobalValue::PrivateLinkage,
- nullptr,
- "\01L_OBJC_PROTOCOL_" + PD->getName());
+ Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy,
+ false, llvm::GlobalValue::PrivateLinkage,
+ nullptr, "OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
// FIXME: Is this necessary? Why only for protocol?
Entry->setAlignment(4);
}
- assertPrivateName(Entry);
return Entry;
}
@@ -2700,19 +2680,17 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
uint64_t Size =
CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
llvm::Constant *Values[] = {
- llvm::ConstantInt::get(ObjCTypes.IntTy, Size),
- EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_"
- + PD->getName(),
- "__OBJC,__cat_inst_meth,regular,no_dead_strip",
- OptInstanceMethods),
- EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_" + PD->getName(),
- "__OBJC,__cat_cls_meth,regular,no_dead_strip",
- OptClassMethods),
- EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + PD->getName(), nullptr,
- PD, ObjCTypes),
- EmitProtocolMethodTypes("\01L_OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(),
- MethodTypesExt, ObjCTypes)
- };
+ llvm::ConstantInt::get(ObjCTypes.IntTy, Size),
+ EmitMethodDescList("OBJC_PROTOCOL_INSTANCE_METHODS_OPT_" + PD->getName(),
+ "__OBJC,__cat_inst_meth,regular,no_dead_strip",
+ OptInstanceMethods),
+ EmitMethodDescList("OBJC_PROTOCOL_CLASS_METHODS_OPT_" + PD->getName(),
+ "__OBJC,__cat_cls_meth,regular,no_dead_strip",
+ OptClassMethods),
+ EmitPropertyList("OBJC_$_PROP_PROTO_LIST_" + PD->getName(), nullptr, PD,
+ ObjCTypes),
+ EmitProtocolMethodTypes("OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(),
+ MethodTypesExt, ObjCTypes)};
// Return null if no extension bits are used.
if (Values[1]->isNullValue() && Values[2]->isNullValue() &&
@@ -2776,7 +2754,7 @@ PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
for (const auto *P : Proto->protocols())
PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes);
for (const auto *PD : Proto->properties()) {
- if (!PropertySet.insert(PD->getIdentifier()))
+ if (!PropertySet.insert(PD->getIdentifier()).second)
continue;
llvm::Constant *Prop[] = {
GetPropertyName(PD->getIdentifier()),
@@ -2941,19 +2919,16 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Values[0] = GetClassName(OCD->getName());
Values[1] = GetClassName(Interface->getObjCRuntimeNameAsString());
LazySymbols.insert(Interface->getIdentifier());
- Values[2] =
- EmitMethodList("\01L_OBJC_CATEGORY_INSTANCE_METHODS_" + ExtName.str(),
- "__OBJC,__cat_inst_meth,regular,no_dead_strip",
- InstanceMethods);
- Values[3] =
- EmitMethodList("\01L_OBJC_CATEGORY_CLASS_METHODS_" + ExtName.str(),
- "__OBJC,__cat_cls_meth,regular,no_dead_strip",
- ClassMethods);
+ Values[2] = EmitMethodList("OBJC_CATEGORY_INSTANCE_METHODS_" + ExtName.str(),
+ "__OBJC,__cat_inst_meth,regular,no_dead_strip",
+ InstanceMethods);
+ Values[3] = EmitMethodList("OBJC_CATEGORY_CLASS_METHODS_" + ExtName.str(),
+ "__OBJC,__cat_cls_meth,regular,no_dead_strip",
+ ClassMethods);
if (Category) {
Values[4] =
- EmitProtocolList("\01L_OBJC_CATEGORY_PROTOCOLS_" + ExtName.str(),
- Category->protocol_begin(),
- Category->protocol_end());
+ EmitProtocolList("OBJC_CATEGORY_PROTOCOLS_" + ExtName.str(),
+ Category->protocol_begin(), Category->protocol_end());
} else {
Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
}
@@ -2971,9 +2946,8 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Values);
llvm::GlobalVariable *GV =
- CreateMetadataVar("\01L_OBJC_CATEGORY_" + ExtName.str(), Init,
- "__OBJC,__category,regular,no_dead_strip",
- 4, true);
+ CreateMetadataVar("OBJC_CATEGORY_" + ExtName.str(), Init,
+ "__OBJC,__category,regular,no_dead_strip", 4, true);
DefinedCategories.push_back(GV);
DefinedCategoryNames.insert(ExtName.str());
// method definition entries must be clear for next implementation.
@@ -3040,9 +3014,9 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
ObjCInterfaceDecl *Interface =
const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
llvm::Constant *Protocols =
- EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getName(),
- Interface->all_referenced_protocol_begin(),
- Interface->all_referenced_protocol_end());
+ EmitProtocolList("OBJC_CLASS_PROTOCOLS_" + ID->getName(),
+ Interface->all_referenced_protocol_begin(),
+ Interface->all_referenced_protocol_end());
unsigned Flags = FragileABI_Class_Factory;
if (ID->hasNonZeroConstructors() || ID->hasDestructors())
Flags |= FragileABI_Class_HasCXXStructors;
@@ -3093,10 +3067,9 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
Values[ 6] = EmitIvarList(ID, false);
- Values[ 7] =
- EmitMethodList("\01L_OBJC_INSTANCE_METHODS_" + ID->getName(),
- "__OBJC,__inst_meth,regular,no_dead_strip",
- InstanceMethods);
+ Values[7] = EmitMethodList("OBJC_INSTANCE_METHODS_" + ID->getName(),
+ "__OBJC,__inst_meth,regular,no_dead_strip",
+ InstanceMethods);
// cache is always NULL.
Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy);
Values[ 9] = Protocols;
@@ -3104,7 +3077,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Values[11] = EmitClassExtension(ID);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
Values);
- std::string Name("\01L_OBJC_CLASS_");
+ std::string Name("OBJC_CLASS_");
Name += ClassName;
const char *Section = "__OBJC,__class,regular,no_dead_strip";
// Check for a forward reference.
@@ -3118,7 +3091,6 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
CGM.addCompilerUsedGlobal(GV);
} else
GV = CreateMetadataVar(Name, Init, Section, 4, true);
- assertPrivateName(GV);
DefinedClasses.push_back(GV);
ImplementedClasses.push_back(Interface);
// method definition entries must be clear for next implementation.
@@ -3158,10 +3130,9 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
Values[ 6] = EmitIvarList(ID, true);
- Values[ 7] =
- EmitMethodList("\01L_OBJC_CLASS_METHODS_" + ID->getNameAsString(),
- "__OBJC,__cls_meth,regular,no_dead_strip",
- Methods);
+ Values[7] =
+ EmitMethodList("OBJC_CLASS_METHODS_" + ID->getNameAsString(),
+ "__OBJC,__cls_meth,regular,no_dead_strip", Methods);
// cache is always NULL.
Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy);
Values[ 9] = Protocols;
@@ -3172,7 +3143,7 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
Values);
- std::string Name("\01L_OBJC_METACLASS_");
+ std::string Name("OBJC_METACLASS_");
Name += ID->getName();
// Check for a forward reference.
@@ -3186,7 +3157,6 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::GlobalValue::PrivateLinkage,
Init, Name);
}
- assertPrivateName(GV);
GV->setSection("__OBJC,__meta_class,regular,no_dead_strip");
GV->setAlignment(4);
CGM.addCompilerUsedGlobal(GV);
@@ -3195,7 +3165,7 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
}
llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
- std::string Name = "\01L_OBJC_METACLASS_" + ID->getNameAsString();
+ std::string Name = "OBJC_METACLASS_" + ID->getNameAsString();
// FIXME: Should we look these up somewhere other than the module. Its a bit
// silly since we only generate these while processing an implementation, so
@@ -3213,12 +3183,11 @@ llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
"Forward metaclass reference has incorrect type.");
- assertPrivateName(GV);
return GV;
}
llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
- std::string Name = "\01L_OBJC_CLASS_" + ID->getNameAsString();
+ std::string Name = "OBJC_CLASS_" + ID->getNameAsString();
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
if (!GV)
@@ -3228,7 +3197,6 @@ llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
"Forward class metadata reference has incorrect type.");
- assertPrivateName(GV);
return GV;
}
@@ -3256,9 +3224,8 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
llvm::Constant *Init =
llvm::ConstantStruct::get(ObjCTypes.ClassExtensionTy, Values);
- return CreateMetadataVar("\01L_OBJC_CLASSEXT_" + ID->getName(),
- Init, "__OBJC,__class_ext,regular,no_dead_strip",
- 4, true);
+ return CreateMetadataVar("OBJC_CLASSEXT_" + ID->getName(), Init,
+ "__OBJC,__class_ext,regular,no_dead_strip", 4, true);
}
/*
@@ -3314,13 +3281,13 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
llvm::GlobalVariable *GV;
if (ForClass)
- GV = CreateMetadataVar("\01L_OBJC_CLASS_VARIABLES_" + ID->getName(),
- Init, "__OBJC,__class_vars,regular,no_dead_strip",
- 4, true);
+ GV =
+ CreateMetadataVar("OBJC_CLASS_VARIABLES_" + ID->getName(), Init,
+ "__OBJC,__class_vars,regular,no_dead_strip", 4, true);
else
- GV = CreateMetadataVar("\01L_OBJC_INSTANCE_VARIABLES_" + ID->getName(),
- Init, "__OBJC,__instance_vars,regular,no_dead_strip",
- 4, true);
+ GV = CreateMetadataVar("OBJC_INSTANCE_VARIABLES_" + ID->getName(), Init,
+ "__OBJC,__instance_vars,regular,no_dead_strip", 4,
+ true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListPtrTy);
}
@@ -3401,7 +3368,6 @@ llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Ty, false,
llvm::GlobalValue::PrivateLinkage, Init, Name);
- assertPrivateName(GV);
if (!Section.empty())
GV->setSection(Section);
if (Align)
@@ -4308,11 +4274,10 @@ void CGObjCCommonMac::EmitImageInfo() {
eImageInfo_GCOnly);
// Require that GC be specified and set to eImageInfo_GarbageCollected.
- llvm::Value *Ops[2] = {
- llvm::MDString::get(VMContext, "Objective-C Garbage Collection"),
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- eImageInfo_GarbageCollected)
- };
+ llvm::Metadata *Ops[2] = {
+ llvm::MDString::get(VMContext, "Objective-C Garbage Collection"),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), eImageInfo_GarbageCollected))};
Mod.addModuleFlag(llvm::Module::Require, "Objective-C GC Only",
llvm::MDNode::get(VMContext, Ops));
}
@@ -4347,10 +4312,9 @@ void CGObjCMac::EmitModuleInfo() {
GetClassName(StringRef("")),
EmitModuleSymbols()
};
- CreateMetadataVar("\01L_OBJC_MODULES",
+ CreateMetadataVar("OBJC_MODULES",
llvm::ConstantStruct::get(ObjCTypes.ModuleTy, Values),
- "__OBJC,__module_info,regular,no_dead_strip",
- 4, true);
+ "__OBJC,__module_info,regular,no_dead_strip", 4, true);
}
llvm::Constant *CGObjCMac::EmitModuleSymbols() {
@@ -4393,10 +4357,8 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
- llvm::GlobalVariable *GV =
- CreateMetadataVar("\01L_OBJC_SYMBOLS", Init,
- "__OBJC,__symbols,regular,no_dead_strip",
- 4, true);
+ llvm::GlobalVariable *GV = CreateMetadataVar(
+ "OBJC_SYMBOLS", Init, "__OBJC,__symbols,regular,no_dead_strip", 4, true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
}
@@ -4410,10 +4372,9 @@ llvm::Value *CGObjCMac::EmitClassRefFromId(CodeGenFunction &CGF,
llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetClassName(II->getName()),
ObjCTypes.ClassPtrTy);
- Entry =
- CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
- "__OBJC,__cls_refs,literal_pointers,no_dead_strip",
- 4, true);
+ Entry = CreateMetadataVar(
+ "OBJC_CLASS_REFERENCES_", Casted,
+ "__OBJC,__cls_refs,literal_pointers,no_dead_strip", 4, true);
}
return CGF.Builder.CreateLoad(Entry);
@@ -4437,10 +4398,9 @@ llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel,
llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
ObjCTypes.SelectorPtrTy);
- Entry =
- CreateMetadataVar("\01L_OBJC_SELECTOR_REFERENCES_", Casted,
- "__OBJC,__message_refs,literal_pointers,no_dead_strip",
- 4, true);
+ Entry = CreateMetadataVar(
+ "OBJC_SELECTOR_REFERENCES_", Casted,
+ "__OBJC,__message_refs,literal_pointers,no_dead_strip", 4, true);
Entry->setExternallyInitialized(true);
}
@@ -4452,13 +4412,12 @@ llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel,
llvm::Constant *CGObjCCommonMac::GetClassName(StringRef RuntimeName) {
llvm::GlobalVariable *&Entry = ClassNames[RuntimeName];
if (!Entry)
- Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
- llvm::ConstantDataArray::getString(VMContext,
- RuntimeName),
- ((ObjCABI == 2) ?
- "__TEXT,__objc_classname,cstring_literals" :
- "__TEXT,__cstring,cstring_literals"),
- 1, true);
+ Entry = CreateMetadataVar(
+ "OBJC_CLASS_NAME_",
+ llvm::ConstantDataArray::getString(VMContext, RuntimeName),
+ ((ObjCABI == 2) ? "__TEXT,__objc_classname,cstring_literals"
+ : "__TEXT,__cstring,cstring_literals"),
+ 1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -4772,14 +4731,13 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string &BitMap) {
// null terminate string.
unsigned char zero = 0;
BitMap += zero;
-
- llvm::GlobalVariable * Entry =
- CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
- llvm::ConstantDataArray::getString(VMContext, BitMap,false),
- ((ObjCABI == 2) ?
- "__TEXT,__objc_classname,cstring_literals" :
- "__TEXT,__cstring,cstring_literals"),
- 1, true);
+
+ llvm::GlobalVariable *Entry = CreateMetadataVar(
+ "OBJC_CLASS_NAME_",
+ llvm::ConstantDataArray::getString(VMContext, BitMap, false),
+ ((ObjCABI == 2) ? "__TEXT,__objc_classname,cstring_literals"
+ : "__TEXT,__cstring,cstring_literals"),
+ 1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -4864,12 +4822,12 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
// FIXME: Avoid std::string in "Sel.getAsString()"
if (!Entry)
- Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_NAME_",
- llvm::ConstantDataArray::getString(VMContext, Sel.getAsString()),
- ((ObjCABI == 2) ?
- "__TEXT,__objc_methname,cstring_literals" :
- "__TEXT,__cstring,cstring_literals"),
- 1, true);
+ Entry = CreateMetadataVar(
+ "OBJC_METH_VAR_NAME_",
+ llvm::ConstantDataArray::getString(VMContext, Sel.getAsString()),
+ ((ObjCABI == 2) ? "__TEXT,__objc_methname,cstring_literals"
+ : "__TEXT,__cstring,cstring_literals"),
+ 1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -4886,12 +4844,12 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
if (!Entry)
- Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
- llvm::ConstantDataArray::getString(VMContext, TypeStr),
- ((ObjCABI == 2) ?
- "__TEXT,__objc_methtype,cstring_literals" :
- "__TEXT,__cstring,cstring_literals"),
- 1, true);
+ Entry = CreateMetadataVar(
+ "OBJC_METH_VAR_TYPE_",
+ llvm::ConstantDataArray::getString(VMContext, TypeStr),
+ ((ObjCABI == 2) ? "__TEXT,__objc_methtype,cstring_literals"
+ : "__TEXT,__cstring,cstring_literals"),
+ 1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -4905,12 +4863,12 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D,
llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
if (!Entry)
- Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
- llvm::ConstantDataArray::getString(VMContext, TypeStr),
- ((ObjCABI == 2) ?
- "__TEXT,__objc_methtype,cstring_literals" :
- "__TEXT,__cstring,cstring_literals"),
- 1, true);
+ Entry = CreateMetadataVar(
+ "OBJC_METH_VAR_TYPE_",
+ llvm::ConstantDataArray::getString(VMContext, TypeStr),
+ ((ObjCABI == 2) ? "__TEXT,__objc_methtype,cstring_literals"
+ : "__TEXT,__cstring,cstring_literals"),
+ 1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -4921,7 +4879,7 @@ llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) {
if (!Entry)
Entry = CreateMetadataVar(
- "\01L_OBJC_PROP_NAME_ATTR_",
+ "OBJC_PROP_NAME_ATTR_",
llvm::ConstantDataArray::getString(VMContext, Ident->getName()),
"__TEXT,__cstring,cstring_literals", 1, true);
@@ -4967,7 +4925,6 @@ void CGObjCMac::FinishModule() {
Values[2] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
Values[3] = Values[4] =
llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
- assertPrivateName(I->second);
I->second->setInitializer(llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
Values));
CGM.addCompilerUsedGlobal(I->second);
@@ -5027,8 +4984,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// arm64 targets use "int" ivar offset variables. All others,
// including OS X x86_64 and Windows x86_64, use "long" ivar offsets.
- if (CGM.getTarget().getTriple().getArch() == llvm::Triple::arm64 ||
- CGM.getTarget().getTriple().getArch() == llvm::Triple::aarch64)
+ if (CGM.getTarget().getTriple().getArch() == llvm::Triple::aarch64)
IvarOffsetVarTy = IntTy;
else
IvarOffsetVarTy = LongTy;
@@ -5072,7 +5028,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// char *attributes;
// }
PropertyTy = llvm::StructType::create("struct._prop_t",
- Int8PtrTy, Int8PtrTy, NULL);
+ Int8PtrTy, Int8PtrTy, nullptr);
// struct _prop_list_t {
// uint32_t entsize; // sizeof(struct _prop_t)
@@ -5081,7 +5037,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// }
PropertyListTy =
llvm::StructType::create("struct._prop_list_t", IntTy, IntTy,
- llvm::ArrayType::get(PropertyTy, 0), NULL);
+ llvm::ArrayType::get(PropertyTy, 0), nullptr);
// struct _prop_list_t *
PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
@@ -5092,7 +5048,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// }
MethodTy = llvm::StructType::create("struct._objc_method",
SelectorPtrTy, Int8PtrTy, Int8PtrTy,
- NULL);
+ nullptr);
// struct _objc_cache *
CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache");
@@ -5108,16 +5064,15 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// }
MethodDescriptionTy =
llvm::StructType::create("struct._objc_method_description",
- SelectorPtrTy, Int8PtrTy, NULL);
+ SelectorPtrTy, Int8PtrTy, nullptr);
// struct _objc_method_description_list {
// int count;
// struct _objc_method_description[1];
// }
- MethodDescriptionListTy =
- llvm::StructType::create("struct._objc_method_description_list",
- IntTy,
- llvm::ArrayType::get(MethodDescriptionTy, 0),NULL);
+ MethodDescriptionListTy = llvm::StructType::create(
+ "struct._objc_method_description_list", IntTy,
+ llvm::ArrayType::get(MethodDescriptionTy, 0), nullptr);
// struct _objc_method_description_list *
MethodDescriptionListPtrTy =
@@ -5136,7 +5091,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
llvm::StructType::create("struct._objc_protocol_extension",
IntTy, MethodDescriptionListPtrTy,
MethodDescriptionListPtrTy, PropertyListPtrTy,
- Int8PtrPtrTy, NULL);
+ Int8PtrPtrTy, nullptr);
// struct _objc_protocol_extension *
ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
@@ -5151,7 +5106,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy),
LongTy,
llvm::ArrayType::get(ProtocolTy, 0),
- NULL);
+ nullptr);
// struct _objc_protocol {
// struct _objc_protocol_extension *isa;
@@ -5164,7 +5119,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
llvm::PointerType::getUnqual(ProtocolListTy),
MethodDescriptionListPtrTy,
MethodDescriptionListPtrTy,
- NULL);
+ nullptr);
// struct _objc_protocol_list *
ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
@@ -5179,7 +5134,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// int ivar_offset;
// }
IvarTy = llvm::StructType::create("struct._objc_ivar",
- Int8PtrTy, Int8PtrTy, IntTy, NULL);
+ Int8PtrTy, Int8PtrTy, IntTy, nullptr);
// struct _objc_ivar_list *
IvarListTy =
@@ -5194,7 +5149,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_class_extension *
ClassExtensionTy =
llvm::StructType::create("struct._objc_class_extension",
- IntTy, Int8PtrTy, PropertyListPtrTy, NULL);
+ IntTy, Int8PtrTy, PropertyListPtrTy, nullptr);
ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
ClassTy = llvm::StructType::create(VMContext, "struct._objc_class");
@@ -5225,7 +5180,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
ProtocolListPtrTy,
Int8PtrTy,
ClassExtensionPtrTy,
- NULL);
+ nullptr);
ClassPtrTy = llvm::PointerType::getUnqual(ClassTy);
@@ -5241,7 +5196,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
llvm::StructType::create("struct._objc_category",
Int8PtrTy, Int8PtrTy, MethodListPtrTy,
MethodListPtrTy, ProtocolListPtrTy,
- IntTy, PropertyListPtrTy, NULL);
+ IntTy, PropertyListPtrTy, nullptr);
// Global metadata structures
@@ -5255,7 +5210,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
SymtabTy =
llvm::StructType::create("struct._objc_symtab",
LongTy, SelectorPtrTy, ShortTy, ShortTy,
- llvm::ArrayType::get(Int8PtrTy, 0), NULL);
+ llvm::ArrayType::get(Int8PtrTy, 0), nullptr);
SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
// struct _objc_module {
@@ -5266,7 +5221,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// }
ModuleTy =
llvm::StructType::create("struct._objc_module",
- LongTy, LongTy, Int8PtrTy, SymtabPtrTy, NULL);
+ LongTy, LongTy, Int8PtrTy, SymtabPtrTy, nullptr);
// FIXME: This is the size of the setjmp buffer and should be target
@@ -5279,7 +5234,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
ExceptionDataTy =
llvm::StructType::create("struct._objc_exception_data",
llvm::ArrayType::get(CGM.Int32Ty,SetJmpBufferSize),
- StackPtrTy, NULL);
+ StackPtrTy, nullptr);
}
@@ -5292,7 +5247,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
MethodListnfABITy =
llvm::StructType::create("struct.__method_list_t", IntTy, IntTy,
- llvm::ArrayType::get(MethodTy, 0), NULL);
+ llvm::ArrayType::get(MethodTy, 0), nullptr);
// struct method_list_t *
MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
@@ -5320,7 +5275,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
MethodListnfABIPtrTy, MethodListnfABIPtrTy,
MethodListnfABIPtrTy, MethodListnfABIPtrTy,
PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy,
- NULL);
+ nullptr);
// struct _protocol_t*
ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
@@ -5331,7 +5286,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
ProtocolListnfABITy->setBody(LongTy,
llvm::ArrayType::get(ProtocolnfABIPtrTy, 0),
- NULL);
+ nullptr);
// struct _objc_protocol_list*
ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
@@ -5345,7 +5300,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
IvarnfABITy = llvm::StructType::create(
"struct._ivar_t", llvm::PointerType::getUnqual(IvarOffsetVarTy),
- Int8PtrTy, Int8PtrTy, IntTy, IntTy, NULL);
+ Int8PtrTy, Int8PtrTy, IntTy, IntTy, nullptr);
// struct _ivar_list_t {
// uint32 entsize; // sizeof(struct _ivar_t)
@@ -5354,7 +5309,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
IvarListnfABITy =
llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy,
- llvm::ArrayType::get(IvarnfABITy, 0), NULL);
+ llvm::ArrayType::get(IvarnfABITy, 0), nullptr);
IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy);
@@ -5378,7 +5333,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
Int8PtrTy, MethodListnfABIPtrTy,
ProtocolListnfABIPtrTy,
IvarListnfABIPtrTy,
- Int8PtrTy, PropertyListPtrTy, NULL);
+ Int8PtrTy, PropertyListPtrTy,
+ nullptr);
// ImpnfABITy - LLVM for id (*)(id, SEL, ...)
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
@@ -5399,7 +5355,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
CachePtrTy,
llvm::PointerType::getUnqual(ImpnfABITy),
llvm::PointerType::getUnqual(ClassRonfABITy),
- NULL);
+ nullptr);
// LLVM for struct _class_t *
ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy);
@@ -5418,7 +5374,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
MethodListnfABIPtrTy,
ProtocolListnfABIPtrTy,
PropertyListPtrTy,
- NULL);
+ nullptr);
// New types for nonfragile abi messaging.
CodeGen::CodeGenTypes &Types = CGM.getTypes();
@@ -5457,7 +5413,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// };
SuperMessageRefTy =
llvm::StructType::create("struct._super_message_ref_t",
- ImpnfABITy, SelectorPtrTy, NULL);
+ ImpnfABITy, SelectorPtrTy, nullptr);
// SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy);
@@ -5471,7 +5427,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
EHTypeTy =
llvm::StructType::create("struct._objc_typeinfo",
llvm::PointerType::getUnqual(Int8PtrTy),
- Int8PtrTy, ClassnfABIPtrTy, NULL);
+ Int8PtrTy, ClassnfABIPtrTy, nullptr);
EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
}
@@ -5504,7 +5460,6 @@ AddModuleClassList(ArrayRef<llvm::GlobalValue*> Container,
llvm::GlobalValue::PrivateLinkage,
Init,
SymbolName);
- assertPrivateName(GV);
GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection(SectionName);
CGM.addCompilerUsedGlobal(GV);
@@ -5526,22 +5481,18 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
DefinedMetaClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
}
}
-
- AddModuleClassList(DefinedClasses,
- "\01L_OBJC_LABEL_CLASS_$",
+
+ AddModuleClassList(DefinedClasses, "OBJC_LABEL_CLASS_$",
"__DATA, __objc_classlist, regular, no_dead_strip");
- AddModuleClassList(DefinedNonLazyClasses,
- "\01L_OBJC_LABEL_NONLAZY_CLASS_$",
+ AddModuleClassList(DefinedNonLazyClasses, "OBJC_LABEL_NONLAZY_CLASS_$",
"__DATA, __objc_nlclslist, regular, no_dead_strip");
// Build list of all implemented category addresses in array
// L_OBJC_LABEL_CATEGORY_$.
- AddModuleClassList(DefinedCategories,
- "\01L_OBJC_LABEL_CATEGORY_$",
+ AddModuleClassList(DefinedCategories, "OBJC_LABEL_CATEGORY_$",
"__DATA, __objc_catlist, regular, no_dead_strip");
- AddModuleClassList(DefinedNonLazyCategories,
- "\01L_OBJC_LABEL_NONLAZY_CATEGORY_$",
+ AddModuleClassList(DefinedNonLazyCategories, "OBJC_LABEL_NONLAZY_CATEGORY_$",
"__DATA, __objc_nlcatlist, regular, no_dead_strip");
EmitImageInfo();
@@ -5701,7 +5652,6 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
(flags & NonFragileABI_Class_Meta) ?
std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName :
std::string("\01l_OBJC_CLASS_RO_$_")+ClassName);
- assertPrivateName(CLASS_RO_GV);
CLASS_RO_GV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
CLASS_RO_GV->setSection("__DATA, __objc_const");
@@ -6038,7 +5988,6 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
llvm::GlobalValue::PrivateLinkage,
Init,
ExtCatName.str());
- assertPrivateName(GCATV);
GCATV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(ObjCTypes.CategorynfABITy));
GCATV->setSection("__DATA, __objc_const");
@@ -6099,7 +6048,6 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::PrivateLinkage, Init, Name);
- assertPrivateName(GV);
GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection(Section);
CGM.addCompilerUsedGlobal(GV);
@@ -6218,7 +6166,6 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
llvm::GlobalValue::PrivateLinkage,
Init,
Prefix + OID->getObjCRuntimeNameAsString());
- assertPrivateName(GV);
GV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection("__DATA, __objc_const");
@@ -6237,7 +6184,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef(
// contents for protocols which were referenced but never defined.
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy,
- false, llvm::GlobalValue::WeakAnyLinkage,
+ false, llvm::GlobalValue::ExternalLinkage,
nullptr,
"\01l_OBJC_PROTOCOL_$_" + PD->getObjCRuntimeNameAsString());
Entry->setSection("__DATA,__datacoal_nt,coalesced");
@@ -6348,8 +6295,8 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
Values);
if (Entry) {
- // Already created, update the initializer.
- assert(Entry->hasWeakAnyLinkage());
+ // Already created, fix the linkage and update the initializer.
+ Entry->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
Entry->setInitializer(Init);
} else {
Entry =
@@ -6424,7 +6371,6 @@ CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::PrivateLinkage,
Init, Name);
- assertPrivateName(GV);
GV->setSection("__DATA, __objc_const");
GV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(Init->getType()));
@@ -6482,7 +6428,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
if (IsIvarOffsetKnownIdempotent(CGF, Ivar))
cast<llvm::LoadInst>(IvarOffsetValue)
->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(VMContext, ArrayRef<llvm::Value *>()));
+ llvm::MDNode::get(VMContext, None));
// This could be 32bit int or 64bit integer depending on the architecture.
// Cast it to 64bit integer value, if it is a 32bit integer ivar offset value
@@ -6673,18 +6619,15 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
getClassSymbolPrefix() +
(ID ? ID->getObjCRuntimeNameAsString() : II->getName()).str());
llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName, Weak);
- Entry =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
- false, llvm::GlobalValue::PrivateLinkage,
- ClassGV,
- "\01L_OBJC_CLASSLIST_REFERENCES_$_");
+ Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
+ false, llvm::GlobalValue::PrivateLinkage,
+ ClassGV, "OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
CGM.addCompilerUsedGlobal(Entry);
}
- assertPrivateName(Entry);
return CGF.Builder.CreateLoad(Entry);
}
@@ -6709,18 +6652,15 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
ClassName += ID->getObjCRuntimeNameAsString();
llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName.str(),
ID->isWeakImported());
- Entry =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
- false, llvm::GlobalValue::PrivateLinkage,
- ClassGV,
- "\01L_OBJC_CLASSLIST_SUP_REFS_$_");
+ Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
+ false, llvm::GlobalValue::PrivateLinkage,
+ ClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.addCompilerUsedGlobal(Entry);
}
- assertPrivateName(Entry);
return CGF.Builder.CreateLoad(Entry);
}
@@ -6736,11 +6676,10 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
MetaClassName += ID->getObjCRuntimeNameAsString();
llvm::GlobalVariable *MetaClassGV =
GetClassGlobal(MetaClassName.str(), Weak);
-
+
Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
false, llvm::GlobalValue::PrivateLinkage,
- MetaClassGV,
- "\01L_OBJC_CLASSLIST_SUP_REFS_$_");
+ MetaClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABIPtrTy));
@@ -6748,7 +6687,6 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
CGM.addCompilerUsedGlobal(Entry);
}
- assertPrivateName(Entry);
return CGF.Builder.CreateLoad(Entry);
}
@@ -6795,8 +6733,7 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
if (IsClassMessage)
- Target = EmitMetaClassRef(CGF, Class,
- (isCategoryImpl && Class->isWeakImported()));
+ Target = EmitMetaClassRef(CGF, Class, Class->isWeakImported());
else
Target = EmitSuperClassRef(CGF, Class);
@@ -6826,23 +6763,20 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
ObjCTypes.SelectorPtrTy);
- Entry =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.SelectorPtrTy, false,
- llvm::GlobalValue::PrivateLinkage,
- Casted, "\01L_OBJC_SELECTOR_REFERENCES_");
+ Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.SelectorPtrTy,
+ false, llvm::GlobalValue::PrivateLinkage,
+ Casted, "OBJC_SELECTOR_REFERENCES_");
Entry->setExternallyInitialized(true);
Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
CGM.addCompilerUsedGlobal(Entry);
}
- assertPrivateName(Entry);
if (lval)
return Entry;
llvm::LoadInst* LI = CGF.Builder.CreateLoad(Entry);
LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(VMContext,
- ArrayRef<llvm::Value*>()));
+ llvm::MDNode::get(VMContext, None));
return LI;
}
/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index fc6bee3fabed..475254649866 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_OBCJRUNTIME_H
-#define CLANG_CODEGEN_OBCJRUNTIME_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGOBJCRUNTIME_H
+#define LLVM_CLANG_LIB_CODEGEN_CGOBJCRUNTIME_H
#include "CGBuilder.h"
#include "CGCall.h"
#include "CGValue.h"
diff --git a/lib/CodeGen/CGOpenCLRuntime.h b/lib/CodeGen/CGOpenCLRuntime.h
index 7b675c3bc1e7..0c50b92914b8 100644
--- a/lib/CodeGen/CGOpenCLRuntime.h
+++ b/lib/CodeGen/CGOpenCLRuntime.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_OPENCLRUNTIME_H
-#define CLANG_CODEGEN_OPENCLRUNTIME_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENCLRUNTIME_H
+#define LLVM_CLANG_LIB_CODEGEN_CGOPENCLRUNTIME_H
#include "clang/AST/Type.h"
#include "llvm/IR/Type.h"
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index 12a3a7790eec..22ee00f2c7ae 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -14,7 +14,9 @@
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/StmtOpenMP.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Value.h"
@@ -24,16 +26,81 @@
using namespace clang;
using namespace CodeGen;
+namespace {
+/// \brief API for captured statement code generation in OpenMP constructs.
+class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
+public:
+ CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &CS,
+ const VarDecl *ThreadIDVar)
+ : CGCapturedStmtInfo(CS, CR_OpenMP), ThreadIDVar(ThreadIDVar),
+ Directive(D) {
+ assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
+ }
+
+ /// \brief Gets a variable or parameter for storing global thread id
+ /// inside OpenMP construct.
+ const VarDecl *getThreadIDVariable() const { return ThreadIDVar; }
+
+ /// \brief Gets an LValue for the current ThreadID variable.
+ LValue getThreadIDVariableLValue(CodeGenFunction &CGF);
+
+ static bool classof(const CGCapturedStmtInfo *Info) {
+ return Info->getKind() == CR_OpenMP;
+ }
+
+ /// \brief Emit the captured statement body.
+ void EmitBody(CodeGenFunction &CGF, Stmt *S) override;
+
+ /// \brief Get the name of the capture helper.
+ StringRef getHelperName() const override { return ".omp_outlined."; }
+
+private:
+ /// \brief A variable or parameter storing global thread id for OpenMP
+ /// constructs.
+ const VarDecl *ThreadIDVar;
+ /// \brief OpenMP executable directive associated with the region.
+ const OMPExecutableDirective &Directive;
+};
+} // namespace
+
+LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) {
+ return CGF.MakeNaturalAlignAddrLValue(
+ CGF.GetAddrOfLocalVar(ThreadIDVar),
+ CGF.getContext().getPointerType(ThreadIDVar->getType()));
+}
+
+void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) {
+ CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
+ CGF.EmitOMPPrivateClause(Directive, PrivateScope);
+ CGF.EmitOMPFirstprivateClause(Directive, PrivateScope);
+ if (PrivateScope.Privatize())
+ // Emit implicit barrier to synchronize threads and avoid data races.
+ CGF.CGM.getOpenMPRuntime().EmitOMPBarrierCall(CGF, Directive.getLocStart(),
+ /*IsExplicit=*/false);
+ CGCapturedStmtInfo::EmitBody(CGF, S);
+}
+
CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
: CGM(CGM), DefaultOpenMPPSource(nullptr) {
IdentTy = llvm::StructType::create(
"ident_t", CGM.Int32Ty /* reserved_1 */, CGM.Int32Ty /* flags */,
CGM.Int32Ty /* reserved_2 */, CGM.Int32Ty /* reserved_3 */,
- CGM.Int8PtrTy /* psource */, NULL);
+ CGM.Int8PtrTy /* psource */, nullptr);
// Build void (*kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid,...)
llvm::Type *MicroParams[] = {llvm::PointerType::getUnqual(CGM.Int32Ty),
llvm::PointerType::getUnqual(CGM.Int32Ty)};
Kmpc_MicroTy = llvm::FunctionType::get(CGM.VoidTy, MicroParams, true);
+ KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
+}
+
+llvm::Value *
+CGOpenMPRuntime::EmitOpenMPOutlinedFunction(const OMPExecutableDirective &D,
+ const VarDecl *ThreadIDVar) {
+ const CapturedStmt *CS = cast<CapturedStmt>(D.getAssociatedStmt());
+ CodeGenFunction CGF(CGM, true);
+ CGOpenMPRegionInfo CGInfo(D, *CS, ThreadIDVar);
+ CGF.CapturedStmtInfo = &CGInfo;
+ return CGF.GenerateCapturedStmtFunction(*CS);
}
llvm::Value *
@@ -50,11 +117,10 @@ CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
DefaultOpenMPPSource =
llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
}
- llvm::GlobalVariable *DefaultOpenMPLocation = cast<llvm::GlobalVariable>(
- CGM.CreateRuntimeVariable(IdentTy, ".kmpc_default_loc.addr"));
+ auto DefaultOpenMPLocation = new llvm::GlobalVariable(
+ CGM.getModule(), IdentTy, /*isConstant*/ true,
+ llvm::GlobalValue::PrivateLinkage, /*Initializer*/ nullptr);
DefaultOpenMPLocation->setUnnamedAddr(true);
- DefaultOpenMPLocation->setConstant(true);
- DefaultOpenMPLocation->setLinkage(llvm::GlobalValue::PrivateLinkage);
llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true);
llvm::Constant *Values[] = {Zero,
@@ -62,6 +128,7 @@ CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
Zero, Zero, DefaultOpenMPPSource};
llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values);
DefaultOpenMPLocation->setInitializer(Init);
+ OpenMPDefaultLocMap[Flags] = DefaultOpenMPLocation;
return DefaultOpenMPLocation;
}
return Entry;
@@ -77,14 +144,17 @@ llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
assert(CGF.CurFn && "No function in current CodeGenFunction.");
llvm::Value *LocValue = nullptr;
- OpenMPLocMapTy::iterator I = OpenMPLocMap.find(CGF.CurFn);
- if (I != OpenMPLocMap.end()) {
- LocValue = I->second;
- } else {
+ auto I = OpenMPLocThreadIDMap.find(CGF.CurFn);
+ if (I != OpenMPLocThreadIDMap.end())
+ LocValue = I->second.DebugLoc;
+ // OpenMPLocThreadIDMap may have null DebugLoc and non-null ThreadID, if
+ // GetOpenMPThreadID was called before this routine.
+ if (LocValue == nullptr) {
// Generate "ident_t .kmpc_loc.addr;"
llvm::AllocaInst *AI = CGF.CreateTempAlloca(IdentTy, ".kmpc_loc.addr");
AI->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(IdentTy));
- OpenMPLocMap[CGF.CurFn] = AI;
+ auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
+ Elem.second.DebugLoc = AI;
LocValue = AI;
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
@@ -95,7 +165,7 @@ llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
}
// char **psource = &.kmpc_loc_<flags>.addr.psource;
- llvm::Value *PSource =
+ auto *PSource =
CGF.Builder.CreateConstInBoundsGEP2_32(LocValue, 0, IdentField_PSource);
auto OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding());
@@ -119,32 +189,54 @@ llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
return LocValue;
}
-llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
- SourceLocation Loc) {
+llvm::Value *CGOpenMPRuntime::GetOpenMPThreadID(CodeGenFunction &CGF,
+ SourceLocation Loc) {
assert(CGF.CurFn && "No function in current CodeGenFunction.");
- llvm::Value *GTid = nullptr;
- OpenMPGtidMapTy::iterator I = OpenMPGtidMap.find(CGF.CurFn);
- if (I != OpenMPGtidMap.end()) {
- GTid = I->second;
+ llvm::Value *ThreadID = nullptr;
+ // Check whether we've already cached a load of the thread id in this
+ // function.
+ auto I = OpenMPLocThreadIDMap.find(CGF.CurFn);
+ if (I != OpenMPLocThreadIDMap.end()) {
+ ThreadID = I->second.ThreadID;
+ if (ThreadID != nullptr)
+ return ThreadID;
+ }
+ if (auto OMPRegionInfo =
+ dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
+ // Check if this an outlined function with thread id passed as argument.
+ auto ThreadIDVar = OMPRegionInfo->getThreadIDVariable();
+ auto LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
+ auto RVal = CGF.EmitLoadOfLValue(LVal, Loc);
+ LVal = CGF.MakeNaturalAlignAddrLValue(RVal.getScalarVal(),
+ ThreadIDVar->getType());
+ ThreadID = CGF.EmitLoadOfLValue(LVal, Loc).getScalarVal();
+ // If value loaded in entry block, cache it and use it everywhere in
+ // function.
+ if (CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) {
+ auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
+ Elem.second.ThreadID = ThreadID;
+ }
} else {
- // Generate "int32 .kmpc_global_thread_num.addr;"
+ // This is not an outlined function region - need to call __kmpc_int32
+ // kmpc_global_thread_num(ident_t *loc).
+ // Generate thread id value and cache this value for use across the
+ // function.
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
- GTid = CGF.EmitRuntimeCall(
+ ThreadID = CGF.EmitRuntimeCall(
CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
- OpenMPGtidMap[CGF.CurFn] = GTid;
+ auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
+ Elem.second.ThreadID = ThreadID;
}
- return GTid;
+ return ThreadID;
}
void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) {
assert(CGF.CurFn && "No function in current CodeGenFunction.");
- if (OpenMPGtidMap.count(CGF.CurFn))
- OpenMPGtidMap.erase(CGF.CurFn);
- if (OpenMPLocMap.count(CGF.CurFn))
- OpenMPLocMap.erase(CGF.CurFn);
+ if (OpenMPLocThreadIDMap.count(CGF.CurFn))
+ OpenMPLocThreadIDMap.erase(CGF.CurFn);
}
llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() {
@@ -165,7 +257,7 @@ CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
getKmpc_MicroPointerTy()};
llvm::FunctionType *FnTy =
- llvm::FunctionType::get(CGM.VoidTy, TypeParams, true);
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true);
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call");
break;
}
@@ -173,10 +265,658 @@ CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
// Build kmp_int32 __kmpc_global_thread_num(ident_t *loc);
llvm::Type *TypeParams[] = {getIdentTyPointerTy()};
llvm::FunctionType *FnTy =
- llvm::FunctionType::get(CGM.Int32Ty, TypeParams, false);
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num");
break;
}
+ case OMPRTL__kmpc_threadprivate_cached: {
+ // Build void *__kmpc_threadprivate_cached(ident_t *loc,
+ // kmp_int32 global_tid, void *data, size_t size, void ***cache);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
+ CGM.VoidPtrTy, CGM.SizeTy,
+ CGM.VoidPtrTy->getPointerTo()->getPointerTo()};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_threadprivate_cached");
+ break;
+ }
+ case OMPRTL__kmpc_critical: {
+ // Build void __kmpc_critical(ident_t *loc, kmp_int32 global_tid,
+ // kmp_critical_name *crit);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), CGM.Int32Ty,
+ llvm::PointerType::getUnqual(KmpCriticalNameTy)};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_critical");
+ break;
+ }
+ case OMPRTL__kmpc_threadprivate_register: {
+ // Build void __kmpc_threadprivate_register(ident_t *, void *data,
+ // kmpc_ctor ctor, kmpc_cctor cctor, kmpc_dtor dtor);
+ // typedef void *(*kmpc_ctor)(void *);
+ auto KmpcCtorTy =
+ llvm::FunctionType::get(CGM.VoidPtrTy, CGM.VoidPtrTy,
+ /*isVarArg*/ false)->getPointerTo();
+ // typedef void *(*kmpc_cctor)(void *, void *);
+ llvm::Type *KmpcCopyCtorTyArgs[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
+ auto KmpcCopyCtorTy =
+ llvm::FunctionType::get(CGM.VoidPtrTy, KmpcCopyCtorTyArgs,
+ /*isVarArg*/ false)->getPointerTo();
+ // typedef void (*kmpc_dtor)(void *);
+ auto KmpcDtorTy =
+ llvm::FunctionType::get(CGM.VoidTy, CGM.VoidPtrTy, /*isVarArg*/ false)
+ ->getPointerTo();
+ llvm::Type *FnTyArgs[] = {getIdentTyPointerTy(), CGM.VoidPtrTy, KmpcCtorTy,
+ KmpcCopyCtorTy, KmpcDtorTy};
+ auto FnTy = llvm::FunctionType::get(CGM.VoidTy, FnTyArgs,
+ /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_threadprivate_register");
+ break;
+ }
+ case OMPRTL__kmpc_end_critical: {
+ // Build void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
+ // kmp_critical_name *crit);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), CGM.Int32Ty,
+ llvm::PointerType::getUnqual(KmpCriticalNameTy)};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical");
+ break;
+ }
+ case OMPRTL__kmpc_cancel_barrier: {
+ // Build kmp_int32 __kmpc_cancel_barrier(ident_t *loc, kmp_int32
+ // global_tid);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_cancel_barrier");
+ break;
+ }
+ // Build __kmpc_for_static_init*(
+ // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
+ // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
+ // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
+ // kmp_int[32|64] incr, kmp_int[32|64] chunk);
+ case OMPRTL__kmpc_for_static_init_4: {
+ auto ITy = CGM.Int32Ty;
+ auto PtrTy = llvm::PointerType::getUnqual(ITy);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), // loc
+ CGM.Int32Ty, // tid
+ CGM.Int32Ty, // schedtype
+ llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
+ PtrTy, // p_lower
+ PtrTy, // p_upper
+ PtrTy, // p_stride
+ ITy, // incr
+ ITy // chunk
+ };
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_for_static_init_4");
+ break;
+ }
+ case OMPRTL__kmpc_for_static_init_4u: {
+ auto ITy = CGM.Int32Ty;
+ auto PtrTy = llvm::PointerType::getUnqual(ITy);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), // loc
+ CGM.Int32Ty, // tid
+ CGM.Int32Ty, // schedtype
+ llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
+ PtrTy, // p_lower
+ PtrTy, // p_upper
+ PtrTy, // p_stride
+ ITy, // incr
+ ITy // chunk
+ };
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_for_static_init_4u");
+ break;
+ }
+ case OMPRTL__kmpc_for_static_init_8: {
+ auto ITy = CGM.Int64Ty;
+ auto PtrTy = llvm::PointerType::getUnqual(ITy);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), // loc
+ CGM.Int32Ty, // tid
+ CGM.Int32Ty, // schedtype
+ llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
+ PtrTy, // p_lower
+ PtrTy, // p_upper
+ PtrTy, // p_stride
+ ITy, // incr
+ ITy // chunk
+ };
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_for_static_init_8");
+ break;
+ }
+ case OMPRTL__kmpc_for_static_init_8u: {
+ auto ITy = CGM.Int64Ty;
+ auto PtrTy = llvm::PointerType::getUnqual(ITy);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), // loc
+ CGM.Int32Ty, // tid
+ CGM.Int32Ty, // schedtype
+ llvm::PointerType::getUnqual(CGM.Int32Ty), // p_lastiter
+ PtrTy, // p_lower
+ PtrTy, // p_upper
+ PtrTy, // p_stride
+ ITy, // incr
+ ITy // chunk
+ };
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_for_static_init_8u");
+ break;
+ }
+ case OMPRTL__kmpc_for_static_fini: {
+ // Build void __kmpc_for_static_fini(ident_t *loc, kmp_int32 global_tid);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_for_static_fini");
+ break;
+ }
+ case OMPRTL__kmpc_push_num_threads: {
+ // Build void __kmpc_push_num_threads(ident_t *loc, kmp_int32 global_tid,
+ // kmp_int32 num_threads)
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
+ CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_push_num_threads");
+ break;
+ }
+ case OMPRTL__kmpc_serialized_parallel: {
+ // Build void __kmpc_serialized_parallel(ident_t *loc, kmp_int32
+ // global_tid);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_serialized_parallel");
+ break;
+ }
+ case OMPRTL__kmpc_end_serialized_parallel: {
+ // Build void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32
+ // global_tid);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_serialized_parallel");
+ break;
+ }
+ case OMPRTL__kmpc_flush: {
+ // Build void __kmpc_flush(ident_t *loc, ...);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy()};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_flush");
+ break;
+ }
+ case OMPRTL__kmpc_master: {
+ // Build kmp_int32 __kmpc_master(ident_t *loc, kmp_int32 global_tid);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_master");
+ break;
+ }
+ case OMPRTL__kmpc_end_master: {
+ // Build void __kmpc_end_master(ident_t *loc, kmp_int32 global_tid);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_master");
+ break;
+ }
}
return RTLFn;
}
+
+llvm::Constant *
+CGOpenMPRuntime::getOrCreateThreadPrivateCache(const VarDecl *VD) {
+ // Lookup the entry, lazily creating it if necessary.
+ return GetOrCreateInternalVariable(CGM.Int8PtrPtrTy,
+ Twine(CGM.getMangledName(VD)) + ".cache.");
+}
+
+llvm::Value *CGOpenMPRuntime::getOMPAddrOfThreadPrivate(CodeGenFunction &CGF,
+ const VarDecl *VD,
+ llvm::Value *VDAddr,
+ SourceLocation Loc) {
+ auto VarTy = VDAddr->getType()->getPointerElementType();
+ llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
+ GetOpenMPThreadID(CGF, Loc),
+ CGF.Builder.CreatePointerCast(VDAddr, CGM.Int8PtrTy),
+ CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)),
+ getOrCreateThreadPrivateCache(VD)};
+ return CGF.EmitRuntimeCall(
+ CreateRuntimeFunction(OMPRTL__kmpc_threadprivate_cached), Args);
+}
+
+void CGOpenMPRuntime::EmitOMPThreadPrivateVarInit(
+ CodeGenFunction &CGF, llvm::Value *VDAddr, llvm::Value *Ctor,
+ llvm::Value *CopyCtor, llvm::Value *Dtor, SourceLocation Loc) {
+ // Call kmp_int32 __kmpc_global_thread_num(&loc) to init OpenMP runtime
+ // library.
+ auto OMPLoc = EmitOpenMPUpdateLocation(CGF, Loc);
+ CGF.EmitRuntimeCall(CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num),
+ OMPLoc);
+ // Call __kmpc_threadprivate_register(&loc, &var, ctor, cctor/*NULL*/, dtor)
+ // to register constructor/destructor for variable.
+ llvm::Value *Args[] = {OMPLoc,
+ CGF.Builder.CreatePointerCast(VDAddr, CGM.VoidPtrTy),
+ Ctor, CopyCtor, Dtor};
+ CGF.EmitRuntimeCall(
+ CreateRuntimeFunction(OMPRTL__kmpc_threadprivate_register), Args);
+}
+
+llvm::Function *CGOpenMPRuntime::EmitOMPThreadPrivateVarDefinition(
+ const VarDecl *VD, llvm::Value *VDAddr, SourceLocation Loc,
+ bool PerformInit, CodeGenFunction *CGF) {
+ VD = VD->getDefinition(CGM.getContext());
+ if (VD && ThreadPrivateWithDefinition.count(VD) == 0) {
+ ThreadPrivateWithDefinition.insert(VD);
+ QualType ASTTy = VD->getType();
+
+ llvm::Value *Ctor = nullptr, *CopyCtor = nullptr, *Dtor = nullptr;
+ auto Init = VD->getAnyInitializer();
+ if (CGM.getLangOpts().CPlusPlus && PerformInit) {
+ // Generate function that re-emits the declaration's initializer into the
+ // threadprivate copy of the variable VD
+ CodeGenFunction CtorCGF(CGM);
+ FunctionArgList Args;
+ ImplicitParamDecl Dst(CGM.getContext(), /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, CGM.getContext().VoidPtrTy);
+ Args.push_back(&Dst);
+
+ auto &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ CGM.getContext().VoidPtrTy, Args, FunctionType::ExtInfo(),
+ /*isVariadic=*/false);
+ auto FTy = CGM.getTypes().GetFunctionType(FI);
+ auto Fn = CGM.CreateGlobalInitOrDestructFunction(
+ FTy, ".__kmpc_global_ctor_.", Loc);
+ CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidPtrTy, Fn, FI,
+ Args, SourceLocation());
+ auto ArgVal = CtorCGF.EmitLoadOfScalar(
+ CtorCGF.GetAddrOfLocalVar(&Dst),
+ /*Volatile=*/false, CGM.PointerAlignInBytes,
+ CGM.getContext().VoidPtrTy, Dst.getLocation());
+ auto Arg = CtorCGF.Builder.CreatePointerCast(
+ ArgVal,
+ CtorCGF.ConvertTypeForMem(CGM.getContext().getPointerType(ASTTy)));
+ CtorCGF.EmitAnyExprToMem(Init, Arg, Init->getType().getQualifiers(),
+ /*IsInitializer=*/true);
+ ArgVal = CtorCGF.EmitLoadOfScalar(
+ CtorCGF.GetAddrOfLocalVar(&Dst),
+ /*Volatile=*/false, CGM.PointerAlignInBytes,
+ CGM.getContext().VoidPtrTy, Dst.getLocation());
+ CtorCGF.Builder.CreateStore(ArgVal, CtorCGF.ReturnValue);
+ CtorCGF.FinishFunction();
+ Ctor = Fn;
+ }
+ if (VD->getType().isDestructedType() != QualType::DK_none) {
+ // Generate function that emits destructor call for the threadprivate copy
+ // of the variable VD
+ CodeGenFunction DtorCGF(CGM);
+ FunctionArgList Args;
+ ImplicitParamDecl Dst(CGM.getContext(), /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, CGM.getContext().VoidPtrTy);
+ Args.push_back(&Dst);
+
+ auto &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ CGM.getContext().VoidTy, Args, FunctionType::ExtInfo(),
+ /*isVariadic=*/false);
+ auto FTy = CGM.getTypes().GetFunctionType(FI);
+ auto Fn = CGM.CreateGlobalInitOrDestructFunction(
+ FTy, ".__kmpc_global_dtor_.", Loc);
+ DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI, Args,
+ SourceLocation());
+ auto ArgVal = DtorCGF.EmitLoadOfScalar(
+ DtorCGF.GetAddrOfLocalVar(&Dst),
+ /*Volatile=*/false, CGM.PointerAlignInBytes,
+ CGM.getContext().VoidPtrTy, Dst.getLocation());
+ DtorCGF.emitDestroy(ArgVal, ASTTy,
+ DtorCGF.getDestroyer(ASTTy.isDestructedType()),
+ DtorCGF.needsEHCleanup(ASTTy.isDestructedType()));
+ DtorCGF.FinishFunction();
+ Dtor = Fn;
+ }
+ // Do not emit init function if it is not required.
+ if (!Ctor && !Dtor)
+ return nullptr;
+
+ llvm::Type *CopyCtorTyArgs[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
+ auto CopyCtorTy =
+ llvm::FunctionType::get(CGM.VoidPtrTy, CopyCtorTyArgs,
+ /*isVarArg=*/false)->getPointerTo();
+ // Copying constructor for the threadprivate variable.
+ // Must be NULL - reserved by runtime, but currently it requires that this
+ // parameter is always NULL. Otherwise it fires assertion.
+ CopyCtor = llvm::Constant::getNullValue(CopyCtorTy);
+ if (Ctor == nullptr) {
+ auto CtorTy = llvm::FunctionType::get(CGM.VoidPtrTy, CGM.VoidPtrTy,
+ /*isVarArg=*/false)->getPointerTo();
+ Ctor = llvm::Constant::getNullValue(CtorTy);
+ }
+ if (Dtor == nullptr) {
+ auto DtorTy = llvm::FunctionType::get(CGM.VoidTy, CGM.VoidPtrTy,
+ /*isVarArg=*/false)->getPointerTo();
+ Dtor = llvm::Constant::getNullValue(DtorTy);
+ }
+ if (!CGF) {
+ auto InitFunctionTy =
+ llvm::FunctionType::get(CGM.VoidTy, /*isVarArg*/ false);
+ auto InitFunction = CGM.CreateGlobalInitOrDestructFunction(
+ InitFunctionTy, ".__omp_threadprivate_init_.");
+ CodeGenFunction InitCGF(CGM);
+ FunctionArgList ArgList;
+ InitCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, InitFunction,
+ CGM.getTypes().arrangeNullaryFunction(), ArgList,
+ Loc);
+ EmitOMPThreadPrivateVarInit(InitCGF, VDAddr, Ctor, CopyCtor, Dtor, Loc);
+ InitCGF.FinishFunction();
+ return InitFunction;
+ }
+ EmitOMPThreadPrivateVarInit(*CGF, VDAddr, Ctor, CopyCtor, Dtor, Loc);
+ }
+ return nullptr;
+}
+
+void CGOpenMPRuntime::EmitOMPParallelCall(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ llvm::Value *OutlinedFn,
+ llvm::Value *CapturedStruct) {
+ // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/)
+ llvm::Value *Args[] = {
+ EmitOpenMPUpdateLocation(CGF, Loc),
+ CGF.Builder.getInt32(1), // Number of arguments after 'microtask' argument
+ // (there is only one additional argument - 'context')
+ CGF.Builder.CreateBitCast(OutlinedFn, getKmpc_MicroPointerTy()),
+ CGF.EmitCastToVoidPtr(CapturedStruct)};
+ auto RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_fork_call);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
+void CGOpenMPRuntime::EmitOMPSerialCall(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ llvm::Value *OutlinedFn,
+ llvm::Value *CapturedStruct) {
+ auto ThreadID = GetOpenMPThreadID(CGF, Loc);
+ // Build calls:
+ // __kmpc_serialized_parallel(&Loc, GTid);
+ llvm::Value *SerArgs[] = {EmitOpenMPUpdateLocation(CGF, Loc), ThreadID};
+ auto RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_serialized_parallel);
+ CGF.EmitRuntimeCall(RTLFn, SerArgs);
+
+ // OutlinedFn(&GTid, &zero, CapturedStruct);
+ auto ThreadIDAddr = EmitThreadIDAddress(CGF, Loc);
+ auto Int32Ty =
+ CGF.getContext().getIntTypeForBitwidth(/*DestWidth*/ 32, /*Signed*/ true);
+ auto ZeroAddr = CGF.CreateMemTemp(Int32Ty, /*Name*/ ".zero.addr");
+ CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
+ llvm::Value *OutlinedFnArgs[] = {ThreadIDAddr, ZeroAddr, CapturedStruct};
+ CGF.EmitCallOrInvoke(OutlinedFn, OutlinedFnArgs);
+
+ // __kmpc_end_serialized_parallel(&Loc, GTid);
+ llvm::Value *EndSerArgs[] = {EmitOpenMPUpdateLocation(CGF, Loc), ThreadID};
+ RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_end_serialized_parallel);
+ CGF.EmitRuntimeCall(RTLFn, EndSerArgs);
+}
+
+// If we're inside an (outlined) parallel region, use the region info's
+// thread-ID variable (it is passed in a first argument of the outlined function
+// as "kmp_int32 *gtid"). Otherwise, if we're not inside parallel region, but in
+// regular serial code region, get thread ID by calling kmp_int32
+// kmpc_global_thread_num(ident_t *loc), stash this thread ID in a temporary and
+// return the address of that temp.
+llvm::Value *CGOpenMPRuntime::EmitThreadIDAddress(CodeGenFunction &CGF,
+ SourceLocation Loc) {
+ if (auto OMPRegionInfo =
+ dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
+ return CGF.EmitLoadOfLValue(OMPRegionInfo->getThreadIDVariableLValue(CGF),
+ SourceLocation()).getScalarVal();
+ auto ThreadID = GetOpenMPThreadID(CGF, Loc);
+ auto Int32Ty =
+ CGF.getContext().getIntTypeForBitwidth(/*DestWidth*/ 32, /*Signed*/ true);
+ auto ThreadIDTemp = CGF.CreateMemTemp(Int32Ty, /*Name*/ ".threadid_temp.");
+ CGF.EmitStoreOfScalar(ThreadID,
+ CGF.MakeNaturalAlignAddrLValue(ThreadIDTemp, Int32Ty));
+
+ return ThreadIDTemp;
+}
+
+llvm::Constant *
+CGOpenMPRuntime::GetOrCreateInternalVariable(llvm::Type *Ty,
+ const llvm::Twine &Name) {
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ Out << Name;
+ auto RuntimeName = Out.str();
+ auto &Elem = *InternalVars.insert(std::make_pair(RuntimeName, nullptr)).first;
+ if (Elem.second) {
+ assert(Elem.second->getType()->getPointerElementType() == Ty &&
+ "OMP internal variable has different type than requested");
+ return &*Elem.second;
+ }
+
+ return Elem.second = new llvm::GlobalVariable(
+ CGM.getModule(), Ty, /*IsConstant*/ false,
+ llvm::GlobalValue::CommonLinkage, llvm::Constant::getNullValue(Ty),
+ Elem.first());
+}
+
+llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) {
+ llvm::Twine Name(".gomp_critical_user_", CriticalName);
+ return GetOrCreateInternalVariable(KmpCriticalNameTy, Name.concat(".var"));
+}
+
+void CGOpenMPRuntime::EmitOMPCriticalRegion(
+ CodeGenFunction &CGF, StringRef CriticalName,
+ const std::function<void()> &CriticalOpGen, SourceLocation Loc) {
+ auto RegionLock = GetCriticalRegionLock(CriticalName);
+ // __kmpc_critical(ident_t *, gtid, Lock);
+ // CriticalOpGen();
+ // __kmpc_end_critical(ident_t *, gtid, Lock);
+ // Prepare arguments and build a call to __kmpc_critical
+ llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
+ GetOpenMPThreadID(CGF, Loc), RegionLock};
+ auto RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_critical);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+ CriticalOpGen();
+ // Build a call to __kmpc_end_critical
+ RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_end_critical);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
+static void EmitOMPIfStmt(CodeGenFunction &CGF, llvm::Value *IfCond,
+ const std::function<void()> &BodyOpGen) {
+ llvm::Value *CallBool = CGF.EmitScalarConversion(
+ IfCond,
+ CGF.getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true),
+ CGF.getContext().BoolTy);
+
+ auto *ThenBlock = CGF.createBasicBlock("omp_if.then");
+ auto *ContBlock = CGF.createBasicBlock("omp_if.end");
+ // Generate the branch (If-stmt)
+ CGF.Builder.CreateCondBr(CallBool, ThenBlock, ContBlock);
+ CGF.EmitBlock(ThenBlock);
+ BodyOpGen();
+ // Emit the rest of bblocks/branches
+ CGF.EmitBranch(ContBlock);
+ CGF.EmitBlock(ContBlock, true);
+}
+
+void CGOpenMPRuntime::EmitOMPMasterRegion(
+ CodeGenFunction &CGF, const std::function<void()> &MasterOpGen,
+ SourceLocation Loc) {
+ // if(__kmpc_master(ident_t *, gtid)) {
+ // MasterOpGen();
+ // __kmpc_end_master(ident_t *, gtid);
+ // }
+ // Prepare arguments and build a call to __kmpc_master
+ llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
+ GetOpenMPThreadID(CGF, Loc)};
+ auto RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_master);
+ auto *IsMaster = CGF.EmitRuntimeCall(RTLFn, Args);
+ EmitOMPIfStmt(CGF, IsMaster, [&]() -> void {
+ MasterOpGen();
+ // Build a call to __kmpc_end_master.
+ // OpenMP [1.2.2 OpenMP Language Terminology]
+ // For C/C++, an executable statement, possibly compound, with a single
+ // entry at the top and a single exit at the bottom, or an OpenMP construct.
+ // * Access to the structured block must not be the result of a branch.
+ // * The point of exit cannot be a branch out of the structured block.
+ // * The point of entry must not be a call to setjmp().
+ // * longjmp() and throw() must not violate the entry/exit criteria.
+ // * An expression statement, iteration statement, selection statement, or
+ // try block is considered to be a structured block if the corresponding
+ // compound statement obtained by enclosing it in { and } would be a
+ // structured block.
+ // It is analyzed in Sema, so we can just call __kmpc_end_master() on
+ // fallthrough rather than pushing a normal cleanup for it.
+ RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_end_master);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+ });
+}
+
+void CGOpenMPRuntime::EmitOMPBarrierCall(CodeGenFunction &CGF,
+ SourceLocation Loc, bool IsExplicit) {
+ // Build call __kmpc_cancel_barrier(loc, thread_id);
+ auto Flags = static_cast<OpenMPLocationFlags>(
+ OMP_IDENT_KMPC |
+ (IsExplicit ? OMP_IDENT_BARRIER_EXPL : OMP_IDENT_BARRIER_IMPL));
+ // Build call __kmpc_cancel_barrier(loc, thread_id);
+ // Replace __kmpc_barrier() function by __kmpc_cancel_barrier() because this
+ // one provides the same functionality and adds initial support for
+ // cancellation constructs introduced in OpenMP 4.0. __kmpc_cancel_barrier()
+ // is provided default by the runtime library so it safe to make such
+ // replacement.
+ llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc, Flags),
+ GetOpenMPThreadID(CGF, Loc)};
+ auto RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_cancel_barrier);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
+/// \brief Schedule types for 'omp for' loops (these enumerators are taken from
+/// the enum sched_type in kmp.h).
+enum OpenMPSchedType {
+ /// \brief Lower bound for default (unordered) versions.
+ OMP_sch_lower = 32,
+ OMP_sch_static_chunked = 33,
+ OMP_sch_static = 34,
+ OMP_sch_dynamic_chunked = 35,
+ OMP_sch_guided_chunked = 36,
+ OMP_sch_runtime = 37,
+ OMP_sch_auto = 38,
+ /// \brief Lower bound for 'ordered' versions.
+ OMP_ord_lower = 64,
+ /// \brief Lower bound for 'nomerge' versions.
+ OMP_nm_lower = 160,
+};
+
+/// \brief Map the OpenMP loop schedule to the runtime enumeration.
+static OpenMPSchedType getRuntimeSchedule(OpenMPScheduleClauseKind ScheduleKind,
+ bool Chunked) {
+ switch (ScheduleKind) {
+ case OMPC_SCHEDULE_static:
+ return Chunked ? OMP_sch_static_chunked : OMP_sch_static;
+ case OMPC_SCHEDULE_dynamic:
+ return OMP_sch_dynamic_chunked;
+ case OMPC_SCHEDULE_guided:
+ return OMP_sch_guided_chunked;
+ case OMPC_SCHEDULE_auto:
+ return OMP_sch_auto;
+ case OMPC_SCHEDULE_runtime:
+ return OMP_sch_runtime;
+ case OMPC_SCHEDULE_unknown:
+ assert(!Chunked && "chunk was specified but schedule kind not known");
+ return OMP_sch_static;
+ }
+ llvm_unreachable("Unexpected runtime schedule");
+}
+
+bool CGOpenMPRuntime::isStaticNonchunked(OpenMPScheduleClauseKind ScheduleKind,
+ bool Chunked) const {
+ auto Schedule = getRuntimeSchedule(ScheduleKind, Chunked);
+ return Schedule == OMP_sch_static;
+}
+
+void CGOpenMPRuntime::EmitOMPForInit(CodeGenFunction &CGF, SourceLocation Loc,
+ OpenMPScheduleClauseKind ScheduleKind,
+ unsigned IVSize, bool IVSigned,
+ llvm::Value *IL, llvm::Value *LB,
+ llvm::Value *UB, llvm::Value *ST,
+ llvm::Value *Chunk) {
+ OpenMPSchedType Schedule = getRuntimeSchedule(ScheduleKind, Chunk != nullptr);
+ // Call __kmpc_for_static_init(
+ // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
+ // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
+ // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
+ // kmp_int[32|64] incr, kmp_int[32|64] chunk);
+ // TODO: Implement dynamic schedule.
+
+ // If the Chunk was not specified in the clause - use default value 1.
+ if (Chunk == nullptr)
+ Chunk = CGF.Builder.getIntN(IVSize, /*C*/ 1);
+
+ llvm::Value *Args[] = {
+ EmitOpenMPUpdateLocation(CGF, Loc, OMP_IDENT_KMPC),
+ GetOpenMPThreadID(CGF, Loc),
+ CGF.Builder.getInt32(Schedule), // Schedule type
+ IL, // &isLastIter
+ LB, // &LB
+ UB, // &UB
+ ST, // &Stride
+ CGF.Builder.getIntN(IVSize, 1), // Incr
+ Chunk // Chunk
+ };
+ assert((IVSize == 32 || IVSize == 64) &&
+ "Index size is not compatible with the omp runtime");
+ auto F = IVSize == 32 ? (IVSigned ? OMPRTL__kmpc_for_static_init_4
+ : OMPRTL__kmpc_for_static_init_4u)
+ : (IVSigned ? OMPRTL__kmpc_for_static_init_8
+ : OMPRTL__kmpc_for_static_init_8u);
+ auto RTLFn = CreateRuntimeFunction(F);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
+void CGOpenMPRuntime::EmitOMPForFinish(CodeGenFunction &CGF, SourceLocation Loc,
+ OpenMPScheduleClauseKind ScheduleKind) {
+ assert((ScheduleKind == OMPC_SCHEDULE_static ||
+ ScheduleKind == OMPC_SCHEDULE_unknown) &&
+ "Non-static schedule kinds are not yet implemented");
+ // Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
+ llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc, OMP_IDENT_KMPC),
+ GetOpenMPThreadID(CGF, Loc)};
+ auto RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_for_static_fini);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
+void CGOpenMPRuntime::EmitOMPNumThreadsClause(CodeGenFunction &CGF,
+ llvm::Value *NumThreads,
+ SourceLocation Loc) {
+ // Build call __kmpc_push_num_threads(&loc, global_tid, num_threads)
+ llvm::Value *Args[] = {
+ EmitOpenMPUpdateLocation(CGF, Loc), GetOpenMPThreadID(CGF, Loc),
+ CGF.Builder.CreateIntCast(NumThreads, CGF.Int32Ty, /*isSigned*/ true)};
+ llvm::Constant *RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_push_num_threads);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
+void CGOpenMPRuntime::EmitOMPFlush(CodeGenFunction &CGF, ArrayRef<const Expr *>,
+ SourceLocation Loc) {
+ // Build call void __kmpc_flush(ident_t *loc, ...)
+ // FIXME: List of variables is ignored by libiomp5 runtime, no need to
+ // generate it, just request full memory fence.
+ llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
+ llvm::ConstantInt::get(CGM.Int32Ty, 0)};
+ auto *RTLFn = CreateRuntimeFunction(OMPRTL__kmpc_flush);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+}
diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
index 862e8a148c56..6daf8179c14e 100644
--- a/lib/CodeGen/CGOpenMPRuntime.h
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -11,29 +11,31 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_OPENMPRUNTIME_H
-#define CLANG_CODEGEN_OPENMPRUNTIME_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
+#define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
-#include "clang/AST/Type.h"
+#include "clang/Basic/OpenMPKinds.h"
+#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/Type.h"
-#include "llvm/IR/Value.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/IR/ValueHandle.h"
namespace llvm {
-class AllocaInst;
-class CallInst;
-class GlobalVariable;
+class ArrayType;
class Constant;
class Function;
-class Module;
-class StructLayout;
class FunctionType;
+class GlobalVariable;
class StructType;
class Type;
class Value;
} // namespace llvm
namespace clang {
+class Expr;
+class OMPExecutableDirective;
+class VarDecl;
namespace CodeGen {
@@ -42,6 +44,52 @@ class CodeGenModule;
class CGOpenMPRuntime {
public:
+
+private:
+ enum OpenMPRTLFunction {
+ /// \brief Call to void __kmpc_fork_call(ident_t *loc, kmp_int32 argc,
+ /// kmpc_micro microtask, ...);
+ OMPRTL__kmpc_fork_call,
+ /// \brief Call to void *__kmpc_threadprivate_cached(ident_t *loc,
+ /// kmp_int32 global_tid, void *data, size_t size, void ***cache);
+ OMPRTL__kmpc_threadprivate_cached,
+ /// \brief Call to void __kmpc_threadprivate_register( ident_t *,
+ /// void *data, kmpc_ctor ctor, kmpc_cctor cctor, kmpc_dtor dtor);
+ OMPRTL__kmpc_threadprivate_register,
+ // Call to __kmpc_int32 kmpc_global_thread_num(ident_t *loc);
+ OMPRTL__kmpc_global_thread_num,
+ // Call to void __kmpc_critical(ident_t *loc, kmp_int32 global_tid,
+ // kmp_critical_name *crit);
+ OMPRTL__kmpc_critical,
+ // Call to void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
+ // kmp_critical_name *crit);
+ OMPRTL__kmpc_end_critical,
+ // Call to kmp_int32 __kmpc_cancel_barrier(ident_t *loc, kmp_int32
+ // global_tid);
+ OMPRTL__kmpc_cancel_barrier,
+ // Calls for static scheduling 'omp for' loops.
+ OMPRTL__kmpc_for_static_init_4,
+ OMPRTL__kmpc_for_static_init_4u,
+ OMPRTL__kmpc_for_static_init_8,
+ OMPRTL__kmpc_for_static_init_8u,
+ OMPRTL__kmpc_for_static_fini,
+ // Call to void __kmpc_serialized_parallel(ident_t *loc, kmp_int32
+ // global_tid);
+ OMPRTL__kmpc_serialized_parallel,
+ // Call to void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32
+ // global_tid);
+ OMPRTL__kmpc_end_serialized_parallel,
+ // Call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32 global_tid,
+ // kmp_int32 num_threads);
+ OMPRTL__kmpc_push_num_threads,
+ // Call to void __kmpc_flush(ident_t *loc, ...);
+ OMPRTL__kmpc_flush,
+ // Call to kmp_int32 __kmpc_master(ident_t *, kmp_int32 global_tid);
+ OMPRTL__kmpc_master,
+ // Call to void __kmpc_end_master(ident_t *, kmp_int32 global_tid);
+ OMPRTL__kmpc_end_master,
+ };
+
/// \brief Values for bit flags used in the ident_t to describe the fields.
/// All enumeric elements are named and described in accordance with the code
/// from http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp.h
@@ -63,20 +111,11 @@ public:
/// \brief Implicit barrier in 'single' directive.
OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140
};
- enum OpenMPRTLFunction {
- // Call to void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro
- // microtask, ...);
- OMPRTL__kmpc_fork_call,
- // Call to kmp_int32 kmpc_global_thread_num(ident_t *loc);
- OMPRTL__kmpc_global_thread_num
- };
-
-private:
CodeGenModule &CGM;
/// \brief Default const ident_t object used for initialization of all other
/// ident_t objects.
llvm::Constant *DefaultOpenMPPSource;
- /// \brief Map of flags and corrsponding default locations.
+ /// \brief Map of flags and corresponding default locations.
typedef llvm::DenseMap<unsigned, llvm::Value *> OpenMPDefaultLocMapTy;
OpenMPDefaultLocMapTy OpenMPDefaultLocMap;
llvm::Value *GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags);
@@ -121,55 +160,241 @@ private:
IdentField_PSource
};
llvm::StructType *IdentTy;
- /// \brief Map for Sourcelocation and OpenMP runtime library debug locations.
+ /// \brief Map for SourceLocation and OpenMP runtime library debug locations.
typedef llvm::DenseMap<unsigned, llvm::Value *> OpenMPDebugLocMapTy;
OpenMPDebugLocMapTy OpenMPDebugLocMap;
/// \brief The type for a microtask which gets passed to __kmpc_fork_call().
/// Original representation is:
/// typedef void (kmpc_micro)(kmp_int32 global_tid, kmp_int32 bound_tid,...);
llvm::FunctionType *Kmpc_MicroTy;
- /// \brief Map of local debug location and functions.
- typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPLocMapTy;
- OpenMPLocMapTy OpenMPLocMap;
- /// \brief Map of local gtid and functions.
- typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPGtidMapTy;
- OpenMPGtidMapTy OpenMPGtidMap;
+ /// \brief Stores debug location and ThreadID for the function.
+ struct DebugLocThreadIdTy {
+ llvm::Value *DebugLoc;
+ llvm::Value *ThreadID;
+ };
+ /// \brief Map of local debug location, ThreadId and functions.
+ typedef llvm::DenseMap<llvm::Function *, DebugLocThreadIdTy>
+ OpenMPLocThreadIDMapTy;
+ OpenMPLocThreadIDMapTy OpenMPLocThreadIDMap;
+ /// \brief Type kmp_critical_name, originally defined as typedef kmp_int32
+ /// kmp_critical_name[8];
+ llvm::ArrayType *KmpCriticalNameTy;
+ /// \brief An ordered map of auto-generated variables to their unique names.
+ /// It stores variables with the following names: 1) ".gomp_critical_user_" +
+ /// <critical_section_name> + ".var" for "omp critical" directives; 2)
+ /// <mangled_name_for_global_var> + ".cache." for cache for threadprivate
+ /// variables.
+ llvm::StringMap<llvm::AssertingVH<llvm::Constant>, llvm::BumpPtrAllocator>
+ InternalVars;
+
+ /// \brief Emits object of ident_t type with info for source location.
+ /// \param Flags Flags for OpenMP location.
+ ///
+ llvm::Value *
+ EmitOpenMPUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc,
+ OpenMPLocationFlags Flags = OMP_IDENT_KMPC);
+
+ /// \brief Returns pointer to ident_t type.
+ llvm::Type *getIdentTyPointerTy();
+
+ /// \brief Returns pointer to kmpc_micro type.
+ llvm::Type *getKmpc_MicroPointerTy();
+
+ /// \brief Returns specified OpenMP runtime function.
+ /// \param Function OpenMP runtime function.
+ /// \return Specified function.
+ llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function);
+
+ /// \brief If the specified mangled name is not in the module, create and
+ /// return threadprivate cache object. This object is a pointer's worth of
+ /// storage that's reserved for use by the OpenMP runtime.
+ /// \param VD Threadprivate variable.
+ /// \return Cache variable for the specified threadprivate.
+ llvm::Constant *getOrCreateThreadPrivateCache(const VarDecl *VD);
+
+ /// \brief Emits address of the word in a memory where current thread id is
+ /// stored.
+ virtual llvm::Value *EmitThreadIDAddress(CodeGenFunction &CGF,
+ SourceLocation Loc);
+
+ /// \brief Gets thread id value for the current thread.
+ ///
+ llvm::Value *GetOpenMPThreadID(CodeGenFunction &CGF, SourceLocation Loc);
+
+ /// \brief Gets (if variable with the given name already exist) or creates
+ /// internal global variable with the specified Name. The created variable has
+ /// linkage CommonLinkage by default and is initialized by null value.
+ /// \param Ty Type of the global variable. If it is exist already the type
+ /// must be the same.
+ /// \param Name Name of the variable.
+ llvm::Constant *GetOrCreateInternalVariable(llvm::Type *Ty,
+ const llvm::Twine &Name);
+
+ /// \brief Set of threadprivate variables with the generated initializer.
+ llvm::DenseSet<const VarDecl *> ThreadPrivateWithDefinition;
+
+ /// \brief Emits initialization code for the threadprivate variables.
+ /// \param VDAddr Address of the global variable \a VD.
+ /// \param Ctor Pointer to a global init function for \a VD.
+ /// \param CopyCtor Pointer to a global copy function for \a VD.
+ /// \param Dtor Pointer to a global destructor function for \a VD.
+ /// \param Loc Location of threadprivate declaration.
+ void EmitOMPThreadPrivateVarInit(CodeGenFunction &CGF, llvm::Value *VDAddr,
+ llvm::Value *Ctor, llvm::Value *CopyCtor,
+ llvm::Value *Dtor, SourceLocation Loc);
+
+ /// \brief Returns corresponding lock object for the specified critical region
+ /// name. If the lock object does not exist it is created, otherwise the
+ /// reference to the existing copy is returned.
+ /// \param CriticalName Name of the critical region.
+ ///
+ llvm::Value *GetCriticalRegionLock(StringRef CriticalName);
public:
explicit CGOpenMPRuntime(CodeGenModule &CGM);
- ~CGOpenMPRuntime() {}
+ virtual ~CGOpenMPRuntime() {}
+
+ /// \brief Emits outlined function for the specified OpenMP directive \a D
+ /// (required for parallel and task directives). This outlined function has
+ /// type void(*)(kmp_int32 /*ThreadID*/, kmp_int32 /*BoundID*/, struct
+ /// context_vars*).
+ /// \param D OpenMP directive.
+ /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
+ ///
+ virtual llvm::Value *
+ EmitOpenMPOutlinedFunction(const OMPExecutableDirective &D,
+ const VarDecl *ThreadIDVar);
/// \brief Cleans up references to the objects in finished function.
- /// \param CGF Reference to finished CodeGenFunction.
///
void FunctionFinished(CodeGenFunction &CGF);
- /// \brief Emits object of ident_t type with info for source location.
+ /// \brief Emits code for parallel call of the \a OutlinedFn with variables
+ /// captured in a record which address is stored in \a CapturedStruct.
+ /// \param OutlinedFn Outlined function to be run in parallel threads. Type of
+ /// this function is void(*)(kmp_int32, kmp_int32, struct context_vars*).
+ /// \param CapturedStruct A pointer to the record with the references to
+ /// variables used in \a OutlinedFn function.
+ ///
+ virtual void EmitOMPParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
+ llvm::Value *OutlinedFn,
+ llvm::Value *CapturedStruct);
+
+ /// \brief Emits code for serial call of the \a OutlinedFn with variables
+ /// captured in a record which address is stored in \a CapturedStruct.
+ /// \param OutlinedFn Outlined function to be run in serial mode.
+ /// \param CapturedStruct A pointer to the record with the references to
+ /// variables used in \a OutlinedFn function.
+ ///
+ virtual void EmitOMPSerialCall(CodeGenFunction &CGF, SourceLocation Loc,
+ llvm::Value *OutlinedFn,
+ llvm::Value *CapturedStruct);
+
+ /// \brief Emits a critical region.
+ /// \param CriticalName Name of the critical region.
+ /// \param CriticalOpGen Generator for the statement associated with the given
+ /// critical region.
+ virtual void EmitOMPCriticalRegion(CodeGenFunction &CGF,
+ StringRef CriticalName,
+ const std::function<void()> &CriticalOpGen,
+ SourceLocation Loc);
+
+ /// \brief Emits a master region.
+ /// \param MasterOpGen Generator for the statement associated with the given
+ /// master region.
+ virtual void EmitOMPMasterRegion(CodeGenFunction &CGF,
+ const std::function<void()> &MasterOpGen,
+ SourceLocation Loc);
+
+ /// \brief Emits explicit barrier for OpenMP threads.
+ /// \param IsExplicit true, if it is explicitly specified barrier.
+ ///
+ virtual void EmitOMPBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
+ bool IsExplicit = true);
+
+ /// \brief Check if the specified \a ScheduleKind is static non-chunked.
+ /// This kind of worksharing directive is emitted without outer loop.
+ /// \param ScheduleKind Schedule kind specified in the 'schedule' clause.
+ /// \param Chunked True if chunk is specified in the clause.
+ ///
+ virtual bool isStaticNonchunked(OpenMPScheduleClauseKind ScheduleKind,
+ bool Chunked) const;
+
+ /// \brief Call the appropriate runtime routine to initialize it before start
+ /// of loop.
+ ///
+ /// Depending on the loop schedule, it is nesessary to call some runtime
+ /// routine before start of the OpenMP loop to get the loop upper / lower
+ /// bounds \a LB and \a UB and stride \a ST.
+ ///
/// \param CGF Reference to current CodeGenFunction.
/// \param Loc Clang source location.
- /// \param Flags Flags for OpenMP location.
+ /// \param SchedKind Schedule kind, specified by the 'schedule' clause.
+ /// \param IVSize Size of the iteration variable in bits.
+ /// \param IVSigned Sign of the interation variable.
+ /// \param IL Address of the output variable in which the flag of the
+ /// last iteration is returned.
+ /// \param LB Address of the output variable in which the lower iteration
+ /// number is returned.
+ /// \param UB Address of the output variable in which the upper iteration
+ /// number is returned.
+ /// \param ST Address of the output variable in which the stride value is
+ /// returned nesessary to generated the static_chunked scheduled loop.
+ /// \param Chunk Value of the chunk for the static_chunked scheduled loop.
+ /// For the default (nullptr) value, the chunk 1 will be used.
///
- llvm::Value *
- EmitOpenMPUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPLocationFlags Flags = OMP_IDENT_KMPC);
+ virtual void EmitOMPForInit(CodeGenFunction &CGF, SourceLocation Loc,
+ OpenMPScheduleClauseKind SchedKind,
+ unsigned IVSize, bool IVSigned, llvm::Value *IL,
+ llvm::Value *LB, llvm::Value *UB, llvm::Value *ST,
+ llvm::Value *Chunk = nullptr);
- /// \brief Generates global thread number value.
+ /// \brief Call the appropriate runtime routine to notify that we finished
+ /// all the work with current loop.
+ ///
/// \param CGF Reference to current CodeGenFunction.
/// \param Loc Clang source location.
+ /// \param ScheduleKind Schedule kind, specified by the 'schedule' clause.
///
- llvm::Value *GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
- SourceLocation Loc);
+ virtual void EmitOMPForFinish(CodeGenFunction &CGF, SourceLocation Loc,
+ OpenMPScheduleClauseKind ScheduleKind);
- /// \brief Returns pointer to ident_t type;
- llvm::Type *getIdentTyPointerTy();
+ /// \brief Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32
+ /// global_tid, kmp_int32 num_threads) to generate code for 'num_threads'
+ /// clause.
+ /// \param NumThreads An integer value of threads.
+ virtual void EmitOMPNumThreadsClause(CodeGenFunction &CGF,
+ llvm::Value *NumThreads,
+ SourceLocation Loc);
- /// \brief Returns pointer to kmpc_micro type;
- llvm::Type *getKmpc_MicroPointerTy();
+ /// \brief Returns address of the threadprivate variable for the current
+ /// thread.
+ /// \param VD Threadprivate variable.
+ /// \param VDAddr Address of the global variable \a VD.
+ /// \param Loc Location of the reference to threadprivate var.
+ /// \return Address of the threadprivate variable for the current thread.
+ virtual llvm::Value *getOMPAddrOfThreadPrivate(CodeGenFunction &CGF,
+ const VarDecl *VD,
+ llvm::Value *VDAddr,
+ SourceLocation Loc);
- /// \brief Returns specified OpenMP runtime function.
- /// \param Function OpenMP runtime function.
- /// \return Specified function.
- llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function);
+ /// \brief Emit a code for initialization of threadprivate variable. It emits
+ /// a call to runtime library which adds initial value to the newly created
+ /// threadprivate variable (if it is not constant) and registers destructor
+ /// for the variable (if any).
+ /// \param VD Threadprivate variable.
+ /// \param VDAddr Address of the global variable \a VD.
+ /// \param Loc Location of threadprivate declaration.
+ /// \param PerformInit true if initialization expression is not constant.
+ virtual llvm::Function *
+ EmitOMPThreadPrivateVarDefinition(const VarDecl *VD, llvm::Value *VDAddr,
+ SourceLocation Loc, bool PerformInit,
+ CodeGenFunction *CGF = nullptr);
+
+ /// \brief Emit flush of the variables specified in 'omp flush' directive.
+ /// \param Vars List of variables to flush.
+ virtual void EmitOMPFlush(CodeGenFunction &CGF, ArrayRef<const Expr *> Vars,
+ SourceLocation Loc);
};
} // namespace CodeGen
} // namespace clang
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index b45fee56ea09..2de0b2f87fc1 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CGRECORDLAYOUT_H
-#define CLANG_CODEGEN_CGRECORDLAYOUT_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGRECORDLAYOUT_H
+#define LLVM_CLANG_LIB_CODEGEN_CGRECORDLAYOUT_H
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index a10d8e791b0f..7ad394b5eeb0 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -93,7 +93,7 @@ struct CGRecordLowering {
bool operator <(const MemberInfo& a) const { return Offset < a.Offset; }
};
// The constructor.
- CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D);
+ CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D, bool Packed);
// Short helper routines.
/// \brief Constructs a MemberInfo instance from an offset and llvm::Type *.
MemberInfo StorageInfo(CharUnits Offset, llvm::Type *Data) {
@@ -174,7 +174,7 @@ struct CGRecordLowering {
/// padding that is or can potentially be used.
void clipTailPadding();
/// \brief Determines if we need a packed llvm struct.
- void determinePacked();
+ void determinePacked(bool NVBaseType);
/// \brief Inserts padding everwhere it's needed.
void insertPadding();
/// \brief Fills out the structures that are ultimately consumed.
@@ -203,12 +203,12 @@ private:
};
} // namespace {
-CGRecordLowering::CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D)
+CGRecordLowering::CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D, bool Packed)
: Types(Types), Context(Types.getContext()), D(D),
RD(dyn_cast<CXXRecordDecl>(D)),
Layout(Types.getContext().getASTRecordLayout(D)),
DataLayout(Types.getDataLayout()), IsZeroInitializable(true),
- IsZeroInitializableAsBase(true), Packed(false) {}
+ IsZeroInitializableAsBase(true), Packed(Packed) {}
void CGRecordLowering::setBitFieldInfo(
const FieldDecl *FD, CharUnits StartOffset, llvm::Type *StorageType) {
@@ -269,7 +269,7 @@ void CGRecordLowering::lower(bool NVBaseType) {
std::stable_sort(Members.begin(), Members.end());
Members.push_back(StorageInfo(Size, getIntNType(8)));
clipTailPadding();
- determinePacked();
+ determinePacked(NVBaseType);
insertPadding();
Members.pop_back();
calculateZeroInit();
@@ -279,13 +279,11 @@ void CGRecordLowering::lower(bool NVBaseType) {
void CGRecordLowering::lowerUnion() {
CharUnits LayoutSize = Layout.getSize();
llvm::Type *StorageType = nullptr;
- // Compute zero-initializable status.
- if (!D->field_empty() && !isZeroInitializable(*D->field_begin()))
- IsZeroInitializable = IsZeroInitializableAsBase = false;
+ bool SeenNamedMember = false;
// Iterate through the fields setting bitFieldInfo and the Fields array. Also
// locate the "most appropriate" storage type. The heuristic for finding the
// storage type isn't necessary, the first (non-0-length-bitfield) field's
- // type would work fine and be simpler but would be differen than what we've
+ // type would work fine and be simpler but would be different than what we've
// been doing and cause lit tests to change.
for (const auto *Field : D->fields()) {
if (Field->isBitField()) {
@@ -299,6 +297,23 @@ void CGRecordLowering::lowerUnion() {
}
Fields[Field->getCanonicalDecl()] = 0;
llvm::Type *FieldType = getStorageType(Field);
+ // Compute zero-initializable status.
+ // This union might not be zero initialized: it may contain a pointer to
+ // data member which might have some exotic initialization sequence.
+ // If this is the case, then we aught not to try and come up with a "better"
+ // type, it might not be very easy to come up with a Constant which
+ // correctly initializes it.
+ if (!SeenNamedMember && Field->getDeclName()) {
+ SeenNamedMember = true;
+ if (!isZeroInitializable(Field)) {
+ IsZeroInitializable = IsZeroInitializableAsBase = false;
+ StorageType = FieldType;
+ }
+ }
+ // Because our union isn't zero initializable, we won't be getting a better
+ // storage type.
+ if (!IsZeroInitializable)
+ continue;
// Conditionally update our storage type if we've got a new "better" one.
if (!StorageType ||
getAlignment(FieldType) > getAlignment(StorageType) ||
@@ -533,8 +548,13 @@ void CGRecordLowering::clipTailPadding() {
}
}
-void CGRecordLowering::determinePacked() {
+void CGRecordLowering::determinePacked(bool NVBaseType) {
+ if (Packed)
+ return;
CharUnits Alignment = CharUnits::One();
+ CharUnits NVAlignment = CharUnits::One();
+ CharUnits NVSize =
+ !NVBaseType && RD ? Layout.getNonVirtualSize() : CharUnits::Zero();
for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
MemberEnd = Members.end();
Member != MemberEnd; ++Member) {
@@ -544,12 +564,19 @@ void CGRecordLowering::determinePacked() {
// then the entire record must be packed.
if (Member->Offset % getAlignment(Member->Data))
Packed = true;
+ if (Member->Offset < NVSize)
+ NVAlignment = std::max(NVAlignment, getAlignment(Member->Data));
Alignment = std::max(Alignment, getAlignment(Member->Data));
}
// If the size of the record (the capstone's offset) is not a multiple of the
// record's alignment, it must be packed.
if (Members.back().Offset % Alignment)
Packed = true;
+ // If the non-virtual sub-object is not a multiple of the non-virtual
+ // sub-object's alignment, it must be packed. We cannot have a packed
+ // non-virtual sub-object and an unpacked complete object or vise versa.
+ if (NVSize % NVAlignment)
+ Packed = true;
// Update the alignment of the sentinal.
if (!Packed)
Members.back().Data = getIntNType(Context.toBits(Alignment));
@@ -641,20 +668,24 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
llvm::StructType *Ty) {
- CGRecordLowering Builder(*this, D);
+ CGRecordLowering Builder(*this, D, /*Packed=*/false);
- Builder.lower(false);
+ Builder.lower(/*NonVirtualBaseType=*/false);
// If we're in C++, compute the base subobject type.
llvm::StructType *BaseTy = nullptr;
if (isa<CXXRecordDecl>(D) && !D->isUnion() && !D->hasAttr<FinalAttr>()) {
BaseTy = Ty;
if (Builder.Layout.getNonVirtualSize() != Builder.Layout.getSize()) {
- CGRecordLowering BaseBuilder(*this, D);
- BaseBuilder.lower(true);
+ CGRecordLowering BaseBuilder(*this, D, /*Packed=*/Builder.Packed);
+ BaseBuilder.lower(/*NonVirtualBaseType=*/true);
BaseTy = llvm::StructType::create(
getLLVMContext(), BaseBuilder.FieldTypes, "", BaseBuilder.Packed);
addRecordTypeName(D, BaseTy, ".base");
+ // BaseTy and Ty must agree on their packedness for getLLVMFieldNo to work
+ // on both of them with the same index.
+ assert(Builder.Packed == BaseBuilder.Packed &&
+ "Non-virtual and complete types must agree on packedness");
}
}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index c2b64a7662b6..e3bdf8661ef7 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -185,6 +185,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::OMPForDirectiveClass:
EmitOMPForDirective(cast<OMPForDirective>(*S));
break;
+ case Stmt::OMPForSimdDirectiveClass:
+ EmitOMPForSimdDirective(cast<OMPForSimdDirective>(*S));
+ break;
case Stmt::OMPSectionsDirectiveClass:
EmitOMPSectionsDirective(cast<OMPSectionsDirective>(*S));
break;
@@ -203,6 +206,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::OMPParallelForDirectiveClass:
EmitOMPParallelForDirective(cast<OMPParallelForDirective>(*S));
break;
+ case Stmt::OMPParallelForSimdDirectiveClass:
+ EmitOMPParallelForSimdDirective(cast<OMPParallelForSimdDirective>(*S));
+ break;
case Stmt::OMPParallelSectionsDirectiveClass:
EmitOMPParallelSectionsDirective(cast<OMPParallelSectionsDirective>(*S));
break;
@@ -221,6 +227,18 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::OMPFlushDirectiveClass:
EmitOMPFlushDirective(cast<OMPFlushDirective>(*S));
break;
+ case Stmt::OMPOrderedDirectiveClass:
+ EmitOMPOrderedDirective(cast<OMPOrderedDirective>(*S));
+ break;
+ case Stmt::OMPAtomicDirectiveClass:
+ EmitOMPAtomicDirective(cast<OMPAtomicDirective>(*S));
+ break;
+ case Stmt::OMPTargetDirectiveClass:
+ EmitOMPTargetDirective(cast<OMPTargetDirective>(*S));
+ break;
+ case Stmt::OMPTeamsDirectiveClass:
+ EmitOMPTeamsDirective(cast<OMPTeamsDirective>(*S));
+ break;
}
}
@@ -547,7 +565,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
if (const Stmt *Else = S.getElse()) {
{
// There is no need to emit line number for unconditional branch.
- SuppressDebugLocation S(Builder);
+ ApplyDebugLocation DL(*this);
EmitBlock(ElseBlock);
}
{
@@ -556,7 +574,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
}
{
// There is no need to emit line number for unconditional branch.
- SuppressDebugLocation S(Builder);
+ ApplyDebugLocation DL(*this);
EmitBranch(ContBlock);
}
}
@@ -567,13 +585,15 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
llvm::BranchInst *CondBr,
- const ArrayRef<const Attr *> &Attrs) {
+ ArrayRef<const Attr *> Attrs) {
// Return if there are no hints.
if (Attrs.empty())
return;
// Add vectorize and unroll hints to the metadata on the conditional branch.
- SmallVector<llvm::Value *, 2> Metadata(1);
+ //
+ // FIXME: Should this really start with a size of 1?
+ SmallVector<llvm::Metadata *, 2> Metadata(1);
for (const auto *Attr : Attrs) {
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
@@ -582,8 +602,7 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
continue;
LoopHintAttr::OptionType Option = LH->getOption();
- int ValueInt = LH->getValue();
-
+ LoopHintAttr::LoopHintState State = LH->getState();
const char *MetadataName;
switch (Option) {
case LoopHintAttr::Vectorize:
@@ -595,19 +614,29 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
MetadataName = "llvm.loop.interleave.count";
break;
case LoopHintAttr::Unroll:
- MetadataName = "llvm.loop.unroll.enable";
+ // With the unroll loop hint, a non-zero value indicates full unrolling.
+ MetadataName = State == LoopHintAttr::Disable ? "llvm.loop.unroll.disable"
+ : "llvm.loop.unroll.full";
break;
case LoopHintAttr::UnrollCount:
MetadataName = "llvm.loop.unroll.count";
break;
}
- llvm::Value *Value;
+ Expr *ValueExpr = LH->getValue();
+ int ValueInt = 1;
+ if (ValueExpr) {
+ llvm::APSInt ValueAPS =
+ ValueExpr->EvaluateKnownConstInt(CGM.getContext());
+ ValueInt = static_cast<int>(ValueAPS.getSExtValue());
+ }
+
+ llvm::Constant *Value;
llvm::MDString *Name;
switch (Option) {
case LoopHintAttr::Vectorize:
case LoopHintAttr::Interleave:
- if (ValueInt == 1) {
+ if (State != LoopHintAttr::Disable) {
// FIXME: In the future I will modifiy the behavior of the metadata
// so we can enable/disable vectorization and interleaving separately.
Name = llvm::MDString::get(Context, "llvm.loop.vectorize.enable");
@@ -619,27 +648,26 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
// Fallthrough.
case LoopHintAttr::VectorizeWidth:
case LoopHintAttr::InterleaveCount:
+ case LoopHintAttr::UnrollCount:
Name = llvm::MDString::get(Context, MetadataName);
Value = llvm::ConstantInt::get(Int32Ty, ValueInt);
break;
case LoopHintAttr::Unroll:
Name = llvm::MDString::get(Context, MetadataName);
- Value = (ValueInt == 0) ? Builder.getFalse() : Builder.getTrue();
- break;
- case LoopHintAttr::UnrollCount:
- Name = llvm::MDString::get(Context, MetadataName);
- Value = llvm::ConstantInt::get(Int32Ty, ValueInt);
+ Value = nullptr;
break;
}
- SmallVector<llvm::Value *, 2> OpValues;
+ SmallVector<llvm::Metadata *, 2> OpValues;
OpValues.push_back(Name);
- OpValues.push_back(Value);
+ if (Value)
+ OpValues.push_back(llvm::ConstantAsMetadata::get(Value));
// Set or overwrite metadata indicated by Name.
Metadata.push_back(llvm::MDNode::get(Context, OpValues));
}
+ // FIXME: This condition is never false. Should it be an assert?
if (!Metadata.empty()) {
// Add llvm.loop MDNode to CondBr.
llvm::MDNode *LoopID = llvm::MDNode::get(Context, Metadata);
@@ -650,7 +678,7 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
}
void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
- const ArrayRef<const Attr *> &WhileAttrs) {
+ ArrayRef<const Attr *> WhileAttrs) {
RegionCounter Cnt = getPGORegionCounter(&S);
// Emit the header for the loop, which will also become
@@ -724,6 +752,7 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
// Immediately force cleanup.
ConditionScope.ForceCleanup();
+ EmitStopPoint(&S);
// Branch to the loop header again.
EmitBranch(LoopHeader.getBlock());
@@ -739,7 +768,7 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
}
void CodeGenFunction::EmitDoStmt(const DoStmt &S,
- const ArrayRef<const Attr *> &DoAttrs) {
+ ArrayRef<const Attr *> DoAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("do.end");
JumpDest LoopCond = getJumpDestInCurrentScope("do.cond");
@@ -800,14 +829,10 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S,
}
void CodeGenFunction::EmitForStmt(const ForStmt &S,
- const ArrayRef<const Attr *> &ForAttrs) {
+ ArrayRef<const Attr *> ForAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
- RunCleanupsScope ForScope(*this);
-
- CGDebugInfo *DI = getDebugInfo();
- if (DI)
- DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
+ LexicalScope ForScope(*this, S.getSourceRange());
// Evaluate the first part before the loop.
if (S.getInit())
@@ -835,7 +860,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
// Create a cleanup scope for the condition variable cleanups.
- RunCleanupsScope ConditionScope(*this);
+ LexicalScope ConditionScope(*this, S.getSourceRange());
if (S.getCond()) {
// If the for statement has a condition scope, emit the local variable
@@ -891,13 +916,12 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
BreakContinueStack.pop_back();
ConditionScope.ForceCleanup();
+
+ EmitStopPoint(&S);
EmitBranch(CondBlock);
ForScope.ForceCleanup();
- if (DI)
- DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
-
LoopStack.pop();
// Emit the fall-through block.
@@ -906,14 +930,10 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
void
CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
- const ArrayRef<const Attr *> &ForAttrs) {
+ ArrayRef<const Attr *> ForAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
- RunCleanupsScope ForScope(*this);
-
- CGDebugInfo *DI = getDebugInfo();
- if (DI)
- DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
+ LexicalScope ForScope(*this, S.getSourceRange());
// Evaluate the first pieces before the loop.
EmitStmt(S.getRangeStmt());
@@ -963,11 +983,12 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
{
// Create a separate cleanup scope for the loop variable and body.
- RunCleanupsScope BodyScope(*this);
+ LexicalScope BodyScope(*this, S.getSourceRange());
EmitStmt(S.getLoopVarStmt());
EmitStmt(S.getBody());
}
+ EmitStopPoint(&S);
// If there is an increment, emit it next.
EmitBlock(Continue.getBlock());
EmitStmt(S.getInc());
@@ -978,9 +999,6 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
ForScope.ForceCleanup();
- if (DI)
- DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
-
LoopStack.pop();
// Emit the fall-through block.
@@ -1641,6 +1659,12 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
while (Constraint[1] && Constraint[1] != ',')
Constraint++;
break;
+ case '&':
+ case '%':
+ Result += *Constraint;
+ while (Constraint[1] && Constraint[1] == *Constraint)
+ Constraint++;
+ break;
case ',':
Result += "|";
break;
@@ -1751,10 +1775,10 @@ llvm::Value* CodeGenFunction::EmitAsmInput(
/// asm.
static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
CodeGenFunction &CGF) {
- SmallVector<llvm::Value *, 8> Locs;
+ SmallVector<llvm::Metadata *, 8> Locs;
// Add the location of the first line to the MDNode.
- Locs.push_back(llvm::ConstantInt::get(CGF.Int32Ty,
- Str->getLocStart().getRawEncoding()));
+ Locs.push_back(llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ CGF.Int32Ty, Str->getLocStart().getRawEncoding())));
StringRef StrVal = Str->getString();
if (!StrVal.empty()) {
const SourceManager &SM = CGF.CGM.getContext().getSourceManager();
@@ -1766,8 +1790,8 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
if (StrVal[i] != '\n') continue;
SourceLocation LineLoc = Str->getLocationOfByte(i+1, SM, LangOpts,
CGF.getTarget());
- Locs.push_back(llvm::ConstantInt::get(CGF.Int32Ty,
- LineLoc.getRawEncoding()));
+ Locs.push_back(llvm::ConstantAsMetadata::get(
+ llvm::ConstantInt::get(CGF.Int32Ty, LineLoc.getRawEncoding())));
}
}
@@ -1905,7 +1929,19 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
}
}
- unsigned NumConstraints = S.getNumOutputs() + S.getNumInputs();
+ // If this is a Microsoft-style asm blob, store the return registers (EAX:EDX)
+ // to the return value slot. Only do this when returning in registers.
+ if (isa<MSAsmStmt>(&S)) {
+ const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo();
+ if (RetAI.isDirect() || RetAI.isExtend()) {
+ // Make a fake lvalue for the return value slot.
+ LValue ReturnSlot = MakeAddrLValue(ReturnValue, FnRetTy);
+ CGM.getTargetCodeGenInfo().addReturnRegisterOutputs(
+ *this, ReturnSlot, Constraints, ResultRegTypes, ResultTruncRegTypes,
+ ResultRegDests, AsmString, S.getNumOutputs());
+ SawAsmBlock = true;
+ }
+ }
for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
const Expr *InputExpr = S.getInputExpr(i);
@@ -1978,9 +2014,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
StringRef Clobber = S.getClobber(i);
if (Clobber != "memory" && Clobber != "cc")
- Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
+ Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
- if (i != 0 || NumConstraints != 0)
+ if (!Constraints.empty())
Constraints += ',';
Constraints += "~{";
@@ -2018,10 +2054,17 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::Attribute::NoUnwind);
// Slap the source location of the inline asm into a !srcloc metadata on the
- // call. FIXME: Handle metadata for MS-style inline asms.
- if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S))
+ // call.
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) {
Result->setMetadata("srcloc", getAsmSrcLocInfo(gccAsmStmt->getAsmString(),
*this));
+ } else {
+ // At least put the line number on MS inline asm blobs.
+ auto Loc = llvm::ConstantInt::get(Int32Ty, S.getAsmLoc().getRawEncoding());
+ Result->setMetadata("srcloc",
+ llvm::MDNode::get(getLLVMContext(),
+ llvm::ConstantAsMetadata::get(Loc)));
+ }
// Extract all of the register value results from the asm.
std::vector<llvm::Value*> RegResults;
@@ -2034,6 +2077,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
}
}
+ assert(RegResults.size() == ResultRegTypes.size());
+ assert(RegResults.size() == ResultTruncRegTypes.size());
+ assert(RegResults.size() == ResultRegDests.size());
for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
llvm::Value *Tmp = RegResults[i];
@@ -2067,46 +2113,35 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
}
}
-static LValue InitCapturedStruct(CodeGenFunction &CGF, const CapturedStmt &S) {
+LValue CodeGenFunction::InitCapturedStruct(const CapturedStmt &S) {
const RecordDecl *RD = S.getCapturedRecordDecl();
- QualType RecordTy = CGF.getContext().getRecordType(RD);
+ QualType RecordTy = getContext().getRecordType(RD);
// Initialize the captured struct.
- LValue SlotLV = CGF.MakeNaturalAlignAddrLValue(
- CGF.CreateMemTemp(RecordTy, "agg.captured"), RecordTy);
+ LValue SlotLV = MakeNaturalAlignAddrLValue(
+ CreateMemTemp(RecordTy, "agg.captured"), RecordTy);
RecordDecl::field_iterator CurField = RD->field_begin();
for (CapturedStmt::capture_init_iterator I = S.capture_init_begin(),
E = S.capture_init_end();
I != E; ++I, ++CurField) {
- LValue LV = CGF.EmitLValueForFieldInitialization(SlotLV, *CurField);
- CGF.EmitInitializerForField(*CurField, LV, *I, ArrayRef<VarDecl *>());
+ LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField);
+ if (CurField->hasCapturedVLAType()) {
+ auto VAT = CurField->getCapturedVLAType();
+ EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV);
+ } else {
+ EmitInitializerForField(*CurField, LV, *I, None);
+ }
}
return SlotLV;
}
-static void InitVLACaptures(CodeGenFunction &CGF, const CapturedStmt &S) {
- for (auto &C : S.captures()) {
- if (C.capturesVariable()) {
- QualType QTy;
- auto VD = C.getCapturedVar();
- if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD))
- QTy = PVD->getOriginalType();
- else
- QTy = VD->getType();
- if (QTy->isVariablyModifiedType()) {
- CGF.EmitVariablyModifiedType(QTy);
- }
- }
- }
-}
-
/// Generate an outlined function for the body of a CapturedStmt, store any
/// captured variables into the captured struct, and call the outlined function.
llvm::Function *
CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) {
- LValue CapStruct = InitCapturedStruct(*this, S);
+ LValue CapStruct = InitCapturedStruct(S);
// Emit the CapturedDecl
CodeGenFunction CGF(CGM, true);
@@ -2122,7 +2157,7 @@ CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) {
llvm::Value *
CodeGenFunction::GenerateCapturedStmtArgument(const CapturedStmt &S) {
- LValue CapStruct = InitCapturedStruct(*this, S);
+ LValue CapStruct = InitCapturedStruct(S);
return CapStruct.getAddress();
}
@@ -2163,22 +2198,27 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) {
CapturedStmtInfo->setContextValue(Builder.CreateLoad(DeclPtr));
// Initialize variable-length arrays.
- InitVLACaptures(*this, S);
+ LValue Base = MakeNaturalAlignAddrLValue(CapturedStmtInfo->getContextValue(),
+ Ctx.getTagDeclType(RD));
+ for (auto *FD : RD->fields()) {
+ if (FD->hasCapturedVLAType()) {
+ auto *ExprArg = EmitLoadOfLValue(EmitLValueForField(Base, FD),
+ S.getLocStart()).getScalarVal();
+ auto VAT = FD->getCapturedVLAType();
+ VLASizeMap[VAT->getSizeExpr()] = ExprArg;
+ }
+ }
// If 'this' is captured, load it into CXXThisValue.
if (CapturedStmtInfo->isCXXThisExprCaptured()) {
FieldDecl *FD = CapturedStmtInfo->getThisFieldDecl();
- LValue LV = MakeNaturalAlignAddrLValue(CapturedStmtInfo->getContextValue(),
- Ctx.getTagDeclType(RD));
- LValue ThisLValue = EmitLValueForField(LV, FD);
+ LValue ThisLValue = EmitLValueForField(Base, FD);
CXXThisValue = EmitLoadOfLValue(ThisLValue, Loc).getScalarVal();
}
PGO.assignRegionCounters(CD, F);
CapturedStmtInfo->EmitBody(*this, CD->getBody());
FinishFunction(CD->getBodyRBrace());
- PGO.emitInstrumentationData();
- PGO.destroyRegionCounters();
return F;
}
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index 867f41592dd9..78fd37ce6562 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -14,43 +14,411 @@
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "TargetInfo.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtOpenMP.h"
using namespace clang;
using namespace CodeGen;
+namespace {
+/// \brief RAII for emitting code of CapturedStmt without function outlining.
+class InlinedOpenMPRegion {
+ CodeGenFunction &CGF;
+ CodeGenFunction::CGCapturedStmtInfo *PrevCapturedStmtInfo;
+ const Decl *StoredCurCodeDecl;
+
+ /// \brief A class to emit CapturedStmt construct as inlined statement without
+ /// generating a function for outlined code.
+ class CGInlinedOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
+ public:
+ CGInlinedOpenMPRegionInfo() : CGCapturedStmtInfo() {}
+ };
+
+public:
+ InlinedOpenMPRegion(CodeGenFunction &CGF, const Stmt *S)
+ : CGF(CGF), PrevCapturedStmtInfo(CGF.CapturedStmtInfo),
+ StoredCurCodeDecl(CGF.CurCodeDecl) {
+ CGF.CurCodeDecl = cast<CapturedStmt>(S)->getCapturedDecl();
+ CGF.CapturedStmtInfo = new CGInlinedOpenMPRegionInfo();
+ }
+ ~InlinedOpenMPRegion() {
+ delete CGF.CapturedStmtInfo;
+ CGF.CapturedStmtInfo = PrevCapturedStmtInfo;
+ CGF.CurCodeDecl = StoredCurCodeDecl;
+ }
+};
+} // namespace
+
//===----------------------------------------------------------------------===//
// OpenMP Directive Emission
//===----------------------------------------------------------------------===//
-void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
- const CapturedStmt *CS = cast<CapturedStmt>(S.getAssociatedStmt());
- llvm::Value *CapturedStruct = GenerateCapturedStmtArgument(*CS);
+/// \brief Emits code for OpenMP 'if' clause using specified \a CodeGen
+/// function. Here is the logic:
+/// if (Cond) {
+/// CodeGen(true);
+/// } else {
+/// CodeGen(false);
+/// }
+static void EmitOMPIfClause(CodeGenFunction &CGF, const Expr *Cond,
+ const std::function<void(bool)> &CodeGen) {
+ CodeGenFunction::LexicalScope ConditionScope(CGF, Cond->getSourceRange());
- llvm::Value *OutlinedFn;
+ // If the condition constant folds and can be elided, try to avoid emitting
+ // the condition and the dead arm of the if/else.
+ bool CondConstant;
+ if (CGF.ConstantFoldsToSimpleInteger(Cond, CondConstant)) {
+ CodeGen(CondConstant);
+ return;
+ }
+
+ // Otherwise, the condition did not fold, or we couldn't elide it. Just
+ // emit the conditional branch.
+ auto ThenBlock = CGF.createBasicBlock(/*name*/ "omp_if.then");
+ auto ElseBlock = CGF.createBasicBlock(/*name*/ "omp_if.else");
+ auto ContBlock = CGF.createBasicBlock(/*name*/ "omp_if.end");
+ CGF.EmitBranchOnBoolExpr(Cond, ThenBlock, ElseBlock, /*TrueCount*/ 0);
+
+ // Emit the 'then' code.
+ CGF.EmitBlock(ThenBlock);
+ CodeGen(/*ThenBlock*/ true);
+ CGF.EmitBranch(ContBlock);
+ // Emit the 'else' code if present.
+ {
+ // There is no need to emit line number for unconditional branch.
+ ApplyDebugLocation DL(CGF);
+ CGF.EmitBlock(ElseBlock);
+ }
+ CodeGen(/*ThenBlock*/ false);
{
- CodeGenFunction CGF(CGM, true);
- CGCapturedStmtInfo CGInfo(*CS, CS->getCapturedRegionKind());
- CGF.CapturedStmtInfo = &CGInfo;
- OutlinedFn = CGF.GenerateCapturedStmtFunction(*CS);
+ // There is no need to emit line number for unconditional branch.
+ ApplyDebugLocation DL(CGF);
+ CGF.EmitBranch(ContBlock);
+ }
+ // Emit the continuation block for code after the if.
+ CGF.EmitBlock(ContBlock, /*IsFinished*/ true);
+}
+
+void CodeGenFunction::EmitOMPAggregateAssign(LValue OriginalAddr,
+ llvm::Value *PrivateAddr,
+ const Expr *AssignExpr,
+ QualType OriginalType,
+ const VarDecl *VDInit) {
+ EmitBlock(createBasicBlock(".omp.assign.begin."));
+ if (!isa<CXXConstructExpr>(AssignExpr) || isTrivialInitializer(AssignExpr)) {
+ // Perform simple memcpy.
+ EmitAggregateAssign(PrivateAddr, OriginalAddr.getAddress(),
+ AssignExpr->getType());
+ } else {
+ // Perform element-by-element initialization.
+ QualType ElementTy;
+ auto SrcBegin = OriginalAddr.getAddress();
+ auto DestBegin = PrivateAddr;
+ auto ArrayTy = OriginalType->getAsArrayTypeUnsafe();
+ auto SrcNumElements = emitArrayLength(ArrayTy, ElementTy, SrcBegin);
+ auto DestNumElements = emitArrayLength(ArrayTy, ElementTy, DestBegin);
+ auto SrcEnd = Builder.CreateGEP(SrcBegin, SrcNumElements);
+ auto DestEnd = Builder.CreateGEP(DestBegin, DestNumElements);
+ // The basic structure here is a do-while loop, because we don't
+ // need to check for the zero-element case.
+ auto BodyBB = createBasicBlock("omp.arraycpy.body");
+ auto DoneBB = createBasicBlock("omp.arraycpy.done");
+ auto IsEmpty =
+ Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty");
+ Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
+
+ // Enter the loop body, making that address the current address.
+ auto EntryBB = Builder.GetInsertBlock();
+ EmitBlock(BodyBB);
+ auto SrcElementPast = Builder.CreatePHI(SrcBegin->getType(), 2,
+ "omp.arraycpy.srcElementPast");
+ SrcElementPast->addIncoming(SrcEnd, EntryBB);
+ auto DestElementPast = Builder.CreatePHI(DestBegin->getType(), 2,
+ "omp.arraycpy.destElementPast");
+ DestElementPast->addIncoming(DestEnd, EntryBB);
+
+ // Shift the address back by one element.
+ auto NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true);
+ auto DestElement = Builder.CreateGEP(DestElementPast, NegativeOne,
+ "omp.arraycpy.dest.element");
+ auto SrcElement = Builder.CreateGEP(SrcElementPast, NegativeOne,
+ "omp.arraycpy.src.element");
+ {
+ // Create RunCleanScope to cleanup possible temps.
+ CodeGenFunction::RunCleanupsScope Init(*this);
+ // Emit initialization for single element.
+ LocalDeclMap[VDInit] = SrcElement;
+ EmitAnyExprToMem(AssignExpr, DestElement,
+ AssignExpr->getType().getQualifiers(),
+ /*IsInitializer*/ false);
+ LocalDeclMap.erase(VDInit);
+ }
+
+ // Check whether we've reached the end.
+ auto Done =
+ Builder.CreateICmpEQ(DestElement, DestBegin, "omp.arraycpy.done");
+ Builder.CreateCondBr(Done, DoneBB, BodyBB);
+ DestElementPast->addIncoming(DestElement, Builder.GetInsertBlock());
+ SrcElementPast->addIncoming(SrcElement, Builder.GetInsertBlock());
+
+ // Done.
+ EmitBlock(DoneBB, true);
+ }
+ EmitBlock(createBasicBlock(".omp.assign.end."));
+}
+
+void CodeGenFunction::EmitOMPFirstprivateClause(
+ const OMPExecutableDirective &D,
+ CodeGenFunction::OMPPrivateScope &PrivateScope) {
+ auto PrivateFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_firstprivate;
+ };
+ for (OMPExecutableDirective::filtered_clause_iterator<decltype(PrivateFilter)>
+ I(D.clauses(), PrivateFilter); I; ++I) {
+ auto *C = cast<OMPFirstprivateClause>(*I);
+ auto IRef = C->varlist_begin();
+ auto InitsRef = C->inits().begin();
+ for (auto IInit : C->private_copies()) {
+ auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
+ auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
+ bool IsRegistered;
+ if (*InitsRef != nullptr) {
+ // Emit VarDecl with copy init for arrays.
+ auto *FD = CapturedStmtInfo->lookup(OrigVD);
+ LValue Base = MakeNaturalAlignAddrLValue(
+ CapturedStmtInfo->getContextValue(),
+ getContext().getTagDeclType(FD->getParent()));
+ auto OriginalAddr = EmitLValueForField(Base, FD);
+ auto VDInit = cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl());
+ IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value * {
+ auto Emission = EmitAutoVarAlloca(*VD);
+ // Emit initialization of aggregate firstprivate vars.
+ EmitOMPAggregateAssign(OriginalAddr, Emission.getAllocatedAddress(),
+ VD->getInit(), (*IRef)->getType(), VDInit);
+ EmitAutoVarCleanups(Emission);
+ return Emission.getAllocatedAddress();
+ });
+ } else
+ IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value * {
+ // Emit private VarDecl with copy init.
+ EmitDecl(*VD);
+ return GetAddrOfLocalVar(VD);
+ });
+ assert(IsRegistered && "counter already registered as private");
+ // Silence the warning about unused variable.
+ (void)IsRegistered;
+ ++IRef, ++InitsRef;
+ }
+ }
+}
+
+void CodeGenFunction::EmitOMPPrivateClause(
+ const OMPExecutableDirective &D,
+ CodeGenFunction::OMPPrivateScope &PrivateScope) {
+ auto PrivateFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_private;
+ };
+ for (OMPExecutableDirective::filtered_clause_iterator<decltype(PrivateFilter)>
+ I(D.clauses(), PrivateFilter); I; ++I) {
+ auto *C = cast<OMPPrivateClause>(*I);
+ auto IRef = C->varlist_begin();
+ for (auto IInit : C->private_copies()) {
+ auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
+ auto VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
+ bool IsRegistered =
+ PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value * {
+ // Emit private VarDecl with copy init.
+ EmitDecl(*VD);
+ return GetAddrOfLocalVar(VD);
+ });
+ assert(IsRegistered && "counter already registered as private");
+ // Silence the warning about unused variable.
+ (void)IsRegistered;
+ ++IRef;
+ }
+ }
+}
+
+/// \brief Emits code for OpenMP parallel directive in the parallel region.
+static void EmitOMPParallelCall(CodeGenFunction &CGF,
+ const OMPParallelDirective &S,
+ llvm::Value *OutlinedFn,
+ llvm::Value *CapturedStruct) {
+ if (auto C = S.getSingleClause(/*K*/ OMPC_num_threads)) {
+ CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
+ auto NumThreadsClause = cast<OMPNumThreadsClause>(C);
+ auto NumThreads = CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(),
+ /*IgnoreResultAssign*/ true);
+ CGF.CGM.getOpenMPRuntime().EmitOMPNumThreadsClause(
+ CGF, NumThreads, NumThreadsClause->getLocStart());
+ }
+ CGF.CGM.getOpenMPRuntime().EmitOMPParallelCall(CGF, S.getLocStart(),
+ OutlinedFn, CapturedStruct);
+}
+
+void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
+ auto CS = cast<CapturedStmt>(S.getAssociatedStmt());
+ auto CapturedStruct = GenerateCapturedStmtArgument(*CS);
+ auto OutlinedFn = CGM.getOpenMPRuntime().EmitOpenMPOutlinedFunction(
+ S, *CS->getCapturedDecl()->param_begin());
+ if (auto C = S.getSingleClause(/*K*/ OMPC_if)) {
+ auto Cond = cast<OMPIfClause>(C)->getCondition();
+ EmitOMPIfClause(*this, Cond, [&](bool ThenBlock) {
+ if (ThenBlock)
+ EmitOMPParallelCall(*this, S, OutlinedFn, CapturedStruct);
+ else
+ CGM.getOpenMPRuntime().EmitOMPSerialCall(*this, S.getLocStart(),
+ OutlinedFn, CapturedStruct);
+ });
+ } else
+ EmitOMPParallelCall(*this, S, OutlinedFn, CapturedStruct);
+}
+
+void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &S,
+ bool SeparateIter) {
+ RunCleanupsScope BodyScope(*this);
+ // Update counters values on current iteration.
+ for (auto I : S.updates()) {
+ EmitIgnoredExpr(I);
+ }
+ // On a continue in the body, jump to the end.
+ auto Continue = getJumpDestInCurrentScope("omp.body.continue");
+ BreakContinueStack.push_back(BreakContinue(JumpDest(), Continue));
+ // Emit loop body.
+ EmitStmt(S.getBody());
+ // The end (updates/cleanups).
+ EmitBlock(Continue.getBlock());
+ BreakContinueStack.pop_back();
+ if (SeparateIter) {
+ // TODO: Update lastprivates if the SeparateIter flag is true.
+ // This will be implemented in a follow-up OMPLastprivateClause patch, but
+ // result should be still correct without it, as we do not make these
+ // variables private yet.
+ }
+}
+
+void CodeGenFunction::EmitOMPInnerLoop(const OMPLoopDirective &S,
+ OMPPrivateScope &LoopScope,
+ bool SeparateIter) {
+ auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end");
+ auto Cnt = getPGORegionCounter(&S);
+
+ // Start the loop with a block that tests the condition.
+ auto CondBlock = createBasicBlock("omp.inner.for.cond");
+ EmitBlock(CondBlock);
+ LoopStack.push(CondBlock);
+
+ // If there are any cleanups between here and the loop-exit scope,
+ // create a block to stage a loop exit along.
+ auto ExitBlock = LoopExit.getBlock();
+ if (LoopScope.requiresCleanups())
+ ExitBlock = createBasicBlock("omp.inner.for.cond.cleanup");
+
+ auto LoopBody = createBasicBlock("omp.inner.for.body");
+
+ // Emit condition: "IV < LastIteration + 1 [ - 1]"
+ // ("- 1" when lastprivate clause is present - separate one iteration).
+ llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond(SeparateIter));
+ Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock,
+ PGO.createLoopWeights(S.getCond(SeparateIter), Cnt));
+
+ if (ExitBlock != LoopExit.getBlock()) {
+ EmitBlock(ExitBlock);
+ EmitBranchThroughCleanup(LoopExit);
+ }
+
+ EmitBlock(LoopBody);
+ Cnt.beginRegion(Builder);
+
+ // Create a block for the increment.
+ auto Continue = getJumpDestInCurrentScope("omp.inner.for.inc");
+ BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
+
+ EmitOMPLoopBody(S);
+ EmitStopPoint(&S);
+
+ // Emit "IV = IV + 1" and a back-edge to the condition block.
+ EmitBlock(Continue.getBlock());
+ EmitIgnoredExpr(S.getInc());
+ BreakContinueStack.pop_back();
+ EmitBranch(CondBlock);
+ LoopStack.pop();
+ // Emit the fall-through block.
+ EmitBlock(LoopExit.getBlock());
+}
+
+void CodeGenFunction::EmitOMPSimdFinal(const OMPLoopDirective &S) {
+ auto IC = S.counters().begin();
+ for (auto F : S.finals()) {
+ if (LocalDeclMap.lookup(cast<DeclRefExpr>((*IC))->getDecl())) {
+ EmitIgnoredExpr(F);
+ }
+ ++IC;
}
+}
- // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/)
- llvm::Value *Args[] = {
- CGM.getOpenMPRuntime().EmitOpenMPUpdateLocation(*this, S.getLocStart()),
- Builder.getInt32(1), // Number of arguments after 'microtask' argument
- // (there is only one additional argument - 'context')
- Builder.CreateBitCast(OutlinedFn,
- CGM.getOpenMPRuntime().getKmpc_MicroPointerTy()),
- EmitCastToVoidPtr(CapturedStruct)};
- llvm::Constant *RTLFn = CGM.getOpenMPRuntime().CreateRuntimeFunction(
- CGOpenMPRuntime::OMPRTL__kmpc_fork_call);
- EmitRuntimeCall(RTLFn, Args);
+static void EmitOMPAlignedClause(CodeGenFunction &CGF, CodeGenModule &CGM,
+ const OMPAlignedClause &Clause) {
+ unsigned ClauseAlignment = 0;
+ if (auto AlignmentExpr = Clause.getAlignment()) {
+ auto AlignmentCI =
+ cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AlignmentExpr));
+ ClauseAlignment = static_cast<unsigned>(AlignmentCI->getZExtValue());
+ }
+ for (auto E : Clause.varlists()) {
+ unsigned Alignment = ClauseAlignment;
+ if (Alignment == 0) {
+ // OpenMP [2.8.1, Description]
+ // If no optional parameter is specified, implementation-defined default
+ // alignments for SIMD instructions on the target platforms are assumed.
+ Alignment = CGM.getTargetCodeGenInfo().getOpenMPSimdDefaultAlignment(
+ E->getType());
+ }
+ assert((Alignment == 0 || llvm::isPowerOf2_32(Alignment)) &&
+ "alignment is not power of 2");
+ if (Alignment != 0) {
+ llvm::Value *PtrValue = CGF.EmitScalarExpr(E);
+ CGF.EmitAlignmentAssumption(PtrValue, Alignment);
+ }
+ }
+}
+
+static void EmitPrivateLoopCounters(CodeGenFunction &CGF,
+ CodeGenFunction::OMPPrivateScope &LoopScope,
+ ArrayRef<Expr *> Counters) {
+ for (auto *E : Counters) {
+ auto VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
+ bool IsRegistered = LoopScope.addPrivate(VD, [&]() -> llvm::Value * {
+ // Emit var without initialization.
+ auto VarEmission = CGF.EmitAutoVarAlloca(*VD);
+ CGF.EmitAutoVarCleanups(VarEmission);
+ return VarEmission.getAllocatedAddress();
+ });
+ assert(IsRegistered && "counter already registered as private");
+ // Silence the warning about unused variable.
+ (void)IsRegistered;
+ }
+ (void)LoopScope.Privatize();
}
void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
- const CapturedStmt *CS = cast<CapturedStmt>(S.getAssociatedStmt());
- const Stmt *Body = CS->getCapturedStmt();
+ // Pragma 'simd' code depends on presence of 'lastprivate'.
+ // If present, we have to separate last iteration of the loop:
+ //
+ // if (LastIteration != 0) {
+ // for (IV in 0..LastIteration-1) BODY;
+ // BODY with updates of lastprivate vars;
+ // <Final counter/linear vars updates>;
+ // }
+ //
+ // otherwise (when there's no lastprivate):
+ //
+ // for (IV in 0..LastIteration) BODY;
+ // <Final counter/linear vars updates>;
+ //
+
+ // Walk clauses and process safelen/lastprivate.
+ bool SeparateIter = false;
LoopStack.setParallel();
LoopStack.setVectorizerEnable(true);
for (auto C : S.clauses()) {
@@ -66,16 +434,181 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
LoopStack.setParallel(false);
break;
}
+ case OMPC_aligned:
+ EmitOMPAlignedClause(*this, CGM, cast<OMPAlignedClause>(*C));
+ break;
+ case OMPC_lastprivate:
+ SeparateIter = true;
+ break;
default:
// Not handled yet
;
}
}
- EmitStmt(Body);
+
+ InlinedOpenMPRegion Region(*this, S.getAssociatedStmt());
+ RunCleanupsScope DirectiveScope(*this);
+
+ CGDebugInfo *DI = getDebugInfo();
+ if (DI)
+ DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
+
+ // Emit the loop iteration variable.
+ const Expr *IVExpr = S.getIterationVariable();
+ const VarDecl *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
+ EmitVarDecl(*IVDecl);
+ EmitIgnoredExpr(S.getInit());
+
+ // Emit the iterations count variable.
+ // If it is not a variable, Sema decided to calculate iterations count on each
+ // iteration (e.g., it is foldable into a constant).
+ if (auto LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
+ EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
+ // Emit calculation of the iterations count.
+ EmitIgnoredExpr(S.getCalcLastIteration());
+ }
+
+ if (SeparateIter) {
+ // Emit: if (LastIteration > 0) - begin.
+ RegionCounter Cnt = getPGORegionCounter(&S);
+ auto ThenBlock = createBasicBlock("simd.if.then");
+ auto ContBlock = createBasicBlock("simd.if.end");
+ EmitBranchOnBoolExpr(S.getPreCond(), ThenBlock, ContBlock, Cnt.getCount());
+ EmitBlock(ThenBlock);
+ Cnt.beginRegion(Builder);
+ // Emit 'then' code.
+ {
+ OMPPrivateScope LoopScope(*this);
+ EmitPrivateLoopCounters(*this, LoopScope, S.counters());
+ EmitOMPInnerLoop(S, LoopScope, /* SeparateIter */ true);
+ EmitOMPLoopBody(S, /* SeparateIter */ true);
+ }
+ EmitOMPSimdFinal(S);
+ // Emit: if (LastIteration != 0) - end.
+ EmitBranch(ContBlock);
+ EmitBlock(ContBlock, true);
+ } else {
+ {
+ OMPPrivateScope LoopScope(*this);
+ EmitPrivateLoopCounters(*this, LoopScope, S.counters());
+ EmitOMPInnerLoop(S, LoopScope);
+ }
+ EmitOMPSimdFinal(S);
+ }
+
+ if (DI)
+ DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
}
-void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &) {
- llvm_unreachable("CodeGen for 'omp for' is not supported yet.");
+/// \brief Emit a helper variable and return corresponding lvalue.
+static LValue EmitOMPHelperVar(CodeGenFunction &CGF,
+ const DeclRefExpr *Helper) {
+ auto VDecl = cast<VarDecl>(Helper->getDecl());
+ CGF.EmitVarDecl(*VDecl);
+ return CGF.EmitLValue(Helper);
+}
+
+void CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
+ // Emit the loop iteration variable.
+ auto IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
+ auto IVDecl = cast<VarDecl>(IVExpr->getDecl());
+ EmitVarDecl(*IVDecl);
+
+ // Emit the iterations count variable.
+ // If it is not a variable, Sema decided to calculate iterations count on each
+ // iteration (e.g., it is foldable into a constant).
+ if (auto LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
+ EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
+ // Emit calculation of the iterations count.
+ EmitIgnoredExpr(S.getCalcLastIteration());
+ }
+
+ auto &RT = CGM.getOpenMPRuntime();
+
+ // Check pre-condition.
+ {
+ // Skip the entire loop if we don't meet the precondition.
+ RegionCounter Cnt = getPGORegionCounter(&S);
+ auto ThenBlock = createBasicBlock("omp.precond.then");
+ auto ContBlock = createBasicBlock("omp.precond.end");
+ EmitBranchOnBoolExpr(S.getPreCond(), ThenBlock, ContBlock, Cnt.getCount());
+ EmitBlock(ThenBlock);
+ Cnt.beginRegion(Builder);
+ // Emit 'then' code.
+ {
+ // Emit helper vars inits.
+ LValue LB =
+ EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getLowerBoundVariable()));
+ LValue UB =
+ EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getUpperBoundVariable()));
+ LValue ST =
+ EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
+ LValue IL =
+ EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getIsLastIterVariable()));
+
+ OMPPrivateScope LoopScope(*this);
+ EmitPrivateLoopCounters(*this, LoopScope, S.counters());
+
+ // Detect the loop schedule kind and chunk.
+ auto ScheduleKind = OMPC_SCHEDULE_unknown;
+ llvm::Value *Chunk = nullptr;
+ if (auto C = cast_or_null<OMPScheduleClause>(
+ S.getSingleClause(OMPC_schedule))) {
+ ScheduleKind = C->getScheduleKind();
+ if (auto Ch = C->getChunkSize()) {
+ Chunk = EmitScalarExpr(Ch);
+ Chunk = EmitScalarConversion(Chunk, Ch->getType(),
+ S.getIterationVariable()->getType());
+ }
+ }
+ const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
+ const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
+ if (RT.isStaticNonchunked(ScheduleKind,
+ /* Chunked */ Chunk != nullptr)) {
+ // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
+ // When no chunk_size is specified, the iteration space is divided into
+ // chunks that are approximately equal in size, and at most one chunk is
+ // distributed to each thread. Note that the size of the chunks is
+ // unspecified in this case.
+ RT.EmitOMPForInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned,
+ IL.getAddress(), LB.getAddress(), UB.getAddress(),
+ ST.getAddress());
+ // UB = min(UB, GlobalUB);
+ EmitIgnoredExpr(S.getEnsureUpperBound());
+ // IV = LB;
+ EmitIgnoredExpr(S.getInit());
+ // while (idx <= UB) { BODY; ++idx; }
+ EmitOMPInnerLoop(S, LoopScope);
+ // Tell the runtime we are done.
+ RT.EmitOMPForFinish(*this, S.getLocStart(), ScheduleKind);
+ } else
+ ErrorUnsupported(&S, "OpenMP loop with requested schedule");
+ }
+ // We're now done with the loop, so jump to the continuation block.
+ EmitBranch(ContBlock);
+ EmitBlock(ContBlock, true);
+ }
+}
+
+void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) {
+ InlinedOpenMPRegion Region(*this, S.getAssociatedStmt());
+ RunCleanupsScope DirectiveScope(*this);
+
+ CGDebugInfo *DI = getDebugInfo();
+ if (DI)
+ DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
+
+ EmitOMPWorksharingLoop(S);
+
+ // Emit an implicit barrier at the end.
+ CGM.getOpenMPRuntime().EmitOMPBarrierCall(*this, S.getLocStart(),
+ /*IsExplicit*/ false);
+ if (DI)
+ DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
+}
+
+void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &) {
+ llvm_unreachable("CodeGen for 'omp for simd' is not supported yet.");
}
void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &) {
@@ -90,12 +623,24 @@ void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &) {
llvm_unreachable("CodeGen for 'omp single' is not supported yet.");
}
-void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &) {
- llvm_unreachable("CodeGen for 'omp master' is not supported yet.");
+void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
+ CGM.getOpenMPRuntime().EmitOMPMasterRegion(*this, [&]() -> void {
+ InlinedOpenMPRegion Region(*this, S.getAssociatedStmt());
+ RunCleanupsScope Scope(*this);
+ EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ EnsureInsertPoint();
+ }, S.getLocStart());
}
-void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &) {
- llvm_unreachable("CodeGen for 'omp critical' is not supported yet.");
+void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) {
+ CGM.getOpenMPRuntime().EmitOMPCriticalRegion(
+ *this, S.getDirectiveName().getAsString(), [&]() -> void {
+ InlinedOpenMPRegion Region(*this, S.getAssociatedStmt());
+ RunCleanupsScope Scope(*this);
+ EmitStmt(
+ cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ EnsureInsertPoint();
+ }, S.getLocStart());
}
void
@@ -103,6 +648,11 @@ CodeGenFunction::EmitOMPParallelForDirective(const OMPParallelForDirective &) {
llvm_unreachable("CodeGen for 'omp parallel for' is not supported yet.");
}
+void CodeGenFunction::EmitOMPParallelForSimdDirective(
+ const OMPParallelForSimdDirective &) {
+ llvm_unreachable("CodeGen for 'omp parallel for simd' is not supported yet.");
+}
+
void CodeGenFunction::EmitOMPParallelSectionsDirective(
const OMPParallelSectionsDirective &) {
llvm_unreachable("CodeGen for 'omp parallel sections' is not supported yet.");
@@ -116,15 +666,40 @@ void CodeGenFunction::EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &) {
llvm_unreachable("CodeGen for 'omp taskyield' is not supported yet.");
}
-void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &) {
- llvm_unreachable("CodeGen for 'omp barrier' is not supported yet.");
+void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) {
+ CGM.getOpenMPRuntime().EmitOMPBarrierCall(*this, S.getLocStart());
}
void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &) {
llvm_unreachable("CodeGen for 'omp taskwait' is not supported yet.");
}
-void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &) {
- llvm_unreachable("CodeGen for 'omp flush' is not supported yet.");
+void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) {
+ CGM.getOpenMPRuntime().EmitOMPFlush(
+ *this, [&]() -> ArrayRef<const Expr *> {
+ if (auto C = S.getSingleClause(/*K*/ OMPC_flush)) {
+ auto FlushClause = cast<OMPFlushClause>(C);
+ return llvm::makeArrayRef(FlushClause->varlist_begin(),
+ FlushClause->varlist_end());
+ }
+ return llvm::None;
+ }(),
+ S.getLocStart());
+}
+
+void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &) {
+ llvm_unreachable("CodeGen for 'omp ordered' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &) {
+ llvm_unreachable("CodeGen for 'omp atomic' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &) {
+ llvm_unreachable("CodeGen for 'omp target' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &) {
+ llvm_unreachable("CodeGen for 'omp teams' is not supported yet.");
}
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 0df2c43d11b5..acb2a56fab30 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -48,7 +48,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(GD);
return GetOrCreateLLVMFunction(Name, Ty, GD, /*ForVTable=*/true,
- /*DontDefer*/ true);
+ /*DontDefer=*/true, /*IsThunk=*/true);
}
static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
@@ -159,14 +159,10 @@ void CodeGenFunction::GenerateVarArgsThunk(
// with "this".
llvm::Value *ThisPtr = &*AI;
llvm::BasicBlock *EntryBB = Fn->begin();
- llvm::Instruction *ThisStore = nullptr;
- 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;
- }
- }
+ llvm::Instruction *ThisStore =
+ std::find_if(EntryBB->begin(), EntryBB->end(), [&](llvm::Instruction &I) {
+ return isa<llvm::StoreInst>(I) && I.getOperand(0) == ThisPtr;
+ });
assert(ThisStore && "Store of this should be in entry block?");
// Adjust "this", if necessary.
Builder.SetInsertPoint(ThisStore);
@@ -194,60 +190,71 @@ void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD,
const CGFunctionInfo &FnInfo) {
assert(!CurGD.getDecl() && "CurGD was already set!");
CurGD = GD;
+ CurFuncIsThunk = true;
// Build FunctionArgs.
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
QualType ThisType = MD->getThisType(getContext());
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- QualType ResultType =
- CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getReturnType();
+ QualType ResultType = CGM.getCXXABI().HasThisReturn(GD)
+ ? ThisType
+ : CGM.getCXXABI().hasMostDerivedReturn(GD)
+ ? CGM.getContext().VoidPtrTy
+ : FPT->getReturnType();
FunctionArgList FunctionArgs;
// Create the implicit 'this' parameter declaration.
CGM.getCXXABI().buildThisParam(*this, FunctionArgs);
// Add the rest of the parameters.
- for (FunctionDecl::param_const_iterator I = MD->param_begin(),
- E = MD->param_end();
- I != E; ++I)
- FunctionArgs.push_back(*I);
+ FunctionArgs.append(MD->param_begin(), MD->param_end());
if (isa<CXXDestructorDecl>(MD))
CGM.getCXXABI().addImplicitStructorParams(*this, ResultType, FunctionArgs);
// Start defining the function.
StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
- MD->getLocation(), SourceLocation());
+ MD->getLocation(), MD->getLocation());
// Since we didn't pass a GlobalDecl to StartFunction, do this ourselves.
CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
CXXThisValue = CXXABIThisValue;
}
-void CodeGenFunction::EmitCallAndReturnForThunk(GlobalDecl GD,
- llvm::Value *Callee,
+void CodeGenFunction::EmitCallAndReturnForThunk(llvm::Value *Callee,
const ThunkInfo *Thunk) {
assert(isa<CXXMethodDecl>(CurGD.getDecl()) &&
"Please use a new CGF for this thunk");
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(CurGD.getDecl());
// Adjust the 'this' pointer if necessary
llvm::Value *AdjustedThisPtr = Thunk ? CGM.getCXXABI().performThisAdjustment(
*this, LoadCXXThis(), Thunk->This)
: LoadCXXThis();
+ if (CurFnInfo->usesInAlloca()) {
+ // We don't handle return adjusting thunks, because they require us to call
+ // the copy constructor. For now, fall through and pretend the return
+ // adjustment was empty so we don't crash.
+ if (Thunk && !Thunk->Return.isEmpty()) {
+ CGM.ErrorUnsupported(
+ MD, "non-trivial argument copy for return-adjusting thunk");
+ }
+ EmitMustTailThunk(MD, AdjustedThisPtr, Callee);
+ return;
+ }
+
// Start building CallArgs.
CallArgList CallArgs;
QualType ThisType = MD->getThisType(getContext());
CallArgs.add(RValue::get(AdjustedThisPtr), ThisType);
if (isa<CXXDestructorDecl>(MD))
- CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, GD, CallArgs);
+ CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, CurGD, CallArgs);
// Add the rest of the arguments.
- for (FunctionDecl::param_const_iterator I = MD->param_begin(),
- E = MD->param_end(); I != E; ++I)
- EmitDelegateCallArg(CallArgs, *I, (*I)->getLocStart());
+ for (const ParmVarDecl *PD : MD->params())
+ EmitDelegateCallArg(CallArgs, PD, PD->getLocStart());
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
@@ -270,8 +277,11 @@ void CodeGenFunction::EmitCallAndReturnForThunk(GlobalDecl GD,
#endif
// Determine whether we have a return value slot to use.
- QualType ResultType =
- CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getReturnType();
+ QualType ResultType = CGM.getCXXABI().HasThisReturn(CurGD)
+ ? ThisType
+ : CGM.getCXXABI().hasMostDerivedReturn(CurGD)
+ ? CGM.getContext().VoidPtrTy
+ : FPT->getReturnType();
ReturnValueSlot Slot;
if (!ResultType->isVoidType() &&
CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
@@ -279,8 +289,9 @@ void CodeGenFunction::EmitCallAndReturnForThunk(GlobalDecl GD,
Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
// Now emit our call.
- RValue RV = EmitCall(*CurFnInfo, Callee, Slot, CallArgs, MD);
-
+ llvm::Instruction *CallOrInvoke;
+ RValue RV = EmitCall(*CurFnInfo, Callee, Slot, CallArgs, MD, &CallOrInvoke);
+
// Consider return adjustment if we have ThunkInfo.
if (Thunk && !Thunk->Return.isEmpty())
RV = PerformReturnAdjustment(*this, ResultType, RV, *Thunk);
@@ -295,6 +306,62 @@ void CodeGenFunction::EmitCallAndReturnForThunk(GlobalDecl GD,
FinishFunction();
}
+void CodeGenFunction::EmitMustTailThunk(const CXXMethodDecl *MD,
+ llvm::Value *AdjustedThisPtr,
+ llvm::Value *Callee) {
+ // Emitting a musttail call thunk doesn't use any of the CGCall.cpp machinery
+ // to translate AST arguments into LLVM IR arguments. For thunks, we know
+ // that the caller prototype more or less matches the callee prototype with
+ // the exception of 'this'.
+ SmallVector<llvm::Value *, 8> Args;
+ for (llvm::Argument &A : CurFn->args())
+ Args.push_back(&A);
+
+ // Set the adjusted 'this' pointer.
+ const ABIArgInfo &ThisAI = CurFnInfo->arg_begin()->info;
+ if (ThisAI.isDirect()) {
+ const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo();
+ int ThisArgNo = RetAI.isIndirect() && !RetAI.isSRetAfterThis() ? 1 : 0;
+ llvm::Type *ThisType = Args[ThisArgNo]->getType();
+ if (ThisType != AdjustedThisPtr->getType())
+ AdjustedThisPtr = Builder.CreateBitCast(AdjustedThisPtr, ThisType);
+ Args[ThisArgNo] = AdjustedThisPtr;
+ } else {
+ assert(ThisAI.isInAlloca() && "this is passed directly or inalloca");
+ llvm::Value *ThisAddr = GetAddrOfLocalVar(CXXABIThisDecl);
+ llvm::Type *ThisType =
+ cast<llvm::PointerType>(ThisAddr->getType())->getElementType();
+ if (ThisType != AdjustedThisPtr->getType())
+ AdjustedThisPtr = Builder.CreateBitCast(AdjustedThisPtr, ThisType);
+ Builder.CreateStore(AdjustedThisPtr, ThisAddr);
+ }
+
+ // Emit the musttail call manually. Even if the prologue pushed cleanups, we
+ // don't actually want to run them.
+ llvm::CallInst *Call = Builder.CreateCall(Callee, Args);
+ Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
+
+ // Apply the standard set of call attributes.
+ unsigned CallingConv;
+ CodeGen::AttributeListType AttributeList;
+ CGM.ConstructAttributeList(*CurFnInfo, MD, AttributeList, CallingConv,
+ /*AttrOnCallSite=*/true);
+ llvm::AttributeSet Attrs =
+ llvm::AttributeSet::get(getLLVMContext(), AttributeList);
+ Call->setAttributes(Attrs);
+ Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
+
+ if (Call->getType()->isVoidTy())
+ Builder.CreateRetVoid();
+ else
+ Builder.CreateRet(Call);
+
+ // Finish the function to maintain CodeGenFunction invariants.
+ // FIXME: Don't emit unreachable code.
+ EmitBlock(createBasicBlock());
+ FinishFunction();
+}
+
void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk) {
@@ -306,7 +373,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
// Make the call and return the result.
- EmitCallAndReturnForThunk(GD, Callee, &Thunk);
+ EmitCallAndReturnForThunk(Callee, &Thunk);
// Set the right linkage.
CGM.setFunctionLinkage(GD, Fn);
@@ -612,7 +679,8 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
// We're at the end of the translation unit, so the current key
// function is fully correct.
- if (const CXXMethodDecl *keyFunction = Context.getCurrentKeyFunction(RD)) {
+ const CXXMethodDecl *keyFunction = Context.getCurrentKeyFunction(RD);
+ if (keyFunction && !RD->hasAttr<DLLImportAttr>()) {
// If this class has a key function, use that to determine the
// linkage of the vtable.
const FunctionDecl *def = nullptr;
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index 69cf079567e3..e0195a22eb1e 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CGVTABLE_H
-#define CLANG_CODEGEN_CGVTABLE_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGVTABLES_H
+#define LLVM_CLANG_LIB_CODEGEN_CGVTABLES_H
#include "clang/AST/BaseSubobject.h"
#include "clang/AST/CharUnits.h"
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 956f3247bd82..82cd9496e00c 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CGVALUE_H
-#define CLANG_CODEGEN_CGVALUE_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGVALUE_H
+#define LLVM_CLANG_LIB_CODEGEN_CGVALUE_H
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 00a87d87a290..10c2409f6bff 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -16,6 +16,15 @@ set(LLVM_LINK_COMPONENTS
TransformUtils
)
+# In a standard Clang+LLVM build, we need to generate intrinsics before
+# building codegen. In a standalone build, LLVM is already built and we don't
+# need this dependency. Furthermore, LLVM doesn't export it so we can't have
+# this dependency.
+set(codegen_deps intrinsics_gen)
+if (CLANG_BUILT_STANDALONE)
+ set(codegen_deps)
+endif()
+
add_clang_library(clangCodeGen
BackendUtil.cpp
CGAtomic.cpp
@@ -57,17 +66,19 @@ add_clang_library(clangCodeGen
CodeGenPGO.cpp
CodeGenTBAA.cpp
CodeGenTypes.cpp
+ CoverageMappingGen.cpp
ItaniumCXXABI.cpp
MicrosoftCXXABI.cpp
ModuleBuilder.cpp
- SanitizerBlacklist.cpp
+ SanitizerMetadata.cpp
TargetInfo.cpp
DEPENDS
- intrinsics_gen
+ ${codegen_deps}
LINK_LIBS
clangAST
clangBasic
clangFrontend
+ clangLex
)
diff --git a/lib/CodeGen/CodeGenABITypes.cpp b/lib/CodeGen/CodeGenABITypes.cpp
index 180cd51940ac..12189ae1aea9 100644
--- a/lib/CodeGen/CodeGenABITypes.cpp
+++ b/lib/CodeGen/CodeGenABITypes.cpp
@@ -26,9 +26,11 @@ using namespace CodeGen;
CodeGenABITypes::CodeGenABITypes(ASTContext &C,
llvm::Module &M,
- const llvm::DataLayout &TD)
+ const llvm::DataLayout &TD,
+ CoverageSourceInfo *CoverageInfo)
: CGO(new CodeGenOptions),
- CGM(new CodeGen::CodeGenModule(C, *CGO, M, TD, C.getDiagnostics())) {
+ CGM(new CodeGen::CodeGenModule(C, *CGO, M, TD, C.getDiagnostics(),
+ CoverageInfo)) {
}
CodeGenABITypes::~CodeGenABITypes()
@@ -65,5 +67,6 @@ CodeGenABITypes::arrangeFreeFunctionCall(CanQualType returnType,
FunctionType::ExtInfo info,
RequiredArgs args) {
return CGM->getTypes().arrangeLLVMFunctionInfo(
- returnType, /*IsInstanceMethod=*/false, argTypes, info, args);
+ returnType, /*IsInstanceMethod=*/false, /*IsChainCall=*/false, argTypes,
+ info, args);
}
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 04d2cd9d53e4..a6f6fdef335c 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -7,18 +7,20 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/CodeGen/CodeGenAction.h"
+#include "CoverageMappingGen.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclGroup.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/BackendUtil.h"
+#include "clang/CodeGen/CodeGenAction.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/DebugInfo.h"
@@ -59,16 +61,18 @@ namespace clang {
const TargetOptions &targetopts,
const LangOptions &langopts, bool TimePasses,
const std::string &infile, llvm::Module *LinkModule,
- raw_ostream *OS, LLVMContext &C)
+ raw_ostream *OS, LLVMContext &C,
+ CoverageSourceInfo *CoverageInfo = nullptr)
: Diags(_Diags), Action(action), CodeGenOpts(compopts),
TargetOpts(targetopts), LangOpts(langopts), AsmOutStream(OS),
- Context(), LLVMIRGeneration("LLVM IR Generation Time"),
- Gen(CreateLLVMCodeGen(Diags, infile, compopts, targetopts, C)),
+ Context(nullptr), LLVMIRGeneration("LLVM IR Generation Time"),
+ Gen(CreateLLVMCodeGen(Diags, infile, compopts,
+ targetopts, C, CoverageInfo)),
LinkModule(LinkModule) {
llvm::TimePassesIsEnabled = TimePasses;
}
- llvm::Module *takeModule() { return TheModule.release(); }
+ std::unique_ptr<llvm::Module> takeModule() { return std::move(TheModule); }
llvm::Module *takeLinkModule() { return LinkModule.release(); }
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
@@ -149,13 +153,10 @@ namespace clang {
// Link LinkModule into this module if present, preserving its validity.
if (LinkModule) {
- std::string ErrorMsg;
- if (Linker::LinkModules(M, LinkModule.get(), Linker::PreserveSource,
- &ErrorMsg)) {
- Diags.Report(diag::err_fe_cannot_link_module)
- << LinkModule->getModuleIdentifier() << ErrorMsg;
+ if (Linker::LinkModules(
+ M, LinkModule.get(),
+ [=](const DiagnosticInfo &DI) { linkerDiagnosticHandler(DI); }))
return;
- }
}
// Install an inline asm handler so that diagnostics get printed through
@@ -218,6 +219,8 @@ namespace clang {
((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc);
}
+ void linkerDiagnosticHandler(const llvm::DiagnosticInfo &DI);
+
static void DiagnosticHandler(const llvm::DiagnosticInfo &DI,
void *Context) {
((BackendConsumer *)Context)->DiagnosticHandlerImpl(DI);
@@ -269,11 +272,11 @@ static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D,
// Create the copy and transfer ownership to clang::SourceManager.
// TODO: Avoid copying files into memory.
- llvm::MemoryBuffer *CBuf =
- llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(),
- LBuf->getBufferIdentifier());
+ std::unique_ptr<llvm::MemoryBuffer> CBuf =
+ llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(),
+ LBuf->getBufferIdentifier());
// FIXME: Keep a file ID map instead of creating new IDs for each location.
- FileID FID = CSM.createFileID(CBuf);
+ FileID FID = CSM.createFileID(std::move(CBuf));
// Translate the offset into the file.
unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
@@ -493,6 +496,21 @@ void BackendConsumer::OptimizationFailureHandler(
EmitOptimizationMessage(D, diag::warn_fe_backend_optimization_failure);
}
+void BackendConsumer::linkerDiagnosticHandler(const DiagnosticInfo &DI) {
+ if (DI.getSeverity() != DS_Error)
+ return;
+
+ std::string MsgStorage;
+ {
+ raw_string_ostream Stream(MsgStorage);
+ DiagnosticPrinterRawOStream DP(Stream);
+ DI.print(DP);
+ }
+
+ Diags.Report(diag::err_fe_cannot_link_module)
+ << LinkModule->getModuleIdentifier() << MsgStorage;
+}
+
/// \brief This function is invoked when the backend needs
/// to report something to the user.
void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
@@ -572,10 +590,12 @@ void CodeGenAction::EndSourceFileAction() {
BEConsumer->takeLinkModule();
// Steal the module from the consumer.
- TheModule.reset(BEConsumer->takeModule());
+ TheModule = BEConsumer->takeModule();
}
-llvm::Module *CodeGenAction::takeModule() { return TheModule.release(); }
+std::unique_ptr<llvm::Module> CodeGenAction::takeModule() {
+ return std::move(TheModule);
+}
llvm::LLVMContext *CodeGenAction::takeLLVMContext() {
OwnsVMContext = false;
@@ -603,8 +623,8 @@ static raw_ostream *GetOutputStream(CompilerInstance &CI,
llvm_unreachable("Invalid action!");
}
-ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
BackendAction BA = static_cast<BackendAction>(Act);
std::unique_ptr<raw_ostream> OS(GetOutputStream(CI, InFile, BA));
if (BA != Backend_EmitNothing && !OS)
@@ -616,18 +636,15 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
// loaded from bitcode, do so now.
const std::string &LinkBCFile = CI.getCodeGenOpts().LinkBitcodeFile;
if (!LinkModuleToUse && !LinkBCFile.empty()) {
- std::string ErrorStr;
-
- llvm::MemoryBuffer *BCBuf =
- CI.getFileManager().getBufferForFile(LinkBCFile, &ErrorStr);
+ auto BCBuf = CI.getFileManager().getBufferForFile(LinkBCFile);
if (!BCBuf) {
CI.getDiagnostics().Report(diag::err_cannot_open_file)
- << LinkBCFile << ErrorStr;
+ << LinkBCFile << BCBuf.getError().message();
return nullptr;
}
ErrorOr<llvm::Module *> ModuleOrErr =
- getLazyBitcodeModule(BCBuf, *VMContext);
+ getLazyBitcodeModule(std::move(*BCBuf), *VMContext);
if (std::error_code EC = ModuleOrErr.getError()) {
CI.getDiagnostics().Report(diag::err_cannot_open_file)
<< LinkBCFile << EC.message();
@@ -636,11 +653,19 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
LinkModuleToUse = ModuleOrErr.get();
}
- BEConsumer = new BackendConsumer(BA, CI.getDiagnostics(), CI.getCodeGenOpts(),
- CI.getTargetOpts(), CI.getLangOpts(),
- CI.getFrontendOpts().ShowTimers, InFile,
- LinkModuleToUse, OS.release(), *VMContext);
- return BEConsumer;
+ CoverageSourceInfo *CoverageInfo = nullptr;
+ // Add the preprocessor callback only when the coverage mapping is generated.
+ if (CI.getCodeGenOpts().CoverageMapping) {
+ CoverageInfo = new CoverageSourceInfo;
+ CI.getPreprocessor().addPPCallbacks(
+ std::unique_ptr<PPCallbacks>(CoverageInfo));
+ }
+ std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
+ BA, CI.getDiagnostics(), CI.getCodeGenOpts(), CI.getTargetOpts(),
+ CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, InFile,
+ LinkModuleToUse, OS.release(), *VMContext, CoverageInfo));
+ BEConsumer = Result.get();
+ return std::move(Result);
}
void CodeGenAction::ExecuteAction() {
@@ -660,7 +685,7 @@ void CodeGenAction::ExecuteAction() {
return;
llvm::SMDiagnostic Err;
- TheModule.reset(ParseIR(MainFile, Err, *VMContext));
+ TheModule = parseIR(MainFile->getMemBufferRef(), Err, *VMContext);
if (!TheModule) {
// Translate from the diagnostic info to the SourceManager location if
// available.
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 5ca3a78bb4fa..826171a46e23 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -37,17 +37,18 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
: CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()),
Builder(cgm.getModule().getContext(), llvm::ConstantFolder(),
CGBuilderInserterTy(this)),
- CapturedStmtInfo(nullptr), SanOpts(&CGM.getLangOpts().Sanitize),
- IsSanitizerScope(false), AutoreleaseResult(false), BlockInfo(nullptr),
- BlockPointer(nullptr), LambdaThisCaptureField(nullptr),
- NormalCleanupDest(nullptr), NextCleanupDestIndex(1),
- FirstBlockInfo(nullptr), EHResumeBlock(nullptr), ExceptionSlot(nullptr),
- EHSelectorSlot(nullptr), DebugInfo(CGM.getModuleDebugInfo()),
- DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(nullptr),
- PGO(cgm), SwitchInsn(nullptr), SwitchWeights(nullptr),
- CaseRangeBlock(nullptr), UnreachableBlock(nullptr), NumReturnExprs(0),
- NumSimpleReturnExprs(0), CXXABIThisDecl(nullptr),
- CXXABIThisValue(nullptr), CXXThisValue(nullptr),
+ CurFn(nullptr), CapturedStmtInfo(nullptr),
+ SanOpts(CGM.getLangOpts().Sanitize), IsSanitizerScope(false),
+ CurFuncIsThunk(false), AutoreleaseResult(false), SawAsmBlock(false),
+ BlockInfo(nullptr), BlockPointer(nullptr),
+ LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),
+ NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr),
+ ExceptionSlot(nullptr), EHSelectorSlot(nullptr),
+ DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false),
+ DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm),
+ SwitchInsn(nullptr), SwitchWeights(nullptr), CaseRangeBlock(nullptr),
+ UnreachableBlock(nullptr), NumReturnExprs(0), NumSimpleReturnExprs(0),
+ CXXABIThisDecl(nullptr), CXXABIThisValue(nullptr), CXXThisValue(nullptr),
CXXDefaultInitExprThis(nullptr), CXXStructorImplicitParamDecl(nullptr),
CXXStructorImplicitParamValue(nullptr), OutermostConditional(nullptr),
CurLexicalScope(nullptr), TerminateLandingPad(nullptr),
@@ -62,6 +63,12 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
FMF.setNoNaNs();
FMF.setNoInfs();
}
+ if (CGM.getCodeGenOpts().NoNaNsFPMath) {
+ FMF.setNoNaNs();
+ }
+ if (CGM.getCodeGenOpts().NoSignedZeros) {
+ FMF.setNoSignedZeros();
+ }
Builder.SetFastMathFlags(FMF);
}
@@ -79,6 +86,17 @@ CodeGenFunction::~CodeGenFunction() {
}
}
+LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) {
+ CharUnits Alignment;
+ if (CGM.getCXXABI().isTypeInfoCalculable(T)) {
+ Alignment = getContext().getTypeAlignInChars(T);
+ unsigned MaxAlign = getContext().getLangOpts().MaxTypeAlign;
+ if (MaxAlign && Alignment.getQuantity() > MaxAlign &&
+ !getContext().isAlignmentRequired(T))
+ Alignment = CharUnits::fromQuantity(MaxAlign);
+ }
+ return LValue::MakeAddr(V, T, Alignment, getContext(), CGM.getTBAAInfo(T));
+}
llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) {
return CGM.getTypes().ConvertTypeForMem(T);
@@ -140,7 +158,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
}
}
-void CodeGenFunction::EmitReturnBlock() {
+llvm::DebugLoc CodeGenFunction::EmitReturnBlock() {
// For cleanliness, we try to avoid emitting the return block for
// simple cases.
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
@@ -155,7 +173,7 @@ void CodeGenFunction::EmitReturnBlock() {
delete ReturnBlock.getBlock();
} else
EmitBlock(ReturnBlock.getBlock());
- return;
+ return llvm::DebugLoc();
}
// Otherwise, if the return block is the target of a single direct
@@ -166,15 +184,13 @@ void CodeGenFunction::EmitReturnBlock() {
dyn_cast<llvm::BranchInst>(*ReturnBlock.getBlock()->user_begin());
if (BI && BI->isUnconditional() &&
BI->getSuccessor(0) == ReturnBlock.getBlock()) {
- // Reset insertion point, including debug location, and delete the
- // branch. This is really subtle and only works because the next change
- // in location will hit the caching in CGDebugInfo::EmitLocation and not
- // override this.
- Builder.SetCurrentDebugLocation(BI->getDebugLoc());
+ // Record/return the DebugLoc of the simple 'return' expression to be used
+ // later by the actual 'ret' instruction.
+ llvm::DebugLoc Loc = BI->getDebugLoc();
Builder.SetInsertPoint(BI->getParent());
BI->eraseFromParent();
delete ReturnBlock.getBlock();
- return;
+ return Loc;
}
}
@@ -183,6 +199,7 @@ void CodeGenFunction::EmitReturnBlock() {
// region.end for now.
EmitBlock(ReturnBlock.getBlock());
+ return llvm::DebugLoc();
}
static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) {
@@ -236,16 +253,18 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
}
// Emit function epilog (to return).
- EmitReturnBlock();
+ llvm::DebugLoc Loc = EmitReturnBlock();
if (ShouldInstrumentFunction())
EmitFunctionInstrumentation("__cyg_profile_func_exit");
// Emit debug descriptor for function end.
- if (CGDebugInfo *DI = getDebugInfo()) {
+ if (CGDebugInfo *DI = getDebugInfo())
DI->EmitFunctionEnd(Builder);
- }
+ // Reset the debug location to that of the simple 'return' expression, if any
+ // rather than that of the end of the function's scope '}'.
+ ApplyDebugLocation AL(*this, Loc);
EmitFunctionEpilog(*CurFnInfo, EmitRetDbgLoc, EndLoc);
EmitEndEHSpec(CurCodeDecl);
@@ -337,9 +356,9 @@ void CodeGenFunction::EmitMCountInstrumentation() {
// information in the program executable. The argument information stored
// includes the argument name, its type, the address and access qualifiers used.
static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
- CodeGenModule &CGM,llvm::LLVMContext &Context,
- SmallVector <llvm::Value*, 5> &kernelMDArgs,
- CGBuilderTy& Builder, ASTContext &ASTCtx) {
+ CodeGenModule &CGM, llvm::LLVMContext &Context,
+ SmallVector<llvm::Metadata *, 5> &kernelMDArgs,
+ CGBuilderTy &Builder, ASTContext &ASTCtx) {
// Create MDNodes that represent the kernel arg metadata.
// Each MDNode is a list in the form of "key", N number of values which is
// the same number of values as their are kernel arguments.
@@ -347,23 +366,28 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
const PrintingPolicy &Policy = ASTCtx.getPrintingPolicy();
// MDNode for the kernel argument address space qualifiers.
- SmallVector<llvm::Value*, 8> addressQuals;
+ SmallVector<llvm::Metadata *, 8> addressQuals;
addressQuals.push_back(llvm::MDString::get(Context, "kernel_arg_addr_space"));
// MDNode for the kernel argument access qualifiers (images only).
- SmallVector<llvm::Value*, 8> accessQuals;
+ SmallVector<llvm::Metadata *, 8> accessQuals;
accessQuals.push_back(llvm::MDString::get(Context, "kernel_arg_access_qual"));
// MDNode for the kernel argument type names.
- SmallVector<llvm::Value*, 8> argTypeNames;
+ SmallVector<llvm::Metadata *, 8> argTypeNames;
argTypeNames.push_back(llvm::MDString::get(Context, "kernel_arg_type"));
+ // MDNode for the kernel argument base type names.
+ SmallVector<llvm::Metadata *, 8> argBaseTypeNames;
+ argBaseTypeNames.push_back(
+ llvm::MDString::get(Context, "kernel_arg_base_type"));
+
// MDNode for the kernel argument type qualifiers.
- SmallVector<llvm::Value*, 8> argTypeQuals;
+ SmallVector<llvm::Metadata *, 8> argTypeQuals;
argTypeQuals.push_back(llvm::MDString::get(Context, "kernel_arg_type_qual"));
// MDNode for the kernel argument names.
- SmallVector<llvm::Value*, 8> argNames;
+ SmallVector<llvm::Metadata *, 8> argNames;
argNames.push_back(llvm::MDString::get(Context, "kernel_arg_name"));
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
@@ -375,8 +399,8 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
QualType pointeeTy = ty->getPointeeType();
// Get address qualifier.
- addressQuals.push_back(Builder.getInt32(ASTCtx.getTargetAddressSpace(
- pointeeTy.getAddressSpace())));
+ addressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(
+ ASTCtx.getTargetAddressSpace(pointeeTy.getAddressSpace()))));
// Get argument type name.
std::string typeName =
@@ -384,11 +408,23 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
// Turn "unsigned type" to "utype"
std::string::size_type pos = typeName.find("unsigned");
- if (pos != std::string::npos)
+ if (pointeeTy.isCanonical() && pos != std::string::npos)
typeName.erase(pos+1, 8);
argTypeNames.push_back(llvm::MDString::get(Context, typeName));
+ std::string baseTypeName =
+ pointeeTy.getUnqualifiedType().getCanonicalType().getAsString(
+ Policy) +
+ "*";
+
+ // Turn "unsigned type" to "utype"
+ pos = baseTypeName.find("unsigned");
+ if (pos != std::string::npos)
+ baseTypeName.erase(pos+1, 8);
+
+ argBaseTypeNames.push_back(llvm::MDString::get(Context, baseTypeName));
+
// Get argument type qualifiers:
if (ty.isRestrictQualified())
typeQuals = "restrict";
@@ -403,18 +439,29 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
AddrSpc =
CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
- addressQuals.push_back(Builder.getInt32(AddrSpc));
+ addressQuals.push_back(
+ llvm::ConstantAsMetadata::get(Builder.getInt32(AddrSpc)));
// Get argument type name.
std::string typeName = ty.getUnqualifiedType().getAsString(Policy);
// Turn "unsigned type" to "utype"
std::string::size_type pos = typeName.find("unsigned");
- if (pos != std::string::npos)
+ if (ty.isCanonical() && pos != std::string::npos)
typeName.erase(pos+1, 8);
argTypeNames.push_back(llvm::MDString::get(Context, typeName));
+ std::string baseTypeName =
+ ty.getUnqualifiedType().getCanonicalType().getAsString(Policy);
+
+ // Turn "unsigned type" to "utype"
+ pos = baseTypeName.find("unsigned");
+ if (pos != std::string::npos)
+ baseTypeName.erase(pos+1, 8);
+
+ argBaseTypeNames.push_back(llvm::MDString::get(Context, baseTypeName));
+
// Get argument type qualifiers:
if (ty.isConstQualified())
typeQuals = "const";
@@ -442,8 +489,10 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
kernelMDArgs.push_back(llvm::MDNode::get(Context, addressQuals));
kernelMDArgs.push_back(llvm::MDNode::get(Context, accessQuals));
kernelMDArgs.push_back(llvm::MDNode::get(Context, argTypeNames));
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, argBaseTypeNames));
kernelMDArgs.push_back(llvm::MDNode::get(Context, argTypeQuals));
- kernelMDArgs.push_back(llvm::MDNode::get(Context, argNames));
+ if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, argNames));
}
void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
@@ -454,12 +503,11 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
llvm::LLVMContext &Context = getLLVMContext();
- SmallVector <llvm::Value*, 5> kernelMDArgs;
- kernelMDArgs.push_back(Fn);
+ SmallVector<llvm::Metadata *, 5> kernelMDArgs;
+ kernelMDArgs.push_back(llvm::ConstantAsMetadata::get(Fn));
- if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
- GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs,
- Builder, getContext());
+ GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs, Builder,
+ getContext());
if (const VecTypeHintAttr *A = FD->getAttr<VecTypeHintAttr>()) {
QualType hintQTy = A->getTypeHint();
@@ -467,33 +515,31 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
bool isSignedInteger =
hintQTy->isSignedIntegerType() ||
(hintEltQTy && hintEltQTy->getElementType()->isSignedIntegerType());
- llvm::Value *attrMDArgs[] = {
- llvm::MDString::get(Context, "vec_type_hint"),
- llvm::UndefValue::get(CGM.getTypes().ConvertType(A->getTypeHint())),
- llvm::ConstantInt::get(
- llvm::IntegerType::get(Context, 32),
- llvm::APInt(32, (uint64_t)(isSignedInteger ? 1 : 0)))
- };
+ llvm::Metadata *attrMDArgs[] = {
+ llvm::MDString::get(Context, "vec_type_hint"),
+ llvm::ConstantAsMetadata::get(llvm::UndefValue::get(
+ CGM.getTypes().ConvertType(A->getTypeHint()))),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ llvm::IntegerType::get(Context, 32),
+ llvm::APInt(32, (uint64_t)(isSignedInteger ? 1 : 0))))};
kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
}
if (const WorkGroupSizeHintAttr *A = FD->getAttr<WorkGroupSizeHintAttr>()) {
- llvm::Value *attrMDArgs[] = {
- llvm::MDString::get(Context, "work_group_size_hint"),
- Builder.getInt32(A->getXDim()),
- Builder.getInt32(A->getYDim()),
- Builder.getInt32(A->getZDim())
- };
+ llvm::Metadata *attrMDArgs[] = {
+ llvm::MDString::get(Context, "work_group_size_hint"),
+ llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())),
+ llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())),
+ llvm::ConstantAsMetadata::get(Builder.getInt32(A->getZDim()))};
kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
}
if (const ReqdWorkGroupSizeAttr *A = FD->getAttr<ReqdWorkGroupSizeAttr>()) {
- llvm::Value *attrMDArgs[] = {
- llvm::MDString::get(Context, "reqd_work_group_size"),
- Builder.getInt32(A->getXDim()),
- Builder.getInt32(A->getYDim()),
- Builder.getInt32(A->getZDim())
- };
+ llvm::Metadata *attrMDArgs[] = {
+ llvm::MDString::get(Context, "reqd_work_group_size"),
+ llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())),
+ llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())),
+ llvm::ConstantAsMetadata::get(Builder.getInt32(A->getZDim()))};
kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
}
@@ -526,6 +572,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
const FunctionArgList &Args,
SourceLocation Loc,
SourceLocation StartLoc) {
+ assert(!CurFn &&
+ "Do not use a CodeGenFunction object for more than one function");
+
const Decl *D = GD.getDecl();
DidCallStackSave = false;
@@ -536,8 +585,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
CurFnInfo = &FnInfo;
assert(CurFn->isDeclaration() && "Function already has body?");
- if (CGM.getSanitizerBlacklist().isIn(*Fn))
- SanOpts = &SanitizerOptions::Disabled;
+ if (CGM.isInSanitizerBlacklist(Fn, Loc))
+ SanOpts.clear();
// Pass inline keyword to optimizer if it appears explicitly on any
// declaration. Also, in the case of -fno-inline attach NoInline
@@ -560,17 +609,17 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
}
// If we are checking function types, emit a function type signature as
- // prefix data.
- if (getLangOpts().CPlusPlus && SanOpts->Function) {
+ // prologue data.
+ if (getLangOpts().CPlusPlus && SanOpts.has(SanitizerKind::Function)) {
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- if (llvm::Constant *PrefixSig =
+ if (llvm::Constant *PrologueSig =
CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
llvm::Constant *FTRTTIConst =
CGM.GetAddrOfRTTIDescriptor(FD->getType(), /*ForEH=*/true);
- llvm::Constant *PrefixStructElems[] = { PrefixSig, FTRTTIConst };
- llvm::Constant *PrefixStructConst =
- llvm::ConstantStruct::getAnon(PrefixStructElems, /*Packed=*/true);
- Fn->setPrefixData(PrefixStructConst);
+ llvm::Constant *PrologueStructElems[] = { PrologueSig, FTRTTIConst };
+ llvm::Constant *PrologueStructConst =
+ llvm::ConstantStruct::getAnon(PrologueStructElems, /*Packed=*/true);
+ Fn->setPrologueData(PrologueStructConst);
}
}
}
@@ -663,6 +712,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
CXXThisValue = EmitLoadOfLValue(ThisLValue,
SourceLocation()).getScalarVal();
}
+ for (auto *FD : MD->getParent()->fields()) {
+ if (FD->hasCapturedVLAType()) {
+ auto *ExprArg = EmitLoadOfLValue(EmitLValueForLambdaField(FD),
+ SourceLocation()).getScalarVal();
+ auto VAT = FD->getCapturedVLAType();
+ VLASizeMap[VAT->getSizeExpr()] = ExprArg;
+ }
+ }
} else {
// Not in a lambda; just use 'this' from the method.
// FIXME: Should we generate a new load for each use of 'this'? The
@@ -771,11 +828,12 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
if (MD && MD->isInstance()) {
if (CGM.getCXXABI().HasThisReturn(GD))
ResTy = MD->getThisType(getContext());
+ else if (CGM.getCXXABI().hasMostDerivedReturn(GD))
+ ResTy = CGM.getContext().VoidPtrTy;
CGM.getCXXABI().buildThisParam(*this, Args);
}
-
- for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
- Args.push_back(FD->getParamDecl(i));
+
+ Args.append(FD->param_begin(), FD->param_end());
if (MD && (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)))
CGM.getCXXABI().addImplicitStructorParams(*this, ResTy, Args);
@@ -801,6 +859,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin());
// Generate the body of the function.
+ PGO.checkGlobalDecl(GD);
PGO.assignRegionCounters(GD.getDecl(), CurFn);
if (isa<CXXDestructorDecl>(FD))
EmitDestructorBody(Args);
@@ -842,13 +901,14 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// C11 6.9.1p12:
// If the '}' that terminates a function is reached, and the value of the
// function call is used by the caller, the behavior is undefined.
- if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() &&
+ if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() && !SawAsmBlock &&
!FD->getReturnType()->isVoidType() && Builder.GetInsertBlock()) {
- if (SanOpts->Return) {
+ if (SanOpts.has(SanitizerKind::Return)) {
SanitizerScope SanScope(this);
- EmitCheck(Builder.getFalse(), "missing_return",
- EmitCheckSourceLocation(FD->getLocation()),
- ArrayRef<llvm::Value *>(), CRK_Unrecoverable);
+ llvm::Value *IsFalse = Builder.getFalse();
+ EmitCheck(std::make_pair(IsFalse, SanitizerKind::Return),
+ "missing_return", EmitCheckSourceLocation(FD->getLocation()),
+ None);
} else if (CGM.getCodeGenOpts().OptimizationLevel == 0)
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap));
Builder.CreateUnreachable();
@@ -862,9 +922,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// a quick pass now to see if we can.
if (!CurFn->doesNotThrow())
TryMarkNoThrow(CurFn);
-
- PGO.emitInstrumentationData();
- PGO.destroyRegionCounters();
}
/// ContainsLabel - Return true if the statement contains a label in it. If
@@ -1499,7 +1556,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
// If the size is an expression that is not an integer constant
// expression [...] each time it is evaluated it shall have a value
// greater than zero.
- if (SanOpts->VLABound &&
+ if (SanOpts.has(SanitizerKind::VLABound) &&
size->getType()->isSignedIntegerType()) {
SanitizerScope SanScope(this);
llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType());
@@ -1507,9 +1564,9 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
EmitCheckSourceLocation(size->getLocStart()),
EmitCheckTypeDescriptor(size->getType())
};
- EmitCheck(Builder.CreateICmpSGT(Size, Zero),
- "vla_bound_not_positive", StaticArgs, Size,
- CRK_Recoverable);
+ EmitCheck(std::make_pair(Builder.CreateICmpSGT(Size, Zero),
+ SanitizerKind::VLABound),
+ "vla_bound_not_positive", StaticArgs, Size);
}
// Always zexting here would be wrong if it weren't
@@ -1655,11 +1712,8 @@ void CodeGenFunction::InsertHelper(llvm::Instruction *I,
llvm::BasicBlock *BB,
llvm::BasicBlock::iterator InsertPt) const {
LoopStack.InsertHelper(I);
- if (IsSanitizerScope) {
- I->setMetadata(
- CGM.getModule().getMDKindID("nosanitize"),
- llvm::MDNode::get(CGM.getLLVMContext(), ArrayRef<llvm::Value *>()));
- }
+ if (IsSanitizerScope)
+ CGM.getSanitizerMetadata()->disableSanitizerForInstruction(I);
}
template <bool PreserveNames>
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 59cc30da42c5..3a990d21490d 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CODEGENFUNCTION_H
-#define CLANG_CODEGEN_CODEGENFUNCTION_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENFUNCTION_H
+#define LLVM_CLANG_LIB_CODEGEN_CODEGENFUNCTION_H
#include "CGBuilder.h"
#include "CGDebugInfo.h"
@@ -93,19 +93,6 @@ enum TypeEvaluationKind {
TEK_Aggregate
};
-class SuppressDebugLocation {
- llvm::DebugLoc CurLoc;
- llvm::IRBuilderBase &Builder;
-public:
- SuppressDebugLocation(llvm::IRBuilderBase &Builder)
- : CurLoc(Builder.getCurrentDebugLocation()), Builder(Builder) {
- Builder.SetCurrentDebugLocation(llvm::DebugLoc());
- }
- ~SuppressDebugLocation() {
- Builder.SetCurrentDebugLocation(CurLoc);
- }
-};
-
/// CodeGenFunction - This class organizes the per-function state that is used
/// while generating LLVM code.
class CodeGenFunction : public CodeGenTypeCache {
@@ -182,6 +169,8 @@ public:
/// \brief API for captured statement code generation.
class CGCapturedStmtInfo {
public:
+ explicit CGCapturedStmtInfo(CapturedRegionKind K = CR_Default)
+ : Kind(K), ThisValue(nullptr), CXXThisFieldDecl(nullptr) {}
explicit CGCapturedStmtInfo(const CapturedStmt &S,
CapturedRegionKind K = CR_Default)
: Kind(K), ThisValue(nullptr), CXXThisFieldDecl(nullptr) {
@@ -193,7 +182,7 @@ public:
I != E; ++I, ++Field) {
if (I->capturesThis())
CXXThisFieldDecl = *Field;
- else
+ else if (I->capturesVariable())
CaptureFields[I->getCapturedVar()] = *Field;
}
}
@@ -214,6 +203,10 @@ public:
bool isCXXThisExprCaptured() const { return CXXThisFieldDecl != nullptr; }
FieldDecl *getThisFieldDecl() const { return CXXThisFieldDecl; }
+ static bool classof(const CGCapturedStmtInfo *) {
+ return true;
+ }
+
/// \brief Emit the captured statement body.
virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) {
RegionCounter Cnt = CGF.getPGORegionCounter(S);
@@ -244,8 +237,8 @@ public:
/// potentially higher performance penalties.
unsigned char BoundsChecking;
- /// \brief Sanitizer options to use for this function.
- const SanitizerOptions *SanOpts;
+ /// \brief Sanitizers enabled for this function.
+ SanitizerSet SanOpts;
/// \brief True if CodeGen currently emits code implementing sanitizer checks.
bool IsSanitizerScope;
@@ -258,9 +251,17 @@ public:
~SanitizerScope();
};
+ /// In C++, whether we are code generating a thunk. This controls whether we
+ /// should emit cleanups.
+ bool CurFuncIsThunk;
+
/// In ARC, whether we should autorelease the return value.
bool AutoreleaseResult;
+ /// Whether we processed a Microsoft-style asm block during CodeGen. These can
+ /// potentially set the return value.
+ bool SawAsmBlock;
+
const CodeGen::CGBlockInfo *BlockInfo;
llvm::Value *BlockPointer;
@@ -277,11 +278,11 @@ public:
/// Header for data within LifetimeExtendedCleanupStack.
struct LifetimeExtendedCleanupHeader {
/// The size of the following cleanup object.
- size_t Size : 29;
+ unsigned Size : 29;
/// The kind of cleanup to push: a value from the CleanupKind enumeration.
unsigned Kind : 3;
- size_t getSize() const { return Size; }
+ size_t getSize() const { return size_t(Size); }
CleanupKind getKind() const { return static_cast<CleanupKind>(Kind); }
};
@@ -531,7 +532,7 @@ public:
}
};
- class LexicalScope: protected RunCleanupsScope {
+ class LexicalScope : public RunCleanupsScope {
SourceRange Range;
SmallVector<const LabelDecl*, 4> Labels;
LexicalScope *ParentScope;
@@ -577,6 +578,67 @@ public:
void rescopeLabels();
};
+ /// \brief The scope used to remap some variables as private in the OpenMP
+ /// loop body (or other captured region emitted without outlining), and to
+ /// restore old vars back on exit.
+ class OMPPrivateScope : public RunCleanupsScope {
+ typedef llvm::DenseMap<const VarDecl *, llvm::Value *> VarDeclMapTy;
+ VarDeclMapTy SavedLocals;
+ VarDeclMapTy SavedPrivates;
+
+ private:
+ OMPPrivateScope(const OMPPrivateScope &) LLVM_DELETED_FUNCTION;
+ void operator=(const OMPPrivateScope &) LLVM_DELETED_FUNCTION;
+
+ public:
+ /// \brief Enter a new OpenMP private scope.
+ explicit OMPPrivateScope(CodeGenFunction &CGF) : RunCleanupsScope(CGF) {}
+
+ /// \brief Registers \a LocalVD variable as a private and apply \a
+ /// PrivateGen function for it to generate corresponding private variable.
+ /// \a PrivateGen returns an address of the generated private variable.
+ /// \return true if the variable is registered as private, false if it has
+ /// been privatized already.
+ bool
+ addPrivate(const VarDecl *LocalVD,
+ const std::function<llvm::Value *()> &PrivateGen) {
+ assert(PerformCleanup && "adding private to dead scope");
+ if (SavedLocals.count(LocalVD) > 0) return false;
+ SavedLocals[LocalVD] = CGF.LocalDeclMap.lookup(LocalVD);
+ CGF.LocalDeclMap.erase(LocalVD);
+ SavedPrivates[LocalVD] = PrivateGen();
+ CGF.LocalDeclMap[LocalVD] = SavedLocals[LocalVD];
+ return true;
+ }
+
+ /// \brief Privatizes local variables previously registered as private.
+ /// Registration is separate from the actual privatization to allow
+ /// initializers use values of the original variables, not the private one.
+ /// This is important, for example, if the private variable is a class
+ /// variable initialized by a constructor that references other private
+ /// variables. But at initialization original variables must be used, not
+ /// private copies.
+ /// \return true if at least one variable was privatized, false otherwise.
+ bool Privatize() {
+ for (auto VDPair : SavedPrivates) {
+ CGF.LocalDeclMap[VDPair.first] = VDPair.second;
+ }
+ SavedPrivates.clear();
+ return !SavedLocals.empty();
+ }
+
+ void ForceCleanup() {
+ RunCleanupsScope::ForceCleanup();
+ // Remap vars back to the original values.
+ for (auto I : SavedLocals) {
+ CGF.LocalDeclMap[I.first] = I.second;
+ }
+ SavedLocals.clear();
+ }
+
+ /// \brief Exit scope - all the mapped variables are restored.
+ ~OMPPrivateScope() { ForceCleanup(); }
+ };
/// \brief Takes the old cleanup stack size and emits the cleanup blocks
/// that have been added.
@@ -1062,6 +1124,9 @@ public:
void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr,
QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
+ void pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete,
+ llvm::Value *CompletePtr,
+ QualType ElementType);
void pushStackRestore(CleanupKind kind, llvm::Value *SPMem);
void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
@@ -1101,9 +1166,7 @@ public:
void GenerateObjCMethod(const ObjCMethodDecl *OMD);
- void StartObjCMethod(const ObjCMethodDecl *MD,
- const ObjCContainerDecl *CD,
- SourceLocation StartLoc);
+ void StartObjCMethod(const ObjCMethodDecl *MD, const ObjCContainerDecl *CD);
/// GenerateObjCGetter - Synthesize an Objective-C property getter function.
void GenerateObjCGetter(ObjCImplementationDecl *IMP,
@@ -1193,10 +1256,11 @@ public:
void EmitLambdaBlockInvokeBody();
void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD);
void EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD);
+ void EmitAsanPrologueOrEpilogue(bool Prologue);
/// EmitReturnBlock - Emit the unified return block, trying to avoid its
/// emission when possible.
- void EmitReturnBlock();
+ llvm::DebugLoc EmitReturnBlock();
/// FinishFunction - Complete IR generation of the current function. It is
/// legal to call this function even if there is no current insertion point.
@@ -1204,8 +1268,11 @@ public:
void StartThunk(llvm::Function *Fn, GlobalDecl GD, const CGFunctionInfo &FnInfo);
- void EmitCallAndReturnForThunk(GlobalDecl GD, llvm::Value *Callee,
- const ThunkInfo *Thunk);
+ void EmitCallAndReturnForThunk(llvm::Value *Callee, const ThunkInfo *Thunk);
+
+ /// Emit a musttail call for a thunk with a potentially adjusted this pointer.
+ void EmitMustTailThunk(const CXXMethodDecl *MD, llvm::Value *AdjustedThisPtr,
+ llvm::Value *Callee);
/// GenerateThunk - Generate a thunk for the given method.
void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
@@ -1390,13 +1457,7 @@ public:
CGM.getTBAAInfo(T));
}
- LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) {
- CharUnits Alignment;
- if (!T->isIncompleteType())
- Alignment = getContext().getTypeAlignInChars(T);
- return LValue::MakeAddr(V, T, Alignment, getContext(),
- CGM.getTBAAInfo(T));
- }
+ LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T);
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
/// block. The caller is responsible for setting an appropriate alignment on
@@ -1468,8 +1529,8 @@ public:
/// EmitExprAsInit - Emits the code necessary to initialize a
/// location in memory with the given initializer.
- void EmitExprAsInit(const Expr *init, const ValueDecl *D,
- LValue lvalue, bool capturedByInit);
+ void EmitExprAsInit(const Expr *init, const ValueDecl *D, LValue lvalue,
+ bool capturedByInit);
/// hasVolatileMember - returns true if aggregate type has a volatile
/// member.
@@ -1610,7 +1671,7 @@ public:
const CXXRecordDecl *Derived,
CastExpr::path_const_iterator PathBegin,
CastExpr::path_const_iterator PathEnd,
- bool NullCheckValue);
+ bool NullCheckValue, SourceLocation Loc);
llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value,
const CXXRecordDecl *Derived,
@@ -1637,27 +1698,22 @@ public:
const FunctionArgList &Args);
void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
bool ForVirtualBase, bool Delegating,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd);
-
+ llvm::Value *This, const CXXConstructExpr *E);
+
void EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
llvm::Value *This, llvm::Value *Src,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd);
+ const CXXConstructExpr *E);
void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
const ConstantArrayType *ArrayTy,
llvm::Value *ArrayPtr,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd,
+ const CXXConstructExpr *E,
bool ZeroInitialization = false);
void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
llvm::Value *NumElements,
llvm::Value *ArrayPtr,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd,
+ const CXXConstructExpr *E,
bool ZeroInitialization = false);
static Destroyer destroyCXXObject;
@@ -1710,7 +1766,13 @@ public:
TCK_DowncastPointer,
/// Checking the operand of a static_cast to a derived reference type. Must
/// be an object within its lifetime.
- TCK_DowncastReference
+ TCK_DowncastReference,
+ /// Checking the operand of a cast to a base object. Must be suitably sized
+ /// and aligned.
+ TCK_Upcast,
+ /// Checking the operand of a cast to a virtual base object. Must be an
+ /// object within its lifetime.
+ TCK_UpcastToVirtualBase
};
/// \brief Whether any type-checking sanitizers are enabled. If \c false,
@@ -1720,7 +1782,8 @@ public:
/// \brief Emit a check that \p V is the address of storage of the
/// appropriate size and alignment for an object of type \p Type.
void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V,
- QualType Type, CharUnits Alignment = CharUnits::Zero());
+ QualType Type, CharUnits Alignment = CharUnits::Zero(),
+ bool SkipNullCheck = false);
/// \brief Emit a check that \p Base points into an array object, which
/// we can access at index \p Index. \p Accessed should be \c false if we
@@ -1732,6 +1795,13 @@ public:
bool isInc, bool isPre);
ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
+
+ void EmitAlignmentAssumption(llvm::Value *PtrValue, unsigned Alignment,
+ llvm::Value *OffsetValue = nullptr) {
+ Builder.CreateAlignmentAssumption(CGM.getDataLayout(), PtrValue, Alignment,
+ OffsetValue);
+ }
+
//===--------------------------------------------------------------------===//
// Declaration Emission
//===--------------------------------------------------------------------===//
@@ -1746,13 +1816,17 @@ public:
/// This function can be called with a null (unreachable) insert point.
void EmitVarDecl(const VarDecl &D);
- void EmitScalarInit(const Expr *init, const ValueDecl *D,
- LValue lvalue, bool capturedByInit);
+ void EmitScalarInit(const Expr *init, const ValueDecl *D, LValue lvalue,
+ bool capturedByInit);
void EmitScalarInit(llvm::Value *init, LValue lvalue);
typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D,
llvm::Value *Address);
+ /// \brief Determine whether the given initializer is trivial in the sense
+ /// that it requires no code to be generated.
+ bool isTrivialInitializer(const Expr *Init);
+
/// EmitAutoVarDecl - Emit an auto variable declaration.
///
/// This function can be called with a null (unreachable) insert point.
@@ -1886,12 +1960,12 @@ public:
void EmitIfStmt(const IfStmt &S);
void EmitCondBrHints(llvm::LLVMContext &Context, llvm::BranchInst *CondBr,
- const ArrayRef<const Attr *> &Attrs);
+ ArrayRef<const Attr *> Attrs);
void EmitWhileStmt(const WhileStmt &S,
- const ArrayRef<const Attr *> &Attrs = None);
- void EmitDoStmt(const DoStmt &S, const ArrayRef<const Attr *> &Attrs = None);
+ ArrayRef<const Attr *> Attrs = None);
+ void EmitDoStmt(const DoStmt &S, ArrayRef<const Attr *> Attrs = None);
void EmitForStmt(const ForStmt &S,
- const ArrayRef<const Attr *> &Attrs = None);
+ ArrayRef<const Attr *> Attrs = None);
void EmitReturnStmt(const ReturnStmt &S);
void EmitDeclStmt(const DeclStmt &S);
void EmitBreakStmt(const BreakStmt &S);
@@ -1915,27 +1989,55 @@ public:
void EmitSEHTryStmt(const SEHTryStmt &S);
void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
- const ArrayRef<const Attr *> &Attrs = None);
+ ArrayRef<const Attr *> Attrs = None);
+ LValue InitCapturedStruct(const CapturedStmt &S);
llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
+ void GenerateCapturedStmtFunctionProlog(const CapturedStmt &S);
+ llvm::Function *GenerateCapturedStmtFunctionEpilog(const CapturedStmt &S);
llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S);
+ void EmitOMPAggregateAssign(LValue OriginalAddr, llvm::Value *PrivateAddr,
+ const Expr *AssignExpr, QualType Type,
+ const VarDecl *VDInit);
+ void EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
+ OMPPrivateScope &PrivateScope);
+ void EmitOMPPrivateClause(const OMPExecutableDirective &D,
+ OMPPrivateScope &PrivateScope);
void EmitOMPParallelDirective(const OMPParallelDirective &S);
void EmitOMPSimdDirective(const OMPSimdDirective &S);
void EmitOMPForDirective(const OMPForDirective &S);
+ void EmitOMPForSimdDirective(const OMPForSimdDirective &S);
void EmitOMPSectionsDirective(const OMPSectionsDirective &S);
void EmitOMPSectionDirective(const OMPSectionDirective &S);
void EmitOMPSingleDirective(const OMPSingleDirective &S);
void EmitOMPMasterDirective(const OMPMasterDirective &S);
void EmitOMPCriticalDirective(const OMPCriticalDirective &S);
void EmitOMPParallelForDirective(const OMPParallelForDirective &S);
+ void EmitOMPParallelForSimdDirective(const OMPParallelForSimdDirective &S);
void EmitOMPParallelSectionsDirective(const OMPParallelSectionsDirective &S);
void EmitOMPTaskDirective(const OMPTaskDirective &S);
void EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &S);
void EmitOMPBarrierDirective(const OMPBarrierDirective &S);
void EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S);
void EmitOMPFlushDirective(const OMPFlushDirective &S);
+ void EmitOMPOrderedDirective(const OMPOrderedDirective &S);
+ void EmitOMPAtomicDirective(const OMPAtomicDirective &S);
+ void EmitOMPTargetDirective(const OMPTargetDirective &S);
+ void EmitOMPTeamsDirective(const OMPTeamsDirective &S);
+
+private:
+
+ /// Helpers for the OpenMP loop directives.
+ void EmitOMPLoopBody(const OMPLoopDirective &Directive,
+ bool SeparateIter = false);
+ void EmitOMPInnerLoop(const OMPLoopDirective &S, OMPPrivateScope &LoopScope,
+ bool SeparateIter = false);
+ void EmitOMPSimdFinal(const OMPLoopDirective &S);
+ void EmitOMPWorksharingLoop(const OMPLoopDirective &S);
+
+public:
//===--------------------------------------------------------------------===//
// LValue Expression Emission
@@ -1988,6 +2090,12 @@ public:
void EmitAtomicStore(RValue rvalue, LValue lvalue, bool isInit);
+ std::pair<RValue, RValue> EmitAtomicCompareExchange(
+ LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
+ llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
+ llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent,
+ bool IsWeak = false, AggValueSlot Slot = AggValueSlot::ignored());
+
/// EmitToMemory - Change a scalar value from its value
/// representation to its in-memory representation.
llvm::Value *EmitToMemory(llvm::Value *Value, QualType Ty);
@@ -2039,7 +2147,7 @@ public:
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
/// lvalue, where both are guaranteed to the have the same type, and that type
/// is 'Ty'.
- void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit=false);
+ void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit = false);
void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst);
void EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst);
@@ -2082,6 +2190,8 @@ public:
LValue EmitCastLValue(const CastExpr *E);
LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
+
+ llvm::Value *EmitExtVectorElementLValue(LValue V);
RValue EmitRValueForField(LValue LV, const FieldDecl *FD, SourceLocation Loc);
@@ -2166,12 +2276,10 @@ public:
const Decl *TargetDecl = nullptr,
llvm::Instruction **callOrInvoke = nullptr);
- RValue EmitCall(QualType FnType, llvm::Value *Callee,
- SourceLocation CallLoc,
+ RValue EmitCall(QualType FnType, llvm::Value *Callee, const CallExpr *E,
ReturnValueSlot ReturnValue,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd,
- const Decl *TargetDecl = nullptr);
+ const Decl *TargetDecl = nullptr,
+ llvm::Value *Chain = nullptr);
RValue EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue = ReturnValueSlot());
@@ -2207,23 +2315,28 @@ public:
CXXDtorType Type,
const CXXRecordDecl *RD);
- RValue EmitCXXMemberCall(const CXXMethodDecl *MD,
- SourceLocation CallLoc,
- llvm::Value *Callee,
- ReturnValueSlot ReturnValue,
- llvm::Value *This,
- llvm::Value *ImplicitParam,
- QualType ImplicitParamTy,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd);
+ RValue
+ EmitCXXMemberOrOperatorCall(const CXXMethodDecl *MD, llvm::Value *Callee,
+ ReturnValueSlot ReturnValue, llvm::Value *This,
+ llvm::Value *ImplicitParam,
+ QualType ImplicitParamTy, const CallExpr *E);
+ RValue EmitCXXStructorCall(const CXXMethodDecl *MD, llvm::Value *Callee,
+ ReturnValueSlot ReturnValue, llvm::Value *This,
+ llvm::Value *ImplicitParam,
+ QualType ImplicitParamTy, const CallExpr *E,
+ StructorType Type);
RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
ReturnValueSlot ReturnValue);
+ RValue EmitCXXMemberOrOperatorMemberCallExpr(const CallExpr *CE,
+ const CXXMethodDecl *MD,
+ ReturnValueSlot ReturnValue,
+ bool HasQualifier,
+ NestedNameSpecifier *Qualifier,
+ bool IsArrow, const Expr *Base);
+ // Compute the object pointer.
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);
@@ -2233,7 +2346,8 @@ public:
RValue EmitBuiltinExpr(const FunctionDecl *FD,
- unsigned BuiltinID, const CallExpr *E);
+ unsigned BuiltinID, const CallExpr *E,
+ ReturnValueSlot ReturnValue);
RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue);
@@ -2413,12 +2527,6 @@ public:
/// EmitLoadOfComplex - Load a complex number from the specified l-value.
ComplexPairTy EmitLoadOfComplex(LValue src, SourceLocation loc);
- /// CreateStaticVarDecl - Create a zero-initialized LLVM global for
- /// a static local variable.
- llvm::Constant *CreateStaticVarDecl(const VarDecl &D,
- const char *Separator,
- llvm::GlobalValue::LinkageTypes Linkage);
-
/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the
/// global variable that has already been created for it. If the initializer
/// has a different type than GV does, this may free GV and return a different
@@ -2433,6 +2541,9 @@ public:
void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr,
bool PerformInit);
+ llvm::Constant *createAtExitStub(const VarDecl &VD, llvm::Constant *Dtor,
+ llvm::Constant *Addr);
+
/// Call atexit() with a function that passes the given argument to
/// the given function.
void registerGlobalDtorWithAtExit(const VarDecl &D, llvm::Constant *fn,
@@ -2449,7 +2560,7 @@ public:
/// GenerateCXXGlobalInitFunc - Generates code for initializing global
/// variables.
void GenerateCXXGlobalInitFunc(llvm::Function *Fn,
- ArrayRef<llvm::Constant *> Decls,
+ ArrayRef<llvm::Function *> CXXThreadLocals,
llvm::GlobalVariable *Guard = nullptr);
/// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
@@ -2541,23 +2652,12 @@ public:
/// passing to a runtime sanitizer handler.
llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc);
- /// \brief Specify under what conditions this check can be recovered
- enum CheckRecoverableKind {
- /// Always terminate program execution if this check fails
- CRK_Unrecoverable,
- /// Check supports recovering, allows user to specify which
- CRK_Recoverable,
- /// Runtime conditionally aborts, always need to support recovery.
- CRK_AlwaysRecoverable
- };
-
/// \brief Create a basic block that will call a handler function in a
/// sanitizer runtime with the provided arguments, and create a conditional
/// branch to it.
- void EmitCheck(llvm::Value *Checked, StringRef CheckName,
- ArrayRef<llvm::Constant *> StaticArgs,
- ArrayRef<llvm::Value *> DynamicArgs,
- CheckRecoverableKind Recoverable);
+ void EmitCheck(ArrayRef<std::pair<llvm::Value *, SanitizerKind>> Checked,
+ StringRef CheckName, ArrayRef<llvm::Constant *> StaticArgs,
+ ArrayRef<llvm::Value *> DynamicArgs);
/// \brief Create a basic block that will call the trap intrinsic, and emit a
/// conditional branch to it, for the -ftrapv checks.
@@ -2589,18 +2689,15 @@ private:
/// from function arguments into \arg Dst. See ABIArgInfo::Expand.
///
/// \param AI - The first function argument of the expansion.
- /// \return The argument following the last expanded function
- /// argument.
- llvm::Function::arg_iterator
- ExpandTypeFromArgs(QualType Ty, LValue Dst,
- llvm::Function::arg_iterator AI);
-
- /// ExpandTypeToArgs - Expand an RValue \arg Src, with the LLVM type for \arg
- /// Ty, into individual arguments on the provided vector \arg Args. See
- /// ABIArgInfo::Expand.
- void ExpandTypeToArgs(QualType Ty, RValue Src,
- SmallVectorImpl<llvm::Value *> &Args,
- llvm::FunctionType *IRFuncTy);
+ void ExpandTypeFromArgs(QualType Ty, LValue Dst,
+ SmallVectorImpl<llvm::Argument *>::iterator &AI);
+
+ /// ExpandTypeToArgs - Expand an RValue \arg RV, with the LLVM type for \arg
+ /// Ty, into individual arguments on the provided vector \arg IRCallArgs,
+ /// starting at index \arg IRCallArgPos. See ABIArgInfo::Expand.
+ void ExpandTypeToArgs(QualType Ty, RValue RV, llvm::FunctionType *IRFuncTy,
+ SmallVectorImpl<llvm::Value *> &IRCallArgs,
+ unsigned &IRCallArgPos);
llvm::Value* EmitAsmInput(const TargetInfo::ConstraintInfo &Info,
const Expr *InputExpr, std::string &ConstraintStr);
@@ -2616,76 +2713,53 @@ public:
void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd,
- bool ForceColumnInfo = false) {
- if (CallArgTypeInfo) {
- EmitCallArgs(Args, CallArgTypeInfo->isVariadic(),
- CallArgTypeInfo->param_type_begin(),
- CallArgTypeInfo->param_type_end(), ArgBeg, ArgEnd,
- ForceColumnInfo);
- } else {
- // T::param_type_iterator might not have a default ctor.
- const QualType *NoIter = nullptr;
- EmitCallArgs(Args, /*AllowExtraArguments=*/true, NoIter, NoIter, ArgBeg,
- ArgEnd, ForceColumnInfo);
- }
- }
-
- template<typename ArgTypeIterator>
- void EmitCallArgs(CallArgList& Args,
- bool AllowExtraArguments,
- ArgTypeIterator ArgTypeBeg,
- ArgTypeIterator ArgTypeEnd,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd,
- bool ForceColumnInfo = false) {
+ const FunctionDecl *CalleeDecl = nullptr,
+ unsigned ParamsToSkip = 0, bool ForceColumnInfo = false) {
SmallVector<QualType, 16> ArgTypes;
CallExpr::const_arg_iterator Arg = ArgBeg;
- // First, use the argument types that the type info knows about
- for (ArgTypeIterator I = ArgTypeBeg, E = ArgTypeEnd; I != E; ++I, ++Arg) {
- assert(Arg != ArgEnd && "Running over edge of argument list!");
-#ifndef NDEBUG
- QualType ArgType = *I;
- QualType ActualArgType = Arg->getType();
- if (ArgType->isPointerType() && ActualArgType->isPointerType()) {
- QualType ActualBaseType =
- ActualArgType->getAs<PointerType>()->getPointeeType();
- QualType ArgBaseType =
- ArgType->getAs<PointerType>()->getPointeeType();
- if (ArgBaseType->isVariableArrayType()) {
- if (const VariableArrayType *VAT =
- getContext().getAsVariableArrayType(ActualBaseType)) {
- if (!VAT->getSizeExpr())
- ActualArgType = ArgType;
- }
- }
+ assert((ParamsToSkip == 0 || CallArgTypeInfo) &&
+ "Can't skip parameters if type info is not provided");
+ if (CallArgTypeInfo) {
+ // First, use the argument types that the type info knows about
+ for (auto I = CallArgTypeInfo->param_type_begin() + ParamsToSkip,
+ E = CallArgTypeInfo->param_type_end();
+ I != E; ++I, ++Arg) {
+ assert(Arg != ArgEnd && "Running over edge of argument list!");
+ assert(
+ ((*I)->isVariablyModifiedType() ||
+ getContext()
+ .getCanonicalType((*I).getNonReferenceType())
+ .getTypePtr() ==
+ getContext().getCanonicalType(Arg->getType()).getTypePtr()) &&
+ "type mismatch in call argument!");
+ ArgTypes.push_back(*I);
}
- assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
- getTypePtr() ==
- getContext().getCanonicalType(ActualArgType).getTypePtr() &&
- "type mismatch in call argument!");
-#endif
- ArgTypes.push_back(*I);
}
// Either we've emitted all the call args, or we have a call to variadic
- // function or some other call that allows extra arguments.
- assert((Arg == ArgEnd || AllowExtraArguments) &&
- "Extra arguments in non-variadic function!");
+ // function.
+ assert(
+ (Arg == ArgEnd || !CallArgTypeInfo || CallArgTypeInfo->isVariadic()) &&
+ "Extra arguments in non-variadic function!");
// If we still have any arguments, emit them using the type of the argument.
for (; Arg != ArgEnd; ++Arg)
- ArgTypes.push_back(Arg->getType());
+ ArgTypes.push_back(getVarArgType(*Arg));
- EmitCallArgs(Args, ArgTypes, ArgBeg, ArgEnd, ForceColumnInfo);
+ EmitCallArgs(Args, ArgTypes, ArgBeg, ArgEnd, CalleeDecl, ParamsToSkip,
+ ForceColumnInfo);
}
void EmitCallArgs(CallArgList &Args, ArrayRef<QualType> ArgTypes,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd,
- bool ForceColumnInfo = false);
+ const FunctionDecl *CalleeDecl = nullptr,
+ unsigned ParamsToSkip = 0, bool ForceColumnInfo = false);
private:
+ QualType getVarArgType(const Expr *Arg);
+
const TargetCodeGenInfo &getTargetHooks() const {
return CGM.getTargetCodeGenInfo();
}
@@ -2701,6 +2775,8 @@ private:
/// GetPointeeAlignment - Given an expression with a pointer type, emit the
/// value and compute our best estimate of the alignment of the pointee.
std::pair<llvm::Value*, unsigned> EmitPointerWithAlignment(const Expr *Addr);
+
+ llvm::Value *GetValueForARMHint(unsigned BuiltinID);
};
/// Helper class with most of the code for saving a value for a
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 48823befcc07..8981bfe89cb4 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -22,6 +22,7 @@
#include "CodeGenFunction.h"
#include "CodeGenPGO.h"
#include "CodeGenTBAA.h"
+#include "CoverageMappingGen.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
@@ -74,7 +75,8 @@ static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
llvm::Module &M, const llvm::DataLayout &TD,
- DiagnosticsEngine &diags)
+ DiagnosticsEngine &diags,
+ CoverageSourceInfo *CoverageInfo)
: Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M),
Diags(diags), TheDataLayout(TD), Target(C.getTargetInfo()),
ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(nullptr),
@@ -87,8 +89,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
NSConcreteStackBlock(nullptr), BlockObjectAssign(nullptr),
BlockObjectDispose(nullptr), BlockDescriptorType(nullptr),
GenericBlockLiteralType(nullptr), LifetimeStartFn(nullptr),
- LifetimeEndFn(nullptr), SanitizerBL(llvm::SpecialCaseList::createOrDie(
- CGO.SanitizerBlacklistFile)) {
+ LifetimeEndFn(nullptr), SanitizerMD(new SanitizerMetadata(*this)) {
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
@@ -108,6 +109,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC();
+ BuiltinCC = getTargetCodeGenInfo().getABIInfo().getBuiltinCC();
if (LangOpts.ObjC1)
createObjCRuntime();
@@ -119,7 +121,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
createCUDARuntime();
// Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0.
- if (LangOpts.Sanitize.Thread ||
+ if (LangOpts.Sanitize.has(SanitizerKind::Thread) ||
(!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0))
TBAA = new CodeGenTBAA(Context, VMContext, CodeGenOpts, getLangOpts(),
getCXXABI().getMangleContext());
@@ -145,6 +147,11 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
getDiags().Report(DiagID) << EC.message();
}
}
+
+ // If coverage mapping generation is enabled, create the
+ // CoverageMappingModuleGen object.
+ if (CodeGenOpts.CoverageMapping)
+ CoverageMapping.reset(new CoverageMappingModuleGen(*this, *CoverageInfo));
}
CodeGenModule::~CodeGenModule() {
@@ -190,6 +197,10 @@ void CodeGenModule::createCUDARuntime() {
CUDARuntime = CreateNVCUDARuntime(*this);
}
+void CodeGenModule::addReplacement(StringRef Name, llvm::Constant *C) {
+ Replacements[Name] = C;
+}
+
void CodeGenModule::applyReplacements() {
for (ReplacementsTy::iterator I = Replacements.begin(),
E = Replacements.end();
@@ -235,7 +246,7 @@ static const llvm::GlobalObject *getAliasedGlobal(const llvm::GlobalAlias &GA) {
auto *GA2 = dyn_cast<llvm::GlobalAlias>(C);
if (!GA2)
return nullptr;
- if (!Visited.insert(GA2))
+ if (!Visited.insert(GA2).second)
return nullptr;
C = GA2->getAliasee();
}
@@ -334,15 +345,15 @@ void CodeGenModule::Release() {
if (ObjCRuntime)
if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction())
AddGlobalCtor(ObjCInitFunction);
- if (getCodeGenOpts().ProfileInstrGenerate)
- if (llvm::Function *PGOInit = CodeGenPGO::emitInitialization(*this))
- AddGlobalCtor(PGOInit, 0);
if (PGOReader && PGOStats.hasDiagnostics())
PGOStats.reportDiagnostics(getDiags(), getCodeGenOpts().MainFileName);
EmitCtorList(GlobalCtors, "llvm.global_ctors");
EmitCtorList(GlobalDtors, "llvm.global_dtors");
EmitGlobalAnnotations();
EmitStaticExternCAliases();
+ EmitDeferredUnusedCoverageMappings();
+ if (CoverageMapping)
+ CoverageMapping->emit();
emitLLVMUsed();
if (CodeGenOpts.Autolink &&
@@ -378,6 +389,18 @@ void CodeGenModule::Release() {
getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth);
}
+ if (uint32_t PLevel = Context.getLangOpts().PICLevel) {
+ llvm::PICLevel::Level PL = llvm::PICLevel::Default;
+ switch (PLevel) {
+ case 0: break;
+ case 1: PL = llvm::PICLevel::Small; break;
+ case 2: PL = llvm::PICLevel::Large; break;
+ default: llvm_unreachable("Invalid PIC Level");
+ }
+
+ getModule().setPICLevel(PL);
+ }
+
SimplifyPersonality();
if (getCodeGenOpts().EmitDeclMetadata)
@@ -510,11 +533,10 @@ static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel(
llvm_unreachable("Invalid TLS model!");
}
-void CodeGenModule::setTLSMode(llvm::GlobalVariable *GV,
- const VarDecl &D) const {
+void CodeGenModule::setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const {
assert(D.getTLSKind() && "setting TLS mode on non-TLS var!");
- llvm::GlobalVariable::ThreadLocalMode TLM;
+ llvm::GlobalValue::ThreadLocalMode TLM;
TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel());
// Override the TLS model if it is explicitly specified.
@@ -548,9 +570,9 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
Str = II->getName();
}
- auto &Mangled = Manglings.GetOrCreateValue(Str);
- Mangled.second = GD;
- return FoundStr = Mangled.first();
+ // Keep the first result in the case of a mangling collision.
+ auto Result = Manglings.insert(std::make_pair(Str, GD));
+ return FoundStr = Result.first->first();
}
StringRef CodeGenModule::getBlockMangledName(GlobalDecl GD,
@@ -570,9 +592,8 @@ StringRef CodeGenModule::getBlockMangledName(GlobalDecl GD,
else
MangleCtx.mangleBlock(cast<DeclContext>(D), BD, Out);
- auto &Mangled = Manglings.GetOrCreateValue(Out.str());
- Mangled.second = BD;
- return Mangled.first();
+ auto Result = Manglings.insert(std::make_pair(Out.str(), BD));
+ return Result.first->first();
}
llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) {
@@ -601,7 +622,7 @@ void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
// Get the type of a ctor entry, { i32, void ()*, i8* }.
llvm::StructType *CtorStructTy = llvm::StructType::get(
- Int32Ty, llvm::PointerType::getUnqual(CtorFTy), VoidPtrTy, NULL);
+ Int32Ty, llvm::PointerType::getUnqual(CtorFTy), VoidPtrTy, nullptr);
// Construct the constructor and destructor arrays.
SmallVector<llvm::Constant*, 8> Ctors;
@@ -692,10 +713,6 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// Naked implies noinline: we should not be inlining such functions.
B.addAttribute(llvm::Attribute::Naked);
B.addAttribute(llvm::Attribute::NoInline);
- } else if (D->hasAttr<OptimizeNoneAttr>()) {
- // OptimizeNone implies noinline; we should not be inlining such functions.
- B.addAttribute(llvm::Attribute::OptimizeNone);
- B.addAttribute(llvm::Attribute::NoInline);
} else if (D->hasAttr<NoDuplicateAttr>()) {
B.addAttribute(llvm::Attribute::NoDuplicate);
} else if (D->hasAttr<NoInlineAttr>()) {
@@ -708,19 +725,14 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
}
if (D->hasAttr<ColdAttr>()) {
- B.addAttribute(llvm::Attribute::OptimizeForSize);
+ if (!D->hasAttr<OptimizeNoneAttr>())
+ B.addAttribute(llvm::Attribute::OptimizeForSize);
B.addAttribute(llvm::Attribute::Cold);
}
if (D->hasAttr<MinSizeAttr>())
B.addAttribute(llvm::Attribute::MinSize);
- if (D->hasAttr<OptimizeNoneAttr>()) {
- // OptimizeNone wins over OptimizeForSize and MinSize.
- B.removeAttribute(llvm::Attribute::OptimizeForSize);
- B.removeAttribute(llvm::Attribute::MinSize);
- }
-
if (LangOpts.getStackProtector() == LangOptions::SSPOn)
B.addAttribute(llvm::Attribute::StackProtect);
else if (LangOpts.getStackProtector() == LangOptions::SSPStrong)
@@ -729,16 +741,19 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
B.addAttribute(llvm::Attribute::StackProtectReq);
// Add sanitizer attributes if function is not blacklisted.
- if (!SanitizerBL.isIn(*F)) {
+ if (!isInSanitizerBlacklist(F, D->getLocation())) {
// When AddressSanitizer is enabled, set SanitizeAddress attribute
// unless __attribute__((no_sanitize_address)) is used.
- if (LangOpts.Sanitize.Address && !D->hasAttr<NoSanitizeAddressAttr>())
+ if (LangOpts.Sanitize.has(SanitizerKind::Address) &&
+ !D->hasAttr<NoSanitizeAddressAttr>())
B.addAttribute(llvm::Attribute::SanitizeAddress);
// Same for ThreadSanitizer and __attribute__((no_sanitize_thread))
- if (LangOpts.Sanitize.Thread && !D->hasAttr<NoSanitizeThreadAttr>())
+ if (LangOpts.Sanitize.has(SanitizerKind::Thread) &&
+ !D->hasAttr<NoSanitizeThreadAttr>())
B.addAttribute(llvm::Attribute::SanitizeThread);
// Same for MemorySanitizer and __attribute__((no_sanitize_memory))
- if (LangOpts.Sanitize.Memory && !D->hasAttr<NoSanitizeMemoryAttr>())
+ if (LangOpts.Sanitize.has(SanitizerKind::Memory) &&
+ !D->hasAttr<NoSanitizeMemoryAttr>())
B.addAttribute(llvm::Attribute::SanitizeMemory);
}
@@ -746,6 +761,24 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
llvm::AttributeSet::get(
F->getContext(), llvm::AttributeSet::FunctionIndex, B));
+ if (D->hasAttr<OptimizeNoneAttr>()) {
+ // OptimizeNone implies noinline; we should not be inlining such functions.
+ F->addFnAttr(llvm::Attribute::OptimizeNone);
+ F->addFnAttr(llvm::Attribute::NoInline);
+
+ // OptimizeNone wins over OptimizeForSize, MinSize, AlwaysInline.
+ assert(!F->hasFnAttribute(llvm::Attribute::OptimizeForSize) &&
+ "OptimizeNone and OptimizeForSize on same function!");
+ assert(!F->hasFnAttribute(llvm::Attribute::MinSize) &&
+ "OptimizeNone and MinSize on same function!");
+ assert(!F->hasFnAttribute(llvm::Attribute::AlwaysInline) &&
+ "OptimizeNone and AlwaysInline on same function!");
+
+ // Attribute 'inlinehint' has no effect on 'optnone' functions.
+ // Explicitly remove it from the set of function attributes.
+ F->removeFnAttr(llvm::Attribute::InlineHint);
+ }
+
if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D))
F->setUnnamedAddr(true);
else if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
@@ -772,6 +805,16 @@ void CodeGenModule::SetCommonAttributes(const Decl *D,
addUsedGlobal(GV);
}
+void CodeGenModule::setAliasAttributes(const Decl *D,
+ llvm::GlobalValue *GV) {
+ SetCommonAttributes(D, GV);
+
+ // Process the dllexport attribute based on whether the original definition
+ // (not necessarily the aliasee) was exported.
+ if (D->hasAttr<DLLExportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+}
+
void CodeGenModule::setNonAliasAttributes(const Decl *D,
llvm::GlobalObject *GO) {
SetCommonAttributes(D, GO);
@@ -818,9 +861,9 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV,
}
}
-void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
- llvm::Function *F,
- bool IsIncompleteFunction) {
+void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
+ bool IsIncompleteFunction,
+ bool IsThunk) {
if (unsigned IID = F->getIntrinsicID()) {
// If this is an intrinsic function, set the function's attributes
// to the intrinsic's attributes.
@@ -837,7 +880,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
// Add the Returned attribute for "this", except for iOS 5 and earlier
// where substantial code, including the libstdc++ dylib, was compiled with
// GCC and does not actually return "this".
- if (getCXXABI().HasThisReturn(GD) &&
+ if (!IsThunk && getCXXABI().HasThisReturn(GD) &&
!(getTarget().getTriple().isiOS() &&
getTarget().getTriple().isOSVersionLT(6))) {
assert(!F->arg_empty() &&
@@ -913,38 +956,37 @@ void CodeGenModule::emitLLVMUsed() {
}
void CodeGenModule::AppendLinkerOptions(StringRef Opts) {
- llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opts);
+ auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opts);
LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
}
void CodeGenModule::AddDetectMismatch(StringRef Name, StringRef Value) {
llvm::SmallString<32> Opt;
getTargetCodeGenInfo().getDetectMismatchOption(Name, Value, Opt);
- llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
+ auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
}
void CodeGenModule::AddDependentLib(StringRef Lib) {
llvm::SmallString<24> Opt;
getTargetCodeGenInfo().getDependentLibraryOption(Lib, Opt);
- llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
+ auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
}
/// \brief Add link options implied by the given module, including modules
/// it depends on, using a postorder walk.
-static void addLinkOptionsPostorder(CodeGenModule &CGM,
- Module *Mod,
- SmallVectorImpl<llvm::Value *> &Metadata,
+static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod,
+ SmallVectorImpl<llvm::Metadata *> &Metadata,
llvm::SmallPtrSet<Module *, 16> &Visited) {
// Import this module's parent.
- if (Mod->Parent && Visited.insert(Mod->Parent)) {
+ if (Mod->Parent && Visited.insert(Mod->Parent).second) {
addLinkOptionsPostorder(CGM, Mod->Parent, Metadata, Visited);
}
// Import this module's dependencies.
for (unsigned I = Mod->Imports.size(); I > 0; --I) {
- if (Visited.insert(Mod->Imports[I-1]))
+ if (Visited.insert(Mod->Imports[I - 1]).second)
addLinkOptionsPostorder(CGM, Mod->Imports[I-1], Metadata, Visited);
}
@@ -955,10 +997,9 @@ static void addLinkOptionsPostorder(CodeGenModule &CGM,
// Link against a framework. Frameworks are currently Darwin only, so we
// don't to ask TargetCodeGenInfo for the spelling of the linker option.
if (Mod->LinkLibraries[I-1].IsFramework) {
- llvm::Value *Args[2] = {
- llvm::MDString::get(Context, "-framework"),
- llvm::MDString::get(Context, Mod->LinkLibraries[I-1].Library)
- };
+ llvm::Metadata *Args[2] = {
+ llvm::MDString::get(Context, "-framework"),
+ llvm::MDString::get(Context, Mod->LinkLibraries[I - 1].Library)};
Metadata.push_back(llvm::MDNode::get(Context, Args));
continue;
@@ -968,7 +1009,7 @@ static void addLinkOptionsPostorder(CodeGenModule &CGM,
llvm::SmallString<24> Opt;
CGM.getTargetCodeGenInfo().getDependentLibraryOption(
Mod->LinkLibraries[I-1].Library, Opt);
- llvm::Value *OptString = llvm::MDString::get(Context, Opt);
+ auto *OptString = llvm::MDString::get(Context, Opt);
Metadata.push_back(llvm::MDNode::get(Context, OptString));
}
}
@@ -985,7 +1026,7 @@ void CodeGenModule::EmitModuleLinkOptions() {
for (llvm::SetVector<clang::Module *>::iterator M = ImportedModules.begin(),
MEnd = ImportedModules.end();
M != MEnd; ++M) {
- if (Visited.insert(*M))
+ if (Visited.insert(*M).second)
Stack.push_back(*M);
}
@@ -1005,7 +1046,7 @@ void CodeGenModule::EmitModuleLinkOptions() {
if ((*Sub)->IsExplicit)
continue;
- if (Visited.insert(*Sub)) {
+ if (Visited.insert(*Sub).second) {
Stack.push_back(*Sub);
AnyChildren = true;
}
@@ -1021,12 +1062,12 @@ void CodeGenModule::EmitModuleLinkOptions() {
// Add link options for all of the imported modules in reverse topological
// order. We don't do anything to try to order import link flags with respect
// to linker options inserted by things like #pragma comment().
- SmallVector<llvm::Value *, 16> MetadataArgs;
+ SmallVector<llvm::Metadata *, 16> MetadataArgs;
Visited.clear();
for (llvm::SetVector<clang::Module *>::iterator M = LinkModules.begin(),
MEnd = LinkModules.end();
M != MEnd; ++M) {
- if (Visited.insert(*M))
+ if (Visited.insert(*M).second)
addLinkOptionsPostorder(*this, *M, MetadataArgs, Visited);
}
std::reverse(MetadataArgs.begin(), MetadataArgs.end());
@@ -1061,14 +1102,18 @@ void CodeGenModule::EmitDeferred() {
llvm::GlobalValue *GV = G.GV;
DeferredDeclsToEmit.pop_back();
- assert(GV == GetGlobalValue(getMangledName(D)));
+ assert(!GV || GV == GetGlobalValue(getMangledName(D)));
+ if (!GV)
+ GV = GetGlobalValue(getMangledName(D));
+
+
// Check to see if we've already emitted this. This is necessary
// for a couple of reasons: first, decls can end up in the
// deferred-decls queue multiple times, and second, decls can end
// up with definitions in unusual ways (e.g. by an extern inline
// function acquiring a strong function redefinition). Just
// ignore these cases.
- if(!GV->isDeclaration())
+ if (GV && !GV->isDeclaration())
continue;
// Otherwise, emit the definition and move on to the next one.
@@ -1147,12 +1192,68 @@ void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation()));
}
-bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
+bool CodeGenModule::isInSanitizerBlacklist(llvm::Function *Fn,
+ SourceLocation Loc) const {
+ const auto &SanitizerBL = getContext().getSanitizerBlacklist();
+ // Blacklist by function name.
+ if (SanitizerBL.isBlacklistedFunction(Fn->getName()))
+ return true;
+ // Blacklist by location.
+ if (!Loc.isInvalid())
+ return SanitizerBL.isBlacklistedLocation(Loc);
+ // If location is unknown, this may be a compiler-generated function. Assume
+ // it's located in the main file.
+ auto &SM = Context.getSourceManager();
+ if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
+ return SanitizerBL.isBlacklistedFile(MainFile->getName());
+ }
+ return false;
+}
+
+bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
+ SourceLocation Loc, QualType Ty,
+ StringRef Category) const {
+ // For now globals can be blacklisted only in ASan.
+ if (!LangOpts.Sanitize.has(SanitizerKind::Address))
+ return false;
+ const auto &SanitizerBL = getContext().getSanitizerBlacklist();
+ if (SanitizerBL.isBlacklistedGlobal(GV->getName(), Category))
+ return true;
+ if (SanitizerBL.isBlacklistedLocation(Loc, Category))
+ return true;
+ // Check global type.
+ if (!Ty.isNull()) {
+ // Drill down the array types: if global variable of a fixed type is
+ // blacklisted, we also don't instrument arrays of them.
+ while (auto AT = dyn_cast<ArrayType>(Ty.getTypePtr()))
+ Ty = AT->getElementType();
+ Ty = Ty.getCanonicalType().getUnqualifiedType();
+ // We allow to blacklist only record types (classes, structs etc.)
+ if (Ty->isRecordType()) {
+ std::string TypeStr = Ty.getAsString(getContext().getPrintingPolicy());
+ if (SanitizerBL.isBlacklistedType(TypeStr, Category))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {
// Never defer when EmitAllDecls is specified.
if (LangOpts.EmitAllDecls)
- return false;
+ return true;
- return !getContext().DeclMustBeEmitted(Global);
+ return getContext().DeclMustBeEmitted(Global);
+}
+
+bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(Global))
+ if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
+ // Implicit template instantiations may change linkage if they are later
+ // explicitly instantiated, so they should not be emitted eagerly.
+ return false;
+
+ return true;
}
llvm::Constant *CodeGenModule::GetAddrOfUuidDescriptor(
@@ -1167,7 +1268,7 @@ llvm::Constant *CodeGenModule::GetAddrOfUuidDescriptor(
if (llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name))
return GV;
- llvm::Constant *Init = EmitUuidofInitializer(Uuid, E->getType());
+ llvm::Constant *Init = EmitUuidofInitializer(Uuid);
assert(Init && "failed to initialize as constant");
auto *GV = new llvm::GlobalVariable(
@@ -1261,9 +1362,10 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
return;
}
- // Defer code generation when possible if this is a static definition, inline
- // function etc. These we only want to emit if they are used.
- if (!MayDeferGeneration(Global)) {
+ // Defer code generation to first use when possible, e.g. if this is an inline
+ // function. If the global must always be emitted, do it eagerly if possible
+ // to benefit from cache locality.
+ if (MustBeEmitted(Global) && MayBeEmittedEagerly(Global)) {
// Emit the definition if it can't be deferred.
EmitGlobalDefinition(GD);
return;
@@ -1276,13 +1378,16 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
DelayedCXXInitPosition[Global] = CXXGlobalInits.size();
CXXGlobalInits.push_back(nullptr);
}
-
- // If the value has already been used, add it directly to the
- // DeferredDeclsToEmit list.
+
StringRef MangledName = getMangledName(GD);
- if (llvm::GlobalValue *GV = GetGlobalValue(MangledName))
+ if (llvm::GlobalValue *GV = GetGlobalValue(MangledName)) {
+ // The value has already been used and should therefore be emitted.
addDeferredDeclToEmit(GV, GD);
- else {
+ } else if (MustBeEmitted(Global)) {
+ // The value must be emitted, but cannot be emitted eagerly.
+ assert(!MayBeEmittedEagerly(Global));
+ addDeferredDeclToEmit(/*GV=*/nullptr, GD);
+ } else {
// Otherwise, remember that we saw a deferred decl with this name. The
// first use of the mangled name will cause it to move into
// DeferredDeclsToEmit.
@@ -1394,9 +1499,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
// Make sure to emit the definition(s) before we emit the thunks.
// This is necessary for the generation of certain thunks.
if (const auto *CD = dyn_cast<CXXConstructorDecl>(Method))
- EmitCXXConstructor(CD, GD.getCtorType());
+ ABI->emitCXXStructor(CD, getFromCtorType(GD.getCtorType()));
else if (const auto *DD = dyn_cast<CXXDestructorDecl>(Method))
- EmitCXXDestructor(DD, GD.getDtorType());
+ ABI->emitCXXStructor(DD, getFromDtorType(GD.getDtorType()));
else
EmitGlobalFunctionDefinition(GD, GV);
@@ -1426,7 +1531,7 @@ llvm::Constant *
CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
llvm::Type *Ty,
GlobalDecl GD, bool ForVTable,
- bool DontDefer,
+ bool DontDefer, bool IsThunk,
llvm::AttributeSet ExtraAttrs) {
const Decl *D = GD.getDecl();
@@ -1439,6 +1544,10 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
Entry->setLinkage(llvm::Function::ExternalLinkage);
}
+ // Handle dropped DLL attributes.
+ if (D && !D->hasAttr<DLLImportAttr>() && !D->hasAttr<DLLExportAttr>())
+ Entry->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
+
if (Entry->getType()->getElementType() == Ty)
return Entry;
@@ -1464,7 +1573,7 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
MangledName, &getModule());
assert(F->getName() == MangledName && "name was uniqued!");
if (D)
- SetFunctionAttributes(GD, F, IsIncompleteFunction);
+ SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk);
if (ExtraAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex)) {
llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeSet::FunctionIndex);
F->addAttributes(llvm::AttributeSet::FunctionIndex,
@@ -1510,26 +1619,18 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
// this will be unnecessary.
//
// We also don't emit a definition for a function if it's going to be an
- // entry
- // in a vtable, unless it's already marked as used.
+ // entry in a vtable, unless it's already marked as used.
} else if (getLangOpts().CPlusPlus && D) {
// Look for a declaration that's lexically in a record.
- const auto *FD = cast<FunctionDecl>(D);
- FD = FD->getMostRecentDecl();
- do {
+ for (const auto *FD = cast<FunctionDecl>(D)->getMostRecentDecl(); FD;
+ FD = FD->getPreviousDecl()) {
if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
- if (FD->isImplicit() && !ForVTable) {
- assert(FD->isUsed() &&
- "Sema didn't mark implicit function as used!");
- addDeferredDeclToEmit(F, GD.getWithDecl(FD));
- break;
- } else if (FD->doesThisDeclarationHaveABody()) {
+ if (FD->doesThisDeclarationHaveABody()) {
addDeferredDeclToEmit(F, GD.getWithDecl(FD));
break;
}
}
- FD = FD->getPreviousDecl();
- } while (FD);
+ }
}
}
@@ -1566,13 +1667,28 @@ CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy,
llvm::AttributeSet ExtraAttrs) {
llvm::Constant *C =
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
- /*DontDefer=*/false, ExtraAttrs);
+ /*DontDefer=*/false, /*IsThunk=*/false, ExtraAttrs);
if (auto *F = dyn_cast<llvm::Function>(C))
if (F->empty())
F->setCallingConv(getRuntimeCC());
return C;
}
+/// CreateBuiltinFunction - Create a new builtin function with the specified
+/// type and name.
+llvm::Constant *
+CodeGenModule::CreateBuiltinFunction(llvm::FunctionType *FTy,
+ StringRef Name,
+ llvm::AttributeSet ExtraAttrs) {
+ llvm::Constant *C =
+ GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
+ /*DontDefer=*/false, /*IsThunk=*/false, ExtraAttrs);
+ if (auto *F = dyn_cast<llvm::Function>(C))
+ if (F->empty())
+ F->setCallingConv(getBuiltinCC());
+ return C;
+}
+
/// isTypeConstant - Determine whether an object of this type can be emitted
/// as a constant.
///
@@ -1612,6 +1728,10 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
Entry->setLinkage(llvm::Function::ExternalLinkage);
}
+ // Handle dropped DLL attributes.
+ if (D && !D->hasAttr<DLLImportAttr>() && !D->hasAttr<DLLExportAttr>())
+ Entry->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
+
if (Entry->getType() == Ty)
return Entry;
@@ -1741,7 +1861,7 @@ CodeGenModule::CreateRuntimeVariable(llvm::Type *Ty,
void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
assert(!D->getInit() && "Cannot emit definite definitions here!");
- if (MayDeferGeneration(D)) {
+ if (!MustBeEmitted(D)) {
// If we have not seen a reference to this variable yet, place it
// into the deferred declarations table to be emitted if needed
// later.
@@ -1808,6 +1928,31 @@ void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D,
R.first->second = nullptr;
}
+static bool shouldBeInCOMDAT(CodeGenModule &CGM, const Decl &D) {
+ if (!CGM.supportsCOMDAT())
+ return false;
+
+ if (D.hasAttr<SelectAnyAttr>())
+ return true;
+
+ GVALinkage Linkage;
+ if (auto *VD = dyn_cast<VarDecl>(&D))
+ Linkage = CGM.getContext().GetGVALinkageForVariable(VD);
+ else
+ Linkage = CGM.getContext().GetGVALinkageForFunction(cast<FunctionDecl>(&D));
+
+ switch (Linkage) {
+ case GVA_Internal:
+ case GVA_AvailableExternally:
+ case GVA_StrongExternal:
+ return false;
+ case GVA_DiscardableODR:
+ case GVA_StrongODR:
+ return true;
+ }
+ llvm_unreachable("No such linkage");
+}
+
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
llvm::Constant *Init = nullptr;
QualType ASTTy = D->getType();
@@ -1910,6 +2055,13 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->setConstant(!NeedsGlobalCtor && !NeedsGlobalDtor &&
isTypeConstant(D->getType(), true));
+ // If it is in a read-only section, mark it 'constant'.
+ if (const SectionAttr *SA = D->getAttr<SectionAttr>()) {
+ const ASTContext::SectionInfo &SI = Context.SectionInfos[SA->getName()];
+ if ((SI.SectionFlags & ASTContext::PSF_Write) == 0)
+ GV->setConstant(true);
+ }
+
GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
// Set the llvm linkage type as appropriate.
@@ -1920,16 +2072,17 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// has internal linkage; all accesses should just be calls to the
// Itanium-specified entry point, which has the normal linkage of the
// variable.
- if (const auto *VD = dyn_cast<VarDecl>(D))
- if (!VD->isStaticLocal() && VD->getTLSKind() == VarDecl::TLS_Dynamic &&
- Context.getTargetInfo().getTriple().isMacOSX())
- Linkage = llvm::GlobalValue::InternalLinkage;
+ if (!D->isStaticLocal() && D->getTLSKind() == VarDecl::TLS_Dynamic &&
+ Context.getTargetInfo().getTriple().isMacOSX())
+ Linkage = llvm::GlobalValue::InternalLinkage;
GV->setLinkage(Linkage);
if (D->hasAttr<DLLImportAttr>())
GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
else if (D->hasAttr<DLLExportAttr>())
GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
+ else
+ GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
if (Linkage == llvm::GlobalVariable::CommonLinkage)
// common vars aren't constant even if declared const.
@@ -1937,11 +2090,20 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
setNonAliasAttributes(D, GV);
+ if (D->getTLSKind() && !GV->isThreadLocal()) {
+ if (D->getTLSKind() == VarDecl::TLS_Dynamic)
+ CXXThreadLocals.push_back(std::make_pair(D, GV));
+ setTLSMode(GV, *D);
+ }
+
+ if (shouldBeInCOMDAT(*this, *D))
+ GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
+
// Emit the initializer function if necessary.
if (NeedsGlobalCtor || NeedsGlobalDtor)
EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
- reportGlobalToASan(GV, *D, NeedsGlobalCtor);
+ SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor);
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
@@ -1949,73 +2111,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
DI->EmitGlobalVariable(GV, D);
}
-void CodeGenModule::reportGlobalToASan(llvm::GlobalVariable *GV,
- SourceLocation Loc, StringRef Name,
- bool IsDynInit, bool IsBlacklisted) {
- if (!LangOpts.Sanitize.Address)
- return;
- IsDynInit &= !SanitizerBL.isIn(*GV, "init");
- IsBlacklisted |= SanitizerBL.isIn(*GV);
-
- llvm::GlobalVariable *LocDescr = nullptr;
- llvm::GlobalVariable *GlobalName = nullptr;
- if (!IsBlacklisted) {
- // Don't generate source location and global name if it is blacklisted -
- // it won't be instrumented anyway.
- PresumedLoc PLoc = Context.getSourceManager().getPresumedLoc(Loc);
- if (PLoc.isValid()) {
- llvm::Constant *LocData[] = {
- GetAddrOfConstantCString(PLoc.getFilename()),
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- PLoc.getLine()),
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- PLoc.getColumn()),
- };
- auto LocStruct = llvm::ConstantStruct::getAnon(LocData);
- LocDescr = new llvm::GlobalVariable(TheModule, LocStruct->getType(), true,
- llvm::GlobalValue::PrivateLinkage,
- LocStruct, ".asan_loc_descr");
- LocDescr->setUnnamedAddr(true);
- // Add LocDescr to llvm.compiler.used, so that it won't be removed by
- // the optimizer before the ASan instrumentation pass.
- addCompilerUsedGlobal(LocDescr);
- }
- if (!Name.empty()) {
- GlobalName = GetAddrOfConstantCString(Name);
- // GlobalName shouldn't be removed by the optimizer.
- addCompilerUsedGlobal(GlobalName);
- }
- }
-
- llvm::Value *GlobalMetadata[] = {
- GV, LocDescr, GlobalName,
- llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsDynInit),
- llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsBlacklisted)};
-
- llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalMetadata);
- llvm::NamedMDNode *AsanGlobals =
- TheModule.getOrInsertNamedMetadata("llvm.asan.globals");
- AsanGlobals->addOperand(ThisGlobal);
-}
-
-void CodeGenModule::reportGlobalToASan(llvm::GlobalVariable *GV,
- const VarDecl &D, bool IsDynInit) {
- if (!LangOpts.Sanitize.Address)
- return;
- std::string QualName;
- llvm::raw_string_ostream OS(QualName);
- D.printQualifiedName(OS);
- reportGlobalToASan(GV, D.getLocation(), OS.str(), IsDynInit);
-}
-
-void CodeGenModule::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
- // For now, just make sure the global is not modified by the ASan
- // instrumentation.
- if (LangOpts.Sanitize.Address)
- reportGlobalToASan(GV, SourceLocation(), "", false, true);
-}
-
-static bool isVarDeclStrongDefinition(const VarDecl *D, bool NoCommon) {
+static bool isVarDeclStrongDefinition(const ASTContext &Context,
+ const VarDecl *D, bool NoCommon) {
// Don't give variables common linkage if -fno-common was specified unless it
// was overridden by a NoCommon attribute.
if ((NoCommon || D->hasAttr<NoCommonAttr>()) && !D->hasAttr<CommonAttr>())
@@ -2040,6 +2137,12 @@ static bool isVarDeclStrongDefinition(const VarDecl *D, bool NoCommon) {
if (D->hasAttr<WeakImportAttr>())
return true;
+ // Declarations with a required alignment do not have common linakge in MSVC
+ // mode.
+ if (Context.getLangOpts().MSVCCompat &&
+ (Context.isAlignmentRequired(D->getType()) || D->hasAttr<AlignedAttr>()))
+ return true;
+
return false;
}
@@ -2086,7 +2189,8 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator(
// C++ doesn't have tentative definitions and thus cannot have common
// linkage.
if (!getLangOpts().CPlusPlus && isa<VarDecl>(D) &&
- !isVarDeclStrongDefinition(cast<VarDecl>(D), CodeGenOpts.NoCommon))
+ !isVarDeclStrongDefinition(Context, cast<VarDecl>(D),
+ CodeGenOpts.NoCommon))
return llvm::GlobalVariable::CommonLinkage;
// selectany symbols are externally visible, so use weak instead of
@@ -2265,6 +2369,9 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
if (!GV->isDeclaration()) {
getDiags().Report(D->getLocation(), diag::err_duplicate_mangled_name);
+ GlobalDecl OldGD = Manglings.lookup(GV->getName());
+ if (auto *Prev = OldGD.getDecl())
+ getDiags().Report(Prev->getLocation(), diag::note_previous_definition);
return;
}
@@ -2314,12 +2421,21 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
// declarations).
auto *Fn = cast<llvm::Function>(GV);
setFunctionLinkage(GD, Fn);
+ if (D->hasAttr<DLLImportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
+ else if (D->hasAttr<DLLExportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
+ else
+ GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
// FIXME: this is redundant with part of setFunctionDefinitionAttributes
setGlobalVisibility(Fn, D);
MaybeHandleStaticInExternC(D, Fn);
+ if (shouldBeInCOMDAT(*this, *D))
+ Fn->setComdat(TheModule.getOrInsertComdat(Fn->getName()));
+
CodeGenFunction(*this).GenerateCode(D, Fn, FI);
setFunctionDefinitionAttributes(D, Fn);
@@ -2359,7 +2475,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
else
Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
llvm::PointerType::getUnqual(DeclTy),
- nullptr);
+ /*D=*/nullptr);
// Create the new alias itself, but don't set a name yet.
auto *GA = llvm::GlobalAlias::create(
@@ -2393,21 +2509,16 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
// Set attributes which are particular to an alias; this is a
// specialization of the attributes which may be set on a global
// variable/function.
- if (D->hasAttr<DLLExportAttr>()) {
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- // The dllexport attribute is ignored for undefined symbols.
- if (FD->hasBody())
- GA->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
- } else {
- GA->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
- }
- } else if (D->hasAttr<WeakAttr>() ||
- D->hasAttr<WeakRefAttr>() ||
- D->isWeakImported()) {
+ if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakRefAttr>() ||
+ D->isWeakImported()) {
GA->setLinkage(llvm::Function::WeakAnyLinkage);
}
- SetCommonAttributes(D, GA);
+ if (const auto *VD = dyn_cast<VarDecl>(D))
+ if (VD->getTLSKind())
+ setTLSMode(GA, *VD);
+
+ setAliasAttributes(D, GA);
}
llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,
@@ -2428,7 +2539,7 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
// Check for simple case.
if (!Literal->containsNonAsciiOrNull()) {
StringLength = NumBytes;
- return Map.GetOrCreateValue(String);
+ return *Map.insert(std::make_pair(String, nullptr)).first;
}
// Otherwise, convert the UTF8 literals into a string of shorts.
@@ -2447,9 +2558,10 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
// Add an explicit null.
*ToPtr = 0;
- return Map.
- GetOrCreateValue(StringRef(reinterpret_cast<const char *>(ToBuf.data()),
- (StringLength + 1) * 2));
+ return *Map.insert(std::make_pair(
+ StringRef(reinterpret_cast<const char *>(ToBuf.data()),
+ (StringLength + 1) * 2),
+ nullptr)).first;
}
static llvm::StringMapEntry<llvm::Constant*> &
@@ -2458,7 +2570,7 @@ GetConstantStringEntry(llvm::StringMap<llvm::Constant*> &Map,
unsigned &StringLength) {
StringRef String = Literal->getString();
StringLength = String.size();
- return Map.GetOrCreateValue(String);
+ return *Map.insert(std::make_pair(String, nullptr)).first;
}
llvm::Constant *
@@ -2470,7 +2582,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
getDataLayout().isLittleEndian(),
isUTF16, StringLength);
- if (llvm::Constant *C = Entry.getValue())
+ if (auto *C = Entry.second)
return C;
llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty);
@@ -2507,13 +2619,12 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
// String pointer.
llvm::Constant *C = nullptr;
if (isUTF16) {
- ArrayRef<uint16_t> Arr =
- llvm::makeArrayRef<uint16_t>(reinterpret_cast<uint16_t*>(
- const_cast<char *>(Entry.getKey().data())),
- Entry.getKey().size() / 2);
+ ArrayRef<uint16_t> Arr = llvm::makeArrayRef<uint16_t>(
+ reinterpret_cast<uint16_t *>(const_cast<char *>(Entry.first().data())),
+ Entry.first().size() / 2);
C = llvm::ConstantDataArray::get(VMContext, Arr);
} else {
- C = llvm::ConstantDataArray::getString(VMContext, Entry.getKey());
+ C = llvm::ConstantDataArray::getString(VMContext, Entry.first());
}
// Note: -fwritable-strings doesn't make the backing store strings of
@@ -2554,7 +2665,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::GlobalVariable::PrivateLinkage, C,
"_unnamed_cfstring_");
GV->setSection("__DATA,__cfstring");
- Entry.setValue(GV);
+ Entry.second = GV;
return GV;
}
@@ -2564,8 +2675,8 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
unsigned StringLength = 0;
llvm::StringMapEntry<llvm::Constant*> &Entry =
GetConstantStringEntry(CFConstantStringMap, Literal, StringLength);
-
- if (llvm::Constant *C = Entry.getValue())
+
+ if (auto *C = Entry.second)
return C;
llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty);
@@ -2638,8 +2749,8 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
// String pointer.
llvm::Constant *C =
- llvm::ConstantDataArray::getString(VMContext, Entry.getKey());
-
+ llvm::ConstantDataArray::getString(VMContext, Entry.first());
+
llvm::GlobalValue::LinkageTypes Linkage;
bool isConstant;
Linkage = llvm::GlobalValue::PrivateLinkage;
@@ -2670,8 +2781,8 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
GV->setSection(LangOpts.ObjCRuntime.isNonFragile()
? NSStringNonFragileABISection
: NSStringSection);
- Entry.setValue(GV);
-
+ Entry.second = GV;
+
return GV;
}
@@ -2769,7 +2880,8 @@ GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT,
/// GetAddrOfConstantStringFromLiteral - Return a pointer to a
/// constant array for the given string literal.
llvm::GlobalVariable *
-CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
+CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
+ StringRef Name) {
auto Alignment =
getContext().getAlignOfGlobalVarInChars(S->getType()).getQuantity();
@@ -2791,7 +2903,8 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
// Mangle the string literal if the ABI allows for it. However, we cannot
// do this if we are compiling with ASan or -fwritable-strings because they
// rely on strings having normal linkage.
- if (!LangOpts.WritableStrings && !LangOpts.Sanitize.Address &&
+ if (!LangOpts.WritableStrings &&
+ !LangOpts.Sanitize.has(SanitizerKind::Address) &&
getCXXABI().getMangleContext().shouldMangleStringLiteral(S)) {
llvm::raw_svector_ostream Out(MangledNameBuffer);
getCXXABI().getMangleContext().mangleStringLiteral(S, Out);
@@ -2801,14 +2914,15 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
GlobalVariableName = MangledNameBuffer;
} else {
LT = llvm::GlobalValue::PrivateLinkage;
- GlobalVariableName = ".str";
+ GlobalVariableName = Name;
}
auto GV = GenerateStringLiteral(C, LT, *this, GlobalVariableName, Alignment);
if (Entry)
*Entry = GV;
- reportGlobalToASan(GV, S->getStrTokenLoc(0), "<string literal>");
+ SanitizerMD->reportGlobalToASan(GV, S->getStrTokenLoc(0), "<string literal>",
+ QualType());
return GV;
}
@@ -2972,6 +3086,19 @@ static bool needsDestructMethod(ObjCImplementationDecl *impl) {
return false;
}
+static bool AllTrivialInitializers(CodeGenModule &CGM,
+ ObjCImplementationDecl *D) {
+ CodeGenFunction CGF(CGM);
+ for (ObjCImplementationDecl::init_iterator B = D->init_begin(),
+ E = D->init_end(); B != E; ++B) {
+ CXXCtorInitializer *CtorInitExp = *B;
+ Expr *Init = CtorInitExp->getInit();
+ if (!CGF.isTrivialInitializer(Init))
+ return false;
+ }
+ return true;
+}
+
/// EmitObjCIvarInitializations - Emit information for ivar initialization
/// for an implementation.
void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
@@ -2992,7 +3119,8 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
// If the implementation doesn't have any ivar initializers, we don't need
// a .cxx_construct.
- if (D->getNumIvarInitializers() == 0)
+ if (D->getNumIvarInitializers() == 0 ||
+ AllTrivialInitializers(*this, D))
return;
IdentifierInfo *II = &getContext().Idents.get(".cxx_construct");
@@ -3060,6 +3188,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
return;
EmitGlobal(cast<FunctionDecl>(D));
+ // Always provide some coverage mapping
+ // even for the functions that aren't emitted.
+ AddDeferredUnusedCoverageMapping(D);
break;
case Decl::Var:
@@ -3194,11 +3325,17 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
}
+ case Decl::OMPThreadPrivate:
+ EmitOMPThreadPrivateDecl(cast<OMPThreadPrivateDecl>(D));
+ break;
+
case Decl::ClassTemplateSpecialization: {
const auto *Spec = cast<ClassTemplateSpecializationDecl>(D);
if (DebugInfo &&
- Spec->getSpecializationKind() == TSK_ExplicitInstantiationDefinition)
+ Spec->getSpecializationKind() == TSK_ExplicitInstantiationDefinition &&
+ Spec->hasDefinition())
DebugInfo->completeTemplateDefinition(*Spec);
+ break;
}
default:
@@ -3206,6 +3343,91 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
// non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind
// function. Need to recode Decl::Kind to do that easily.
assert(isa<TypeDecl>(D) && "Unsupported decl kind");
+ break;
+ }
+}
+
+void CodeGenModule::AddDeferredUnusedCoverageMapping(Decl *D) {
+ // Do we need to generate coverage mapping?
+ if (!CodeGenOpts.CoverageMapping)
+ return;
+ switch (D->getKind()) {
+ case Decl::CXXConversion:
+ case Decl::CXXMethod:
+ case Decl::Function:
+ case Decl::ObjCMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor: {
+ if (!cast<FunctionDecl>(D)->hasBody())
+ return;
+ auto I = DeferredEmptyCoverageMappingDecls.find(D);
+ if (I == DeferredEmptyCoverageMappingDecls.end())
+ DeferredEmptyCoverageMappingDecls[D] = true;
+ break;
+ }
+ default:
+ break;
+ };
+}
+
+void CodeGenModule::ClearUnusedCoverageMapping(const Decl *D) {
+ // Do we need to generate coverage mapping?
+ if (!CodeGenOpts.CoverageMapping)
+ return;
+ if (const auto *Fn = dyn_cast<FunctionDecl>(D)) {
+ if (Fn->isTemplateInstantiation())
+ ClearUnusedCoverageMapping(Fn->getTemplateInstantiationPattern());
+ }
+ auto I = DeferredEmptyCoverageMappingDecls.find(D);
+ if (I == DeferredEmptyCoverageMappingDecls.end())
+ DeferredEmptyCoverageMappingDecls[D] = false;
+ else
+ I->second = false;
+}
+
+void CodeGenModule::EmitDeferredUnusedCoverageMappings() {
+ std::vector<const Decl *> DeferredDecls;
+ for (const auto I : DeferredEmptyCoverageMappingDecls) {
+ if (!I.second)
+ continue;
+ DeferredDecls.push_back(I.first);
+ }
+ // Sort the declarations by their location to make sure that the tests get a
+ // predictable order for the coverage mapping for the unused declarations.
+ if (CodeGenOpts.DumpCoverageMapping)
+ std::sort(DeferredDecls.begin(), DeferredDecls.end(),
+ [] (const Decl *LHS, const Decl *RHS) {
+ return LHS->getLocStart() < RHS->getLocStart();
+ });
+ for (const auto *D : DeferredDecls) {
+ switch (D->getKind()) {
+ case Decl::CXXConversion:
+ case Decl::CXXMethod:
+ case Decl::Function:
+ case Decl::ObjCMethod: {
+ CodeGenPGO PGO(*this);
+ GlobalDecl GD(cast<FunctionDecl>(D));
+ PGO.emitEmptyCounterMapping(D, getMangledName(GD),
+ getFunctionLinkage(GD));
+ break;
+ }
+ case Decl::CXXConstructor: {
+ CodeGenPGO PGO(*this);
+ GlobalDecl GD(cast<CXXConstructorDecl>(D), Ctor_Base);
+ PGO.emitEmptyCounterMapping(D, getMangledName(GD),
+ getFunctionLinkage(GD));
+ break;
+ }
+ case Decl::CXXDestructor: {
+ CodeGenPGO PGO(*this);
+ GlobalDecl GD(cast<CXXDestructorDecl>(D), Dtor_Base);
+ PGO.emitEmptyCounterMapping(D, getMangledName(GD),
+ getFunctionLinkage(GD));
+ break;
+ }
+ default:
+ break;
+ };
}
}
@@ -3226,10 +3448,9 @@ static void EmitGlobalDeclMetadata(CodeGenModule &CGM,
CGM.getModule().getOrInsertNamedMetadata("clang.global.decl.ptrs");
// TODO: should we report variant information for ctors/dtors?
- llvm::Value *Ops[] = {
- Addr,
- GetPointerConstant(CGM.getLLVMContext(), D.getDecl())
- };
+ llvm::Metadata *Ops[] = {llvm::ConstantAsMetadata::get(Addr),
+ llvm::ConstantAsMetadata::get(GetPointerConstant(
+ CGM.getLLVMContext(), D.getDecl()))};
GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops));
}
@@ -3292,7 +3513,9 @@ void CodeGenFunction::EmitDeclMetadata() {
llvm::Value *Addr = I.second;
if (auto *Alloca = dyn_cast<llvm::AllocaInst>(Addr)) {
llvm::Value *DAddr = GetPointerConstant(getLLVMContext(), D);
- Alloca->setMetadata(DeclPtrKind, llvm::MDNode::get(Context, DAddr));
+ Alloca->setMetadata(
+ DeclPtrKind, llvm::MDNode::get(
+ Context, llvm::ValueAsMetadata::getConstant(DAddr)));
} else if (auto *GV = dyn_cast<llvm::GlobalValue>(Addr)) {
GlobalDecl GD = GlobalDecl(cast<VarDecl>(D));
EmitGlobalDeclMetadata(CGM, GlobalMetadata, GD, GV);
@@ -3306,16 +3529,21 @@ void CodeGenModule::EmitVersionIdentMetadata() {
std::string Version = getClangFullVersion();
llvm::LLVMContext &Ctx = TheModule.getContext();
- llvm::Value *IdentNode[] = {
- llvm::MDString::get(Ctx, Version)
- };
+ llvm::Metadata *IdentNode[] = {llvm::MDString::get(Ctx, Version)};
IdentMetadata->addOperand(llvm::MDNode::get(Ctx, IdentNode));
}
void CodeGenModule::EmitTargetMetadata() {
- for (auto &I : MangledDeclNames) {
- const Decl *D = I.first.getDecl()->getMostRecentDecl();
- llvm::GlobalValue *GV = GetGlobalValue(I.second);
+ // Warning, new MangledDeclNames may be appended within this loop.
+ // We rely on MapVector insertions adding new elements to the end
+ // of the container.
+ // FIXME: Move this loop into the one target that needs it, and only
+ // loop over those declarations for which we couldn't emit the target
+ // metadata when we emitted the declaration.
+ for (unsigned I = 0; I != MangledDeclNames.size(); ++I) {
+ auto Val = *(MangledDeclNames.begin() + I);
+ const Decl *D = Val.first.getDecl()->getMostRecentDecl();
+ llvm::GlobalValue *GV = GetGlobalValue(Val.second);
getTargetCodeGenInfo().emitTargetMD(D, GV, *this);
}
}
@@ -3329,16 +3557,14 @@ void CodeGenModule::EmitCoverageFile() {
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);
+ llvm::Metadata *Elts[] = {CoverageFile, CU};
+ GCov->addOperand(llvm::MDNode::get(Ctx, Elts));
}
}
}
}
-llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid,
- QualType GuidType) {
+llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid) {
// Sema has checked that all uuid strings are of the form
// "12345678-1234-1234-1234-1234567890ab".
assert(Uuid.size() == 36);
@@ -3347,6 +3573,7 @@ llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid,
else assert(isHexDigit(Uuid[i]));
}
+ // The starts of all bytes of Field3 in Uuid. Field 3 is "1234-1234567890ab".
const unsigned Field3ValueOffsets[8] = { 19, 21, 24, 26, 28, 30, 32, 34 };
llvm::Constant *Field3[8];
@@ -3379,3 +3606,18 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
return getCXXABI().getAddrOfRTTIDescriptor(Ty);
}
+void CodeGenModule::EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) {
+ for (auto RefExpr : D->varlists()) {
+ auto *VD = cast<VarDecl>(cast<DeclRefExpr>(RefExpr)->getDecl());
+ bool PerformInit =
+ VD->getAnyInitializer() &&
+ !VD->getAnyInitializer()->isConstantInitializer(getContext(),
+ /*ForRef=*/false);
+ if (auto InitFunction =
+ getOpenMPRuntime().EmitOMPThreadPrivateVarDefinition(
+ VD, GetAddrOfGlobalVar(VD), RefExpr->getLocStart(),
+ PerformInit))
+ CXXGlobalInits.push_back(InitFunction);
+ }
+}
+
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 9533a8dabb20..54f3a82feb2d 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CODEGENMODULE_H
-#define CLANG_CODEGEN_CODEGENMODULE_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H
+#define LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H
#include "CGVTables.h"
#include "CodeGenTypes.h"
-#include "SanitizerBlacklist.h"
+#include "SanitizerMetadata.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -25,6 +25,7 @@
#include "clang/Basic/ABI.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
+#include "clang/Basic/SanitizerBlacklist.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -72,6 +73,7 @@ class DiagnosticsEngine;
class AnnotateAttr;
class CXXDestructorDecl;
class Module;
+class CoverageSourceInfo;
namespace CodeGen {
@@ -86,6 +88,7 @@ class CGOpenMPRuntime;
class CGCUDARuntime;
class BlockFieldFlags;
class FunctionArgList;
+class CoverageMappingModuleGen;
struct OrderGlobalInits {
unsigned int priority;
@@ -147,6 +150,8 @@ struct CodeGenTypeCache {
llvm::CallingConv::ID RuntimeCC;
llvm::CallingConv::ID getRuntimeCC() const { return RuntimeCC; }
+ llvm::CallingConv::ID BuiltinCC;
+ llvm::CallingConv::ID getBuiltinCC() const { return BuiltinCC; }
};
struct RREntrypoints {
@@ -256,6 +261,7 @@ class CodeGenModule : public CodeGenTypeCache {
CodeGenModule(const CodeGenModule &) LLVM_DELETED_FUNCTION;
void operator=(const CodeGenModule &) LLVM_DELETED_FUNCTION;
+public:
struct Structor {
Structor() : Priority(0), Initializer(nullptr), AssociatedData(nullptr) {}
Structor(int Priority, llvm::Constant *Initializer,
@@ -269,6 +275,7 @@ class CodeGenModule : public CodeGenTypeCache {
typedef std::vector<Structor> CtorList;
+private:
ASTContext &Context;
const LangOptions &LangOpts;
const CodeGenOptions &CodeGenOpts;
@@ -384,10 +391,11 @@ class CodeGenModule : public CodeGenTypeCache {
/// \brief thread_local variables with initializers that need to run
/// before any thread_local variable in this TU is odr-used.
- std::vector<llvm::Constant*> CXXThreadLocalInits;
+ std::vector<llvm::Function *> CXXThreadLocalInits;
+ std::vector<llvm::GlobalVariable *> CXXThreadLocalInitVars;
/// Global variables with initializers that need to run before main.
- std::vector<llvm::Constant*> CXXGlobalInits;
+ std::vector<llvm::Function *> CXXGlobalInits;
/// When a C++ decl with an initializer is deferred, null is
/// appended to CXXGlobalInits, and the index of that null is placed
@@ -415,7 +423,7 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::SetVector<clang::Module *> ImportedModules;
/// \brief A vector of metadata strings.
- SmallVector<llvm::Value *, 16> LinkerOptionsMetadata;
+ SmallVector<llvm::Metadata *, 16> LinkerOptionsMetadata;
/// @name Cache for Objective-C runtime types
/// @{
@@ -471,13 +479,18 @@ class CodeGenModule : public CodeGenTypeCache {
GlobalDecl initializedGlobalDecl;
- SanitizerBlacklist SanitizerBL;
+ std::unique_ptr<SanitizerMetadata> SanitizerMD;
/// @}
+
+ llvm::DenseMap<const Decl *, bool> DeferredEmptyCoverageMappingDecls;
+
+ std::unique_ptr<CoverageMappingModuleGen> CoverageMapping;
public:
CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
llvm::Module &M, const llvm::DataLayout &TD,
- DiagnosticsEngine &Diags);
+ DiagnosticsEngine &Diags,
+ CoverageSourceInfo *CoverageInfo = nullptr);
~CodeGenModule();
@@ -526,6 +539,10 @@ public:
InstrProfStats &getPGOStats() { return PGOStats; }
llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); }
+ CoverageMappingModuleGen *getCoverageMapping() const {
+ return CoverageMapping.get();
+ }
+
llvm::Constant *getStaticLocalDeclAddress(const VarDecl *D) {
return StaticLocalDeclMap[D];
}
@@ -534,6 +551,10 @@ public:
StaticLocalDeclMap[D] = C;
}
+ llvm::Constant *
+ getOrCreateStaticVarDecl(const VarDecl &D,
+ llvm::GlobalValue::LinkageTypes Linkage);
+
llvm::GlobalVariable *getStaticLocalDeclGuardAddress(const VarDecl *D) {
return StaticLocalDeclGuardMap[D];
}
@@ -572,9 +593,7 @@ public:
llvm::MDNode *getNoObjCARCExceptionsMetadata() {
if (!NoObjCARCExceptionsMetadata)
- NoObjCARCExceptionsMetadata =
- llvm::MDNode::get(getLLVMContext(),
- SmallVector<llvm::Value*,1>());
+ NoObjCARCExceptionsMetadata = llvm::MDNode::get(getLLVMContext(), None);
return NoObjCARCExceptionsMetadata;
}
@@ -585,6 +604,9 @@ public:
DiagnosticsEngine &getDiags() const { return Diags; }
const llvm::DataLayout &getDataLayout() const { return TheDataLayout; }
const TargetInfo &getTarget() const { return Target; }
+ const llvm::Triple &getTriple() const;
+ bool supportsCOMDAT() const;
+
CGCXXABI &getCXXABI() const { return *ABI; }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
@@ -604,6 +626,9 @@ public:
return VTables.getMicrosoftVTableContext();
}
+ CtorList &getGlobalCtors() { return GlobalCtors; }
+ CtorList &getGlobalDtors() { return GlobalDtors; }
+
llvm::MDNode *getTBAAInfo(QualType QTy);
llvm::MDNode *getTBAAInfoForVTablePtr();
llvm::MDNode *getTBAAStructInfo(QualType QTy);
@@ -632,9 +657,9 @@ public:
/// Set the visibility for the given LLVM GlobalValue.
void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const;
- /// Set the TLS mode for the given LLVM GlobalVariable for the thread-local
+ /// Set the TLS mode for the given LLVM GlobalValue for the thread-local
/// variable declaration D.
- void setTLSMode(llvm::GlobalVariable *GV, const VarDecl &D) const;
+ void setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const;
static llvm::GlobalValue::VisibilityTypes GetLLVMVisibility(Visibility V) {
switch (V) {
@@ -647,11 +672,11 @@ public:
llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) {
if (isa<CXXConstructorDecl>(GD.getDecl()))
- return GetAddrOfCXXConstructor(cast<CXXConstructorDecl>(GD.getDecl()),
- GD.getCtorType());
+ return getAddrOfCXXStructor(cast<CXXConstructorDecl>(GD.getDecl()),
+ getFromCtorType(GD.getCtorType()));
else if (isa<CXXDestructorDecl>(GD.getDecl()))
- return GetAddrOfCXXDestructor(cast<CXXDestructorDecl>(GD.getDecl()),
- GD.getDtorType());
+ return getAddrOfCXXStructor(cast<CXXDestructorDecl>(GD.getDecl()),
+ getFromDtorType(GD.getDtorType()));
else if (isa<FunctionDecl>(GD.getDecl()))
return GetAddrOfFunction(GD);
else
@@ -666,6 +691,11 @@ public:
CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty,
llvm::GlobalValue::LinkageTypes Linkage);
+ llvm::Function *
+ CreateGlobalInitOrDestructFunction(llvm::FunctionType *ty, const Twine &name,
+ SourceLocation Loc = SourceLocation(),
+ bool TLS = false);
+
/// Return the address space of the underlying global variable for D, as
/// determined by its declaration. Normally this is the same as the address
/// space of D's type, but in CUDA, address spaces are associated with
@@ -759,7 +789,8 @@ public:
/// Return a pointer to a constant array for the given string literal.
llvm::GlobalVariable *
- GetAddrOfConstantStringFromLiteral(const StringLiteral *S);
+ GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
+ StringRef Name = ".str");
/// Return a pointer to a constant array for the given ObjCEncodeExpr node.
llvm::GlobalVariable *
@@ -787,20 +818,19 @@ public:
/// \brief Retrieve the record type that describes the state of an
/// Objective-C fast enumeration loop (for..in).
QualType getObjCFastEnumerationStateType();
-
- /// Return the address of the constructor of the given type.
- llvm::GlobalValue *
- GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor, CXXCtorType ctorType,
- const CGFunctionInfo *fnInfo = nullptr,
- bool DontDefer = false);
- /// Return the address of the constructor of the given type.
+ // Produce code for this constructor/destructor. This method doesn't try
+ // to apply any ABI rules about which other constructors/destructors
+ // are needed or if they are alias to each other.
+ llvm::Function *codegenCXXStructor(const CXXMethodDecl *MD,
+ StructorType Type);
+
+ /// Return the address of the constructor/destructor of the given type.
llvm::GlobalValue *
- GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
- CXXDtorType dtorType,
- const CGFunctionInfo *fnInfo = nullptr,
- llvm::FunctionType *fnType = nullptr,
- bool DontDefer = false);
+ getAddrOfCXXStructor(const CXXMethodDecl *MD, StructorType Type,
+ const CGFunctionInfo *FnInfo = nullptr,
+ llvm::FunctionType *FnType = nullptr,
+ bool DontDefer = false);
/// Given a builtin id for a function like "__builtin_fabsf", return a
/// Function* for "fabsf".
@@ -812,6 +842,18 @@ public:
/// Emit code for a single top level declaration.
void EmitTopLevelDecl(Decl *D);
+ /// \brief Stored a deferred empty coverage mapping for an unused
+ /// and thus uninstrumented top level declaration.
+ void AddDeferredUnusedCoverageMapping(Decl *D);
+
+ /// \brief Remove the deferred empty coverage mapping as this
+ /// declaration is actually instrumented.
+ void ClearUnusedCoverageMapping(const Decl *D);
+
+ /// \brief Emit all the deferred coverage mappings
+ /// for the uninstrumented functions.
+ void EmitDeferredUnusedCoverageMappings();
+
/// Tell the consumer that this variable has been instantiated.
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD);
@@ -837,6 +879,11 @@ public:
StringRef Name,
llvm::AttributeSet ExtraAttrs =
llvm::AttributeSet());
+ /// Create a new compiler builtin function with the specified type and name.
+ llvm::Constant *CreateBuiltinFunction(llvm::FunctionType *Ty,
+ StringRef Name,
+ llvm::AttributeSet ExtraAttrs =
+ llvm::AttributeSet());
/// Create a new runtime global variable with the specified type and name.
llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
StringRef Name);
@@ -910,7 +957,7 @@ public:
llvm::Function *F);
/// Set the LLVM function attributes which only apply to a function
- /// definintion.
+ /// definition.
void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F);
/// Return true iff the given type uses 'sret' when used as a return type.
@@ -1009,18 +1056,15 @@ public:
/// annotations are emitted during finalization of the LLVM code.
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
- const SanitizerBlacklist &getSanitizerBlacklist() const {
- return SanitizerBL;
- }
+ bool isInSanitizerBlacklist(llvm::Function *Fn, SourceLocation Loc) const;
- void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D,
- bool IsDynInit = false);
- void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc,
- StringRef Name, bool IsDynInit = false,
- bool IsBlacklisted = false);
+ bool isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc,
+ QualType Ty,
+ StringRef Category = StringRef()) const;
- /// Disable sanitizer instrumentation for this global.
- void disableSanitizerForGlobal(llvm::GlobalVariable *GV);
+ SanitizerMetadata *getSanitizerMetadata() {
+ return SanitizerMD.get();
+ }
void addDeferredVTable(const CXXRecordDecl *RD) {
DeferredVTables.push_back(RD);
@@ -1030,34 +1074,50 @@ public:
/// are emitted lazily.
void EmitGlobal(GlobalDecl D);
-private:
+ bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target,
+ bool InEveryTU);
+ bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D);
+
+ /// Set attributes for a global definition.
+ void setFunctionDefinitionAttributes(const FunctionDecl *D,
+ llvm::Function *F);
+
llvm::GlobalValue *GetGlobalValue(StringRef Ref);
+ /// Set attributes which are common to any form of a global definition (alias,
+ /// Objective-C method, function, global variable).
+ ///
+ /// NOTE: This should only be called for definitions.
+ void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV);
+
+ /// Set attributes which must be preserved by an alias. This includes common
+ /// attributes (i.e. it includes a call to SetCommonAttributes).
+ ///
+ /// NOTE: This should only be called for definitions.
+ void setAliasAttributes(const Decl *D, llvm::GlobalValue *GV);
+
+ void addReplacement(StringRef Name, llvm::Constant *C);
+
+ /// \brief Emit a code for threadprivate directive.
+ /// \param D Threadprivate declaration.
+ void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);
+
+private:
llvm::Constant *
GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
bool ForVTable, bool DontDefer = false,
+ bool IsThunk = false,
llvm::AttributeSet ExtraAttrs = llvm::AttributeSet());
llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
llvm::PointerType *PTy,
const VarDecl *D);
- /// Set attributes which are common to any form of a global definition (alias,
- /// Objective-C method, function, global variable).
- ///
- /// NOTE: This should only be called for definitions.
- void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV);
-
void setNonAliasAttributes(const Decl *D, llvm::GlobalObject *GO);
- /// Set attributes for a global definition.
- void setFunctionDefinitionAttributes(const FunctionDecl *D,
- llvm::Function *F);
-
/// Set function attributes for a function declaration.
- void SetFunctionAttributes(GlobalDecl GD,
- llvm::Function *F,
- bool IsIncompleteFunction);
+ void SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
+ bool IsIncompleteFunction, bool IsThunk);
void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr);
@@ -1069,20 +1129,10 @@ private:
// C++ related functions.
- bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target,
- bool InEveryTU);
- bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D);
-
void EmitNamespace(const NamespaceDecl *D);
void EmitLinkageSpec(const LinkageSpecDecl *D);
void CompleteDIClassType(const CXXMethodDecl* D);
- /// Emit a single constructor with the given type from a C++ constructor Decl.
- void EmitCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type);
-
- /// Emit a single destructor with the given type from a C++ destructor Decl.
- void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type);
-
/// \brief Emit the function that initializes C++ thread_local variables.
void EmitCXXThreadLocalInitFunc();
@@ -1148,11 +1198,17 @@ private:
void EmitCoverageFile();
/// Emits the initializer for a uuidof string.
- llvm::Constant *EmitUuidofInitializer(StringRef uuidstr, QualType IIDType);
+ llvm::Constant *EmitUuidofInitializer(StringRef uuidstr);
+
+ /// Determine whether the definition must be emitted; if this returns \c
+ /// false, the definition can be emitted lazily if it's used.
+ bool MustBeEmitted(const ValueDecl *D);
- /// 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.
- bool MayDeferGeneration(const ValueDecl *D);
+ /// Determine whether the definition can be emitted eagerly, or should be
+ /// delayed until the end of the translation unit. This is relevant for
+ /// definitions whose linkage can change, e.g. implicit function instantions
+ /// which may later be explicitly instantiated.
+ bool MayBeEmittedEagerly(const ValueDecl *D);
/// Check whether we can use a "simpler", more core exceptions personality
/// function.
diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
index b233e3c7d75e..24b035d67598 100644
--- a/lib/CodeGen/CodeGenPGO.cpp
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -13,8 +13,10 @@
#include "CodeGenPGO.h"
#include "CodeGenFunction.h"
+#include "CoverageMappingGen.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/Endian.h"
@@ -24,8 +26,9 @@
using namespace clang;
using namespace CodeGen;
-void CodeGenPGO::setFuncName(llvm::Function *Fn) {
- RawFuncName = Fn->getName();
+void CodeGenPGO::setFuncName(StringRef Name,
+ llvm::GlobalValue::LinkageTypes Linkage) {
+ StringRef RawFuncName = Name;
// Function names may be prefixed with a binary '1' to indicate
// that the backend should not modify the symbols due to any platform
@@ -33,172 +36,44 @@ void CodeGenPGO::setFuncName(llvm::Function *Fn) {
if (RawFuncName[0] == '\1')
RawFuncName = RawFuncName.substr(1);
- if (!Fn->hasLocalLinkage()) {
- PrefixedFuncName.reset(new std::string(RawFuncName));
- return;
+ FuncName = RawFuncName;
+ if (llvm::GlobalValue::isLocalLinkage(Linkage)) {
+ // For local symbols, prepend the main file name to distinguish them.
+ // Do not include the full path in the file name since there's no guarantee
+ // that it will stay the same, e.g., if the files are checked out from
+ // version control in different locations.
+ if (CGM.getCodeGenOpts().MainFileName.empty())
+ FuncName = FuncName.insert(0, "<unknown>:");
+ else
+ FuncName = FuncName.insert(0, CGM.getCodeGenOpts().MainFileName + ":");
}
- // For local symbols, prepend the main file name to distinguish them.
- // Do not include the full path in the file name since there's no guarantee
- // that it will stay the same, e.g., if the files are checked out from
- // version control in different locations.
- PrefixedFuncName.reset(new std::string(CGM.getCodeGenOpts().MainFileName));
- if (PrefixedFuncName->empty())
- PrefixedFuncName->assign("<unknown>");
- PrefixedFuncName->append(":");
- PrefixedFuncName->append(RawFuncName);
-}
-
-static llvm::Function *getRegisterFunc(CodeGenModule &CGM) {
- return CGM.getModule().getFunction("__llvm_profile_register_functions");
-}
-
-static llvm::BasicBlock *getOrInsertRegisterBB(CodeGenModule &CGM) {
- // Don't do this for Darwin. compiler-rt uses linker magic.
- if (CGM.getTarget().getTriple().isOSDarwin())
- return nullptr;
-
- // Only need to insert this once per module.
- if (llvm::Function *RegisterF = getRegisterFunc(CGM))
- return &RegisterF->getEntryBlock();
-
- // Construct the function.
- auto *VoidTy = llvm::Type::getVoidTy(CGM.getLLVMContext());
- auto *RegisterFTy = llvm::FunctionType::get(VoidTy, false);
- auto *RegisterF = llvm::Function::Create(RegisterFTy,
- llvm::GlobalValue::InternalLinkage,
- "__llvm_profile_register_functions",
- &CGM.getModule());
- RegisterF->setUnnamedAddr(true);
- if (CGM.getCodeGenOpts().DisableRedZone)
- RegisterF->addFnAttr(llvm::Attribute::NoRedZone);
-
- // Construct and return the entry block.
- auto *BB = llvm::BasicBlock::Create(CGM.getLLVMContext(), "", RegisterF);
- CGBuilderTy Builder(BB);
- Builder.CreateRetVoid();
- return BB;
-}
-
-static llvm::Constant *getOrInsertRuntimeRegister(CodeGenModule &CGM) {
- auto *VoidTy = llvm::Type::getVoidTy(CGM.getLLVMContext());
- auto *VoidPtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- auto *RuntimeRegisterTy = llvm::FunctionType::get(VoidTy, VoidPtrTy, false);
- return CGM.getModule().getOrInsertFunction("__llvm_profile_register_function",
- RuntimeRegisterTy);
-}
-
-static bool isMachO(const CodeGenModule &CGM) {
- return CGM.getTarget().getTriple().isOSBinFormatMachO();
-}
-
-static StringRef getCountersSection(const CodeGenModule &CGM) {
- return isMachO(CGM) ? "__DATA,__llvm_prf_cnts" : "__llvm_prf_cnts";
-}
-
-static StringRef getNameSection(const CodeGenModule &CGM) {
- return isMachO(CGM) ? "__DATA,__llvm_prf_names" : "__llvm_prf_names";
+ // If we're generating a profile, create a variable for the name.
+ if (CGM.getCodeGenOpts().ProfileInstrGenerate)
+ createFuncNameVar(Linkage);
}
-static StringRef getDataSection(const CodeGenModule &CGM) {
- return isMachO(CGM) ? "__DATA,__llvm_prf_data" : "__llvm_prf_data";
-}
-
-llvm::GlobalVariable *CodeGenPGO::buildDataVar() {
- // Create name variable.
- llvm::LLVMContext &Ctx = CGM.getLLVMContext();
- auto *VarName = llvm::ConstantDataArray::getString(Ctx, getFuncName(),
- false);
- auto *Name = new llvm::GlobalVariable(CGM.getModule(), VarName->getType(),
- true, VarLinkage, VarName,
- getFuncVarName("name"));
- Name->setSection(getNameSection(CGM));
- Name->setAlignment(1);
-
- // Create data variable.
- auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
- auto *Int64Ty = llvm::Type::getInt64Ty(Ctx);
- auto *Int8PtrTy = llvm::Type::getInt8PtrTy(Ctx);
- auto *Int64PtrTy = llvm::Type::getInt64PtrTy(Ctx);
- llvm::Type *DataTypes[] = {
- Int32Ty, Int32Ty, Int64Ty, Int8PtrTy, Int64PtrTy
- };
- auto *DataTy = llvm::StructType::get(Ctx, makeArrayRef(DataTypes));
- llvm::Constant *DataVals[] = {
- llvm::ConstantInt::get(Int32Ty, getFuncName().size()),
- llvm::ConstantInt::get(Int32Ty, NumRegionCounters),
- llvm::ConstantInt::get(Int64Ty, FunctionHash),
- llvm::ConstantExpr::getBitCast(Name, Int8PtrTy),
- llvm::ConstantExpr::getBitCast(RegionCounters, Int64PtrTy)
- };
- auto *Data =
- new llvm::GlobalVariable(CGM.getModule(), DataTy, true, VarLinkage,
- llvm::ConstantStruct::get(DataTy, DataVals),
- getFuncVarName("data"));
-
- // All the data should be packed into an array in its own section.
- Data->setSection(getDataSection(CGM));
- Data->setAlignment(8);
-
- // Hide all these symbols so that we correctly get a copy for each
- // executable. The profile format expects names and counters to be
- // contiguous, so references into shared objects would be invalid.
- if (!llvm::GlobalValue::isLocalLinkage(VarLinkage)) {
- Name->setVisibility(llvm::GlobalValue::HiddenVisibility);
- Data->setVisibility(llvm::GlobalValue::HiddenVisibility);
- RegionCounters->setVisibility(llvm::GlobalValue::HiddenVisibility);
- }
-
- // Make sure the data doesn't get deleted.
- CGM.addUsedGlobal(Data);
- return Data;
+void CodeGenPGO::setFuncName(llvm::Function *Fn) {
+ setFuncName(Fn->getName(), Fn->getLinkage());
}
-void CodeGenPGO::emitInstrumentationData() {
- if (!RegionCounters)
- return;
-
- // Build the data.
- auto *Data = buildDataVar();
-
- // Register the data.
- auto *RegisterBB = getOrInsertRegisterBB(CGM);
- if (!RegisterBB)
- return;
- CGBuilderTy Builder(RegisterBB->getTerminator());
- auto *VoidPtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- Builder.CreateCall(getOrInsertRuntimeRegister(CGM),
- Builder.CreateBitCast(Data, VoidPtrTy));
-}
-
-llvm::Function *CodeGenPGO::emitInitialization(CodeGenModule &CGM) {
- if (!CGM.getCodeGenOpts().ProfileInstrGenerate)
- return nullptr;
-
- assert(CGM.getModule().getFunction("__llvm_profile_init") == nullptr &&
- "profile initialization already emitted");
-
- // Get the function to call at initialization.
- llvm::Constant *RegisterF = getRegisterFunc(CGM);
- if (!RegisterF)
- return nullptr;
-
- // Create the initialization function.
- auto *VoidTy = llvm::Type::getVoidTy(CGM.getLLVMContext());
- auto *F = llvm::Function::Create(llvm::FunctionType::get(VoidTy, false),
- llvm::GlobalValue::InternalLinkage,
- "__llvm_profile_init", &CGM.getModule());
- F->setUnnamedAddr(true);
- F->addFnAttr(llvm::Attribute::NoInline);
- if (CGM.getCodeGenOpts().DisableRedZone)
- F->addFnAttr(llvm::Attribute::NoRedZone);
-
- // Add the basic block and the necessary calls.
- CGBuilderTy Builder(llvm::BasicBlock::Create(CGM.getLLVMContext(), "", F));
- Builder.CreateCall(RegisterF);
- Builder.CreateRetVoid();
-
- return F;
+void CodeGenPGO::createFuncNameVar(llvm::GlobalValue::LinkageTypes Linkage) {
+ // Usually, we want to match the function's linkage, but
+ // available_externally and extern_weak both have the wrong semantics.
+ if (Linkage == llvm::GlobalValue::ExternalWeakLinkage)
+ Linkage = llvm::GlobalValue::LinkOnceAnyLinkage;
+ else if (Linkage == llvm::GlobalValue::AvailableExternallyLinkage)
+ Linkage = llvm::GlobalValue::LinkOnceODRLinkage;
+
+ auto *Value =
+ llvm::ConstantDataArray::getString(CGM.getLLVMContext(), FuncName, false);
+ FuncNameVar =
+ new llvm::GlobalVariable(CGM.getModule(), Value->getType(), true, Linkage,
+ Value, "__llvm_profile_name_" + FuncName);
+
+ // Hide the symbol so that we correctly get a copy for each executable.
+ if (!llvm::GlobalValue::isLocalLinkage(FuncNameVar->getLinkage()))
+ FuncNameVar->setVisibility(llvm::GlobalValue::HiddenVisibility);
}
namespace {
@@ -778,33 +653,18 @@ uint64_t PGOHash::finalize() {
return endian::read<uint64_t, little, unaligned>(Result);
}
-static void emitRuntimeHook(CodeGenModule &CGM) {
- const char *const RuntimeVarName = "__llvm_profile_runtime";
- const char *const RuntimeUserName = "__llvm_profile_runtime_user";
- if (CGM.getModule().getGlobalVariable(RuntimeVarName))
- return;
-
- // Declare the runtime hook.
- llvm::LLVMContext &Ctx = CGM.getLLVMContext();
- auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
- auto *Var = new llvm::GlobalVariable(CGM.getModule(), Int32Ty, false,
- llvm::GlobalValue::ExternalLinkage,
- nullptr, RuntimeVarName);
-
- // Make a function that uses it.
- auto *User = llvm::Function::Create(llvm::FunctionType::get(Int32Ty, false),
- llvm::GlobalValue::LinkOnceODRLinkage,
- RuntimeUserName, &CGM.getModule());
- User->addFnAttr(llvm::Attribute::NoInline);
- if (CGM.getCodeGenOpts().DisableRedZone)
- User->addFnAttr(llvm::Attribute::NoRedZone);
- CGBuilderTy Builder(llvm::BasicBlock::Create(CGM.getLLVMContext(), "", User));
- auto *Load = Builder.CreateLoad(Var);
- Builder.CreateRet(Load);
-
- // Create a use of the function. Now the definition of the runtime variable
- // should get pulled in, along with any static initializears.
- CGM.addUsedGlobal(User);
+void CodeGenPGO::checkGlobalDecl(GlobalDecl GD) {
+ // Make sure we only emit coverage mapping for one constructor/destructor.
+ // Clang emits several functions for the constructor and the destructor of
+ // a class. Every function is instrumented, but we only want to provide
+ // coverage for one of them. Because of that we only emit the coverage mapping
+ // for the base constructor/destructor.
+ if ((isa<CXXConstructorDecl>(GD.getDecl()) &&
+ GD.getCtorType() != Ctor_Base) ||
+ (isa<CXXDestructorDecl>(GD.getDecl()) &&
+ GD.getDtorType() != Dtor_Base)) {
+ SkipCoverageMapping = true;
+ }
}
void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) {
@@ -814,28 +674,12 @@ void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) {
return;
if (D->isImplicit())
return;
+ CGM.ClearUnusedCoverageMapping(D);
setFuncName(Fn);
- // Set the linkage for variables based on the function linkage. Usually, we
- // want to match it, but available_externally and extern_weak both have the
- // wrong semantics.
- VarLinkage = Fn->getLinkage();
- switch (VarLinkage) {
- case llvm::GlobalValue::ExternalWeakLinkage:
- VarLinkage = llvm::GlobalValue::LinkOnceAnyLinkage;
- break;
- case llvm::GlobalValue::AvailableExternallyLinkage:
- VarLinkage = llvm::GlobalValue::LinkOnceODRLinkage;
- break;
- default:
- break;
- }
-
mapRegionCounters(D);
- if (InstrumentRegions) {
- emitRuntimeHook(CGM);
- emitCounterVariables();
- }
+ if (CGM.getCodeGenOpts().CoverageMapping)
+ emitCounterRegionMapping(D);
if (PGOReader) {
SourceManager &SM = CGM.getContext().getSourceManager();
loadRegionCounts(PGOReader, SM.isInMainFile(D->getLocation()));
@@ -860,6 +704,56 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
FunctionHash = Walker.Hash.finalize();
}
+void CodeGenPGO::emitCounterRegionMapping(const Decl *D) {
+ if (SkipCoverageMapping)
+ return;
+ // Don't map the functions inside the system headers
+ auto Loc = D->getBody()->getLocStart();
+ if (CGM.getContext().getSourceManager().isInSystemHeader(Loc))
+ return;
+
+ std::string CoverageMapping;
+ llvm::raw_string_ostream OS(CoverageMapping);
+ CoverageMappingGen MappingGen(*CGM.getCoverageMapping(),
+ CGM.getContext().getSourceManager(),
+ CGM.getLangOpts(), RegionCounterMap.get());
+ MappingGen.emitCounterMapping(D, OS);
+ OS.flush();
+
+ if (CoverageMapping.empty())
+ return;
+
+ CGM.getCoverageMapping()->addFunctionMappingRecord(
+ FuncNameVar, FuncName, FunctionHash, CoverageMapping);
+}
+
+void
+CodeGenPGO::emitEmptyCounterMapping(const Decl *D, StringRef FuncName,
+ llvm::GlobalValue::LinkageTypes Linkage) {
+ if (SkipCoverageMapping)
+ return;
+ setFuncName(FuncName, Linkage);
+
+ // Don't map the functions inside the system headers
+ auto Loc = D->getBody()->getLocStart();
+ if (CGM.getContext().getSourceManager().isInSystemHeader(Loc))
+ return;
+
+ std::string CoverageMapping;
+ llvm::raw_string_ostream OS(CoverageMapping);
+ CoverageMappingGen MappingGen(*CGM.getCoverageMapping(),
+ CGM.getContext().getSourceManager(),
+ CGM.getLangOpts());
+ MappingGen.emitEmptyMapping(D, OS);
+ OS.flush();
+
+ if (CoverageMapping.empty())
+ return;
+
+ CGM.getCoverageMapping()->addFunctionMappingRecord(
+ FuncNameVar, FuncName, FunctionHash, CoverageMapping);
+}
+
void CodeGenPGO::computeRegionCounts(const Decl *D) {
StmtCountMap.reset(new llvm::DenseMap<const Stmt *, uint64_t>);
ComputeRegionCounts Walker(*StmtCountMap, *this);
@@ -891,50 +785,36 @@ CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
Fn->addFnAttr(llvm::Attribute::Cold);
}
-void CodeGenPGO::emitCounterVariables() {
- llvm::LLVMContext &Ctx = CGM.getLLVMContext();
- llvm::ArrayType *CounterTy = llvm::ArrayType::get(llvm::Type::getInt64Ty(Ctx),
- NumRegionCounters);
- RegionCounters =
- new llvm::GlobalVariable(CGM.getModule(), CounterTy, false, VarLinkage,
- llvm::Constant::getNullValue(CounterTy),
- getFuncVarName("counters"));
- RegionCounters->setAlignment(8);
- RegionCounters->setSection(getCountersSection(CGM));
-}
-
void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, unsigned Counter) {
- if (!RegionCounters)
+ if (!CGM.getCodeGenOpts().ProfileInstrGenerate || !RegionCounterMap)
return;
- llvm::Value *Addr =
- Builder.CreateConstInBoundsGEP2_64(RegionCounters, 0, Counter);
- llvm::Value *Count = Builder.CreateLoad(Addr, "pgocount");
- Count = Builder.CreateAdd(Count, Builder.getInt64(1));
- Builder.CreateStore(Count, Addr);
+ if (!Builder.GetInsertPoint())
+ return;
+ auto *I8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ Builder.CreateCall4(CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment),
+ llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
+ Builder.getInt64(FunctionHash),
+ Builder.getInt32(NumRegionCounters),
+ Builder.getInt32(Counter));
}
void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,
bool IsInMainFile) {
CGM.getPGOStats().addVisited(IsInMainFile);
- RegionCounts.reset(new std::vector<uint64_t>);
- uint64_t Hash;
- if (PGOReader->getFunctionCounts(getFuncName(), Hash, *RegionCounts)) {
- CGM.getPGOStats().addMissing(IsInMainFile);
- RegionCounts.reset();
- } else if (Hash != FunctionHash ||
- RegionCounts->size() != NumRegionCounters) {
- CGM.getPGOStats().addMismatched(IsInMainFile);
- RegionCounts.reset();
+ RegionCounts.clear();
+ if (std::error_code EC =
+ PGOReader->getFunctionCounts(FuncName, FunctionHash, RegionCounts)) {
+ if (EC == llvm::instrprof_error::unknown_function)
+ CGM.getPGOStats().addMissing(IsInMainFile);
+ else if (EC == llvm::instrprof_error::hash_mismatch)
+ CGM.getPGOStats().addMismatched(IsInMainFile);
+ else if (EC == llvm::instrprof_error::malformed)
+ // TODO: Consider a more specific warning for this case.
+ CGM.getPGOStats().addMismatched(IsInMainFile);
+ RegionCounts.clear();
}
}
-void CodeGenPGO::destroyRegionCounters() {
- RegionCounterMap.reset();
- StmtCountMap.reset();
- RegionCounts.reset();
- RegionCounters = nullptr;
-}
-
/// \brief Calculate what to divide by to scale weights.
///
/// Given the maximum weight, calculate a divisor that will scale all the
diff --git a/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h
index 2f4aa660bea3..431c850ef81e 100644
--- a/lib/CodeGen/CodeGenPGO.h
+++ b/lib/CodeGen/CodeGenPGO.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CODEGENPGO_H
-#define CLANG_CODEGEN_CODEGENPGO_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENPGO_H
+#define LLVM_CLANG_LIB_CODEGEN_CODEGENPGO_H
#include "CGBuilder.h"
#include "CodeGenModule.h"
@@ -31,34 +31,28 @@ class RegionCounter;
class CodeGenPGO {
private:
CodeGenModule &CGM;
- std::unique_ptr<std::string> PrefixedFuncName;
- StringRef RawFuncName;
- llvm::GlobalValue::LinkageTypes VarLinkage;
+ std::string FuncName;
+ llvm::GlobalVariable *FuncNameVar;
unsigned NumRegionCounters;
uint64_t FunctionHash;
- llvm::GlobalVariable *RegionCounters;
std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionCounterMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, uint64_t>> StmtCountMap;
- std::unique_ptr<std::vector<uint64_t>> RegionCounts;
+ std::vector<uint64_t> RegionCounts;
uint64_t CurrentRegionCount;
+ /// \brief A flag that is set to true when this function doesn't need
+ /// to have coverage mapping data.
+ bool SkipCoverageMapping;
public:
CodeGenPGO(CodeGenModule &CGM)
- : CGM(CGM), NumRegionCounters(0), FunctionHash(0),
- RegionCounters(nullptr), CurrentRegionCount(0) {}
+ : CGM(CGM), NumRegionCounters(0), FunctionHash(0), CurrentRegionCount(0),
+ SkipCoverageMapping(false) {}
/// Whether or not we have PGO region data for the current function. This is
/// false both when we have no data at all and when our data has been
/// discarded.
- bool haveRegionCounts() const { return RegionCounts != nullptr; }
-
- /// Get the string used to identify this function in the profile data.
- /// For functions with local linkage, this includes the main file name.
- StringRef getFuncName() const { return StringRef(*PrefixedFuncName); }
- std::string getFuncVarName(StringRef VarName) const {
- return ("__llvm_profile_" + VarName + "_" + RawFuncName).str();
- }
+ bool haveRegionCounts() const { return !RegionCounts.empty(); }
/// Return the counter value of the current region.
uint64_t getCurrentRegionCount() const { return CurrentRegionCount; }
@@ -99,21 +93,21 @@ public:
llvm::MDNode *createBranchWeights(ArrayRef<uint64_t> Weights);
llvm::MDNode *createLoopWeights(const Stmt *Cond, RegionCounter &Cnt);
+ /// Check if we need to emit coverage mapping for a given declaration
+ void checkGlobalDecl(GlobalDecl GD);
/// Assign counters to regions and configure them for PGO of a given
/// function. Does nothing if instrumentation is not enabled and either
/// generates global variables or associates PGO data with each of the
/// counters depending on whether we are generating or using instrumentation.
void assignRegionCounters(const Decl *D, llvm::Function *Fn);
- /// Emit static data structures for instrumentation data.
- void emitInstrumentationData();
- /// Clean up region counter state. Must be called if assignRegionCounters is
- /// used.
- void destroyRegionCounters();
- /// Emit static initialization code, if any.
- static llvm::Function *emitInitialization(CodeGenModule &CGM);
-
+ /// Emit a coverage mapping range with a counter zero
+ /// for an unused declaration.
+ void emitEmptyCounterMapping(const Decl *D, StringRef FuncName,
+ llvm::GlobalValue::LinkageTypes Linkage);
private:
void setFuncName(llvm::Function *Fn);
+ void setFuncName(StringRef Name, llvm::GlobalValue::LinkageTypes Linkage);
+ void createFuncNameVar(llvm::GlobalValue::LinkageTypes Linkage);
void mapRegionCounters(const Decl *D);
void computeRegionCounts(const Decl *D);
void applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
@@ -121,7 +115,7 @@ private:
void loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,
bool IsInMainFile);
void emitCounterVariables();
- llvm::GlobalVariable *buildDataVar();
+ void emitCounterRegionMapping(const Decl *D);
/// Emit code to increment the counter at the given index
void emitCounterIncrement(CGBuilderTy &Builder, unsigned Counter);
@@ -138,7 +132,7 @@ private:
uint64_t getRegionCount(unsigned Counter) {
if (!haveRegionCounts())
return 0;
- return (*RegionCounts)[Counter];
+ return RegionCounts[Counter];
}
friend class RegionCounter;
diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h
index 0ad4be24fd24..632caddce980 100644
--- a/lib/CodeGen/CodeGenTBAA.h
+++ b/lib/CodeGen/CodeGenTBAA.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CODEGENTBAA_H
-#define CLANG_CODEGEN_CODEGENTBAA_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTBAA_H
+#define LLVM_CLANG_LIB_CODEGEN_CODEGENTBAA_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index d4e22623e029..67a9fbec2690 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -81,7 +81,7 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
/// ConvertType in that it is used to convert to the memory representation for
/// a type. For example, the scalar representation for _Bool is i1, but the
/// memory representation is usually i8 or i32, depending on the target.
-llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T){
+llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
llvm::Type *R = ConvertType(T);
// If this is a non-bool type, don't map it.
@@ -115,8 +115,9 @@ isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT,
llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked) {
// If we have already checked this type (maybe the same type is used by-value
// multiple times in multiple structure fields, don't check again.
- if (!AlreadyChecked.insert(RD)) return true;
-
+ if (!AlreadyChecked.insert(RD).second)
+ return true;
+
const Type *Key = CGT.getContext().getTagDeclType(RD).getTypePtr();
// If this type is already laid out, converting it is a noop.
@@ -187,6 +188,11 @@ static bool isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT) {
/// we've temporarily deferred expanding the type because we're in a recursive
/// context.
bool CodeGenTypes::isFuncParamTypeConvertible(QualType Ty) {
+ // Some ABIs cannot have their member pointers represented in IR unless
+ // certain circumstances have been reached.
+ if (const auto *MPT = Ty->getAs<MemberPointerType>())
+ return getCXXABI().isMemberPointerConvertible(MPT);
+
// If this isn't a tagged type, we can convert it!
const TagType *TT = Ty->getAs<TagType>();
if (!TT) return true;
@@ -194,7 +200,7 @@ bool CodeGenTypes::isFuncParamTypeConvertible(QualType Ty) {
// Incomplete types cannot be converted.
if (TT->isIncompleteType())
return false;
-
+
// If this is an enum, then it is always safe to convert.
const RecordType *RT = dyn_cast<RecordType>(TT);
if (!RT) return true;
@@ -353,9 +359,10 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
case BuiltinType::Half:
// Half FP can either be storage-only (lowered to i16) or native.
- ResultType = getTypeForFormat(getLLVMContext(),
- Context.getFloatTypeSemantics(T),
- Context.getLangOpts().NativeHalfType);
+ ResultType =
+ getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T),
+ Context.getLangOpts().NativeHalfType ||
+ Context.getLangOpts().HalfArgsAndReturns);
break;
case BuiltinType::Float:
case BuiltinType::Double:
@@ -399,7 +406,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
llvm_unreachable("Unexpected undeduced auto type!");
case Type::Complex: {
llvm::Type *EltTy = ConvertType(cast<ComplexType>(Ty)->getElementType());
- ResultType = llvm::StructType::get(EltTy, EltTy, NULL);
+ ResultType = llvm::StructType::get(EltTy, EltTy, nullptr);
break;
}
case Type::LValueReference:
@@ -494,7 +501,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// While we're converting the parameter types for a function, we don't want
// to recursively convert any pointed-to structs. Converting directly-used
// structs is ok though.
- if (!RecordsBeingLaidOut.insert(Ty)) {
+ if (!RecordsBeingLaidOut.insert(Ty).second) {
ResultType = llvm::StructType::get(getLLVMContext());
SkippedLayout = true;
@@ -581,6 +588,8 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
case Type::MemberPointer: {
+ if (!getCXXABI().isMemberPointerConvertible(cast<MemberPointerType>(Ty)))
+ return llvm::StructType::create(getLLVMContext());
ResultType =
getCXXABI().ConvertMemberPointerType(cast<MemberPointerType>(Ty));
break;
@@ -648,7 +657,8 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
}
// Okay, this is a definition of a type. Compile the implementation now.
- bool InsertResult = RecordsBeingLaidOut.insert(Key); (void)InsertResult;
+ bool InsertResult = RecordsBeingLaidOut.insert(Key).second;
+ (void)InsertResult;
assert(InsertResult && "Recursively compiling a struct?");
// Force conversion of non-virtual base classes recursively.
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index fe155b53b3c4..64c5799ccec9 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_CODEGENTYPES_H
-#define CLANG_CODEGEN_CODEGENTYPES_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H
+#define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H
#include "CGCall.h"
#include "clang/AST/GlobalDecl.h"
@@ -22,39 +22,95 @@
#include <vector>
namespace llvm {
- class FunctionType;
- class Module;
- class DataLayout;
- class Type;
- class LLVMContext;
- class StructType;
+class FunctionType;
+class Module;
+class DataLayout;
+class Type;
+class LLVMContext;
+class StructType;
}
namespace clang {
- class ABIInfo;
- class ASTContext;
- template <typename> class CanQual;
- class CXXConstructorDecl;
- class CXXDestructorDecl;
- class CXXMethodDecl;
- class CodeGenOptions;
- class FieldDecl;
- class FunctionProtoType;
- class ObjCInterfaceDecl;
- class ObjCIvarDecl;
- class PointerType;
- class QualType;
- class RecordDecl;
- class TagDecl;
- class TargetInfo;
- class Type;
- typedef CanQual<Type> CanQualType;
+class ABIInfo;
+class ASTContext;
+template <typename> class CanQual;
+class CXXConstructorDecl;
+class CXXDestructorDecl;
+class CXXMethodDecl;
+class CodeGenOptions;
+class FieldDecl;
+class FunctionProtoType;
+class ObjCInterfaceDecl;
+class ObjCIvarDecl;
+class PointerType;
+class QualType;
+class RecordDecl;
+class TagDecl;
+class TargetInfo;
+class Type;
+typedef CanQual<Type> CanQualType;
namespace CodeGen {
- class CGCXXABI;
- class CGRecordLayout;
- class CodeGenModule;
- class RequiredArgs;
+class CGCXXABI;
+class CGRecordLayout;
+class CodeGenModule;
+class RequiredArgs;
+
+enum class StructorType {
+ Complete, // constructor or destructor
+ Base, // constructor or destructor
+ Deleting // destructor only
+};
+
+inline CXXCtorType toCXXCtorType(StructorType T) {
+ switch (T) {
+ case StructorType::Complete:
+ return Ctor_Complete;
+ case StructorType::Base:
+ return Ctor_Base;
+ case StructorType::Deleting:
+ llvm_unreachable("cannot have a deleting ctor");
+ }
+ llvm_unreachable("not a StructorType");
+}
+
+inline StructorType getFromCtorType(CXXCtorType T) {
+ switch (T) {
+ case Ctor_Complete:
+ return StructorType::Complete;
+ case Ctor_Base:
+ return StructorType::Base;
+ case Ctor_Comdat:
+ llvm_unreachable("not expecting a COMDAT");
+ }
+ llvm_unreachable("not a CXXCtorType");
+}
+
+inline CXXDtorType toCXXDtorType(StructorType T) {
+ switch (T) {
+ case StructorType::Complete:
+ return Dtor_Complete;
+ case StructorType::Base:
+ return Dtor_Base;
+ case StructorType::Deleting:
+ return Dtor_Deleting;
+ }
+ llvm_unreachable("not a StructorType");
+}
+
+inline StructorType getFromDtorType(CXXDtorType T) {
+ switch (T) {
+ case Dtor_Deleting:
+ return StructorType::Deleting;
+ case Dtor_Complete:
+ return StructorType::Complete;
+ case Dtor_Base:
+ return StructorType::Base;
+ case Dtor_Comdat:
+ llvm_unreachable("not expecting a COMDAT");
+ }
+ llvm_unreachable("not a CXXDtorType");
+}
/// CodeGenTypes - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
@@ -185,18 +241,15 @@ public:
QualType receiverType);
const CGFunctionInfo &arrangeCXXMethodDeclaration(const CXXMethodDecl *MD);
- const CGFunctionInfo &arrangeCXXConstructorDeclaration(
- const CXXConstructorDecl *D,
- CXXCtorType Type);
+ const CGFunctionInfo &arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
+ StructorType Type);
const CGFunctionInfo &arrangeCXXConstructorCall(const CallArgList &Args,
const CXXConstructorDecl *D,
CXXCtorType CtorKind,
unsigned ExtraArgs);
- const CGFunctionInfo &arrangeCXXDestructor(const CXXDestructorDecl *D,
- CXXDtorType Type);
-
const CGFunctionInfo &arrangeFreeFunctionCall(const CallArgList &Args,
- const FunctionType *Ty);
+ const FunctionType *Ty,
+ bool ChainCall);
const CGFunctionInfo &arrangeFreeFunctionCall(QualType ResTy,
const CallArgList &args,
FunctionType::ExtInfo info,
@@ -207,6 +260,7 @@ public:
const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,
const FunctionProtoType *type,
RequiredArgs required);
+ const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD);
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty);
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionNoProtoType> Ty);
@@ -220,7 +274,8 @@ public:
///
/// \param argTypes - must all actually be canonical as params
const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType,
- bool IsInstanceMethod,
+ bool instanceMethod,
+ bool chainCall,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs args);
@@ -239,11 +294,10 @@ public: // These are internal details of CGT that shouldn't be used externally.
/// ConvertRecordDeclType - Lay out a tagged decl type like struct or union.
llvm::StructType *ConvertRecordDeclType(const RecordDecl *TD);
- /// 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 type,
- SmallVectorImpl<llvm::Type*> &expanded);
+ /// getExpandedTypes - Expand the type \arg Ty into the LLVM
+ /// argument types it would be passed as. See ABIArgInfo::Expand.
+ void getExpandedTypes(QualType Ty,
+ SmallVectorImpl<llvm::Type *>::iterator &TI);
/// IsZeroInitializable - Return whether a type can be
/// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp
new file mode 100644
index 000000000000..6f159d47375e
--- /dev/null
+++ b/lib/CodeGen/CoverageMappingGen.cpp
@@ -0,0 +1,1174 @@
+//===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Instrumentation-based code coverage mapping generator
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageMappingGen.h"
+#include "CodeGenFunction.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/ProfileData/CoverageMappingReader.h"
+#include "llvm/ProfileData/CoverageMappingWriter.h"
+#include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/Support/FileSystem.h"
+
+using namespace clang;
+using namespace CodeGen;
+using namespace llvm::coverage;
+
+void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range) {
+ SkippedRanges.push_back(Range);
+}
+
+namespace {
+
+/// \brief A region of source code that can be mapped to a counter.
+class SourceMappingRegion {
+public:
+ enum RegionFlags {
+ /// \brief This region won't be emitted if it wasn't extended.
+ /// This is useful so that we won't emit source ranges for single tokens
+ /// that we don't really care that much about, like:
+ /// the '(' token in #define MACRO (
+ IgnoreIfNotExtended = 0x0001,
+ };
+
+private:
+ FileID File, MacroArgumentFile;
+
+ Counter Count;
+
+ /// \brief A statement that initiated the count of Zero.
+ ///
+ /// This initiator statement is useful to prevent merging of unreachable
+ /// regions with different statements that caused the counter to become
+ /// unreachable.
+ const Stmt *UnreachableInitiator;
+
+ /// \brief A statement that separates certain mapping regions into groups.
+ ///
+ /// The group statement is sometimes useful when we are emitting the source
+ /// regions not in their correct lexical order, e.g. the regions for the
+ /// incrementation expression in the 'for' construct. By marking the regions
+ /// in the incrementation expression with the group statement, we avoid the
+ /// merging of the regions from the incrementation expression and the loop's
+ /// body.
+ const Stmt *Group;
+
+ /// \brief The region's starting location.
+ SourceLocation LocStart;
+
+ /// \brief The region's ending location.
+ SourceLocation LocEnd, AlternativeLocEnd;
+ unsigned Flags;
+
+public:
+ SourceMappingRegion(FileID File, FileID MacroArgumentFile, Counter Count,
+ const Stmt *UnreachableInitiator, const Stmt *Group,
+ SourceLocation LocStart, SourceLocation LocEnd,
+ unsigned Flags = 0)
+ : File(File), MacroArgumentFile(MacroArgumentFile), Count(Count),
+ UnreachableInitiator(UnreachableInitiator), Group(Group),
+ LocStart(LocStart), LocEnd(LocEnd), AlternativeLocEnd(LocStart),
+ Flags(Flags) {}
+
+ const FileID &getFile() const { return File; }
+
+ const Counter &getCounter() const { return Count; }
+
+ const SourceLocation &getStartLoc() const { return LocStart; }
+
+ const SourceLocation &getEndLoc(const SourceManager &SM) const {
+ if (SM.getFileID(LocEnd) != File)
+ return AlternativeLocEnd;
+ return LocEnd;
+ }
+
+ bool hasFlag(RegionFlags Flag) const { return (Flags & Flag) != 0; }
+
+ void setFlag(RegionFlags Flag) { Flags |= Flag; }
+
+ void clearFlag(RegionFlags Flag) { Flags &= ~Flag; }
+
+ /// \brief Return true if two regions can be merged together.
+ bool isMergeable(SourceMappingRegion &R) {
+ // FIXME: We allow merging regions with a gap in between them. Should we?
+ return File == R.File && MacroArgumentFile == R.MacroArgumentFile &&
+ Count == R.Count && UnreachableInitiator == R.UnreachableInitiator &&
+ Group == R.Group;
+ }
+
+ /// \brief A comparison that sorts such that mergeable regions are adjacent.
+ friend bool operator<(const SourceMappingRegion &LHS,
+ const SourceMappingRegion &RHS) {
+ return std::tie(LHS.File, LHS.MacroArgumentFile, LHS.Count,
+ LHS.UnreachableInitiator, LHS.Group) <
+ std::tie(RHS.File, RHS.MacroArgumentFile, RHS.Count,
+ RHS.UnreachableInitiator, RHS.Group);
+ }
+};
+
+/// \brief Provides the common functionality for the different
+/// coverage mapping region builders.
+class CoverageMappingBuilder {
+public:
+ CoverageMappingModuleGen &CVM;
+ SourceManager &SM;
+ const LangOptions &LangOpts;
+
+private:
+ struct FileInfo {
+ /// \brief The file id that will be used by the coverage mapping system.
+ unsigned CovMappingFileID;
+ const FileEntry *Entry;
+
+ FileInfo(unsigned CovMappingFileID, const FileEntry *Entry)
+ : CovMappingFileID(CovMappingFileID), Entry(Entry) {}
+ };
+
+ /// \brief This mapping maps clang's FileIDs to file ids used
+ /// by the coverage mapping system and clang's file entries.
+ llvm::SmallDenseMap<FileID, FileInfo, 8> FileIDMapping;
+
+public:
+ /// \brief The statement that corresponds to the current source group.
+ const Stmt *CurrentSourceGroup;
+
+ /// \brief The statement the initiated the current unreachable region.
+ const Stmt *CurrentUnreachableRegionInitiator;
+
+ /// \brief The coverage mapping regions for this function
+ llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
+ /// \brief The source mapping regions for this function.
+ std::vector<SourceMappingRegion> SourceRegions;
+
+ CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
+ const LangOptions &LangOpts)
+ : CVM(CVM), SM(SM), LangOpts(LangOpts),
+ CurrentSourceGroup(nullptr),
+ CurrentUnreachableRegionInitiator(nullptr) {}
+
+ /// \brief Return the precise end location for the given token.
+ SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
+ return Lexer::getLocForEndOfToken(SM.getSpellingLoc(Loc), 0, SM, LangOpts);
+ }
+
+ /// \brief Create the mapping that maps from the function's file ids to
+ /// the indices for the translation unit's filenames.
+ void createFileIDMapping(SmallVectorImpl<unsigned> &Mapping) {
+ Mapping.resize(FileIDMapping.size(), 0);
+ for (const auto &I : FileIDMapping)
+ Mapping[I.second.CovMappingFileID] = CVM.getFileID(I.second.Entry);
+ }
+
+ /// \brief Get the coverage mapping file id that corresponds to the given
+ /// clang file id. If such file id doesn't exist, it gets added to the
+ /// mapping that maps from clang's file ids to coverage mapping file ids.
+ /// Return true if there was an error getting the coverage mapping file id.
+ /// An example of an when this function fails is when the region tries
+ /// to get a coverage file id for a location in a built-in macro.
+ bool getCoverageFileID(SourceLocation LocStart, FileID File,
+ FileID SpellingFile, unsigned &Result) {
+ auto Mapping = FileIDMapping.find(File);
+ if (Mapping != FileIDMapping.end()) {
+ Result = Mapping->second.CovMappingFileID;
+ return false;
+ }
+
+ auto Entry = SM.getFileEntryForID(SpellingFile);
+ if (!Entry)
+ return true;
+
+ Result = FileIDMapping.size();
+ FileIDMapping.insert(std::make_pair(File, FileInfo(Result, Entry)));
+ createFileExpansionRegion(LocStart, File);
+ return false;
+ }
+
+ /// \brief Get the coverage mapping file id that corresponds to the given
+ /// clang file id.
+ /// Return true if there was an error getting the coverage mapping file id.
+ bool getExistingCoverageFileID(FileID File, unsigned &Result) {
+ // Make sure that the file is valid.
+ if (File.isInvalid())
+ return true;
+ auto Mapping = FileIDMapping.find(File);
+ if (Mapping != FileIDMapping.end()) {
+ Result = Mapping->second.CovMappingFileID;
+ return false;
+ }
+ return true;
+ }
+
+ /// \brief Return true if the given clang's file id has a corresponding
+ /// coverage file id.
+ bool hasExistingCoverageFileID(FileID File) const {
+ return FileIDMapping.count(File);
+ }
+
+ /// \brief Gather all the regions that were skipped by the preprocessor
+ /// using the constructs like #if.
+ void gatherSkippedRegions() {
+ /// An array of the minimum lineStarts and the maximum lineEnds
+ /// for mapping regions from the appropriate source files.
+ llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
+ FileLineRanges.resize(
+ FileIDMapping.size(),
+ std::make_pair(std::numeric_limits<unsigned>::max(), 0));
+ for (const auto &R : MappingRegions) {
+ FileLineRanges[R.FileID].first =
+ std::min(FileLineRanges[R.FileID].first, R.LineStart);
+ FileLineRanges[R.FileID].second =
+ std::max(FileLineRanges[R.FileID].second, R.LineEnd);
+ }
+
+ auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
+ for (const auto &I : SkippedRanges) {
+ auto LocStart = I.getBegin();
+ auto LocEnd = I.getEnd();
+ auto FileStart = SM.getFileID(LocStart);
+ if (!hasExistingCoverageFileID(FileStart))
+ continue;
+ auto ActualFileStart = SM.getDecomposedSpellingLoc(LocStart).first;
+ if (ActualFileStart != SM.getDecomposedSpellingLoc(LocEnd).first)
+ // Ignore regions that span across multiple files.
+ continue;
+
+ unsigned CovFileID;
+ if (getCoverageFileID(LocStart, FileStart, ActualFileStart, CovFileID))
+ continue;
+ unsigned LineStart = SM.getSpellingLineNumber(LocStart);
+ unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart);
+ unsigned LineEnd = SM.getSpellingLineNumber(LocEnd);
+ unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
+ CounterMappingRegion Region(Counter(), CovFileID, LineStart, ColumnStart,
+ LineEnd, ColumnEnd, false,
+ CounterMappingRegion::SkippedRegion);
+ // Make sure that we only collect the regions that are inside
+ // the souce code of this function.
+ if (Region.LineStart >= FileLineRanges[CovFileID].first &&
+ Region.LineEnd <= FileLineRanges[CovFileID].second)
+ MappingRegions.push_back(Region);
+ }
+ }
+
+ /// \brief Create a mapping region that correponds to an expansion of
+ /// a macro or an embedded include.
+ void createFileExpansionRegion(SourceLocation Loc, FileID ExpandedFile) {
+ SourceLocation LocStart;
+ if (Loc.isMacroID())
+ LocStart = SM.getImmediateExpansionRange(Loc).first;
+ else {
+ LocStart = SM.getIncludeLoc(ExpandedFile);
+ if (LocStart.isInvalid())
+ return; // This file has no expansion region.
+ }
+
+ auto File = SM.getFileID(LocStart);
+ auto SpellingFile = SM.getDecomposedSpellingLoc(LocStart).first;
+ unsigned CovFileID, ExpandedFileID;
+ if (getExistingCoverageFileID(ExpandedFile, ExpandedFileID))
+ return;
+ if (getCoverageFileID(LocStart, File, SpellingFile, CovFileID))
+ return;
+ unsigned LineStart = SM.getSpellingLineNumber(LocStart);
+ unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart);
+ unsigned LineEnd = LineStart;
+ // Compute the end column manually as Lexer::getLocForEndOfToken doesn't
+ // give the correct result in all cases.
+ unsigned ColumnEnd =
+ ColumnStart +
+ Lexer::MeasureTokenLength(SM.getSpellingLoc(LocStart), SM, LangOpts);
+
+ MappingRegions.push_back(CounterMappingRegion(
+ Counter(), CovFileID, LineStart, ColumnStart, LineEnd, ColumnEnd,
+ false, CounterMappingRegion::ExpansionRegion));
+ MappingRegions.back().ExpandedFileID = ExpandedFileID;
+ }
+
+ /// \brief Enter a source region group that is identified by the given
+ /// statement.
+ /// It's not possible to enter a group when there is already
+ /// another group present.
+ void beginSourceRegionGroup(const Stmt *Group) {
+ assert(!CurrentSourceGroup);
+ CurrentSourceGroup = Group;
+ }
+
+ /// \brief Exit the current source region group.
+ void endSourceRegionGroup() { CurrentSourceGroup = nullptr; }
+
+ /// \brief Associate a counter with a given source code range.
+ void mapSourceCodeRange(SourceLocation LocStart, SourceLocation LocEnd,
+ Counter Count, const Stmt *UnreachableInitiator,
+ const Stmt *SourceGroup, unsigned Flags = 0,
+ FileID MacroArgumentFile = FileID()) {
+ if (SM.isMacroArgExpansion(LocStart)) {
+ // Map the code range with the macro argument's value.
+ mapSourceCodeRange(SM.getImmediateSpellingLoc(LocStart),
+ SM.getImmediateSpellingLoc(LocEnd), Count,
+ UnreachableInitiator, SourceGroup, Flags,
+ SM.getFileID(LocStart));
+ // Map the code range where the macro argument is referenced.
+ SourceLocation RefLocStart(SM.getImmediateExpansionRange(LocStart).first);
+ SourceLocation RefLocEnd(RefLocStart);
+ if (SM.isMacroArgExpansion(RefLocStart))
+ mapSourceCodeRange(RefLocStart, RefLocEnd, Count, UnreachableInitiator,
+ SourceGroup, 0, SM.getFileID(RefLocStart));
+ else
+ mapSourceCodeRange(RefLocStart, RefLocEnd, Count, UnreachableInitiator,
+ SourceGroup);
+ return;
+ }
+ auto File = SM.getFileID(LocStart);
+ // Make sure that the file id is valid.
+ if (File.isInvalid())
+ return;
+ SourceRegions.emplace_back(File, MacroArgumentFile, Count,
+ UnreachableInitiator, SourceGroup, LocStart,
+ LocEnd, Flags);
+ }
+
+ void mapSourceCodeRange(SourceLocation LocStart, SourceLocation LocEnd,
+ Counter Count, unsigned Flags = 0) {
+ mapSourceCodeRange(LocStart, LocEnd, Count,
+ CurrentUnreachableRegionInitiator, CurrentSourceGroup,
+ Flags);
+ }
+
+ /// \brief Generate the coverage counter mapping regions from collected
+ /// source regions.
+ void emitSourceRegions() {
+ std::sort(SourceRegions.begin(), SourceRegions.end());
+
+ for (auto I = SourceRegions.begin(), E = SourceRegions.end(); I != E; ++I) {
+ // Keep the original start location of this region.
+ SourceLocation LocStart = I->getStartLoc();
+ SourceLocation LocEnd = I->getEndLoc(SM);
+
+ bool Ignore = I->hasFlag(SourceMappingRegion::IgnoreIfNotExtended);
+ // We need to handle mergeable regions together.
+ for (auto Next = I + 1; Next != E && Next->isMergeable(*I); ++Next) {
+ ++I;
+ LocStart = std::min(LocStart, I->getStartLoc());
+ LocEnd = std::max(LocEnd, I->getEndLoc(SM));
+ // FIXME: Should we && together the Ignore flag of multiple regions?
+ Ignore = false;
+ }
+ if (Ignore)
+ continue;
+
+ // Find the spilling locations for the mapping region.
+ LocEnd = getPreciseTokenLocEnd(LocEnd);
+ unsigned LineStart = SM.getSpellingLineNumber(LocStart);
+ unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart);
+ unsigned LineEnd = SM.getSpellingLineNumber(LocEnd);
+ unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
+
+ auto SpellingFile = SM.getDecomposedSpellingLoc(LocStart).first;
+ unsigned CovFileID;
+ if (getCoverageFileID(LocStart, I->getFile(), SpellingFile, CovFileID))
+ continue;
+
+ assert(LineStart <= LineEnd);
+ MappingRegions.push_back(CounterMappingRegion(
+ I->getCounter(), CovFileID, LineStart, ColumnStart, LineEnd,
+ ColumnEnd, false, CounterMappingRegion::CodeRegion));
+ }
+ }
+};
+
+/// \brief Creates unreachable coverage regions for the functions that
+/// are not emitted.
+struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
+ EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
+ const LangOptions &LangOpts)
+ : CoverageMappingBuilder(CVM, SM, LangOpts) {}
+
+ void VisitDecl(const Decl *D) {
+ if (!D->hasBody())
+ return;
+ auto Body = D->getBody();
+ mapSourceCodeRange(Body->getLocStart(), Body->getLocEnd(), Counter());
+ }
+
+ /// \brief Write the mapping data to the output stream
+ void write(llvm::raw_ostream &OS) {
+ emitSourceRegions();
+ SmallVector<unsigned, 16> FileIDMapping;
+ createFileIDMapping(FileIDMapping);
+
+ CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions);
+ Writer.write(OS);
+ }
+};
+
+/// \brief A StmtVisitor that creates coverage mapping regions which map
+/// from the source code locations to the PGO counters.
+struct CounterCoverageMappingBuilder
+ : public CoverageMappingBuilder,
+ public ConstStmtVisitor<CounterCoverageMappingBuilder> {
+ /// \brief The map of statements to count values.
+ llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
+
+ Counter CurrentRegionCount;
+
+ CounterExpressionBuilder Builder;
+
+ /// \brief Return a counter that represents the
+ /// expression that subracts rhs from lhs.
+ Counter subtractCounters(Counter LHS, Counter RHS) {
+ return Builder.subtract(LHS, RHS);
+ }
+
+ /// \brief Return a counter that represents the
+ /// the exression that adds lhs and rhs.
+ Counter addCounters(Counter LHS, Counter RHS) {
+ return Builder.add(LHS, RHS);
+ }
+
+ /// \brief Return the region counter for the given statement.
+ /// This should only be called on statements that have a dedicated counter.
+ unsigned getRegionCounter(const Stmt *S) { return CounterMap[S]; }
+
+ /// \brief Return the region count for the counter at the given index.
+ Counter getRegionCount(unsigned CounterId) {
+ return Counter::getCounter(CounterId);
+ }
+
+ /// \brief Return the counter value of the current region.
+ Counter getCurrentRegionCount() { return CurrentRegionCount; }
+
+ /// \brief Set the counter value for the current region.
+ /// This is used to keep track of changes to the most recent counter
+ /// from control flow and non-local exits.
+ void setCurrentRegionCount(Counter Count) {
+ CurrentRegionCount = Count;
+ CurrentUnreachableRegionInitiator = nullptr;
+ }
+
+ /// \brief Indicate that the current region is never reached,
+ /// and thus should have a counter value of zero.
+ /// This is important so that subsequent regions can correctly track
+ /// their parent counts.
+ void setCurrentRegionUnreachable(const Stmt *Initiator) {
+ CurrentRegionCount = Counter::getZero();
+ CurrentUnreachableRegionInitiator = Initiator;
+ }
+
+ /// \brief A counter for a particular region.
+ /// This is the primary interface through
+ /// which the coverage mapping builder manages counters and their values.
+ class RegionMapper {
+ CounterCoverageMappingBuilder &Mapping;
+ Counter Count;
+ Counter ParentCount;
+ Counter RegionCount;
+ Counter Adjust;
+
+ public:
+ RegionMapper(CounterCoverageMappingBuilder *Mapper, const Stmt *S)
+ : Mapping(*Mapper),
+ Count(Mapper->getRegionCount(Mapper->getRegionCounter(S))),
+ ParentCount(Mapper->getCurrentRegionCount()) {}
+
+ /// Get the value of the counter. In most cases this is the number of times
+ /// the region of the counter was entered, but for switch labels it's the
+ /// number of direct jumps to that label.
+ Counter getCount() const { return Count; }
+
+ /// Get the value of the counter with adjustments applied. Adjustments occur
+ /// when control enters or leaves the region abnormally; i.e., if there is a
+ /// jump to a label within the region, or if the function can return from
+ /// within the region. The adjusted count, then, is the value of the counter
+ /// at the end of the region.
+ Counter getAdjustedCount() const {
+ return Mapping.addCounters(Count, Adjust);
+ }
+
+ /// Get the value of the counter in this region's parent, i.e., the region
+ /// that was active when this region began. This is useful for deriving
+ /// counts in implicitly counted regions, like the false case of a condition
+ /// or the normal exits of a loop.
+ Counter getParentCount() const { return ParentCount; }
+
+ /// Activate the counter by emitting an increment and starting to track
+ /// adjustments. If AddIncomingFallThrough is true, the current region count
+ /// will be added to the counter for the purposes of tracking the region.
+ void beginRegion(bool AddIncomingFallThrough = false) {
+ RegionCount = Count;
+ if (AddIncomingFallThrough)
+ RegionCount =
+ Mapping.addCounters(RegionCount, Mapping.getCurrentRegionCount());
+ Mapping.setCurrentRegionCount(RegionCount);
+ }
+
+ /// For counters on boolean branches, begins tracking adjustments for the
+ /// uncounted path.
+ void beginElseRegion() {
+ RegionCount = Mapping.subtractCounters(ParentCount, Count);
+ Mapping.setCurrentRegionCount(RegionCount);
+ }
+
+ /// Reset the current region count.
+ void setCurrentRegionCount(Counter CurrentCount) {
+ RegionCount = CurrentCount;
+ Mapping.setCurrentRegionCount(RegionCount);
+ }
+
+ /// Adjust for non-local control flow after emitting a subexpression or
+ /// substatement. This must be called to account for constructs such as
+ /// gotos,
+ /// labels, and returns, so that we can ensure that our region's count is
+ /// correct in the code that follows.
+ void adjustForControlFlow() {
+ Adjust = Mapping.addCounters(
+ Adjust, Mapping.subtractCounters(Mapping.getCurrentRegionCount(),
+ RegionCount));
+ // Reset the region count in case this is called again later.
+ RegionCount = Mapping.getCurrentRegionCount();
+ }
+
+ /// Commit all adjustments to the current region. If the region is a loop,
+ /// the LoopAdjust value should be the count of all the breaks and continues
+ /// from the loop, to compensate for those counts being deducted from the
+ /// adjustments for the body of the loop.
+ void applyAdjustmentsToRegion() {
+ Mapping.setCurrentRegionCount(Mapping.addCounters(ParentCount, Adjust));
+ }
+ void applyAdjustmentsToRegion(Counter LoopAdjust) {
+ Mapping.setCurrentRegionCount(Mapping.addCounters(
+ Mapping.addCounters(ParentCount, Adjust), LoopAdjust));
+ }
+ };
+
+ /// \brief Keep counts of breaks and continues inside loops.
+ struct BreakContinue {
+ Counter BreakCount;
+ Counter ContinueCount;
+ };
+ SmallVector<BreakContinue, 8> BreakContinueStack;
+
+ CounterCoverageMappingBuilder(
+ CoverageMappingModuleGen &CVM,
+ llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM,
+ const LangOptions &LangOpts)
+ : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {}
+
+ /// \brief Write the mapping data to the output stream
+ void write(llvm::raw_ostream &OS) {
+ emitSourceRegions();
+ llvm::SmallVector<unsigned, 8> VirtualFileMapping;
+ createFileIDMapping(VirtualFileMapping);
+ gatherSkippedRegions();
+
+ CoverageMappingWriter Writer(
+ VirtualFileMapping, Builder.getExpressions(), MappingRegions);
+ Writer.write(OS);
+ }
+
+ /// \brief Associate the source code range with the current region count.
+ void mapSourceCodeRange(SourceLocation LocStart, SourceLocation LocEnd,
+ unsigned Flags = 0) {
+ CoverageMappingBuilder::mapSourceCodeRange(LocStart, LocEnd,
+ CurrentRegionCount, Flags);
+ }
+
+ void mapSourceCodeRange(SourceLocation LocStart) {
+ CoverageMappingBuilder::mapSourceCodeRange(LocStart, LocStart,
+ CurrentRegionCount);
+ }
+
+ /// \brief Associate the source range of a token with the current region
+ /// count.
+ /// Ignore the source range for this token if it produces a distinct
+ /// mapping region with no other source ranges.
+ void mapToken(SourceLocation LocStart) {
+ CoverageMappingBuilder::mapSourceCodeRange(
+ LocStart, LocStart, CurrentRegionCount,
+ SourceMappingRegion::IgnoreIfNotExtended);
+ }
+
+ void VisitStmt(const Stmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ for (Stmt::const_child_range I = S->children(); I; ++I) {
+ if (*I)
+ this->Visit(*I);
+ }
+ }
+
+ void VisitDecl(const Decl *D) {
+ if (!D->hasBody())
+ return;
+ // Counter tracks entry to the function body.
+ auto Body = D->getBody();
+ RegionMapper Cnt(this, Body);
+ Cnt.beginRegion();
+ Visit(Body);
+ }
+
+ void VisitDeclStmt(const DeclStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ for (Stmt::const_child_range I = static_cast<const Stmt *>(S)->children();
+ I; ++I) {
+ if (*I)
+ this->Visit(*I);
+ }
+ }
+
+ void VisitCompoundStmt(const CompoundStmt *S) {
+ mapSourceCodeRange(S->getLBracLoc());
+ mapSourceCodeRange(S->getRBracLoc());
+ for (Stmt::const_child_range I = S->children(); I; ++I) {
+ if (*I)
+ this->Visit(*I);
+ }
+ }
+
+ void VisitReturnStmt(const ReturnStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ if (S->getRetValue())
+ Visit(S->getRetValue());
+ setCurrentRegionUnreachable(S);
+ }
+
+ void VisitGotoStmt(const GotoStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ mapToken(S->getLabelLoc());
+ setCurrentRegionUnreachable(S);
+ }
+
+ void VisitLabelStmt(const LabelStmt *S) {
+ // Counter tracks the block following the label.
+ RegionMapper Cnt(this, S);
+ Cnt.beginRegion();
+ mapSourceCodeRange(S->getLocStart());
+ // Can't map the ':' token as its location isn't known.
+ Visit(S->getSubStmt());
+ }
+
+ void VisitBreakStmt(const BreakStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
+ BreakContinueStack.back().BreakCount = addCounters(
+ BreakContinueStack.back().BreakCount, getCurrentRegionCount());
+ setCurrentRegionUnreachable(S);
+ }
+
+ void VisitContinueStmt(const ContinueStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
+ BreakContinueStack.back().ContinueCount = addCounters(
+ BreakContinueStack.back().ContinueCount, getCurrentRegionCount());
+ setCurrentRegionUnreachable(S);
+ }
+
+ void VisitWhileStmt(const WhileStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ // Counter tracks the body of the loop.
+ RegionMapper Cnt(this, S);
+ BreakContinueStack.push_back(BreakContinue());
+ // Visit the body region first so the break/continue adjustments can be
+ // included when visiting the condition.
+ Cnt.beginRegion();
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ // ...then go back and propagate counts through the condition. The count
+ // at the start of the condition is the sum of the incoming edges,
+ // the backedge from the end of the loop body, and the edges from
+ // continue statements.
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ Cnt.setCurrentRegionCount(
+ addCounters(Cnt.getParentCount(),
+ addCounters(Cnt.getAdjustedCount(), BC.ContinueCount)));
+ beginSourceRegionGroup(S->getCond());
+ Visit(S->getCond());
+ endSourceRegionGroup();
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, BC.ContinueCount));
+ }
+
+ void VisitDoStmt(const DoStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ // Counter tracks the body of the loop.
+ RegionMapper Cnt(this, S);
+ BreakContinueStack.push_back(BreakContinue());
+ Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ // The count at the start of the condition is equal to the count at the
+ // end of the body. The adjusted count does not include either the
+ // fall-through count coming into the loop or the continue count, so add
+ // both of those separately. This is coincidentally the same equation as
+ // with while loops but for different reasons.
+ Cnt.setCurrentRegionCount(
+ addCounters(Cnt.getParentCount(),
+ addCounters(Cnt.getAdjustedCount(), BC.ContinueCount)));
+ Visit(S->getCond());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, BC.ContinueCount));
+ }
+
+ void VisitForStmt(const ForStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ if (S->getInit())
+ Visit(S->getInit());
+
+ // Counter tracks the body of the loop.
+ RegionMapper Cnt(this, S);
+ BreakContinueStack.push_back(BreakContinue());
+ // Visit the body region first. (This is basically the same as a while
+ // loop; see further comments in VisitWhileStmt.)
+ Cnt.beginRegion();
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ // The increment is essentially part of the body but it needs to include
+ // the count for all the continue statements.
+ if (S->getInc()) {
+ Cnt.setCurrentRegionCount(addCounters(
+ getCurrentRegionCount(), BreakContinueStack.back().ContinueCount));
+ beginSourceRegionGroup(S->getInc());
+ Visit(S->getInc());
+ endSourceRegionGroup();
+ Cnt.adjustForControlFlow();
+ }
+
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+
+ // ...then go back and propagate counts through the condition.
+ if (S->getCond()) {
+ Cnt.setCurrentRegionCount(
+ addCounters(addCounters(Cnt.getParentCount(), Cnt.getAdjustedCount()),
+ BC.ContinueCount));
+ beginSourceRegionGroup(S->getCond());
+ Visit(S->getCond());
+ endSourceRegionGroup();
+ Cnt.adjustForControlFlow();
+ }
+ Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, BC.ContinueCount));
+ }
+
+ void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ Visit(S->getRangeStmt());
+ Visit(S->getBeginEndStmt());
+ // Counter tracks the body of the loop.
+ RegionMapper Cnt(this, S);
+ BreakContinueStack.push_back(BreakContinue());
+ // Visit the body region first. (This is basically the same as a while
+ // loop; see further comments in VisitWhileStmt.)
+ Cnt.beginRegion();
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, BC.ContinueCount));
+ }
+
+ void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ Visit(S->getElement());
+ // Counter tracks the body of the loop.
+ RegionMapper Cnt(this, S);
+ BreakContinueStack.push_back(BreakContinue());
+ Cnt.beginRegion();
+ Visit(S->getBody());
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, BC.ContinueCount));
+ }
+
+ void VisitSwitchStmt(const SwitchStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ Visit(S->getCond());
+ BreakContinueStack.push_back(BreakContinue());
+ // Map the '}' for the body to have the same count as the regions after
+ // the switch.
+ SourceLocation RBracLoc;
+ if (const auto *CS = dyn_cast<CompoundStmt>(S->getBody())) {
+ mapSourceCodeRange(CS->getLBracLoc());
+ setCurrentRegionUnreachable(S);
+ for (Stmt::const_child_range I = CS->children(); I; ++I) {
+ if (*I)
+ this->Visit(*I);
+ }
+ RBracLoc = CS->getRBracLoc();
+ } else {
+ setCurrentRegionUnreachable(S);
+ Visit(S->getBody());
+ }
+ // If the switch is inside a loop, add the continue counts.
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ if (!BreakContinueStack.empty())
+ BreakContinueStack.back().ContinueCount = addCounters(
+ BreakContinueStack.back().ContinueCount, BC.ContinueCount);
+ // Counter tracks the exit block of the switch.
+ RegionMapper ExitCnt(this, S);
+ ExitCnt.beginRegion();
+ if (RBracLoc.isValid())
+ mapSourceCodeRange(RBracLoc);
+ }
+
+ void VisitCaseStmt(const CaseStmt *S) {
+ // Counter for this particular case. This counts only jumps from the
+ // switch header and does not include fallthrough from the case before
+ // this one.
+ RegionMapper Cnt(this, S);
+ Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
+ mapSourceCodeRange(S->getLocStart());
+ mapToken(S->getColonLoc());
+ Visit(S->getSubStmt());
+ }
+
+ void VisitDefaultStmt(const DefaultStmt *S) {
+ // Counter for this default case. This does not include fallthrough from
+ // the previous case.
+ RegionMapper Cnt(this, S);
+ Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
+ mapSourceCodeRange(S->getLocStart());
+ mapToken(S->getColonLoc());
+ Visit(S->getSubStmt());
+ }
+
+ void VisitIfStmt(const IfStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ Visit(S->getCond());
+ mapToken(S->getElseLoc());
+
+ // Counter tracks the "then" part of an if statement. The count for
+ // the "else" part, if it exists, will be calculated from this counter.
+ RegionMapper Cnt(this, S);
+ Cnt.beginRegion();
+ Visit(S->getThen());
+ Cnt.adjustForControlFlow();
+
+ if (S->getElse()) {
+ Cnt.beginElseRegion();
+ Visit(S->getElse());
+ Cnt.adjustForControlFlow();
+ }
+ Cnt.applyAdjustmentsToRegion();
+ }
+
+ void VisitCXXTryStmt(const CXXTryStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ Visit(S->getTryBlock());
+ for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
+ Visit(S->getHandler(I));
+ // Counter tracks the continuation block of the try statement.
+ RegionMapper Cnt(this, S);
+ Cnt.beginRegion();
+ }
+
+ void VisitCXXCatchStmt(const CXXCatchStmt *S) {
+ mapSourceCodeRange(S->getLocStart());
+ // Counter tracks the catch statement's handler block.
+ RegionMapper Cnt(this, S);
+ Cnt.beginRegion();
+ Visit(S->getHandlerBlock());
+ }
+
+ void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
+ Visit(E->getCond());
+ mapToken(E->getQuestionLoc());
+ mapToken(E->getColonLoc());
+
+ // Counter tracks the "true" part of a conditional operator. The
+ // count in the "false" part will be calculated from this counter.
+ RegionMapper Cnt(this, E);
+ Cnt.beginRegion();
+ Visit(E->getTrueExpr());
+ Cnt.adjustForControlFlow();
+
+ Cnt.beginElseRegion();
+ Visit(E->getFalseExpr());
+ Cnt.adjustForControlFlow();
+
+ Cnt.applyAdjustmentsToRegion();
+ }
+
+ void VisitBinLAnd(const BinaryOperator *E) {
+ Visit(E->getLHS());
+ mapToken(E->getOperatorLoc());
+ // Counter tracks the right hand side of a logical and operator.
+ RegionMapper Cnt(this, E);
+ Cnt.beginRegion();
+ Visit(E->getRHS());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion();
+ }
+
+ void VisitBinLOr(const BinaryOperator *E) {
+ Visit(E->getLHS());
+ mapToken(E->getOperatorLoc());
+ // Counter tracks the right hand side of a logical or operator.
+ RegionMapper Cnt(this, E);
+ Cnt.beginRegion();
+ Visit(E->getRHS());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion();
+ }
+
+ void VisitParenExpr(const ParenExpr *E) {
+ mapToken(E->getLParen());
+ Visit(E->getSubExpr());
+ mapToken(E->getRParen());
+ }
+
+ void VisitBinaryOperator(const BinaryOperator *E) {
+ Visit(E->getLHS());
+ mapToken(E->getOperatorLoc());
+ Visit(E->getRHS());
+ }
+
+ void VisitUnaryOperator(const UnaryOperator *E) {
+ bool Postfix = E->isPostfix();
+ if (!Postfix)
+ mapToken(E->getOperatorLoc());
+ Visit(E->getSubExpr());
+ if (Postfix)
+ mapToken(E->getOperatorLoc());
+ }
+
+ void VisitMemberExpr(const MemberExpr *E) {
+ Visit(E->getBase());
+ mapToken(E->getMemberLoc());
+ }
+
+ void VisitCallExpr(const CallExpr *E) {
+ Visit(E->getCallee());
+ for (const auto &Arg : E->arguments())
+ Visit(Arg);
+ mapToken(E->getRParenLoc());
+ }
+
+ void VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ Visit(E->getLHS());
+ Visit(E->getRHS());
+ mapToken(E->getRBracketLoc());
+ }
+
+ void VisitCStyleCastExpr(const CStyleCastExpr *E) {
+ mapToken(E->getLParenLoc());
+ mapToken(E->getRParenLoc());
+ Visit(E->getSubExpr());
+ }
+
+ // Map literals as tokens so that the macros like #define PI 3.14
+ // won't generate coverage mapping regions.
+
+ void VisitIntegerLiteral(const IntegerLiteral *E) {
+ mapToken(E->getLocStart());
+ }
+
+ void VisitFloatingLiteral(const FloatingLiteral *E) {
+ mapToken(E->getLocStart());
+ }
+
+ void VisitCharacterLiteral(const CharacterLiteral *E) {
+ mapToken(E->getLocStart());
+ }
+
+ void VisitStringLiteral(const StringLiteral *E) {
+ mapToken(E->getLocStart());
+ }
+
+ void VisitImaginaryLiteral(const ImaginaryLiteral *E) {
+ mapToken(E->getLocStart());
+ }
+
+ void VisitObjCMessageExpr(const ObjCMessageExpr *E) {
+ mapToken(E->getLeftLoc());
+ for (Stmt::const_child_range I = static_cast<const Stmt*>(E)->children(); I;
+ ++I) {
+ if (*I)
+ this->Visit(*I);
+ }
+ mapToken(E->getRightLoc());
+ }
+};
+}
+
+static bool isMachO(const CodeGenModule &CGM) {
+ return CGM.getTarget().getTriple().isOSBinFormatMachO();
+}
+
+static StringRef getCoverageSection(const CodeGenModule &CGM) {
+ return isMachO(CGM) ? "__DATA,__llvm_covmap" : "__llvm_covmap";
+}
+
+static void dump(llvm::raw_ostream &OS, const CoverageMappingRecord &Function) {
+ OS << Function.FunctionName << ":\n";
+ CounterMappingContext Ctx(Function.Expressions);
+ for (const auto &R : Function.MappingRegions) {
+ OS.indent(2);
+ switch (R.Kind) {
+ case CounterMappingRegion::CodeRegion:
+ break;
+ case CounterMappingRegion::ExpansionRegion:
+ OS << "Expansion,";
+ break;
+ case CounterMappingRegion::SkippedRegion:
+ OS << "Skipped,";
+ break;
+ }
+
+ OS << "File " << R.FileID << ", " << R.LineStart << ":"
+ << R.ColumnStart << " -> " << R.LineEnd << ":" << R.ColumnEnd
+ << " = ";
+ Ctx.dump(R.Count);
+ OS << " (HasCodeBefore = " << R.HasCodeBefore;
+ if (R.Kind == CounterMappingRegion::ExpansionRegion)
+ OS << ", Expanded file = " << R.ExpandedFileID;
+
+ OS << ")\n";
+ }
+}
+
+void CoverageMappingModuleGen::addFunctionMappingRecord(
+ llvm::GlobalVariable *FunctionName, StringRef FunctionNameValue,
+ uint64_t FunctionHash, const std::string &CoverageMapping) {
+ llvm::LLVMContext &Ctx = CGM.getLLVMContext();
+ auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
+ auto *Int64Ty = llvm::Type::getInt64Ty(Ctx);
+ auto *Int8PtrTy = llvm::Type::getInt8PtrTy(Ctx);
+ if (!FunctionRecordTy) {
+ llvm::Type *FunctionRecordTypes[] = {Int8PtrTy, Int32Ty, Int32Ty, Int64Ty};
+ FunctionRecordTy =
+ llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes));
+ }
+
+ llvm::Constant *FunctionRecordVals[] = {
+ llvm::ConstantExpr::getBitCast(FunctionName, Int8PtrTy),
+ llvm::ConstantInt::get(Int32Ty, FunctionNameValue.size()),
+ llvm::ConstantInt::get(Int32Ty, CoverageMapping.size()),
+ llvm::ConstantInt::get(Int64Ty, FunctionHash)};
+ FunctionRecords.push_back(llvm::ConstantStruct::get(
+ FunctionRecordTy, makeArrayRef(FunctionRecordVals)));
+ CoverageMappings += CoverageMapping;
+
+ if (CGM.getCodeGenOpts().DumpCoverageMapping) {
+ // Dump the coverage mapping data for this function by decoding the
+ // encoded data. This allows us to dump the mapping regions which were
+ // also processed by the CoverageMappingWriter which performs
+ // additional minimization operations such as reducing the number of
+ // expressions.
+ std::vector<StringRef> Filenames;
+ std::vector<CounterExpression> Expressions;
+ std::vector<CounterMappingRegion> Regions;
+ llvm::SmallVector<StringRef, 16> FilenameRefs;
+ FilenameRefs.resize(FileEntries.size());
+ for (const auto &Entry : FileEntries)
+ FilenameRefs[Entry.second] = Entry.first->getName();
+ RawCoverageMappingReader Reader(FunctionNameValue, CoverageMapping,
+ FilenameRefs,
+ Filenames, Expressions, Regions);
+ CoverageMappingRecord FunctionRecord;
+ if (Reader.read(FunctionRecord))
+ return;
+ dump(llvm::outs(), FunctionRecord);
+ }
+}
+
+void CoverageMappingModuleGen::emit() {
+ if (FunctionRecords.empty())
+ return;
+ llvm::LLVMContext &Ctx = CGM.getLLVMContext();
+ auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
+
+ // Create the filenames and merge them with coverage mappings
+ llvm::SmallVector<std::string, 16> FilenameStrs;
+ llvm::SmallVector<StringRef, 16> FilenameRefs;
+ FilenameStrs.resize(FileEntries.size());
+ FilenameRefs.resize(FileEntries.size());
+ for (const auto &Entry : FileEntries) {
+ llvm::SmallString<256> Path(Entry.first->getName());
+ llvm::sys::fs::make_absolute(Path);
+
+ auto I = Entry.second;
+ FilenameStrs[I] = std::move(std::string(Path.begin(), Path.end()));
+ FilenameRefs[I] = FilenameStrs[I];
+ }
+
+ std::string FilenamesAndCoverageMappings;
+ llvm::raw_string_ostream OS(FilenamesAndCoverageMappings);
+ CoverageFilenamesSectionWriter(FilenameRefs).write(OS);
+ OS << CoverageMappings;
+ size_t CoverageMappingSize = CoverageMappings.size();
+ size_t FilenamesSize = OS.str().size() - CoverageMappingSize;
+ // Append extra zeroes if necessary to ensure that the size of the filenames
+ // and coverage mappings is a multiple of 8.
+ if (size_t Rem = OS.str().size() % 8) {
+ CoverageMappingSize += 8 - Rem;
+ for (size_t I = 0, S = 8 - Rem; I < S; ++I)
+ OS << '\0';
+ }
+ auto *FilenamesAndMappingsVal =
+ llvm::ConstantDataArray::getString(Ctx, OS.str(), false);
+
+ // Create the deferred function records array
+ auto RecordsTy =
+ llvm::ArrayType::get(FunctionRecordTy, FunctionRecords.size());
+ auto RecordsVal = llvm::ConstantArray::get(RecordsTy, FunctionRecords);
+
+ // Create the coverage data record
+ llvm::Type *CovDataTypes[] = {Int32Ty, Int32Ty,
+ Int32Ty, Int32Ty,
+ RecordsTy, FilenamesAndMappingsVal->getType()};
+ auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes));
+ llvm::Constant *TUDataVals[] = {
+ llvm::ConstantInt::get(Int32Ty, FunctionRecords.size()),
+ llvm::ConstantInt::get(Int32Ty, FilenamesSize),
+ llvm::ConstantInt::get(Int32Ty, CoverageMappingSize),
+ llvm::ConstantInt::get(Int32Ty,
+ /*Version=*/CoverageMappingVersion1),
+ RecordsVal, FilenamesAndMappingsVal};
+ auto CovDataVal =
+ llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals));
+ auto CovData = new llvm::GlobalVariable(CGM.getModule(), CovDataTy, true,
+ llvm::GlobalValue::InternalLinkage,
+ CovDataVal,
+ "__llvm_coverage_mapping");
+
+ CovData->setSection(getCoverageSection(CGM));
+ CovData->setAlignment(8);
+
+ // Make sure the data doesn't get deleted.
+ CGM.addUsedGlobal(CovData);
+}
+
+unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
+ auto It = FileEntries.find(File);
+ if (It != FileEntries.end())
+ return It->second;
+ unsigned FileID = FileEntries.size();
+ FileEntries.insert(std::make_pair(File, FileID));
+ return FileID;
+}
+
+void CoverageMappingGen::emitCounterMapping(const Decl *D,
+ llvm::raw_ostream &OS) {
+ assert(CounterMap);
+ CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts);
+ Walker.VisitDecl(D);
+ Walker.write(OS);
+}
+
+void CoverageMappingGen::emitEmptyMapping(const Decl *D,
+ llvm::raw_ostream &OS) {
+ EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
+ Walker.VisitDecl(D);
+ Walker.write(OS);
+}
diff --git a/lib/CodeGen/CoverageMappingGen.h b/lib/CodeGen/CoverageMappingGen.h
new file mode 100644
index 000000000000..0d1bf6d975c9
--- /dev/null
+++ b/lib/CodeGen/CoverageMappingGen.h
@@ -0,0 +1,114 @@
+//===---- CoverageMappingGen.h - Coverage mapping generation ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Instrumentation-based code coverage mapping generator
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CODEGEN_COVERAGEMAPPINGGEN_H
+#define LLVM_CLANG_LIB_CODEGEN_COVERAGEMAPPINGGEN_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Frontend/CodeGenOptions.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+
+class LangOptions;
+class SourceManager;
+class FileEntry;
+class Preprocessor;
+class Decl;
+class Stmt;
+
+/// \brief Stores additional source code information like skipped ranges which
+/// is required by the coverage mapping generator and is obtained from
+/// the preprocessor.
+class CoverageSourceInfo : public PPCallbacks {
+ std::vector<SourceRange> SkippedRanges;
+public:
+ ArrayRef<SourceRange> getSkippedRanges() const { return SkippedRanges; }
+
+ void SourceRangeSkipped(SourceRange Range) override;
+};
+
+namespace CodeGen {
+
+class CodeGenModule;
+
+/// \brief Organizes the cross-function state that is used while generating
+/// code coverage mapping data.
+class CoverageMappingModuleGen {
+ CodeGenModule &CGM;
+ CoverageSourceInfo &SourceInfo;
+ llvm::SmallDenseMap<const FileEntry *, unsigned, 8> FileEntries;
+ std::vector<llvm::Constant *> FunctionRecords;
+ llvm::StructType *FunctionRecordTy;
+ std::string CoverageMappings;
+
+public:
+ CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
+ : CGM(CGM), SourceInfo(SourceInfo), FunctionRecordTy(nullptr) {}
+
+ CoverageSourceInfo &getSourceInfo() const {
+ return SourceInfo;
+ }
+
+ /// \brief Add a function's coverage mapping record to the collection of the
+ /// function mapping records.
+ void addFunctionMappingRecord(llvm::GlobalVariable *FunctionName,
+ StringRef FunctionNameValue,
+ uint64_t FunctionHash,
+ const std::string &CoverageMapping);
+
+ /// \brief Emit the coverage mapping data for a translation unit.
+ void emit();
+
+ /// \brief Return the coverage mapping translation unit file id
+ /// for the given file.
+ unsigned getFileID(const FileEntry *File);
+};
+
+/// \brief Organizes the per-function state that is used while generating
+/// code coverage mapping data.
+class CoverageMappingGen {
+ CoverageMappingModuleGen &CVM;
+ SourceManager &SM;
+ const LangOptions &LangOpts;
+ llvm::DenseMap<const Stmt *, unsigned> *CounterMap;
+
+public:
+ CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM,
+ const LangOptions &LangOpts)
+ : CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(nullptr) {}
+
+ CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM,
+ const LangOptions &LangOpts,
+ llvm::DenseMap<const Stmt *, unsigned> *CounterMap)
+ : CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(CounterMap) {}
+
+ /// \brief Emit the coverage mapping data which maps the regions of
+ /// code to counters that will be used to find the execution
+ /// counts for those regions.
+ void emitCounterMapping(const Decl *D, llvm::raw_ostream &OS);
+
+ /// \brief Emit the coverage mapping data for an unused function.
+ /// It creates mapping regions with the counter of zero.
+ void emitEmptyMapping(const Decl *D, llvm::raw_ostream &OS);
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/EHScopeStack.h b/lib/CodeGen/EHScopeStack.h
index b9ccfb63d7d5..e69584840990 100644
--- a/lib/CodeGen/EHScopeStack.h
+++ b/lib/CodeGen/EHScopeStack.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_EHSCOPESTACK_H
-#define CLANG_CODEGEN_EHSCOPESTACK_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H
+#define LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallVector.h"
@@ -74,7 +74,7 @@ template <class T> struct DominatingPointer<T,false> : InvariantValue<T*> {};
template <class T> struct DominatingValue<T*> : DominatingPointer<T> {};
-enum CleanupKind {
+enum CleanupKind : unsigned {
EHCleanup = 0x1,
NormalCleanup = 0x2,
NormalAndEHCleanup = EHCleanup | NormalCleanup,
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index d7e61f0fe577..f2ffabcf3e9d 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -106,8 +106,11 @@ public:
llvm::Value *Addr,
const MemberPointerType *MPT) override;
- llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, llvm::Value *ptr,
- QualType type) override;
+ void emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE,
+ llvm::Value *Ptr, QualType ElementType,
+ const CXXDestructorDecl *Dtor) override;
+
+ void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;
void EmitFundamentalRTTIDescriptor(QualType Type);
void EmitFundamentalRTTIDescriptors();
@@ -138,15 +141,10 @@ public:
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) override;
- void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType T, CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) override;
-
void EmitCXXConstructors(const CXXConstructorDecl *D) override;
- void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
- CXXDtorType T, CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) override;
+ void buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
+ SmallVectorImpl<CanQualType> &ArgTys) override;
bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
CXXDtorType DT) const override {
@@ -192,10 +190,11 @@ public:
llvm::Value *This,
llvm::Type *Ty) override;
- void EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType, SourceLocation CallLoc,
- llvm::Value *This) override;
+ llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ llvm::Value *This,
+ const CXXMemberCallExpr *CE) override;
void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
@@ -213,6 +212,12 @@ public:
llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
const ReturnAdjustment &RA) override;
+ size_t getSrcArgforCopyCtor(const CXXConstructorDecl *,
+ FunctionArgList &Args) const override {
+ assert(!Args.empty() && "expected the arglist to not be empty!");
+ return Args.size() - 1;
+ }
+
StringRef GetPureVirtualCallName() override { return "__cxa_pure_virtual"; }
StringRef GetDeletedVirtualCallName() override
{ return "__cxa_deleted_virtual"; }
@@ -234,10 +239,15 @@ public:
llvm::Constant *dtor, llvm::Constant *addr) override;
llvm::Function *getOrCreateThreadLocalWrapper(const VarDecl *VD,
- llvm::GlobalVariable *Var);
+ llvm::Value *Val);
void EmitThreadLocalInitFuncs(
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
- llvm::Function *InitFunc) override;
+ CodeGenModule &CGM,
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
+ CXXThreadLocals,
+ ArrayRef<llvm::Function *> CXXThreadLocalInits,
+ ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) override;
+
+ bool usesThreadWrapperFunction() const override { return true; }
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
QualType LValType) override;
@@ -273,6 +283,8 @@ public:
classifyRTTIUniqueness(QualType CanTy,
llvm::GlobalValue::LinkageTypes Linkage) const;
friend class ItaniumRTTIBuilder;
+
+ void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -348,7 +360,7 @@ llvm::Type *
ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
if (MPT->isMemberDataPointer())
return CGM.PtrDiffTy;
- return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy, NULL);
+ return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy, nullptr);
}
/// In the Itanium and ARM ABIs, method pointers have the form:
@@ -839,21 +851,56 @@ bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
/// The Itanium ABI always places an offset to the complete object
/// at entry -2 in the vtable.
-llvm::Value *ItaniumCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
- llvm::Value *ptr,
- QualType type) {
- // Grab the vtable pointer as an intptr_t*.
- llvm::Value *vtable = CGF.GetVTablePtr(ptr, CGF.IntPtrTy->getPointerTo());
-
- // Track back to entry -2 and pull out the offset there.
- llvm::Value *offsetPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(vtable, -2, "complete-offset.ptr");
- llvm::LoadInst *offset = CGF.Builder.CreateLoad(offsetPtr);
- offset->setAlignment(CGF.PointerAlignInBytes);
+void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF,
+ const CXXDeleteExpr *DE,
+ llvm::Value *Ptr,
+ QualType ElementType,
+ const CXXDestructorDecl *Dtor) {
+ bool UseGlobalDelete = DE->isGlobalDelete();
+ if (UseGlobalDelete) {
+ // Derive the complete-object pointer, which is what we need
+ // to pass to the deallocation function.
+
+ // Grab the vtable pointer as an intptr_t*.
+ llvm::Value *VTable = CGF.GetVTablePtr(Ptr, CGF.IntPtrTy->getPointerTo());
+
+ // Track back to entry -2 and pull out the offset there.
+ llvm::Value *OffsetPtr = CGF.Builder.CreateConstInBoundsGEP1_64(
+ VTable, -2, "complete-offset.ptr");
+ llvm::LoadInst *Offset = CGF.Builder.CreateLoad(OffsetPtr);
+ Offset->setAlignment(CGF.PointerAlignInBytes);
+
+ // Apply the offset.
+ llvm::Value *CompletePtr = CGF.Builder.CreateBitCast(Ptr, CGF.Int8PtrTy);
+ CompletePtr = CGF.Builder.CreateInBoundsGEP(CompletePtr, Offset);
+
+ // If we're supposed to call the global delete, make sure we do so
+ // even if the destructor throws.
+ CGF.pushCallObjectDeleteCleanup(DE->getOperatorDelete(), CompletePtr,
+ ElementType);
+ }
- // Apply the offset.
- ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8PtrTy);
- return CGF.Builder.CreateInBoundsGEP(ptr, offset);
+ // FIXME: Provide a source location here even though there's no
+ // CXXMemberCallExpr for dtor call.
+ CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
+ EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, /*CE=*/nullptr);
+
+ if (UseGlobalDelete)
+ CGF.PopCleanupBlock();
+}
+
+void ItaniumCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) {
+ // void __cxa_rethrow();
+
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
+
+ llvm::Constant *Fn = CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
+
+ if (isNoReturn)
+ CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, None);
+ else
+ CGF.EmitRuntimeCallOrInvoke(Fn);
}
static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {
@@ -1066,23 +1113,6 @@ ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
return VBaseOffset;
}
-/// The generic ABI passes 'this', plus a VTT if it's initializing a
-/// base subobject.
-void
-ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType Type, CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
- ASTContext &Context = getContext();
-
- // All parameters are already in place except VTT, which goes after 'this'.
- // These are Clang types, so we don't need to worry about sret yet.
-
- // Check if we need to add a VTT parameter (which has type void **).
- if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0)
- ArgTys.insert(ArgTys.begin() + 1,
- Context.getPointerType(Context.VoidPtrTy));
-}
-
void ItaniumCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
// Just make sure we're in sync with TargetCXXABI.
assert(CGM.getTarget().getCXXABI().hasConstructorVariants());
@@ -1092,27 +1122,25 @@ void ItaniumCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
CGM.EmitGlobal(GlobalDecl(D, Ctor_Base));
// The constructor used for constructing this as a complete class;
- // constucts the virtual bases, then calls the base constructor.
+ // constructs the virtual bases, then calls the base constructor.
if (!D->getParent()->isAbstract()) {
// We don't need to emit the complete ctor if the class is abstract.
CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete));
}
}
-/// The generic ABI passes 'this', plus a VTT if it's destroying a
-/// base subobject.
-void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
- CXXDtorType Type,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
+void
+ItaniumCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
+ SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext();
- // 'this' parameter is already there, as well as 'this' return if
- // HasThisReturn(GlobalDecl(Dtor, Type)) is true
+ // All parameters are already in place except VTT, which goes after 'this'.
+ // These are Clang types, so we don't need to worry about sret yet.
// Check if we need to add a VTT parameter (which has type void **).
- if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0)
- ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
+ if (T == StructorType::Base && MD->getParent()->getNumVBases() != 0)
+ ArgTys.insert(ArgTys.begin() + 1,
+ Context.getPointerType(Context.VoidPtrTy));
}
void ItaniumCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
@@ -1201,11 +1229,10 @@ void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
Callee = CGF.BuildAppleKextVirtualDestructorCall(DD, Type, DD->getParent());
if (!Callee)
- Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
+ Callee = CGM.getAddrOfCXXStructor(DD, getFromDtorType(Type));
- // FIXME: Provide a source location here.
- CGF.EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
- VTT, VTTTy, nullptr, nullptr);
+ CGF.EmitCXXMemberOrOperatorCall(DD, Callee, ReturnValueSlot(), This, VTT,
+ VTTTy, nullptr);
}
void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
@@ -1232,6 +1259,12 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
// Set the right visibility.
CGM.setGlobalVisibility(VTable, RD);
+ // Use pointer alignment for the vtable. Otherwise we would align them based
+ // on the size of the initializer which doesn't make sense as only single
+ // values are read.
+ unsigned PAlign = CGM.getTarget().getPointerAlign(0);
+ VTable->setAlignment(getContext().toCharUnitsFromBits(PAlign).getQuantity());
+
// If this is the magic class __cxxabiv1::__fundamental_type_info,
// we will emit the typeinfo for the fundamental types. This is the
// same behaviour as GCC.
@@ -1339,22 +1372,21 @@ llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
return CGF.Builder.CreateLoad(VFuncPtr);
}
-void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- SourceLocation CallLoc,
- llvm::Value *This) {
+llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall(
+ CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType,
+ llvm::Value *This, const CXXMemberCallExpr *CE) {
+ assert(CE == nullptr || CE->arg_begin() == CE->arg_end());
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
- const CGFunctionInfo *FInfo
- = &CGM.getTypes().arrangeCXXDestructor(Dtor, DtorType);
+ const CGFunctionInfo *FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration(
+ Dtor, getFromDtorType(DtorType));
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
llvm::Value *Callee =
getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, DtorType), This, Ty);
- CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
- /*ImplicitParam=*/nullptr, QualType(), nullptr,
- nullptr);
+ CGF.EmitCXXMemberOrOperatorCall(Dtor, Callee, ReturnValueSlot(), This,
+ /*ImplicitParam=*/nullptr, QualType(), CE);
+ return nullptr;
}
void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
@@ -1473,10 +1505,20 @@ llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
CookieOffset.getQuantity());
// Write the number of elements into the appropriate slot.
- llvm::Value *NumElementsPtr
- = CGF.Builder.CreateBitCast(CookiePtr,
- CGF.ConvertType(SizeTy)->getPointerTo(AS));
- CGF.Builder.CreateStore(NumElements, NumElementsPtr);
+ llvm::Type *NumElementsTy = CGF.ConvertType(SizeTy)->getPointerTo(AS);
+ llvm::Value *NumElementsPtr =
+ CGF.Builder.CreateBitCast(CookiePtr, NumElementsTy);
+ llvm::Instruction *SI = CGF.Builder.CreateStore(NumElements, NumElementsPtr);
+ if (CGM.getLangOpts().Sanitize.has(SanitizerKind::Address) && AS == 0 &&
+ expr->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
+ // The store to the CookiePtr does not need to be instrumented.
+ CGM.getSanitizerMetadata()->disableSanitizerForInstruction(SI);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, NumElementsTy, false);
+ llvm::Constant *F =
+ CGM.CreateRuntimeFunction(FTy, "__asan_poison_cxx_array_cookie");
+ CGF.Builder.CreateCall(F, NumElementsPtr);
+ }
// Finally, compute a pointer to the actual data buffer by skipping
// over the cookie completely.
@@ -1499,7 +1541,18 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
unsigned AS = allocPtr->getType()->getPointerAddressSpace();
numElementsPtr =
CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS));
- return CGF.Builder.CreateLoad(numElementsPtr);
+ if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Address) || AS != 0)
+ return CGF.Builder.CreateLoad(numElementsPtr);
+ // In asan mode emit a function call instead of a regular load and let the
+ // run-time deal with it: if the shadow is properly poisoned return the
+ // cookie, otherwise return 0 to avoid an infinite loop calling DTORs.
+ // We can't simply ignore this load using nosanitize metadata because
+ // the metadata may be lost.
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.SizeTy, CGF.SizeTy->getPointerTo(0), false);
+ llvm::Constant *F =
+ CGM.CreateRuntimeFunction(FTy, "__asan_load_cxx_array_cookie");
+ return CGF.Builder.CreateCall(F, numElementsPtr);
}
CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) {
@@ -1656,6 +1709,16 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// If the variable is thread-local, so is its guard variable.
guard->setThreadLocalMode(var->getThreadLocalMode());
+ // The ABI says: It is suggested that it be emitted in the same COMDAT group
+ // as the associated data object
+ llvm::Comdat *C = var->getComdat();
+ if (!D.isLocalVarDecl() && C) {
+ guard->setComdat(C);
+ CGF.CurFn->setComdat(C);
+ } else if (CGM.supportsCOMDAT() && guard->isWeakForLinker()) {
+ guard->setComdat(CGM.getModule().getOrInsertComdat(guard->getName()));
+ }
+
CGM.setStaticLocalDeclGuardAddress(&D, guard);
}
@@ -1851,7 +1914,7 @@ getThreadLocalWrapperLinkage(const VarDecl *VD, CodeGen::CodeGenModule &CGM) {
llvm::Function *
ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
- llvm::GlobalVariable *Var) {
+ llvm::Value *Val) {
// Mangle the name for the thread_local wrapper function.
SmallString<256> WrapperName;
{
@@ -1860,10 +1923,10 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
Out.flush();
}
- if (llvm::Value *V = Var->getParent()->getNamedValue(WrapperName))
+ if (llvm::Value *V = CGM.getModule().getNamedValue(WrapperName))
return cast<llvm::Function>(V);
- llvm::Type *RetTy = Var->getType();
+ llvm::Type *RetTy = Val->getType();
if (VD->getType()->isReferenceType())
RetTy = RetTy->getPointerElementType();
@@ -1878,11 +1941,29 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
}
void ItaniumCXXABI::EmitThreadLocalInitFuncs(
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
- llvm::Function *InitFunc) {
- for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
- const VarDecl *VD = Decls[I].first;
- llvm::GlobalVariable *Var = Decls[I].second;
+ CodeGenModule &CGM,
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
+ CXXThreadLocals, ArrayRef<llvm::Function *> CXXThreadLocalInits,
+ ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) {
+ llvm::Function *InitFunc = nullptr;
+ if (!CXXThreadLocalInits.empty()) {
+ // Generate a guarded initialization function.
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+ InitFunc = CGM.CreateGlobalInitOrDestructFunction(FTy, "__tls_init",
+ SourceLocation(),
+ /*TLS=*/true);
+ llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
+ CGM.getModule(), CGM.Int8Ty, /*isConstant=*/false,
+ llvm::GlobalVariable::InternalLinkage,
+ llvm::ConstantInt::get(CGM.Int8Ty, 0), "__tls_guard");
+ Guard->setThreadLocal(true);
+ CodeGenFunction(CGM)
+ .GenerateCXXGlobalInitFunc(InitFunc, CXXThreadLocalInits, Guard);
+ }
+ for (unsigned I = 0, N = CXXThreadLocals.size(); I != N; ++I) {
+ const VarDecl *VD = CXXThreadLocals[I].first;
+ llvm::GlobalVariable *Var = CXXThreadLocals[I].second;
// Some targets require that all access to thread local variables go through
// the thread wrapper. This means that we cannot attempt to create a thread
@@ -1951,7 +2032,9 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
LI->setAlignment(CGM.getContext().getDeclAlign(VD).getQuantity());
Val = LI;
}
-
+ if (Val->getType() != Wrapper->getReturnType())
+ Val = Builder.CreatePointerBitCastOrAddrSpaceCast(
+ Val, Wrapper->getReturnType(), "");
Builder.CreateRet(Val);
}
}
@@ -1962,8 +2045,7 @@ LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
QualType T = VD->getType();
llvm::Type *Ty = CGF.getTypes().ConvertTypeForMem(T);
llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty);
- llvm::Function *Wrapper =
- getOrCreateThreadLocalWrapper(VD, cast<llvm::GlobalVariable>(Val));
+ llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Val);
Val = CGF.Builder.CreateCall(Wrapper);
@@ -2125,6 +2207,11 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
/*Constant=*/true,
llvm::GlobalValue::ExternalLinkage, nullptr,
Name);
+ if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (RD->hasAttr<DLLImportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
+ }
}
return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
@@ -2247,7 +2334,11 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
// FIXME: this may need to be reconsidered if the key function
// changes.
- return CGM.getVTables().isVTableExternal(RD);
+ if (CGM.getVTables().isVTableExternal(RD))
+ return true;
+
+ if (RD->hasAttr<DLLImportAttr>())
+ return true;
}
return false;
@@ -2742,7 +2833,7 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
if (Base->isVirtual()) {
// Mark the virtual base as seen.
- if (!Bases.VirtualBases.insert(BaseDecl)) {
+ if (!Bases.VirtualBases.insert(BaseDecl).second) {
// If this virtual base has been seen before, then the class is diamond
// shaped.
Flags |= ItaniumRTTIBuilder::VMI_DiamondShaped;
@@ -2752,7 +2843,7 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
}
} else {
// Mark the non-virtual base as seen.
- if (!Bases.NonVirtualBases.insert(BaseDecl)) {
+ if (!Bases.NonVirtualBases.insert(BaseDecl).second) {
// If this non-virtual base has been seen before, then the class has non-
// diamond shaped repeated inheritance.
Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
@@ -2988,3 +3079,128 @@ ItaniumCXXABI::RTTIUniquenessKind ItaniumCXXABI::classifyRTTIUniqueness(
assert(Linkage == llvm::GlobalValue::WeakODRLinkage);
return RUK_NonUniqueVisible;
}
+
+// Find out how to codegen the complete destructor and constructor
+namespace {
+enum class StructorCodegen { Emit, RAUW, Alias, COMDAT };
+}
+static StructorCodegen getCodegenToUse(CodeGenModule &CGM,
+ const CXXMethodDecl *MD) {
+ if (!CGM.getCodeGenOpts().CXXCtorDtorAliases)
+ return StructorCodegen::Emit;
+
+ // The complete and base structors are not equivalent if there are any virtual
+ // bases, so emit separate functions.
+ if (MD->getParent()->getNumVBases())
+ return StructorCodegen::Emit;
+
+ GlobalDecl AliasDecl;
+ if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ AliasDecl = GlobalDecl(DD, Dtor_Complete);
+ } else {
+ const auto *CD = cast<CXXConstructorDecl>(MD);
+ AliasDecl = GlobalDecl(CD, Ctor_Complete);
+ }
+ llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage(AliasDecl);
+
+ if (llvm::GlobalValue::isDiscardableIfUnused(Linkage))
+ return StructorCodegen::RAUW;
+
+ // FIXME: Should we allow available_externally aliases?
+ if (!llvm::GlobalAlias::isValidLinkage(Linkage))
+ return StructorCodegen::RAUW;
+
+ if (llvm::GlobalValue::isWeakForLinker(Linkage)) {
+ // Only ELF supports COMDATs with arbitrary names (C5/D5).
+ if (CGM.getTarget().getTriple().isOSBinFormatELF())
+ return StructorCodegen::COMDAT;
+ return StructorCodegen::Emit;
+ }
+
+ return StructorCodegen::Alias;
+}
+
+static void emitConstructorDestructorAlias(CodeGenModule &CGM,
+ GlobalDecl AliasDecl,
+ GlobalDecl TargetDecl) {
+ llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage(AliasDecl);
+
+ StringRef MangledName = CGM.getMangledName(AliasDecl);
+ llvm::GlobalValue *Entry = CGM.GetGlobalValue(MangledName);
+ if (Entry && !Entry->isDeclaration())
+ return;
+
+ auto *Aliasee = cast<llvm::GlobalValue>(CGM.GetAddrOfGlobal(TargetDecl));
+ llvm::PointerType *AliasType = Aliasee->getType();
+
+ // Create the alias with no name.
+ auto *Alias = llvm::GlobalAlias::create(
+ AliasType->getElementType(), 0, Linkage, "", Aliasee, &CGM.getModule());
+
+ // Switch any previous uses to the alias.
+ if (Entry) {
+ assert(Entry->getType() == AliasType &&
+ "declaration exists with different type");
+ Alias->takeName(Entry);
+ Entry->replaceAllUsesWith(Alias);
+ Entry->eraseFromParent();
+ } else {
+ Alias->setName(MangledName);
+ }
+
+ // Finally, set up the alias with its proper name and attributes.
+ CGM.setAliasAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
+}
+
+void ItaniumCXXABI::emitCXXStructor(const CXXMethodDecl *MD,
+ StructorType Type) {
+ auto *CD = dyn_cast<CXXConstructorDecl>(MD);
+ const CXXDestructorDecl *DD = CD ? nullptr : cast<CXXDestructorDecl>(MD);
+
+ StructorCodegen CGType = getCodegenToUse(CGM, MD);
+
+ if (Type == StructorType::Complete) {
+ GlobalDecl CompleteDecl;
+ GlobalDecl BaseDecl;
+ if (CD) {
+ CompleteDecl = GlobalDecl(CD, Ctor_Complete);
+ BaseDecl = GlobalDecl(CD, Ctor_Base);
+ } else {
+ CompleteDecl = GlobalDecl(DD, Dtor_Complete);
+ BaseDecl = GlobalDecl(DD, Dtor_Base);
+ }
+
+ if (CGType == StructorCodegen::Alias || CGType == StructorCodegen::COMDAT) {
+ emitConstructorDestructorAlias(CGM, CompleteDecl, BaseDecl);
+ return;
+ }
+
+ if (CGType == StructorCodegen::RAUW) {
+ StringRef MangledName = CGM.getMangledName(CompleteDecl);
+ auto *Aliasee = cast<llvm::GlobalValue>(CGM.GetAddrOfGlobal(BaseDecl));
+ CGM.addReplacement(MangledName, Aliasee);
+ return;
+ }
+ }
+
+ // The base destructor is equivalent to the base destructor of its
+ // base class if there is exactly one non-virtual base class with a
+ // non-trivial destructor, there are no fields with a non-trivial
+ // destructor, and the body of the destructor is trivial.
+ if (DD && Type == StructorType::Base && CGType != StructorCodegen::COMDAT &&
+ !CGM.TryEmitBaseDestructorAsAlias(DD))
+ return;
+
+ llvm::Function *Fn = CGM.codegenCXXStructor(MD, Type);
+
+ if (CGType == StructorCodegen::COMDAT) {
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ if (DD)
+ getMangleContext().mangleCXXDtorComdat(DD, Out);
+ else
+ getMangleContext().mangleCXXCtorComdat(CD, Out);
+ llvm::Comdat *C = CGM.getModule().getOrInsertComdat(Out.str());
+ Fn->setComdat(C);
+ }
+}
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index a69d4dd3fe86..c80db7d18a1b 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -43,6 +43,7 @@ public:
CompleteObjectLocatorType(nullptr) {}
bool HasThisReturn(GlobalDecl GD) const override;
+ bool hasMostDerivedReturn(GlobalDecl GD) const override;
bool classifyReturnType(CGFunctionInfo &FI) const override;
@@ -50,14 +51,26 @@ public:
bool isSRetParameterAfterThis() const override { return true; }
+ size_t getSrcArgforCopyCtor(const CXXConstructorDecl *CD,
+ FunctionArgList &Args) const override {
+ assert(Args.size() >= 2 &&
+ "expected the arglist to have at least two args!");
+ // The 'most_derived' parameter goes second if the ctor is variadic and
+ // has v-bases.
+ if (CD->getParent()->getNumVBases() > 0 &&
+ CD->getType()->castAs<FunctionProtoType>()->isVariadic())
+ return 2;
+ return 1;
+ }
+
StringRef GetPureVirtualCallName() override { return "_purecall"; }
- // No known support for deleted functions in MSVC yet, so this choice is
- // arbitrary.
StringRef GetDeletedVirtualCallName() override { return "_purecall"; }
- llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
- llvm::Value *ptr,
- QualType type) override;
+ void emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE,
+ llvm::Value *Ptr, QualType ElementType,
+ const CXXDestructorDecl *Dtor) override;
+
+ void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;
llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD,
const VPtrInfo *Info);
@@ -89,10 +102,6 @@ public:
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) override;
- void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType Type, CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) override;
-
llvm::BasicBlock *
EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
const CXXRecordDecl *RD) override;
@@ -134,10 +143,8 @@ public:
// lacks a definition for the destructor, non-base destructors must always
// delegate to or alias the base destructor.
- void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
- CXXDtorType Type,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) override;
+ void buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
+ SmallVectorImpl<CanQualType> &ArgTys) override;
/// Non-base dtors should be emitted as delegating thunks in this ABI.
bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
@@ -207,10 +214,11 @@ public:
llvm::Value *This,
llvm::Type *Ty) override;
- void EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType, SourceLocation CallLoc,
- llvm::Value *This) override;
+ llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ llvm::Value *This,
+ const CXXMemberCallExpr *CE) override;
void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, GlobalDecl GD,
CallArgList &CallArgs) override {
@@ -251,9 +259,22 @@ public:
llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
const ReturnAdjustment &RA) override;
+ void EmitThreadLocalInitFuncs(
+ CodeGenModule &CGM,
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
+ CXXThreadLocals,
+ ArrayRef<llvm::Function *> CXXThreadLocalInits,
+ ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) override;
+
+ bool usesThreadWrapperFunction() const override { return false; }
+ LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
+ QualType LValType) override;
+
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr,
bool PerformInit) override;
+ void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
+ llvm::Constant *Dtor, llvm::Constant *Addr) override;
// ==== Notes on array cookies =========
//
@@ -440,6 +461,7 @@ private:
int32_t VBPtrOffset,
int32_t VBTableOffset,
llvm::Value **VBPtr = nullptr) {
+ assert(VBTableOffset % 4 == 0 && "should be byte offset into table of i32s");
llvm::Value *VBPOffset = llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset),
*VBTOffset = llvm::ConstantInt::get(CGM.IntTy, VBTableOffset);
return GetVBaseOffsetFromVBPtr(CGF, Base, VBPOffset, VBTOffset, VBPtr);
@@ -482,6 +504,22 @@ public:
bool isZeroInitializable(const MemberPointerType *MPT) override;
+ bool isMemberPointerConvertible(const MemberPointerType *MPT) const override {
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ return RD->hasAttr<MSInheritanceAttr>();
+ }
+
+ bool isTypeInfoCalculable(QualType Ty) const override {
+ if (!CGCXXABI::isTypeInfoCalculable(Ty))
+ return false;
+ if (const auto *MPT = Ty->getAs<MemberPointerType>()) {
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ if (!RD->hasAttr<MSInheritanceAttr>())
+ return false;
+ }
+ return true;
+ }
+
llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT) override;
llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
@@ -516,6 +554,8 @@ public:
llvm::Value *&This, llvm::Value *MemPtr,
const MemberPointerType *MPT) override;
+ void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
+
private:
typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy;
typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VTablesMapTy;
@@ -577,8 +617,15 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const {
if (RD->hasNonTrivialCopyConstructor())
return RAA_Indirect;
- // Win64 passes objects larger than 8 bytes indirectly.
- if (getContext().getTypeSize(RD->getTypeForDecl()) > 64)
+ // If an object has a destructor, we'd really like to pass it indirectly
+ // because it allows us to elide copies. Unfortunately, MSVC makes that
+ // impossible for small types, which it will pass in a single register or
+ // stack slot. Most objects with dtors are large-ish, so handle that early.
+ // We can't call out all large objects as being indirect because there are
+ // multiple x64 calling conventions and the C++ ABI code shouldn't dictate
+ // how we pass large POD types.
+ if (RD->hasNonTrivialDestructor() &&
+ getContext().getTypeSize(RD->getTypeForDecl()) > 64)
return RAA_Indirect;
// We have a trivial copy constructor or no copy constructors, but we have
@@ -605,11 +652,43 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const {
llvm_unreachable("invalid enum");
}
-llvm::Value *MicrosoftCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
- llvm::Value *ptr,
- QualType type) {
- // FIXME: implement
- return ptr;
+void MicrosoftCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF,
+ const CXXDeleteExpr *DE,
+ llvm::Value *Ptr,
+ QualType ElementType,
+ const CXXDestructorDecl *Dtor) {
+ // FIXME: Provide a source location here even though there's no
+ // CXXMemberCallExpr for dtor call.
+ bool UseGlobalDelete = DE->isGlobalDelete();
+ CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
+ llvm::Value *MDThis =
+ EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, /*CE=*/nullptr);
+ if (UseGlobalDelete)
+ CGF.EmitDeleteCall(DE->getOperatorDelete(), MDThis, ElementType);
+}
+
+static llvm::Function *getRethrowFn(CodeGenModule &CGM) {
+ // _CxxThrowException takes two pointer width arguments: a value and a context
+ // object which points to a TypeInfo object.
+ llvm::Type *ArgTypes[] = {CGM.Int8PtrTy, CGM.Int8PtrTy};
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false);
+ auto *Fn = cast<llvm::Function>(
+ CGM.CreateRuntimeFunction(FTy, "_CxxThrowException"));
+ // _CxxThrowException is stdcall on 32-bit x86 platforms.
+ if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86)
+ Fn->setCallingConv(llvm::CallingConv::X86_StdCall);
+ return Fn;
+}
+
+void MicrosoftCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) {
+ llvm::Value *Args[] = {llvm::ConstantPointerNull::get(CGM.Int8PtrTy),
+ llvm::ConstantPointerNull::get(CGM.Int8PtrTy)};
+ auto *Fn = getRethrowFn(CGM);
+ if (isNoReturn)
+ CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, Args);
+ else
+ CGF.EmitRuntimeCallOrInvoke(Fn, Args);
}
/// \brief Gets the offset to the virtual base that contains the vfptr for
@@ -735,11 +814,9 @@ bool MicrosoftCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {
return false;
}
-llvm::Value *
-MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
- llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
+llvm::Value *MicrosoftCXXABI::GetVirtualBaseClassOffset(
+ CodeGenFunction &CGF, llvm::Value *This, const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) {
int64_t VBPtrChars =
getContext().getASTRecordLayout(ClassDecl).getVBPtrOffset().getQuantity();
llvm::Value *VBPtrOffset = llvm::ConstantInt::get(CGM.PtrDiffTy, VBPtrChars);
@@ -748,12 +825,12 @@ MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
IntSize *
CGM.getMicrosoftVTableContext().getVBTableIndex(ClassDecl, BaseClassDecl);
llvm::Value *VBTableOffset =
- llvm::ConstantInt::get(CGM.IntTy, VBTableChars.getQuantity());
+ llvm::ConstantInt::get(CGM.IntTy, VBTableChars.getQuantity());
llvm::Value *VBPtrToNewBase =
- GetVBaseOffsetFromVBPtr(CGF, This, VBPtrOffset, VBTableOffset);
+ GetVBaseOffsetFromVBPtr(CGF, This, VBPtrOffset, VBTableOffset);
VBPtrToNewBase =
- CGF.Builder.CreateSExtOrBitCast(VBPtrToNewBase, CGM.PtrDiffTy);
+ CGF.Builder.CreateSExtOrBitCast(VBPtrToNewBase, CGM.PtrDiffTy);
return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase);
}
@@ -761,6 +838,15 @@ bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const {
return isa<CXXConstructorDecl>(GD.getDecl());
}
+static bool isDeletingDtor(GlobalDecl GD) {
+ return isa<CXXDestructorDecl>(GD.getDecl()) &&
+ GD.getDtorType() == Dtor_Deleting;
+}
+
+bool MicrosoftCXXABI::hasMostDerivedReturn(GlobalDecl GD) const {
+ return isDeletingDtor(GD);
+}
+
bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl();
if (!RD)
@@ -782,23 +868,6 @@ bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
return false;
}
-void MicrosoftCXXABI::BuildConstructorSignature(
- const CXXConstructorDecl *Ctor, CXXCtorType Type, CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
-
- // All parameters are already in place except is_most_derived, which goes
- // after 'this' if it's variadic and last if it's not.
-
- const CXXRecordDecl *Class = Ctor->getParent();
- const FunctionProtoType *FPT = Ctor->getType()->castAs<FunctionProtoType>();
- if (Class->getNumVBases()) {
- if (FPT->isVariadic())
- ArgTys.insert(ArgTys.begin() + 1, CGM.getContext().IntTy);
- else
- ArgTys.push_back(CGM.getContext().IntTy);
- }
-}
-
llvm::BasicBlock *
MicrosoftCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
const CXXRecordDecl *RD) {
@@ -901,24 +970,36 @@ void MicrosoftCXXABI::EmitVBPtrStores(CodeGenFunction &CGF,
Offs += Layout.getVBaseClassOffset(VBT->getVBaseWithVPtr());
llvm::Value *VBPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(ThisInt8Ptr, Offs.getQuantity());
- VBPtr = CGF.Builder.CreateBitCast(VBPtr, GV->getType()->getPointerTo(0),
+ llvm::Value *GVPtr = CGF.Builder.CreateConstInBoundsGEP2_32(GV, 0, 0);
+ VBPtr = CGF.Builder.CreateBitCast(VBPtr, GVPtr->getType()->getPointerTo(0),
"vbptr." + VBT->ReusingBase->getName());
- CGF.Builder.CreateStore(GV, VBPtr);
+ CGF.Builder.CreateStore(GVPtr, VBPtr);
}
}
-void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
- CXXDtorType Type,
- CanQualType &ResTy,
+void
+MicrosoftCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
SmallVectorImpl<CanQualType> &ArgTys) {
- // 'this' is already in place
-
// TODO: 'for base' flag
-
- if (Type == Dtor_Deleting) {
+ if (T == StructorType::Deleting) {
// The scalar deleting destructor takes an implicit int parameter.
ArgTys.push_back(CGM.getContext().IntTy);
}
+ auto *CD = dyn_cast<CXXConstructorDecl>(MD);
+ if (!CD)
+ return;
+
+ // All parameters are already in place except is_most_derived, which goes
+ // after 'this' if it's variadic and last if it's not.
+
+ const CXXRecordDecl *Class = CD->getParent();
+ const FunctionProtoType *FPT = CD->getType()->castAs<FunctionProtoType>();
+ if (Class->getNumVBases()) {
+ if (FPT->isVariadic())
+ ArgTys.insert(ArgTys.begin() + 1, CGM.getContext().IntTy);
+ else
+ ArgTys.push_back(CGM.getContext().IntTy);
+ }
}
void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
@@ -1030,14 +1111,6 @@ llvm::Value *MicrosoftCXXABI::adjustThisArgumentForVirtualFunctionCall(
return This;
}
-static bool IsDeletingDtor(GlobalDecl GD) {
- const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
- if (isa<CXXDestructorDecl>(MD)) {
- return GD.getDtorType() == Dtor_Deleting;
- }
- return false;
-}
-
void MicrosoftCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params) {
@@ -1058,7 +1131,7 @@ void MicrosoftCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
else
Params.push_back(IsMostDerived);
getStructorImplicitParamDecl(CGF) = IsMostDerived;
- } else if (IsDeletingDtor(CGF.CurGD)) {
+ } else if (isDeletingDtor(CGF.CurGD)) {
ImplicitParamDecl *ShouldDelete
= ImplicitParamDecl::Create(Context, nullptr,
CGF.CurGD.getDecl()->getLocation(),
@@ -1104,6 +1177,9 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
/// HasThisReturn only specifies a contract, not the implementation
if (HasThisReturn(CGF.CurGD))
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
+ else if (hasMostDerivedReturn(CGF.CurGD))
+ CGF.Builder.CreateStore(CGF.EmitCastToVoidPtr(getThisValue(CGF)),
+ CGF.ReturnValue);
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
@@ -1115,7 +1191,7 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
"is_most_derived");
}
- if (IsDeletingDtor(CGF.CurGD)) {
+ if (isDeletingDtor(CGF.CurGD)) {
assert(getStructorImplicitParamDecl(CGF) &&
"no implicit parameter for a deleting destructor?");
getStructorImplicitParamValue(CGF)
@@ -1154,7 +1230,7 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *DD,
CXXDtorType Type, bool ForVirtualBase,
bool Delegating, llvm::Value *This) {
- llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
+ llvm::Value *Callee = CGM.getAddrOfCXXStructor(DD, getFromDtorType(Type));
if (DD->isVirtual()) {
assert(Type != CXXDtorType::Dtor_Deleting &&
@@ -1163,23 +1239,25 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
This, false);
}
- // FIXME: Provide a source location here.
- CGF.EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
- /*ImplicitParam=*/nullptr,
- /*ImplicitParamTy=*/QualType(), nullptr, nullptr);
+ CGF.EmitCXXStructorCall(DD, Callee, ReturnValueSlot(), This,
+ /*ImplicitParam=*/nullptr,
+ /*ImplicitParamTy=*/QualType(), nullptr,
+ getFromDtorType(Type));
}
void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
const CXXRecordDecl *RD) {
MicrosoftVTableContext &VFTContext = CGM.getMicrosoftVTableContext();
- VPtrInfoVector VFPtrs = VFTContext.getVFPtrOffsets(RD);
+ const VPtrInfoVector &VFPtrs = VFTContext.getVFPtrOffsets(RD);
for (VPtrInfo *Info : VFPtrs) {
llvm::GlobalVariable *VTable = getAddrOfVTable(RD, Info->FullOffsetInMDC);
if (VTable->hasInitializer())
continue;
- llvm::Constant *RTTI = getMSCompleteObjectLocator(RD, Info);
+ llvm::Constant *RTTI = getContext().getLangOpts().RTTIData
+ ? getMSCompleteObjectLocator(RD, Info)
+ : nullptr;
const VTableLayout &VTLayout =
VFTContext.getVFTableLayout(RD, Info->FullOffsetInMDC);
@@ -1240,7 +1318,7 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
MicrosoftVTableContext &VTContext = CGM.getMicrosoftVTableContext();
const VPtrInfoVector &VFPtrs = VTContext.getVFPtrOffsets(RD);
- if (DeferredVFTables.insert(RD)) {
+ if (DeferredVFTables.insert(RD).second) {
// We haven't processed this record type before.
// Queue up this v-table for possible deferred emission.
CGM.addDeferredVTable(RD);
@@ -1252,7 +1330,7 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) {
SmallString<256> Name;
mangleVFTableName(getMangleContext(), RD, VFPtrs[J], Name);
- if (!ObservedMangledNames.insert(Name.str()))
+ if (!ObservedMangledNames.insert(Name.str()).second)
llvm_unreachable("Already saw this mangling before?");
}
#endif
@@ -1372,29 +1450,30 @@ llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
return Builder.CreateLoad(VFuncPtr);
}
-void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor,
- CXXDtorType DtorType,
- SourceLocation CallLoc,
- llvm::Value *This) {
+llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall(
+ CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType,
+ llvm::Value *This, const CXXMemberCallExpr *CE) {
+ assert(CE == nullptr || CE->arg_begin() == CE->arg_end());
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
// We have only one destructor in the vftable but can get both behaviors
// by passing an implicit int parameter.
GlobalDecl GD(Dtor, Dtor_Deleting);
- const CGFunctionInfo *FInfo =
- &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
+ const CGFunctionInfo *FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration(
+ Dtor, StructorType::Deleting);
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
llvm::Value *Callee = getVirtualFunctionPointer(CGF, GD, This, Ty);
ASTContext &Context = CGF.getContext();
- llvm::Value *ImplicitParam =
- llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(CGF.getLLVMContext()),
- DtorType == Dtor_Deleting);
+ llvm::Value *ImplicitParam = llvm::ConstantInt::get(
+ llvm::IntegerType::getInt32Ty(CGF.getLLVMContext()),
+ DtorType == Dtor_Deleting);
This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
- CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
- ImplicitParam, Context.IntTy, nullptr, nullptr);
+ RValue RV = CGF.EmitCXXStructorCall(Dtor, Callee, ReturnValueSlot(), This,
+ ImplicitParam, Context.IntTy, CE,
+ StructorType::Deleting);
+ return RV.getScalarVal();
}
const VBTableGlobals &
@@ -1427,6 +1506,9 @@ MicrosoftCXXABI::enumerateVBTables(const CXXRecordDecl *RD) {
llvm::Function *MicrosoftCXXABI::EmitVirtualMemPtrThunk(
const CXXMethodDecl *MD,
const MicrosoftVTableContext::MethodVFTableLocation &ML) {
+ assert(!isa<CXXConstructorDecl>(MD) && !isa<CXXDestructorDecl>(MD) &&
+ "can't form pointers to ctors or virtual dtors");
+
// Calculate the mangled name.
SmallString<256> ThunkName;
llvm::raw_svector_ostream Out(ThunkName);
@@ -1438,7 +1520,7 @@ llvm::Function *MicrosoftCXXABI::EmitVirtualMemPtrThunk(
return cast<llvm::Function>(GV);
// Create the llvm::Function.
- const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(MD);
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeMSMemberPointerThunk(MD);
llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
llvm::Function *ThunkFn =
llvm::Function::Create(ThunkTy, llvm::Function::ExternalLinkage,
@@ -1452,44 +1534,33 @@ llvm::Function *MicrosoftCXXABI::EmitVirtualMemPtrThunk(
CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn);
CGM.SetLLVMFunctionAttributesForDefinition(MD, ThunkFn);
+ // These thunks can be compared, so they are not unnamed.
+ ThunkFn->setUnnamedAddr(false);
+
// Start codegen.
CodeGenFunction CGF(CGM);
- CGF.StartThunk(ThunkFn, MD, FnInfo);
+ CGF.CurGD = GlobalDecl(MD);
+ CGF.CurFuncIsThunk = true;
+
+ // Build FunctionArgs, but only include the implicit 'this' parameter
+ // declaration.
+ FunctionArgList FunctionArgs;
+ buildThisParam(CGF, FunctionArgs);
+
+ // Start defining the function.
+ CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
+ FunctionArgs, MD->getLocation(), SourceLocation());
+ EmitThisParam(CGF);
// Load the vfptr and then callee from the vftable. The callee should have
// adjusted 'this' so that the vfptr is at offset zero.
- llvm::Value *This = CGF.LoadCXXThis();
- llvm::Value *VTable =
- CGF.GetVTablePtr(This, ThunkTy->getPointerTo()->getPointerTo());
+ llvm::Value *VTable = CGF.GetVTablePtr(
+ getThisValue(CGF), ThunkTy->getPointerTo()->getPointerTo());
llvm::Value *VFuncPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
llvm::Value *Callee = CGF.Builder.CreateLoad(VFuncPtr);
- unsigned CallingConv;
- CodeGen::AttributeListType AttributeList;
- CGM.ConstructAttributeList(FnInfo, MD, AttributeList, CallingConv, true);
- llvm::AttributeSet Attrs =
- llvm::AttributeSet::get(CGF.getLLVMContext(), AttributeList);
-
- // Do a musttail call with perfect argument forwarding. Any inalloca argument
- // will be forwarded in place without any copy.
- SmallVector<llvm::Value *, 8> Args;
- for (llvm::Argument &A : ThunkFn->args())
- Args.push_back(&A);
- llvm::CallInst *Call = CGF.Builder.CreateCall(Callee, Args);
- Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
- Call->setAttributes(Attrs);
- Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
-
- if (Call->getType()->isVoidTy())
- CGF.Builder.CreateRetVoid();
- else
- CGF.Builder.CreateRet(Call);
-
- // Finish the function to maintain CodeGenFunction invariants.
- // FIXME: Don't emit unreachable code.
- CGF.EmitBlock(CGF.createBasicBlock());
- CGF.FinishFunction();
+ CGF.EmitMustTailThunk(MD, getThisValue(CGF), Callee);
return ThunkFn;
}
@@ -1703,6 +1774,86 @@ llvm::Value* MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
cookieSize.getQuantity());
}
+static void emitGlobalDtorWithTLRegDtor(CodeGenFunction &CGF, const VarDecl &VD,
+ llvm::Constant *Dtor,
+ llvm::Constant *Addr) {
+ // Create a function which calls the destructor.
+ llvm::Constant *DtorStub = CGF.createAtExitStub(VD, Dtor, Addr);
+
+ // extern "C" int __tlregdtor(void (*f)(void));
+ llvm::FunctionType *TLRegDtorTy = llvm::FunctionType::get(
+ CGF.IntTy, DtorStub->getType(), /*IsVarArg=*/false);
+
+ llvm::Constant *TLRegDtor =
+ CGF.CGM.CreateRuntimeFunction(TLRegDtorTy, "__tlregdtor");
+ if (llvm::Function *TLRegDtorFn = dyn_cast<llvm::Function>(TLRegDtor))
+ TLRegDtorFn->setDoesNotThrow();
+
+ CGF.EmitNounwindRuntimeCall(TLRegDtor, DtorStub);
+}
+
+void MicrosoftCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
+ llvm::Constant *Dtor,
+ llvm::Constant *Addr) {
+ if (D.getTLSKind())
+ return emitGlobalDtorWithTLRegDtor(CGF, D, Dtor, Addr);
+
+ // The default behavior is to use atexit.
+ CGF.registerGlobalDtorWithAtExit(D, Dtor, Addr);
+}
+
+void MicrosoftCXXABI::EmitThreadLocalInitFuncs(
+ CodeGenModule &CGM,
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
+ CXXThreadLocals,
+ ArrayRef<llvm::Function *> CXXThreadLocalInits,
+ ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) {
+ // This will create a GV in the .CRT$XDU section. It will point to our
+ // initialization function. The CRT will call all of these function
+ // pointers at start-up time and, eventually, at thread-creation time.
+ auto AddToXDU = [&CGM](llvm::Function *InitFunc) {
+ llvm::GlobalVariable *InitFuncPtr = new llvm::GlobalVariable(
+ CGM.getModule(), InitFunc->getType(), /*IsConstant=*/true,
+ llvm::GlobalVariable::InternalLinkage, InitFunc,
+ Twine(InitFunc->getName(), "$initializer$"));
+ InitFuncPtr->setSection(".CRT$XDU");
+ // This variable has discardable linkage, we have to add it to @llvm.used to
+ // ensure it won't get discarded.
+ CGM.addUsedGlobal(InitFuncPtr);
+ return InitFuncPtr;
+ };
+
+ std::vector<llvm::Function *> NonComdatInits;
+ for (size_t I = 0, E = CXXThreadLocalInitVars.size(); I != E; ++I) {
+ llvm::GlobalVariable *GV = CXXThreadLocalInitVars[I];
+ llvm::Function *F = CXXThreadLocalInits[I];
+
+ // If the GV is already in a comdat group, then we have to join it.
+ if (llvm::Comdat *C = GV->getComdat())
+ AddToXDU(F)->setComdat(C);
+ else
+ NonComdatInits.push_back(F);
+ }
+
+ if (!NonComdatInits.empty()) {
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+ llvm::Function *InitFunc = CGM.CreateGlobalInitOrDestructFunction(
+ FTy, "__tls_init", SourceLocation(),
+ /*TLS=*/true);
+ CodeGenFunction(CGM).GenerateCXXGlobalInitFunc(InitFunc, NonComdatInits);
+
+ AddToXDU(InitFunc);
+ }
+}
+
+LValue MicrosoftCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
+ const VarDecl *VD,
+ QualType LValType) {
+ CGF.CGM.ErrorUnsupported(VD, "thread wrappers");
+ return LValue();
+}
+
void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *GV,
bool PerformInit) {
@@ -1949,8 +2100,8 @@ MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
CodeGenTypes &Types = CGM.getTypes();
llvm::Constant *FirstField;
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
if (!MD->isVirtual()) {
- const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
llvm::Type *Ty;
// Check whether the function has a computable LLVM signature.
if (Types.isFuncTypeConvertible(FPT)) {
@@ -1966,14 +2117,14 @@ MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
} else {
MicrosoftVTableContext::MethodVFTableLocation ML =
CGM.getMicrosoftVTableContext().getMethodVFTableLocation(MD);
- if (MD->isVariadic()) {
- CGM.ErrorUnsupported(MD, "pointer to variadic virtual member function");
- FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
- } else if (!CGM.getTypes().isFuncTypeConvertible(
- MD->getType()->castAs<FunctionType>())) {
+ if (!CGM.getTypes().isFuncTypeConvertible(
+ MD->getType()->castAs<FunctionType>())) {
CGM.ErrorUnsupported(MD, "pointer to virtual member function with "
"incomplete return or parameter type");
FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
+ } else if (FPT->getCallConv() == CC_X86FastCall) {
+ CGM.ErrorUnsupported(MD, "pointer to fastcall virtual member function");
+ FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
} else if (ML.VBase) {
CGM.ErrorUnsupported(MD, "pointer to virtual member function overriding "
"member function in virtual base class");
@@ -2128,11 +2279,17 @@ MicrosoftCXXABI::GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
llvm::Value *VBPtr =
Builder.CreateInBoundsGEP(This, VBPtrOffset, "vbptr");
if (VBPtrOut) *VBPtrOut = VBPtr;
- VBPtr = Builder.CreateBitCast(VBPtr, CGM.Int8PtrTy->getPointerTo(0));
+ VBPtr = Builder.CreateBitCast(VBPtr,
+ CGM.Int32Ty->getPointerTo(0)->getPointerTo(0));
llvm::Value *VBTable = Builder.CreateLoad(VBPtr, "vbtable");
+ // Translate from byte offset to table index. It improves analyzability.
+ llvm::Value *VBTableIndex = Builder.CreateAShr(
+ VBTableOffset, llvm::ConstantInt::get(VBTableOffset->getType(), 2),
+ "vbtindex", /*isExact=*/true);
+
// Load an i32 offset from the vb-table.
- llvm::Value *VBaseOffs = Builder.CreateInBoundsGEP(VBTable, VBTableOffset);
+ llvm::Value *VBaseOffs = Builder.CreateInBoundsGEP(VBTable, VBTableIndex);
VBaseOffs = Builder.CreateBitCast(VBaseOffs, CGM.Int32Ty->getPointerTo(0));
return Builder.CreateLoad(VBaseOffs, "vbase_offs");
}
@@ -2645,11 +2802,11 @@ detectAmbiguousBases(SmallVectorImpl<MSRTTIClass> &Classes) {
llvm::SmallPtrSet<const CXXRecordDecl *, 8> AmbiguousBases;
for (MSRTTIClass *Class = &Classes.front(); Class <= &Classes.back();) {
if ((Class->Flags & MSRTTIClass::IsVirtual) &&
- !VirtualBases.insert(Class->RD)) {
+ !VirtualBases.insert(Class->RD).second) {
Class = MSRTTIClass::getNextChild(Class);
continue;
}
- if (!UniqueBases.insert(Class->RD))
+ if (!UniqueBases.insert(Class->RD).second)
AmbiguousBases.insert(Class->RD);
Class++;
}
@@ -2875,3 +3032,45 @@ MicrosoftCXXABI::getMSCompleteObjectLocator(const CXXRecordDecl *RD,
const VPtrInfo *Info) {
return MSRTTIBuilder(*this, RD).getCompleteObjectLocator(Info);
}
+
+static void emitCXXConstructor(CodeGenModule &CGM,
+ const CXXConstructorDecl *ctor,
+ StructorType ctorType) {
+ // There are no constructor variants, always emit the complete destructor.
+ CGM.codegenCXXStructor(ctor, StructorType::Complete);
+}
+
+static void emitCXXDestructor(CodeGenModule &CGM, const CXXDestructorDecl *dtor,
+ StructorType dtorType) {
+ // The complete destructor is equivalent to the base destructor for
+ // classes with no virtual bases, so try to emit it as an alias.
+ if (!dtor->getParent()->getNumVBases() &&
+ (dtorType == StructorType::Complete || dtorType == StructorType::Base)) {
+ bool ProducedAlias = !CGM.TryEmitDefinitionAsAlias(
+ GlobalDecl(dtor, Dtor_Complete), GlobalDecl(dtor, Dtor_Base), true);
+ if (ProducedAlias) {
+ if (dtorType == StructorType::Complete)
+ return;
+ if (dtor->isVirtual())
+ CGM.getVTables().EmitThunks(GlobalDecl(dtor, Dtor_Complete));
+ }
+ }
+
+ // The base destructor is equivalent to the base destructor of its
+ // base class if there is exactly one non-virtual base class with a
+ // non-trivial destructor, there are no fields with a non-trivial
+ // destructor, and the body of the destructor is trivial.
+ if (dtorType == StructorType::Base && !CGM.TryEmitBaseDestructorAsAlias(dtor))
+ return;
+
+ CGM.codegenCXXStructor(dtor, dtorType);
+}
+
+void MicrosoftCXXABI::emitCXXStructor(const CXXMethodDecl *MD,
+ StructorType Type) {
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
+ emitCXXConstructor(CGM, CD, Type);
+ return;
+ }
+ emitCXXDestructor(CGM, cast<CXXDestructorDecl>(MD), Type);
+}
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index c5d18d3286a7..4f1a82e0248d 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -33,17 +33,41 @@ namespace {
std::unique_ptr<const llvm::DataLayout> TD;
ASTContext *Ctx;
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
+
+ unsigned HandlingTopLevelDecls;
+ struct HandlingTopLevelDeclRAII {
+ CodeGeneratorImpl &Self;
+ HandlingTopLevelDeclRAII(CodeGeneratorImpl &Self) : Self(Self) {
+ ++Self.HandlingTopLevelDecls;
+ }
+ ~HandlingTopLevelDeclRAII() {
+ if (--Self.HandlingTopLevelDecls == 0)
+ Self.EmitDeferredDecls();
+ }
+ };
+
+ CoverageSourceInfo *CoverageInfo;
+
protected:
std::unique_ptr<llvm::Module> M;
std::unique_ptr<CodeGen::CodeGenModule> Builder;
+ private:
+ SmallVector<CXXMethodDecl *, 8> DeferredInlineMethodDefinitions;
+
public:
CodeGeneratorImpl(DiagnosticsEngine &diags, const std::string& ModuleName,
- const CodeGenOptions &CGO, llvm::LLVMContext& C)
- : Diags(diags), CodeGenOpts(CGO),
+ const CodeGenOptions &CGO, llvm::LLVMContext& C,
+ CoverageSourceInfo *CoverageInfo = nullptr)
+ : Diags(diags), Ctx(nullptr), CodeGenOpts(CGO), HandlingTopLevelDecls(0),
+ CoverageInfo(CoverageInfo),
M(new llvm::Module(ModuleName, C)) {}
- virtual ~CodeGeneratorImpl() {}
+ virtual ~CodeGeneratorImpl() {
+ // There should normally not be any leftover inline method definitions.
+ assert(DeferredInlineMethodDefinitions.empty() ||
+ Diags.hasErrorOccurred());
+ }
llvm::Module* GetModule() override {
return M.get();
@@ -73,7 +97,7 @@ namespace {
M->setDataLayout(Ctx->getTargetInfo().getTargetDescription());
TD.reset(new llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription()));
Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, *M, *TD,
- Diags));
+ Diags, CoverageInfo));
for (size_t i = 0, e = CodeGenOpts.DependentLibraries.size(); i < e; ++i)
HandleDependentLibrary(CodeGenOpts.DependentLibraries[i]);
@@ -90,18 +114,28 @@ namespace {
if (Diags.hasErrorOccurred())
return true;
+ HandlingTopLevelDeclRAII HandlingDecl(*this);
+
// Make sure to emit all elements of a Decl.
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
Builder->EmitTopLevelDecl(*I);
- // Emit any deferred inline method definitions.
- for (CXXMethodDecl *MD : DeferredInlineMethodDefinitions)
- Builder->EmitTopLevelDecl(MD);
- DeferredInlineMethodDefinitions.clear();
-
return true;
}
+ void EmitDeferredDecls() {
+ if (DeferredInlineMethodDefinitions.empty())
+ return;
+
+ // Emit any deferred inline method definitions. Note that more deferred
+ // methods may be added during this loop, since ASTConsumer callbacks
+ // can be invoked if AST inspection results in declarations being added.
+ HandlingTopLevelDeclRAII HandlingDecl(*this);
+ for (unsigned I = 0; I != DeferredInlineMethodDefinitions.size(); ++I)
+ Builder->EmitTopLevelDecl(DeferredInlineMethodDefinitions[I]);
+ DeferredInlineMethodDefinitions.clear();
+ }
+
void HandleInlineMethodDefinition(CXXMethodDecl *D) override {
if (Diags.hasErrorOccurred())
return;
@@ -117,6 +151,12 @@ namespace {
// void foo() { bar(); }
// } A;
DeferredInlineMethodDefinitions.push_back(D);
+
+ // Provide some coverage mapping even for methods that aren't emitted.
+ // Don't do this for templated classes though, as they may not be
+ // instantiable.
+ if (!D->getParent()->getDescribedClassTemplate())
+ Builder->AddDeferredUnusedCoverageMapping(D);
}
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
@@ -190,9 +230,6 @@ namespace {
void HandleDependentLibrary(llvm::StringRef Lib) override {
Builder->AddDependentLib(Lib);
}
-
- private:
- std::vector<CXXMethodDecl *> DeferredInlineMethodDefinitions;
};
}
@@ -202,6 +239,7 @@ CodeGenerator *clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags,
const std::string& ModuleName,
const CodeGenOptions &CGO,
const TargetOptions &/*TO*/,
- llvm::LLVMContext& C) {
- return new CodeGeneratorImpl(Diags, ModuleName, CGO, C);
+ llvm::LLVMContext& C,
+ CoverageSourceInfo *CoverageInfo) {
+ return new CodeGeneratorImpl(Diags, ModuleName, CGO, C, CoverageInfo);
}
diff --git a/lib/CodeGen/SanitizerBlacklist.cpp b/lib/CodeGen/SanitizerBlacklist.cpp
deleted file mode 100644
index 9f1ddc8e7d7b..000000000000
--- a/lib/CodeGen/SanitizerBlacklist.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-//===--- SanitizerBlacklist.cpp - Blacklist for sanitizers ----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// User-provided blacklist used to disable/alter instrumentation done in
-// sanitizers.
-//
-//===----------------------------------------------------------------------===//
-#include "SanitizerBlacklist.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/GlobalValue.h"
-#include "llvm/IR/Module.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-static StringRef GetGlobalTypeString(const llvm::GlobalValue &G) {
- // Types of GlobalVariables are always pointer types.
- llvm::Type *GType = G.getType()->getElementType();
- // For now we support blacklisting struct types only.
- if (llvm::StructType *SGType = dyn_cast<llvm::StructType>(GType)) {
- if (!SGType->isLiteral())
- return SGType->getName();
- }
- return "<unknown type>";
-}
-
-bool SanitizerBlacklist::isIn(const llvm::Module &M,
- const StringRef Category) const {
- return SCL->inSection("src", M.getModuleIdentifier(), Category);
-}
-
-bool SanitizerBlacklist::isIn(const llvm::Function &F) const {
- return isIn(*F.getParent()) ||
- SCL->inSection("fun", F.getName(), "");
-}
-
-bool SanitizerBlacklist::isIn(const llvm::GlobalVariable &G,
- const StringRef Category) const {
- return isIn(*G.getParent(), Category) ||
- SCL->inSection("global", G.getName(), Category) ||
- SCL->inSection("type", GetGlobalTypeString(G), Category);
-}
-
-bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName) const {
- return SCL->inSection("type", MangledTypeName);
-}
diff --git a/lib/CodeGen/SanitizerBlacklist.h b/lib/CodeGen/SanitizerBlacklist.h
deleted file mode 100644
index 659441dfe346..000000000000
--- a/lib/CodeGen/SanitizerBlacklist.h
+++ /dev/null
@@ -1,46 +0,0 @@
-//===--- SanitizerBlacklist.h - Blacklist for sanitizers --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// User-provided blacklist used to disable/alter instrumentation done in
-// sanitizers.
-//
-//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_SANITIZERBLACKLIST_H
-#define CLANG_CODEGEN_SANITIZERBLACKLIST_H
-
-#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/SpecialCaseList.h"
-#include <memory>
-
-namespace llvm {
-class GlobalVariable;
-class Function;
-class Module;
-}
-
-namespace clang {
-namespace CodeGen {
-
-class SanitizerBlacklist {
- std::unique_ptr<llvm::SpecialCaseList> SCL;
-
-public:
- SanitizerBlacklist(llvm::SpecialCaseList *SCL) : SCL(SCL) {}
- bool isIn(const llvm::Module &M,
- const StringRef Category = StringRef()) const;
- bool isIn(const llvm::Function &F) const;
- bool isIn(const llvm::GlobalVariable &G,
- const StringRef Category = StringRef()) const;
- bool isBlacklistedType(StringRef MangledTypeName) const;
-};
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/lib/CodeGen/SanitizerMetadata.cpp b/lib/CodeGen/SanitizerMetadata.cpp
new file mode 100644
index 000000000000..7c38b2807e95
--- /dev/null
+++ b/lib/CodeGen/SanitizerMetadata.cpp
@@ -0,0 +1,92 @@
+//===--- SanitizerMetadata.cpp - Blacklist for sanitizers -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Class which emits metadata consumed by sanitizer instrumentation passes.
+//
+//===----------------------------------------------------------------------===//
+#include "SanitizerMetadata.h"
+#include "CodeGenModule.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/Constants.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {}
+
+void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
+ SourceLocation Loc, StringRef Name,
+ QualType Ty, bool IsDynInit,
+ bool IsBlacklisted) {
+ if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Address))
+ return;
+ IsDynInit &= !CGM.isInSanitizerBlacklist(GV, Loc, Ty, "init");
+ IsBlacklisted |= CGM.isInSanitizerBlacklist(GV, Loc, Ty);
+
+ llvm::Metadata *LocDescr = nullptr;
+ llvm::Metadata *GlobalName = nullptr;
+ llvm::LLVMContext &VMContext = CGM.getLLVMContext();
+ if (!IsBlacklisted) {
+ // Don't generate source location and global name if it is blacklisted -
+ // it won't be instrumented anyway.
+ LocDescr = getLocationMetadata(Loc);
+ if (!Name.empty())
+ GlobalName = llvm::MDString::get(VMContext, Name);
+ }
+
+ llvm::Metadata *GlobalMetadata[] = {
+ llvm::ConstantAsMetadata::get(GV), LocDescr, GlobalName,
+ llvm::ConstantAsMetadata::get(
+ llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsDynInit)),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ llvm::Type::getInt1Ty(VMContext), IsBlacklisted))};
+
+ llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalMetadata);
+ llvm::NamedMDNode *AsanGlobals =
+ CGM.getModule().getOrInsertNamedMetadata("llvm.asan.globals");
+ AsanGlobals->addOperand(ThisGlobal);
+}
+
+void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
+ const VarDecl &D, bool IsDynInit) {
+ if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Address))
+ return;
+ std::string QualName;
+ llvm::raw_string_ostream OS(QualName);
+ D.printQualifiedName(OS);
+ reportGlobalToASan(GV, D.getLocation(), OS.str(), D.getType(), IsDynInit);
+}
+
+void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
+ // For now, just make sure the global is not modified by the ASan
+ // instrumentation.
+ if (CGM.getLangOpts().Sanitize.has(SanitizerKind::Address))
+ reportGlobalToASan(GV, SourceLocation(), "", QualType(), false, true);
+}
+
+void SanitizerMetadata::disableSanitizerForInstruction(llvm::Instruction *I) {
+ I->setMetadata(CGM.getModule().getMDKindID("nosanitize"),
+ llvm::MDNode::get(CGM.getLLVMContext(), None));
+}
+
+llvm::MDNode *SanitizerMetadata::getLocationMetadata(SourceLocation Loc) {
+ PresumedLoc PLoc = CGM.getContext().getSourceManager().getPresumedLoc(Loc);
+ if (!PLoc.isValid())
+ return nullptr;
+ llvm::LLVMContext &VMContext = CGM.getLLVMContext();
+ llvm::Metadata *LocMetadata[] = {
+ llvm::MDString::get(VMContext, PLoc.getFilename()),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), PLoc.getLine())),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), PLoc.getColumn())),
+ };
+ return llvm::MDNode::get(VMContext, LocMetadata);
+}
diff --git a/lib/CodeGen/SanitizerMetadata.h b/lib/CodeGen/SanitizerMetadata.h
new file mode 100644
index 000000000000..d2f0651159a2
--- /dev/null
+++ b/lib/CodeGen/SanitizerMetadata.h
@@ -0,0 +1,53 @@
+//===--- SanitizerMetadata.h - Metadata for sanitizers ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Class which emits metadata consumed by sanitizer instrumentation passes.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LIB_CODEGEN_SANITIZERMETADATA_H
+#define LLVM_CLANG_LIB_CODEGEN_SANITIZERMETADATA_H
+
+#include "clang/AST/Type.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+
+namespace llvm {
+class GlobalVariable;
+class Instruction;
+class MDNode;
+}
+
+namespace clang {
+class VarDecl;
+
+namespace CodeGen {
+
+class CodeGenModule;
+
+class SanitizerMetadata {
+ SanitizerMetadata(const SanitizerMetadata &) LLVM_DELETED_FUNCTION;
+ void operator=(const SanitizerMetadata &) LLVM_DELETED_FUNCTION;
+
+ CodeGenModule &CGM;
+public:
+ SanitizerMetadata(CodeGenModule &CGM);
+ void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D,
+ bool IsDynInit = false);
+ void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc,
+ StringRef Name, QualType Ty, bool IsDynInit = false,
+ bool IsBlacklisted = false);
+ void disableSanitizerForGlobal(llvm::GlobalVariable *GV);
+ void disableSanitizerForInstruction(llvm::Instruction *I);
+private:
+ llvm::MDNode *getLocationMetadata(SourceLocation Loc);
+};
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index f75e59d6f2d8..6ad349515769 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -15,15 +15,16 @@
#include "TargetInfo.h"
#include "ABIInfo.h"
#include "CGCXXABI.h"
+#include "CGValue.h"
#include "CodeGenFunction.h"
#include "clang/AST/RecordLayout.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
-
#include <algorithm> // std::sort
using namespace clang;
@@ -64,6 +65,19 @@ static CGCXXABI::RecordArgABI getRecordArgABI(QualType T,
return getRecordArgABI(RT, CXXABI);
}
+/// Pass transparent unions as if they were the type of the first element. Sema
+/// should ensure that all elements of the union have the same "machine type".
+static QualType useFirstFieldIfTransparentUnion(QualType Ty) {
+ if (const RecordType *UT = Ty->getAsUnionType()) {
+ const RecordDecl *UD = UT->getDecl();
+ if (UD->hasAttr<TransparentUnionAttr>()) {
+ assert(!UD->field_empty() && "sema created an empty transparent union");
+ return UD->field_begin()->getType();
+ }
+ }
+ return Ty;
+}
+
CGCXXABI &ABIInfo::getCXXABI() const {
return CGT.getCXXABI();
}
@@ -84,6 +98,15 @@ const TargetInfo &ABIInfo::getTarget() const {
return CGT.getTarget();
}
+bool ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
+ return false;
+}
+
+bool ABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base,
+ uint64_t Members) const {
+ return false;
+}
+
void ABIArgInfo::dump() const {
raw_ostream &OS = llvm::errs();
OS << "(ABIArgInfo Kind=";
@@ -498,18 +521,39 @@ static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
return Ty;
}
+/// Returns true if this type can be passed in SSE registers with the
+/// X86_VectorCall calling convention. Shared between x86_32 and x86_64.
+static bool isX86VectorTypeForVectorCall(ASTContext &Context, QualType Ty) {
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half)
+ return true;
+ } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ // vectorcall can pass XMM, YMM, and ZMM vectors. We don't pass SSE1 MMX
+ // registers specially.
+ unsigned VecSize = Context.getTypeSize(VT);
+ if (VecSize == 128 || VecSize == 256 || VecSize == 512)
+ return true;
+ }
+ return false;
+}
+
+/// Returns true if this aggregate is small enough to be passed in SSE registers
+/// in the X86_VectorCall calling convention. Shared between x86_32 and x86_64.
+static bool isX86VectorCallAggregateSmallEnough(uint64_t NumMembers) {
+ return NumMembers <= 4;
+}
+
//===----------------------------------------------------------------------===//
// X86-32 ABI Implementation
//===----------------------------------------------------------------------===//
/// \brief Similar to llvm::CCState, but for Clang.
struct CCState {
- CCState(unsigned CC) : CC(CC), FreeRegs(0) {}
+ CCState(unsigned CC) : CC(CC), FreeRegs(0), FreeSSERegs(0) {}
unsigned CC;
unsigned FreeRegs;
- unsigned StackOffset;
- bool UseInAlloca;
+ unsigned FreeSSERegs;
};
/// X86_32ABIInfo - The X86-32 ABI information.
@@ -530,6 +574,17 @@ class X86_32ABIInfo : public ABIInfo {
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
}
+ bool isHomogeneousAggregateBaseType(QualType Ty) const override {
+ // FIXME: Assumes vectorcall is in use.
+ return isX86VectorTypeForVectorCall(getContext(), Ty);
+ }
+
+ bool isHomogeneousAggregateSmallEnough(const Type *Ty,
+ uint64_t NumMembers) const override {
+ // FIXME: Assumes vectorcall is in use.
+ return isX86VectorCallAggregateSmallEnough(NumMembers);
+ }
+
bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context) const;
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
@@ -593,6 +648,14 @@ public:
return X86AdjustInlineAsmType(CGF, Constraint, Ty);
}
+ void addReturnRegisterOutputs(CodeGenFunction &CGF, LValue ReturnValue,
+ std::string &Constraints,
+ std::vector<llvm::Type *> &ResultRegTypes,
+ std::vector<llvm::Type *> &ResultTruncRegTypes,
+ std::vector<LValue> &ResultRegDests,
+ std::string &AsmString,
+ unsigned NumOutputs) const override;
+
llvm::Constant *
getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override {
unsigned Sig = (0xeb << 0) | // jmp rel8
@@ -606,6 +669,85 @@ public:
}
+/// Rewrite input constraint references after adding some output constraints.
+/// In the case where there is one output and one input and we add one output,
+/// we need to replace all operand references greater than or equal to 1:
+/// mov $0, $1
+/// mov eax, $1
+/// The result will be:
+/// mov $0, $2
+/// mov eax, $2
+static void rewriteInputConstraintReferences(unsigned FirstIn,
+ unsigned NumNewOuts,
+ std::string &AsmString) {
+ std::string Buf;
+ llvm::raw_string_ostream OS(Buf);
+ size_t Pos = 0;
+ while (Pos < AsmString.size()) {
+ size_t DollarStart = AsmString.find('$', Pos);
+ if (DollarStart == std::string::npos)
+ DollarStart = AsmString.size();
+ size_t DollarEnd = AsmString.find_first_not_of('$', DollarStart);
+ if (DollarEnd == std::string::npos)
+ DollarEnd = AsmString.size();
+ OS << StringRef(&AsmString[Pos], DollarEnd - Pos);
+ Pos = DollarEnd;
+ size_t NumDollars = DollarEnd - DollarStart;
+ if (NumDollars % 2 != 0 && Pos < AsmString.size()) {
+ // We have an operand reference.
+ size_t DigitStart = Pos;
+ size_t DigitEnd = AsmString.find_first_not_of("0123456789", DigitStart);
+ if (DigitEnd == std::string::npos)
+ DigitEnd = AsmString.size();
+ StringRef OperandStr(&AsmString[DigitStart], DigitEnd - DigitStart);
+ unsigned OperandIndex;
+ if (!OperandStr.getAsInteger(10, OperandIndex)) {
+ if (OperandIndex >= FirstIn)
+ OperandIndex += NumNewOuts;
+ OS << OperandIndex;
+ } else {
+ OS << OperandStr;
+ }
+ Pos = DigitEnd;
+ }
+ }
+ AsmString = std::move(OS.str());
+}
+
+/// Add output constraints for EAX:EDX because they are return registers.
+void X86_32TargetCodeGenInfo::addReturnRegisterOutputs(
+ CodeGenFunction &CGF, LValue ReturnSlot, std::string &Constraints,
+ std::vector<llvm::Type *> &ResultRegTypes,
+ std::vector<llvm::Type *> &ResultTruncRegTypes,
+ std::vector<LValue> &ResultRegDests, std::string &AsmString,
+ unsigned NumOutputs) const {
+ uint64_t RetWidth = CGF.getContext().getTypeSize(ReturnSlot.getType());
+
+ // Use the EAX constraint if the width is 32 or smaller and EAX:EDX if it is
+ // larger.
+ if (!Constraints.empty())
+ Constraints += ',';
+ if (RetWidth <= 32) {
+ Constraints += "={eax}";
+ ResultRegTypes.push_back(CGF.Int32Ty);
+ } else {
+ // Use the 'A' constraint for EAX:EDX.
+ Constraints += "=A";
+ ResultRegTypes.push_back(CGF.Int64Ty);
+ }
+
+ // Truncate EAX or EAX:EDX to an integer of the appropriate size.
+ llvm::Type *CoerceTy = llvm::IntegerType::get(CGF.getLLVMContext(), RetWidth);
+ ResultTruncRegTypes.push_back(CoerceTy);
+
+ // Coerce the integer by bitcasting the return slot pointer.
+ ReturnSlot.setAddress(CGF.Builder.CreateBitCast(ReturnSlot.getAddress(),
+ CoerceTy->getPointerTo()));
+ ResultRegDests.push_back(ReturnSlot);
+
+ rewriteInputConstraintReferences(NumOutputs, 1, AsmString);
+}
+
/// shouldReturnTypeInRegister - Determine if the given type should be
/// passed in a register (for the Darwin ABI).
bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
@@ -670,6 +812,14 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State) con
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
+ const Type *Base = nullptr;
+ uint64_t NumElts = 0;
+ if (State.CC == llvm::CallingConv::X86_VectorCall &&
+ isHomogeneousAggregate(RetTy, Base, NumElts)) {
+ // The LLVM struct type for such an aggregate should lower properly.
+ return ABIArgInfo::getDirect();
+ }
+
if (const VectorType *VT = RetTy->getAs<VectorType>()) {
// On Darwin, some vectors are returned in registers.
if (IsDarwinVectorABI) {
@@ -842,7 +992,8 @@ bool X86_32ABIInfo::shouldUseInReg(QualType Ty, CCState &State,
State.FreeRegs -= SizeInRegs;
- if (State.CC == llvm::CallingConv::X86_FastCall) {
+ if (State.CC == llvm::CallingConv::X86_FastCall ||
+ State.CC == llvm::CallingConv::X86_VectorCall) {
if (Size > 32)
return false;
@@ -867,17 +1018,38 @@ bool X86_32ABIInfo::shouldUseInReg(QualType Ty, CCState &State,
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
CCState &State) const {
// FIXME: Set alignment on indirect arguments.
- if (isAggregateTypeForABI(Ty)) {
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- // Check with the C++ ABI first.
- CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
- if (RAA == CGCXXABI::RAA_Indirect) {
- return getIndirectResult(Ty, false, State);
- } else if (RAA == CGCXXABI::RAA_DirectInMemory) {
- // The field index doesn't matter, we'll fix it up later.
- return ABIArgInfo::getInAlloca(/*FieldIndex=*/0);
- }
+ Ty = useFirstFieldIfTransparentUnion(Ty);
+
+ // Check with the C++ ABI first.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (RT) {
+ CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
+ if (RAA == CGCXXABI::RAA_Indirect) {
+ return getIndirectResult(Ty, false, State);
+ } else if (RAA == CGCXXABI::RAA_DirectInMemory) {
+ // The field index doesn't matter, we'll fix it up later.
+ return ABIArgInfo::getInAlloca(/*FieldIndex=*/0);
+ }
+ }
+
+ // vectorcall adds the concept of a homogenous vector aggregate, similar
+ // to other targets.
+ const Type *Base = nullptr;
+ uint64_t NumElts = 0;
+ if (State.CC == llvm::CallingConv::X86_VectorCall &&
+ isHomogeneousAggregate(Ty, Base, NumElts)) {
+ if (State.FreeSSERegs >= NumElts) {
+ State.FreeSSERegs -= NumElts;
+ if (Ty->isBuiltinType() || Ty->isVectorType())
+ return ABIArgInfo::getDirect();
+ return ABIArgInfo::getExpand();
+ }
+ return getIndirectResult(Ty, /*ByVal=*/false, State);
+ }
+
+ if (isAggregateTypeForABI(Ty)) {
+ if (RT) {
// Structs are always byval on win32, regardless of what they contain.
if (IsWin32StructABI)
return getIndirectResult(Ty, true, State);
@@ -909,7 +1081,9 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
if (getContext().getTypeSize(Ty) <= 4*32 &&
canExpandIndirectArgument(Ty, getContext()))
return ABIArgInfo::getExpandWithPadding(
- State.CC == llvm::CallingConv::X86_FastCall, PaddingType);
+ State.CC == llvm::CallingConv::X86_FastCall ||
+ State.CC == llvm::CallingConv::X86_VectorCall,
+ PaddingType);
return getIndirectResult(Ty, true, State);
}
@@ -952,7 +1126,10 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
CCState State(FI.getCallingConvention());
if (State.CC == llvm::CallingConv::X86_FastCall)
State.FreeRegs = 2;
- else if (FI.getHasRegParm())
+ else if (State.CC == llvm::CallingConv::X86_VectorCall) {
+ State.FreeRegs = 2;
+ State.FreeSSERegs = 6;
+ } else if (FI.getHasRegParm())
State.FreeRegs = FI.getRegParm();
else
State.FreeRegs = DefaultNumRegisterParameters;
@@ -968,6 +1145,10 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
}
}
+ // The chain argument effectively gives us another free register.
+ if (FI.isChainCall())
+ ++State.FreeRegs;
+
bool UsedInAlloca = false;
for (auto &I : FI.arguments()) {
I.info = classifyArgumentType(I.type, State);
@@ -1002,6 +1183,26 @@ X86_32ABIInfo::addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields,
}
}
+static bool isArgInAlloca(const ABIArgInfo &Info) {
+ // Leave ignored and inreg arguments alone.
+ switch (Info.getKind()) {
+ case ABIArgInfo::InAlloca:
+ return true;
+ case ABIArgInfo::Indirect:
+ assert(Info.getIndirectByVal());
+ return true;
+ case ABIArgInfo::Ignore:
+ return false;
+ case ABIArgInfo::Direct:
+ case ABIArgInfo::Extend:
+ case ABIArgInfo::Expand:
+ if (Info.getInReg())
+ return false;
+ return true;
+ }
+ llvm_unreachable("invalid enum");
+}
+
void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
assert(IsWin32StructABI && "inalloca only supported on win32");
@@ -1009,9 +1210,19 @@ void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
SmallVector<llvm::Type *, 6> FrameFields;
unsigned StackOffset = 0;
+ CGFunctionInfo::arg_iterator I = FI.arg_begin(), E = FI.arg_end();
- // Put the sret parameter into the inalloca struct if it's in memory.
+ // Put 'this' into the struct before 'sret', if necessary.
+ bool IsThisCall =
+ FI.getCallingConvention() == llvm::CallingConv::X86_ThisCall;
ABIArgInfo &Ret = FI.getReturnInfo();
+ if (Ret.isIndirect() && Ret.isSRetAfterThis() && !IsThisCall &&
+ isArgInAlloca(I->info)) {
+ addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type);
+ ++I;
+ }
+
+ // Put the sret parameter into the inalloca struct if it's in memory.
if (Ret.isIndirect() && !Ret.getInReg()) {
CanQualType PtrTy = getContext().getPointerType(FI.getReturnType());
addFieldToArgStruct(FrameFields, StackOffset, Ret, PtrTy);
@@ -1020,30 +1231,13 @@ void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
}
// Skip the 'this' parameter in ecx.
- CGFunctionInfo::arg_iterator I = FI.arg_begin(), E = FI.arg_end();
- if (FI.getCallingConvention() == llvm::CallingConv::X86_ThisCall)
+ if (IsThisCall)
++I;
// Put arguments passed in memory into the struct.
for (; I != E; ++I) {
-
- // Leave ignored and inreg arguments alone.
- switch (I->info.getKind()) {
- case ABIArgInfo::Indirect:
- assert(I->info.getIndirectByVal());
- break;
- case ABIArgInfo::Ignore:
- continue;
- case ABIArgInfo::Direct:
- case ABIArgInfo::Extend:
- if (I->info.getInReg())
- continue;
- break;
- default:
- break;
- }
-
- addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type);
+ if (isArgInAlloca(I->info))
+ addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type);
}
FI.setArgStruct(llvm::StructType::get(getVMContext(), FrameFields,
@@ -1107,22 +1301,12 @@ bool X86_32TargetCodeGenInfo::isStructReturnInRegABI(
return true;
switch (Triple.getOS()) {
- case llvm::Triple::AuroraUX:
case llvm::Triple::DragonFly:
case llvm::Triple::FreeBSD:
case llvm::Triple::OpenBSD:
case llvm::Triple::Bitrig:
- return true;
case llvm::Triple::Win32:
- switch (Triple.getEnvironment()) {
- case llvm::Triple::UnknownEnvironment:
- case llvm::Triple::Cygnus:
- case llvm::Triple::GNU:
- case llvm::Triple::MSVC:
- return true;
- default:
- return false;
- }
+ return true;
default:
return false;
}
@@ -1325,7 +1509,8 @@ public:
/// WinX86_64ABIInfo - The Windows X86_64 ABI information.
class WinX86_64ABIInfo : public ABIInfo {
- ABIArgInfo classify(QualType Ty, bool IsReturnType) const;
+ ABIArgInfo classify(QualType Ty, unsigned &FreeSSERegs,
+ bool IsReturnType) const;
public:
WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {}
@@ -1334,12 +1519,24 @@ public:
llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const override;
+
+ bool isHomogeneousAggregateBaseType(QualType Ty) const override {
+ // FIXME: Assumes vectorcall is in use.
+ return isX86VectorTypeForVectorCall(getContext(), Ty);
+ }
+
+ bool isHomogeneousAggregateSmallEnough(const Type *Ty,
+ uint64_t NumMembers) const override {
+ // FIXME: Assumes vectorcall is in use.
+ return isX86VectorCallAggregateSmallEnough(NumMembers);
+ }
};
class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
+ bool HasAVX;
public:
X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
- : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {}
+ : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)), HasAVX(HasAVX) {}
const X86_64ABIInfo &getABIInfo() const {
return static_cast<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
@@ -1399,6 +1596,9 @@ public:
return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
}
+ unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
+ return HasAVX ? 32 : 16;
+ }
};
static std::string qualifyWindowsLibrary(llvm::StringRef Lib) {
@@ -1430,9 +1630,10 @@ public:
};
class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
+ bool HasAVX;
public:
- WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)) {}
+ WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
+ : TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)), HasAVX(HasAVX) {}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
return 7;
@@ -1459,6 +1660,10 @@ public:
llvm::SmallString<32> &Opt) const override {
Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
}
+
+ unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
+ return HasAVX ? 32 : 16;
+ }
};
}
@@ -1586,10 +1791,25 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
}
if (Ty->isMemberPointerType()) {
- if (Ty->isMemberFunctionPointerType() && Has64BitPointers)
- Lo = Hi = Integer;
- else
+ if (Ty->isMemberFunctionPointerType()) {
+ if (Has64BitPointers) {
+ // If Has64BitPointers, this is an {i64, i64}, so classify both
+ // Lo and Hi now.
+ Lo = Hi = Integer;
+ } else {
+ // Otherwise, with 32-bit pointers, this is an {i32, i32}. If that
+ // straddles an eightbyte boundary, Hi should be classified as well.
+ uint64_t EB_FuncPtr = (OffsetBase) / 64;
+ uint64_t EB_ThisAdj = (OffsetBase + 64 - 1) / 64;
+ if (EB_FuncPtr != EB_ThisAdj) {
+ Lo = Hi = Integer;
+ } else {
+ Current = Integer;
+ }
+ }
+ } else {
Current = Integer;
+ }
return;
}
@@ -2171,7 +2391,7 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi,
// the second element at offset 8. Check for this:
unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo);
unsigned HiAlign = TD.getABITypeAlignment(Hi);
- unsigned HiStart = llvm::DataLayout::RoundUpAlignment(LoSize, HiAlign);
+ unsigned HiStart = llvm::RoundUpToAlignment(LoSize, HiAlign);
assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!");
// To handle this, we have to increase the size of the low part so that the
@@ -2190,7 +2410,7 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi,
}
}
- llvm::StructType *Result = llvm::StructType::get(Lo, Hi, NULL);
+ llvm::StructType *Result = llvm::StructType::get(Lo, Hi, nullptr);
// Verify that the second element is at an 8-byte offset.
@@ -2267,7 +2487,7 @@ classifyReturnType(QualType RetTy) const {
assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
ResType = llvm::StructType::get(llvm::Type::getX86_FP80Ty(getVMContext()),
llvm::Type::getX86_FP80Ty(getVMContext()),
- NULL);
+ nullptr);
break;
}
@@ -2333,6 +2553,8 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(
bool isNamedArg)
const
{
+ Ty = useFirstFieldIfTransparentUnion(Ty);
+
X86_64ABIInfo::Class Lo, Hi;
classify(Ty, 0, Lo, Hi, isNamedArg);
@@ -2468,23 +2690,21 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
if (FI.getReturnInfo().isIndirect())
--freeIntRegs;
- bool isVariadic = FI.isVariadic();
- unsigned numRequiredArgs = 0;
- if (isVariadic)
- numRequiredArgs = FI.getRequiredArgs().getNumRequiredArgs();
+ // The chain argument effectively gives us another free register.
+ if (FI.isChainCall())
+ ++freeIntRegs;
+ unsigned NumRequiredArgs = FI.getNumRequiredArgs();
// AMD64-ABI 3.2.3p3: Once arguments are classified, the registers
// get assigned (in left-to-right order) for passing as follows...
+ unsigned ArgNo = 0;
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it) {
- bool isNamedArg = true;
- if (isVariadic)
- isNamedArg = (it - FI.arg_begin()) <
- static_cast<signed>(numRequiredArgs);
+ it != ie; ++it, ++ArgNo) {
+ bool IsNamedArg = ArgNo < NumRequiredArgs;
unsigned neededInt, neededSSE;
it->info = classifyArgumentType(it->type, freeIntRegs, neededInt,
- neededSSE, isNamedArg);
+ neededSSE, IsNamedArg);
// AMD64-ABI 3.2.3p3: If there are no registers available for any
// eightbyte of an argument, the whole argument is passed on the
@@ -2674,7 +2894,7 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
llvm::Type *DoubleTy = CGF.DoubleTy;
llvm::Type *DblPtrTy =
llvm::PointerType::getUnqual(DoubleTy);
- llvm::StructType *ST = llvm::StructType::get(DoubleTy, DoubleTy, NULL);
+ llvm::StructType *ST = llvm::StructType::get(DoubleTy, DoubleTy, nullptr);
llvm::Value *V, *Tmp = CGF.CreateMemTemp(Ty);
Tmp = CGF.Builder.CreateBitCast(Tmp, ST->getPointerTo());
V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo,
@@ -2717,7 +2937,8 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return ResAddr;
}
-ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const {
+ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs,
+ bool IsReturnType) const {
if (Ty->isVoidType())
return ABIArgInfo::getIgnore();
@@ -2725,7 +2946,9 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const {
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
- uint64_t Size = getContext().getTypeSize(Ty);
+ TypeInfo Info = getContext().getTypeInfo(Ty);
+ uint64_t Width = Info.Width;
+ unsigned Align = getContext().toCharUnitsFromBits(Info.Align).getQuantity();
const RecordType *RT = Ty->getAs<RecordType>();
if (RT) {
@@ -2738,11 +2961,26 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const {
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
// FIXME: mingw-w64-gcc emits 128-bit struct as i128
- if (Size == 128 && getTarget().getTriple().isWindowsGNUEnvironment())
+ if (Width == 128 && getTarget().getTriple().isWindowsGNUEnvironment())
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
- Size));
+ Width));
}
+ // vectorcall adds the concept of a homogenous vector aggregate, similar to
+ // other targets.
+ const Type *Base = nullptr;
+ uint64_t NumElts = 0;
+ if (FreeSSERegs && isHomogeneousAggregate(Ty, Base, NumElts)) {
+ if (FreeSSERegs >= NumElts) {
+ FreeSSERegs -= NumElts;
+ if (IsReturnType || Ty->isBuiltinType() || Ty->isVectorType())
+ return ABIArgInfo::getDirect();
+ return ABIArgInfo::getExpand();
+ }
+ return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
+ }
+
+
if (Ty->isMemberPointerType()) {
// If the member pointer is represented by an LLVM int or ptr, pass it
// directly.
@@ -2754,25 +2992,35 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const {
if (RT || Ty->isMemberPointerType()) {
// MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is
// not 1, 2, 4, or 8 bytes, must be passed by reference."
- if (Size > 64 || !llvm::isPowerOf2_64(Size))
+ if (Width > 64 || !llvm::isPowerOf2_64(Width))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
// Otherwise, coerce it to a small integer.
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size));
+ return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Width));
}
- if (Ty->isPromotableIntegerType())
+ // Bool type is always extended to the ABI, other builtin types are not
+ // extended.
+ const BuiltinType *BT = Ty->getAs<BuiltinType>();
+ if (BT && BT->getKind() == BuiltinType::Bool)
return ABIArgInfo::getExtend();
return ABIArgInfo::getDirect();
}
void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ bool IsVectorCall =
+ FI.getCallingConvention() == llvm::CallingConv::X86_VectorCall;
+
+ // We can use up to 4 SSE return registers with vectorcall.
+ unsigned FreeSSERegs = IsVectorCall ? 4 : 0;
if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classify(FI.getReturnType(), true);
+ FI.getReturnInfo() = classify(FI.getReturnType(), FreeSSERegs, true);
+ // We can use up to 6 SSE register parameters with vectorcall.
+ FreeSSERegs = IsVectorCall ? 6 : 0;
for (auto &I : FI.arguments())
- I.info = classify(I.type, false);
+ I.info = classify(I.type, FreeSSERegs, false);
}
llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -2812,9 +3060,14 @@ class NaClX86_64ABIInfo : public ABIInfo {
};
class NaClX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
+ bool HasAVX;
public:
- NaClX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
- : TargetCodeGenInfo(new NaClX86_64ABIInfo(CGT, HasAVX)) {}
+ NaClX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
+ : TargetCodeGenInfo(new NaClX86_64ABIInfo(CGT, HasAVX)), HasAVX(HasAVX) {
+ }
+ unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
+ return HasAVX ? 32 : 16;
+ }
};
}
@@ -2835,11 +3088,19 @@ llvm::Value *NaClX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// PowerPC-32
-
namespace {
-class PPC32TargetCodeGenInfo : public DefaultTargetCodeGenInfo {
+/// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information.
+class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
public:
- PPC32TargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {}
+ PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
+
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
+};
+
+class PPC32TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ PPC32TargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new PPC32_SVR4_ABIInfo(CGT)) {}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
// This is recovered from gcc output.
@@ -2848,10 +3109,104 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const override;
+
+ unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
+ return 16; // Natural alignment for Altivec vectors.
+ }
};
}
+llvm::Value *PPC32_SVR4_ABIInfo::EmitVAArg(llvm::Value *VAListAddr,
+ QualType Ty,
+ CodeGenFunction &CGF) const {
+ if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
+ // TODO: Implement this. For now ignore.
+ (void)CTy;
+ return nullptr;
+ }
+
+ bool isI64 = Ty->isIntegerType() && getContext().getTypeSize(Ty) == 64;
+ bool isInt = Ty->isIntegerType() || Ty->isPointerType() || Ty->isAggregateType();
+ llvm::Type *CharPtr = CGF.Int8PtrTy;
+ llvm::Type *CharPtrPtr = CGF.Int8PtrPtrTy;
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *GPRPtr = Builder.CreateBitCast(VAListAddr, CharPtr, "gprptr");
+ llvm::Value *GPRPtrAsInt = Builder.CreatePtrToInt(GPRPtr, CGF.Int32Ty);
+ llvm::Value *FPRPtrAsInt = Builder.CreateAdd(GPRPtrAsInt, Builder.getInt32(1));
+ llvm::Value *FPRPtr = Builder.CreateIntToPtr(FPRPtrAsInt, CharPtr);
+ llvm::Value *OverflowAreaPtrAsInt = Builder.CreateAdd(FPRPtrAsInt, Builder.getInt32(3));
+ llvm::Value *OverflowAreaPtr = Builder.CreateIntToPtr(OverflowAreaPtrAsInt, CharPtrPtr);
+ llvm::Value *RegsaveAreaPtrAsInt = Builder.CreateAdd(OverflowAreaPtrAsInt, Builder.getInt32(4));
+ llvm::Value *RegsaveAreaPtr = Builder.CreateIntToPtr(RegsaveAreaPtrAsInt, CharPtrPtr);
+ llvm::Value *GPR = Builder.CreateLoad(GPRPtr, false, "gpr");
+ // Align GPR when TY is i64.
+ if (isI64) {
+ llvm::Value *GPRAnd = Builder.CreateAnd(GPR, Builder.getInt8(1));
+ llvm::Value *CC64 = Builder.CreateICmpEQ(GPRAnd, Builder.getInt8(1));
+ llvm::Value *GPRPlusOne = Builder.CreateAdd(GPR, Builder.getInt8(1));
+ GPR = Builder.CreateSelect(CC64, GPRPlusOne, GPR);
+ }
+ llvm::Value *FPR = Builder.CreateLoad(FPRPtr, false, "fpr");
+ llvm::Value *OverflowArea = Builder.CreateLoad(OverflowAreaPtr, false, "overflow_area");
+ llvm::Value *OverflowAreaAsInt = Builder.CreatePtrToInt(OverflowArea, CGF.Int32Ty);
+ llvm::Value *RegsaveArea = Builder.CreateLoad(RegsaveAreaPtr, false, "regsave_area");
+ llvm::Value *RegsaveAreaAsInt = Builder.CreatePtrToInt(RegsaveArea, CGF.Int32Ty);
+
+ llvm::Value *CC = Builder.CreateICmpULT(isInt ? GPR : FPR,
+ Builder.getInt8(8), "cond");
+
+ llvm::Value *RegConstant = Builder.CreateMul(isInt ? GPR : FPR,
+ Builder.getInt8(isInt ? 4 : 8));
+
+ llvm::Value *OurReg = Builder.CreateAdd(RegsaveAreaAsInt, Builder.CreateSExt(RegConstant, CGF.Int32Ty));
+
+ if (Ty->isFloatingType())
+ OurReg = Builder.CreateAdd(OurReg, Builder.getInt32(32));
+
+ llvm::BasicBlock *UsingRegs = CGF.createBasicBlock("using_regs");
+ llvm::BasicBlock *UsingOverflow = CGF.createBasicBlock("using_overflow");
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
+
+ Builder.CreateCondBr(CC, UsingRegs, UsingOverflow);
+
+ CGF.EmitBlock(UsingRegs);
+
+ llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *Result1 = Builder.CreateIntToPtr(OurReg, PTy);
+ // Increase the GPR/FPR indexes.
+ if (isInt) {
+ GPR = Builder.CreateAdd(GPR, Builder.getInt8(isI64 ? 2 : 1));
+ Builder.CreateStore(GPR, GPRPtr);
+ } else {
+ FPR = Builder.CreateAdd(FPR, Builder.getInt8(1));
+ Builder.CreateStore(FPR, FPRPtr);
+ }
+ CGF.EmitBranch(Cont);
+
+ CGF.EmitBlock(UsingOverflow);
+
+ // Increase the overflow area.
+ llvm::Value *Result2 = Builder.CreateIntToPtr(OverflowAreaAsInt, PTy);
+ OverflowAreaAsInt = Builder.CreateAdd(OverflowAreaAsInt, Builder.getInt32(isInt ? 4 : 8));
+ Builder.CreateStore(Builder.CreateIntToPtr(OverflowAreaAsInt, CharPtr), OverflowAreaPtr);
+ CGF.EmitBranch(Cont);
+
+ CGF.EmitBlock(Cont);
+
+ llvm::PHINode *Result = CGF.Builder.CreatePHI(PTy, 2, "vaarg.addr");
+ Result->addIncoming(Result1, UsingRegs);
+ Result->addIncoming(Result2, UsingOverflow);
+
+ if (Ty->isAggregateType()) {
+ llvm::Value *AGGPtr = Builder.CreateBitCast(Result, CharPtrPtr, "aggrptr") ;
+ return Builder.CreateLoad(AGGPtr, false, "aggr");
+ }
+
+ return Result;
+}
+
bool
PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const {
@@ -2914,12 +3269,14 @@ public:
bool isPromotableTypeForABI(QualType Ty) const;
bool isAlignedParamType(QualType Ty) const;
- bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
- uint64_t &Members) const;
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType Ty) const;
+ bool isHomogeneousAggregateBaseType(QualType Ty) const override;
+ bool isHomogeneousAggregateSmallEnough(const Type *Ty,
+ uint64_t Members) const override;
+
// TODO: We can add more logic to computeInfo to improve performance.
// Example: For aggregate arguments that fit in a register, we could
// use getDirectInReg (as is done below for structs containing a single
@@ -2964,6 +3321,10 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const override;
+
+ unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
+ return 16; // Natural alignment for Altivec and VSX vectors.
+ }
};
class PPC64TargetCodeGenInfo : public DefaultTargetCodeGenInfo {
@@ -2977,6 +3338,10 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const override;
+
+ unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
+ return 16; // Natural alignment for Altivec vectors.
+ }
};
}
@@ -3054,9 +3419,8 @@ PPC64_SVR4_ABIInfo::isAlignedParamType(QualType Ty) const {
/// isHomogeneousAggregate - Return true if a type is an ELFv2 homogeneous
/// aggregate. Base is set to the base element type, and Members is set
/// to the number of base elements.
-bool
-PPC64_SVR4_ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base,
- uint64_t &Members) const {
+bool ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base,
+ uint64_t &Members) const {
if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) {
uint64_t NElements = AT->getSize().getZExtValue();
if (NElements == 0)
@@ -3070,6 +3434,22 @@ PPC64_SVR4_ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base,
return false;
Members = 0;
+
+ // If this is a C++ record, check the bases first.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (const auto &I : CXXRD->bases()) {
+ // Ignore empty records.
+ if (isEmptyRecord(getContext(), I.getType(), true))
+ continue;
+
+ uint64_t FldMembers;
+ if (!isHomogeneousAggregate(I.getType(), Base, FldMembers))
+ return false;
+
+ Members += FldMembers;
+ }
+ }
+
for (const auto *FD : RD->fields()) {
// Ignore (non-zero arrays of) empty records.
QualType FT = FD->getType();
@@ -3109,19 +3489,9 @@ PPC64_SVR4_ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base,
Ty = CT->getElementType();
}
- // Homogeneous aggregates for ELFv2 must have base types of float,
- // double, long double, or 128-bit vectors.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->getKind() != BuiltinType::Float &&
- BT->getKind() != BuiltinType::Double &&
- BT->getKind() != BuiltinType::LongDouble)
- return false;
- } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
- if (getContext().getTypeSize(VT) != 128)
- return false;
- } else {
+ // Most ABIs only support float, double, and some vector type widths.
+ if (!isHomogeneousAggregateBaseType(Ty))
return false;
- }
// The base type must be the same for all members. Types that
// agree in both total size and mode (float vs. vector) are
@@ -3134,18 +3504,40 @@ PPC64_SVR4_ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base,
getContext().getTypeSize(Base) != getContext().getTypeSize(TyPtr))
return false;
}
+ return Members > 0 && isHomogeneousAggregateSmallEnough(Base, Members);
+}
+
+bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
+ // Homogeneous aggregates for ELFv2 must have base types of float,
+ // double, long double, or 128-bit vectors.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::Float ||
+ BT->getKind() == BuiltinType::Double ||
+ BT->getKind() == BuiltinType::LongDouble)
+ return true;
+ }
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ if (getContext().getTypeSize(VT) == 128)
+ return true;
+ }
+ return false;
+}
+bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateSmallEnough(
+ const Type *Base, uint64_t Members) const {
// Vector types require one register, floating point types require one
// or two registers depending on their size.
- uint32_t NumRegs = Base->isVectorType() ? 1 :
- (getContext().getTypeSize(Base) + 63) / 64;
+ uint32_t NumRegs =
+ Base->isVectorType() ? 1 : (getContext().getTypeSize(Base) + 63) / 64;
// Homogeneous Aggregates may occupy at most 8 registers.
- return (Members > 0 && Members * NumRegs <= 8);
+ return Members * NumRegs <= 8;
}
ABIArgInfo
PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
+ Ty = useFirstFieldIfTransparentUnion(Ty);
+
if (Ty->isAnyComplexType())
return ABIArgInfo::getDirect();
@@ -3252,7 +3644,7 @@ PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
llvm::Type *CoerceTy;
if (Bits > GPRBits) {
CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
- CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy, NULL);
+ CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy, nullptr);
} else
CoerceTy = llvm::IntegerType::get(getVMContext(),
llvm::RoundUpToAlignment(Bits, 8));
@@ -3429,76 +3821,19 @@ private:
bool isDarwinPCS() const { return Kind == DarwinPCS; }
ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &AllocatedVFP,
- bool &IsHA, unsigned &AllocatedGPR,
- bool &IsSmallAggr, bool IsNamedArg) const;
- bool isIllegalVectorType(QualType Ty) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy) const;
+ bool isHomogeneousAggregateBaseType(QualType Ty) const override;
+ bool isHomogeneousAggregateSmallEnough(const Type *Ty,
+ uint64_t Members) const override;
- virtual void computeInfo(CGFunctionInfo &FI) const {
- // To correctly handle Homogeneous Aggregate, we need to keep track of the
- // number of SIMD and Floating-point registers allocated so far.
- // If the argument is an HFA or an HVA and there are sufficient unallocated
- // SIMD and Floating-point registers, then the argument is allocated to SIMD
- // and Floating-point Registers (with one register per member of the HFA or
- // HVA). Otherwise, the NSRN is set to 8.
- unsigned AllocatedVFP = 0;
-
- // To correctly handle small aggregates, we need to keep track of the number
- // of GPRs allocated so far. If the small aggregate can't all fit into
- // registers, it will be on stack. We don't allow the aggregate to be
- // partially in registers.
- unsigned AllocatedGPR = 0;
-
- // Find the number of named arguments. Variadic arguments get special
- // treatment with the Darwin ABI.
- unsigned NumRequiredArgs = (FI.isVariadic() ?
- FI.getRequiredArgs().getNumRequiredArgs() :
- FI.arg_size());
+ bool isIllegalVectorType(QualType Ty) const;
+ void computeInfo(CGFunctionInfo &FI) const override {
if (!getCXXABI().classifyReturnType(FI))
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it) {
- unsigned PreAllocation = AllocatedVFP, PreGPR = AllocatedGPR;
- bool IsHA = false, IsSmallAggr = false;
- const unsigned NumVFPs = 8;
- const unsigned NumGPRs = 8;
- bool IsNamedArg = ((it - FI.arg_begin()) <
- static_cast<signed>(NumRequiredArgs));
- it->info = classifyArgumentType(it->type, AllocatedVFP, IsHA,
- AllocatedGPR, IsSmallAggr, IsNamedArg);
-
- // Under AAPCS the 64-bit stack slot alignment means we can't pass HAs
- // as sequences of floats since they'll get "holes" inserted as
- // padding by the back end.
- if (IsHA && AllocatedVFP > NumVFPs && !isDarwinPCS() &&
- getContext().getTypeAlign(it->type) < 64) {
- uint32_t NumStackSlots = getContext().getTypeSize(it->type);
- NumStackSlots = llvm::RoundUpToAlignment(NumStackSlots, 64) / 64;
-
- llvm::Type *CoerceTy = llvm::ArrayType::get(
- llvm::Type::getDoubleTy(getVMContext()), NumStackSlots);
- it->info = ABIArgInfo::getDirect(CoerceTy);
- }
-
- // If we do not have enough VFP registers for the HA, any VFP registers
- // that are unallocated are marked as unavailable. To achieve this, we add
- // padding of (NumVFPs - PreAllocation) floats.
- if (IsHA && AllocatedVFP > NumVFPs && PreAllocation < NumVFPs) {
- llvm::Type *PaddingTy = llvm::ArrayType::get(
- llvm::Type::getFloatTy(getVMContext()), NumVFPs - PreAllocation);
- it->info.setPaddingType(PaddingTy);
- }
- // If we do not have enough GPRs for the small aggregate, any GPR regs
- // that are unallocated are marked as unavailable.
- if (IsSmallAggr && AllocatedGPR > NumGPRs && PreGPR < NumGPRs) {
- llvm::Type *PaddingTy = llvm::ArrayType::get(
- llvm::Type::getInt32Ty(getVMContext()), NumGPRs - PreGPR);
- it->info =
- ABIArgInfo::getDirect(it->info.getCoerceToType(), 0, PaddingTy);
- }
- }
+ for (auto &it : FI.arguments())
+ it.info = classifyArgumentType(it.type);
}
llvm::Value *EmitDarwinVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -3508,7 +3843,7 @@ private:
CodeGenFunction &CGF) const;
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
+ CodeGenFunction &CGF) const override {
return isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF)
: EmitAAPCSVAArg(VAListAddr, Ty, CGF);
}
@@ -3529,63 +3864,34 @@ public:
};
}
-static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
- ASTContext &Context,
- uint64_t *HAMembers = nullptr);
+ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const {
+ Ty = useFirstFieldIfTransparentUnion(Ty);
-ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty,
- unsigned &AllocatedVFP,
- bool &IsHA,
- unsigned &AllocatedGPR,
- bool &IsSmallAggr,
- bool IsNamedArg) const {
// Handle illegal vector types here.
if (isIllegalVectorType(Ty)) {
uint64_t Size = getContext().getTypeSize(Ty);
if (Size <= 32) {
llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext());
- AllocatedGPR++;
return ABIArgInfo::getDirect(ResType);
}
if (Size == 64) {
llvm::Type *ResType =
llvm::VectorType::get(llvm::Type::getInt32Ty(getVMContext()), 2);
- AllocatedVFP++;
return ABIArgInfo::getDirect(ResType);
}
if (Size == 128) {
llvm::Type *ResType =
llvm::VectorType::get(llvm::Type::getInt32Ty(getVMContext()), 4);
- AllocatedVFP++;
return ABIArgInfo::getDirect(ResType);
}
- AllocatedGPR++;
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
}
- if (Ty->isVectorType())
- // Size of a legal vector should be either 64 or 128.
- AllocatedVFP++;
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->getKind() == BuiltinType::Half ||
- BT->getKind() == BuiltinType::Float ||
- BT->getKind() == BuiltinType::Double ||
- BT->getKind() == BuiltinType::LongDouble)
- AllocatedVFP++;
- }
if (!isAggregateTypeForABI(Ty)) {
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
- if (!Ty->isFloatingType() && !Ty->isVectorType()) {
- unsigned Alignment = getContext().getTypeAlign(Ty);
- if (!isDarwinPCS() && Alignment > 64)
- AllocatedGPR = llvm::RoundUpToAlignment(AllocatedGPR, Alignment / 64);
-
- int RegsNeeded = getContext().getTypeSize(Ty) > 64 ? 2 : 1;
- AllocatedGPR += RegsNeeded;
- }
return (Ty->isPromotableIntegerType() && isDarwinPCS()
? ABIArgInfo::getExtend()
: ABIArgInfo::getDirect());
@@ -3594,9 +3900,8 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty,
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are always indirect.
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
- AllocatedGPR++;
return ABIArgInfo::getIndirect(0, /*ByVal=*/RAA ==
- CGCXXABI::RAA_DirectInMemory);
+ CGCXXABI::RAA_DirectInMemory);
}
// Empty records are always ignored on Darwin, but actually passed in C++ mode
@@ -3605,36 +3910,23 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty,
if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS())
return ABIArgInfo::getIgnore();
- ++AllocatedGPR;
return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
}
// Homogeneous Floating-point Aggregates (HFAs) need to be expanded.
const Type *Base = nullptr;
uint64_t Members = 0;
- if (isHomogeneousAggregate(Ty, Base, getContext(), &Members)) {
- IsHA = true;
- if (!IsNamedArg && isDarwinPCS()) {
- // With the Darwin ABI, variadic arguments are always passed on the stack
- // and should not be expanded. Treat variadic HFAs as arrays of doubles.
- uint64_t Size = getContext().getTypeSize(Ty);
- llvm::Type *BaseTy = llvm::Type::getDoubleTy(getVMContext());
- return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64));
- }
- AllocatedVFP += Members;
- return ABIArgInfo::getExpand();
+ if (isHomogeneousAggregate(Ty, Base, Members)) {
+ return ABIArgInfo::getDirect(
+ llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members));
}
// Aggregates <= 16 bytes are passed directly in registers or on the stack.
uint64_t Size = getContext().getTypeSize(Ty);
if (Size <= 128) {
unsigned Alignment = getContext().getTypeAlign(Ty);
- if (!isDarwinPCS() && Alignment > 64)
- AllocatedGPR = llvm::RoundUpToAlignment(AllocatedGPR, Alignment / 64);
-
Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes
- AllocatedGPR += Size / 64;
- IsSmallAggr = true;
+
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
// For aggregates with 16-byte alignment, we use i128.
if (Alignment < 128 && Size == 128) {
@@ -3644,7 +3936,6 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty,
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size));
}
- AllocatedGPR++;
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
}
@@ -3670,7 +3961,8 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getIgnore();
const Type *Base = nullptr;
- if (isHomogeneousAggregate(RetTy, Base, getContext()))
+ uint64_t Members = 0;
+ if (isHomogeneousAggregate(RetTy, Base, Members))
// Homogeneous Floating-point Aggregates (HFAs) are returned directly.
return ABIArgInfo::getDirect();
@@ -3698,9 +3990,46 @@ bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const {
return false;
}
-static llvm::Value *EmitAArch64VAArg(llvm::Value *VAListAddr, QualType Ty,
- int AllocatedGPR, int AllocatedVFP,
- bool IsIndirect, CodeGenFunction &CGF) {
+bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
+ // Homogeneous aggregates for AAPCS64 must have base types of a floating
+ // point type or a short-vector type. This is the same as the 32-bit ABI,
+ // but with the difference that any floating-point type is allowed,
+ // including __fp16.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->isFloatingPoint())
+ return true;
+ } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ unsigned VecSize = getContext().getTypeSize(VT);
+ if (VecSize == 64 || VecSize == 128)
+ return true;
+ }
+ return false;
+}
+
+bool AArch64ABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base,
+ uint64_t Members) const {
+ return Members <= 4;
+}
+
+llvm::Value *AArch64ABIInfo::EmitAAPCSVAArg(llvm::Value *VAListAddr,
+ QualType Ty,
+ CodeGenFunction &CGF) const {
+ ABIArgInfo AI = classifyArgumentType(Ty);
+ bool IsIndirect = AI.isIndirect();
+
+ llvm::Type *BaseTy = CGF.ConvertType(Ty);
+ if (IsIndirect)
+ BaseTy = llvm::PointerType::getUnqual(BaseTy);
+ else if (AI.getCoerceToType())
+ BaseTy = AI.getCoerceToType();
+
+ unsigned NumRegs = 1;
+ if (llvm::ArrayType *ArrTy = dyn_cast<llvm::ArrayType>(BaseTy)) {
+ BaseTy = ArrTy->getElementType();
+ NumRegs = ArrTy->getNumElements();
+ }
+ bool IsFPR = BaseTy->isFloatingPointTy() || BaseTy->isVectorTy();
+
// The AArch64 va_list type and handling is specified in the Procedure Call
// Standard, section B.4:
//
@@ -3720,21 +4049,19 @@ static llvm::Value *EmitAArch64VAArg(llvm::Value *VAListAddr, QualType Ty,
llvm::Value *reg_offs_p = nullptr, *reg_offs = nullptr;
int reg_top_index;
- int RegSize;
- if (AllocatedGPR) {
- assert(!AllocatedVFP && "Arguments never split between int & VFP regs");
+ int RegSize = IsIndirect ? 8 : getContext().getTypeSize(Ty) / 8;
+ if (!IsFPR) {
// 3 is the field number of __gr_offs
reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 3, "gr_offs_p");
reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "gr_offs");
reg_top_index = 1; // field number for __gr_top
- RegSize = 8 * AllocatedGPR;
+ RegSize = llvm::RoundUpToAlignment(RegSize, 8);
} else {
- assert(!AllocatedGPR && "Argument must go in VFP or int regs");
// 4 is the field number of __vr_offs.
reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 4, "vr_offs_p");
reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "vr_offs");
reg_top_index = 2; // field number for __vr_top
- RegSize = 16 * AllocatedVFP;
+ RegSize = 16 * NumRegs;
}
//=======================================
@@ -3758,7 +4085,7 @@ static llvm::Value *EmitAArch64VAArg(llvm::Value *VAListAddr, QualType Ty,
// Integer arguments may need to correct register alignment (for example a
// "struct { __int128 a; };" gets passed in x_2N, x_{2N+1}). In this case we
// align __gr_offs to calculate the potential address.
- if (AllocatedGPR && !IsIndirect && Ctx.getTypeAlign(Ty) > 64) {
+ if (!IsFPR && !IsIndirect && Ctx.getTypeAlign(Ty) > 64) {
int Align = Ctx.getTypeAlign(Ty) / 8;
reg_offs = CGF.Builder.CreateAdd(
@@ -3806,8 +4133,8 @@ static llvm::Value *EmitAArch64VAArg(llvm::Value *VAListAddr, QualType Ty,
}
const Type *Base = nullptr;
- uint64_t NumMembers;
- bool IsHFA = isHomogeneousAggregate(Ty, Base, Ctx, &NumMembers);
+ uint64_t NumMembers = 0;
+ bool IsHFA = isHomogeneousAggregate(Ty, Base, NumMembers);
if (IsHFA && NumMembers > 1) {
// Homogeneous aggregates passed in registers will have their elements split
// and stored 16-bytes apart regardless of size (they're notionally in qN,
@@ -3926,18 +4253,6 @@ static llvm::Value *EmitAArch64VAArg(llvm::Value *VAListAddr, QualType Ty,
return ResAddr;
}
-llvm::Value *AArch64ABIInfo::EmitAAPCSVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
-
- unsigned AllocatedGPR = 0, AllocatedVFP = 0;
- bool IsHA = false, IsSmallAggr = false;
- ABIArgInfo AI = classifyArgumentType(Ty, AllocatedVFP, IsHA, AllocatedGPR,
- IsSmallAggr, false /*IsNamedArg*/);
-
- return EmitAArch64VAArg(VAListAddr, Ty, AllocatedGPR, AllocatedVFP,
- AI.isIndirect(), CGF);
-}
-
llvm::Value *AArch64ABIInfo::EmitDarwinVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
// We do not support va_arg for aggregates or illegal vector types.
@@ -3950,7 +4265,8 @@ llvm::Value *AArch64ABIInfo::EmitDarwinVAArg(llvm::Value *VAListAddr, QualType T
uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8;
const Type *Base = nullptr;
- bool isHA = isHomogeneousAggregate(Ty, Base, getContext());
+ uint64_t Members = 0;
+ bool isHA = isHomogeneousAggregate(Ty, Base, Members);
bool isIndirect = false;
// Arguments bigger than 16 bytes which aren't homogeneous aggregates should
@@ -4022,7 +4338,7 @@ private:
public:
ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind),
NumVFPs(16), NumGPRs(4) {
- setRuntimeCC();
+ setCCs();
resetAllocatedRegs();
}
@@ -4057,6 +4373,10 @@ private:
bool &IsCPRC) const;
bool isIllegalVectorType(QualType Ty) const;
+ bool isHomogeneousAggregateBaseType(QualType Ty) const override;
+ bool isHomogeneousAggregateSmallEnough(const Type *Ty,
+ uint64_t Members) const override;
+
void computeInfo(CGFunctionInfo &FI) const override;
llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -4064,7 +4384,7 @@ private:
llvm::CallingConv::ID getLLVMDefaultCC() const;
llvm::CallingConv::ID getABIDefaultCC() const;
- void setRuntimeCC();
+ void setCCs();
void markAllocatedGPRs(unsigned Alignment, unsigned NumRequired) const;
void markAllocatedVFPs(unsigned Alignment, unsigned NumRequired) const;
@@ -4183,11 +4503,11 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
llvm::Type *PaddingTy = llvm::ArrayType::get(
llvm::Type::getInt32Ty(getVMContext()), NumGPRs - PreAllocationGPRs);
if (I.info.canHaveCoerceToType()) {
- I.info = ABIArgInfo::getDirect(I.info.getCoerceToType() /* type */, 0 /* offset */,
- PaddingTy);
+ I.info = ABIArgInfo::getDirect(I.info.getCoerceToType() /* type */,
+ 0 /* offset */, PaddingTy, true);
} else {
I.info = ABIArgInfo::getDirect(nullptr /* type */, 0 /* offset */,
- PaddingTy);
+ PaddingTy, true);
}
}
}
@@ -4223,7 +4543,7 @@ llvm::CallingConv::ID ARMABIInfo::getABIDefaultCC() const {
llvm_unreachable("bad ABI kind");
}
-void ARMABIInfo::setRuntimeCC() {
+void ARMABIInfo::setCCs() {
assert(getRuntimeCC() == llvm::CallingConv::C);
// Don't muddy up the IR with a ton of explicit annotations if
@@ -4231,90 +4551,9 @@ void ARMABIInfo::setRuntimeCC() {
llvm::CallingConv::ID abiCC = getABIDefaultCC();
if (abiCC != getLLVMDefaultCC())
RuntimeCC = abiCC;
-}
-
-/// isHomogeneousAggregate - Return true if a type is an AAPCS-VFP homogeneous
-/// aggregate. If HAMembers is non-null, the number of base elements
-/// contained in the type is returned through it; this is used for the
-/// recursive calls that check aggregate component types.
-static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
- ASTContext &Context, uint64_t *HAMembers) {
- uint64_t Members = 0;
- if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
- if (!isHomogeneousAggregate(AT->getElementType(), Base, Context, &Members))
- return false;
- Members *= AT->getSize().getZExtValue();
- } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return false;
-
- Members = 0;
- for (const auto *FD : RD->fields()) {
- uint64_t FldMembers;
- if (!isHomogeneousAggregate(FD->getType(), Base, Context, &FldMembers))
- return false;
-
- Members = (RD->isUnion() ?
- std::max(Members, FldMembers) : Members + FldMembers);
- }
- } else {
- Members = 1;
- if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
- Members = 2;
- Ty = CT->getElementType();
- }
-
- // Homogeneous aggregates for AAPCS-VFP must have base types of float,
- // double, or 64-bit or 128-bit vectors.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->getKind() != BuiltinType::Float &&
- BT->getKind() != BuiltinType::Double &&
- BT->getKind() != BuiltinType::LongDouble)
- return false;
- } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
- unsigned VecSize = Context.getTypeSize(VT);
- if (VecSize != 64 && VecSize != 128)
- return false;
- } else {
- return false;
- }
-
- // The base type must be the same for all members. Vector types of the
- // same total size are treated as being equivalent here.
- const Type *TyPtr = Ty.getTypePtr();
- if (!Base)
- Base = TyPtr;
-
- if (Base != TyPtr) {
- // Homogeneous aggregates are defined as containing members with the
- // same machine type. There are two cases in which two members have
- // different TypePtrs but the same machine type:
-
- // 1) Vectors of the same length, regardless of the type and number
- // of their members.
- const bool SameLengthVectors = Base->isVectorType() && TyPtr->isVectorType()
- && (Context.getTypeSize(Base) == Context.getTypeSize(TyPtr));
-
- // 2) In the 32-bit AAPCS, `double' and `long double' have the same
- // machine type. This is not the case for the 64-bit AAPCS.
- const bool SameSizeDoubles =
- ( ( Base->isSpecificBuiltinType(BuiltinType::Double)
- && TyPtr->isSpecificBuiltinType(BuiltinType::LongDouble))
- || ( Base->isSpecificBuiltinType(BuiltinType::LongDouble)
- && TyPtr->isSpecificBuiltinType(BuiltinType::Double)))
- && (Context.getTypeSize(Base) == Context.getTypeSize(TyPtr));
-
- if (!SameLengthVectors && !SameSizeDoubles)
- return false;
- }
- }
-
- // Homogeneous Aggregates can have at most 4 members of the base type.
- if (HAMembers)
- *HAMembers = Members;
- return (Members > 0 && Members <= 4);
+ BuiltinCC = (getABIKind() == APCS ?
+ llvm::CallingConv::ARM_APCS : llvm::CallingConv::ARM_AAPCS);
}
/// markAllocatedVFPs - update VFPRegs according to the alignment and
@@ -4382,6 +4621,9 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
// with a Base Type of a single- or double-precision floating-point type,
// 64-bit containerized vectors or 128-bit containerized vectors with one
// to four Elements.
+ bool IsEffectivelyAAPCS_VFP = getABIKind() == AAPCS_VFP && !isVariadic;
+
+ Ty = useFirstFieldIfTransparentUnion(Ty);
// Handle illegal vector types here.
if (isIllegalVectorType(Ty)) {
@@ -4451,8 +4693,8 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
unsigned Size = getContext().getTypeSize(Ty);
if (!IsCPRC)
markAllocatedGPRs(Size > 32 ? 2 : 1, (Size + 31) / 32);
- return (Ty->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend()
+ : ABIArgInfo::getDirect());
}
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
@@ -4464,12 +4706,12 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
if (isEmptyRecord(getContext(), Ty, true))
return ABIArgInfo::getIgnore();
- if (getABIKind() == ARMABIInfo::AAPCS_VFP && !isVariadic) {
+ if (IsEffectivelyAAPCS_VFP) {
// Homogeneous Aggregates need to be expanded when we can fit the aggregate
// into VFP registers.
const Type *Base = nullptr;
uint64_t Members = 0;
- if (isHomogeneousAggregate(Ty, Base, getContext(), &Members)) {
+ if (isHomogeneousAggregate(Ty, Base, Members)) {
assert(Base && "Base class should be set for homogeneous aggregate");
// Base can be a floating-point or a vector.
if (Base->isVectorType()) {
@@ -4485,7 +4727,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
markAllocatedVFPs(2, Members * 2);
}
IsCPRC = true;
- return ABIArgInfo::getDirect();
+ return ABIArgInfo::getDirect(nullptr, 0, nullptr, false);
}
}
@@ -4523,9 +4765,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
markAllocatedGPRs(2, SizeRegs * 2);
}
- llvm::Type *STy =
- llvm::StructType::get(llvm::ArrayType::get(ElemTy, SizeRegs), NULL);
- return ABIArgInfo::getDirect(STy);
+ return ABIArgInfo::getDirect(llvm::ArrayType::get(ElemTy, SizeRegs));
}
static bool isIntegerLikeType(QualType Ty, ASTContext &Context,
@@ -4615,6 +4855,8 @@ static bool isIntegerLikeType(QualType Ty, ASTContext &Context,
ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
bool isVariadic) const {
+ bool IsEffectivelyAAPCS_VFP = getABIKind() == AAPCS_VFP && !isVariadic;
+
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
@@ -4629,8 +4871,8 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
RetTy = EnumTy->getDecl()->getIntegerType();
- return (RetTy->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ return RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend()
+ : ABIArgInfo::getDirect();
}
// Are we following APCS?
@@ -4643,8 +4885,8 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
// FIXME: Consider using 2 x vector types if the back end handles them
// correctly.
if (RetTy->isAnyComplexType())
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
- getContext().getTypeSize(RetTy)));
+ return ABIArgInfo::getDirect(llvm::IntegerType::get(
+ getVMContext(), getContext().getTypeSize(RetTy)));
// Integer like structures are returned in r0.
if (isIntegerLikeType(RetTy, getContext(), getVMContext())) {
@@ -4668,12 +4910,13 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
return ABIArgInfo::getIgnore();
// Check for homogeneous aggregates with AAPCS-VFP.
- if (getABIKind() == AAPCS_VFP && !isVariadic) {
+ if (IsEffectivelyAAPCS_VFP) {
const Type *Base = nullptr;
- if (isHomogeneousAggregate(RetTy, Base, getContext())) {
+ uint64_t Members;
+ if (isHomogeneousAggregate(RetTy, Base, Members)) {
assert(Base && "Base class should be set for homogeneous aggregate");
// Homogeneous Aggregates are returned directly.
- return ABIArgInfo::getDirect();
+ return ABIArgInfo::getDirect(nullptr, 0, nullptr, false);
}
}
@@ -4712,6 +4955,27 @@ bool ARMABIInfo::isIllegalVectorType(QualType Ty) const {
return false;
}
+bool ARMABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
+ // Homogeneous aggregates for AAPCS-VFP must have base types of float,
+ // double, or 64-bit or 128-bit vectors.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::Float ||
+ BT->getKind() == BuiltinType::Double ||
+ BT->getKind() == BuiltinType::LongDouble)
+ return true;
+ } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ unsigned VecSize = getContext().getTypeSize(VT);
+ if (VecSize == 64 || VecSize == 128)
+ return true;
+ }
+ return false;
+}
+
+bool ARMABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base,
+ uint64_t Members) const {
+ return Members <= 4;
+}
+
llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
llvm::Type *BP = CGF.Int8PtrTy;
@@ -4876,6 +5140,10 @@ ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const {
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
+ // Return aggregates type as indirect by value
+ if (isAggregateTypeForABI(Ty))
+ return ABIArgInfo::getIndirect(0, /* byval */ true);
+
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
@@ -4953,9 +5221,10 @@ void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::Function *F, StringRef Name,
// Get "nvvm.annotations" metadata node
llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations");
- llvm::Value *MDVals[] = {
- F, llvm::MDString::get(Ctx, Name),
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand)};
+ llvm::Metadata *MDVals[] = {
+ llvm::ConstantAsMetadata::get(F), llvm::MDString::get(Ctx, Name),
+ llvm::ConstantAsMetadata::get(
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))};
// Append metadata to nvvm.annotations
MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
}
@@ -5424,6 +5693,8 @@ llvm::Type *MipsABIInfo::getPaddingType(uint64_t OrigOffset,
ABIArgInfo
MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
+ Ty = useFirstFieldIfTransparentUnion(Ty);
+
uint64_t OrigOffset = Offset;
uint64_t TySize = getContext().getTypeSize(Ty);
uint64_t Align = getContext().getTypeAlign(Ty) / 8;
@@ -5524,7 +5795,7 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getDirect();
// O32 returns integer vectors in registers and N32/N64 returns all small
- // aggregates in registers..
+ // aggregates in registers.
if (!IsO32 ||
(RetTy->isVectorType() && !RetTy->hasFloatingRepresentation())) {
ABIArgInfo ArgInfo =
@@ -5562,10 +5833,13 @@ llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
llvm::Type *BP = CGF.Int8PtrTy;
llvm::Type *BPP = CGF.Int8PtrPtrTy;
- // Integer arguments are promoted 32-bit on O32 and 64-bit on N32/N64.
+ // Integer arguments are promoted to 32-bit on O32 and 64-bit on N32/N64.
+ // Pointers are also promoted in the same way but this only matters for N32.
unsigned SlotSizeInBits = IsO32 ? 32 : 64;
- if (Ty->isIntegerType() &&
- CGF.getContext().getIntWidth(Ty) < SlotSizeInBits) {
+ unsigned PtrWidth = getTarget().getPointerWidth(0);
+ if ((Ty->isIntegerType() &&
+ CGF.getContext().getIntWidth(Ty) < SlotSizeInBits) ||
+ (Ty->isPointerType() && PtrWidth < SlotSizeInBits)) {
Ty = CGF.getContext().getIntTypeForBitwidth(SlotSizeInBits,
Ty->isSignedIntegerType());
}
@@ -5577,7 +5851,6 @@ llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
std::min(getContext().getTypeAlign(Ty) / 8, StackAlignInBytes);
llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
llvm::Value *AddrTyped;
- unsigned PtrWidth = getTarget().getPointerWidth(0);
llvm::IntegerType *IntTy = (PtrWidth == 32) ? CGF.Int32Ty : CGF.Int64Ty;
if (TypeAlign > MinABIStackAlignInBytes) {
@@ -5667,20 +5940,24 @@ void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
llvm::NamedMDNode *OpenCLMetadata =
M.getModule().getOrInsertNamedMetadata("opencl.kernel_wg_size_info");
- SmallVector<llvm::Value*, 5> Operands;
- Operands.push_back(F);
+ SmallVector<llvm::Metadata *, 5> Operands;
+ Operands.push_back(llvm::ConstantAsMetadata::get(F));
- Operands.push_back(llvm::Constant::getIntegerValue(M.Int32Ty,
- llvm::APInt(32, Attr->getXDim())));
- Operands.push_back(llvm::Constant::getIntegerValue(M.Int32Ty,
- llvm::APInt(32, Attr->getYDim())));
- Operands.push_back(llvm::Constant::getIntegerValue(M.Int32Ty,
- llvm::APInt(32, Attr->getZDim())));
+ Operands.push_back(
+ llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue(
+ M.Int32Ty, llvm::APInt(32, Attr->getXDim()))));
+ Operands.push_back(
+ llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue(
+ M.Int32Ty, llvm::APInt(32, Attr->getYDim()))));
+ Operands.push_back(
+ llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue(
+ M.Int32Ty, llvm::APInt(32, Attr->getZDim()))));
// Add a boolean constant operand for "required" (true) or "hint" (false)
// for implementing the work_group_size_hint attr later. Currently
// always true as the hint is not yet implemented.
- Operands.push_back(llvm::ConstantInt::getTrue(Context));
+ Operands.push_back(
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::getTrue(Context)));
OpenCLMetadata->addOperand(llvm::MDNode::get(Context, Operands));
}
}
@@ -5822,6 +6099,45 @@ llvm::Value *HexagonABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return AddrTyped;
}
+//===----------------------------------------------------------------------===//
+// AMDGPU ABI Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ AMDGPUTargetCodeGenInfo(CodeGenTypes &CGT)
+ : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
+ void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const override;
+};
+
+}
+
+void AMDGPUTargetCodeGenInfo::SetTargetAttributes(
+ const Decl *D,
+ llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const {
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD)
+ return;
+
+ if (const auto Attr = FD->getAttr<AMDGPUNumVGPRAttr>()) {
+ llvm::Function *F = cast<llvm::Function>(GV);
+ uint32_t NumVGPR = Attr->getNumVGPR();
+ if (NumVGPR != 0)
+ F->addFnAttr("amdgpu_num_vgpr", llvm::utostr(NumVGPR));
+ }
+
+ if (const auto Attr = FD->getAttr<AMDGPUNumSGPRAttr>()) {
+ llvm::Function *F = cast<llvm::Function>(GV);
+ unsigned NumSGPR = Attr->getNumSGPR();
+ if (NumSGPR != 0)
+ F->addFnAttr("amdgpu_num_sgpr", llvm::utostr(NumSGPR));
+ }
+}
+
//===----------------------------------------------------------------------===//
// SPARC v9 ABI Implementation.
@@ -6405,8 +6721,8 @@ void XCoreTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
SmallStringEnc Enc;
if (getTypeString(Enc, D, CGM, TSC)) {
llvm::LLVMContext &Ctx = CGM.getModule().getContext();
- llvm::SmallVector<llvm::Value *, 2> MDVals;
- MDVals.push_back(GV);
+ llvm::SmallVector<llvm::Metadata *, 2> MDVals;
+ MDVals.push_back(llvm::ConstantAsMetadata::get(GV));
MDVals.push_back(llvm::MDString::get(Ctx, Enc.str()));
llvm::NamedMDNode *MD =
CGM.getModule().getOrInsertNamedMetadata("xcore.typestrings");
@@ -6424,26 +6740,25 @@ static bool extractFieldType(SmallVectorImpl<FieldEncoding> &FE,
const RecordDecl *RD,
const CodeGen::CodeGenModule &CGM,
TypeStringCache &TSC) {
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I) {
+ for (const auto *Field : RD->fields()) {
SmallStringEnc Enc;
Enc += "m(";
- Enc += I->getName();
+ Enc += Field->getName();
Enc += "){";
- if (I->isBitField()) {
+ if (Field->isBitField()) {
Enc += "b(";
llvm::raw_svector_ostream OS(Enc);
OS.resync();
- OS << I->getBitWidthValue(CGM.getContext());
+ OS << Field->getBitWidthValue(CGM.getContext());
OS.flush();
Enc += ':';
}
- if (!appendType(Enc, I->getType(), CGM, TSC))
+ if (!appendType(Enc, Field->getType(), CGM, TSC))
return false;
- if (I->isBitField())
+ if (Field->isBitField())
Enc += ')';
Enc += '}';
- FE.push_back(FieldEncoding(!I->getName().empty(), Enc));
+ FE.push_back(FieldEncoding(!Field->getName().empty(), Enc));
}
return true;
}
@@ -6752,6 +7067,14 @@ static bool getTypeString(SmallStringEnc &Enc, const Decl *D,
// Driver code
//===----------------------------------------------------------------------===//
+const llvm::Triple &CodeGenModule::getTriple() const {
+ return getTarget().getTriple();
+}
+
+bool CodeGenModule::supportsCOMDAT() const {
+ return !getTriple().isOSBinFormatMachO();
+}
+
const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
if (TheTargetCodeGenInfo)
return *TheTargetCodeGenInfo;
@@ -6772,9 +7095,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, false));
case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- case llvm::Triple::arm64:
- case llvm::Triple::arm64_be: {
+ case llvm::Triple::aarch64_be: {
AArch64ABIInfo::ABIKind Kind = AArch64ABIInfo::AAPCS;
if (getTarget().getABI() == "darwinpcs")
Kind = AArch64ABIInfo::DarwinPCS;
@@ -6809,16 +7130,20 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types));
case llvm::Triple::ppc64:
if (Triple.isOSBinFormatELF()) {
- // FIXME: Should be switchable via command-line option.
PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1;
+ if (getTarget().getABI() == "elfv2")
+ Kind = PPC64_SVR4_ABIInfo::ELFv2;
+
return *(TheTargetCodeGenInfo =
new PPC64_SVR4_TargetCodeGenInfo(Types, Kind));
} else
return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
case llvm::Triple::ppc64le: {
assert(Triple.isOSBinFormatELF() && "PPC64 LE non-ELF not supported!");
- // FIXME: Should be switchable via command-line option.
PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv2;
+ if (getTarget().getABI() == "elfv1")
+ Kind = PPC64_SVR4_ABIInfo::ELFv1;
+
return *(TheTargetCodeGenInfo =
new PPC64_SVR4_TargetCodeGenInfo(Types, Kind));
}
@@ -6840,7 +7165,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
bool IsDarwinVectorABI = Triple.isOSDarwin();
bool IsSmallStructInRegABI =
X86_32TargetCodeGenInfo::isStructReturnInRegABI(Triple, CodeGenOpts);
- bool IsWin32FloatStructABI = Triple.isWindowsMSVCEnvironment();
+ bool IsWin32FloatStructABI = Triple.isOSWindows() && !Triple.isOSCygMing();
if (Triple.getOS() == llvm::Triple::Win32) {
return *(TheTargetCodeGenInfo =
@@ -6862,17 +7187,22 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
switch (Triple.getOS()) {
case llvm::Triple::Win32:
- return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types));
+ return *(TheTargetCodeGenInfo =
+ new WinX86_64TargetCodeGenInfo(Types, HasAVX));
case llvm::Triple::NaCl:
- return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types,
- HasAVX));
+ return *(TheTargetCodeGenInfo =
+ new NaClX86_64TargetCodeGenInfo(Types, HasAVX));
default:
- return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types,
- HasAVX));
+ return *(TheTargetCodeGenInfo =
+ new X86_64TargetCodeGenInfo(Types, HasAVX));
}
}
case llvm::Triple::hexagon:
return *(TheTargetCodeGenInfo = new HexagonTargetCodeGenInfo(Types));
+ case llvm::Triple::r600:
+ return *(TheTargetCodeGenInfo = new AMDGPUTargetCodeGenInfo(Types));
+ case llvm::Triple::amdgcn:
+ return *(TheTargetCodeGenInfo = new AMDGPUTargetCodeGenInfo(Types));
case llvm::Triple::sparcv9:
return *(TheTargetCodeGenInfo = new SparcV9TargetCodeGenInfo(Types));
case llvm::Triple::xcore:
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index 2616820185f5..cc469d69e390 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -12,9 +12,10 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_CODEGEN_TARGETINFO_H
-#define CLANG_CODEGEN_TARGETINFO_H
+#ifndef LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
+#define LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
+#include "CGValue.h"
#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallString.h"
@@ -129,6 +130,14 @@ public:
return Ty;
}
+ /// Adds constraints and types for result registers.
+ virtual void addReturnRegisterOutputs(
+ CodeGen::CodeGenFunction &CGF, CodeGen::LValue ReturnValue,
+ std::string &Constraints, std::vector<llvm::Type *> &ResultRegTypes,
+ std::vector<llvm::Type *> &ResultTruncRegTypes,
+ std::vector<CodeGen::LValue> &ResultRegDests, std::string &AsmString,
+ unsigned NumOutputs) const {}
+
/// doesReturnSlotInterfereWithArgs - Return true if the target uses an
/// argument slot for an 'sret' type.
virtual bool doesReturnSlotInterfereWithArgs() const { return true; }
@@ -209,7 +218,14 @@ public:
virtual void getDetectMismatchOption(llvm::StringRef Name,
llvm::StringRef Value,
llvm::SmallString<32> &Opt) const {}
+
+ /// Gets the target-specific default alignment used when an 'aligned' clause
+ /// is used with a 'simd' OpenMP directive without specifying a specific
+ /// alignment.
+ virtual unsigned getOpenMPSimdDefaultAlignment(QualType Type) const {
+ return 0;
+ }
};
}
-#endif // CLANG_CODEGEN_TARGETINFO_H
+#endif
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index 86a48fd8b7f9..360dbeecabf9 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -29,6 +29,7 @@ const char *Action::getClassName(ActionClass AC) {
case AnalyzeJobClass: return "analyzer";
case MigrateJobClass: return "migrator";
case CompileJobClass: return "compiler";
+ case BackendJobClass: return "backend";
case AssembleJobClass: return "assembler";
case LinkJobClass: return "linker";
case LipoJobClass: return "lipo";
@@ -48,15 +49,15 @@ InputAction::InputAction(const Arg &_Input, types::ID _Type)
void BindArchAction::anchor() {}
-BindArchAction::BindArchAction(Action *Input, const char *_ArchName)
- : Action(BindArchClass, Input, Input->getType()), ArchName(_ArchName) {
-}
+BindArchAction::BindArchAction(std::unique_ptr<Action> Input,
+ const char *_ArchName)
+ : Action(BindArchClass, std::move(Input)), ArchName(_ArchName) {}
void JobAction::anchor() {}
-JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
- : Action(Kind, Input, Type) {
-}
+JobAction::JobAction(ActionClass Kind, std::unique_ptr<Action> Input,
+ types::ID Type)
+ : Action(Kind, std::move(Input), Type) {}
JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
: Action(Kind, Inputs, Type) {
@@ -64,39 +65,45 @@ JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
void PreprocessJobAction::anchor() {}
-PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
- : JobAction(PreprocessJobClass, Input, OutputType) {
-}
+PreprocessJobAction::PreprocessJobAction(std::unique_ptr<Action> Input,
+ types::ID OutputType)
+ : JobAction(PreprocessJobClass, std::move(Input), OutputType) {}
void PrecompileJobAction::anchor() {}
-PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
- : JobAction(PrecompileJobClass, Input, OutputType) {
-}
+PrecompileJobAction::PrecompileJobAction(std::unique_ptr<Action> Input,
+ types::ID OutputType)
+ : JobAction(PrecompileJobClass, std::move(Input), OutputType) {}
void AnalyzeJobAction::anchor() {}
-AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
- : JobAction(AnalyzeJobClass, Input, OutputType) {
-}
+AnalyzeJobAction::AnalyzeJobAction(std::unique_ptr<Action> Input,
+ types::ID OutputType)
+ : JobAction(AnalyzeJobClass, std::move(Input), OutputType) {}
void MigrateJobAction::anchor() {}
-MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType)
- : JobAction(MigrateJobClass, Input, OutputType) {
-}
+MigrateJobAction::MigrateJobAction(std::unique_ptr<Action> Input,
+ types::ID OutputType)
+ : JobAction(MigrateJobClass, std::move(Input), OutputType) {}
void CompileJobAction::anchor() {}
-CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
- : JobAction(CompileJobClass, Input, OutputType) {
-}
+CompileJobAction::CompileJobAction(std::unique_ptr<Action> Input,
+ types::ID OutputType)
+ : JobAction(CompileJobClass, std::move(Input), OutputType) {}
+
+void BackendJobAction::anchor() {}
+
+BackendJobAction::BackendJobAction(std::unique_ptr<Action> Input,
+ types::ID OutputType)
+ : JobAction(BackendJobClass, std::move(Input), OutputType) {}
void AssembleJobAction::anchor() {}
-AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
- : JobAction(AssembleJobClass, Input, OutputType) {
-}
+AssembleJobAction::AssembleJobAction(std::unique_ptr<Action> Input,
+ types::ID OutputType)
+ : JobAction(AssembleJobClass, std::move(Input), OutputType) {}
void LinkJobAction::anchor() {}
@@ -118,9 +125,9 @@ DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
void VerifyJobAction::anchor() {}
-VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input,
- types::ID Type)
- : JobAction(Kind, Input, Type) {
+VerifyJobAction::VerifyJobAction(ActionClass Kind,
+ std::unique_ptr<Action> Input, types::ID Type)
+ : JobAction(Kind, std::move(Input), Type) {
assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&
"ActionClass is not a valid VerifyJobAction");
}
@@ -134,13 +141,12 @@ VerifyJobAction::VerifyJobAction(ActionClass Kind, ActionList &Inputs,
void VerifyDebugInfoJobAction::anchor() {}
-VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,
- types::ID Type)
- : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {
-}
+VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(
+ std::unique_ptr<Action> Input, types::ID Type)
+ : VerifyJobAction(VerifyDebugInfoJobClass, std::move(Input), Type) {}
void VerifyPCHJobAction::anchor() {}
-VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
- : VerifyJobAction(VerifyPCHJobClass, Input, Type) {
-}
+VerifyPCHJobAction::VerifyPCHJobAction(std::unique_ptr<Action> Input,
+ types::ID Type)
+ : VerifyJobAction(VerifyPCHJobClass, std::move(Input), Type) {}
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index 33db5e9a9e17..412840b6ea6e 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -6,16 +6,17 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangDriver
Action.cpp
Compilation.cpp
+ CrossWindowsToolChain.cpp
Driver.cpp
DriverOptions.cpp
Job.cpp
Multilib.cpp
+ MSVCToolChain.cpp
Phases.cpp
SanitizerArgs.cpp
Tool.cpp
ToolChain.cpp
ToolChains.cpp
- WindowsToolChain.cpp
Tools.cpp
Types.cpp
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 49b7edd96659..2bcbd5cf943c 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -88,7 +88,7 @@ bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
// Failure is only failure if the file exists and is "regular". We checked
// for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
// so we don't need to check again.
-
+
if (IssueErrors)
getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
<< EC.message();
@@ -131,13 +131,13 @@ int Compilation::ExecuteCommand(const Command &C,
// Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
// output stream.
if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
- std::string Error;
- OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, Error,
+ std::error_code EC;
+ OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, EC,
llvm::sys::fs::F_Append |
llvm::sys::fs::F_Text);
- if (!Error.empty()) {
+ if (EC) {
getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
- << Error;
+ << EC.message();
FailingCommand = &C;
delete OS;
return 1;
@@ -202,9 +202,8 @@ void Compilation::ExecuteJob(const Job &J,
FailingCommands.push_back(std::make_pair(Res, FailingCommand));
} else {
const JobList *Jobs = cast<JobList>(&J);
- for (JobList::const_iterator it = Jobs->begin(), ie = Jobs->end();
- it != ie; ++it)
- ExecuteJob(**it, FailingCommands);
+ for (const auto &Job : *Jobs)
+ ExecuteJob(Job, FailingCommands);
}
}
@@ -233,8 +232,8 @@ void Compilation::initCompilationForDiagnostics() {
// Redirect stdout/stderr to /dev/null.
Redirects = new const StringRef*[3]();
Redirects[0] = nullptr;
- Redirects[1] = new const StringRef();
- Redirects[2] = new const StringRef();
+ Redirects[1] = new StringRef();
+ Redirects[2] = new StringRef();
}
StringRef Compilation::getSysRoot() const {
diff --git a/lib/Driver/CrossWindowsToolChain.cpp b/lib/Driver/CrossWindowsToolChain.cpp
new file mode 100644
index 000000000000..03fe41b74fe0
--- /dev/null
+++ b/lib/Driver/CrossWindowsToolChain.cpp
@@ -0,0 +1,117 @@
+//===--- CrossWindowsToolChain.cpp - Cross Windows Tool Chain -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ToolChains.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+
+CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D,
+ const llvm::Triple &T,
+ const llvm::opt::ArgList &Args)
+ : Generic_GCC(D, T, Args) {
+ if (GetCXXStdlibType(Args) == ToolChain::CST_Libstdcxx) {
+ const std::string &SysRoot = D.SysRoot;
+
+ // libstdc++ resides in /usr/lib, but depends on libgcc which is placed in
+ // /usr/lib/gcc.
+ getFilePaths().push_back(SysRoot + "/usr/lib");
+ getFilePaths().push_back(SysRoot + "/usr/lib/gcc");
+ }
+}
+
+bool CrossWindowsToolChain::IsUnwindTablesDefault() const {
+ // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does
+ // not know how to emit them.
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool CrossWindowsToolChain::isPICDefault() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool CrossWindowsToolChain::isPIEDefault() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool CrossWindowsToolChain::isPICDefaultForced() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+void CrossWindowsToolChain::
+AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ const std::string &SysRoot = D.SysRoot;
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> ResourceDir(D.ResourceDir);
+ llvm::sys::path::append(ResourceDir, "include");
+ addSystemInclude(DriverArgs, CC1Args, ResourceDir.str());
+ }
+ addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
+}
+
+void CrossWindowsToolChain::
+AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const llvm::Triple &Triple = getTriple();
+ const std::string &SysRoot = getDriver().SysRoot;
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx:
+ addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++/v1");
+ break;
+
+ case ToolChain::CST_Libstdcxx:
+ addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++");
+ addSystemInclude(DriverArgs, CC1Args,
+ SysRoot + "/usr/include/c++/" + Triple.str());
+ addSystemInclude(DriverArgs, CC1Args,
+ SysRoot + "/usr/include/c++/backwards");
+ }
+}
+
+void CrossWindowsToolChain::
+AddCXXStdlibLibArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx:
+ CC1Args.push_back("-lc++");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ CC1Args.push_back("-lstdc++");
+ CC1Args.push_back("-lmingw32");
+ CC1Args.push_back("-lmingwex");
+ CC1Args.push_back("-lgcc");
+ CC1Args.push_back("-lmoldname");
+ CC1Args.push_back("-lmingw32");
+ break;
+ }
+}
+
+Tool *CrossWindowsToolChain::buildLinker() const {
+ return new tools::CrossWindows::Link(*this);
+}
+
+Tool *CrossWindowsToolChain::buildAssembler() const {
+ return new tools::CrossWindows::Assemble(*this);
+}
+
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index ef26bfacdd64..1664d0d49d46 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -50,7 +50,6 @@ Driver::Driver(StringRef ClangExecutable,
: Opts(createDriverOptTable()), Diags(Diags), Mode(GCCMode),
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple),
- DefaultImageName("a.out"),
DriverTitle("clang LLVM compiler"),
CCPrintOptionsFilename(nullptr), CCPrintHeadersFilename(nullptr),
CCLogDiagnosticsFilename(nullptr),
@@ -65,10 +64,13 @@ Driver::Driver(StringRef ClangExecutable,
// Compute the path to the resource directory.
StringRef ClangResourceDir(CLANG_RESOURCE_DIR);
SmallString<128> P(Dir);
- if (ClangResourceDir != "")
+ if (ClangResourceDir != "") {
llvm::sys::path::append(P, ClangResourceDir);
- else
- llvm::sys::path::append(P, "..", "lib", "clang", CLANG_VERSION_STRING);
+ } else {
+ StringRef ClangLibdirSuffix(CLANG_LIBDIR_SUFFIX);
+ llvm::sys::path::append(P, "..", Twine("lib") + ClangLibdirSuffix, "clang",
+ CLANG_VERSION_STRING);
+ }
ResourceDir = P.str();
}
@@ -83,6 +85,9 @@ void Driver::ParseDriverMode(ArrayRef<const char *> Args) {
getOpts().getOption(options::OPT_driver_mode).getPrefixedName();
for (size_t I = 0, E = Args.size(); I != E; ++I) {
+ // Ingore nullptrs, they are response file's EOL markers
+ if (Args[I] == nullptr)
+ continue;
const StringRef Arg = Args[I];
if (!Arg.startswith(OptName))
continue;
@@ -102,7 +107,7 @@ void Driver::ParseDriverMode(ArrayRef<const char *> Args) {
}
}
-InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
+InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) {
llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
unsigned IncludedFlagsBitmask;
@@ -111,7 +116,7 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
getIncludeExcludeOptionFlagMasks();
unsigned MissingArgIndex, MissingArgCount;
- InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(),
+ InputArgList *Args = getOpts().ParseArgs(ArgStrings.begin(), ArgStrings.end(),
MissingArgIndex, MissingArgCount,
IncludedFlagsBitmask,
ExcludedFlagsBitmask);
@@ -122,9 +127,7 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
<< Args->getArgString(MissingArgIndex) << MissingArgCount;
// Check for unsupported options.
- for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
- it != ie; ++it) {
- Arg *A = *it;
+ for (const Arg *A : *Args) {
if (A->getOption().hasFlag(options::Unsupported)) {
Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(*Args);
continue;
@@ -162,7 +165,7 @@ const {
(PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) {
FinalPhase = phases::Preprocess;
- // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler.
+ // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
(PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) ||
(PhaseArg = DAL.getLastArg(options::OPT_verify_pch)) ||
@@ -171,10 +174,13 @@ const {
(PhaseArg = DAL.getLastArg(options::OPT__migrate)) ||
(PhaseArg = DAL.getLastArg(options::OPT__analyze,
options::OPT__analyze_auto)) ||
- (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) ||
- (PhaseArg = DAL.getLastArg(options::OPT_S))) {
+ (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) {
FinalPhase = phases::Compile;
+ // -S only runs up to the backend.
+ } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) {
+ FinalPhase = phases::Backend;
+
// -c only runs up to the assembler.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) {
FinalPhase = phases::Assemble;
@@ -202,10 +208,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
DerivedArgList *DAL = new DerivedArgList(Args);
bool HasNostdlib = Args.hasArg(options::OPT_nostdlib);
- for (ArgList::const_iterator it = Args.begin(),
- ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
-
+ for (Arg *A : Args) {
// Unfortunately, we have to parse some forwarding options (-Xassembler,
// -Xlinker, -Xpreprocessor) because we either integrate their functionality
// (assembler and preprocessor), or bypass a previous driver ('collect2').
@@ -271,7 +274,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
continue;
}
- DAL->append(*it);
+ DAL->append(A);
}
// Add a default value of -mlinker-version=, if one was given and the user
@@ -400,13 +403,13 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// preprocessed source file(s). Request that the developer attach the
// diagnostic information to a bug report.
void Driver::generateCompilationDiagnostics(Compilation &C,
- const Command *FailingCommand) {
+ const Command &FailingCommand) {
if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics))
return;
// Don't try to generate diagnostics for link or dsymutil jobs.
- if (FailingCommand && (FailingCommand->getCreator().isLinkJob() ||
- FailingCommand->getCreator().isDsymutilJob()))
+ if (FailingCommand.getCreator().isLinkJob() ||
+ FailingCommand.getCreator().isDsymutilJob())
return;
// Print the version of the compiler.
@@ -421,15 +424,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
CCGenDiagnostics = true;
// Save the original job command(s).
- std::string Cmd;
- llvm::raw_string_ostream OS(Cmd);
- if (FailingCommand)
- FailingCommand->Print(OS, "\n", /*Quote*/ false, /*CrashReport*/ true);
- else
- // Crash triggered by FORCE_CLANG_DIAGNOSTICS_CRASH, which doesn't have an
- // associated FailingCommand, so just pass all jobs.
- C.getJobs().Print(OS, "\n", /*Quote*/ false, /*CrashReport*/ true);
- OS.flush();
+ Command Cmd = FailingCommand;
// Keep track of whether we produce any errors while trying to produce
// preprocessed sources.
@@ -473,9 +468,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
// Don't attempt to generate preprocessed files if multiple -arch options are
// used, unless they're all duplicates.
llvm::StringSet<> ArchNames;
- for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
- it != ie; ++it) {
- Arg *A = *it;
+ for (const Arg *A : C.getArgs()) {
if (A->getOption().matches(options::OPT_arch)) {
StringRef ArchName = A->getValue();
ArchNames.insert(ArchName);
@@ -509,70 +502,86 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
C.ExecuteJob(C.getJobs(), FailingCommands);
- // If the command succeeded, we are done.
- if (FailingCommands.empty()) {
+ // If any of the preprocessing commands failed, clean up and exit.
+ if (!FailingCommands.empty()) {
+ if (!C.getArgs().hasArg(options::OPT_save_temps))
+ C.CleanupFileList(C.getTempFiles(), true);
+
Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "Error generating preprocessed source(s).";
+ return;
+ }
+
+ const ArgStringList &TempFiles = C.getTempFiles();
+ if (TempFiles.empty()) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "Error generating preprocessed source(s).";
+ return;
+ }
+
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "\n********************\n\n"
- "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n"
- "Preprocessed source(s) and associated run script(s) are located at:";
- ArgStringList Files = C.getTempFiles();
- for (ArgStringList::const_iterator it = Files.begin(), ie = Files.end();
- it != ie; ++it) {
- Diag(clang::diag::note_drv_command_failed_diag_msg) << *it;
- std::string Script = StringRef(*it).rsplit('.').first;
+ "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n"
+ "Preprocessed source(s) and associated run script(s) are located at:";
+
+ SmallString<128> VFS;
+ for (const char *TempFile : TempFiles) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << TempFile;
+ if (StringRef(TempFile).endswith(".cache")) {
// In some cases (modules) we'll dump extra data to help with reproducing
// the crash into a directory next to the output.
- SmallString<128> VFS;
- if (llvm::sys::fs::exists(Script + ".cache")) {
- Diag(clang::diag::note_drv_command_failed_diag_msg)
- << Script + ".cache";
- VFS = llvm::sys::path::filename(Script + ".cache");
- llvm::sys::path::append(VFS, "vfs", "vfs.yaml");
- }
-
- std::string Err;
- Script += ".sh";
- llvm::raw_fd_ostream ScriptOS(Script.c_str(), Err, llvm::sys::fs::F_Excl);
- if (!Err.empty()) {
- Diag(clang::diag::note_drv_command_failed_diag_msg)
- << "Error generating run script: " + Script + " " + Err;
- } else {
- // Replace the original filename with the preprocessed one.
- size_t I, E;
- I = Cmd.find("-main-file-name ");
- assert (I != std::string::npos && "Expected to find -main-file-name");
- I += 16;
- E = Cmd.find(" ", I);
- assert (E != std::string::npos && "-main-file-name missing argument?");
- StringRef OldFilename = StringRef(Cmd).slice(I, E);
- StringRef NewFilename = llvm::sys::path::filename(*it);
- I = StringRef(Cmd).rfind(OldFilename);
- E = I + OldFilename.size();
- I = Cmd.rfind(" ", I) + 1;
- Cmd.replace(I, E - I, NewFilename.data(), NewFilename.size());
- if (!VFS.empty()) {
- // Add the VFS overlay to the reproduction script.
- I += NewFilename.size();
- Cmd.insert(I, std::string(" -ivfsoverlay ") + VFS.c_str());
- }
- ScriptOS << Cmd;
- Diag(clang::diag::note_drv_command_failed_diag_msg) << Script;
- }
+ VFS = llvm::sys::path::filename(TempFile);
+ llvm::sys::path::append(VFS, "vfs", "vfs.yaml");
}
+ }
+
+ // Assume associated files are based off of the first temporary file.
+ CrashReportInfo CrashInfo(TempFiles[0], VFS);
+
+ std::string Script = CrashInfo.Filename.rsplit('.').first.str() + ".sh";
+ std::error_code EC;
+ llvm::raw_fd_ostream ScriptOS(Script, EC, llvm::sys::fs::F_Excl);
+ if (EC) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
- << "\n\n********************";
+ << "Error generating run script: " + Script + " " + EC.message();
} else {
- // Failure, remove preprocessed files.
- if (!C.getArgs().hasArg(options::OPT_save_temps))
- C.CleanupFileList(C.getTempFiles(), true);
+ Cmd.Print(ScriptOS, "\n", /*Quote=*/true, &CrashInfo);
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << Script;
+ }
- Diag(clang::diag::note_drv_command_failed_diag_msg)
- << "Error generating preprocessed source(s).";
+ for (const auto &A : C.getArgs().filtered(options::OPT_frewrite_map_file,
+ options::OPT_frewrite_map_file_EQ))
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << A->getValue();
+
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "\n\n********************";
+}
+
+void Driver::setUpResponseFiles(Compilation &C, Job &J) {
+ if (JobList *Jobs = dyn_cast<JobList>(&J)) {
+ for (auto &Job : *Jobs)
+ setUpResponseFiles(C, Job);
+ return;
}
+
+ Command *CurCommand = dyn_cast<Command>(&J);
+ if (!CurCommand)
+ return;
+
+ // Since argumentsFitWithinSystemLimits() may underestimate system's capacity
+ // if the tool does not support response files, there is a chance/ that things
+ // will just work without a response file, so we silently just skip it.
+ if (CurCommand->getCreator().getResponseFilesSupport() == Tool::RF_None ||
+ llvm::sys::argumentsFitWithinSystemLimits(CurCommand->getArguments()))
+ return;
+
+ std::string TmpName = GetTemporaryPath("response", "txt");
+ CurCommand->setResponseFile(C.addTempFile(C.getArgs().MakeArgString(
+ TmpName.c_str())));
}
-int Driver::ExecuteCompilation(const Compilation &C,
- SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) const {
+int Driver::ExecuteCompilation(Compilation &C,
+ SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) {
// Just print if -### was present.
if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
C.getJobs().Print(llvm::errs(), "\n", true);
@@ -583,6 +592,9 @@ int Driver::ExecuteCompilation(const Compilation &C,
if (Diags.hasErrorOccurred())
return 1;
+ // Set up response file names for each command, if necessary
+ setUpResponseFiles(C, C.getJobs());
+
C.ExecuteJob(C.getJobs(), FailingCommands);
// Remove temp files.
@@ -653,9 +665,13 @@ void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
OS << "Target: " << TC.getTripleString() << '\n';
// Print the threading model.
- //
- // FIXME: Implement correctly.
- OS << "Thread model: " << "posix" << '\n';
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_mthread_model)) {
+ // Don't print if the ToolChain would have barfed on it already
+ if (TC.isThreadModelSupported(A->getValue()))
+ OS << "Thread model: " << A->getValue();
+ } else
+ OS << "Thread model: " << TC.getThreadModel();
+ OS << '\n';
}
/// PrintDiagnosticCategories - Implement the --print-diagnostic-categories
@@ -836,7 +852,9 @@ void Driver::PrintActions(const Compilation &C) const {
/// \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))
+ if (isa<CompileJobAction>(A) ||
+ isa<BackendJobAction>(A) ||
+ isa<AssembleJobAction>(A))
return true;
for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it)
@@ -855,10 +873,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
// be handled once (in the order seen).
llvm::StringSet<> ArchNames;
SmallVector<const char *, 4> Archs;
- for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
- it != ie; ++it) {
- Arg *A = *it;
-
+ for (Arg *A : Args) {
if (A->getOption().matches(options::OPT_arch)) {
// Validate the option here; we don't save the type here because its
// particular spelling may participate in other driver choices.
@@ -871,7 +886,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
}
A->claim();
- if (ArchNames.insert(A->getValue()))
+ if (ArchNames.insert(A->getValue()).second)
Archs.push_back(A->getValue());
}
}
@@ -901,7 +916,8 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
ActionList Inputs;
for (unsigned i = 0, e = Archs.size(); i != e; ++i) {
- Inputs.push_back(new BindArchAction(Act, Archs[i]));
+ Inputs.push_back(
+ new BindArchAction(std::unique_ptr<Action>(Act), Archs[i]));
if (i != 0)
Inputs.back()->setOwnsInputs(false);
}
@@ -932,9 +948,9 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
// Verify the debug info output.
if (Args.hasArg(options::OPT_verify_debug_info)) {
- Action *VerifyInput = Actions.back();
+ std::unique_ptr<Action> VerifyInput(Actions.back());
Actions.pop_back();
- Actions.push_back(new VerifyDebugInfoJobAction(VerifyInput,
+ Actions.push_back(new VerifyDebugInfoJobAction(std::move(VerifyInput),
types::TY_Nothing));
}
}
@@ -981,8 +997,8 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
Arg *InputTypeArg = nullptr;
// The last /TC or /TP option sets the input type to C or C++ globally.
- if (Arg *TCTP = Args.getLastArg(options::OPT__SLASH_TC,
- options::OPT__SLASH_TP)) {
+ if (Arg *TCTP = Args.getLastArgNoClaim(options::OPT__SLASH_TC,
+ options::OPT__SLASH_TP)) {
InputTypeArg = TCTP;
InputType = TCTP->getOption().matches(options::OPT__SLASH_TC)
? types::TY_C : types::TY_CXX;
@@ -1005,10 +1021,7 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
assert(!Args.hasArg(options::OPT_x) && "-x and /TC or /TP is not allowed");
}
- for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
- it != ie; ++it) {
- Arg *A = *it;
-
+ for (Arg *A : Args) {
if (A->getOption().getKind() == Option::InputClass) {
const char *Value = A->getValue();
types::ID Ty = types::TY_INVALID;
@@ -1070,8 +1083,17 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
}
} else {
assert(InputTypeArg && "InputType set w/o InputTypeArg");
- InputTypeArg->claim();
- Ty = InputType;
+ if (!InputTypeArg->getOption().matches(options::OPT_x)) {
+ // If emulating cl.exe, make sure that /TC and /TP don't affect input
+ // object files.
+ const char *Ext = strrchr(Value, '.');
+ if (Ext && TC.LookupTypeForExtension(Ext + 1) == types::TY_Object)
+ Ty = types::TY_Object;
+ }
+ if (Ty == types::TY_INVALID) {
+ Ty = InputType;
+ InputTypeArg->claim();
+ }
}
if (DiagnoseInputExistence(*this, Args, Value))
@@ -1142,11 +1164,8 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
// Diagnose misuse of /Fo.
if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) {
StringRef V = A->getValue();
- if (V.empty()) {
- // It has to have a value.
- Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1;
- Args.eraseArg(options::OPT__SLASH_Fo);
- } else if (Inputs.size() > 1 && !llvm::sys::path::is_separator(V.back())) {
+ if (Inputs.size() > 1 && !V.empty() &&
+ !llvm::sys::path::is_separator(V.back())) {
// Check whether /Fo tries to name an output file for multiple inputs.
Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources)
<< A->getSpelling() << V;
@@ -1157,7 +1176,8 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
// Diagnose misuse of /Fa.
if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fa)) {
StringRef V = A->getValue();
- if (Inputs.size() > 1 && !llvm::sys::path::is_separator(V.back())) {
+ if (Inputs.size() > 1 && !V.empty() &&
+ !llvm::sys::path::is_separator(V.back())) {
// Check whether /Fa tries to name an asm file for multiple inputs.
Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources)
<< A->getSpelling() << V;
@@ -1165,12 +1185,12 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
}
}
- // Diagnose misuse of /Fe.
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fe)) {
+ // Diagnose misuse of /o.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_o)) {
if (A->getValue()[0] == '\0') {
// It has to have a value.
Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1;
- Args.eraseArg(options::OPT__SLASH_Fe);
+ Args.eraseArg(options::OPT__SLASH_o);
}
}
@@ -1244,7 +1264,7 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
continue;
// Otherwise construct the appropriate action.
- Current.reset(ConstructPhaseAction(Args, Phase, Current.release()));
+ Current = ConstructPhaseAction(Args, Phase, std::move(Current));
if (Current->getType() == types::TY_Nothing)
break;
}
@@ -1269,8 +1289,9 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
Args.ClaimAllArgs(options::OPT_cl_ignored_Group);
}
-Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
- Action *Input) const {
+std::unique_ptr<Action>
+Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
+ std::unique_ptr<Action> Input) const {
llvm::PrettyStackTraceString CrashInfo("Constructing phase actions");
// Build the appropriate action.
switch (Phase) {
@@ -1289,7 +1310,7 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
assert(OutputTy != types::TY_INVALID &&
"Cannot preprocess this input type!");
}
- return new PreprocessJobAction(Input, OutputTy);
+ return llvm::make_unique<PreprocessJobAction>(std::move(Input), OutputTy);
}
case phases::Precompile: {
types::ID OutputTy = types::TY_PCH;
@@ -1297,39 +1318,53 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
// Syntax checks should not emit a PCH file
OutputTy = types::TY_Nothing;
}
- return new PrecompileJobAction(Input, OutputTy);
+ return llvm::make_unique<PrecompileJobAction>(std::move(Input), OutputTy);
}
case phases::Compile: {
- if (Args.hasArg(options::OPT_fsyntax_only)) {
- return new CompileJobAction(Input, types::TY_Nothing);
- } else if (Args.hasArg(options::OPT_rewrite_objc)) {
- return new CompileJobAction(Input, types::TY_RewrittenObjC);
- } else if (Args.hasArg(options::OPT_rewrite_legacy_objc)) {
- return new CompileJobAction(Input, types::TY_RewrittenLegacyObjC);
- } else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) {
- return new AnalyzeJobAction(Input, types::TY_Plist);
- } else if (Args.hasArg(options::OPT__migrate)) {
- return new MigrateJobAction(Input, types::TY_Remap);
- } else if (Args.hasArg(options::OPT_emit_ast)) {
- return new CompileJobAction(Input, types::TY_AST);
- } else if (Args.hasArg(options::OPT_module_file_info)) {
- return new CompileJobAction(Input, types::TY_ModuleFile);
- } else if (Args.hasArg(options::OPT_verify_pch)) {
- return new VerifyPCHJobAction(Input, types::TY_Nothing);
- } else if (IsUsingLTO(Args)) {
+ if (Args.hasArg(options::OPT_fsyntax_only))
+ return llvm::make_unique<CompileJobAction>(std::move(Input),
+ types::TY_Nothing);
+ if (Args.hasArg(options::OPT_rewrite_objc))
+ return llvm::make_unique<CompileJobAction>(std::move(Input),
+ types::TY_RewrittenObjC);
+ if (Args.hasArg(options::OPT_rewrite_legacy_objc))
+ return llvm::make_unique<CompileJobAction>(std::move(Input),
+ types::TY_RewrittenLegacyObjC);
+ if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto))
+ return llvm::make_unique<AnalyzeJobAction>(std::move(Input),
+ types::TY_Plist);
+ if (Args.hasArg(options::OPT__migrate))
+ return llvm::make_unique<MigrateJobAction>(std::move(Input),
+ types::TY_Remap);
+ if (Args.hasArg(options::OPT_emit_ast))
+ return llvm::make_unique<CompileJobAction>(std::move(Input),
+ types::TY_AST);
+ if (Args.hasArg(options::OPT_module_file_info))
+ return llvm::make_unique<CompileJobAction>(std::move(Input),
+ types::TY_ModuleFile);
+ if (Args.hasArg(options::OPT_verify_pch))
+ return llvm::make_unique<VerifyPCHJobAction>(std::move(Input),
+ types::TY_Nothing);
+ return llvm::make_unique<CompileJobAction>(std::move(Input),
+ types::TY_LLVM_BC);
+ }
+ case phases::Backend: {
+ if (IsUsingLTO(Args)) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
- return new CompileJobAction(Input, Output);
- } else if (Args.hasArg(options::OPT_emit_llvm)) {
+ return llvm::make_unique<BackendJobAction>(std::move(Input), Output);
+ }
+ if (Args.hasArg(options::OPT_emit_llvm)) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC;
- return new CompileJobAction(Input, Output);
- } else {
- return new CompileJobAction(Input, types::TY_PP_Asm);
+ return llvm::make_unique<BackendJobAction>(std::move(Input), Output);
}
+ return llvm::make_unique<BackendJobAction>(std::move(Input),
+ types::TY_PP_Asm);
}
case phases::Assemble:
- return new AssembleJobAction(Input, types::TY_Object);
+ return llvm::make_unique<AssembleJobAction>(std::move(Input),
+ types::TY_Object);
}
llvm_unreachable("invalid phase in ConstructPhaseAction");
@@ -1351,9 +1386,8 @@ void Driver::BuildJobs(Compilation &C) const {
// files.
if (FinalOutput) {
unsigned NumOutputs = 0;
- for (ActionList::const_iterator it = C.getActions().begin(),
- ie = C.getActions().end(); it != ie; ++it)
- if ((*it)->getType() != types::TY_Nothing)
+ for (const Action *A : C.getActions())
+ if (A->getType() != types::TY_Nothing)
++NumOutputs;
if (NumOutputs > 1) {
@@ -1364,19 +1398,12 @@ void Driver::BuildJobs(Compilation &C) const {
// Collect the list of architectures.
llvm::StringSet<> ArchNames;
- if (C.getDefaultToolChain().getTriple().isOSBinFormatMachO()) {
- for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
- it != ie; ++it) {
- Arg *A = *it;
+ if (C.getDefaultToolChain().getTriple().isOSBinFormatMachO())
+ for (const Arg *A : C.getArgs())
if (A->getOption().matches(options::OPT_arch))
ArchNames.insert(A->getValue());
- }
- }
-
- for (ActionList::const_iterator it = C.getActions().begin(),
- ie = C.getActions().end(); it != ie; ++it) {
- Action *A = *it;
+ for (Action *A : C.getActions()) {
// If we are linking an image for multiple archs then the linker wants
// -arch_multiple and -final_output <final image name>. Unfortunately, this
// doesn't fit in cleanly because we have to pass this information down.
@@ -1388,7 +1415,7 @@ void Driver::BuildJobs(Compilation &C) const {
if (FinalOutput)
LinkingOutput = FinalOutput->getValue();
else
- LinkingOutput = DefaultImageName.c_str();
+ LinkingOutput = getDefaultImageName();
}
InputInfo II;
@@ -1412,10 +1439,7 @@ void Driver::BuildJobs(Compilation &C) const {
// Claim --driver-mode, it was handled earlier.
(void) C.getArgs().hasArg(options::OPT_driver_mode);
- for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
- it != ie; ++it) {
- Arg *A = *it;
-
+ for (Arg *A : C.getArgs()) {
// FIXME: It would be nice to be able to send the argument to the
// DiagnosticsEngine, so that extra values, position, and so on could be
// printed.
@@ -1462,12 +1486,34 @@ static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC,
!C.getArgs().hasArg(options::OPT__SLASH_FA) &&
!C.getArgs().hasArg(options::OPT__SLASH_Fa) &&
isa<AssembleJobAction>(JA) &&
- Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) {
- const Tool *Compiler =
- TC->SelectTool(cast<JobAction>(**Inputs->begin()));
+ Inputs->size() == 1 && isa<BackendJobAction>(*Inputs->begin())) {
+ // A BackendJob is always preceded by a CompileJob, and without
+ // -save-temps they will always get combined together, so instead of
+ // checking the backend tool, check if the tool for the CompileJob
+ // has an integrated assembler.
+ const ActionList *BackendInputs = &(*Inputs)[0]->getInputs();
+ JobAction *CompileJA = cast<CompileJobAction>(*BackendInputs->begin());
+ const Tool *Compiler = TC->SelectTool(*CompileJA);
if (!Compiler)
return nullptr;
if (Compiler->hasIntegratedAssembler()) {
+ Inputs = &(*BackendInputs)[0]->getInputs();
+ ToolForJob = Compiler;
+ }
+ }
+
+ // A backend job should always be combined with the preceding compile job
+ // unless OPT_save_temps is enabled and the compiler is capable of emitting
+ // LLVM IR as an intermediate output.
+ if (isa<BackendJobAction>(JA)) {
+ // Check if the compiler supports emitting LLVM IR.
+ assert(Inputs->size() == 1);
+ JobAction *CompileJA = cast<CompileJobAction>(*Inputs->begin());
+ const Tool *Compiler = TC->SelectTool(*CompileJA);
+ if (!Compiler)
+ return nullptr;
+ if (!Compiler->canEmitIR() ||
+ !C.getArgs().hasArg(options::OPT_save_temps)) {
Inputs = &(*Inputs)[0]->getInputs();
ToolForJob = Compiler;
}
@@ -1537,8 +1583,7 @@ void Driver::BuildJobsForAction(Compilation &C,
// Only use pipes when there is exactly one input.
InputInfoList InputInfos;
- for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end();
- it != ie; ++it) {
+ for (const Action *Input : *Inputs) {
// Treat dsymutil and verify sub-jobs as being at the top-level too, they
// shouldn't get temporary output names.
// FIXME: Clean this up.
@@ -1547,7 +1592,7 @@ void Driver::BuildJobsForAction(Compilation &C,
SubJobAtTopLevel = true;
InputInfo II;
- BuildJobsForAction(C, *it, TC, BoundArch, SubJobAtTopLevel, MultipleArchs,
+ BuildJobsForAction(C, Input, TC, BoundArch, SubJobAtTopLevel, MultipleArchs,
LinkingOutput, II);
InputInfos.push_back(II);
}
@@ -1583,6 +1628,11 @@ void Driver::BuildJobsForAction(Compilation &C,
}
}
+const char *Driver::getDefaultImageName() const {
+ llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple));
+ return Target.isOSWindows() ? "a.exe" : "a.out";
+}
+
/// \brief Create output filename based on ArgValue, which could either be a
/// full filename, filename without extension, or a directory. If ArgValue
/// does not provide a filename, then use BaseName, and use the extension
@@ -1634,7 +1684,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
assert(AtTopLevel && isa<PreprocessJobAction>(JA));
StringRef BaseName = llvm::sys::path::filename(BaseInput);
StringRef NameArg;
- if (Arg *A = C.getArgs().getLastArg(options::OPT__SLASH_Fi))
+ if (Arg *A = C.getArgs().getLastArg(options::OPT__SLASH_Fi,
+ options::OPT__SLASH_o))
NameArg = A->getValue();
return C.addResultFile(MakeCLOutputFilename(C.getArgs(), NameArg, BaseName,
types::TY_PP_C), &JA);
@@ -1681,15 +1732,17 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
const char *NamedOutput;
if (JA.getType() == types::TY_Object &&
- C.getArgs().hasArg(options::OPT__SLASH_Fo)) {
- // The /Fo flag decides the object filename.
- StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fo)->getValue();
+ C.getArgs().hasArg(options::OPT__SLASH_Fo, options::OPT__SLASH_o)) {
+ // The /Fo or /o flag decides the object filename.
+ StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fo,
+ options::OPT__SLASH_o)->getValue();
NamedOutput = MakeCLOutputFilename(C.getArgs(), Val, BaseName,
types::TY_Object);
} else if (JA.getType() == types::TY_Image &&
- C.getArgs().hasArg(options::OPT__SLASH_Fe)) {
- // The /Fe flag names the linked file.
- StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fe)->getValue();
+ C.getArgs().hasArg(options::OPT__SLASH_Fe, options::OPT__SLASH_o)) {
+ // The /Fe or /o flag names the linked file.
+ StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fe,
+ options::OPT__SLASH_o)->getValue();
NamedOutput = MakeCLOutputFilename(C.getArgs(), Val, BaseName,
types::TY_Image);
} else if (JA.getType() == types::TY_Image) {
@@ -1698,12 +1751,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
NamedOutput = MakeCLOutputFilename(C.getArgs(), "", BaseName,
types::TY_Image);
} else if (MultipleArchs && BoundArch) {
- SmallString<128> Output(DefaultImageName.c_str());
+ SmallString<128> Output(getDefaultImageName());
Output += "-";
Output.append(BoundArch);
NamedOutput = C.getArgs().MakeArgString(Output.c_str());
} else
- NamedOutput = DefaultImageName.c_str();
+ NamedOutput = getDefaultImageName();
} else {
const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode());
assert(Suffix && "All types used for output should have a suffix.");
@@ -1716,6 +1769,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
Suffixed += "-";
Suffixed.append(BoundArch);
}
+ // When using both -save-temps and -emit-llvm, use a ".tmp.bc" suffix for
+ // the unoptimized bitcode so that it does not get overwritten by the ".bc"
+ // optimized bitcode output.
+ if (!AtTopLevel && C.getArgs().hasArg(options::OPT_emit_llvm) &&
+ JA.getType() == types::TY_LLVM_BC)
+ Suffixed += ".tmp";
Suffixed += '.';
Suffixed += Suffix;
NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str());
@@ -1793,51 +1852,56 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
return Name;
}
+void
+Driver::generatePrefixedToolNames(const char *Tool, const ToolChain &TC,
+ SmallVectorImpl<std::string> &Names) const {
+ // FIXME: Needs a better variable than DefaultTargetTriple
+ Names.push_back(DefaultTargetTriple + "-" + Tool);
+ Names.push_back(Tool);
+}
+
+static bool ScanDirForExecutable(SmallString<128> &Dir,
+ ArrayRef<std::string> Names) {
+ for (const auto &Name : Names) {
+ llvm::sys::path::append(Dir, Name);
+ if (llvm::sys::fs::can_execute(Twine(Dir)))
+ return true;
+ llvm::sys::path::remove_filename(Dir);
+ }
+ return false;
+}
+
std::string Driver::GetProgramPath(const char *Name,
const ToolChain &TC) const {
- // FIXME: Needs a better variable than DefaultTargetTriple
- std::string TargetSpecificExecutable(DefaultTargetTriple + "-" + Name);
+ SmallVector<std::string, 2> TargetSpecificExecutables;
+ generatePrefixedToolNames(Name, TC, TargetSpecificExecutables);
+
// Respect a limited subset of the '-Bprefix' functionality in GCC by
// attempting to use this prefix when looking for program paths.
- for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(),
- ie = PrefixDirs.end(); it != ie; ++it) {
- if (llvm::sys::fs::is_directory(*it)) {
- SmallString<128> P(*it);
- llvm::sys::path::append(P, TargetSpecificExecutable);
- if (llvm::sys::fs::can_execute(Twine(P)))
- return P.str();
- llvm::sys::path::remove_filename(P);
- llvm::sys::path::append(P, Name);
- if (llvm::sys::fs::can_execute(Twine(P)))
+ for (const auto &PrefixDir : PrefixDirs) {
+ if (llvm::sys::fs::is_directory(PrefixDir)) {
+ SmallString<128> P(PrefixDir);
+ if (ScanDirForExecutable(P, TargetSpecificExecutables))
return P.str();
} else {
- SmallString<128> P(*it + Name);
+ SmallString<128> P(PrefixDir + Name);
if (llvm::sys::fs::can_execute(Twine(P)))
return P.str();
}
}
const ToolChain::path_list &List = TC.getProgramPaths();
- for (ToolChain::path_list::const_iterator
- it = List.begin(), ie = List.end(); it != ie; ++it) {
- SmallString<128> P(*it);
- llvm::sys::path::append(P, TargetSpecificExecutable);
- if (llvm::sys::fs::can_execute(Twine(P)))
- return P.str();
- llvm::sys::path::remove_filename(P);
- llvm::sys::path::append(P, Name);
- if (llvm::sys::fs::can_execute(Twine(P)))
+ for (const auto &Path : List) {
+ SmallString<128> P(Path);
+ if (ScanDirForExecutable(P, TargetSpecificExecutables))
return P.str();
}
// If all else failed, search the path.
- std::string P(llvm::sys::FindProgramByName(TargetSpecificExecutable));
- if (!P.empty())
- return P;
-
- P = llvm::sys::FindProgramByName(Name);
- if (!P.empty())
- return P;
+ for (const auto &TargetSpecificExecutable : TargetSpecificExecutables)
+ if (llvm::ErrorOr<std::string> P =
+ llvm::sys::findProgramByName(TargetSpecificExecutable))
+ return *P;
return Name;
}
@@ -1893,8 +1957,6 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
Target.setArch(llvm::Triple::mips64el);
else if (Target.getArch() == llvm::Triple::aarch64_be)
Target.setArch(llvm::Triple::aarch64);
- else if (Target.getArch() == llvm::Triple::arm64_be)
- Target.setArch(llvm::Triple::arm64);
} else {
if (Target.getArch() == llvm::Triple::mipsel)
Target.setArch(llvm::Triple::mips);
@@ -1902,15 +1964,11 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
Target.setArch(llvm::Triple::mips64);
else if (Target.getArch() == llvm::Triple::aarch64)
Target.setArch(llvm::Triple::aarch64_be);
- else if (Target.getArch() == llvm::Triple::arm64)
- Target.setArch(llvm::Triple::arm64_be);
}
}
// Skip further flag support on OSes which don't support '-m32' or '-m64'.
- if (Target.getArchName() == "tce" ||
- Target.getOS() == llvm::Triple::AuroraUX ||
- Target.getOS() == llvm::Triple::Minix)
+ if (Target.getArchName() == "tce" || Target.getOS() == llvm::Triple::Minix)
return Target;
// Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'.
@@ -1918,21 +1976,25 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
options::OPT_m32, options::OPT_m16)) {
llvm::Triple::ArchType AT = llvm::Triple::UnknownArch;
- if (A->getOption().matches(options::OPT_m64))
+ if (A->getOption().matches(options::OPT_m64)) {
AT = Target.get64BitArchVariant().getArch();
- else if (A->getOption().matches(options::OPT_mx32) &&
+ if (Target.getEnvironment() == llvm::Triple::GNUX32)
+ Target.setEnvironment(llvm::Triple::GNU);
+ } else if (A->getOption().matches(options::OPT_mx32) &&
Target.get64BitArchVariant().getArch() == llvm::Triple::x86_64) {
AT = llvm::Triple::x86_64;
Target.setEnvironment(llvm::Triple::GNUX32);
- } else if (A->getOption().matches(options::OPT_m32))
+ } else if (A->getOption().matches(options::OPT_m32)) {
AT = Target.get32BitArchVariant().getArch();
- else if (A->getOption().matches(options::OPT_m16) &&
+ if (Target.getEnvironment() == llvm::Triple::GNUX32)
+ Target.setEnvironment(llvm::Triple::GNU);
+ } else if (A->getOption().matches(options::OPT_m16) &&
Target.get32BitArchVariant().getArch() == llvm::Triple::x86) {
AT = llvm::Triple::x86;
Target.setEnvironment(llvm::Triple::CODE16);
}
- if (AT != llvm::Triple::UnknownArch)
+ if (AT != llvm::Triple::UnknownArch && AT != Target.getArch())
Target.setArch(AT);
}
@@ -1947,9 +2009,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
ToolChain *&TC = ToolChains[Target.str()];
if (!TC) {
switch (Target.getOS()) {
- case llvm::Triple::AuroraUX:
- TC = new toolchains::AuroraUX(*this, Target, Args);
- break;
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
case llvm::Triple::IOS:
@@ -2000,9 +2059,12 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
else
TC = new toolchains::Generic_GCC(*this, Target, Args);
break;
+ case llvm::Triple::Itanium:
+ TC = new toolchains::CrossWindowsToolChain(*this, Target, Args);
+ break;
case llvm::Triple::MSVC:
case llvm::Triple::UnknownEnvironment:
- TC = new toolchains::Windows(*this, Target, Args);
+ TC = new toolchains::MSVCToolChain(*this, Target, Args);
break;
}
break;
@@ -2025,7 +2087,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
TC = new toolchains::Generic_ELF(*this, Target, Args);
break;
}
- if (Target.getObjectFormat() == llvm::Triple::MachO) {
+ if (Target.isOSBinFormatMachO()) {
TC = new toolchains::MachO(*this, Target, Args);
break;
}
@@ -2045,7 +2107,7 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const {
// Otherwise make sure this is an action clang understands.
if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) &&
- !isa<CompileJobAction>(JA))
+ !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA))
return false;
return true;
diff --git a/lib/Driver/InputInfo.h b/lib/Driver/InputInfo.h
index 4eedd22a62da..b23ba575b65e 100644
--- a/lib/Driver/InputInfo.h
+++ b/lib/Driver/InputInfo.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_LIB_DRIVER_INPUTINFO_H_
-#define CLANG_LIB_DRIVER_INPUTINFO_H_
+#ifndef LLVM_CLANG_LIB_DRIVER_INPUTINFO_H
+#define LLVM_CLANG_LIB_DRIVER_INPUTINFO_H
#include "clang/Driver/Types.h"
#include "llvm/Option/Arg.h"
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 42cc1bc29077..c5b3f5a307b9 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -12,8 +12,10 @@
#include "clang/Driver/Job.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
@@ -21,6 +23,7 @@
using namespace clang::driver;
using llvm::raw_ostream;
using llvm::StringRef;
+using llvm::ArrayRef;
Job::~Job() {}
@@ -28,7 +31,8 @@ Command::Command(const Action &_Source, const Tool &_Creator,
const char *_Executable,
const ArgStringList &_Arguments)
: Job(CommandClass), Source(_Source), Creator(_Creator),
- Executable(_Executable), Arguments(_Arguments) {}
+ Executable(_Executable), Arguments(_Arguments),
+ ResponseFile(nullptr) {}
static int skipArgs(const char *Flag) {
// These flags are all of the form -Flag <Arg> and are treated as two
@@ -69,12 +73,6 @@ static int skipArgs(const char *Flag) {
return 0;
}
-static bool quoteNextArg(const char *flag) {
- return llvm::StringSwitch<bool>(flag)
- .Case("-D", true)
- .Default(false);
-}
-
static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) {
const bool Escape = std::strpbrk(Arg, "\"\\$");
@@ -93,38 +91,162 @@ static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) {
OS << '"';
}
+void Command::writeResponseFile(raw_ostream &OS) const {
+ // In a file list, we only write the set of inputs to the response file
+ if (Creator.getResponseFilesSupport() == Tool::RF_FileList) {
+ for (const char *Arg : InputFileList) {
+ OS << Arg << '\n';
+ }
+ return;
+ }
+
+ // In regular response files, we send all arguments to the response file
+ for (const char *Arg : Arguments) {
+ OS << '"';
+
+ for (; *Arg != '\0'; Arg++) {
+ if (*Arg == '\"' || *Arg == '\\') {
+ OS << '\\';
+ }
+ OS << *Arg;
+ }
+
+ OS << "\" ";
+ }
+}
+
+void Command::buildArgvForResponseFile(
+ llvm::SmallVectorImpl<const char *> &Out) const {
+ // When not a file list, all arguments are sent to the response file.
+ // This leaves us to set the argv to a single parameter, requesting the tool
+ // to read the response file.
+ if (Creator.getResponseFilesSupport() != Tool::RF_FileList) {
+ Out.push_back(Executable);
+ Out.push_back(ResponseFileFlag.c_str());
+ return;
+ }
+
+ llvm::StringSet<> Inputs;
+ for (const char *InputName : InputFileList)
+ Inputs.insert(InputName);
+ Out.push_back(Executable);
+ // In a file list, build args vector ignoring parameters that will go in the
+ // response file (elements of the InputFileList vector)
+ bool FirstInput = true;
+ for (const char *Arg : Arguments) {
+ if (Inputs.count(Arg) == 0) {
+ Out.push_back(Arg);
+ } else if (FirstInput) {
+ FirstInput = false;
+ Out.push_back(Creator.getResponseFileFlag());
+ Out.push_back(ResponseFile);
+ }
+ }
+}
+
void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
- bool CrashReport) const {
- OS << " \"" << Executable << '"';
+ CrashReportInfo *CrashInfo) const {
+ // Always quote the exe.
+ OS << ' ';
+ PrintArg(OS, Executable, /*Quote=*/true);
+
+ llvm::ArrayRef<const char *> Args = Arguments;
+ llvm::SmallVector<const char *, 128> ArgsRespFile;
+ if (ResponseFile != nullptr) {
+ buildArgvForResponseFile(ArgsRespFile);
+ Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
+ }
- for (size_t i = 0, e = Arguments.size(); i < e; ++i) {
- const char *const Arg = Arguments[i];
+ StringRef MainFilename;
+ // We'll need the argument to -main-file-name to find the input file name.
+ if (CrashInfo)
+ for (size_t I = 0, E = Args.size(); I + 1 < E; ++I)
+ if (StringRef(Args[I]).equals("-main-file-name"))
+ MainFilename = Args[I + 1];
- if (CrashReport) {
+ for (size_t i = 0, e = Args.size(); i < e; ++i) {
+ const char *const Arg = Args[i];
+
+ if (CrashInfo) {
if (int Skip = skipArgs(Arg)) {
i += Skip - 1;
continue;
+ } else if (llvm::sys::path::filename(Arg) == MainFilename &&
+ (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) {
+ // Replace the input file name with the crashinfo's file name.
+ OS << ' ';
+ StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename);
+ PrintArg(OS, ShortName.str().c_str(), Quote);
+ continue;
}
}
OS << ' ';
PrintArg(OS, Arg, Quote);
+ }
- if (CrashReport && quoteNextArg(Arg) && i + 1 < e) {
- OS << ' ';
- PrintArg(OS, Arguments[++i], true);
- }
+ if (CrashInfo && !CrashInfo->VFSPath.empty()) {
+ OS << ' ';
+ PrintArg(OS, "-ivfsoverlay", Quote);
+ OS << ' ';
+ PrintArg(OS, CrashInfo->VFSPath.str().c_str(), Quote);
}
+
+ if (ResponseFile != nullptr) {
+ OS << "\n Arguments passed via response file:\n";
+ writeResponseFile(OS);
+ // Avoiding duplicated newline terminator, since FileLists are
+ // newline-separated.
+ if (Creator.getResponseFilesSupport() != Tool::RF_FileList)
+ OS << "\n";
+ OS << " (end of response file)";
+ }
+
OS << Terminator;
}
+void Command::setResponseFile(const char *FileName) {
+ ResponseFile = FileName;
+ ResponseFileFlag = Creator.getResponseFileFlag();
+ ResponseFileFlag += FileName;
+}
+
int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
bool *ExecutionFailed) const {
SmallVector<const char*, 128> Argv;
- Argv.push_back(Executable);
- for (size_t i = 0, e = Arguments.size(); i != e; ++i)
- Argv.push_back(Arguments[i]);
+
+ if (ResponseFile == nullptr) {
+ Argv.push_back(Executable);
+ for (size_t i = 0, e = Arguments.size(); i != e; ++i)
+ Argv.push_back(Arguments[i]);
+ Argv.push_back(nullptr);
+
+ return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
+ Redirects, /*secondsToWait*/ 0,
+ /*memoryLimit*/ 0, ErrMsg,
+ ExecutionFailed);
+ }
+
+ // We need to put arguments in a response file (command is too large)
+ // Open stream to store the response file contents
+ std::string RespContents;
+ llvm::raw_string_ostream SS(RespContents);
+
+ // Write file contents and build the Argv vector
+ writeResponseFile(SS);
+ buildArgvForResponseFile(Argv);
Argv.push_back(nullptr);
+ SS.flush();
+
+ // Save the response file in the appropriate encoding
+ if (std::error_code EC = writeFileWithEncoding(
+ ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
+ if (ErrMsg)
+ *ErrMsg = EC.message();
+ if (ExecutionFailed)
+ *ExecutionFailed = true;
+ return -1;
+ }
return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
Redirects, /*secondsToWait*/ 0,
@@ -134,15 +256,15 @@ int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
const char *Executable_,
const ArgStringList &Arguments_,
- Command *Fallback_)
- : Command(Source_, Creator_, Executable_, Arguments_), Fallback(Fallback_) {
-}
+ std::unique_ptr<Command> Fallback_)
+ : Command(Source_, Creator_, Executable_, Arguments_),
+ Fallback(std::move(Fallback_)) {}
void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
- bool Quote, bool CrashReport) const {
- Command::Print(OS, "", Quote, CrashReport);
+ bool Quote, CrashReportInfo *CrashInfo) const {
+ Command::Print(OS, "", Quote, CrashInfo);
OS << " ||";
- Fallback->Print(OS, Terminator, Quote, CrashReport);
+ Fallback->Print(OS, Terminator, Quote, CrashInfo);
}
static bool ShouldFallback(int ExitCode) {
@@ -173,17 +295,10 @@ int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
JobList::JobList() : Job(JobListClass) {}
-JobList::~JobList() {
- for (iterator it = begin(), ie = end(); it != ie; ++it)
- delete *it;
-}
-
void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
- bool CrashReport) const {
- for (const_iterator it = begin(), ie = end(); it != ie; ++it)
- (*it)->Print(OS, Terminator, Quote, CrashReport);
+ CrashReportInfo *CrashInfo) const {
+ for (const auto &Job : *this)
+ Job.Print(OS, Terminator, Quote, CrashInfo);
}
-void JobList::clear() {
- DeleteContainerPointers(Jobs);
-}
+void JobList::clear() { Jobs.clear(); }
diff --git a/lib/Driver/MSVCToolChain.cpp b/lib/Driver/MSVCToolChain.cpp
new file mode 100644
index 000000000000..d6bd5c31ae6e
--- /dev/null
+++ b/lib/Driver/MSVCToolChain.cpp
@@ -0,0 +1,496 @@
+//===--- ToolChains.cpp - ToolChain Implementations -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ToolChains.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/Version.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Process.h"
+
+// Include the necessary headers to interface with the Windows registry and
+// environment.
+#if defined(LLVM_ON_WIN32)
+#define USE_WIN32
+#endif
+
+#ifdef USE_WIN32
+ #define WIN32_LEAN_AND_MEAN
+ #define NOGDI
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+ #include <windows.h>
+#endif
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+}
+
+Tool *MSVCToolChain::buildLinker() const {
+ return new tools::visualstudio::Link(*this);
+}
+
+Tool *MSVCToolChain::buildAssembler() const {
+ if (getTriple().isOSBinFormatMachO())
+ return new tools::darwin::Assemble(*this);
+ getDriver().Diag(clang::diag::err_no_external_assembler);
+ return nullptr;
+}
+
+bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
+ return true;
+}
+
+bool MSVCToolChain::IsUnwindTablesDefault() const {
+ // Emit unwind tables by default on Win64. All non-x86_32 Windows platforms
+ // such as ARM and PPC actually require unwind tables, but LLVM doesn't know
+ // how to generate them yet.
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool MSVCToolChain::isPICDefault() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool MSVCToolChain::isPIEDefault() const {
+ return false;
+}
+
+bool MSVCToolChain::isPICDefaultForced() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+#ifdef USE_WIN32
+static bool readFullStringValue(HKEY hkey, const char *valueName,
+ std::string &value) {
+ // FIXME: We should be using the W versions of the registry functions, but
+ // doing so requires UTF8 / UTF16 conversions similar to how we handle command
+ // line arguments. The UTF8 conversion functions are not exposed publicly
+ // from LLVM though, so in order to do this we will probably need to create
+ // a registry abstraction in LLVMSupport that is Windows only.
+ DWORD result = 0;
+ DWORD valueSize = 0;
+ DWORD type = 0;
+ // First just query for the required size.
+ result = RegQueryValueEx(hkey, valueName, NULL, &type, NULL, &valueSize);
+ if (result != ERROR_SUCCESS || type != REG_SZ)
+ return false;
+ std::vector<BYTE> buffer(valueSize);
+ result = RegQueryValueEx(hkey, valueName, NULL, NULL, &buffer[0], &valueSize);
+ if (result == ERROR_SUCCESS)
+ value.assign(reinterpret_cast<const char *>(buffer.data()));
+ return result;
+}
+#endif
+
+/// \brief Read registry string.
+/// This also supports a means to look for high-versioned keys by use
+/// of a $VERSION placeholder in the key path.
+/// $VERSION in the key path is a placeholder for the version number,
+/// causing the highest value path to be searched for and used.
+/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
+/// There can be additional characters in the component. Only the numeric
+/// characters are compared. This function only searches HKLM.
+static bool getSystemRegistryString(const char *keyPath, const char *valueName,
+ std::string &value, std::string *phValue) {
+#ifndef USE_WIN32
+ return false;
+#else
+ HKEY hRootKey = HKEY_LOCAL_MACHINE;
+ HKEY hKey = NULL;
+ long lResult;
+ bool returnValue = false;
+
+ const char *placeHolder = strstr(keyPath, "$VERSION");
+ std::string bestName;
+ // If we have a $VERSION placeholder, do the highest-version search.
+ if (placeHolder) {
+ const char *keyEnd = placeHolder - 1;
+ const char *nextKey = placeHolder;
+ // Find end of previous key.
+ while ((keyEnd > keyPath) && (*keyEnd != '\\'))
+ keyEnd--;
+ // Find end of key containing $VERSION.
+ while (*nextKey && (*nextKey != '\\'))
+ nextKey++;
+ size_t partialKeyLength = keyEnd - keyPath;
+ char partialKey[256];
+ if (partialKeyLength > sizeof(partialKey))
+ partialKeyLength = sizeof(partialKey);
+ strncpy(partialKey, keyPath, partialKeyLength);
+ partialKey[partialKeyLength] = '\0';
+ HKEY hTopKey = NULL;
+ lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
+ &hTopKey);
+ if (lResult == ERROR_SUCCESS) {
+ char keyName[256];
+ double bestValue = 0.0;
+ DWORD index, size = sizeof(keyName) - 1;
+ for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
+ NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
+ const char *sp = keyName;
+ while (*sp && !isDigit(*sp))
+ sp++;
+ if (!*sp)
+ continue;
+ const char *ep = sp + 1;
+ while (*ep && (isDigit(*ep) || (*ep == '.')))
+ ep++;
+ char numBuf[32];
+ strncpy(numBuf, sp, sizeof(numBuf) - 1);
+ numBuf[sizeof(numBuf) - 1] = '\0';
+ double dvalue = strtod(numBuf, NULL);
+ if (dvalue > bestValue) {
+ // Test that InstallDir is indeed there before keeping this index.
+ // Open the chosen key path remainder.
+ bestName = keyName;
+ // Append rest of key.
+ bestName.append(nextKey);
+ lResult = RegOpenKeyEx(hTopKey, bestName.c_str(), 0,
+ KEY_READ | KEY_WOW64_32KEY, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ lResult = readFullStringValue(hKey, valueName, value);
+ if (lResult == ERROR_SUCCESS) {
+ bestValue = dvalue;
+ if (phValue)
+ *phValue = bestName;
+ returnValue = true;
+ }
+ RegCloseKey(hKey);
+ }
+ }
+ size = sizeof(keyName) - 1;
+ }
+ RegCloseKey(hTopKey);
+ }
+ } else {
+ lResult =
+ RegOpenKeyEx(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ lResult = readFullStringValue(hKey, valueName, value);
+ if (lResult == ERROR_SUCCESS)
+ returnValue = true;
+ if (phValue)
+ phValue->clear();
+ RegCloseKey(hKey);
+ }
+ }
+ return returnValue;
+#endif // USE_WIN32
+}
+
+/// \brief Get Windows SDK installation directory.
+bool MSVCToolChain::getWindowsSDKDir(std::string &path, int &major,
+ int &minor) const {
+ std::string sdkVersion;
+ // Try the Windows registry.
+ bool hasSDKDir = getSystemRegistryString(
+ "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
+ "InstallationFolder", path, &sdkVersion);
+ if (!sdkVersion.empty())
+ ::sscanf(sdkVersion.c_str(), "v%d.%d", &major, &minor);
+ return hasSDKDir && !path.empty();
+}
+
+// Gets the library path required to link against the Windows SDK.
+bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
+ std::string sdkPath;
+ int sdkMajor = 0;
+ int sdkMinor = 0;
+
+ path.clear();
+ if (!getWindowsSDKDir(sdkPath, sdkMajor, sdkMinor))
+ return false;
+
+ llvm::SmallString<128> libPath(sdkPath);
+ llvm::sys::path::append(libPath, "Lib");
+ if (sdkMajor <= 7) {
+ switch (getArch()) {
+ // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
+ case llvm::Triple::x86:
+ break;
+ case llvm::Triple::x86_64:
+ llvm::sys::path::append(libPath, "x64");
+ break;
+ case llvm::Triple::arm:
+ // It is not necessary to link against Windows SDK 7.x when targeting ARM.
+ return false;
+ default:
+ return false;
+ }
+ } else {
+ // Windows SDK 8.x installs libraries in a folder whose names depend on the
+ // version of the OS you're targeting. By default choose the newest, which
+ // usually corresponds to the version of the OS you've installed the SDK on.
+ const char *tests[] = {"winv6.3", "win8", "win7"};
+ bool found = false;
+ for (const char *test : tests) {
+ llvm::SmallString<128> testPath(libPath);
+ llvm::sys::path::append(testPath, test);
+ if (llvm::sys::fs::exists(testPath.c_str())) {
+ libPath = testPath;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return false;
+
+ llvm::sys::path::append(libPath, "um");
+ switch (getArch()) {
+ case llvm::Triple::x86:
+ llvm::sys::path::append(libPath, "x86");
+ break;
+ case llvm::Triple::x86_64:
+ llvm::sys::path::append(libPath, "x64");
+ break;
+ case llvm::Triple::arm:
+ llvm::sys::path::append(libPath, "arm");
+ break;
+ default:
+ return false;
+ }
+ }
+
+ path = libPath.str();
+ return true;
+}
+
+// Get the location to use for Visual Studio binaries. The location priority
+// is: %VCINSTALLDIR% > %PATH% > newest copy of Visual Studio installed on
+// system (as reported by the registry).
+bool MSVCToolChain::getVisualStudioBinariesFolder(const char *clangProgramPath,
+ std::string &path) const {
+ path.clear();
+
+ SmallString<128> BinDir;
+
+ // First check the environment variables that vsvars32.bat sets.
+ llvm::Optional<std::string> VcInstallDir =
+ llvm::sys::Process::GetEnv("VCINSTALLDIR");
+ if (VcInstallDir.hasValue()) {
+ BinDir = VcInstallDir.getValue();
+ llvm::sys::path::append(BinDir, "bin");
+ } else {
+ // Next walk the PATH, trying to find a cl.exe in the path. If we find one,
+ // use that. However, make sure it's not clang's cl.exe.
+ llvm::Optional<std::string> OptPath = llvm::sys::Process::GetEnv("PATH");
+ if (OptPath.hasValue()) {
+ const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
+ SmallVector<StringRef, 8> PathSegments;
+ llvm::SplitString(OptPath.getValue(), PathSegments, EnvPathSeparatorStr);
+
+ for (StringRef PathSegment : PathSegments) {
+ if (PathSegment.empty())
+ continue;
+
+ SmallString<128> FilePath(PathSegment);
+ llvm::sys::path::append(FilePath, "cl.exe");
+ if (llvm::sys::fs::can_execute(FilePath.c_str()) &&
+ !llvm::sys::fs::equivalent(FilePath.c_str(), clangProgramPath)) {
+ // If we found it on the PATH, use it exactly as is with no
+ // modifications.
+ path = PathSegment;
+ return true;
+ }
+ }
+ }
+
+ std::string installDir;
+ // With no VCINSTALLDIR and nothing on the PATH, if we can't find it in the
+ // registry then we have no choice but to fail.
+ if (!getVisualStudioInstallDir(installDir))
+ return false;
+
+ // Regardless of what binary we're ultimately trying to find, we make sure
+ // that this is a Visual Studio directory by checking for cl.exe. We use
+ // cl.exe instead of other binaries like link.exe because programs such as
+ // GnuWin32 also have a utility called link.exe, so cl.exe is the least
+ // ambiguous.
+ BinDir = installDir;
+ llvm::sys::path::append(BinDir, "VC", "bin");
+ SmallString<128> ClPath(BinDir);
+ llvm::sys::path::append(ClPath, "cl.exe");
+
+ if (!llvm::sys::fs::can_execute(ClPath.c_str()))
+ return false;
+ }
+
+ if (BinDir.empty())
+ return false;
+
+ switch (getArch()) {
+ case llvm::Triple::x86:
+ break;
+ case llvm::Triple::x86_64:
+ llvm::sys::path::append(BinDir, "amd64");
+ break;
+ case llvm::Triple::arm:
+ llvm::sys::path::append(BinDir, "arm");
+ break;
+ default:
+ // Whatever this is, Visual Studio doesn't have a toolchain for it.
+ return false;
+ }
+ path = BinDir.str();
+ return true;
+}
+
+// Get Visual Studio installation directory.
+bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const {
+ // First check the environment variables that vsvars32.bat sets.
+ const char *vcinstalldir = getenv("VCINSTALLDIR");
+ if (vcinstalldir) {
+ path = vcinstalldir;
+ path = path.substr(0, path.find("\\VC"));
+ return true;
+ }
+
+ std::string vsIDEInstallDir;
+ std::string vsExpressIDEInstallDir;
+ // Then try the windows registry.
+ bool hasVCDir =
+ getSystemRegistryString("SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
+ "InstallDir", vsIDEInstallDir, nullptr);
+ if (hasVCDir && !vsIDEInstallDir.empty()) {
+ path = vsIDEInstallDir.substr(0, vsIDEInstallDir.find("\\Common7\\IDE"));
+ return true;
+ }
+
+ bool hasVCExpressDir =
+ getSystemRegistryString("SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
+ "InstallDir", vsExpressIDEInstallDir, nullptr);
+ if (hasVCExpressDir && !vsExpressIDEInstallDir.empty()) {
+ path = vsExpressIDEInstallDir.substr(
+ 0, vsIDEInstallDir.find("\\Common7\\IDE"));
+ return true;
+ }
+
+ // Try the environment.
+ const char *vs120comntools = getenv("VS120COMNTOOLS");
+ const char *vs100comntools = getenv("VS100COMNTOOLS");
+ const char *vs90comntools = getenv("VS90COMNTOOLS");
+ const char *vs80comntools = getenv("VS80COMNTOOLS");
+
+ const char *vscomntools = nullptr;
+
+ // Find any version we can
+ if (vs120comntools)
+ vscomntools = vs120comntools;
+ else if (vs100comntools)
+ vscomntools = vs100comntools;
+ else if (vs90comntools)
+ vscomntools = vs90comntools;
+ else if (vs80comntools)
+ vscomntools = vs80comntools;
+
+ if (vscomntools && *vscomntools) {
+ const char *p = strstr(vscomntools, "\\Common7\\Tools");
+ path = p ? std::string(vscomntools, p) : vscomntools;
+ return true;
+ }
+ return false;
+}
+
+void MSVCToolChain::AddSystemIncludeWithSubfolder(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ const std::string &folder,
+ const char *subfolder) const {
+ llvm::SmallString<128> path(folder);
+ llvm::sys::path::append(path, subfolder);
+ addSystemInclude(DriverArgs, CC1Args, path.str());
+}
+
+void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> P(getDriver().ResourceDir);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
+ if (const char *cl_include_dir = getenv("INCLUDE")) {
+ SmallVector<StringRef, 8> Dirs;
+ StringRef(cl_include_dir)
+ .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ for (StringRef Dir : Dirs)
+ addSystemInclude(DriverArgs, CC1Args, Dir);
+ if (!Dirs.empty())
+ return;
+ }
+
+ std::string VSDir;
+
+ // When built with access to the proper Windows APIs, try to actually find
+ // the correct include paths first.
+ if (getVisualStudioInstallDir(VSDir)) {
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, VSDir, "VC\\include");
+
+ std::string WindowsSDKDir;
+ int major, minor;
+ if (getWindowsSDKDir(WindowsSDKDir, major, minor)) {
+ if (major >= 8) {
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
+ "include\\shared");
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
+ "include\\um");
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
+ "include\\winrt");
+ } else {
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
+ "include");
+ }
+ } else {
+ addSystemInclude(DriverArgs, CC1Args, VSDir);
+ }
+ return;
+ }
+
+ // As a fallback, select default install paths.
+ // FIXME: Don't guess drives and paths like this on Windows.
+ const StringRef Paths[] = {
+ "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
+ "C:/Program Files/Microsoft Visual Studio 8/VC/include",
+ "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
+ };
+ addSystemIncludes(DriverArgs, CC1Args, Paths);
+}
+
+void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ // FIXME: There should probably be logic here to find libc++ on Windows.
+}
diff --git a/lib/Driver/Multilib.cpp b/lib/Driver/Multilib.cpp
index 484ce1627d7b..1f5d62f247c4 100644
--- a/lib/Driver/Multilib.cpp
+++ b/lib/Driver/Multilib.cpp
@@ -37,7 +37,7 @@ static void normalizePathSegment(std::string &Segment) {
// Prune trailing "/" or "./"
while (1) {
- StringRef last = *--path::end(seg);
+ StringRef last = path::filename(seg);
if (last != ".")
break;
seg = path::parent_path(seg);
diff --git a/lib/Driver/Phases.cpp b/lib/Driver/Phases.cpp
index 155e53b64fc1..7ae270857f4d 100644
--- a/lib/Driver/Phases.cpp
+++ b/lib/Driver/Phases.cpp
@@ -18,6 +18,7 @@ const char *phases::getPhaseName(ID Id) {
case Preprocess: return "preprocessor";
case Precompile: return "precompiler";
case Compile: return "compiler";
+ case Backend: return "backend";
case Assemble: return "assembler";
case Link: return "linker";
}
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index b64f0275768c..bd7bc218e3bf 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -21,93 +21,263 @@
using namespace clang::driver;
using namespace llvm::opt;
+namespace {
+/// Assign ordinals to possible values of -fsanitize= flag.
+/// We use the ordinal values as bit positions within \c SanitizeKind.
+enum SanitizeOrdinal {
+#define SANITIZER(NAME, ID) SO_##ID,
+#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
+#include "clang/Basic/Sanitizers.def"
+ SO_Count
+};
+
+/// Represents a set of sanitizer kinds. It is also used to define:
+/// 1) set of sanitizers each sanitizer group expands into.
+/// 2) set of sanitizers sharing a specific property (e.g.
+/// all sanitizers with zero-base shadow).
+enum SanitizeKind {
+#define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
+#define SANITIZER_GROUP(NAME, ID, ALIAS) \
+ID = ALIAS, ID##Group = 1 << SO_##ID##Group,
+#include "clang/Basic/Sanitizers.def"
+ NeedsUbsanRt = Undefined | Integer,
+ NotAllowedWithTrap = Vptr,
+ RequiresPIE = Memory | DataFlow,
+ NeedsUnwindTables = Address | Thread | Memory | DataFlow,
+ SupportsCoverage = Address | Memory | Leak | Undefined | Integer,
+ RecoverableByDefault = Undefined | Integer,
+ Unrecoverable = Address | Unreachable | Return,
+ LegacyFsanitizeRecoverMask = Undefined | Integer
+};
+}
+
+/// Returns true if set of \p Sanitizers contain at least one sanitizer from
+/// \p Kinds.
+static bool hasOneOf(const clang::SanitizerSet &Sanitizers, unsigned Kinds) {
+#define SANITIZER(NAME, ID) \
+ if (Sanitizers.has(clang::SanitizerKind::ID) && (Kinds & ID)) \
+ return true;
+#include "clang/Basic/Sanitizers.def"
+ return false;
+}
+
+/// Adds all sanitizers from \p Kinds to \p Sanitizers.
+static void addAllOf(clang::SanitizerSet &Sanitizers, unsigned Kinds) {
+#define SANITIZER(NAME, ID) \
+ if (Kinds & ID) \
+ Sanitizers.set(clang::SanitizerKind::ID, true);
+#include "clang/Basic/Sanitizers.def"
+}
+
+static unsigned toSanitizeKind(clang::SanitizerKind K) {
+#define SANITIZER(NAME, ID) \
+ if (K == clang::SanitizerKind::ID) \
+ return ID;
+#include "clang/Basic/Sanitizers.def"
+ llvm_unreachable("Invalid SanitizerKind!");
+}
+
+/// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
+/// Returns a member of the \c SanitizeKind enumeration, or \c 0
+/// if \p Value is not known.
+static unsigned parseValue(const char *Value);
+
+/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
+/// invalid components. Returns OR of members of \c SanitizeKind enumeration.
+static unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors);
+
+/// Produce an argument string from ArgList \p Args, which shows how it
+/// provides some sanitizer kind from \p Mask. For example, the argument list
+/// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
+/// would produce "-fsanitize=vptr".
+static std::string lastArgumentForMask(const Driver &D,
+ const llvm::opt::ArgList &Args,
+ unsigned Mask);
+
+static std::string lastArgumentForKind(const Driver &D,
+ const llvm::opt::ArgList &Args,
+ clang::SanitizerKind K) {
+ return lastArgumentForMask(D, Args, toSanitizeKind(K));
+}
+
+/// Produce an argument string from argument \p A, which shows how it provides
+/// a value in \p Mask. For instance, the argument
+/// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
+/// "-fsanitize=alignment".
+static std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask);
+
+/// Produce a string containing comma-separated names of sanitizers in \p
+/// Sanitizers set.
+static std::string toString(const clang::SanitizerSet &Sanitizers);
+
+/// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
+/// this group enables.
+static unsigned expandGroups(unsigned Kinds);
+
+static unsigned getToolchainUnsupportedKinds(const ToolChain &TC) {
+ bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD;
+ bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux;
+ bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86;
+ bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64;
+
+ unsigned Unsupported = 0;
+ if (!(IsLinux && IsX86_64)) {
+ Unsupported |= Memory | DataFlow;
+ }
+ if (!((IsLinux || IsFreeBSD) && IsX86_64)) {
+ Unsupported |= Thread;
+ }
+ if (!(IsLinux && (IsX86 || IsX86_64))) {
+ Unsupported |= Function;
+ }
+ return Unsupported;
+}
+
+bool SanitizerArgs::needsUbsanRt() const {
+ return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt);
+}
+
+bool SanitizerArgs::requiresPIE() const {
+ return AsanZeroBaseShadow || hasOneOf(Sanitizers, RequiresPIE);
+}
+
+bool SanitizerArgs::needsUnwindTables() const {
+ return hasOneOf(Sanitizers, NeedsUnwindTables);
+}
+
void SanitizerArgs::clear() {
- Kind = 0;
+ Sanitizers.clear();
+ RecoverableSanitizers.clear();
BlacklistFile = "";
+ SanitizeCoverage = 0;
MsanTrackOrigins = 0;
+ AsanFieldPadding = 0;
AsanZeroBaseShadow = false;
UbsanTrapOnError = false;
AsanSharedRuntime = false;
-}
-
-SanitizerArgs::SanitizerArgs() {
- clear();
+ LinkCXXRuntimes = false;
}
SanitizerArgs::SanitizerArgs(const ToolChain &TC,
const llvm::opt::ArgList &Args) {
clear();
- unsigned AllAdd = 0; // All kinds of sanitizers that were turned on
- // at least once (possibly, disabled further).
unsigned AllRemove = 0; // During the loop below, the accumulated set of
// sanitizers disabled by the current sanitizer
// argument or any argument after it.
unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
// Used to deduplicate diagnostics.
+ unsigned Kinds = 0;
+ unsigned NotSupported = getToolchainUnsupportedKinds(TC);
const Driver &D = TC.getDriver();
for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
I != E; ++I) {
- unsigned Add, Remove;
- if (!parse(D, Args, *I, Add, Remove, true))
- continue;
- (*I)->claim();
-
- AllAdd |= expandGroups(Add);
- AllRemove |= expandGroups(Remove);
-
- // Avoid diagnosing any sanitizer which is disabled later.
- Add &= ~AllRemove;
- // At this point we have not expanded groups, so any unsupported sanitizers
- // in Add are those which have been explicitly enabled. Diagnose them.
- Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/true,
- DiagnosedKinds);
- Add = expandGroups(Add);
- // Group expansion may have enabled a sanitizer which is disabled later.
- Add &= ~AllRemove;
- // Silently discard any unsupported sanitizers implicitly enabled through
- // group expansion.
- Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/false,
- DiagnosedKinds);
-
- Kind |= Add;
+ const auto *Arg = *I;
+ if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
+ Arg->claim();
+ unsigned Add = parseArgValues(D, Arg, true);
+
+ // Avoid diagnosing any sanitizer which is disabled later.
+ Add &= ~AllRemove;
+ // At this point we have not expanded groups, so any unsupported
+ // sanitizers in Add are those which have been explicitly enabled.
+ // Diagnose them.
+ if (unsigned KindsToDiagnose = Add & NotSupported & ~DiagnosedKinds) {
+ // Only diagnose the new kinds.
+ std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Desc << TC.getTriple().str();
+ DiagnosedKinds |= KindsToDiagnose;
+ }
+ Add &= ~NotSupported;
+
+ Add = expandGroups(Add);
+ // Group expansion may have enabled a sanitizer which is disabled later.
+ Add &= ~AllRemove;
+ // Silently discard any unsupported sanitizers implicitly enabled through
+ // group expansion.
+ Add &= ~NotSupported;
+
+ Kinds |= Add;
+ } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
+ Arg->claim();
+ unsigned Remove = parseArgValues(D, Arg, true);
+ AllRemove |= expandGroups(Remove);
+ }
+ }
+ addAllOf(Sanitizers, Kinds);
+
+ // Parse -f(no-)?sanitize-recover flags.
+ unsigned RecoverableKinds = RecoverableByDefault;
+ unsigned DiagnosedUnrecoverableKinds = 0;
+ for (const auto *Arg : Args) {
+ if (Arg->getOption().matches(options::OPT_fsanitize_recover)) {
+ // FIXME: Add deprecation notice, and then remove this flag.
+ RecoverableKinds |= expandGroups(LegacyFsanitizeRecoverMask);
+ Arg->claim();
+ } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) {
+ // FIXME: Add deprecation notice, and then remove this flag.
+ RecoverableKinds &= ~expandGroups(LegacyFsanitizeRecoverMask);
+ Arg->claim();
+ } else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
+ unsigned Add = parseArgValues(D, Arg, true);
+ // Report error if user explicitly tries to recover from unrecoverable
+ // sanitizer.
+ if (unsigned KindsToDiagnose =
+ Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
+ SanitizerSet SetToDiagnose;
+ addAllOf(SetToDiagnose, KindsToDiagnose);
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << Arg->getOption().getName() << toString(SetToDiagnose);
+ DiagnosedUnrecoverableKinds |= KindsToDiagnose;
+ }
+ RecoverableKinds |= expandGroups(Add);
+ Arg->claim();
+ } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
+ RecoverableKinds &= ~expandGroups(parseArgValues(D, Arg, true));
+ Arg->claim();
+ }
}
+ RecoverableKinds &= Kinds;
+ RecoverableKinds &= ~Unrecoverable;
+ addAllOf(RecoverableSanitizers, RecoverableKinds);
UbsanTrapOnError =
Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
options::OPT_fno_sanitize_undefined_trap_on_error, false);
// Warn about undefined sanitizer options that require runtime support.
- if (UbsanTrapOnError && notAllowedWithTrap()) {
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NotAllowedWithTrap)
+ if (UbsanTrapOnError && hasOneOf(Sanitizers, NotAllowedWithTrap)) {
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForMask(D, Args, NotAllowedWithTrap)
<< "-fsanitize-undefined-trap-on-error";
}
- // Only one runtime library can be used at once.
- bool NeedsAsan = needsAsanRt();
- bool NeedsTsan = needsTsanRt();
- bool NeedsMsan = needsMsanRt();
- bool NeedsLsan = needsLeakDetection();
+ // Check for incompatible sanitizers.
+ bool NeedsAsan = Sanitizers.has(SanitizerKind::Address);
+ bool NeedsTsan = Sanitizers.has(SanitizerKind::Thread);
+ bool NeedsMsan = Sanitizers.has(SanitizerKind::Memory);
+ bool NeedsLsan = Sanitizers.has(SanitizerKind::Leak);
if (NeedsAsan && NeedsTsan)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NeedsAsanRt)
- << lastArgumentForKind(D, Args, NeedsTsanRt);
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, SanitizerKind::Address)
+ << lastArgumentForKind(D, Args, SanitizerKind::Thread);
if (NeedsAsan && NeedsMsan)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NeedsAsanRt)
- << lastArgumentForKind(D, Args, NeedsMsanRt);
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, SanitizerKind::Address)
+ << lastArgumentForKind(D, Args, SanitizerKind::Memory);
if (NeedsTsan && NeedsMsan)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NeedsTsanRt)
- << lastArgumentForKind(D, Args, NeedsMsanRt);
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, SanitizerKind::Thread)
+ << lastArgumentForKind(D, Args, SanitizerKind::Memory);
if (NeedsLsan && NeedsTsan)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NeedsLeakDetection)
- << lastArgumentForKind(D, Args, NeedsTsanRt);
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, SanitizerKind::Leak)
+ << lastArgumentForKind(D, Args, SanitizerKind::Thread);
if (NeedsLsan && NeedsMsan)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NeedsLeakDetection)
- << lastArgumentForKind(D, Args, NeedsMsanRt);
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, SanitizerKind::Leak)
+ << lastArgumentForKind(D, Args, SanitizerKind::Memory);
// FIXME: Currently -fsanitize=leak is silently ignored in the presence of
// -fsanitize=address. Perhaps it should print an error, or perhaps
// -f(-no)sanitize=leak should change whether leak detection is enabled by
@@ -124,19 +294,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
std::unique_ptr<llvm::SpecialCaseList> SCL(
llvm::SpecialCaseList::create(BLPath, BLError));
if (!SCL.get())
- D.Diag(diag::err_drv_malformed_sanitizer_blacklist) << BLError;
+ D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
else
BlacklistFile = BLPath;
} else {
- D.Diag(diag::err_drv_no_such_file) << BLPath;
+ D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
}
}
} else {
// If no -fsanitize-blacklist option is specified, try to look up for
// blacklist in the resource directory.
std::string BLPath;
- if (getDefaultBlacklistForKind(D, Kind, BLPath) &&
- llvm::sys::fs::exists(BLPath))
+ if (getDefaultBlacklist(D, BLPath) && llvm::sys::fs::exists(BLPath))
BlacklistFile = BLPath;
}
@@ -155,32 +324,85 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
StringRef S = A->getValue();
if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
MsanTrackOrigins > 2) {
- D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
}
}
}
}
+ // Parse -fsanitize-coverage=N. Currently one of asan/msan/lsan is required.
+ if (hasOneOf(Sanitizers, SupportsCoverage)) {
+ if (Arg *A = Args.getLastArg(options::OPT_fsanitize_coverage)) {
+ StringRef S = A->getValue();
+ // Legal values are 0..4.
+ if (S.getAsInteger(0, SanitizeCoverage) || SanitizeCoverage < 0 ||
+ SanitizeCoverage > 4)
+ D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ }
+ }
+
if (NeedsAsan) {
AsanSharedRuntime =
Args.hasArg(options::OPT_shared_libasan) ||
(TC.getTriple().getEnvironment() == llvm::Triple::Android);
AsanZeroBaseShadow =
(TC.getTriple().getEnvironment() == llvm::Triple::Android);
+ if (Arg *A =
+ Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
+ StringRef S = A->getValue();
+ // Legal values are 0 and 1, 2, but in future we may add more levels.
+ if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
+ AsanFieldPadding > 2) {
+ D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ }
+ }
+
+ if (Arg *WindowsDebugRTArg =
+ Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
+ options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
+ options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
+ switch (WindowsDebugRTArg->getOption().getID()) {
+ case options::OPT__SLASH_MTd:
+ case options::OPT__SLASH_MDd:
+ case options::OPT__SLASH_LDd:
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << WindowsDebugRTArg->getAsString(Args)
+ << lastArgumentForKind(D, Args, SanitizerKind::Address);
+ D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
+ }
+ }
+ }
+
+ // Parse -link-cxx-sanitizer flag.
+ LinkCXXRuntimes =
+ Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
+}
+
+static std::string toString(const clang::SanitizerSet &Sanitizers) {
+ std::string Res;
+#define SANITIZER(NAME, ID) \
+ if (Sanitizers.has(clang::SanitizerKind::ID)) { \
+ if (!Res.empty()) \
+ Res += ","; \
+ Res += NAME; \
}
+#include "clang/Basic/Sanitizers.def"
+ return Res;
}
void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const {
- if (!Kind)
+ if (Sanitizers.empty())
return;
- SmallString<256> SanitizeOpt("-fsanitize=");
-#define SANITIZER(NAME, ID) \
- if (Kind & ID) \
- SanitizeOpt += NAME ",";
-#include "clang/Basic/Sanitizers.def"
- SanitizeOpt.pop_back();
- CmdArgs.push_back(Args.MakeArgString(SanitizeOpt));
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
+
+ if (!RecoverableSanitizers.empty())
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" +
+ toString(RecoverableSanitizers)));
+
+ if (UbsanTrapOnError)
+ CmdArgs.push_back("-fsanitize-undefined-trap-on-error");
+
if (!BlacklistFile.empty()) {
SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
BlacklistOpt += BlacklistFile;
@@ -190,13 +412,38 @@ void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
if (MsanTrackOrigins)
CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
llvm::utostr(MsanTrackOrigins)));
-
+ if (AsanFieldPadding)
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
+ llvm::utostr(AsanFieldPadding)));
+ if (SanitizeCoverage)
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize-coverage=" +
+ llvm::utostr(SanitizeCoverage)));
// Workaround for PR16386.
- if (needsMsanRt())
+ if (Sanitizers.has(SanitizerKind::Memory))
CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
}
-unsigned SanitizerArgs::parse(const char *Value) {
+bool SanitizerArgs::getDefaultBlacklist(const Driver &D, std::string &BLPath) {
+ const char *BlacklistFile = nullptr;
+ if (Sanitizers.has(SanitizerKind::Address))
+ BlacklistFile = "asan_blacklist.txt";
+ else if (Sanitizers.has(SanitizerKind::Memory))
+ BlacklistFile = "msan_blacklist.txt";
+ else if (Sanitizers.has(SanitizerKind::Thread))
+ BlacklistFile = "tsan_blacklist.txt";
+ else if (Sanitizers.has(SanitizerKind::DataFlow))
+ BlacklistFile = "dfsan_abilist.txt";
+
+ if (BlacklistFile) {
+ SmallString<64> Path(D.ResourceDir);
+ llvm::sys::path::append(Path, BlacklistFile);
+ BLPath = Path.str();
+ return true;
+ }
+ return false;
+}
+
+unsigned parseValue(const char *Value) {
unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
#define SANITIZER(NAME, ID) .Case(NAME, ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group)
@@ -205,107 +452,65 @@ unsigned SanitizerArgs::parse(const char *Value) {
return ParsedKind;
}
-unsigned SanitizerArgs::expandGroups(unsigned Kinds) {
+unsigned expandGroups(unsigned Kinds) {
#define SANITIZER(NAME, ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID;
#include "clang/Basic/Sanitizers.def"
return Kinds;
}
-void SanitizerArgs::filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds,
- unsigned Mask,
- const llvm::opt::ArgList &Args,
- const llvm::opt::Arg *A,
- bool DiagnoseErrors,
- unsigned &DiagnosedKinds) {
- unsigned MaskedKinds = Kinds & Mask;
- if (!MaskedKinds)
- return;
- Kinds &= ~Mask;
- // Do we have new kinds to diagnose?
- if (DiagnoseErrors && (DiagnosedKinds & MaskedKinds) != MaskedKinds) {
- // Only diagnose the new kinds.
- std::string Desc =
- describeSanitizeArg(Args, A, MaskedKinds & ~DiagnosedKinds);
- TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
- << Desc << TC.getTriple().str();
- DiagnosedKinds |= MaskedKinds;
- }
-}
-
-unsigned SanitizerArgs::filterUnsupportedKinds(const ToolChain &TC,
- unsigned Kinds,
- const llvm::opt::ArgList &Args,
- const llvm::opt::Arg *A,
- bool DiagnoseErrors,
- unsigned &DiagnosedKinds) {
- bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux;
- bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86;
- bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64;
- if (!(IsLinux && IsX86_64)) {
- filterUnsupportedMask(TC, Kinds, Thread | Memory | DataFlow, Args, A,
- DiagnoseErrors, DiagnosedKinds);
- }
- if (!(IsLinux && (IsX86 || IsX86_64))) {
- filterUnsupportedMask(TC, Kinds, Function, Args, A, DiagnoseErrors,
- DiagnosedKinds);
- }
- return Kinds;
-}
-
-unsigned SanitizerArgs::parse(const Driver &D, const llvm::opt::Arg *A,
- bool DiagnoseErrors) {
- unsigned Kind = 0;
+unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors) {
+ assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
+ A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
+ A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
+ A->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) &&
+ "Invalid argument in parseArgValues!");
+ unsigned Kinds = 0;
for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
- if (unsigned K = parse(A->getValue(I)))
- Kind |= K;
- else if (DiagnoseErrors)
- D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue(I);
- }
- return Kind;
-}
+ const char *Value = A->getValue(I);
+ unsigned Kind;
+ // Special case: don't accept -fsanitize=all.
+ if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
+ 0 == strcmp("all", Value))
+ Kind = 0;
+ else
+ Kind = parseValue(Value);
-bool SanitizerArgs::parse(const Driver &D, const llvm::opt::ArgList &Args,
- const llvm::opt::Arg *A, unsigned &Add,
- unsigned &Remove, bool DiagnoseErrors) {
- Add = 0;
- Remove = 0;
- if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
- Add = parse(D, A, DiagnoseErrors);
- } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
- Remove = parse(D, A, DiagnoseErrors);
- } else {
- // Flag is not relevant to sanitizers.
- return false;
+ if (Kind)
+ Kinds |= Kind;
+ else if (DiagnoseErrors)
+ D.Diag(clang::diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
}
- return true;
+ return Kinds;
}
-std::string SanitizerArgs::lastArgumentForKind(const Driver &D,
- const llvm::opt::ArgList &Args,
- unsigned Kind) {
+std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
+ unsigned Mask) {
for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
E = Args.rend();
I != E; ++I) {
- unsigned Add, Remove;
- if (parse(D, Args, *I, Add, Remove, false) &&
- (expandGroups(Add) & Kind))
- return describeSanitizeArg(Args, *I, Kind);
- Kind &= ~Remove;
+ const auto *Arg = *I;
+ if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
+ unsigned AddKinds = expandGroups(parseArgValues(D, Arg, false));
+ if (AddKinds & Mask)
+ return describeSanitizeArg(Arg, Mask);
+ } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
+ unsigned RemoveKinds = expandGroups(parseArgValues(D, Arg, false));
+ Mask &= ~RemoveKinds;
+ }
}
llvm_unreachable("arg list didn't provide expected value");
}
-std::string SanitizerArgs::describeSanitizeArg(const llvm::opt::ArgList &Args,
- const llvm::opt::Arg *A,
- unsigned Mask) {
- if (!A->getOption().matches(options::OPT_fsanitize_EQ))
- return A->getAsString(Args);
+std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask) {
+ assert(A->getOption().matches(options::OPT_fsanitize_EQ)
+ && "Invalid argument in describeSanitizerArg!");
std::string Sanitizers;
for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
- if (expandGroups(parse(A->getValue(I))) & Mask) {
+ if (expandGroups(parseValue(A->getValue(I))) & Mask) {
if (!Sanitizers.empty())
Sanitizers += ",";
Sanitizers += A->getValue(I);
@@ -315,24 +520,3 @@ std::string SanitizerArgs::describeSanitizeArg(const llvm::opt::ArgList &Args,
assert(!Sanitizers.empty() && "arg didn't provide expected value");
return "-fsanitize=" + Sanitizers;
}
-
-bool SanitizerArgs::getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
- std::string &BLPath) {
- const char *BlacklistFile = nullptr;
- if (Kind & NeedsAsanRt)
- BlacklistFile = "asan_blacklist.txt";
- else if (Kind & NeedsMsanRt)
- BlacklistFile = "msan_blacklist.txt";
- else if (Kind & NeedsTsanRt)
- BlacklistFile = "tsan_blacklist.txt";
- else if (Kind & NeedsDfsanRt)
- BlacklistFile = "dfsan_abilist.txt";
-
- if (BlacklistFile) {
- SmallString<64> Path(D.ResourceDir);
- llvm::sys::path::append(Path, BlacklistFile);
- BLPath = Path.str();
- return true;
- }
- return false;
-}
diff --git a/lib/Driver/Tool.cpp b/lib/Driver/Tool.cpp
index b93864ff8bf2..7142e822f16e 100644
--- a/lib/Driver/Tool.cpp
+++ b/lib/Driver/Tool.cpp
@@ -11,11 +11,13 @@
using namespace clang::driver;
-Tool::Tool(const char *_Name, const char *_ShortName,
- const ToolChain &TC) : Name(_Name), ShortName(_ShortName),
- TheToolChain(TC)
-{
-}
+Tool::Tool(const char *_Name, const char *_ShortName, const ToolChain &TC,
+ ResponseFileSupport _ResponseSupport,
+ llvm::sys::WindowsEncodingMethod _ResponseEncoding,
+ const char *_ResponseFlag)
+ : Name(_Name), ShortName(_ShortName), TheToolChain(TC),
+ ResponseSupport(_ResponseSupport), ResponseEncoding(_ResponseEncoding),
+ ResponseFlag(_ResponseFlag) {}
Tool::~Tool() {
}
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 4f90d083c7dc..2bcfecf6bde6 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -27,8 +27,13 @@ using namespace clang;
using namespace llvm::opt;
ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
- const ArgList &A)
- : D(D), Triple(T), Args(A) {
+ const ArgList &Args)
+ : D(D), Triple(T), Args(Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_mthread_model))
+ if (!isThreadModelSupported(A->getValue()))
+ D.Diag(diag::err_drv_invalid_thread_model_for_target)
+ << A->getValue()
+ << A->getAsString(Args);
}
ToolChain::~ToolChain() {
@@ -50,7 +55,7 @@ const SanitizerArgs& ToolChain::getSanitizerArgs() const {
return *SanitizerArguments.get();
}
-std::string ToolChain::getDefaultUniversalArchName() const {
+StringRef ToolChain::getDefaultUniversalArchName() const {
// In universal driver terms, the arch name accepted by -arch isn't exactly
// the same as the ones that appear in the triple. Roughly speaking, this is
// an inverse of the darwin::getArchTypeForDarwinArchName() function, but the
@@ -124,6 +129,7 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::AnalyzeJobClass:
case Action::MigrateJobClass:
case Action::VerifyPCHJobClass:
+ case Action::BackendJobClass:
return getClang();
}
@@ -201,6 +207,19 @@ ObjCRuntime ToolChain::getDefaultObjCRuntime(bool isNonFragile) const {
VersionTuple());
}
+bool ToolChain::isThreadModelSupported(const StringRef Model) const {
+ if (Model == "single") {
+ // FIXME: 'single' is only supported on ARM so far.
+ return Triple.getArch() == llvm::Triple::arm ||
+ Triple.getArch() == llvm::Triple::armeb ||
+ Triple.getArch() == llvm::Triple::thumb ||
+ Triple.getArch() == llvm::Triple::thumbeb;
+ } else if (Model == "posix")
+ return true;
+
+ return false;
+}
+
std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
types::ID InputType) const {
switch (getTriple().getArch()) {
@@ -221,6 +240,17 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
}
return Triple.getTriple();
}
+ case llvm::Triple::aarch64: {
+ llvm::Triple Triple = getTriple();
+ if (!Triple.isOSBinFormatMachO())
+ return getTripleString();
+
+ // FIXME: older versions of ld64 expect the "arm64" component in the actual
+ // triple string and query it to determine whether an LTO file can be
+ // handled. Remove this when we don't care any more.
+ Triple.setArchName("arm64");
+ return Triple.getTriple();
+ }
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index b46f69de96a3..4d97ab3bf485 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -133,11 +133,11 @@ static const char *GetArmArchForMCpu(StringRef Value) {
.Case("xscale", "xscale")
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "armv6")
.Case("cortex-m0", "armv6m")
- .Cases("cortex-a5", "cortex-a7", "cortex-a8", "cortex-a9-mp", "armv7")
- .Cases("cortex-a9", "cortex-a12", "cortex-a15", "krait", "armv7")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "armv7")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait", "armv7")
.Cases("cortex-r4", "cortex-r5", "armv7r")
.Case("cortex-m3", "armv7m")
- .Case("cortex-m4", "armv7em")
+ .Cases("cortex-m4", "cortex-m7", "armv7em")
.Case("swift", "armv7s")
.Default(nullptr);
}
@@ -147,7 +147,7 @@ static bool isSoftFloatABI(const ArgList &Args) {
options::OPT_mfloat_abi_EQ);
if (!A)
return false;
-
+
return A->getOption().matches(options::OPT_msoft_float) ||
(A->getOption().matches(options::OPT_mfloat_abi_EQ) &&
A->getValue() == StringRef("soft"));
@@ -156,7 +156,10 @@ static bool isSoftFloatABI(const ArgList &Args) {
StringRef MachO::getMachOArchName(const ArgList &Args) const {
switch (getTriple().getArch()) {
default:
- return getArchName();
+ return getDefaultUniversalArchName();
+
+ case llvm::Triple::aarch64:
+ return "arm64";
case llvm::Triple::thumb:
case llvm::Triple::arm: {
@@ -288,17 +291,37 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
}
void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
- StringRef DarwinStaticLib, bool AlwaysLink,
- bool IsEmbedded) const {
- SmallString<128> P(getDriver().ResourceDir);
- llvm::sys::path::append(P, "lib", IsEmbedded ? "macho_embedded" : "darwin",
- DarwinStaticLib);
+ StringRef DarwinLibName, bool AlwaysLink,
+ bool IsEmbedded, bool AddRPath) const {
+ SmallString<128> Dir(getDriver().ResourceDir);
+ llvm::sys::path::append(Dir, "lib", IsEmbedded ? "macho_embedded" : "darwin");
+
+ SmallString<128> P(Dir);
+ llvm::sys::path::append(P, DarwinLibName);
// For now, allow missing resource libraries to support developers who may
// not have compiler-rt checked out or integrated into their build (unless
// we explicitly force linking with this library).
if (AlwaysLink || llvm::sys::fs::exists(P.str()))
CmdArgs.push_back(Args.MakeArgString(P.str()));
+
+ // Adding the rpaths might negatively interact when other rpaths are involved,
+ // so we should make sure we add the rpaths last, after all user-specified
+ // rpaths. This is currently true from this place, but we need to be
+ // careful if this function is ever called before user's rpaths are emitted.
+ if (AddRPath) {
+ assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library");
+
+ // Add @executable_path to rpath to support having the dylib copied with
+ // the executable.
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back("@executable_path");
+
+ // Add the path to the resource dir to rpath to support using the dylib
+ // from the default location without copying.
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back(Args.MakeArgString(Dir.str()));
+ }
}
void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
@@ -330,7 +353,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
// If we are building profile support, link that library in.
- if (Args.hasArg(options::OPT_fprofile_arcs) ||
+ if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
+ false) ||
Args.hasArg(options::OPT_fprofile_generate) ||
Args.hasArg(options::OPT_fprofile_instr_generate) ||
Args.hasArg(options::OPT_fcreate_profile) ||
@@ -375,12 +399,14 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
if (isTargetMacOS()) {
AddLinkRuntimeLib(Args, CmdArgs,
"libclang_rt.asan_osx_dynamic.dylib",
- true);
+ /*AlwaysLink*/ true, /*IsEmbedded*/ false,
+ /*AddRPath*/ true);
} else {
if (isTargetIOSSimulator()) {
AddLinkRuntimeLib(Args, CmdArgs,
"libclang_rt.asan_iossim_dynamic.dylib",
- true);
+ /*AlwaysLink*/ true, /*IsEmbedded*/ false,
+ /*AddRPath*/ true);
}
}
}
@@ -396,8 +422,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// it never went into the SDK.
// Linking against libgcc_s.1 isn't needed for iOS 5.0+
if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator() &&
- (getTriple().getArch() != llvm::Triple::arm64 &&
- getTriple().getArch() != llvm::Triple::aarch64))
+ getTriple().getArch() != llvm::Triple::aarch64)
CmdArgs.push_back("-lgcc_s.1");
// We currently always need a static runtime library for iOS.
@@ -453,31 +478,21 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
- Arg *iOSSimVersion = Args.getLastArg(
- options::OPT_mios_simulator_version_min_EQ);
- if (OSXVersion && (iOSVersion || iOSSimVersion)) {
+ if (OSXVersion && iOSVersion) {
getDriver().Diag(diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)
- << (iOSVersion ? iOSVersion : iOSSimVersion)->getAsString(Args);
- iOSVersion = iOSSimVersion = nullptr;
- } else if (iOSVersion && iOSSimVersion) {
- getDriver().Diag(diag::err_drv_argument_not_allowed_with)
- << iOSVersion->getAsString(Args)
- << iOSSimVersion->getAsString(Args);
- iOSSimVersion = nullptr;
- } else if (!OSXVersion && !iOSVersion && !iOSSimVersion) {
+ << iOSVersion->getAsString(Args);
+ iOSVersion = nullptr;
+ } else if (!OSXVersion && !iOSVersion) {
// If no deployment target was specified on the command line, check for
// environment defines.
StringRef OSXTarget;
StringRef iOSTarget;
- StringRef iOSSimTarget;
if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET"))
OSXTarget = env;
if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET"))
iOSTarget = env;
- if (char *env = ::getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET"))
- iOSSimTarget = env;
// If no '-miphoneos-version-min' specified on the command line and
// IPHONEOS_DEPLOYMENT_TARGET is not defined, see if we can set the default
@@ -500,23 +515,10 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
MachOArchName == "arm64"))
iOSTarget = iOSVersionMin;
- // Handle conflicting deployment targets
- //
- // FIXME: Don't hardcode default here.
-
- // Do not allow conflicts with the iOS simulator target.
- if (!iOSSimTarget.empty() && (!OSXTarget.empty() || !iOSTarget.empty())) {
- getDriver().Diag(diag::err_drv_conflicting_deployment_targets)
- << "IOS_SIMULATOR_DEPLOYMENT_TARGET"
- << (!OSXTarget.empty() ? "MACOSX_DEPLOYMENT_TARGET" :
- "IPHONEOS_DEPLOYMENT_TARGET");
- }
-
// Allow conflicts among OSX and iOS for historical reasons, but choose the
// default platform.
if (!OSXTarget.empty() && !iOSTarget.empty()) {
if (getTriple().getArch() == llvm::Triple::arm ||
- getTriple().getArch() == llvm::Triple::arm64 ||
getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::thumb)
OSXTarget = "";
@@ -532,11 +534,6 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
iOSVersion = Args.MakeJoinedArg(nullptr, O, iOSTarget);
Args.append(iOSVersion);
- } else if (!iOSSimTarget.empty()) {
- const Option O = Opts.getOption(
- options::OPT_mios_simulator_version_min_EQ);
- iOSSimVersion = Args.MakeJoinedArg(nullptr, O, iOSSimTarget);
- Args.append(iOSSimVersion);
} else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" &&
MachOArchName != "armv7em") {
// Otherwise, assume we are targeting OS X.
@@ -551,43 +548,30 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
Platform = MacOS;
else if (iOSVersion)
Platform = IPhoneOS;
- else if (iOSSimVersion)
- Platform = IPhoneOSSimulator;
else
llvm_unreachable("Unable to infer Darwin variant");
- // Reject invalid architecture combinations.
- if (iOSSimVersion && (getTriple().getArch() != llvm::Triple::x86 &&
- getTriple().getArch() != llvm::Triple::x86_64)) {
- getDriver().Diag(diag::err_drv_invalid_arch_for_deployment_target)
- << getTriple().getArchName() << iOSSimVersion->getAsString(Args);
- }
-
// Set the tool chain target information.
unsigned Major, Minor, Micro;
bool HadExtra;
if (Platform == MacOS) {
- assert((!iOSVersion && !iOSSimVersion) && "Unknown target platform!");
+ assert(!iOSVersion && "Unknown target platform!");
if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor,
Micro, HadExtra) || HadExtra ||
Major != 10 || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSXVersion->getAsString(Args);
- } else if (Platform == IPhoneOS || Platform == IPhoneOSSimulator) {
- const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion;
- assert(Version && "Unknown target platform!");
- if (!Driver::GetReleaseVersion(Version->getValue(), Major, Minor,
+ } else if (Platform == IPhoneOS) {
+ assert(iOSVersion && "Unknown target platform!");
+ if (!Driver::GetReleaseVersion(iOSVersion->getValue(), Major, Minor,
Micro, HadExtra) || HadExtra ||
Major >= 10 || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
- << Version->getAsString(Args);
+ << iOSVersion->getAsString(Args);
} else
llvm_unreachable("unknown kind of Darwin platform");
- // In GCC, the simulator historically was treated as being OS X in some
- // contexts, like determining the link logic, despite generally being called
- // with an iOS deployment target. For compatibility, we detect the
- // simulator as iOS + x86, and treat it differently in a few contexts.
+ // Recognize iOS targets with an x86 architecture as the iOS simulator.
if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 ||
getTriple().getArch() == llvm::Triple::x86_64))
Platform = IPhoneOSSimulator;
@@ -653,7 +637,6 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
// Use the newer cc_kext for iOS ARM after 6.0.
if (!isTargetIPhoneOS() || isTargetIOSSimulator() ||
- getTriple().getArch() == llvm::Triple::arm64 ||
getTriple().getArch() == llvm::Triple::aarch64 ||
!isIPhoneOSVersionLT(6, 0)) {
llvm::sys::path::append(P, "libclang_rt.cc_kext.a");
@@ -919,9 +902,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// FIXME: It would be far better to avoid inserting those -static arguments,
// but we can't check the deployment target in the translation code until
// it is set here.
- if (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0) &&
- getTriple().getArch() != llvm::Triple::arm64 &&
- getTriple().getArch() != llvm::Triple::aarch64) {
+ if (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0)) {
for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) {
Arg *A = *it;
++it;
@@ -988,7 +969,6 @@ bool MachO::isPIEDefault() const {
bool MachO::isPICDefaultForced() const {
return (getArch() == llvm::Triple::x86_64 ||
- getArch() == llvm::Triple::arm64 ||
getArch() == llvm::Triple::aarch64);
}
@@ -1001,14 +981,7 @@ void Darwin::addMinVersionArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const {
VersionTuple TargetVersion = getTargetVersion();
- // If we had an explicit -mios-simulator-version-min argument, honor that,
- // otherwise use the traditional deployment targets. We can't just check the
- // is-sim attribute because existing code follows this path, and the linker
- // may not handle the argument.
- //
- // FIXME: We may be able to remove this, once we can verify no one depends on
- // it.
- if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ))
+ if (isTargetIOSSimulator())
CmdArgs.push_back("-ios_simulator_version_min");
else if (isTargetIOSBased())
CmdArgs.push_back("-iphoneos_version_min");
@@ -1078,8 +1051,7 @@ void Darwin::addStartObjectFileArgs(const llvm::opt::ArgList &Args,
if (isTargetIOSSimulator()) {
; // iOS simulator does not need crt1.o.
} else if (isTargetIPhoneOS()) {
- if (getArch() == llvm::Triple::arm64 ||
- getArch() == llvm::Triple::aarch64)
+ if (getArch() == llvm::Triple::aarch64)
; // iOS does not need any crt1 files for arm64
else if (isIPhoneOSVersionLT(3, 1))
CmdArgs.push_back("-lcrt1.o");
@@ -1222,8 +1194,8 @@ Generic_GCC::GCCInstallationDetector::init(
// The library directories which may contain GCC installations.
SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs;
// The compatible GCC triples for this particular architecture.
- SmallVector<StringRef, 10> CandidateTripleAliases;
- SmallVector<StringRef, 10> CandidateBiarchTripleAliases;
+ SmallVector<StringRef, 16> CandidateTripleAliases;
+ SmallVector<StringRef, 16> CandidateBiarchTripleAliases;
CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs,
CandidateTripleAliases, CandidateBiarchLibDirs,
CandidateBiarchTripleAliases);
@@ -1397,176 +1369,116 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
"s390x-suse-linux", "s390x-redhat-linux"
};
+ using std::begin;
+ using std::end;
+
switch (TargetTriple.getArch()) {
- case llvm::Triple::arm64:
case llvm::Triple::aarch64:
- LibDirs.append(AArch64LibDirs,
- AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs));
- TripleAliases.append(AArch64Triples,
- AArch64Triples + llvm::array_lengthof(AArch64Triples));
- BiarchLibDirs.append(AArch64LibDirs,
- AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs));
- BiarchTripleAliases.append(
- AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples));
+ LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
+ TripleAliases.append(begin(AArch64Triples), end(AArch64Triples));
+ BiarchLibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
+ BiarchTripleAliases.append(begin(AArch64Triples), end(AArch64Triples));
break;
- case llvm::Triple::arm64_be:
case llvm::Triple::aarch64_be:
- LibDirs.append(AArch64beLibDirs,
- AArch64beLibDirs + llvm::array_lengthof(AArch64beLibDirs));
- TripleAliases.append(AArch64beTriples,
- AArch64beTriples + llvm::array_lengthof(AArch64beTriples));
- BiarchLibDirs.append(AArch64beLibDirs,
- AArch64beLibDirs + llvm::array_lengthof(AArch64beLibDirs));
- BiarchTripleAliases.append(
- AArch64beTriples, AArch64beTriples + llvm::array_lengthof(AArch64beTriples));
+ LibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs));
+ TripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples));
+ BiarchLibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs));
+ BiarchTripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples));
break;
case llvm::Triple::arm:
case llvm::Triple::thumb:
- LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs));
+ LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs));
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
- TripleAliases.append(ARMHFTriples,
- ARMHFTriples + llvm::array_lengthof(ARMHFTriples));
+ TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples));
} else {
- TripleAliases.append(ARMTriples,
- ARMTriples + llvm::array_lengthof(ARMTriples));
+ TripleAliases.append(begin(ARMTriples), end(ARMTriples));
}
break;
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
- LibDirs.append(ARMebLibDirs, ARMebLibDirs + llvm::array_lengthof(ARMebLibDirs));
+ LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs));
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
- TripleAliases.append(ARMebHFTriples,
- ARMebHFTriples + llvm::array_lengthof(ARMebHFTriples));
+ TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples));
} else {
- TripleAliases.append(ARMebTriples,
- ARMebTriples + llvm::array_lengthof(ARMebTriples));
+ TripleAliases.append(begin(ARMebTriples), end(ARMebTriples));
}
break;
case llvm::Triple::x86_64:
- LibDirs.append(X86_64LibDirs,
- X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
- TripleAliases.append(X86_64Triples,
- X86_64Triples + llvm::array_lengthof(X86_64Triples));
- // x32 is always available when x86_64 is available, so adding it as secondary
- // arch with x86_64 triples
+ LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
+ TripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
+ // x32 is always available when x86_64 is available, so adding it as
+ // secondary arch with x86_64 triples
if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) {
- BiarchLibDirs.append(X32LibDirs,
- X32LibDirs + llvm::array_lengthof(X32LibDirs));
- BiarchTripleAliases.append(X86_64Triples,
- X86_64Triples + llvm::array_lengthof(X86_64Triples));
+ BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs));
+ BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
} else {
- BiarchLibDirs.append(X86LibDirs,
- X86LibDirs + llvm::array_lengthof(X86LibDirs));
- BiarchTripleAliases.append(X86Triples,
- X86Triples + llvm::array_lengthof(X86Triples));
+ BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs));
+ BiarchTripleAliases.append(begin(X86Triples), end(X86Triples));
}
break;
case llvm::Triple::x86:
- LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs));
- TripleAliases.append(X86Triples,
- X86Triples + llvm::array_lengthof(X86Triples));
- BiarchLibDirs.append(X86_64LibDirs,
- X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
- BiarchTripleAliases.append(
- X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples));
+ LibDirs.append(begin(X86LibDirs), end(X86LibDirs));
+ TripleAliases.append(begin(X86Triples), end(X86Triples));
+ BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
+ BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
break;
case llvm::Triple::mips:
- LibDirs.append(MIPSLibDirs,
- MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs));
- TripleAliases.append(MIPSTriples,
- MIPSTriples + llvm::array_lengthof(MIPSTriples));
- BiarchLibDirs.append(MIPS64LibDirs,
- MIPS64LibDirs + llvm::array_lengthof(MIPS64LibDirs));
- BiarchTripleAliases.append(
- MIPS64Triples, MIPS64Triples + llvm::array_lengthof(MIPS64Triples));
+ LibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs));
+ TripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
+ BiarchLibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs));
+ BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples));
break;
case llvm::Triple::mipsel:
- LibDirs.append(MIPSELLibDirs,
- MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs));
- TripleAliases.append(MIPSELTriples,
- MIPSELTriples + llvm::array_lengthof(MIPSELTriples));
- TripleAliases.append(MIPSTriples,
- MIPSTriples + llvm::array_lengthof(MIPSTriples));
- BiarchLibDirs.append(
- MIPS64ELLibDirs,
- MIPS64ELLibDirs + llvm::array_lengthof(MIPS64ELLibDirs));
- BiarchTripleAliases.append(
- MIPS64ELTriples,
- MIPS64ELTriples + llvm::array_lengthof(MIPS64ELTriples));
+ LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs));
+ TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples));
+ TripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
+ BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs));
+ BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples));
break;
case llvm::Triple::mips64:
- LibDirs.append(MIPS64LibDirs,
- MIPS64LibDirs + llvm::array_lengthof(MIPS64LibDirs));
- TripleAliases.append(MIPS64Triples,
- MIPS64Triples + llvm::array_lengthof(MIPS64Triples));
- BiarchLibDirs.append(MIPSLibDirs,
- MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs));
- BiarchTripleAliases.append(MIPSTriples,
- MIPSTriples + llvm::array_lengthof(MIPSTriples));
+ LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs));
+ TripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples));
+ BiarchLibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs));
+ BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
break;
case llvm::Triple::mips64el:
- LibDirs.append(MIPS64ELLibDirs,
- MIPS64ELLibDirs + llvm::array_lengthof(MIPS64ELLibDirs));
- TripleAliases.append(
- MIPS64ELTriples,
- MIPS64ELTriples + llvm::array_lengthof(MIPS64ELTriples));
- BiarchLibDirs.append(MIPSELLibDirs,
- MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs));
- BiarchTripleAliases.append(
- MIPSELTriples, MIPSELTriples + llvm::array_lengthof(MIPSELTriples));
- BiarchTripleAliases.append(
- MIPSTriples, MIPSTriples + llvm::array_lengthof(MIPSTriples));
+ LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs));
+ TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples));
+ BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs));
+ BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples));
+ BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
break;
case llvm::Triple::ppc:
- LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
- TripleAliases.append(PPCTriples,
- PPCTriples + llvm::array_lengthof(PPCTriples));
- BiarchLibDirs.append(PPC64LibDirs,
- PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
- BiarchTripleAliases.append(
- PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples));
+ LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs));
+ TripleAliases.append(begin(PPCTriples), end(PPCTriples));
+ BiarchLibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs));
+ BiarchTripleAliases.append(begin(PPC64Triples), end(PPC64Triples));
break;
case llvm::Triple::ppc64:
- LibDirs.append(PPC64LibDirs,
- PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
- TripleAliases.append(PPC64Triples,
- PPC64Triples + llvm::array_lengthof(PPC64Triples));
- BiarchLibDirs.append(PPCLibDirs,
- PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
- BiarchTripleAliases.append(PPCTriples,
- PPCTriples + llvm::array_lengthof(PPCTriples));
+ LibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs));
+ TripleAliases.append(begin(PPC64Triples), end(PPC64Triples));
+ BiarchLibDirs.append(begin(PPCLibDirs), end(PPCLibDirs));
+ BiarchTripleAliases.append(begin(PPCTriples), end(PPCTriples));
break;
case llvm::Triple::ppc64le:
- LibDirs.append(PPC64LELibDirs,
- PPC64LELibDirs + llvm::array_lengthof(PPC64LELibDirs));
- TripleAliases.append(PPC64LETriples,
- PPC64LETriples + llvm::array_lengthof(PPC64LETriples));
+ LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs));
+ TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples));
break;
case llvm::Triple::sparc:
- LibDirs.append(SPARCv8LibDirs,
- SPARCv8LibDirs + llvm::array_lengthof(SPARCv8LibDirs));
- TripleAliases.append(SPARCv8Triples,
- SPARCv8Triples + llvm::array_lengthof(SPARCv8Triples));
- BiarchLibDirs.append(SPARCv9LibDirs,
- SPARCv9LibDirs + llvm::array_lengthof(SPARCv9LibDirs));
- BiarchTripleAliases.append(
- SPARCv9Triples, SPARCv9Triples + llvm::array_lengthof(SPARCv9Triples));
+ LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs));
+ TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples));
+ BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs));
+ BiarchTripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples));
break;
case llvm::Triple::sparcv9:
- LibDirs.append(SPARCv9LibDirs,
- SPARCv9LibDirs + llvm::array_lengthof(SPARCv9LibDirs));
- TripleAliases.append(SPARCv9Triples,
- SPARCv9Triples + llvm::array_lengthof(SPARCv9Triples));
- BiarchLibDirs.append(SPARCv8LibDirs,
- SPARCv8LibDirs + llvm::array_lengthof(SPARCv8LibDirs));
- BiarchTripleAliases.append(
- SPARCv8Triples, SPARCv8Triples + llvm::array_lengthof(SPARCv8Triples));
+ LibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs));
+ TripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples));
+ BiarchLibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs));
+ BiarchTripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples));
break;
case llvm::Triple::systemz:
- LibDirs.append(SystemZLibDirs,
- SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs));
- TripleAliases.append(SystemZTriples,
- SystemZTriples + llvm::array_lengthof(SystemZTriples));
+ LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs));
+ TripleAliases.append(begin(SystemZTriples), end(SystemZTriples));
break;
default:
@@ -1645,6 +1557,10 @@ struct DetectedMultilibs {
llvm::Optional<Multilib> BiarchSibling;
};
+static Multilib makeMultilib(StringRef commonSuffix) {
+ return Multilib(commonSuffix, commonSuffix, commonSuffix);
+}
+
static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path,
const llvm::opt::ArgList &Args,
DetectedMultilibs &Result) {
@@ -1678,69 +1594,46 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path,
// Check for FSF toolchain multilibs
MultilibSet FSFMipsMultilibs;
{
- Multilib MArchMips32 = Multilib()
- .gccSuffix("/mips32")
- .osSuffix("/mips32")
- .includeSuffix("/mips32")
+ auto MArchMips32 = makeMultilib("/mips32")
.flag("+m32").flag("-m64").flag("-mmicromips").flag("+march=mips32");
- Multilib MArchMicroMips = Multilib()
- .gccSuffix("/micromips")
- .osSuffix("/micromips")
- .includeSuffix("/micromips")
+ auto MArchMicroMips = makeMultilib("/micromips")
.flag("+m32").flag("-m64").flag("+mmicromips");
- Multilib MArchMips64r2 = Multilib()
- .gccSuffix("/mips64r2")
- .osSuffix("/mips64r2")
- .includeSuffix("/mips64r2")
+ auto MArchMips64r2 = makeMultilib("/mips64r2")
.flag("-m32").flag("+m64").flag("+march=mips64r2");
- Multilib MArchMips64 = Multilib()
- .gccSuffix("/mips64")
- .osSuffix("/mips64")
- .includeSuffix("/mips64")
+ auto MArchMips64 = makeMultilib("/mips64")
.flag("-m32").flag("+m64").flag("-march=mips64r2");
- Multilib MArchDefault = Multilib()
+ auto MArchDefault = makeMultilib("")
.flag("+m32").flag("-m64").flag("-mmicromips").flag("+march=mips32r2");
- Multilib Mips16 = Multilib()
- .gccSuffix("/mips16")
- .osSuffix("/mips16")
- .includeSuffix("/mips16")
+ auto Mips16 = makeMultilib("/mips16")
.flag("+mips16");
- Multilib MAbi64 = Multilib()
- .gccSuffix("/64")
- .osSuffix("/64")
- .includeSuffix("/64")
+ auto UCLibc = makeMultilib("/uclibc")
+ .flag("+muclibc");
+
+ auto MAbi64 = makeMultilib("/64")
.flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
- Multilib BigEndian = Multilib()
+ auto BigEndian = makeMultilib("")
.flag("+EB").flag("-EL");
- Multilib LittleEndian = Multilib()
- .gccSuffix("/el")
- .osSuffix("/el")
- .includeSuffix("/el")
+ auto LittleEndian = makeMultilib("/el")
.flag("+EL").flag("-EB");
- Multilib SoftFloat = Multilib()
- .gccSuffix("/sof")
- .osSuffix("/sof")
- .includeSuffix("/sof")
+ auto SoftFloat = makeMultilib("/sof")
.flag("+msoft-float");
- Multilib Nan2008 = Multilib()
- .gccSuffix("/nan2008")
- .osSuffix("/nan2008")
- .includeSuffix("/nan2008")
+ auto Nan2008 = makeMultilib("/nan2008")
.flag("+mnan=2008");
FSFMipsMultilibs = MultilibSet()
.Either(MArchMips32, MArchMicroMips,
MArchMips64r2, MArchMips64, MArchDefault)
+ .Maybe(UCLibc)
.Maybe(Mips16)
.FilterOut("/mips64/mips16")
.FilterOut("/mips64r2/mips16")
@@ -1754,59 +1647,59 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path,
.Maybe(SoftFloat)
.Maybe(Nan2008)
.FilterOut(".*sof/nan2008")
- .FilterOut(NonExistent);
+ .FilterOut(NonExistent)
+ .setIncludeDirsCallback([](
+ StringRef InstallDir, StringRef TripleStr, const Multilib &M) {
+ std::vector<std::string> Dirs;
+ Dirs.push_back((InstallDir + "/include").str());
+ std::string SysRootInc = InstallDir.str() + "/../../../../sysroot";
+ if (StringRef(M.includeSuffix()).startswith("/uclibc"))
+ Dirs.push_back(SysRootInc + "/uclibc/usr/include");
+ else
+ Dirs.push_back(SysRootInc + "/usr/include");
+ return Dirs;
+ });
}
// Check for Code Sourcery toolchain multilibs
MultilibSet CSMipsMultilibs;
{
- Multilib MArchMips16 = Multilib()
- .gccSuffix("/mips16")
- .osSuffix("/mips16")
- .includeSuffix("/mips16")
+ auto MArchMips16 = makeMultilib("/mips16")
.flag("+m32").flag("+mips16");
- Multilib MArchMicroMips = Multilib()
- .gccSuffix("/micromips")
- .osSuffix("/micromips")
- .includeSuffix("/micromips")
+ auto MArchMicroMips = makeMultilib("/micromips")
.flag("+m32").flag("+mmicromips");
- Multilib MArchDefault = Multilib()
+ auto MArchDefault = makeMultilib("")
.flag("-mips16").flag("-mmicromips");
- Multilib SoftFloat = Multilib()
- .gccSuffix("/soft-float")
- .osSuffix("/soft-float")
- .includeSuffix("/soft-float")
+ auto UCLibc = makeMultilib("/uclibc")
+ .flag("+muclibc");
+
+ auto SoftFloat = makeMultilib("/soft-float")
.flag("+msoft-float");
- Multilib Nan2008 = Multilib()
- .gccSuffix("/nan2008")
- .osSuffix("/nan2008")
- .includeSuffix("/nan2008")
+ auto Nan2008 = makeMultilib("/nan2008")
.flag("+mnan=2008");
- Multilib DefaultFloat = Multilib()
+ auto DefaultFloat = makeMultilib("")
.flag("-msoft-float").flag("-mnan=2008");
- Multilib BigEndian = Multilib()
+ auto BigEndian = makeMultilib("")
.flag("+EB").flag("-EL");
- Multilib LittleEndian = Multilib()
- .gccSuffix("/el")
- .osSuffix("/el")
- .includeSuffix("/el")
+ auto LittleEndian = makeMultilib("/el")
.flag("+EL").flag("-EB");
// Note that this one's osSuffix is ""
- Multilib MAbi64 = Multilib()
+ auto MAbi64 = makeMultilib("")
.gccSuffix("/64")
.includeSuffix("/64")
.flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
CSMipsMultilibs = MultilibSet()
.Either(MArchMips16, MArchMicroMips, MArchDefault)
+ .Maybe(UCLibc)
.Either(SoftFloat, Nan2008, DefaultFloat)
.FilterOut("/micromips/nan2008")
.FilterOut("/mips16/nan2008")
@@ -1814,7 +1707,19 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path,
.Maybe(MAbi64)
.FilterOut("/mips16.*/64")
.FilterOut("/micromips.*/64")
- .FilterOut(NonExistent);
+ .FilterOut(NonExistent)
+ .setIncludeDirsCallback([](
+ StringRef InstallDir, StringRef TripleStr, const Multilib &M) {
+ std::vector<std::string> Dirs;
+ Dirs.push_back((InstallDir + "/include").str());
+ std::string SysRootInc =
+ InstallDir.str() + "/../../../../" + TripleStr.str();
+ if (StringRef(M.includeSuffix()).startswith("/uclibc"))
+ Dirs.push_back(SysRootInc + "/libc/uclibc/usr/include");
+ else
+ Dirs.push_back(SysRootInc + "/libc/usr/include");
+ return Dirs;
+ });
}
MultilibSet AndroidMipsMultilibs = MultilibSet()
@@ -1843,29 +1748,27 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path,
MultilibSet ImgMultilibs;
{
- Multilib Mips64r6 = Multilib()
- .gccSuffix("/mips64r6")
- .osSuffix("/mips64r6")
- .includeSuffix("/mips64r6")
+ auto Mips64r6 = makeMultilib("/mips64r6")
.flag("+m64").flag("-m32");
- Multilib LittleEndian = Multilib()
- .gccSuffix("/el")
- .osSuffix("/el")
- .includeSuffix("/el")
+ auto LittleEndian = makeMultilib("/el")
.flag("+EL").flag("-EB");
- Multilib MAbi64 = Multilib()
- .gccSuffix("/64")
- .osSuffix("/64")
- .includeSuffix("/64")
+ auto MAbi64 = makeMultilib("/64")
.flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
ImgMultilibs = MultilibSet()
.Maybe(Mips64r6)
.Maybe(MAbi64)
.Maybe(LittleEndian)
- .FilterOut(NonExistent);
+ .FilterOut(NonExistent)
+ .setIncludeDirsCallback([](
+ StringRef InstallDir, StringRef TripleStr, const Multilib &M) {
+ std::vector<std::string> Dirs;
+ Dirs.push_back((InstallDir + "/include").str());
+ Dirs.push_back((InstallDir + "/../../../../sysroot/usr/include").str());
+ return Dirs;
+ });
}
StringRef CPUName;
@@ -1884,6 +1787,7 @@ static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path,
addMultilibFlag(CPUName == "mips64r2" || CPUName == "octeon",
"march=mips64r2", Flags);
addMultilibFlag(isMicroMips(Args), "mmicromips", Flags);
+ addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags);
addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008",
Flags);
addMultilibFlag(ABIName == "n32", "mabi=n32", Flags);
@@ -2159,12 +2063,16 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const {
getTriple().getArch() == llvm::Triple::x86_64 ||
getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::aarch64_be ||
- getTriple().getArch() == llvm::Triple::arm64 ||
- getTriple().getArch() == llvm::Triple::arm64_be ||
getTriple().getArch() == llvm::Triple::arm ||
getTriple().getArch() == llvm::Triple::armeb ||
getTriple().getArch() == llvm::Triple::thumb ||
- getTriple().getArch() == llvm::Triple::thumbeb;
+ getTriple().getArch() == llvm::Triple::thumbeb ||
+ getTriple().getArch() == llvm::Triple::ppc ||
+ getTriple().getArch() == llvm::Triple::ppc64 ||
+ getTriple().getArch() == llvm::Triple::ppc64le ||
+ getTriple().getArch() == llvm::Triple::sparc ||
+ getTriple().getArch() == llvm::Triple::sparcv9 ||
+ getTriple().getArch() == llvm::Triple::systemz;
}
void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
@@ -2173,8 +2081,6 @@ void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
bool UseInitArrayDefault =
getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::aarch64_be ||
- getTriple().getArch() == llvm::Triple::arm64 ||
- getTriple().getArch() == llvm::Triple::arm64_be ||
(getTriple().getOS() == llvm::Triple::Linux &&
(!V.isOlderThan(4, 7, 0) ||
getTriple().getEnvironment() == llvm::Triple::Android));
@@ -2187,11 +2093,14 @@ void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
/// Hexagon Toolchain
-std::string Hexagon_TC::GetGnuDir(const std::string &InstalledDir) {
+std::string Hexagon_TC::GetGnuDir(const std::string &InstalledDir,
+ const ArgList &Args) {
// Locate the rest of the toolchain ...
- if (strlen(GCC_INSTALL_PREFIX))
- return std::string(GCC_INSTALL_PREFIX);
+ std::string GccToolchain = getGCCToolchainDir(Args);
+
+ if (!GccToolchain.empty())
+ return GccToolchain;
std::string InstallRelDir = InstalledDir + "/../../gnu";
if (llvm::sys::fs::exists(InstallRelDir))
@@ -2206,8 +2115,8 @@ std::string Hexagon_TC::GetGnuDir(const std::string &InstalledDir) {
static void GetHexagonLibraryPaths(
const ArgList &Args,
- const std::string Ver,
- const std::string MarchString,
+ const std::string &Ver,
+ const std::string &MarchString,
const std::string &InstalledDir,
ToolChain::path_list *LibPaths)
{
@@ -2231,7 +2140,7 @@ static void GetHexagonLibraryPaths(
const std::string MarchSuffix = "/" + MarchString;
const std::string G0Suffix = "/G0";
const std::string MarchG0Suffix = MarchSuffix + G0Suffix;
- const std::string RootDir = Hexagon_TC::GetGnuDir(InstalledDir) + "/";
+ const std::string RootDir = Hexagon_TC::GetGnuDir(InstalledDir, Args) + "/";
// lib/gcc/hexagon/...
std::string LibGCCHexagonDir = RootDir + "lib/gcc/hexagon/";
@@ -2259,7 +2168,7 @@ Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: Linux(D, Triple, Args) {
const std::string InstalledDir(getDriver().getInstalledDir());
- const std::string GnuDir = Hexagon_TC::GetGnuDir(InstalledDir);
+ const std::string GnuDir = Hexagon_TC::GetGnuDir(InstalledDir, Args);
// Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
// program paths
@@ -2314,7 +2223,7 @@ void Hexagon_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
return;
std::string Ver(GetGCCLibAndIncVersion());
- std::string GnuDir = Hexagon_TC::GetGnuDir(D.InstalledDir);
+ std::string GnuDir = Hexagon_TC::GetGnuDir(D.InstalledDir, DriverArgs);
std::string HexagonDir(GnuDir + "/lib/gcc/hexagon/" + Ver);
addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include");
addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include-fixed");
@@ -2330,7 +2239,8 @@ void Hexagon_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
const Driver &D = getDriver();
std::string Ver(GetGCCLibAndIncVersion());
- SmallString<128> IncludeDir(Hexagon_TC::GetGnuDir(D.InstalledDir));
+ SmallString<128> IncludeDir(
+ Hexagon_TC::GetGnuDir(D.InstalledDir, DriverArgs));
llvm::sys::path::append(IncludeDir, "hexagon/include/c++/");
llvm::sys::path::append(IncludeDir, Ver);
@@ -2599,7 +2509,7 @@ bool FreeBSD::HasNativeLLVMSupport() const {
}
bool FreeBSD::isPIEDefault() const {
- return getSanitizerArgs().hasZeroBaseShadow();
+ return getSanitizerArgs().requiresPIE();
}
/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
@@ -2623,11 +2533,13 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
case llvm::Triple::thumbeb:
switch (Triple.getEnvironment()) {
case llvm::Triple::EABI:
- case llvm::Triple::EABIHF:
case llvm::Triple::GNUEABI:
- case llvm::Triple::GNUEABIHF:
getFilePaths().push_back("=/usr/lib/eabi");
break;
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABIHF:
+ getFilePaths().push_back("=/usr/lib/eabihf");
+ break;
default:
getFilePaths().push_back("=/usr/lib/oabi");
break;
@@ -2640,6 +2552,9 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
else if (tools::mips::hasMipsAbiArg(Args, "64"))
getFilePaths().push_back("=/usr/lib/64");
break;
+ case llvm::Triple::ppc:
+ getFilePaths().push_back("=/usr/lib/powerpc");
+ break;
case llvm::Triple::sparc:
getFilePaths().push_back("=/usr/lib/sparc");
break;
@@ -2674,12 +2589,16 @@ NetBSD::GetCXXStdlibType(const ArgList &Args) const {
unsigned Major, Minor, Micro;
getTriple().getOSVersion(Major, Minor, Micro);
- if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 40) || Major == 0) {
+ if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 49) || Major == 0) {
switch (getArch()) {
+ case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
return ToolChain::CST_Libcxx;
@@ -2726,32 +2645,6 @@ Tool *Minix::buildLinker() const {
return new tools::minix::Link(*this);
}
-/// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly.
-
-AuroraUX::AuroraUX(const Driver &D, const llvm::Triple& Triple,
- const ArgList &Args)
- : Generic_GCC(D, Triple, Args) {
-
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir)
- getProgramPaths().push_back(getDriver().Dir);
-
- getFilePaths().push_back(getDriver().Dir + "/../lib");
- getFilePaths().push_back("/usr/lib");
- getFilePaths().push_back("/usr/sfw/lib");
- getFilePaths().push_back("/opt/gcc4/lib");
- getFilePaths().push_back("/opt/gcc4/lib/gcc/i386-pc-solaris2.11/4.2.4");
-
-}
-
-Tool *AuroraUX::buildAssembler() const {
- return new tools::auroraux::Assemble(*this);
-}
-
-Tool *AuroraUX::buildLinker() const {
- return new tools::auroraux::Link(*this);
-}
-
/// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
Solaris::Solaris(const Driver &D, const llvm::Triple& Triple,
@@ -2825,7 +2718,7 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) {
llvm::MemoryBuffer::getFile("/etc/lsb-release");
if (File) {
StringRef Data = File.get()->getBuffer();
- SmallVector<StringRef, 8> Lines;
+ SmallVector<StringRef, 16> Lines;
Data.split(Lines, "\n");
Distro Version = UnknownDistro;
for (unsigned i = 0, s = Lines.size(); i != s; ++i)
@@ -2939,12 +2832,10 @@ static std::string getMultiarchTriple(const llvm::Triple &TargetTriple,
llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu"))
return "x86_64-linux-gnu";
return TargetTriple.str();
- case llvm::Triple::arm64:
case llvm::Triple::aarch64:
if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu"))
return "aarch64-linux-gnu";
return TargetTriple.str();
- case llvm::Triple::arm64_be:
case llvm::Triple::aarch64_be:
if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64_be-linux-gnu"))
return "aarch64_be-linux-gnu";
@@ -3115,7 +3006,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// installation that is *not* within the system root to ensure two things:
//
// 1) Any DSOs that are linked in from this tree or from the install path
- // above must be preasant on the system root and found via an
+ // above must be present on the system root and found via an
// appropriate rpath.
// 2) There must not be libraries installed into
// <prefix>/<triple>/<libdir> unless they should be preferred over
@@ -3272,20 +3163,16 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// Lacking those, try to detect the correct set of system includes for the
// target triple.
- // Sourcery CodeBench and modern FSF Mips toolchains put extern C
- // system includes under three additional directories.
- if (GCCInstallation.isValid() && isMipsArch(getTriple().getArch())) {
- addExternCSystemIncludeIfExists(
- DriverArgs, CC1Args, GCCInstallation.getInstallPath() + "/include");
-
- addExternCSystemIncludeIfExists(
- DriverArgs, CC1Args,
- GCCInstallation.getInstallPath() + "/../../../../" +
- GCCInstallation.getTriple().str() + "/libc/usr/include");
-
- addExternCSystemIncludeIfExists(
- DriverArgs, CC1Args,
- GCCInstallation.getInstallPath() + "/../../../../sysroot/usr/include");
+ // Add include directories specific to the selected multilib set and multilib.
+ if (GCCInstallation.isValid()) {
+ auto Callback = Multilibs.includeDirsCallback();
+ if (Callback) {
+ const auto IncludePaths = Callback(GCCInstallation.getInstallPath(),
+ GCCInstallation.getTriple().str(),
+ GCCInstallation.getMultilib());
+ for (const auto &Path : IncludePaths)
+ addExternCSystemIncludeIfExists(DriverArgs, CC1Args, Path);
+ }
}
// Implement generic Debian multiarch support.
@@ -3344,9 +3231,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
} else if (getTriple().getArch() == llvm::Triple::x86) {
MultiarchIncludeDirs = X86MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::aarch64 ||
- getTriple().getArch() == llvm::Triple::aarch64_be ||
- getTriple().getArch() == llvm::Triple::arm64 ||
- getTriple().getArch() == llvm::Triple::arm64_be) {
+ getTriple().getArch() == llvm::Triple::aarch64_be) {
MultiarchIncludeDirs = AArch64MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::arm) {
if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
@@ -3500,7 +3385,7 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
}
bool Linux::isPIEDefault() const {
- return getSanitizerArgs().hasZeroBaseShadow();
+ return getSanitizerArgs().requiresPIE();
}
/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly.
@@ -3586,7 +3471,8 @@ void XCore::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
void XCore::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdinc) ||
- DriverArgs.hasArg(options::OPT_nostdlibinc))
+ DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
return;
if (const char *cl_include_dir = getenv("XCC_CPLUS_INCLUDE_PATH")) {
SmallVector<StringRef, 4> Dirs;
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index b5df8668d69e..47fb10d3f6c5 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_LIB_DRIVER_TOOLCHAINS_H_
-#define CLANG_LIB_DRIVER_TOOLCHAINS_H_
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H
#include "Tools.h"
#include "clang/Basic/VersionTuple.h"
@@ -234,9 +234,10 @@ public:
void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
- StringRef DarwinStaticLib,
+ StringRef DarwinLibName,
bool AlwaysLink = false,
- bool IsEmbedded = false) const;
+ bool IsEmbedded = false,
+ bool AddRPath = false) const;
/// }
/// @name ToolChain Implementation
@@ -255,7 +256,7 @@ public:
bool IsBlocksDefault() const override {
// Always allow blocks on Apple; users interested in versioning are
- // expected to use /usr/include/Blocks.h.
+ // expected to use /usr/include/Block.h.
return true;
}
bool IsIntegratedAssemblerDefault() const override {
@@ -362,7 +363,7 @@ public:
bool isKernelStatic() const override {
return !isTargetIPhoneOS() || isIPhoneOSVersionLT(6, 0) ||
- getTriple().getArch() == llvm::Triple::arm64;
+ getTriple().getArch() == llvm::Triple::aarch64;
}
protected:
@@ -487,7 +488,8 @@ public:
AddCCKextLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
- virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const;
+ virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args)
+ const override;
void
AddLinkARCArgs(const llvm::opt::ArgList &Args,
@@ -506,16 +508,6 @@ public:
llvm::opt::ArgStringList &CC1Args) const override;
};
-class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC {
-public:
- AuroraUX(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC {
public:
Solaris(const Driver &D, const llvm::Triple &Triple,
@@ -542,14 +534,6 @@ public:
return 2;
}
- virtual bool IsIntegratedAssemblerDefault() const override {
- if (getTriple().getArch() == llvm::Triple::ppc ||
- getTriple().getArch() == llvm::Triple::sparc ||
- getTriple().getArch() == llvm::Triple::sparcv9)
- return true;
- return Generic_ELF::IsIntegratedAssemblerDefault();
- }
-
protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
@@ -591,12 +575,6 @@ public:
void
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- bool IsIntegratedAssemblerDefault() const override {
- if (getTriple().getArch() == llvm::Triple::ppc ||
- getTriple().getArch() == llvm::Triple::ppc64)
- return true;
- return Generic_ELF::IsIntegratedAssemblerDefault();
- }
bool UseSjLjExceptions() const override;
bool isPIEDefault() const override;
@@ -621,11 +599,6 @@ public:
bool IsUnwindTablesDefault() const override {
return true;
}
- bool IsIntegratedAssemblerDefault() const override {
- if (getTriple().getArch() == llvm::Triple::ppc)
- return true;
- return Generic_ELF::IsIntegratedAssemblerDefault();
- }
protected:
Tool *buildAssembler() const override;
@@ -709,7 +682,8 @@ public:
StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; }
- static std::string GetGnuDir(const std::string &InstalledDir);
+ static std::string GetGnuDir(const std::string &InstalledDir,
+ const llvm::opt::ArgList &Args);
static StringRef GetTargetCPU(const llvm::opt::ArgList &Args);
};
@@ -728,10 +702,10 @@ public:
bool isPICDefaultForced() const override;
};
-class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain {
+class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
public:
- Windows(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
+ MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
bool IsIntegratedAssemblerDefault() const override;
bool IsUnwindTablesDefault() const override;
@@ -746,11 +720,50 @@ public:
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+ bool getWindowsSDKDir(std::string &path, int &major, int &minor) const;
+ bool getWindowsSDKLibraryPath(std::string &path) const;
+ bool getVisualStudioInstallDir(std::string &path) const;
+ bool getVisualStudioBinariesFolder(const char *clangProgramPath,
+ std::string &path) const;
+
protected:
+ void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ const std::string &folder,
+ const char *subfolder) const;
+
Tool *buildLinker() const override;
Tool *buildAssembler() const override;
};
+class LLVM_LIBRARY_VISIBILITY CrossWindowsToolChain : public Generic_GCC {
+public:
+ CrossWindowsToolChain(const Driver &D, const llvm::Triple &T,
+ const llvm::opt::ArgList &Args);
+
+ bool IsIntegratedAssemblerDefault() const override { return true; }
+ bool IsUnwindTablesDefault() const override;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+
+ unsigned int GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
+ return 0;
+ }
+
+ void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args)
+ const override;
+ void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args)
+ const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+protected:
+ Tool *buildLinker() const override;
+ Tool *buildAssembler() const override;
+};
class LLVM_LIBRARY_VISIBILITY XCore : public ToolChain {
public:
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 198e82e15369..d625c0e3e2f6 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -83,6 +83,23 @@ static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) {
<< A->getAsString(Args) << "-static";
}
+// Add backslashes to escape spaces and other backslashes.
+// This is used for the space-separated argument list specified with
+// the -dwarf-debug-flags option.
+static void EscapeSpacesAndBackslashes(const char *Arg,
+ SmallVectorImpl<char> &Res) {
+ for ( ; *Arg; ++Arg) {
+ switch (*Arg) {
+ default: break;
+ case ' ':
+ case '\\':
+ Res.push_back('\\');
+ break;
+ }
+ Res.push_back(*Arg);
+ }
+}
+
// Quote target names for inclusion in GNU Make dependency files.
// Only the characters '$', '#', ' ', '\t' are quoted.
static void QuoteTarget(StringRef Target,
@@ -457,10 +474,10 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
- case llvm::Triple::arm64:
- case llvm::Triple::arm64_be:
case llvm::Triple::arm:
case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
if (Triple.isOSDarwin() || Triple.isOSWindows())
return true;
return false;
@@ -508,7 +525,7 @@ static void getARMHWDivFeatures(const Driver &D, const Arg *A,
} else
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
-
+
// Handle -mfpu=.
//
// FIXME: Centralize feature selection, defaulting shouldn't be also in the
@@ -546,6 +563,18 @@ static void getARMFPUFeatures(const Driver &D, const Arg *A,
Features.push_back("+d16");
Features.push_back("+fp-only-sp");
Features.push_back("-neon");
+ } else if (FPU == "fp5-sp-d16" || FPU == "fpv5-sp-d16") {
+ Features.push_back("+fp-armv8");
+ Features.push_back("+fp-only-sp");
+ Features.push_back("+d16");
+ Features.push_back("-neon");
+ Features.push_back("-crypto");
+ } else if (FPU == "fp5-dp-d16" || FPU == "fpv5-dp-d16" ||
+ FPU == "fp5-d16" || FPU == "fpv5-d16") {
+ Features.push_back("+fp-armv8");
+ Features.push_back("+d16");
+ Features.push_back("-neon");
+ Features.push_back("-crypto");
} else if (FPU == "fp-armv8") {
Features.push_back("+fp-armv8");
Features.push_back("-neon");
@@ -560,6 +589,12 @@ static void getARMFPUFeatures(const Driver &D, const Arg *A,
Features.push_back("+crypto");
} else if (FPU == "neon") {
Features.push_back("+neon");
+ } else if (FPU == "neon-vfpv3") {
+ Features.push_back("+vfp3");
+ Features.push_back("+neon");
+ } else if (FPU == "neon-vfpv4") {
+ Features.push_back("+neon");
+ Features.push_back("+vfp4");
} else if (FPU == "none") {
Features.push_back("-vfp2");
Features.push_back("-vfp3");
@@ -730,6 +765,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// Select the ABI to use.
//
// FIXME: Support -meabi.
+ // FIXME: Parts of this are duplicated in the backend, unify this somehow.
const char *ABIName = nullptr;
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
ABIName = A->getValue();
@@ -737,8 +773,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// The backend is hardwired to assume AAPCS for M-class processors, ensure
// the frontend matches that.
if (Triple.getEnvironment() == llvm::Triple::EABI ||
- (Triple.getOS() == llvm::Triple::UnknownOS &&
- Triple.getObjectFormat() == llvm::Triple::MachO) ||
+ Triple.getOS() == llvm::Triple::UnknownOS ||
StringRef(CPUName).startswith("cortex-m")) {
ABIName = "aapcs";
} else {
@@ -760,7 +795,11 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
ABIName = "aapcs";
break;
default:
- ABIName = "apcs-gnu";
+ if (Triple.getOS() == llvm::Triple::NetBSD)
+ ABIName = "apcs-gnu";
+ else
+ ABIName = "aapcs";
+ break;
}
}
CmdArgs.push_back("-target-abi");
@@ -801,6 +840,21 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back("-arm-use-movt=0");
}
+ // -mkernel implies -mstrict-align; don't add the redundant option.
+ if (!KernelOrKext) {
+ if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
+ options::OPT_munaligned_access)) {
+ CmdArgs.push_back("-backend-option");
+ if (A->getOption().matches(options::OPT_mno_unaligned_access))
+ CmdArgs.push_back("-arm-strict-align");
+ else {
+ if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
+ D.Diag(diag::err_target_unsupported_unaligned) << "v6m";
+ CmdArgs.push_back("-arm-no-strict-align");
+ }
+ }
+ }
+
// Setting -mno-global-merge disables the codegen global merge pass. Setting
// -mglobal-merge has no effect as the pass is enabled by default.
if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
@@ -875,9 +929,26 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
- if (Args.hasArg(options::OPT_mstrict_align)) {
+ if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
+ options::OPT_munaligned_access)) {
+ CmdArgs.push_back("-backend-option");
+ if (A->getOption().matches(options::OPT_mno_unaligned_access))
+ CmdArgs.push_back("-aarch64-strict-align");
+ else
+ CmdArgs.push_back("-aarch64-no-strict-align");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769,
+ options::OPT_mno_fix_cortex_a53_835769)) {
+ CmdArgs.push_back("-backend-option");
+ if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769))
+ CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1");
+ else
+ CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0");
+ } else if (Triple.getEnvironment() == llvm::Triple::Android) {
+ // Enabled A53 errata (835769) workaround by default on android
CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-aarch64-strict-align");
+ CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1");
}
// Setting -mno-global-merge disables the codegen global merge pass. Setting
@@ -906,6 +977,10 @@ void mips::getMipsCPUAndABI(const ArgList &Args,
DefMips64CPU = "mips64r6";
}
+ // MIPS3 is the default for mips64*-unknown-openbsd.
+ if (Triple.getOS() == llvm::Triple::OpenBSD)
+ DefMips64CPU = "mips3";
+
if (Arg *A = Args.getLastArg(options::OPT_march_EQ,
options::OPT_mcpu_EQ))
CPUName = A->getValue();
@@ -952,6 +1027,8 @@ void mips::getMipsCPUAndABI(const ArgList &Args,
.Cases("n32", "n64", DefMips64CPU)
.Default("");
}
+
+ // FIXME: Warn on inconsistent use of -march and -mabi.
}
// Convert ABI name to the GNU tools acceptable variant.
@@ -1024,6 +1101,9 @@ static void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back("-n64");
Features.push_back(Args.MakeArgString(ABIFeature));
+ AddTargetFeature(Args, Features, options::OPT_mno_abicalls,
+ options::OPT_mabicalls, "noabicalls");
+
StringRef FloatABI = getMipsFloatABI(D, Args);
if (FloatABI == "soft") {
// FIXME: Note, this is a hack. We need to pass the selected float
@@ -1228,6 +1308,35 @@ static void getPPCTargetFeatures(const ArgList &Args,
options::OPT_fno_altivec, "altivec");
}
+void Clang::AddPPCTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Select the ABI to use.
+ const char *ABIName = nullptr;
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
+ ABIName = A->getValue();
+ } else if (getToolChain().getTriple().isOSLinux())
+ switch(getToolChain().getArch()) {
+ case llvm::Triple::ppc64:
+ ABIName = "elfv1";
+ break;
+ case llvm::Triple::ppc64le:
+ ABIName = "elfv2";
+ break;
+ default:
+ break;
+ }
+
+ if (ABIName) {
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(ABIName);
+ }
+}
+
+bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) {
+ Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
+ return A && (A->getValue() == StringRef(Value));
+}
+
/// Get the (LLVM) name of the R600 gpu we are targeting.
static std::string getR600TargetGPU(const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
@@ -1246,7 +1355,7 @@ static std::string getR600TargetGPU(const ArgList &Args) {
}
static void getSparcTargetFeatures(const ArgList &Args,
- std::vector<const char *> Features) {
+ std::vector<const char *> &Features) {
bool SoftFloatABI = true;
if (Arg *A =
Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) {
@@ -1360,8 +1469,6 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) {
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
- case llvm::Triple::arm64:
- case llvm::Triple::arm64_be:
return getAArch64TargetCPU(Args);
case llvm::Triple::arm:
@@ -1415,6 +1522,7 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) {
return getSystemZTargetCPU(Args);
case llvm::Triple::r600:
+ case llvm::Triple::amdgcn:
return getR600TargetGPU(Args);
}
}
@@ -1588,7 +1696,7 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
}
// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
-static bool DecodeAArch64Features(const Driver &D, const StringRef &text,
+static bool DecodeAArch64Features(const Driver &D, StringRef text,
std::vector<const char *> &Features) {
SmallVector<StringRef, 8> Split;
text.split(Split, StringRef("+"), -1, false);
@@ -1697,6 +1805,9 @@ static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features);
else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
+ else if (Args.hasArg(options::OPT_arch))
+ success = getAArch64ArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args), Args,
+ Features);
if (success && (A = Args.getLastArg(options::OPT_mtune_EQ)))
success =
@@ -1704,6 +1815,9 @@ static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
success =
getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
+ else if (Args.hasArg(options::OPT_arch))
+ success = getAArch64MicroArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args),
+ Args, Features);
if (!success)
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
@@ -1751,12 +1865,11 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
getPPCTargetFeatures(Args, Features);
break;
case llvm::Triple::sparc:
+ case llvm::Triple::sparcv9:
getSparcTargetFeatures(Args, Features);
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
- case llvm::Triple::arm64:
- case llvm::Triple::arm64_be:
getAArch64TargetFeatures(D, Args, Features);
break;
case llvm::Triple::x86:
@@ -1804,43 +1917,15 @@ shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
Triple.getArch() == llvm::Triple::arm));
}
-namespace {
- struct ExceptionSettings {
- bool ExceptionsEnabled;
- bool ShouldUseExceptionTables;
- ExceptionSettings() : ExceptionsEnabled(false),
- ShouldUseExceptionTables(false) {}
- };
-} // end anonymous namespace.
-
// exceptionSettings() exists to share the logic between -cc1 and linker
// invocations.
-static ExceptionSettings exceptionSettings(const ArgList &Args,
- const llvm::Triple &Triple) {
- ExceptionSettings ES;
-
- // Are exceptions enabled by default?
- ES.ExceptionsEnabled = (Triple.getArch() != llvm::Triple::xcore);
-
- // This keeps track of whether exceptions were explicitly turned on or off.
- bool DidHaveExplicitExceptionFlag = false;
-
+static bool exceptionSettings(const ArgList &Args, const llvm::Triple &Triple) {
if (Arg *A = Args.getLastArg(options::OPT_fexceptions,
- options::OPT_fno_exceptions)) {
+ options::OPT_fno_exceptions))
if (A->getOption().matches(options::OPT_fexceptions))
- ES.ExceptionsEnabled = true;
- else
- ES.ExceptionsEnabled = false;
-
- DidHaveExplicitExceptionFlag = true;
- }
-
- // Exception tables and cleanups can be enabled with -fexceptions even if the
- // language itself doesn't support exceptions.
- if (ES.ExceptionsEnabled && DidHaveExplicitExceptionFlag)
- ES.ShouldUseExceptionTables = true;
+ return true;
- return ES;
+ return false;
}
/// addExceptionArgs - Adds exception related arguments to the driver command
@@ -1865,8 +1950,8 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
return;
}
- // Gather the exception settings from the command line arguments.
- ExceptionSettings ES = exceptionSettings(Args, Triple);
+ // Gather the exception settings from the command line arguments.
+ bool EH = exceptionSettings(Args, Triple);
// Obj-C exceptions are enabled by default, regardless of -fexceptions. This
// is not necessarily sensible, but follows GCC.
@@ -1876,31 +1961,27 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
true)) {
CmdArgs.push_back("-fobjc-exceptions");
- ES.ShouldUseExceptionTables |=
- shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple);
+ EH |= shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple);
}
if (types::isCXX(InputType)) {
- bool CXXExceptionsEnabled = ES.ExceptionsEnabled;
-
+ bool CXXExceptionsEnabled = Triple.getArch() != llvm::Triple::xcore;
if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions,
options::OPT_fno_cxx_exceptions,
options::OPT_fexceptions,
- options::OPT_fno_exceptions)) {
- if (A->getOption().matches(options::OPT_fcxx_exceptions))
- CXXExceptionsEnabled = true;
- else if (A->getOption().matches(options::OPT_fno_cxx_exceptions))
- CXXExceptionsEnabled = false;
- }
+ options::OPT_fno_exceptions))
+ CXXExceptionsEnabled =
+ A->getOption().matches(options::OPT_fcxx_exceptions) ||
+ A->getOption().matches(options::OPT_fexceptions);
if (CXXExceptionsEnabled) {
CmdArgs.push_back("-fcxx-exceptions");
- ES.ShouldUseExceptionTables = true;
+ EH = true;
}
}
- if (ES.ShouldUseExceptionTables)
+ if (EH)
CmdArgs.push_back("-fexceptions");
}
@@ -1926,7 +2007,7 @@ static bool ShouldDisableDwarfDirectory(const ArgList &Args,
/// \brief Check whether the given input tree contains any compilation actions.
static bool ContainsCompileAction(const Action *A) {
- if (isa<CompileJobAction>(A))
+ if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A))
return true;
for (const auto &Act : *A)
@@ -1994,8 +2075,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
} 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");
+ CmdArgs.push_back("-massembler-fatal-warnings");
} else if (Value == "--noexecstack") {
CmdArgs.push_back("-mnoexecstack");
} else if (Value == "-compress-debug-sections" ||
@@ -2028,11 +2108,13 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
// Until ARM libraries are build separately, we have them all in one library
static StringRef getArchNameForCompilerRTLib(const ToolChain &TC) {
- if (TC.getArch() == llvm::Triple::arm ||
- TC.getArch() == llvm::Triple::armeb)
+ // FIXME: handle 64-bit
+ if (TC.getTriple().isOSWindows() &&
+ !TC.getTriple().isWindowsItaniumEnvironment())
+ return "i386";
+ if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb)
return "arm";
- else
- return TC.getArchName();
+ return TC.getArchName();
}
static SmallString<128> getCompilerRTLibDir(const ToolChain &TC) {
@@ -2040,209 +2122,167 @@ static SmallString<128> getCompilerRTLibDir(const ToolChain &TC) {
SmallString<128> Res(TC.getDriver().ResourceDir);
const llvm::Triple &Triple = TC.getTriple();
// TC.getOS() yield "freebsd10.0" whereas "freebsd" is expected.
- StringRef OSLibName = (Triple.getOS() == llvm::Triple::FreeBSD) ?
- "freebsd" : TC.getOS();
+ StringRef OSLibName =
+ (Triple.getOS() == llvm::Triple::FreeBSD) ? "freebsd" : TC.getOS();
llvm::sys::path::append(Res, "lib", OSLibName);
return Res;
}
+static SmallString<128> getCompilerRT(const ToolChain &TC, StringRef Component,
+ bool Shared = false,
+ const char *Env = "") {
+ bool IsOSWindows = TC.getTriple().isOSWindows();
+ StringRef Arch = getArchNameForCompilerRTLib(TC);
+ const char *Prefix = IsOSWindows ? "" : "lib";
+ const char *Suffix =
+ Shared ? (IsOSWindows ? ".dll" : ".so") : (IsOSWindows ? ".lib" : ".a");
+
+ SmallString<128> Path = getCompilerRTLibDir(TC);
+ llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" +
+ Arch + Env + Suffix);
+
+ return Path;
+}
+
// This adds the static libclang_rt.builtins-arch.a directly to the command line
// FIXME: Make sure we can also emit shared objects if they're requested
// and available, check for possible errors, etc.
-static void addClangRTLinux(
- const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) {
- SmallString<128> LibClangRT = getCompilerRTLibDir(TC);
- llvm::sys::path::append(LibClangRT, Twine("libclang_rt.builtins-") +
- getArchNameForCompilerRTLib(TC) +
- ".a");
-
- CmdArgs.push_back(Args.MakeArgString(LibClangRT));
- CmdArgs.push_back("-lgcc_s");
- if (TC.getDriver().CCCIsCXX())
- CmdArgs.push_back("-lgcc_eh");
+static void addClangRT(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, "builtins")));
+
+ if (!TC.getTriple().isOSWindows()) {
+ // FIXME: why do we link against gcc when we are using compiler-rt?
+ CmdArgs.push_back("-lgcc_s");
+ if (TC.getDriver().CCCIsCXX())
+ CmdArgs.push_back("-lgcc_eh");
+ }
}
-static void addProfileRT(
- const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) {
- if (!(Args.hasArg(options::OPT_fprofile_arcs) ||
+static void addProfileRT(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
+ false) ||
Args.hasArg(options::OPT_fprofile_generate) ||
Args.hasArg(options::OPT_fprofile_instr_generate) ||
Args.hasArg(options::OPT_fcreate_profile) ||
Args.hasArg(options::OPT_coverage)))
return;
- // -fprofile-instr-generate requires position-independent code to build with
- // shared objects. Link against the right archive.
- const char *Lib = "libclang_rt.profile-";
- if (Args.hasArg(options::OPT_fprofile_instr_generate) &&
- Args.hasArg(options::OPT_shared))
- Lib = "libclang_rt.profile-pic-";
-
- SmallString<128> LibProfile = getCompilerRTLibDir(TC);
- llvm::sys::path::append(LibProfile,
- Twine(Lib) + getArchNameForCompilerRTLib(TC) + ".a");
-
- CmdArgs.push_back(Args.MakeArgString(LibProfile));
+ CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, "profile")));
}
-static SmallString<128> getSanitizerRTLibName(const ToolChain &TC,
- const StringRef Sanitizer,
- bool Shared) {
- // Sanitizer runtime has name "libclang_rt.<Sanitizer>-<ArchName>.{a,so}"
- // (or "libclang_rt.<Sanitizer>-<ArchName>-android.so for Android)
- const char *EnvSuffix =
- TC.getTriple().getEnvironment() == llvm::Triple::Android ? "-android" : "";
- SmallString<128> LibSanitizer = getCompilerRTLibDir(TC);
- llvm::sys::path::append(LibSanitizer,
- Twine("libclang_rt.") + Sanitizer + "-" +
- getArchNameForCompilerRTLib(TC) + EnvSuffix +
- (Shared ? ".so" : ".a"));
- return LibSanitizer;
+static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs, StringRef Sanitizer,
+ bool IsShared) {
+ const char *Env = TC.getTriple().getEnvironment() == llvm::Triple::Android
+ ? "-android"
+ : "";
+
+ // Static runtimes must be forced into executable, so we wrap them in
+ // whole-archive.
+ if (!IsShared)
+ CmdArgs.push_back("-whole-archive");
+ CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, Sanitizer, IsShared,
+ Env)));
+ if (!IsShared)
+ CmdArgs.push_back("-no-whole-archive");
}
-static void addSanitizerRTLinkFlags(const ToolChain &TC, const ArgList &Args,
+// Tries to use a file with the list of dynamic symbols that need to be exported
+// from the runtime library. Returns true if the file was found.
+static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs,
- const StringRef Sanitizer,
- bool BeforeLibStdCXX,
- bool ExportSymbols = true,
- bool LinkDeps = true) {
- SmallString<128> LibSanitizer =
- getSanitizerRTLibName(TC, Sanitizer, /*Shared*/ false);
-
- // Sanitizer runtime may need to come before -lstdc++ (or -lc++, libstdc++.a,
- // etc.) so that the linker picks custom versions of the global 'operator
- // new' and 'operator delete' symbols. We take the extreme (but simple)
- // strategy of inserting it at the front of the link command. It also
- // needs to be forced to end up in the executable, so wrap it in
- // whole-archive.
- SmallVector<const char *, 3> LibSanitizerArgs;
- LibSanitizerArgs.push_back("-whole-archive");
- LibSanitizerArgs.push_back(Args.MakeArgString(LibSanitizer));
- LibSanitizerArgs.push_back("-no-whole-archive");
-
- CmdArgs.insert(BeforeLibStdCXX ? CmdArgs.begin() : CmdArgs.end(),
- LibSanitizerArgs.begin(), LibSanitizerArgs.end());
-
- if (LinkDeps) {
- // Link sanitizer dependencies explicitly
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-lrt");
- CmdArgs.push_back("-lm");
- // There's no libdl on FreeBSD.
- if (TC.getTriple().getOS() != llvm::Triple::FreeBSD)
- CmdArgs.push_back("-ldl");
+ StringRef Sanitizer) {
+ SmallString<128> SanRT = getCompilerRT(TC, Sanitizer);
+ if (llvm::sys::fs::exists(SanRT + ".syms")) {
+ CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms"));
+ return true;
}
+ return false;
+}
- // If possible, use a dynamic symbols file to export the symbols from the
- // runtime library. If we can't do so, use -export-dynamic instead to export
- // all symbols from the binary.
- if (ExportSymbols) {
- if (llvm::sys::fs::exists(LibSanitizer + ".syms"))
- CmdArgs.push_back(
- Args.MakeArgString("--dynamic-list=" + LibSanitizer + ".syms"));
- else
- CmdArgs.push_back("-export-dynamic");
- }
+static void linkSanitizerRuntimeDeps(const ToolChain &TC,
+ ArgStringList &CmdArgs) {
+ // Force linking against the system libraries sanitizers depends on
+ // (see PR15823 why this is necessary).
+ CmdArgs.push_back("--no-as-needed");
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-lrt");
+ CmdArgs.push_back("-lm");
+ // There's no libdl on FreeBSD.
+ if (TC.getTriple().getOS() != llvm::Triple::FreeBSD)
+ CmdArgs.push_back("-ldl");
}
-/// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
-/// This needs to be called before we add the C run-time (malloc, etc).
-static void addAsanRT(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs, bool Shared, bool IsCXX) {
- if (Shared) {
- // Link dynamic runtime if necessary.
- SmallString<128> LibSanitizer =
- getSanitizerRTLibName(TC, "asan", Shared);
- CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibSanitizer));
+static void
+collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
+ SmallVectorImpl<StringRef> &SharedRuntimes,
+ SmallVectorImpl<StringRef> &StaticRuntimes,
+ SmallVectorImpl<StringRef> &HelperStaticRuntimes) {
+ const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
+ // Collect shared runtimes.
+ if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) {
+ SharedRuntimes.push_back("asan");
}
- // Do not link static runtime to DSOs or if compiling for Android.
+ // Collect static runtimes.
if (Args.hasArg(options::OPT_shared) ||
- (TC.getTriple().getEnvironment() == llvm::Triple::Android))
+ (TC.getTriple().getEnvironment() == llvm::Triple::Android)) {
+ // Don't link static runtimes into DSOs or if compiling for Android.
return;
-
- if (Shared) {
- addSanitizerRTLinkFlags(TC, Args, CmdArgs, "asan-preinit",
- /*BeforeLibStdCXX*/ true, /*ExportSymbols*/ false,
- /*LinkDeps*/ false);
- } else {
- addSanitizerRTLinkFlags(TC, Args, CmdArgs, "asan", true);
- if (IsCXX)
- addSanitizerRTLinkFlags(TC, Args, CmdArgs, "asan_cxx", true);
}
-}
-
-/// If ThreadSanitizer is enabled, add appropriate linker flags (Linux).
-/// This needs to be called before we add the C run-time (malloc, etc).
-static void addTsanRT(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if (!Args.hasArg(options::OPT_shared))
- addSanitizerRTLinkFlags(TC, Args, CmdArgs, "tsan", true);
-}
-
-/// If MemorySanitizer is enabled, add appropriate linker flags (Linux).
-/// This needs to be called before we add the C run-time (malloc, etc).
-static void addMsanRT(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if (!Args.hasArg(options::OPT_shared))
- addSanitizerRTLinkFlags(TC, Args, CmdArgs, "msan", true);
-}
-
-/// If LeakSanitizer is enabled, add appropriate linker flags (Linux).
-/// This needs to be called before we add the C run-time (malloc, etc).
-static void addLsanRT(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if (!Args.hasArg(options::OPT_shared))
- addSanitizerRTLinkFlags(TC, Args, CmdArgs, "lsan", true);
-}
-
-/// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags
-/// (Linux).
-static void addUbsanRT(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs, bool IsCXX,
- bool HasOtherSanitizerRt) {
- // Do not link runtime into shared libraries.
- if (Args.hasArg(options::OPT_shared))
- return;
-
- // Need a copy of sanitizer_common. This could come from another sanitizer
- // runtime; if we're not including one, include our own copy.
- if (!HasOtherSanitizerRt)
- addSanitizerRTLinkFlags(TC, Args, CmdArgs, "san", true, false);
-
- addSanitizerRTLinkFlags(TC, Args, CmdArgs, "ubsan", false, true);
-
- // Only include the bits of the runtime which need a C++ ABI library if
- // we're linking in C++ mode.
- if (IsCXX)
- addSanitizerRTLinkFlags(TC, Args, CmdArgs, "ubsan_cxx", false, true);
-}
-
-static void addDfsanRT(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if (!Args.hasArg(options::OPT_shared))
- addSanitizerRTLinkFlags(TC, Args, CmdArgs, "dfsan", true);
-}
-
-// Should be called before we add C++ ABI library.
-static void addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
+ if (SanArgs.needsAsanRt()) {
+ if (SanArgs.needsSharedAsanRt()) {
+ HelperStaticRuntimes.push_back("asan-preinit");
+ } else {
+ StaticRuntimes.push_back("asan");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("asan_cxx");
+ }
+ }
+ if (SanArgs.needsDfsanRt())
+ StaticRuntimes.push_back("dfsan");
+ if (SanArgs.needsLsanRt())
+ StaticRuntimes.push_back("lsan");
+ if (SanArgs.needsMsanRt())
+ StaticRuntimes.push_back("msan");
+ if (SanArgs.needsTsanRt())
+ StaticRuntimes.push_back("tsan");
+ // WARNING: UBSan should always go last.
+ if (SanArgs.needsUbsanRt()) {
+ // If UBSan is not combined with another sanitizer, we need to pull in
+ // sanitizer_common explicitly.
+ if (StaticRuntimes.empty())
+ HelperStaticRuntimes.push_back("san");
+ StaticRuntimes.push_back("ubsan");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("ubsan_cxx");
+ }
+}
+
+// Should be called before we add system libraries (C++ ABI, libstdc++/libc++,
+// C runtime, etc). Returns true if sanitizer system deps need to be linked in.
+static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
- const SanitizerArgs &Sanitize = TC.getSanitizerArgs();
- const Driver &D = TC.getDriver();
- if (Sanitize.needsUbsanRt())
- addUbsanRT(TC, Args, CmdArgs, D.CCCIsCXX(),
- Sanitize.needsAsanRt() || Sanitize.needsTsanRt() ||
- Sanitize.needsMsanRt() || Sanitize.needsLsanRt());
- if (Sanitize.needsAsanRt())
- addAsanRT(TC, Args, CmdArgs, Sanitize.needsSharedAsanRt(), D.CCCIsCXX());
- if (Sanitize.needsTsanRt())
- addTsanRT(TC, Args, CmdArgs);
- if (Sanitize.needsMsanRt())
- addMsanRT(TC, Args, CmdArgs);
- if (Sanitize.needsLsanRt())
- addLsanRT(TC, Args, CmdArgs);
- if (Sanitize.needsDfsanRt())
- addDfsanRT(TC, Args, CmdArgs);
+ SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes,
+ HelperStaticRuntimes;
+ collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
+ HelperStaticRuntimes);
+ for (auto RT : SharedRuntimes)
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, true);
+ for (auto RT : HelperStaticRuntimes)
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, false);
+ bool AddExportDynamic = false;
+ for (auto RT : StaticRuntimes) {
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, false);
+ AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
+ }
+ // If there is a static runtime with no dynamic list, force all the symbols
+ // to be dynamic to be sure we export sanitizer interface functions.
+ if (AddExportDynamic)
+ CmdArgs.push_back("-export-dynamic");
+ return !StaticRuntimes.empty();
}
static bool shouldUseFramePointerForTarget(const ArgList &Args,
@@ -2332,10 +2372,10 @@ static void SplitDebugInfo(const ToolChain &TC, Compilation &C,
Args.MakeArgString(TC.GetProgramPath("objcopy"));
// First extract the dwo sections.
- C.addCommand(new Command(JA, T, Exec, ExtractArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, T, Exec, ExtractArgs));
// Then remove them from the original .o file.
- C.addCommand(new Command(JA, T, Exec, StripArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, T, Exec, StripArgs));
}
/// \brief Vectorize at all optimization levels greater than 1 except for -Oz.
@@ -2405,6 +2445,16 @@ static std::string getMSCompatibilityVersion(const char *VersionStr) {
llvm::utostr_32(Build);
}
+// Claim options we don't want to warn if they are unused. We do this for
+// options that build systems might add but are unused when assembling or only
+// running the preprocessor for example.
+static void claimNoWarnArgs(const ArgList &Args) {
+ // Don't warn about unused -f(no-)?lto. This can happen when we're
+ // preprocessing, precompiling or assembling.
+ Args.ClaimAllArgs(options::OPT_flto);
+ Args.ClaimAllArgs(options::OPT_fno_lto);
+}
+
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -2485,7 +2535,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (isa<VerifyPCHJobAction>(JA)) {
CmdArgs.push_back("-verify-pch");
} else {
- assert(isa<CompileJobAction>(JA) && "Invalid action for clang tool.");
+ assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
+ "Invalid action for clang tool.");
if (JA.getType() == types::TY_Nothing) {
CmdArgs.push_back("-fsyntax-only");
@@ -2599,7 +2650,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
case llvm::Triple::aarch64:
- case llvm::Triple::arm64:
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
@@ -2679,9 +2729,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Note that these flags are trump-cards. Regardless of the order w.r.t. the
// PIC or PIE options above, if these show up, PIC is disabled.
llvm::Triple Triple(TripleStr);
- if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6) ||
- Triple.getArch() == llvm::Triple::arm64 ||
- Triple.getArch() == llvm::Triple::aarch64))
+ if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)))
PIC = PIE = false;
if (Args.hasArg(options::OPT_static))
PIC = PIE = false;
@@ -2721,12 +2769,31 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ CmdArgs.push_back("-mthread-model");
+ if (Arg *A = Args.getLastArg(options::OPT_mthread_model))
+ CmdArgs.push_back(A->getValue());
+ else
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().getThreadModel()));
+
if (!Args.hasFlag(options::OPT_fmerge_all_constants,
options::OPT_fno_merge_all_constants))
CmdArgs.push_back("-fno-merge-all-constants");
// LLVM Code Generator Options.
+ if (Args.hasArg(options::OPT_frewrite_map_file) ||
+ Args.hasArg(options::OPT_frewrite_map_file_EQ)) {
+ for (arg_iterator
+ MFI = Args.filtered_begin(options::OPT_frewrite_map_file,
+ options::OPT_frewrite_map_file_EQ),
+ MFE = Args.filtered_end();
+ MFI != MFE; ++MFI) {
+ CmdArgs.push_back("-frewrite-map-file");
+ CmdArgs.push_back((*MFI)->getValue());
+ (*MFI)->claim();
+ }
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) {
StringRef v = A->getValue();
CmdArgs.push_back("-mllvm");
@@ -3017,8 +3084,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
- case llvm::Triple::arm64:
- case llvm::Triple::arm64_be:
AddAArch64TargetArgs(Args, CmdArgs);
break;
@@ -3029,6 +3094,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
AddMIPSTargetArgs(Args, CmdArgs);
break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ AddPPCTargetArgs(Args, CmdArgs);
+ break;
+
case llvm::Triple::sparc:
case llvm::Triple::sparcv9:
AddSparcTargetArgs(Args, CmdArgs);
@@ -3092,14 +3163,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// are preserved, all other debug options are substituted with "-g".
Args.ClaimAllArgs(options::OPT_g_Group);
if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
- if (A->getOption().matches(options::OPT_gline_tables_only)) {
+ if (A->getOption().matches(options::OPT_gline_tables_only) ||
+ A->getOption().matches(options::OPT_g1)) {
// FIXME: we should support specifying dwarf version with
// -gline-tables-only.
CmdArgs.push_back("-gline-tables-only");
- // Default is dwarf-2 for Darwin, OpenBSD and FreeBSD.
+ // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris.
const llvm::Triple &Triple = getToolChain().getTriple();
if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD ||
- Triple.getOS() == llvm::Triple::FreeBSD)
+ Triple.getOS() == llvm::Triple::FreeBSD ||
+ Triple.getOS() == llvm::Triple::Solaris)
CmdArgs.push_back("-gdwarf-2");
} else if (A->getOption().matches(options::OPT_gdwarf_2))
CmdArgs.push_back("-gdwarf-2");
@@ -3109,10 +3182,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-gdwarf-4");
else if (!A->getOption().matches(options::OPT_g0) &&
!A->getOption().matches(options::OPT_ggdb0)) {
- // Default is dwarf-2 for Darwin, OpenBSD and FreeBSD.
+ // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris.
const llvm::Triple &Triple = getToolChain().getTriple();
if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD ||
- Triple.getOS() == llvm::Triple::FreeBSD)
+ Triple.getOS() == llvm::Triple::FreeBSD ||
+ Triple.getOS() == llvm::Triple::Solaris)
CmdArgs.push_back("-gdwarf-2");
else
CmdArgs.push_back("-g");
@@ -3183,15 +3257,29 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_ftest_coverage) ||
Args.hasArg(options::OPT_coverage))
CmdArgs.push_back("-femit-coverage-notes");
- if (Args.hasArg(options::OPT_fprofile_arcs) ||
+ if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
+ false) ||
Args.hasArg(options::OPT_coverage))
CmdArgs.push_back("-femit-coverage-data");
+ if (Args.hasArg(options::OPT_fcoverage_mapping) &&
+ !Args.hasArg(options::OPT_fprofile_instr_generate))
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << "-fcoverage-mapping" << "-fprofile-instr-generate";
+
+ if (Args.hasArg(options::OPT_fcoverage_mapping))
+ CmdArgs.push_back("-fcoverage-mapping");
+
if (C.getArgs().hasArg(options::OPT_c) ||
C.getArgs().hasArg(options::OPT_S)) {
if (Output.isFilename()) {
CmdArgs.push_back("-coverage-file");
- SmallString<128> CoverageFilename(Output.getFilename());
+ SmallString<128> CoverageFilename;
+ if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) {
+ CoverageFilename = FinalOutput->getValue();
+ } else {
+ CoverageFilename = llvm::sys::path::filename(Output.getBaseInput());
+ }
if (llvm::sys::path::is_relative(CoverageFilename.str())) {
SmallString<128> Pwd;
if (!llvm::sys::fs::current_path(Pwd)) {
@@ -3319,9 +3407,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
D.Diag(diag::warn_ignored_gcc_optimization) << (*it)->getAsString(Args);
}
- // Don't warn about unused -flto. This can happen when we're preprocessing or
- // precompiling.
- Args.ClaimAllArgs(options::OPT_flto);
+ claimNoWarnArgs(Args);
Args.AddAllArgs(CmdArgs, options::OPT_R_Group);
Args.AddAllArgs(CmdArgs, options::OPT_W_Group);
@@ -3344,8 +3430,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else
Std->render(Args, CmdArgs);
+ // If -f(no-)trigraphs appears after the language standard flag, honor it.
if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi,
- options::OPT_trigraphs))
+ options::OPT_ftrigraphs,
+ options::OPT_fno_trigraphs))
if (A != Std)
A->render(Args, CmdArgs);
} else {
@@ -3361,7 +3449,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else if (IsWindowsMSVC)
CmdArgs.push_back("-std=c++11");
- Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
+ Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs,
+ options::OPT_fno_trigraphs);
}
// GCC's behavior for -Wwrite-strings is a bit strange:
@@ -3480,6 +3569,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
+ if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) {
+ CmdArgs.push_back("-fspell-checking-limit");
+ CmdArgs.push_back(A->getValue());
+ }
+
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
@@ -3531,15 +3625,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs();
Sanitize.addArgs(Args, CmdArgs);
- if (!Args.hasFlag(options::OPT_fsanitize_recover,
- options::OPT_fno_sanitize_recover,
- true))
- CmdArgs.push_back("-fno-sanitize-recover");
-
- if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
- options::OPT_fno_sanitize_undefined_trap_on_error, false))
- CmdArgs.push_back("-fsanitize-undefined-trap-on-error");
-
// Report an error for -faltivec on anything other than PowerPC.
if (const Arg *A = Args.getLastArg(options::OPT_faltivec))
if (!(getToolChain().getArch() == llvm::Triple::ppc ||
@@ -3647,31 +3732,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
}
- // -mkernel implies -mstrict-align; don't add the redundant option.
- if (!KernelOrKext) {
- if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
- options::OPT_munaligned_access)) {
- if (A->getOption().matches(options::OPT_mno_unaligned_access)) {
- CmdArgs.push_back("-backend-option");
- if (getToolChain().getTriple().getArch() == llvm::Triple::aarch64 ||
- getToolChain().getTriple().getArch() == llvm::Triple::aarch64_be ||
- getToolChain().getTriple().getArch() == llvm::Triple::arm64 ||
- getToolChain().getTriple().getArch() == llvm::Triple::arm64_be)
- CmdArgs.push_back("-aarch64-strict-align");
- else
- CmdArgs.push_back("-arm-strict-align");
- } else {
- CmdArgs.push_back("-backend-option");
- if (getToolChain().getTriple().getArch() == llvm::Triple::aarch64 ||
- getToolChain().getTriple().getArch() == llvm::Triple::aarch64_be ||
- getToolChain().getTriple().getArch() == llvm::Triple::arm64 ||
- getToolChain().getTriple().getArch() == llvm::Triple::arm64_be)
- CmdArgs.push_back("-aarch64-no-strict-align");
- else
- CmdArgs.push_back("-arm-no-strict-align");
- }
- }
- }
+
+ if (getToolChain().getTriple().getArch() == llvm::Triple::aarch64 ||
+ getToolChain().getTriple().getArch() == llvm::Triple::aarch64_be)
+ CmdArgs.push_back("-fallow-half-arguments-and-returns");
if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
options::OPT_mno_restrict_it)) {
@@ -3738,14 +3802,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks-runtime-optional");
}
- // -fmodules enables modules (off by default). However, for C++/Objective-C++,
- // users must also pass -fcxx-modules. The latter flag will disappear once the
- // modules implementation is solid for C++/Objective-C++ programs as well.
+ // -fmodules enables modules (off by default).
+ // Users can pass -fno-cxx-modules to turn off modules support for
+ // C++/Objective-C++ programs, which is a little less mature.
bool HaveModules = false;
if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
options::OPT_fno_cxx_modules,
- false);
+ true);
if (AllowedInCXX || !types::isCXX(InputType)) {
CmdArgs.push_back("-fmodules");
HaveModules = true;
@@ -3777,15 +3841,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fmodule-name specifies the module that is currently being built (or
// used for header checking by -fmodule-maps).
- if (Arg *A = Args.getLastArg(options::OPT_fmodule_name))
- A->render(Args, CmdArgs);
+ Args.AddLastArg(CmdArgs, options::OPT_fmodule_name);
- // -fmodule-map-file can be used to specify a file containing module
+ // -fmodule-map-file can be used to specify files containing module
// definitions.
- if (Arg *A = Args.getLastArg(options::OPT_fmodule_map_file))
- A->render(Args, CmdArgs);
+ Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file);
+
+ // -fmodule-file can be used to specify files containing precompiled modules.
+ Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file);
- // -fmodule-cache-path specifies where our module files should be written.
+ // -fmodule-cache-path specifies where our implicitly-built module files
+ // should be written.
SmallString<128> ModuleCachePath;
if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path))
ModuleCachePath = A->getValue();
@@ -3813,14 +3879,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (HaveModules && C.isForDiagnostics()) {
SmallString<128> VFSDir(Output.getFilename());
llvm::sys::path::replace_extension(VFSDir, ".cache");
+ // Add the cache directory as a temp so the crash diagnostics pick it up.
+ C.addTempFile(Args.MakeArgString(VFSDir));
+
llvm::sys::path::append(VFSDir, "vfs");
CmdArgs.push_back("-module-dependency-dir");
CmdArgs.push_back(Args.MakeArgString(VFSDir));
}
- if (Arg *A = Args.getLastArg(options::OPT_fmodules_user_build_path))
- if (HaveModules)
- A->render(Args, CmdArgs);
+ if (HaveModules)
+ Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path);
// Pass through all -fmodules-ignore-macro arguments.
Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro);
@@ -3829,8 +3897,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
+ if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) {
+ if (Args.hasArg(options::OPT_fbuild_session_timestamp))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "-fbuild-session-timestamp";
+
+ llvm::sys::fs::file_status Status;
+ if (llvm::sys::fs::status(A->getValue(), Status))
+ D.Diag(diag::err_drv_no_such_file) << A->getValue();
+ char TimeStamp[48];
+ snprintf(TimeStamp, sizeof(TimeStamp), "-fbuild-session-timestamp=%" PRIu64,
+ (uint64_t)Status.getLastModificationTime().toEpochTime());
+ CmdArgs.push_back(Args.MakeArgString(TimeStamp));
+ }
+
if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) {
- if (!Args.getLastArg(options::OPT_fbuild_session_timestamp))
+ if (!Args.getLastArg(options::OPT_fbuild_session_timestamp,
+ options::OPT_fbuild_session_file))
D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
Args.AddLastArg(CmdArgs,
@@ -4085,6 +4168,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fpack-struct=1");
}
+ // Handle -fmax-type-align=N and -fno-type-align
+ bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align);
+ if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) {
+ if (!SkipMaxTypeAlign) {
+ std::string MaxTypeAlignStr = "-fmax-type-align=";
+ MaxTypeAlignStr += A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
+ }
+ } else if (getToolChain().getTriple().isOSDarwin()) {
+ if (!SkipMaxTypeAlign) {
+ std::string MaxTypeAlignStr = "-fmax-type-align=16";
+ CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
+ }
+ }
+
if (KernelOrKext || isNoCommonDefault(getToolChain().getTriple())) {
if (!Args.hasArg(options::OPT_fcommon))
CmdArgs.push_back("-fno-common");
@@ -4116,6 +4214,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args) << value;
}
+ // -fexec_charset=UTF-8 is default. Reject others
+ if (Arg *execCharset = Args.getLastArg(
+ options::OPT_fexec_charset_EQ)) {
+ StringRef value = execCharset->getValue();
+ if (value != "UTF-8")
+ D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args) << value;
+ }
+
// -fcaret-diagnostics is default.
if (!Args.hasFlag(options::OPT_fcaret_diagnostics,
options::OPT_fno_caret_diagnostics, true))
@@ -4321,18 +4427,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
+ bool OptDisabled = false;
for (arg_iterator it = Args.filtered_begin(options::OPT_mllvm),
ie = Args.filtered_end(); it != ie; ++it) {
(*it)->claim();
// We translate this by hand to the -cc1 argument, since nightly test uses
// it and developers have been trained to spell it with -mllvm.
- if (StringRef((*it)->getValue(0)) == "-disable-llvm-optzns")
+ if (StringRef((*it)->getValue(0)) == "-disable-llvm-optzns") {
CmdArgs.push_back("-disable-llvm-optzns");
- else
+ OptDisabled = true;
+ } else
(*it)->render(Args, CmdArgs);
}
+ // With -save-temps, we want to save the unoptimized bitcode output from the
+ // CompileJobAction, so disable optimizations if they are not already
+ // disabled.
+ if (Args.hasArg(options::OPT_save_temps) && !OptDisabled &&
+ isa<CompileJobAction>(JA))
+ CmdArgs.push_back("-disable-llvm-optzns");
+
if (Output.getType() == types::TY_Dependencies) {
// Handled with other dependency code.
} else if (Output.isFilename()) {
@@ -4365,8 +4480,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
SmallString<256> Flags;
Flags += Exec;
for (unsigned i = 0, e = OriginalArgs.size(); i != e; ++i) {
+ SmallString<128> EscapedArg;
+ EscapeSpacesAndBackslashes(OriginalArgs[i], EscapedArg);
Flags += " ";
- Flags += OriginalArgs[i];
+ Flags += EscapedArg;
}
CmdArgs.push_back("-dwarf-debug-flags");
CmdArgs.push_back(Args.MakeArgString(Flags.str()));
@@ -4376,7 +4493,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// can propagate it to the backend.
bool SplitDwarf = Args.hasArg(options::OPT_gsplit_dwarf) &&
getToolChain().getTriple().isOSLinux() &&
- (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA));
+ (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) ||
+ isa<BackendJobAction>(JA));
const char *SplitDwarfOut;
if (SplitDwarf) {
CmdArgs.push_back("-split-dwarf-file");
@@ -4388,18 +4506,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT__SLASH_fallback) &&
Output.getType() == types::TY_Object &&
(InputType == types::TY_C || InputType == types::TY_CXX)) {
- Command *CLCommand = getCLFallback()->GetCommand(C, JA, Output, Inputs,
- Args, LinkingOutput);
- C.addCommand(new FallbackCommand(JA, *this, Exec, CmdArgs, CLCommand));
+ auto CLCommand =
+ getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput);
+ C.addCommand(llvm::make_unique<FallbackCommand>(JA, *this, Exec, CmdArgs,
+ std::move(CLCommand)));
} else {
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
// Handle the debug info splitting at object creation time if we're
// creating an object.
// TODO: Currently only works on linux with newer objcopy.
- if (SplitDwarf && !isa<CompileJobAction>(JA))
+ if (SplitDwarf && !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA))
SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDwarfOut);
if (Arg *A = Args.getLastArg(options::OPT_pg))
@@ -4716,6 +4835,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// and "clang -emit-llvm -c foo.s"
Args.ClaimAllArgs(options::OPT_emit_llvm);
+ claimNoWarnArgs(Args);
+
// Invoke ourselves in -cc1as mode.
//
// FIXME: Implement custom jobs for internal actions.
@@ -4795,8 +4916,10 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec = getToolChain().getDriver().getClangProgramPath();
Flags += Exec;
for (unsigned i = 0, e = OriginalArgs.size(); i != e; ++i) {
+ SmallString<128> EscapedArg;
+ EscapeSpacesAndBackslashes(OriginalArgs[i], EscapedArg);
Flags += " ";
- Flags += OriginalArgs[i];
+ Flags += EscapedArg;
}
CmdArgs.push_back("-dwarf-debug-flags");
CmdArgs.push_back(Args.MakeArgString(Flags.str()));
@@ -4827,7 +4950,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Input.getFilename());
const char *Exec = getToolChain().getDriver().getClangProgramPath();
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
// Handle the debug info splitting at object creation time if we're
// creating an object.
@@ -4838,6 +4961,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
SplitDebugName(Args, Inputs));
}
+void GnuTool::anchor() {}
+
void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -4870,19 +4995,10 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
RenderExtraToolArgs(JA, CmdArgs);
// If using a driver driver, force the arch.
- llvm::Triple::ArchType Arch = getToolChain().getArch();
if (getToolChain().getTriple().isOSDarwin()) {
CmdArgs.push_back("-arch");
-
- // FIXME: Remove these special cases.
- if (Arch == llvm::Triple::ppc)
- CmdArgs.push_back("ppc");
- else if (Arch == llvm::Triple::ppc64)
- CmdArgs.push_back("ppc64");
- else if (Arch == llvm::Triple::ppc64le)
- CmdArgs.push_back("ppc64le");
- else
- CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName()));
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().getDefaultUniversalArchName()));
}
// Try to force gcc to match the tool chain we want, if we recognize
@@ -4890,6 +5006,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
//
// FIXME: The triple class should directly provide the information we want
// here.
+ llvm::Triple::ArchType Arch = getToolChain().getArch();
if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc)
CmdArgs.push_back("-m32");
else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64 ||
@@ -4960,7 +5077,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void gcc::Preprocess::RenderExtraToolArgs(const JobAction &JA,
@@ -5000,6 +5117,7 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
@@ -5056,7 +5174,7 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *GCCName = "hexagon-as";
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void hexagon::Link::RenderExtraToolArgs(const JobAction &JA,
@@ -5133,8 +5251,8 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
const std::string MarchSuffix = "/" + MarchString;
const std::string G0Suffix = "/G0";
const std::string MarchG0Suffix = MarchSuffix + G0Suffix;
- const std::string RootDir = toolchains::Hexagon_TC::GetGnuDir(D.InstalledDir)
- + "/";
+ const std::string RootDir =
+ toolchains::Hexagon_TC::GetGnuDir(D.InstalledDir, Args) + "/";
const std::string StartFilesDir = RootDir
+ "hexagon/lib"
+ (buildingLib
@@ -5222,7 +5340,8 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
std::string Linker = ToolChain.GetProgramPath("hexagon-ld");
- C.addCommand(new Command(JA, *this, Args.MakeArgString(Linker), CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
+ CmdArgs));
}
// Hexagon tools end.
@@ -5287,12 +5406,12 @@ const char *arm::getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a5", "cortex-a7", "cortex-a8", "cortex-a9-mp", "v7")
- .Cases("cortex-a9", "cortex-a12", "cortex-a15", "krait", "v7")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait", "v7")
.Cases("cortex-r4", "cortex-r5", "v7r")
.Case("cortex-m0", "v6m")
.Case("cortex-m3", "v7m")
- .Case("cortex-m4", "v7em")
+ .Cases("cortex-m4", "cortex-m7", "v7em")
.Case("swift", "v7s")
.Case("cyclone", "v8")
.Cases("cortex-a53", "cortex-a57", "v8")
@@ -5304,6 +5423,11 @@ bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) {
return A && (A->getValue() == StringRef(Value));
}
+bool mips::isUCLibc(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_m_libc_Group);
+ return A && A->getOption().matches(options::OPT_muclibc);
+}
+
bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) {
if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ))
return llvm::StringSwitch<bool>(NaNArg->getValue())
@@ -5360,8 +5484,9 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
.Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm)
.Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm)
.Cases("armv7s", "xscale", llvm::Triple::arm)
- .Case("arm64", llvm::Triple::arm64)
+ .Case("arm64", llvm::Triple::aarch64)
.Case("r600", llvm::Triple::r600)
+ .Case("amdgcn", llvm::Triple::amdgcn)
.Case("nvptx", llvm::Triple::nvptx)
.Case("nvptx64", llvm::Triple::nvptx64)
.Case("amdil", llvm::Triple::amdil)
@@ -5478,7 +5603,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void darwin::MachOTool::anchor() {}
@@ -5694,6 +5819,12 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
assert(Output.getType() == types::TY_Image && "Invalid linker output type.");
+ // If the number of arguments surpasses the system limits, we will encode the
+ // input files in a separate file, shortening the command line. To this end,
+ // build a list of input file names that can be passed via a file with the
+ // -filelist linker option.
+ llvm::opt::ArgStringList InputFileList;
+
// The logic here is derived from gcc's behavior; most of which
// comes from specs (starting with link_command). Consult gcc for
// more information.
@@ -5707,7 +5838,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("touch"));
CmdArgs.push_back(Output.getFilename());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
return;
}
@@ -5762,7 +5893,23 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
-
+ // Build the input file for -filelist (list of linker input files) in case we
+ // need it later
+ for (const auto &II : Inputs) {
+ if (!II.isFilename()) {
+ // This is a linker input argument.
+ // We cannot mix input arguments and file names in a -filelist input, thus
+ // we prematurely stop our list (remaining files shall be passed as
+ // arguments).
+ if (InputFileList.size() > 0)
+ break;
+
+ continue;
+ }
+
+ InputFileList.push_back(II.getFilename());
+ }
+
if (isObjCRuntimeLinked(Args) &&
!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
@@ -5805,7 +5952,10 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ std::unique_ptr<Command> Cmd =
+ llvm::make_unique<Command>(JA, *this, Exec, CmdArgs);
+ Cmd->setInputFileList(std::move(InputFileList));
+ C.addCommand(std::move(Cmd));
}
void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
@@ -5827,7 +5977,7 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
@@ -5847,7 +5997,7 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("dsymutil"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
@@ -5870,7 +6020,7 @@ void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void solaris::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -5878,6 +6028,7 @@ void solaris::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
ArgStringList CmdArgs;
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -5890,7 +6041,7 @@ void solaris::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -5995,115 +6146,7 @@ void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
-}
-
-void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
- options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("gas"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
-}
-
-void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- if ((!Args.hasArg(options::OPT_nostdlib)) &&
- (!Args.hasArg(options::OPT_shared))) {
- CmdArgs.push_back("-e");
- CmdArgs.push_back("_start");
- }
-
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-Bstatic");
- CmdArgs.push_back("-dn");
- } else {
-// CmdArgs.push_back("--eh-frame-hdr");
- CmdArgs.push_back("-Bdynamic");
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-shared");
- } else {
- CmdArgs.push_back("--dynamic-linker");
- CmdArgs.push_back("/lib/ld.so.1"); // 64Bit Path /lib/amd64/ld.so.1
- }
- }
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crt1.o")));
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crti.o")));
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crtbegin.o")));
- } else {
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crti.o")));
- }
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crtn.o")));
- }
-
- CmdArgs.push_back(Args.MakeArgString("-L/opt/gcc4/lib/gcc/"
- + getToolChain().getTripleString()
- + "/4.2.4"));
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_e);
-
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
-
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
- // FIXME: For some reason GCC passes -lgcc before adding
- // the default system libraries. Just mimic this for now.
- CmdArgs.push_back("-lgcc");
-
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-pthread");
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lgcc");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crtend.o")));
- }
-
- addProfileRT(getToolChain(), Args, CmdArgs);
-
- const char *Exec =
- Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6111,6 +6154,7 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
ArgStringList CmdArgs;
bool NeedsKPIC = false;
@@ -6173,7 +6217,7 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6305,7 +6349,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void bitrig::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6313,6 +6357,7 @@ void bitrig::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
ArgStringList CmdArgs;
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -6325,7 +6370,7 @@ void bitrig::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6441,7 +6486,7 @@ void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6449,6 +6494,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
ArgStringList CmdArgs;
// When building 32-bit code on FreeBSD/amd64, we have to explicitly
@@ -6522,7 +6568,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6621,7 +6667,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
- const ToolChain::path_list Paths = ToolChain.getFilePaths();
+ const ToolChain::path_list &Paths = ToolChain.getFilePaths();
for (const auto &Path : Paths)
CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
@@ -6634,6 +6680,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (D.IsUsingLTO(Args))
AddGoldPlugin(ToolChain, Args, CmdArgs);
+ bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
if (!Args.hasArg(options::OPT_nostdlib) &&
@@ -6645,6 +6692,8 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("-lm");
}
+ if (NeedsSanitizerDeps)
+ linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
// FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
// the default system libraries. Just mimic this for now.
if (Args.hasArg(options::OPT_pg))
@@ -6699,13 +6748,11 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
- addSanitizerRuntimes(getToolChain(), Args, CmdArgs);
-
addProfileRT(ToolChain, Args, CmdArgs);
const char *Exec =
Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6713,6 +6760,7 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
ArgStringList CmdArgs;
// GNU as needs different flags for creating the correct output format
@@ -6779,7 +6827,7 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as")));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6815,9 +6863,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("elf_i386");
break;
case llvm::Triple::arm:
- case llvm::Triple::armeb:
case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
CmdArgs.push_back("-m");
switch (getToolChain().getTriple().getEnvironment()) {
case llvm::Triple::EABI:
@@ -6833,6 +6879,23 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
break;
}
break;
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ CmdArgs.push_back("-m");
+ switch (getToolChain().getTriple().getEnvironment()) {
+ case llvm::Triple::EABI:
+ case llvm::Triple::GNUEABI:
+ CmdArgs.push_back("armelfb_nbsd_eabi");
+ break;
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABIHF:
+ CmdArgs.push_back("armelfb_nbsd_eabihf");
+ break;
+ default:
+ CmdArgs.push_back("armelfb_nbsd");
+ break;
+ }
+ break;
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
if (mips::hasMipsAbiArg(Args, "32")) {
@@ -6849,6 +6912,16 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("elf64ltsmip");
}
break;
+ case llvm::Triple::ppc:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf32ppc_nbsd");
+ break;
+
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf64ppc");
+ break;
case llvm::Triple::sparc:
CmdArgs.push_back("-m");
@@ -6901,12 +6974,16 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
unsigned Major, Minor, Micro;
getToolChain().getTriple().getOSVersion(Major, Minor, Micro);
bool useLibgcc = true;
- if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 40) || Major == 0) {
+ if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 49) || Major == 0) {
switch(getToolChain().getArch()) {
+ case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
useLibgcc = false;
@@ -6958,7 +7035,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
addProfileRT(getToolChain(), Args, CmdArgs);
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6966,6 +7043,8 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+
ArgStringList CmdArgs;
bool NeedsKPIC = false;
@@ -7131,7 +7210,7 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
// Handle the debug info splitting at object creation time if we're
// creating an object.
@@ -7175,8 +7254,8 @@ static void AddLibgcc(const llvm::Triple &Triple, const Driver &D,
CmdArgs.push_back("-ldl");
}
-static StringRef getLinuxDynamicLinker(const ArgList &Args,
- const toolchains::Linux &ToolChain) {
+static std::string getLinuxDynamicLinker(const ArgList &Args,
+ const toolchains::Linux &ToolChain) {
if (ToolChain.getTriple().getEnvironment() == llvm::Triple::Android) {
if (ToolChain.getTriple().isArch64Bit())
return "/system/bin/linker64";
@@ -7185,11 +7264,9 @@ static StringRef getLinuxDynamicLinker(const ArgList &Args,
} else if (ToolChain.getArch() == llvm::Triple::x86 ||
ToolChain.getArch() == llvm::Triple::sparc)
return "/lib/ld-linux.so.2";
- else if (ToolChain.getArch() == llvm::Triple::aarch64 ||
- ToolChain.getArch() == llvm::Triple::arm64)
+ else if (ToolChain.getArch() == llvm::Triple::aarch64)
return "/lib/ld-linux-aarch64.so.1";
- else if (ToolChain.getArch() == llvm::Triple::aarch64_be ||
- ToolChain.getArch() == llvm::Triple::arm64_be)
+ else if (ToolChain.getArch() == llvm::Triple::aarch64_be)
return "/lib/ld-linux-aarch64_be.so.1";
else if (ToolChain.getArch() == llvm::Triple::arm ||
ToolChain.getArch() == llvm::Triple::thumb) {
@@ -7204,24 +7281,38 @@ static StringRef getLinuxDynamicLinker(const ArgList &Args,
else
return "/lib/ld-linux.so.3"; /* TODO: check which dynamic linker name. */
} else if (ToolChain.getArch() == llvm::Triple::mips ||
- ToolChain.getArch() == llvm::Triple::mipsel) {
- if (mips::isNaN2008(Args, ToolChain.getTriple()))
- return "/lib/ld-linux-mipsn8.so.1";
- return "/lib/ld.so.1";
- } else if (ToolChain.getArch() == llvm::Triple::mips64 ||
+ ToolChain.getArch() == llvm::Triple::mipsel ||
+ ToolChain.getArch() == llvm::Triple::mips64 ||
ToolChain.getArch() == llvm::Triple::mips64el) {
- if (mips::hasMipsAbiArg(Args, "n32"))
- return mips::isNaN2008(Args, ToolChain.getTriple())
- ? "/lib32/ld-linux-mipsn8.so.1" : "/lib32/ld.so.1";
- return mips::isNaN2008(Args, ToolChain.getTriple())
- ? "/lib64/ld-linux-mipsn8.so.1" : "/lib64/ld.so.1";
+ StringRef CPUName;
+ StringRef ABIName;
+ mips::getMipsCPUAndABI(Args, ToolChain.getTriple(), CPUName, ABIName);
+ bool IsNaN2008 = mips::isNaN2008(Args, ToolChain.getTriple());
+
+ StringRef LibDir = llvm::StringSwitch<llvm::StringRef>(ABIName)
+ .Case("o32", "/lib")
+ .Case("n32", "/lib32")
+ .Case("n64", "/lib64")
+ .Default("/lib");
+ StringRef LibName;
+ if (mips::isUCLibc(Args))
+ LibName = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0";
+ else
+ LibName = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1";
+
+ return (LibDir + "/" + LibName).str();
} else if (ToolChain.getArch() == llvm::Triple::ppc)
return "/lib/ld.so.1";
- else if (ToolChain.getArch() == llvm::Triple::ppc64 ||
- ToolChain.getArch() == llvm::Triple::systemz)
+ else if (ToolChain.getArch() == llvm::Triple::ppc64) {
+ if (ppc::hasPPCAbiArg(Args, "elfv2"))
+ return "/lib64/ld64.so.2";
return "/lib64/ld64.so.1";
- else if (ToolChain.getArch() == llvm::Triple::ppc64le)
+ } else if (ToolChain.getArch() == llvm::Triple::ppc64le) {
+ if (ppc::hasPPCAbiArg(Args, "elfv1"))
+ return "/lib64/ld64.so.1";
return "/lib64/ld64.so.2";
+ } else if (ToolChain.getArch() == llvm::Triple::systemz)
+ return "/lib64/ld64.so.1";
else if (ToolChain.getArch() == llvm::Triple::sparcv9)
return "/lib64/ld-linux.so.2";
else if (ToolChain.getArch() == llvm::Triple::x86_64 &&
@@ -7232,13 +7323,19 @@ static StringRef getLinuxDynamicLinker(const ArgList &Args,
}
static void AddRunTimeLibs(const ToolChain &TC, const Driver &D,
- ArgStringList &CmdArgs, const ArgList &Args) {
+ ArgStringList &CmdArgs, const ArgList &Args) {
// Make use of compiler-rt if --rtlib option is used
ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(Args);
- switch(RLT) {
+ switch (RLT) {
case ToolChain::RLT_CompilerRT:
- addClangRTLinux(TC, Args, CmdArgs);
+ switch (TC.getTriple().getOS()) {
+ default: llvm_unreachable("unsupported OS");
+ case llvm::Triple::Win32:
+ case llvm::Triple::Linux:
+ addClangRT(TC, Args, CmdArgs);
+ break;
+ }
break;
case ToolChain::RLT_Libgcc:
AddLibgcc(TC.getTriple(), D, CmdArgs, Args);
@@ -7246,6 +7343,53 @@ static void AddRunTimeLibs(const ToolChain &TC, const Driver &D,
}
}
+static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
+ switch (T.getArch()) {
+ case llvm::Triple::x86:
+ return "elf_i386";
+ case llvm::Triple::aarch64:
+ return "aarch64linux";
+ case llvm::Triple::aarch64_be:
+ return "aarch64_be_linux";
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ return "armelf_linux_eabi";
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ return "armebelf_linux_eabi"; /* TODO: check which NAME. */
+ case llvm::Triple::ppc:
+ return "elf32ppclinux";
+ case llvm::Triple::ppc64:
+ return "elf64ppc";
+ case llvm::Triple::ppc64le:
+ return "elf64lppc";
+ case llvm::Triple::sparc:
+ return "elf32_sparc";
+ case llvm::Triple::sparcv9:
+ return "elf64_sparc";
+ case llvm::Triple::mips:
+ return "elf32btsmip";
+ case llvm::Triple::mipsel:
+ return "elf32ltsmip";
+ case llvm::Triple::mips64:
+ if (mips::hasMipsAbiArg(Args, "n32"))
+ return "elf32btsmipn32";
+ return "elf64btsmip";
+ case llvm::Triple::mips64el:
+ if (mips::hasMipsAbiArg(Args, "n32"))
+ return "elf32ltsmipn32";
+ return "elf64ltsmip";
+ case llvm::Triple::systemz:
+ return "elf64_s390";
+ case llvm::Triple::x86_64:
+ if (T.getEnvironment() == llvm::Triple::GNUX32)
+ return "elf32_x86_64";
+ return "elf_x86_64";
+ default:
+ llvm_unreachable("Unexpected arch");
+ }
+}
+
void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -7295,53 +7439,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
CmdArgs.push_back("-m");
- if (ToolChain.getArch() == llvm::Triple::x86)
- CmdArgs.push_back("elf_i386");
- else if (ToolChain.getArch() == llvm::Triple::aarch64 ||
- ToolChain.getArch() == llvm::Triple::arm64)
- CmdArgs.push_back("aarch64linux");
- else if (ToolChain.getArch() == llvm::Triple::aarch64_be ||
- ToolChain.getArch() == llvm::Triple::arm64_be)
- CmdArgs.push_back("aarch64_be_linux");
- else if (ToolChain.getArch() == llvm::Triple::arm
- || ToolChain.getArch() == llvm::Triple::thumb)
- CmdArgs.push_back("armelf_linux_eabi");
- else if (ToolChain.getArch() == llvm::Triple::armeb
- || ToolChain.getArch() == llvm::Triple::thumbeb)
- CmdArgs.push_back("armebelf_linux_eabi"); /* TODO: check which NAME. */
- else if (ToolChain.getArch() == llvm::Triple::ppc)
- CmdArgs.push_back("elf32ppclinux");
- else if (ToolChain.getArch() == llvm::Triple::ppc64)
- CmdArgs.push_back("elf64ppc");
- else if (ToolChain.getArch() == llvm::Triple::ppc64le)
- CmdArgs.push_back("elf64lppc");
- else if (ToolChain.getArch() == llvm::Triple::sparc)
- CmdArgs.push_back("elf32_sparc");
- else if (ToolChain.getArch() == llvm::Triple::sparcv9)
- CmdArgs.push_back("elf64_sparc");
- else if (ToolChain.getArch() == llvm::Triple::mips)
- CmdArgs.push_back("elf32btsmip");
- else if (ToolChain.getArch() == llvm::Triple::mipsel)
- CmdArgs.push_back("elf32ltsmip");
- else if (ToolChain.getArch() == llvm::Triple::mips64) {
- if (mips::hasMipsAbiArg(Args, "n32"))
- CmdArgs.push_back("elf32btsmipn32");
- else
- CmdArgs.push_back("elf64btsmip");
- }
- else if (ToolChain.getArch() == llvm::Triple::mips64el) {
- if (mips::hasMipsAbiArg(Args, "n32"))
- CmdArgs.push_back("elf32ltsmipn32");
- else
- CmdArgs.push_back("elf64ltsmip");
- }
- else if (ToolChain.getArch() == llvm::Triple::systemz)
- CmdArgs.push_back("elf64_s390");
- else if (ToolChain.getArch() == llvm::Triple::x86_64 &&
- ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUX32)
- CmdArgs.push_back("elf32_x86_64");
- else
- CmdArgs.push_back("elf_x86_64");
+ CmdArgs.push_back(getLDMOption(ToolChain.getTriple(), Args));
if (Args.hasArg(options::OPT_static)) {
if (ToolChain.getArch() == llvm::Triple::arm ||
@@ -7405,7 +7503,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_u);
- const ToolChain::path_list Paths = ToolChain.getFilePaths();
+ const ToolChain::path_list &Paths = ToolChain.getFilePaths();
for (const auto &Path : Paths)
CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
@@ -7416,9 +7514,8 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
+ bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
-
- addSanitizerRuntimes(getToolChain(), Args, CmdArgs);
// The profile runtime also needs access to system libraries.
addProfileRT(getToolChain(), Args, CmdArgs);
@@ -7440,6 +7537,9 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("--start-group");
+ if (NeedsSanitizerDeps)
+ linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
+
LibOpenMP UsedOpenMPLib = LibUnknown;
if (Args.hasArg(options::OPT_fopenmp)) {
UsedOpenMPLib = LibGOMP;
@@ -7496,7 +7596,8 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- C.addCommand(new Command(JA, *this, ToolChain.Linker.c_str(), CmdArgs));
+ C.addCommand(
+ llvm::make_unique<Command>(JA, *this, ToolChain.Linker.c_str(), CmdArgs));
}
void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -7504,6 +7605,7 @@ void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
ArgStringList CmdArgs;
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
@@ -7515,7 +7617,7 @@ void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -7569,7 +7671,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
/// DragonFly Tools
@@ -7581,6 +7683,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
ArgStringList CmdArgs;
// When building 32-bit code on DragonFly/pc64, we have to explicitly
@@ -7597,7 +7700,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -7605,12 +7708,9 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- bool UseGCC47 = false;
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
-
- if (llvm::sys::fs::exists("/usr/lib/gcc47", UseGCC47))
- UseGCC47 = false;
+ bool UseGCC47 = llvm::sys::fs::exists("/usr/lib/gcc47");
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
@@ -7747,16 +7847,27 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
addProfileRT(getToolChain(), Args, CmdArgs);
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
-}
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
+}
+
+// Try to find Exe from a Visual Studio distribution. This first tries to find
+// an installed copy of Visual Studio and, failing that, looks in the PATH,
+// making sure that whatever executable that's found is not a same-named exe
+// from clang itself to prevent clang from falling back to itself.
+static std::string FindVisualStudioExecutable(const ToolChain &TC,
+ const char *Exe,
+ const char *ClangProgramPath) {
+ const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
+ std::string visualStudioBinDir;
+ if (MSVC.getVisualStudioBinariesFolder(ClangProgramPath,
+ visualStudioBinDir)) {
+ SmallString<128> FilePath(visualStudioBinDir);
+ llvm::sys::path::append(FilePath, Exe);
+ if (llvm::sys::fs::can_execute(FilePath.c_str()))
+ return FilePath.str();
+ }
-static void addSanitizerRTWindows(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs,
- const StringRef RTName) {
- SmallString<128> LibSanitizer(getCompilerRTLibDir(TC));
- llvm::sys::path::append(LibSanitizer,
- Twine("clang_rt.") + RTName + ".lib");
- CmdArgs.push_back(Args.MakeArgString(LibSanitizer));
+ return Exe;
}
void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -7765,28 +7876,56 @@ void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA,
const ArgList &Args,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
+ const ToolChain &TC = getToolChain();
- if (Output.isFilename()) {
+ assert((Output.isFilename() || Output.isNothing()) && "invalid output");
+ if (Output.isFilename())
CmdArgs.push_back(Args.MakeArgString(std::string("-out:") +
Output.getFilename()));
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles) &&
- !C.getDriver().IsCLMode()) {
+ !Args.hasArg(options::OPT_nostartfiles) && !C.getDriver().IsCLMode())
CmdArgs.push_back("-defaultlib:libcmt");
+
+ if (!llvm::sys::Process::GetEnv("LIB")) {
+ // If the VC environment hasn't been configured (perhaps because the user
+ // did not run vcvarsall), try to build a consistent link environment. If
+ // the environment variable is set however, assume the user knows what he's
+ // doing.
+ std::string VisualStudioDir;
+ const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
+ if (MSVC.getVisualStudioInstallDir(VisualStudioDir)) {
+ SmallString<128> LibDir(VisualStudioDir);
+ llvm::sys::path::append(LibDir, "VC", "lib");
+ switch (MSVC.getArch()) {
+ case llvm::Triple::x86:
+ // x86 just puts the libraries directly in lib
+ break;
+ case llvm::Triple::x86_64:
+ llvm::sys::path::append(LibDir, "amd64");
+ break;
+ case llvm::Triple::arm:
+ llvm::sys::path::append(LibDir, "arm");
+ break;
+ default:
+ break;
+ }
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-libpath:") + LibDir.c_str()));
+ }
+
+ std::string WindowsSdkLibPath;
+ if (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
+ CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
+ WindowsSdkLibPath.c_str()));
}
CmdArgs.push_back("-nologo");
- if (Args.hasArg(options::OPT_g_Group)) {
+ if (Args.hasArg(options::OPT_g_Group))
CmdArgs.push_back("-debug");
- }
bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd);
-
if (DLL) {
CmdArgs.push_back(Args.MakeArgString("-dll"));
@@ -7796,32 +7935,81 @@ void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA,
ImplibName.str()));
}
- if (getToolChain().getSanitizerArgs().needsAsanRt()) {
+ if (TC.getSanitizerArgs().needsAsanRt()) {
CmdArgs.push_back(Args.MakeArgString("-debug"));
CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
- // FIXME: Handle 64-bit.
- if (DLL) {
- addSanitizerRTWindows(getToolChain(), Args, CmdArgs,
- "asan_dll_thunk-i386");
+ if (Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) {
+ static const char *CompilerRTComponents[] = {
+ "asan_dynamic",
+ "asan_dynamic_runtime_thunk",
+ };
+ for (const auto &Component : CompilerRTComponents)
+ CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, Component)));
+ // Make sure the dynamic runtime thunk is not optimized out at link time
+ // to ensure proper SEH handling.
+ CmdArgs.push_back(Args.MakeArgString("-include:___asan_seh_interceptor"));
+ } else if (DLL) {
+ CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, "asan_dll_thunk")));
} else {
- addSanitizerRTWindows(getToolChain(), Args, CmdArgs, "asan-i386");
- addSanitizerRTWindows(getToolChain(), Args, CmdArgs, "asan_cxx-i386");
+ static const char *CompilerRTComponents[] = {
+ "asan",
+ "asan_cxx",
+ };
+ for (const auto &Component : CompilerRTComponents)
+ CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, Component)));
}
}
- Args.AddAllArgValues(CmdArgs, options::OPT_l);
Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
- // Add filenames immediately.
- for (const auto &Input : Inputs)
- if (Input.isFilename())
+ // Add filenames, libraries, and other linker inputs.
+ for (const auto &Input : Inputs) {
+ if (Input.isFilename()) {
CmdArgs.push_back(Input.getFilename());
- else
- Input.getInputArg().renderAsInput(Args, CmdArgs);
+ continue;
+ }
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("link.exe"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ const Arg &A = Input.getInputArg();
+
+ // Render -l options differently for the MSVC linker.
+ if (A.getOption().matches(options::OPT_l)) {
+ StringRef Lib = A.getValue();
+ const char *LinkLibArg;
+ if (Lib.endswith(".lib"))
+ LinkLibArg = Args.MakeArgString(Lib);
+ else
+ LinkLibArg = Args.MakeArgString(Lib + ".lib");
+ CmdArgs.push_back(LinkLibArg);
+ continue;
+ }
+
+ // Otherwise, this is some other kind of linker input option like -Wl, -z,
+ // or -L. Render it, even if MSVC doesn't understand it.
+ A.renderAsInput(Args, CmdArgs);
+ }
+
+ // We need to special case some linker paths. In the case of lld, we need to
+ // translate 'lld' into 'lld-link', and in the case of the regular msvc
+ // linker, we need to use a special search algorithm.
+ llvm::SmallString<128> linkPath;
+ StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "link");
+ if (Linker.equals_lower("lld"))
+ Linker = "lld-link";
+
+ if (Linker.equals_lower("link")) {
+ // If we're using the MSVC linker, it's not sufficient to just use link
+ // from the program PATH, because other environments like GnuWin32 install
+ // their own link.exe which may come first.
+ linkPath = FindVisualStudioExecutable(TC, "link.exe",
+ C.getDriver().getClangProgramPath());
+ } else {
+ linkPath = Linker;
+ llvm::sys::path::replace_extension(linkPath, "exe");
+ linkPath = TC.GetProgramPath(linkPath.c_str());
+ }
+
+ const char *Exec = Args.MakeArgString(linkPath);
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void visualstudio::Compile::ConstructJob(Compilation &C, const JobAction &JA,
@@ -7832,40 +8020,10 @@ void visualstudio::Compile::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput));
}
-// Try to find FallbackName on PATH that is not identical to ClangProgramPath.
-// If one cannot be found, return FallbackName.
-// We do this special search to prevent clang-cl from falling back onto itself
-// if it's available as cl.exe on the path.
-static std::string FindFallback(const char *FallbackName,
- const char *ClangProgramPath) {
- llvm::Optional<std::string> OptPath = llvm::sys::Process::GetEnv("PATH");
- if (!OptPath.hasValue())
- return FallbackName;
-
- const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
- SmallVector<StringRef, 8> PathSegments;
- llvm::SplitString(OptPath.getValue(), PathSegments, EnvPathSeparatorStr);
-
- for (size_t i = 0, e = PathSegments.size(); i != e; ++i) {
- const StringRef &PathSegment = PathSegments[i];
- if (PathSegment.empty())
- continue;
-
- SmallString<128> FilePath(PathSegment);
- llvm::sys::path::append(FilePath, FallbackName);
- if (llvm::sys::fs::can_execute(Twine(FilePath)) &&
- !llvm::sys::fs::equivalent(Twine(FilePath), ClangProgramPath))
- return FilePath.str();
- }
-
- return FallbackName;
-}
-
-Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+std::unique_ptr<Command> visualstudio::Compile::GetCommand(
+ Compilation &C, const JobAction &JA, const InputInfo &Output,
+ const InputInfoList &Inputs, const ArgList &Args,
+ const char *LinkingOutput) const {
ArgStringList CmdArgs;
CmdArgs.push_back("/nologo");
CmdArgs.push_back("/c"); // Compile only.
@@ -7943,8 +8101,10 @@ Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Fo);
const Driver &D = getToolChain().getDriver();
- std::string Exec = FindFallback("cl.exe", D.getClangProgramPath());
- return new Command(JA, *this, Args.MakeArgString(Exec), CmdArgs);
+ std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe",
+ D.getClangProgramPath());
+ return llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
+ CmdArgs);
}
@@ -7956,6 +8116,7 @@ void XCore::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
ArgStringList CmdArgs;
CmdArgs.push_back("-o");
@@ -7981,7 +8142,7 @@ void XCore::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
void XCore::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -8001,12 +8162,189 @@ void XCore::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_v))
CmdArgs.push_back("-v");
- ExceptionSettings EH = exceptionSettings(Args, getToolChain().getTriple());
- if (EH.ShouldUseExceptionTables)
+ if (exceptionSettings(Args, getToolChain().getTriple()))
CmdArgs.push_back("-fexceptions");
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
+}
+
+void CrossWindows::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ const auto &TC =
+ static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
+ ArgStringList CmdArgs;
+ const char *Exec;
+
+ switch (TC.getArch()) {
+ default: llvm_unreachable("unsupported architecture");
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ break;
+ case llvm::Triple::x86:
+ CmdArgs.push_back("--32");
+ break;
+ case llvm::Triple::x86_64:
+ CmdArgs.push_back("--64");
+ break;
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &Input : Inputs)
+ CmdArgs.push_back(Input.getFilename());
+
+ const std::string Assembler = TC.GetProgramPath("as");
+ Exec = Args.MakeArgString(Assembler);
+
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
+}
+
+void CrossWindows::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const auto &TC =
+ static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
+ const llvm::Triple &T = TC.getTriple();
+ const Driver &D = TC.getDriver();
+ SmallString<128> EntryPoint;
+ ArgStringList CmdArgs;
+ const char *Exec;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_w);
+ // Other warning options are already handled somewhere else.
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back("-pie");
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+ if (Args.hasArg(options::OPT_s))
+ CmdArgs.push_back("--strip-all");
+
+ CmdArgs.push_back("-m");
+ switch (TC.getArch()) {
+ default: llvm_unreachable("unsupported architecture");
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // FIXME: this is incorrect for WinCE
+ CmdArgs.push_back("thumb2pe");
+ break;
+ case llvm::Triple::x86:
+ CmdArgs.push_back("i386pe");
+ EntryPoint.append("_");
+ break;
+ case llvm::Triple::x86_64:
+ CmdArgs.push_back("i386pep");
+ break;
+ }
+
+ if (Args.hasArg(options::OPT_shared)) {
+ switch (T.getArch()) {
+ default: llvm_unreachable("unsupported architecture");
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ case llvm::Triple::x86_64:
+ EntryPoint.append("_DllMainCRTStartup");
+ break;
+ case llvm::Triple::x86:
+ EntryPoint.append("_DllMainCRTStartup@12");
+ break;
+ }
+
+ CmdArgs.push_back("-shared");
+ CmdArgs.push_back("-Bdynamic");
+
+ CmdArgs.push_back("--enable-auto-image-base");
+
+ CmdArgs.push_back("--entry");
+ CmdArgs.push_back(Args.MakeArgString(EntryPoint));
+ } else {
+ EntryPoint.append("mainCRTStartup");
+
+ CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
+ : "-Bdynamic");
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ CmdArgs.push_back("--entry");
+ CmdArgs.push_back(Args.MakeArgString(EntryPoint));
+ }
+
+ // FIXME: handle subsystem
+ }
+
+ // NOTE: deal with multiple definitions on Windows (e.g. COMDAT)
+ CmdArgs.push_back("--allow-multiple-definition");
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) {
+ SmallString<261> ImpLib(Output.getFilename());
+ llvm::sys::path::replace_extension(ImpLib, ".lib");
+
+ CmdArgs.push_back("--out-implib");
+ CmdArgs.push_back(Args.MakeArgString(ImpLib));
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ const std::string CRTPath(D.SysRoot + "/usr/lib/");
+ const char *CRTBegin;
+
+ CRTBegin =
+ Args.hasArg(options::OPT_shared) ? "crtbeginS.obj" : "crtbegin.obj";
+ CmdArgs.push_back(Args.MakeArgString(CRTPath + CRTBegin));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+
+ const auto &Paths = TC.getFilePaths();
+ for (const auto &Path : Paths)
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+
+ AddLinkerInputs(TC, Inputs, Args, CmdArgs);
+
+ if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) &&
+ !Args.hasArg(options::OPT_static);
+ if (StaticCXX)
+ CmdArgs.push_back("-Bstatic");
+ TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (StaticCXX)
+ CmdArgs.push_back("-Bdynamic");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib)) {
+ if (!Args.hasArg(options::OPT_nodefaultlibs)) {
+ // TODO handle /MT[d] /MD[d]
+ CmdArgs.push_back("-lmsvcrt");
+ AddRunTimeLibs(TC, D, CmdArgs, Args);
+ }
+ }
+
+ const std::string Linker = TC.GetProgramPath("ld");
+ Exec = Args.MakeArgString(Linker);
+
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
}
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 4c89676e0e19..6647f39ce817 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_LIB_DRIVER_TOOLS_H_
-#define CLANG_LIB_DRIVER_TOOLS_H_
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLS_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLS_H
#include "clang/Driver/Tool.h"
#include "clang/Driver/Types.h"
@@ -63,6 +63,8 @@ using llvm::opt::ArgStringList;
llvm::opt::ArgStringList &CmdArgs) const;
void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+ void AddPPCTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
void AddR600TargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
void AddSparcTargetArgs(const llvm::opt::ArgList &Args,
@@ -88,11 +90,12 @@ using llvm::opt::ArgStringList;
mutable std::unique_ptr<visualstudio::Compile> CLFallback;
public:
- Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC) {}
+ Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC, RF_Full) {}
bool hasGoodDiagnostics() const override { return true; }
bool hasIntegratedAssembler() const override { return true; }
bool hasIntegratedCPP() const override { return true; }
+ bool canEmitIR() const override { return true; }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
@@ -104,7 +107,8 @@ using llvm::opt::ArgStringList;
class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {
public:
ClangAs(const ToolChain &TC) : Tool("clang::as",
- "clang integrated assembler", TC) {}
+ "clang integrated assembler", TC,
+ RF_Full) {}
bool hasGoodDiagnostics() const override { return true; }
bool hasIntegratedAssembler() const override { return false; }
@@ -116,12 +120,22 @@ using llvm::opt::ArgStringList;
const char *LinkingOutput) const override;
};
+ /// \brief Base class for all GNU tools that provide the same behavior when
+ /// it comes to response files support
+ class GnuTool : public Tool {
+ virtual void anchor();
+
+ public:
+ GnuTool(const char *Name, const char *ShortName, const ToolChain &TC)
+ : Tool(Name, ShortName, TC, RF_Full, llvm::sys::WEM_CurrentCodePage) {}
+ };
+
/// gcc - Generic GCC tool implementations.
namespace gcc {
- class LLVM_LIBRARY_VISIBILITY Common : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Common : public GnuTool {
public:
Common(const char *Name, const char *ShortName,
- const ToolChain &TC) : Tool(Name, ShortName, TC) {}
+ const ToolChain &TC) : GnuTool(Name, ShortName, TC) {}
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -176,9 +190,9 @@ namespace gcc {
namespace hexagon {
// For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile and Compile.
// We simply use "clang -cc1" for those actions.
- class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool {
public:
- Assemble(const ToolChain &TC) : Tool("hexagon::Assemble",
+ Assemble(const ToolChain &TC) : GnuTool("hexagon::Assemble",
"hexagon-as", TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -191,9 +205,9 @@ namespace hexagon {
const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public GnuTool {
public:
- Link(const ToolChain &TC) : Tool("hexagon::Link",
+ Link(const ToolChain &TC) : GnuTool("hexagon::Link",
"hexagon-ld", TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -221,11 +235,16 @@ namespace mips {
const llvm::Triple &Triple, StringRef &CPUName,
StringRef &ABIName);
bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value);
+ bool isUCLibc(const llvm::opt::ArgList &Args);
bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple);
bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
StringRef ABIName);
}
+namespace ppc {
+ bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value);
+}
+
namespace darwin {
llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str);
void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str);
@@ -241,8 +260,13 @@ namespace darwin {
}
public:
- MachOTool(const char *Name, const char *ShortName,
- const ToolChain &TC) : Tool(Name, ShortName, TC) {}
+ MachOTool(
+ const char *Name, const char *ShortName, const ToolChain &TC,
+ ResponseFileSupport ResponseSupport = RF_None,
+ llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8,
+ const char *ResponseFlag = "@")
+ : Tool(Name, ShortName, TC, ResponseSupport, ResponseEncoding,
+ ResponseFlag) {}
};
class LLVM_LIBRARY_VISIBILITY Assemble : public MachOTool {
@@ -265,7 +289,9 @@ namespace darwin {
const InputInfoList &Inputs) const;
public:
- Link(const ToolChain &TC) : MachOTool("darwin::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : MachOTool("darwin::Link", "linker", TC,
+ RF_FileList, llvm::sys::WEM_UTF8,
+ "-filelist") {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -320,9 +346,9 @@ namespace darwin {
/// openbsd -- Directly call GNU Binutils assembler and linker
namespace openbsd {
- class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool {
public:
- Assemble(const ToolChain &TC) : Tool("openbsd::Assemble", "assembler",
+ Assemble(const ToolChain &TC) : GnuTool("openbsd::Assemble", "assembler",
TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -333,9 +359,9 @@ namespace openbsd {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public GnuTool {
public:
- Link(const ToolChain &TC) : Tool("openbsd::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : GnuTool("openbsd::Link", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -349,9 +375,9 @@ namespace openbsd {
/// bitrig -- Directly call GNU Binutils assembler and linker
namespace bitrig {
- class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool {
public:
- Assemble(const ToolChain &TC) : Tool("bitrig::Assemble", "assembler",
+ Assemble(const ToolChain &TC) : GnuTool("bitrig::Assemble", "assembler",
TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -361,9 +387,9 @@ namespace bitrig {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public GnuTool {
public:
- Link(const ToolChain &TC) : Tool("bitrig::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : GnuTool("bitrig::Link", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -377,9 +403,9 @@ namespace bitrig {
/// freebsd -- Directly call GNU Binutils assembler and linker
namespace freebsd {
- class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool {
public:
- Assemble(const ToolChain &TC) : Tool("freebsd::Assemble", "assembler",
+ Assemble(const ToolChain &TC) : GnuTool("freebsd::Assemble", "assembler",
TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -389,9 +415,9 @@ namespace freebsd {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public GnuTool {
public:
- Link(const ToolChain &TC) : Tool("freebsd::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : GnuTool("freebsd::Link", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -405,11 +431,11 @@ namespace freebsd {
/// netbsd -- Directly call GNU Binutils assembler and linker
namespace netbsd {
- class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool {
public:
Assemble(const ToolChain &TC)
- : Tool("netbsd::Assemble", "assembler", TC) {}
+ : GnuTool("netbsd::Assemble", "assembler", TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -418,11 +444,11 @@ namespace netbsd {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public GnuTool {
public:
Link(const ToolChain &TC)
- : Tool("netbsd::Link", "linker", TC) {}
+ : GnuTool("netbsd::Link", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -436,9 +462,9 @@ namespace netbsd {
/// Directly call GNU Binutils' assembler and linker.
namespace gnutools {
- class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool {
public:
- Assemble(const ToolChain &TC) : Tool("GNU::Assemble", "assembler", TC) {}
+ Assemble(const ToolChain &TC) : GnuTool("GNU::Assemble", "assembler", TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -448,9 +474,9 @@ namespace gnutools {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public GnuTool {
public:
- Link(const ToolChain &TC) : Tool("GNU::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : GnuTool("GNU::Link", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -464,9 +490,9 @@ namespace gnutools {
}
/// minix -- Directly call GNU Binutils assembler and linker
namespace minix {
- class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool {
public:
- Assemble(const ToolChain &TC) : Tool("minix::Assemble", "assembler",
+ Assemble(const ToolChain &TC) : GnuTool("minix::Assemble", "assembler",
TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -477,9 +503,9 @@ namespace minix {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public GnuTool {
public:
- Link(const ToolChain &TC) : Tool("minix::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : GnuTool("minix::Link", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -520,39 +546,11 @@ namespace solaris {
};
} // end namespace solaris
- /// auroraux -- Directly call GNU Binutils assembler and linker
-namespace auroraux {
- class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
- public:
- Assemble(const ToolChain &TC) : Tool("auroraux::Assemble", "assembler",
- TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
- };
- class LLVM_LIBRARY_VISIBILITY Link : public Tool {
- public:
- Link(const ToolChain &TC) : Tool("auroraux::Link", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
- };
-} // end namespace auroraux
-
/// dragonfly -- Directly call GNU Binutils assembler and linker
namespace dragonfly {
- class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool {
public:
- Assemble(const ToolChain &TC) : Tool("dragonfly::Assemble", "assembler",
+ Assemble(const ToolChain &TC) : GnuTool("dragonfly::Assemble", "assembler",
TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -562,9 +560,9 @@ namespace dragonfly {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public GnuTool {
public:
- Link(const ToolChain &TC) : Tool("dragonfly::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : GnuTool("dragonfly::Link", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -581,7 +579,8 @@ namespace dragonfly {
namespace visualstudio {
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
- Link(const ToolChain &TC) : Tool("visualstudio::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : Tool("visualstudio::Link", "linker", TC,
+ RF_Full, llvm::sys::WEM_UTF16) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -594,7 +593,8 @@ namespace visualstudio {
class LLVM_LIBRARY_VISIBILITY Compile : public Tool {
public:
- Compile(const ToolChain &TC) : Tool("visualstudio::Compile", "compiler", TC) {}
+ Compile(const ToolChain &TC) : Tool("visualstudio::Compile", "compiler", TC,
+ RF_Full, llvm::sys::WEM_UTF16) {}
bool hasIntegratedAssembler() const override { return true; }
bool hasIntegratedCPP() const override { return true; }
@@ -605,11 +605,11 @@ namespace visualstudio {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
- Command *GetCommand(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ std::unique_ptr<Command> GetCommand(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const;
};
} // end namespace visualstudio
@@ -646,9 +646,35 @@ namespace XCore {
};
} // end namespace XCore.
+namespace CrossWindows {
+class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+public:
+ Assemble(const ToolChain &TC) : Tool("CrossWindows::Assemble", "as", TC) { }
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+public:
+ Link(const ToolChain &TC) : Tool("CrossWindows::Link", "ld", TC, RF_Full) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+}
} // end namespace toolchains
} // end namespace driver
} // end namespace clang
-#endif // CLANG_LIB_DRIVER_TOOLS_H_
+#endif
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 3538dbc2c0e9..6ee764c64e34 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -143,6 +143,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("S", TY_Asm)
.Case("o", TY_Object)
.Case("obj", TY_Object)
+ .Case("lib", TY_Object)
.Case("ii", TY_PP_CXX)
.Case("mi", TY_PP_ObjC)
.Case("mm", TY_ObjCXX)
@@ -202,6 +203,7 @@ void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) {
} else {
if (!onlyAssembleType(Id)) {
P.push_back(phases::Compile);
+ P.push_back(phases::Backend);
}
P.push_back(phases::Assemble);
}
diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp
deleted file mode 100644
index 913425a19f00..000000000000
--- a/lib/Driver/WindowsToolChain.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-//===--- ToolChains.cpp - ToolChain Implementations -----------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ToolChains.h"
-#include "clang/Basic/CharInfo.h"
-#include "clang/Basic/Version.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Options.h"
-#include "llvm/Config/llvm-config.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Path.h"
-
-// Include the necessary headers to interface with the Windows registry and
-// environment.
-#if defined(LLVM_ON_WIN32)
-#define USE_WIN32
-#endif
-
-#ifdef USE_WIN32
- #define WIN32_LEAN_AND_MEAN
- #define NOGDI
- #define NOMINMAX
- #include <windows.h>
-#endif
-
-using namespace clang::driver;
-using namespace clang::driver::toolchains;
-using namespace clang;
-using namespace llvm::opt;
-
-Windows::Windows(const Driver &D, const llvm::Triple& Triple,
- const ArgList &Args)
- : ToolChain(D, Triple, Args) {
-}
-
-Tool *Windows::buildLinker() const {
- return new tools::visualstudio::Link(*this);
-}
-
-Tool *Windows::buildAssembler() const {
- if (getTriple().isOSBinFormatMachO())
- return new tools::darwin::Assemble(*this);
- getDriver().Diag(clang::diag::err_no_external_assembler);
- return nullptr;
-}
-
-bool Windows::IsIntegratedAssemblerDefault() const {
- return true;
-}
-
-bool Windows::IsUnwindTablesDefault() const {
- // FIXME: LLVM's lowering of Win64 data is broken right now. MSVC's linker
- // says that our object files provide invalid .pdata contributions. Until
- // that is fixed, don't ask for unwind tables.
- return false;
- //return getArch() == llvm::Triple::x86_64;
-}
-
-bool Windows::isPICDefault() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-bool Windows::isPIEDefault() const {
- return false;
-}
-
-bool Windows::isPICDefaultForced() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-/// \brief Read registry string.
-/// This also supports a means to look for high-versioned keys by use
-/// of a $VERSION placeholder in the key path.
-/// $VERSION in the key path is a placeholder for the version number,
-/// causing the highest value path to be searched for and used.
-/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
-/// There can be additional characters in the component. Only the numberic
-/// characters are compared.
-static bool getSystemRegistryString(const char *keyPath, const char *valueName,
- char *value, size_t maxLength) {
-#ifndef USE_WIN32
- return false;
-#else
- HKEY hRootKey = NULL;
- HKEY hKey = NULL;
- const char* subKey = NULL;
- DWORD valueType;
- DWORD valueSize = maxLength - 1;
- long lResult;
- bool returnValue = false;
-
- if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
- hRootKey = HKEY_CLASSES_ROOT;
- subKey = keyPath + 18;
- } else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
- hRootKey = HKEY_USERS;
- subKey = keyPath + 11;
- } else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
- hRootKey = HKEY_LOCAL_MACHINE;
- subKey = keyPath + 19;
- } else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
- hRootKey = HKEY_CURRENT_USER;
- subKey = keyPath + 18;
- } else {
- return false;
- }
-
- const char *placeHolder = strstr(subKey, "$VERSION");
- char bestName[256];
- bestName[0] = '\0';
- // If we have a $VERSION placeholder, do the highest-version search.
- if (placeHolder) {
- const char *keyEnd = placeHolder - 1;
- const char *nextKey = placeHolder;
- // Find end of previous key.
- while ((keyEnd > subKey) && (*keyEnd != '\\'))
- keyEnd--;
- // Find end of key containing $VERSION.
- while (*nextKey && (*nextKey != '\\'))
- nextKey++;
- size_t partialKeyLength = keyEnd - subKey;
- char partialKey[256];
- if (partialKeyLength > sizeof(partialKey))
- partialKeyLength = sizeof(partialKey);
- strncpy(partialKey, subKey, partialKeyLength);
- partialKey[partialKeyLength] = '\0';
- HKEY hTopKey = NULL;
- lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
- &hTopKey);
- if (lResult == ERROR_SUCCESS) {
- char keyName[256];
- int bestIndex = -1;
- double bestValue = 0.0;
- DWORD index, size = sizeof(keyName) - 1;
- for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
- NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
- const char *sp = keyName;
- while (*sp && !isDigit(*sp))
- sp++;
- if (!*sp)
- continue;
- const char *ep = sp + 1;
- while (*ep && (isDigit(*ep) || (*ep == '.')))
- ep++;
- char numBuf[32];
- strncpy(numBuf, sp, sizeof(numBuf) - 1);
- numBuf[sizeof(numBuf) - 1] = '\0';
- double dvalue = strtod(numBuf, NULL);
- if (dvalue > bestValue) {
- // Test that InstallDir is indeed there before keeping this index.
- // Open the chosen key path remainder.
- strcpy(bestName, keyName);
- // Append rest of key.
- strncat(bestName, nextKey, sizeof(bestName) - 1);
- bestName[sizeof(bestName) - 1] = '\0';
- lResult = RegOpenKeyEx(hTopKey, bestName, 0,
- KEY_READ | KEY_WOW64_32KEY, &hKey);
- if (lResult == ERROR_SUCCESS) {
- lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
- (LPBYTE)value, &valueSize);
- if (lResult == ERROR_SUCCESS) {
- bestIndex = (int)index;
- bestValue = dvalue;
- returnValue = true;
- }
- RegCloseKey(hKey);
- }
- }
- size = sizeof(keyName) - 1;
- }
- RegCloseKey(hTopKey);
- }
- } else {
- lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ | KEY_WOW64_32KEY,
- &hKey);
- if (lResult == ERROR_SUCCESS) {
- lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
- (LPBYTE)value, &valueSize);
- if (lResult == ERROR_SUCCESS)
- returnValue = true;
- RegCloseKey(hKey);
- }
- }
- return returnValue;
-#endif // USE_WIN32
-}
-
-/// \brief Get Windows SDK installation directory.
-static bool getWindowsSDKDir(std::string &path) {
- char windowsSDKInstallDir[256];
- // Try the Windows registry.
- bool hasSDKDir = getSystemRegistryString(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
- "InstallationFolder",
- windowsSDKInstallDir,
- sizeof(windowsSDKInstallDir) - 1);
- // If we have both vc80 and vc90, pick version we were compiled with.
- if (hasSDKDir && windowsSDKInstallDir[0]) {
- path = windowsSDKInstallDir;
- return true;
- }
- return false;
-}
-
-// Get Visual Studio installation directory.
-static bool getVisualStudioDir(std::string &path) {
- // First check the environment variables that vsvars32.bat sets.
- const char* vcinstalldir = getenv("VCINSTALLDIR");
- if (vcinstalldir) {
- char *p = const_cast<char *>(strstr(vcinstalldir, "\\VC"));
- if (p)
- *p = '\0';
- path = vcinstalldir;
- return true;
- }
-
- char vsIDEInstallDir[256];
- char vsExpressIDEInstallDir[256];
- // Then try the windows registry.
- bool hasVCDir = getSystemRegistryString(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
- "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
- bool hasVCExpressDir = getSystemRegistryString(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
- "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
- // If we have both vc80 and vc90, pick version we were compiled with.
- if (hasVCDir && vsIDEInstallDir[0]) {
- char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
- if (p)
- *p = '\0';
- path = vsIDEInstallDir;
- return true;
- }
-
- if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
- char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
- if (p)
- *p = '\0';
- path = vsExpressIDEInstallDir;
- return true;
- }
-
- // Try the environment.
- const char *vs100comntools = getenv("VS100COMNTOOLS");
- const char *vs90comntools = getenv("VS90COMNTOOLS");
- const char *vs80comntools = getenv("VS80COMNTOOLS");
-
- const char *vscomntools = nullptr;
-
- // Find any version we can
- if (vs100comntools)
- vscomntools = vs100comntools;
- else if (vs90comntools)
- vscomntools = vs90comntools;
- else if (vs80comntools)
- vscomntools = vs80comntools;
-
- if (vscomntools && *vscomntools) {
- const char *p = strstr(vscomntools, "\\Common7\\Tools");
- path = p ? std::string(vscomntools, p) : vscomntools;
- return true;
- }
- return false;
-}
-
-void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc))
- return;
-
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- SmallString<128> P(getDriver().ResourceDir);
- llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
- }
-
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
-
- // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
- if (const char *cl_include_dir = getenv("INCLUDE")) {
- SmallVector<StringRef, 8> Dirs;
- StringRef(cl_include_dir)
- .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- for (StringRef Dir : Dirs)
- addSystemInclude(DriverArgs, CC1Args, Dir);
- if (!Dirs.empty())
- return;
- }
-
- std::string VSDir;
- std::string WindowsSDKDir;
-
- // When built with access to the proper Windows APIs, try to actually find
- // the correct include paths first.
- if (getVisualStudioDir(VSDir)) {
- SmallString<128> P;
- P = VSDir;
- llvm::sys::path::append(P, "VC\\include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
- if (getWindowsSDKDir(WindowsSDKDir)) {
- P = WindowsSDKDir;
- llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
- } else {
- P = VSDir;
- llvm::sys::path::append(P, "VC\\PlatformSDK\\Include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
- }
- return;
- }
-
- // As a fallback, select default install paths.
- // FIXME: Don't guess drives and paths like this on Windows.
- const StringRef Paths[] = {
- "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
- "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
- "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
- "C:/Program Files/Microsoft Visual Studio 8/VC/include",
- "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
- };
- addSystemIncludes(DriverArgs, CC1Args, Paths);
-}
-
-void Windows::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- // FIXME: There should probably be logic here to find libc++ on Windows.
-}
diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp
index 6cf6335da181..1c66cb827706 100644
--- a/lib/Edit/EditedSource.cpp
+++ b/lib/Edit/EditedSource.cpp
@@ -280,6 +280,12 @@ static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts,
unsigned begin = offs.getOffset();
unsigned end = begin + len;
+ // Do not try to extend the removal if we're at the end of the buffer already.
+ if (end == buffer.size())
+ return;
+
+ assert(begin < buffer.size() && end < buffer.size() && "Invalid range!");
+
// FIXME: Remove newline.
if (begin == 0) {
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index 666844c65ffc..9f71168de8fc 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1149,7 +1149,8 @@ static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
Selector Sel = Msg->getSelector();
if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
- Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString)) {
+ Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString) ||
+ Sel == NS.getNSStringSelector(NSAPI::NSStr_initWithUTF8String)) {
if (Msg->getNumArgs() != 1)
return false;
return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index 1bea0e565131..26f1371b4092 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/lib/Format/BreakableToken.cpp
@@ -303,7 +303,8 @@ BreakableBlockComment::BreakableBlockComment(
StartOfLineColumn[i] += Decoration.size();
Lines[i] = Lines[i].substr(Decoration.size());
LeadingWhitespace[i] += Decoration.size();
- IndentAtLineBreak = std::min<int>(IndentAtLineBreak, StartOfLineColumn[i]);
+ IndentAtLineBreak =
+ std::min<int>(IndentAtLineBreak, std::max(0, StartOfLineColumn[i]));
}
IndentAtLineBreak = std::max<unsigned>(IndentAtLineBreak, Decoration.size());
DEBUG({
diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h
index 72bb1e4404ff..eb1f9fda3071 100644
--- a/lib/Format/BreakableToken.h
+++ b/lib/Format/BreakableToken.h
@@ -14,8 +14,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
-#define LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
+#ifndef LLVM_CLANG_LIB_FORMAT_BREAKABLETOKEN_H
+#define LLVM_CLANG_LIB_FORMAT_BREAKABLETOKEN_H
#include "Encoding.h"
#include "TokenAnnotator.h"
@@ -212,6 +212,11 @@ private:
// StartOfLineColumn[i] is the target column at which Line[i] should be.
// Note that this excludes a leading "* " or "*" in case all lines have
// a "*" prefix.
+ // The first line's target column is always positive. The remaining lines'
+ // target columns are relative to the first line to allow correct indentation
+ // of comments in \c WhitespaceManager. Thus they can be negative as well (in
+ // case the first line needs to be unindented more than there's actual
+ // whitespace in another line).
SmallVector<int, 16> StartOfLineColumn;
// The column at which the text of a broken line should start.
@@ -237,4 +242,4 @@ private:
} // namespace format
} // namespace clang
-#endif // LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
+#endif
diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt
index 47e15bd08a3f..2ce38343cfe9 100644
--- a/lib/Format/CMakeLists.txt
+++ b/lib/Format/CMakeLists.txt
@@ -6,11 +6,12 @@ add_clang_library(clangFormat
Format.cpp
FormatToken.cpp
TokenAnnotator.cpp
+ UnwrappedLineFormatter.cpp
UnwrappedLineParser.cpp
WhitespaceManager.cpp
LINK_LIBS
clangBasic
clangLex
- clangTooling
+ clangToolingCore
)
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 014c30e346ad..4cc92b02a9e5 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -48,21 +48,22 @@ static bool startsSegmentOfBuilderTypeCall(const FormatToken &Tok) {
static bool startsNextParameter(const FormatToken &Current,
const FormatStyle &Style) {
const FormatToken &Previous = *Current.Previous;
- if (Current.Type == TT_CtorInitializerComma &&
+ if (Current.is(TT_CtorInitializerComma) &&
Style.BreakConstructorInitializersBeforeComma)
return true;
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
- (Previous.Type != TT_CtorInitializerComma ||
+ (Previous.isNot(TT_CtorInitializerComma) ||
!Style.BreakConstructorInitializersBeforeComma);
}
ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
+ const AdditionalKeywords &Keywords,
SourceManager &SourceMgr,
WhitespaceManager &Whitespaces,
encoding::Encoding Encoding,
bool BinPackInconclusiveFunctions)
- : Style(Style), SourceMgr(SourceMgr), Whitespaces(Whitespaces),
- Encoding(Encoding),
+ : Style(Style), Keywords(Keywords), SourceMgr(SourceMgr),
+ Whitespaces(Whitespaces), Encoding(Encoding),
BinPackInconclusiveFunctions(BinPackInconclusiveFunctions),
CommentPragmasRegex(Style.CommentPragmas) {}
@@ -92,13 +93,14 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *Current.Previous;
assert(&Previous == Current.Previous);
- if (!Current.CanBreakBefore && !(State.Stack.back().BreakBeforeClosingBrace &&
- Current.closesBlockTypeList(Style)))
+ if (!Current.CanBreakBefore &&
+ !(State.Stack.back().BreakBeforeClosingBrace &&
+ Current.closesBlockTypeList(Style)))
return false;
// The opening "{" of a braced list has to be on the same line as the first
// element if it is nested in another braced init list or function call.
if (!Current.MustBreakBefore && Previous.is(tok::l_brace) &&
- Previous.Type != TT_DictLiteral && Previous.BlockKind == BK_BracedInit &&
+ Previous.isNot(TT_DictLiteral) && Previous.BlockKind == BK_BracedInit &&
Previous.Previous &&
Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma))
return false;
@@ -116,19 +118,24 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
// Don't create a 'hanging' indent if there are multiple blocks in a single
// statement.
- if (Style.Language == FormatStyle::LK_JavaScript &&
- Previous.is(tok::l_brace) && State.Stack.size() > 1 &&
- State.Stack[State.Stack.size() - 2].JSFunctionInlined &&
+ if (Previous.is(tok::l_brace) && State.Stack.size() > 1 &&
+ State.Stack[State.Stack.size() - 2].NestedBlockInlined &&
State.Stack[State.Stack.size() - 2].HasMultipleNestedBlocks)
return false;
+ // Don't break after very short return types (e.g. "void") as that is often
+ // unexpected.
+ if (Current.is(TT_FunctionDeclarationName) &&
+ !Style.AlwaysBreakAfterDefinitionReturnType && State.Column < 6)
+ return false;
+
return !State.Stack.back().NoLineBreak;
}
bool ContinuationIndenter::mustBreak(const LineState &State) {
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *Current.Previous;
- if (Current.MustBreakBefore || Current.Type == TT_InlineASMColon)
+ if (Current.MustBreakBefore || Current.is(TT_InlineASMColon))
return true;
if (State.Stack.back().BreakBeforeClosingBrace &&
Current.closesBlockTypeList(Style))
@@ -137,32 +144,32 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) ||
(Style.BreakBeforeTernaryOperators &&
- (Current.is(tok::question) || (Current.Type == TT_ConditionalExpr &&
- Previous.isNot(tok::question)))) ||
+ (Current.is(tok::question) ||
+ (Current.is(TT_ConditionalExpr) && Previous.isNot(tok::question)))) ||
(!Style.BreakBeforeTernaryOperators &&
- (Previous.is(tok::question) || Previous.Type == TT_ConditionalExpr))) &&
+ (Previous.is(tok::question) || Previous.is(TT_ConditionalExpr)))) &&
State.Stack.back().BreakBeforeParameter && !Current.isTrailingComment() &&
!Current.isOneOf(tok::r_paren, tok::r_brace))
return true;
if (Style.AlwaysBreakBeforeMultilineStrings &&
State.Column > State.Stack.back().Indent && // Breaking saves columns.
!Previous.isOneOf(tok::kw_return, tok::lessless, tok::at) &&
- Previous.Type != TT_InlineASMColon &&
- Previous.Type != TT_ConditionalExpr && nextIsMultilineString(State))
+ !Previous.isOneOf(TT_InlineASMColon, TT_ConditionalExpr) &&
+ nextIsMultilineString(State))
return true;
- if (((Previous.Type == TT_DictLiteral && Previous.is(tok::l_brace)) ||
- Previous.Type == TT_ArrayInitializerLSquare) &&
+ if (((Previous.is(TT_DictLiteral) && Previous.is(tok::l_brace)) ||
+ Previous.is(TT_ArrayInitializerLSquare)) &&
Style.ColumnLimit > 0 &&
getLengthToMatchingParen(Previous) + State.Column > getColumnLimit(State))
return true;
- if (Current.Type == TT_CtorInitializerColon &&
+ if (Current.is(TT_CtorInitializerColon) &&
((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) ||
Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0))
return true;
if (State.Column < getNewLineColumn(State))
return false;
- if (!Style.BreakBeforeBinaryOperators) {
+ if (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None) {
// If we need to break somewhere inside the LHS of a binary expression, we
// should also break after the operator. Otherwise, the formatting would
// hide the operator precedence, e.g. in:
@@ -172,41 +179,43 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
// expression itself as otherwise, the line breaks seem superfluous.
// We need special cases for ">>" which we have split into two ">" while
// lexing in order to make template parsing easier.
- //
- // FIXME: We'll need something similar for styles that break before binary
- // operators.
bool IsComparison = (Previous.getPrecedence() == prec::Relational ||
Previous.getPrecedence() == prec::Equality) &&
Previous.Previous &&
- Previous.Previous->Type != TT_BinaryOperator; // For >>.
+ Previous.Previous->isNot(TT_BinaryOperator); // For >>.
bool LHSIsBinaryExpr =
Previous.Previous && Previous.Previous->EndsBinaryExpression;
- if (Previous.Type == TT_BinaryOperator &&
- (!IsComparison || LHSIsBinaryExpr) &&
- Current.Type != TT_BinaryOperator && // For >>.
+ if (Previous.is(TT_BinaryOperator) && (!IsComparison || LHSIsBinaryExpr) &&
+ Current.isNot(TT_BinaryOperator) && // For >>.
!Current.isTrailingComment() && !Previous.is(tok::lessless) &&
Previous.getPrecedence() != prec::Assignment &&
State.Stack.back().BreakBeforeParameter)
return true;
+ } else {
+ if (Current.is(TT_BinaryOperator) && Previous.EndsBinaryExpression &&
+ State.Stack.back().BreakBeforeParameter)
+ return true;
}
// Same as above, but for the first "<<" operator.
- if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator &&
+ if (Current.is(tok::lessless) && Current.isNot(TT_OverloadedOperator) &&
State.Stack.back().BreakBeforeParameter &&
State.Stack.back().FirstLessLess == 0)
return true;
- if (Current.Type == TT_SelectorName &&
- State.Stack.back().ObjCSelectorNameFound &&
+ if (Current.is(TT_SelectorName) && State.Stack.back().ObjCSelectorNameFound &&
State.Stack.back().BreakBeforeParameter)
return true;
- if (Previous.ClosesTemplateDeclaration && Current.NestingLevel == 0 &&
- !Current.isTrailingComment())
- return true;
+ if (Current.NestingLevel == 0 && !Current.isTrailingComment()) {
+ if (Previous.ClosesTemplateDeclaration)
+ return true;
+ if (Previous.is(TT_LeadingJavaAnnotation) && Current.isNot(tok::l_paren) &&
+ Current.isNot(TT_LeadingJavaAnnotation))
+ return true;
+ }
// If the return type spans multiple lines, wrap before the function name.
- if ((Current.Type == TT_FunctionDeclarationName ||
- Current.is(tok::kw_operator)) &&
+ if (Current.isOneOf(TT_FunctionDeclarationName, tok::kw_operator) &&
State.Stack.back().BreakBeforeParameter)
return true;
@@ -232,7 +241,7 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
const FormatToken &Current = *State.NextToken;
assert(!State.Stack.empty());
- if ((Current.Type == TT_ImplicitStringLiteral &&
+ if ((Current.is(TT_ImplicitStringLiteral) &&
(Current.Previous->Tok.getIdentifierInfo() == nullptr ||
Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp_not_keyword))) {
@@ -281,7 +290,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0,
Spaces, State.Column + Spaces);
- if (Current.Type == TT_SelectorName &&
+ if (Current.is(TT_SelectorName) &&
!State.Stack.back().ObjCSelectorNameFound) {
if (Current.LongestObjCSelectorName == 0)
State.Stack.back().AlignColons = false;
@@ -293,36 +302,50 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
State.Stack.back().ColonPos = State.Column + Spaces + Current.ColumnWidth;
}
- if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr &&
- (Current.Type != TT_LineComment || Previous.BlockKind == BK_BracedInit))
+ if (Style.AlignAfterOpenBracket && Previous.opensScope() &&
+ Previous.isNot(TT_ObjCMethodExpr) &&
+ (Current.isNot(TT_LineComment) || Previous.BlockKind == BK_BracedInit))
State.Stack.back().Indent = State.Column + Spaces;
if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style))
State.Stack.back().NoLineBreak = true;
if (startsSegmentOfBuilderTypeCall(Current))
State.Stack.back().ContainsUnwrappedBuilder = true;
+ if (Current.isMemberAccess() && Previous.is(tok::r_paren) &&
+ (Previous.MatchingParen &&
+ (Previous.TotalLength - Previous.MatchingParen->TotalLength > 10))) {
+ // If there is a function call with long parameters, break before trailing
+ // calls. This prevents things like:
+ // EXPECT_CALL(SomeLongParameter).Times(
+ // 2);
+ // We don't want to do this for short parameters as they can just be
+ // indexes.
+ State.Stack.back().NoLineBreak = true;
+ }
+
State.Column += Spaces;
if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) &&
- Previous.Previous && Previous.Previous->isOneOf(tok::kw_if, tok::kw_for))
+ Previous.Previous &&
+ Previous.Previous->isOneOf(tok::kw_if, tok::kw_for)) {
// Treat the condition inside an if as if it was a second function
// parameter, i.e. let nested calls have a continuation indent.
State.Stack.back().LastSpace = State.Column;
- else if (!Current.isOneOf(tok::comment, tok::caret) &&
- (Previous.is(tok::comma) ||
- (Previous.is(tok::colon) && Previous.Type == TT_ObjCMethodExpr)))
+ State.Stack.back().NestedBlockIndent = State.Column;
+ } else if (!Current.isOneOf(tok::comment, tok::caret) &&
+ (Previous.is(tok::comma) ||
+ (Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) {
State.Stack.back().LastSpace = State.Column;
- else if ((Previous.Type == TT_BinaryOperator ||
- Previous.Type == TT_ConditionalExpr ||
- Previous.Type == TT_CtorInitializerColon) &&
- ((Previous.getPrecedence() != prec::Assignment &&
- (Previous.isNot(tok::lessless) || Previous.OperatorIndex != 0 ||
- !Previous.LastOperator)) ||
- Current.StartsBinaryExpression))
+ } else if ((Previous.isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
+ TT_CtorInitializerColon)) &&
+ ((Previous.getPrecedence() != prec::Assignment &&
+ (Previous.isNot(tok::lessless) || Previous.OperatorIndex != 0 ||
+ !Previous.LastOperator)) ||
+ Current.StartsBinaryExpression)) {
// Always indent relative to the RHS of the expression unless this is a
// simple assignment without binary expression on the RHS. Also indent
// relative to unary operators and the colons of constructor initializers.
State.Stack.back().LastSpace = State.Column;
- else if (Previous.Type == TT_InheritanceColon) {
+ } else if (Previous.is(TT_InheritanceColon)) {
State.Stack.back().Indent = State.Column;
State.Stack.back().LastSpace = State.Column;
} else if (Previous.opensScope()) {
@@ -373,10 +396,11 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
Penalty += Style.PenaltyBreakFirstLessLess;
State.Column = getNewLineColumn(State);
+ State.Stack.back().NestedBlockIndent = State.Column;
if (NextNonComment->isMemberAccess()) {
if (State.Stack.back().CallContinuation == 0)
State.Stack.back().CallContinuation = State.Column;
- } else if (NextNonComment->Type == TT_SelectorName) {
+ } else if (NextNonComment->is(TT_SelectorName)) {
if (!State.Stack.back().ObjCSelectorNameFound) {
if (NextNonComment->LongestObjCSelectorName == 0) {
State.Stack.back().AlignColons = false;
@@ -389,8 +413,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
State.Stack.back().ColonPos = State.Column + NextNonComment->ColumnWidth;
}
} else if (PreviousNonComment && PreviousNonComment->is(tok::colon) &&
- (PreviousNonComment->Type == TT_ObjCMethodExpr ||
- PreviousNonComment->Type == TT_DictLiteral)) {
+ PreviousNonComment->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral)) {
// FIXME: This is hacky, find a better way. The problem is that in an ObjC
// method expression, the block should be aligned to the line starting it,
// e.g.:
@@ -408,9 +431,10 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
if ((Previous.isOneOf(tok::comma, tok::semi) &&
!State.Stack.back().AvoidBinPacking) ||
- Previous.Type == TT_BinaryOperator)
+ Previous.is(TT_BinaryOperator))
State.Stack.back().BreakBeforeParameter = false;
- if (Previous.Type == TT_TemplateCloser && Current.NestingLevel == 0)
+ if (Previous.isOneOf(TT_TemplateCloser, TT_JavaAnnotation) &&
+ Current.NestingLevel == 0)
State.Stack.back().BreakBeforeParameter = false;
if (NextNonComment->is(tok::question) ||
(PreviousNonComment && PreviousNonComment->is(tok::question)))
@@ -431,11 +455,10 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
// Any break on this level means that the parent level has been broken
// and we need to avoid bin packing there.
- bool JavaScriptFormat = Style.Language == FormatStyle::LK_JavaScript &&
- Current.is(tok::r_brace) &&
- State.Stack.size() > 1 &&
- State.Stack[State.Stack.size() - 2].JSFunctionInlined;
- if (!JavaScriptFormat) {
+ bool NestedBlockSpecialCase =
+ Current.is(tok::r_brace) && State.Stack.size() > 1 &&
+ State.Stack[State.Stack.size() - 2].NestedBlockInlined;
+ if (!NestedBlockSpecialCase) {
for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
State.Stack[i].BreakBeforeParameter = true;
}
@@ -443,27 +466,27 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
if (PreviousNonComment &&
!PreviousNonComment->isOneOf(tok::comma, tok::semi) &&
- PreviousNonComment->Type != TT_TemplateCloser &&
- PreviousNonComment->Type != TT_BinaryOperator &&
- Current.Type != TT_BinaryOperator && !PreviousNonComment->opensScope())
+ (PreviousNonComment->isNot(TT_TemplateCloser) ||
+ Current.NestingLevel != 0) &&
+ !PreviousNonComment->isOneOf(TT_BinaryOperator, TT_JavaAnnotation,
+ TT_LeadingJavaAnnotation) &&
+ Current.isNot(TT_BinaryOperator) && !PreviousNonComment->opensScope())
State.Stack.back().BreakBeforeParameter = true;
// If we break after { or the [ of an array initializer, we should also break
// before the corresponding } or ].
if (PreviousNonComment &&
- (PreviousNonComment->is(tok::l_brace) ||
- PreviousNonComment->Type == TT_ArrayInitializerLSquare))
+ (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)))
State.Stack.back().BreakBeforeClosingBrace = true;
if (State.Stack.back().AvoidBinPacking) {
// If we are breaking after '(', '{', '<', this is not bin packing
// unless AllowAllParametersOfDeclarationOnNextLine is false or this is a
// dict/object literal.
- if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) ||
- Previous.Type == TT_BinaryOperator) ||
+ if (!Previous.isOneOf(tok::l_paren, tok::l_brace, TT_BinaryOperator) ||
(!Style.AllowAllParametersOfDeclarationOnNextLine &&
State.Line->MustBeDeclaration) ||
- Previous.Type == TT_DictLiteral)
+ Previous.is(TT_DictLiteral))
State.Stack.back().BreakBeforeParameter = true;
}
@@ -474,7 +497,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
if (!State.NextToken || !State.NextToken->Previous)
return 0;
FormatToken &Current = *State.NextToken;
- const FormatToken &Previous = *State.NextToken->Previous;
+ const FormatToken &Previous = *Current.Previous;
// If we are continuing an expression, we want to use the continuation indent.
unsigned ContinuationIndent =
std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) +
@@ -483,22 +506,26 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
const FormatToken *NextNonComment = Previous.getNextNonComment();
if (!NextNonComment)
NextNonComment = &Current;
+
+ // Java specific bits.
+ if (Style.Language == FormatStyle::LK_Java &&
+ Current.isOneOf(Keywords.kw_implements, Keywords.kw_extends))
+ return std::max(State.Stack.back().LastSpace,
+ State.Stack.back().Indent + Style.ContinuationIndentWidth);
+
if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block)
return Current.NestingLevel == 0 ? State.FirstIndent
: State.Stack.back().Indent;
if (Current.isOneOf(tok::r_brace, tok::r_square)) {
- if (State.Stack.size() > 1 &&
- State.Stack[State.Stack.size() - 2].JSFunctionInlined)
- return State.FirstIndent;
- if (Current.closesBlockTypeList(Style) ||
- (Current.MatchingParen &&
- Current.MatchingParen->BlockKind == BK_BracedInit))
+ if (Current.closesBlockTypeList(Style))
+ return State.Stack[State.Stack.size() - 2].NestedBlockIndent;
+ if (Current.MatchingParen &&
+ Current.MatchingParen->BlockKind == BK_BracedInit)
return State.Stack[State.Stack.size() - 2].LastSpace;
- else
- return State.FirstIndent;
+ return State.FirstIndent;
}
if (Current.is(tok::identifier) && Current.Next &&
- Current.Next->Type == TT_DictLiteral)
+ Current.Next->is(TT_DictLiteral))
return State.Stack.back().Indent;
if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0)
return State.StartOfStringLiteral;
@@ -506,60 +533,57 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
State.Stack.back().FirstLessLess != 0)
return State.Stack.back().FirstLessLess;
if (NextNonComment->isMemberAccess()) {
- if (State.Stack.back().CallContinuation == 0) {
+ if (State.Stack.back().CallContinuation == 0)
return ContinuationIndent;
- } else {
- return State.Stack.back().CallContinuation;
- }
+ return State.Stack.back().CallContinuation;
}
if (State.Stack.back().QuestionColumn != 0 &&
((NextNonComment->is(tok::colon) &&
- NextNonComment->Type == TT_ConditionalExpr) ||
- Previous.Type == TT_ConditionalExpr))
+ NextNonComment->is(TT_ConditionalExpr)) ||
+ Previous.is(TT_ConditionalExpr)))
return State.Stack.back().QuestionColumn;
if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0)
return State.Stack.back().VariablePos;
- if ((PreviousNonComment && (PreviousNonComment->ClosesTemplateDeclaration ||
- PreviousNonComment->Type == TT_AttributeParen)) ||
+ if ((PreviousNonComment &&
+ (PreviousNonComment->ClosesTemplateDeclaration ||
+ PreviousNonComment->isOneOf(TT_AttributeParen, TT_JavaAnnotation,
+ TT_LeadingJavaAnnotation))) ||
(!Style.IndentWrappedFunctionNames &&
- (NextNonComment->is(tok::kw_operator) ||
- NextNonComment->Type == TT_FunctionDeclarationName)))
+ NextNonComment->isOneOf(tok::kw_operator, TT_FunctionDeclarationName)))
return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent);
- if (NextNonComment->Type == TT_SelectorName) {
+ if (NextNonComment->is(TT_SelectorName)) {
if (!State.Stack.back().ObjCSelectorNameFound) {
- if (NextNonComment->LongestObjCSelectorName == 0) {
+ if (NextNonComment->LongestObjCSelectorName == 0)
return State.Stack.back().Indent;
- } else {
- return State.Stack.back().Indent +
- NextNonComment->LongestObjCSelectorName -
- NextNonComment->ColumnWidth;
- }
- } else if (!State.Stack.back().AlignColons) {
+ return State.Stack.back().Indent +
+ NextNonComment->LongestObjCSelectorName -
+ NextNonComment->ColumnWidth;
+ }
+ if (!State.Stack.back().AlignColons)
return State.Stack.back().Indent;
- } else if (State.Stack.back().ColonPos > NextNonComment->ColumnWidth) {
+ if (State.Stack.back().ColonPos > NextNonComment->ColumnWidth)
return State.Stack.back().ColonPos - NextNonComment->ColumnWidth;
- } else {
- return State.Stack.back().Indent;
- }
+ return State.Stack.back().Indent;
}
- if (NextNonComment->Type == TT_ArraySubscriptLSquare) {
+ if (NextNonComment->is(TT_ArraySubscriptLSquare)) {
if (State.Stack.back().StartOfArraySubscripts != 0)
return State.Stack.back().StartOfArraySubscripts;
- else
- return ContinuationIndent;
+ return ContinuationIndent;
}
- if (NextNonComment->Type == TT_StartOfName ||
+ if (NextNonComment->is(TT_StartOfName) ||
Previous.isOneOf(tok::coloncolon, tok::equal)) {
return ContinuationIndent;
}
if (PreviousNonComment && PreviousNonComment->is(tok::colon) &&
- (PreviousNonComment->Type == TT_ObjCMethodExpr ||
- PreviousNonComment->Type == TT_DictLiteral))
+ PreviousNonComment->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral))
return ContinuationIndent;
- if (NextNonComment->Type == TT_CtorInitializerColon)
+ if (NextNonComment->is(TT_CtorInitializerColon))
return State.FirstIndent + Style.ConstructorInitializerIndentWidth;
- if (NextNonComment->Type == TT_CtorInitializerComma)
+ if (NextNonComment->is(TT_CtorInitializerComma))
return State.Stack.back().Indent;
+ if (Previous.is(tok::r_paren) && !Current.isBinaryOperator() &&
+ !Current.isOneOf(tok::colon, tok::comment))
+ return ContinuationIndent;
if (State.Stack.back().Indent == State.FirstIndent && PreviousNonComment &&
PreviousNonComment->isNot(tok::r_brace))
// Ensure that we fall back to the continuation indent width instead of
@@ -573,18 +597,18 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
assert(State.Stack.size());
const FormatToken &Current = *State.NextToken;
- if (Current.Type == TT_InheritanceColon)
+ if (Current.is(TT_InheritanceColon))
State.Stack.back().AvoidBinPacking = true;
- if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator) {
+ if (Current.is(tok::lessless) && Current.isNot(TT_OverloadedOperator)) {
if (State.Stack.back().FirstLessLess == 0)
State.Stack.back().FirstLessLess = State.Column;
else
State.Stack.back().LastOperatorWrapped = Newline;
}
- if ((Current.Type == TT_BinaryOperator && Current.isNot(tok::lessless)) ||
- Current.Type == TT_ConditionalExpr)
+ if ((Current.is(TT_BinaryOperator) && Current.isNot(tok::lessless)) ||
+ Current.is(TT_ConditionalExpr))
State.Stack.back().LastOperatorWrapped = Newline;
- if (Current.Type == TT_ArraySubscriptLSquare &&
+ if (Current.is(TT_ArraySubscriptLSquare) &&
State.Stack.back().StartOfArraySubscripts == 0)
State.Stack.back().StartOfArraySubscripts = State.Column;
if ((Current.is(tok::question) && Style.BreakBeforeTernaryOperators) ||
@@ -598,9 +622,9 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
if (Current.isMemberAccess())
State.Stack.back().StartOfFunctionCall =
Current.LastOperator ? 0 : State.Column + Current.ColumnWidth;
- if (Current.Type == TT_SelectorName)
+ if (Current.is(TT_SelectorName))
State.Stack.back().ObjCSelectorNameFound = true;
- if (Current.Type == TT_CtorInitializerColon) {
+ if (Current.is(TT_CtorInitializerColon)) {
// Indent 2 from the column, so:
// SomeClass::SomeClass()
// : First(...), ...
@@ -608,6 +632,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
// ^ line up here.
State.Stack.back().Indent =
State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2);
+ State.Stack.back().NestedBlockIndent = State.Stack.back().Indent;
if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
State.Stack.back().AvoidBinPacking = true;
State.Stack.back().BreakBeforeParameter = false;
@@ -616,7 +641,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
// In ObjC method declaration we align on the ":" of parameters, but we need
// to ensure that we indent parameters on subsequent lines by at least our
// continuation indent width.
- if (Current.Type == TT_ObjCMethodSpecifier)
+ if (Current.is(TT_ObjCMethodSpecifier))
State.Stack.back().Indent += Style.ContinuationIndentWidth;
// Insert scopes created by fake parenthesis.
@@ -628,18 +653,21 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
// foo();
// bar();
// }, a, b, c);
- if (Style.Language == FormatStyle::LK_JavaScript) {
- if (Current.isNot(tok::comment) && Previous && Previous->is(tok::l_brace) &&
- State.Stack.size() > 1) {
- if (State.Stack[State.Stack.size() - 2].JSFunctionInlined && Newline) {
- for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
- State.Stack[i].NoLineBreak = true;
- }
+ if (Current.isNot(tok::comment) && Previous && Previous->is(tok::l_brace) &&
+ State.Stack.size() > 1) {
+ if (State.Stack[State.Stack.size() - 2].NestedBlockInlined && Newline) {
+ for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
+ State.Stack[i].NoLineBreak = true;
}
- State.Stack[State.Stack.size() - 2].JSFunctionInlined = false;
}
- if (Current.TokenText == "function")
- State.Stack.back().JSFunctionInlined = !Newline;
+ State.Stack[State.Stack.size() - 2].NestedBlockInlined = false;
+ }
+ if (Previous && (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) ||
+ Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr)) &&
+ !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) {
+ State.Stack.back().NestedBlockInlined =
+ !Newline &&
+ (Previous->isNot(tok::l_paren) || Previous->ParameterCount > 1);
}
moveStatePastFakeLParens(State, Newline);
@@ -685,8 +713,9 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
// is special cased.
bool SkipFirstExtraIndent =
(Previous && (Previous->opensScope() || Previous->is(tok::kw_return) ||
- Previous->getPrecedence() == prec::Assignment ||
- Previous->Type == TT_ObjCMethodExpr));
+ (Previous->getPrecedence() == prec::Assignment &&
+ Style.AlignOperands) ||
+ Previous->is(TT_ObjCMethodExpr)));
for (SmallVectorImpl<prec::Level>::const_reverse_iterator
I = Current.FakeLParens.rbegin(),
E = Current.FakeLParens.rend();
@@ -694,10 +723,15 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
ParenState NewParenState = State.Stack.back();
NewParenState.ContainsLineBreak = false;
- // Indent from 'LastSpace' unless this the fake parentheses encapsulating a
- // builder type call after 'return'. If such a call is line-wrapped, we
- // commonly just want to indent from the start of the line.
- if (!Previous || Previous->isNot(tok::kw_return) || *I > 0)
+ // Indent from 'LastSpace' unless these are fake parentheses encapsulating
+ // a builder type call after 'return' or, if the alignment after opening
+ // brackets is disabled.
+ if (!Current.isTrailingComment() &&
+ (Style.AlignOperands || *I < prec::Assignment) &&
+ (!Previous || Previous->isNot(tok::kw_return) ||
+ (Style.Language != FormatStyle::LK_Java && *I > 0)) &&
+ (Style.AlignAfterOpenBracket || *I != prec::Comma ||
+ Current.NestingLevel == 0))
NewParenState.Indent =
std::max(std::max(State.Column, NewParenState.Indent),
State.Stack.back().LastSpace);
@@ -707,14 +741,14 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
// Exclude relational operators, as there, it is always more desirable to
// have the LHS 'left' of the RHS.
if (Previous && Previous->getPrecedence() > prec::Assignment &&
- (Previous->Type == TT_BinaryOperator ||
- Previous->Type == TT_ConditionalExpr) &&
+ Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr) &&
Previous->getPrecedence() != prec::Relational) {
- bool BreakBeforeOperator = Previous->is(tok::lessless) ||
- (Previous->Type == TT_BinaryOperator &&
- Style.BreakBeforeBinaryOperators) ||
- (Previous->Type == TT_ConditionalExpr &&
- Style.BreakBeforeTernaryOperators);
+ bool BreakBeforeOperator =
+ Previous->is(tok::lessless) ||
+ (Previous->is(TT_BinaryOperator) &&
+ Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None) ||
+ (Previous->is(TT_ConditionalExpr) &&
+ Style.BreakBeforeTernaryOperators);
if ((!Newline && !BreakBeforeOperator) ||
(!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator))
NewParenState.NoLineBreak = true;
@@ -728,7 +762,8 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
// ParameterToInnerFunction));
if (*I > prec::Unknown)
NewParenState.LastSpace = std::max(NewParenState.LastSpace, State.Column);
- NewParenState.StartOfFunctionCall = State.Column;
+ if (*I != prec::Conditional)
+ NewParenState.StartOfFunctionCall = State.Column;
// Always indent conditional expressions. Never indent expression where
// the 'operator' is ',', ';' or an assignment (i.e. *I <=
@@ -736,7 +771,7 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
// other expression, unless the indentation needs to be skipped.
if (*I == prec::Conditional ||
(!SkipFirstExtraIndent && *I > prec::Assignment &&
- !Style.BreakBeforeBinaryOperators))
+ !Current.isTrailingComment()))
NewParenState.Indent += Style.ContinuationIndentWidth;
if ((Previous && !Previous->opensScope()) || *I > prec::Comma)
NewParenState.BreakBeforeParameter = false;
@@ -745,9 +780,8 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
}
}
-// Remove the fake r_parens after 'Tok'.
-static void consumeRParens(LineState& State, const FormatToken &Tok) {
- for (unsigned i = 0, e = Tok.FakeRParens; i != e; ++i) {
+void ContinuationIndenter::moveStatePastFakeRParens(LineState &State) {
+ for (unsigned i = 0, e = State.NextToken->FakeRParens; i != e; ++i) {
unsigned VariablePos = State.Stack.back().VariablePos;
assert(State.Stack.size() > 1);
if (State.Stack.size() == 1) {
@@ -759,46 +793,6 @@ static void consumeRParens(LineState& State, const FormatToken &Tok) {
}
}
-// Returns whether 'Tok' opens or closes a scope requiring special handling
-// of the subsequent fake r_parens.
-//
-// For example, if this is an l_brace starting a nested block, we pretend (wrt.
-// to indentation) that we already consumed the corresponding r_brace. Thus, we
-// remove all ParenStates caused by fake parentheses that end at the r_brace.
-// The net effect of this is that we don't indent relative to the l_brace, if
-// the nested block is the last parameter of a function. This formats:
-//
-// SomeFunction(a, [] {
-// f(); // break
-// });
-//
-// instead of:
-// SomeFunction(a, [] {
-// f(); // break
-// });
-static bool fakeRParenSpecialCase(const LineState &State) {
- const FormatToken &Tok = *State.NextToken;
- if (!Tok.MatchingParen)
- return false;
- const FormatToken *Left = &Tok;
- if (Tok.isOneOf(tok::r_brace, tok::r_square))
- Left = Tok.MatchingParen;
- return !State.Stack.back().HasMultipleNestedBlocks &&
- Left->isOneOf(tok::l_brace, tok::l_square) &&
- (Left->BlockKind == BK_Block ||
- Left->Type == TT_ArrayInitializerLSquare ||
- Left->Type == TT_DictLiteral);
-}
-
-void ContinuationIndenter::moveStatePastFakeRParens(LineState &State) {
- // Don't remove FakeRParens attached to r_braces that surround nested blocks
- // as they will have been removed early (see above).
- if (fakeRParenSpecialCase(State))
- return;
-
- consumeRParens(State, *State.NextToken);
-}
-
void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
bool Newline) {
const FormatToken &Current = *State.NextToken;
@@ -814,48 +808,46 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
unsigned NewIndentLevel = State.Stack.back().IndentLevel;
bool AvoidBinPacking;
bool BreakBeforeParameter = false;
- if (Current.is(tok::l_brace) || Current.Type == TT_ArrayInitializerLSquare) {
- if (fakeRParenSpecialCase(State))
- consumeRParens(State, *Current.MatchingParen);
-
- NewIndent = State.Stack.back().LastSpace;
+ if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) {
if (Current.opensBlockTypeList(Style)) {
- NewIndent += Style.IndentWidth;
+ NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth;
NewIndent = std::min(State.Column + 2, NewIndent);
++NewIndentLevel;
} else {
- NewIndent += Style.ContinuationIndentWidth;
+ NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth;
NewIndent = std::min(State.Column + 1, NewIndent);
}
const FormatToken *NextNoComment = Current.getNextNonComment();
- AvoidBinPacking = Current.Type == TT_ArrayInitializerLSquare ||
- Current.Type == TT_DictLiteral ||
- Style.Language == FormatStyle::LK_Proto ||
- !Style.BinPackParameters ||
- (NextNoComment &&
- NextNoComment->Type == TT_DesignatedInitializerPeriod);
+ AvoidBinPacking =
+ Current.isOneOf(TT_ArrayInitializerLSquare, TT_DictLiteral) ||
+ Style.Language == FormatStyle::LK_Proto || !Style.BinPackParameters ||
+ (NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod));
} else {
NewIndent = Style.ContinuationIndentWidth +
std::max(State.Stack.back().LastSpace,
State.Stack.back().StartOfFunctionCall);
- AvoidBinPacking = !Style.BinPackParameters ||
- (Style.ExperimentalAutoDetectBinPacking &&
- (Current.PackingKind == PPK_OnePerLine ||
- (!BinPackInconclusiveFunctions &&
- Current.PackingKind == PPK_Inconclusive)));
+ AvoidBinPacking =
+ (State.Line->MustBeDeclaration && !Style.BinPackParameters) ||
+ (!State.Line->MustBeDeclaration && !Style.BinPackArguments) ||
+ (Style.ExperimentalAutoDetectBinPacking &&
+ (Current.PackingKind == PPK_OnePerLine ||
+ (!BinPackInconclusiveFunctions &&
+ Current.PackingKind == PPK_Inconclusive)));
// If this '[' opens an ObjC call, determine whether all parameters fit
// into one line and put one per line if they don't.
- if (Current.Type == TT_ObjCMethodExpr && Style.ColumnLimit != 0 &&
+ if (Current.is(TT_ObjCMethodExpr) && Style.ColumnLimit != 0 &&
getLengthToMatchingParen(Current) + State.Column >
getColumnLimit(State))
BreakBeforeParameter = true;
}
bool NoLineBreak = State.Stack.back().NoLineBreak ||
- (Current.Type == TT_TemplateOpener &&
+ (Current.is(TT_TemplateOpener) &&
State.Stack.back().ContainsUnwrappedBuilder);
+ unsigned NestedBlockIndent = State.Stack.back().NestedBlockIndent;
State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
State.Stack.back().LastSpace,
AvoidBinPacking, NoLineBreak));
+ State.Stack.back().NestedBlockIndent = NestedBlockIndent;
State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
State.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1;
}
@@ -870,7 +862,7 @@ void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) {
if (State.Stack.size() > 1 &&
(Current.isOneOf(tok::r_paren, tok::r_square) ||
(Current.is(tok::r_brace) && State.NextToken != State.Line->First) ||
- State.NextToken->Type == TT_TemplateCloser))
+ State.NextToken->is(TT_TemplateCloser)))
State.Stack.pop_back();
if (Current.is(tok::r_square)) {
@@ -882,20 +874,17 @@ void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) {
}
void ContinuationIndenter::moveStateToNewBlock(LineState &State) {
- // If we have already found more than one lambda introducers on this level, we
- // opt out of this because similarity between the lambdas is more important.
- if (fakeRParenSpecialCase(State))
- consumeRParens(State, *State.NextToken->MatchingParen);
-
- // For some reason, ObjC blocks are indented like continuations.
- unsigned NewIndent = State.Stack.back().LastSpace +
- (State.NextToken->Type == TT_ObjCBlockLBrace
- ? Style.ContinuationIndentWidth
- : Style.IndentWidth);
+ unsigned NestedBlockIndent = State.Stack.back().NestedBlockIndent;
+ // ObjC block sometimes follow special indentation rules.
+ unsigned NewIndent =
+ NestedBlockIndent + (State.NextToken->is(TT_ObjCBlockLBrace)
+ ? Style.ObjCBlockIndentWidth
+ : Style.IndentWidth);
State.Stack.push_back(ParenState(
NewIndent, /*NewIndentLevel=*/State.Stack.back().IndentLevel + 1,
State.Stack.back().LastSpace, /*AvoidBinPacking=*/true,
State.Stack.back().NoLineBreak));
+ State.Stack.back().NestedBlockIndent = NestedBlockIndent;
State.Stack.back().BreakBeforeParameter = true;
}
@@ -915,34 +904,17 @@ unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
return 0;
}
-static bool getRawStringLiteralPrefixPostfix(StringRef Text, StringRef &Prefix,
- StringRef &Postfix) {
- if (Text.startswith(Prefix = "R\"") || Text.startswith(Prefix = "uR\"") ||
- Text.startswith(Prefix = "UR\"") || Text.startswith(Prefix = "u8R\"") ||
- Text.startswith(Prefix = "LR\"")) {
- size_t ParenPos = Text.find('(');
- if (ParenPos != StringRef::npos) {
- StringRef Delimiter =
- Text.substr(Prefix.size(), ParenPos - Prefix.size());
- Prefix = Text.substr(0, ParenPos + 1);
- Postfix = Text.substr(Text.size() - 2 - Delimiter.size());
- return Postfix.front() == ')' && Postfix.back() == '"' &&
- Postfix.substr(1).startswith(Delimiter);
- }
- }
- return false;
-}
-
unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
LineState &State,
bool DryRun) {
// Don't break multi-line tokens other than block comments. Instead, just
// update the state.
- if (Current.Type != TT_BlockComment && Current.IsMultiline)
+ if (Current.isNot(TT_BlockComment) && Current.IsMultiline)
return addMultilineToken(Current, State);
- // Don't break implicit string literals.
- if (Current.Type == TT_ImplicitStringLiteral)
+ // Don't break implicit string literals or import statements.
+ if (Current.is(TT_ImplicitStringLiteral) ||
+ State.Line->Type == LT_ImportStatement)
return 0;
if (!Current.isStringLiteral() && !Current.is(tok::comment))
@@ -953,6 +925,12 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
unsigned ColumnLimit = getColumnLimit(State);
if (Current.isStringLiteral()) {
+ // FIXME: String literal breaking is currently disabled for Java and JS, as
+ // it requires strings to be merged using "+" which we don't support.
+ if (Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript)
+ return 0;
+
// Don't break string literals inside preprocessor directives (except for
// #define directives, as their contents are stored in separate lines and
// are not affected by this check).
@@ -983,23 +961,22 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
Text.startswith(Prefix = "u\"") || Text.startswith(Prefix = "U\"") ||
Text.startswith(Prefix = "u8\"") ||
Text.startswith(Prefix = "L\""))) ||
- (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")")) ||
- getRawStringLiteralPrefixPostfix(Text, Prefix, Postfix)) {
+ (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")"))) {
Token.reset(new BreakableStringLiteral(
Current, State.Line->Level, StartColumn, Prefix, Postfix,
State.Line->InPPDirective, Encoding, Style));
} else {
return 0;
}
- } else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) {
+ } else if (Current.is(TT_BlockComment) && Current.isTrailingComment()) {
if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
return 0;
Token.reset(new BreakableBlockComment(
Current, State.Line->Level, StartColumn, Current.OriginalColumn,
!Current.Previous, State.Line->InPPDirective, Encoding, Style));
- } else if (Current.Type == TT_LineComment &&
+ } else if (Current.is(TT_LineComment) &&
(Current.Previous == nullptr ||
- Current.Previous->Type != TT_ImplicitStringLiteral)) {
+ Current.Previous->isNot(TT_ImplicitStringLiteral))) {
if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
return 0;
Token.reset(new BreakableLineComment(Current, State.Line->Level,
@@ -1073,7 +1050,7 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
// If we break the token inside a parameter list, we need to break before
// the next parameter on all levels, so that the next parameter is clearly
// visible. Line comments already introduce a break.
- if (Current.Type != TT_LineComment) {
+ if (Current.isNot(TT_LineComment)) {
for (unsigned i = 0, e = State.Stack.size(); i != e; ++i)
State.Stack[i].BreakBeforeParameter = true;
}
@@ -1093,7 +1070,7 @@ unsigned ContinuationIndenter::getColumnLimit(const LineState &State) const {
bool ContinuationIndenter::nextIsMultilineString(const LineState &State) {
const FormatToken &Current = *State.NextToken;
- if (!Current.isStringLiteral() || Current.Type == TT_ImplicitStringLiteral)
+ if (!Current.isStringLiteral() || Current.is(TT_ImplicitStringLiteral))
return false;
// We never consider raw string literals "multiline" for the purpose of
// AlwaysBreakBeforeMultilineStrings implementation as they are special-cased
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
index 0969a8cec983..36691d945b4f 100644
--- a/lib/Format/ContinuationIndenter.h
+++ b/lib/Format/ContinuationIndenter.h
@@ -13,10 +13,11 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H
-#define LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H
+#ifndef LLVM_CLANG_LIB_FORMAT_CONTINUATIONINDENTER_H
+#define LLVM_CLANG_LIB_FORMAT_CONTINUATIONINDENTER_H
#include "Encoding.h"
+#include "FormatToken.h"
#include "clang/Format/Format.h"
#include "llvm/Support/Regex.h"
@@ -35,8 +36,9 @@ class ContinuationIndenter {
public:
/// \brief Constructs a \c ContinuationIndenter to format \p Line starting in
/// column \p FirstIndent.
- ContinuationIndenter(const FormatStyle &Style, SourceManager &SourceMgr,
- WhitespaceManager &Whitespaces,
+ ContinuationIndenter(const FormatStyle &Style,
+ const AdditionalKeywords &Keywords,
+ SourceManager &SourceMgr, WhitespaceManager &Whitespaces,
encoding::Encoding Encoding,
bool BinPackInconclusiveFunctions);
@@ -134,6 +136,7 @@ private:
bool nextIsMultilineString(const LineState &State);
FormatStyle Style;
+ const AdditionalKeywords &Keywords;
SourceManager &SourceMgr;
WhitespaceManager &Whitespaces;
encoding::Encoding Encoding;
@@ -145,14 +148,15 @@ struct ParenState {
ParenState(unsigned Indent, unsigned IndentLevel, unsigned LastSpace,
bool AvoidBinPacking, bool NoLineBreak)
: Indent(Indent), IndentLevel(IndentLevel), LastSpace(LastSpace),
- FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0),
+ NestedBlockIndent(Indent), FirstLessLess(0),
+ BreakBeforeClosingBrace(false), QuestionColumn(0),
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
NoLineBreak(NoLineBreak), LastOperatorWrapped(true), ColonPos(0),
StartOfFunctionCall(0), StartOfArraySubscripts(0),
NestedNameSpecifierContinuation(0), CallContinuation(0), VariablePos(0),
ContainsLineBreak(false), ContainsUnwrappedBuilder(0),
AlignColons(true), ObjCSelectorNameFound(false),
- HasMultipleNestedBlocks(false), JSFunctionInlined(false) {}
+ HasMultipleNestedBlocks(false), NestedBlockInlined(false) {}
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
@@ -168,6 +172,10 @@ struct ParenState {
/// OtherParameter));
unsigned LastSpace;
+ /// \brief If a block relative to this parenthesis level gets wrapped, indent
+ /// it this much.
+ unsigned NestedBlockIndent;
+
/// \brief The position the first "<<" operator encountered on each level.
///
/// Used to align "<<" operators. 0 if no such operator has been encountered
@@ -253,15 +261,17 @@ struct ParenState {
/// the same token.
bool HasMultipleNestedBlocks;
- // \brief The previous JavaScript 'function' keyword is not wrapped to a new
- // line.
- bool JSFunctionInlined;
+ // \brief The start of a nested block (e.g. lambda introducer in C++ or
+ // "function" in JavaScript) is not wrapped to a new line.
+ bool NestedBlockInlined;
bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
if (LastSpace != Other.LastSpace)
return LastSpace < Other.LastSpace;
+ if (NestedBlockIndent != Other.NestedBlockIndent)
+ return NestedBlockIndent < Other.NestedBlockIndent;
if (FirstLessLess != Other.FirstLessLess)
return FirstLessLess < Other.FirstLessLess;
if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace)
@@ -290,8 +300,8 @@ struct ParenState {
return ContainsLineBreak < Other.ContainsLineBreak;
if (ContainsUnwrappedBuilder != Other.ContainsUnwrappedBuilder)
return ContainsUnwrappedBuilder < Other.ContainsUnwrappedBuilder;
- if (JSFunctionInlined != Other.JSFunctionInlined)
- return JSFunctionInlined < Other.JSFunctionInlined;
+ if (NestedBlockInlined != Other.NestedBlockInlined)
+ return NestedBlockInlined < Other.NestedBlockInlined;
return false;
}
};
@@ -370,4 +380,4 @@ struct LineState {
} // end namespace format
} // end namespace clang
-#endif // LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H
+#endif
diff --git a/lib/Format/Encoding.h b/lib/Format/Encoding.h
index dba5174b97b4..766d29274ce6 100644
--- a/lib/Format/Encoding.h
+++ b/lib/Format/Encoding.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FORMAT_ENCODING_H
-#define LLVM_CLANG_FORMAT_ENCODING_H
+#ifndef LLVM_CLANG_LIB_FORMAT_ENCODING_H
+#define LLVM_CLANG_LIB_FORMAT_ENCODING_H
#include "clang/Basic/LLVM.h"
#include "llvm/Support/ConvertUTF.h"
@@ -143,4 +143,4 @@ inline unsigned getEscapeSequenceLength(StringRef Text) {
} // namespace format
} // namespace clang
-#endif // LLVM_CLANG_FORMAT_ENCODING_H
+#endif
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 58dd5604e427..2a4721f2b3b7 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -15,6 +15,7 @@
#include "ContinuationIndenter.h"
#include "TokenAnnotator.h"
+#include "UnwrappedLineFormatter.h"
#include "UnwrappedLineParser.h"
#include "WhitespaceManager.h"
#include "clang/Basic/Diagnostic.h"
@@ -41,6 +42,7 @@ namespace yaml {
template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
+ IO.enumCase(Value, "Java", FormatStyle::LK_Java);
IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
}
@@ -73,6 +75,17 @@ template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
IO.enumCase(Value, "All", FormatStyle::SFS_All);
IO.enumCase(Value, "true", FormatStyle::SFS_All);
IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
+ IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> {
+ static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) {
+ IO.enumCase(Value, "All", FormatStyle::BOS_All);
+ IO.enumCase(Value, "true", FormatStyle::BOS_All);
+ IO.enumCase(Value, "None", FormatStyle::BOS_None);
+ IO.enumCase(Value, "false", FormatStyle::BOS_None);
+ IO.enumCase(Value, "NonAssignment", FormatStyle::BOS_NonAssignment);
}
};
@@ -159,20 +172,24 @@ template <> struct MappingTraits<FormatStyle> {
}
IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
- IO.mapOptional("ConstructorInitializerIndentWidth",
- Style.ConstructorInitializerIndentWidth);
+ IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlinesLeft);
+ IO.mapOptional("AlignOperands", Style.AlignOperands);
IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
Style.AllowAllParametersOfDeclarationOnNextLine);
IO.mapOptional("AllowShortBlocksOnASingleLine",
Style.AllowShortBlocksOnASingleLine);
+ IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
+ Style.AllowShortCaseLabelsOnASingleLine);
IO.mapOptional("AllowShortIfStatementsOnASingleLine",
Style.AllowShortIfStatementsOnASingleLine);
IO.mapOptional("AllowShortLoopsOnASingleLine",
Style.AllowShortLoopsOnASingleLine);
IO.mapOptional("AllowShortFunctionsOnASingleLine",
Style.AllowShortFunctionsOnASingleLine);
+ IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
+ Style.AlwaysBreakAfterDefinitionReturnType);
IO.mapOptional("AlwaysBreakTemplateDeclarations",
Style.AlwaysBreakTemplateDeclarations);
IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
@@ -184,9 +201,12 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("BreakConstructorInitializersBeforeComma",
Style.BreakConstructorInitializersBeforeComma);
IO.mapOptional("BinPackParameters", Style.BinPackParameters);
+ IO.mapOptional("BinPackArguments", Style.BinPackArguments);
IO.mapOptional("ColumnLimit", Style.ColumnLimit);
IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
+ IO.mapOptional("ConstructorInitializerIndentWidth",
+ Style.ConstructorInitializerIndentWidth);
IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment);
IO.mapOptional("ExperimentalAutoDetectBinPacking",
Style.ExperimentalAutoDetectBinPacking);
@@ -199,6 +219,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
Style.KeepEmptyLinesAtTheStartOfBlocks);
IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
+ IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
IO.mapOptional("ObjCSpaceBeforeProtocolList",
Style.ObjCSpaceBeforeProtocolList);
@@ -221,10 +242,12 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("UseTab", Style.UseTab);
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
+ IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
IO.mapOptional("SpacesInCStyleCastParentheses",
Style.SpacesInCStyleCastParentheses);
+ IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
IO.mapOptional("SpacesInContainerLiterals",
Style.SpacesInContainerLiterals);
IO.mapOptional("SpaceBeforeAssignmentOperators",
@@ -305,16 +328,21 @@ FormatStyle getLLVMStyle() {
LLVMStyle.Language = FormatStyle::LK_Cpp;
LLVMStyle.AccessModifierOffset = -2;
LLVMStyle.AlignEscapedNewlinesLeft = false;
+ LLVMStyle.AlignAfterOpenBracket = true;
+ LLVMStyle.AlignOperands = true;
LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
LLVMStyle.AllowShortBlocksOnASingleLine = false;
+ LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
LLVMStyle.AllowShortLoopsOnASingleLine = false;
+ LLVMStyle.AlwaysBreakAfterDefinitionReturnType = false;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AlwaysBreakTemplateDeclarations = false;
LLVMStyle.BinPackParameters = true;
- LLVMStyle.BreakBeforeBinaryOperators = false;
+ LLVMStyle.BinPackArguments = true;
+ LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
LLVMStyle.BreakBeforeTernaryOperators = true;
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
LLVMStyle.BreakConstructorInitializersBeforeComma = false;
@@ -336,6 +364,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.MaxEmptyLinesToKeep = 1;
LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
+ LLVMStyle.ObjCBlockIndentWidth = 2;
LLVMStyle.ObjCSpaceAfterProperty = false;
LLVMStyle.ObjCSpaceBeforeProtocolList = true;
LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
@@ -343,9 +372,11 @@ FormatStyle getLLVMStyle() {
LLVMStyle.Standard = FormatStyle::LS_Cpp11;
LLVMStyle.UseTab = FormatStyle::UT_Never;
LLVMStyle.SpacesInParentheses = false;
+ LLVMStyle.SpacesInSquareBrackets = false;
LLVMStyle.SpaceInEmptyParentheses = false;
LLVMStyle.SpacesInContainerLiterals = true;
LLVMStyle.SpacesInCStyleCastParentheses = false;
+ LLVMStyle.SpaceAfterCStyleCast = false;
LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
LLVMStyle.SpaceBeforeAssignmentOperators = true;
LLVMStyle.SpacesInAngles = false;
@@ -385,10 +416,23 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
- if (Language == FormatStyle::LK_JavaScript) {
+ if (Language == FormatStyle::LK_Java) {
+ GoogleStyle.AlignAfterOpenBracket = false;
+ GoogleStyle.AlignOperands = false;
+ GoogleStyle.AlignTrailingComments = false;
+ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
+ GoogleStyle.AllowShortIfStatementsOnASingleLine = false;
+ GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
+ GoogleStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
+ GoogleStyle.ColumnLimit = 100;
+ GoogleStyle.SpaceAfterCStyleCast = true;
+ GoogleStyle.SpacesBeforeTrailingComments = 1;
+ } else if (Language == FormatStyle::LK_JavaScript) {
GoogleStyle.BreakBeforeTernaryOperators = false;
GoogleStyle.MaxEmptyLinesToKeep = 3;
GoogleStyle.SpacesInContainerLiterals = false;
+ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
+ GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
} else if (Language == FormatStyle::LK_Proto) {
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
GoogleStyle.SpacesInContainerLiterals = false;
@@ -399,13 +443,18 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
FormatStyle ChromiumStyle = getGoogleStyle(Language);
- ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
- ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
- ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
- ChromiumStyle.AllowShortLoopsOnASingleLine = false;
- ChromiumStyle.BinPackParameters = false;
- ChromiumStyle.DerivePointerAlignment = false;
- ChromiumStyle.Standard = FormatStyle::LS_Cpp03;
+ if (Language == FormatStyle::LK_Java) {
+ ChromiumStyle.AllowShortIfStatementsOnASingleLine = true;
+ ChromiumStyle.IndentWidth = 4;
+ ChromiumStyle.ContinuationIndentWidth = 8;
+ } else {
+ ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
+ ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
+ ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
+ ChromiumStyle.AllowShortLoopsOnASingleLine = false;
+ ChromiumStyle.BinPackParameters = false;
+ ChromiumStyle.DerivePointerAlignment = false;
+ }
return ChromiumStyle;
}
@@ -427,14 +476,17 @@ FormatStyle getMozillaStyle() {
FormatStyle getWebKitStyle() {
FormatStyle Style = getLLVMStyle();
Style.AccessModifierOffset = -4;
+ Style.AlignAfterOpenBracket = false;
+ Style.AlignOperands = false;
Style.AlignTrailingComments = false;
- Style.BreakBeforeBinaryOperators = true;
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
Style.BreakConstructorInitializersBeforeComma = true;
Style.Cpp11BracedListStyle = false;
Style.ColumnLimit = 0;
Style.IndentWidth = 4;
Style.NamespaceIndentation = FormatStyle::NI_Inner;
+ Style.ObjCBlockIndentWidth = 4;
Style.ObjCSpaceAfterProperty = true;
Style.PointerAlignment = FormatStyle::PAS_Left;
Style.Standard = FormatStyle::LS_Cpp03;
@@ -443,7 +495,8 @@ FormatStyle getWebKitStyle() {
FormatStyle getGNUStyle() {
FormatStyle Style = getLLVMStyle();
- Style.BreakBeforeBinaryOperators = true;
+ Style.AlwaysBreakAfterDefinitionReturnType = true;
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Style.BreakBeforeBraces = FormatStyle::BS_GNU;
Style.BreakBeforeTernaryOperators = true;
Style.Cpp11BracedListStyle = false;
@@ -542,736 +595,18 @@ std::string configurationAsText(const FormatStyle &Style) {
namespace {
-class NoColumnLimitFormatter {
-public:
- NoColumnLimitFormatter(ContinuationIndenter *Indenter) : Indenter(Indenter) {}
-
- /// \brief Formats the line starting at \p State, simply keeping all of the
- /// input's line breaking decisions.
- void format(unsigned FirstIndent, const AnnotatedLine *Line) {
- LineState State =
- Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);
- while (State.NextToken) {
- bool Newline =
- Indenter->mustBreak(State) ||
- (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
- Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
- }
- }
-
-private:
- ContinuationIndenter *Indenter;
-};
-
-class LineJoiner {
-public:
- LineJoiner(const FormatStyle &Style) : Style(Style) {}
-
- /// \brief Calculates how many lines can be merged into 1 starting at \p I.
- unsigned
- tryFitMultipleLinesInOne(unsigned Indent,
- SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
- // We can never merge stuff if there are trailing line comments.
- const AnnotatedLine *TheLine = *I;
- if (TheLine->Last->Type == TT_LineComment)
- return 0;
-
- if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
- return 0;
-
- unsigned Limit =
- Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;
- // If we already exceed the column limit, we set 'Limit' to 0. The different
- // tryMerge..() functions can then decide whether to still do merging.
- Limit = TheLine->Last->TotalLength > Limit
- ? 0
- : Limit - TheLine->Last->TotalLength;
-
- if (I + 1 == E || I[1]->Type == LT_Invalid || I[1]->First->MustBreakBefore)
- return 0;
-
- // FIXME: TheLine->Level != 0 might or might not be the right check to do.
- // If necessary, change to something smarter.
- bool MergeShortFunctions =
- Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
- (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
- TheLine->Level != 0);
-
- if (TheLine->Last->Type == TT_FunctionLBrace &&
- TheLine->First != TheLine->Last) {
- return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
- }
- if (TheLine->Last->is(tok::l_brace)) {
- return Style.BreakBeforeBraces == FormatStyle::BS_Attach
- ? tryMergeSimpleBlock(I, E, Limit)
- : 0;
- }
- if (I[1]->First->Type == TT_FunctionLBrace &&
- Style.BreakBeforeBraces != FormatStyle::BS_Attach) {
- // Check for Limit <= 2 to account for the " {".
- if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))
- return 0;
- Limit -= 2;
-
- unsigned MergedLines = 0;
- if (MergeShortFunctions) {
- MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
- // If we managed to merge the block, count the function header, which is
- // on a separate line.
- if (MergedLines > 0)
- ++MergedLines;
- }
- return MergedLines;
- }
- if (TheLine->First->is(tok::kw_if)) {
- return Style.AllowShortIfStatementsOnASingleLine
- ? tryMergeSimpleControlStatement(I, E, Limit)
- : 0;
- }
- if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
- return Style.AllowShortLoopsOnASingleLine
- ? tryMergeSimpleControlStatement(I, E, Limit)
- : 0;
- }
- if (TheLine->InPPDirective &&
- (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {
- return tryMergeSimplePPDirective(I, E, Limit);
- }
- return 0;
- }
-
-private:
- unsigned
- tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,
- unsigned Limit) {
- if (Limit == 0)
- return 0;
- if (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline)
- return 0;
- if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)
- return 0;
- if (1 + I[1]->Last->TotalLength > Limit)
- return 0;
- return 1;
- }
-
- unsigned tryMergeSimpleControlStatement(
- SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
- if (Limit == 0)
- return 0;
- if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
- Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&
- (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))
- return 0;
- if (I[1]->InPPDirective != (*I)->InPPDirective ||
- (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
- return 0;
- Limit = limitConsideringMacros(I + 1, E, Limit);
- AnnotatedLine &Line = **I;
- if (Line.Last->isNot(tok::r_paren))
- return 0;
- if (1 + I[1]->Last->TotalLength > Limit)
- return 0;
- if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,
- tok::kw_while) ||
- I[1]->First->Type == TT_LineComment)
- return 0;
- // Only inline simple if's (no nested if or else).
- if (I + 2 != E && Line.First->is(tok::kw_if) &&
- I[2]->First->is(tok::kw_else))
- return 0;
- return 1;
- }
-
- unsigned
- tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,
- unsigned Limit) {
- AnnotatedLine &Line = **I;
-
- // Don't merge ObjC @ keywords and methods.
- if (Line.First->isOneOf(tok::at, tok::minus, tok::plus))
- return 0;
-
- // Check that the current line allows merging. This depends on whether we
- // are in a control flow statements as well as several style flags.
- if (Line.First->isOneOf(tok::kw_else, tok::kw_case))
- return 0;
- if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,
- tok::kw_catch, tok::kw_for, tok::r_brace)) {
- if (!Style.AllowShortBlocksOnASingleLine)
- return 0;
- if (!Style.AllowShortIfStatementsOnASingleLine &&
- Line.First->is(tok::kw_if))
- return 0;
- if (!Style.AllowShortLoopsOnASingleLine &&
- Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))
- return 0;
- // FIXME: Consider an option to allow short exception handling clauses on
- // a single line.
- if (Line.First->isOneOf(tok::kw_try, tok::kw_catch))
- return 0;
- }
-
- FormatToken *Tok = I[1]->First;
- if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
- (Tok->getNextNonComment() == nullptr ||
- Tok->getNextNonComment()->is(tok::semi))) {
- // We merge empty blocks even if the line exceeds the column limit.
- Tok->SpacesRequiredBefore = 0;
- Tok->CanBreakBefore = true;
- return 1;
- } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace)) {
- // We don't merge short records.
- if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct))
- return 0;
-
- // Check that we still have three lines and they fit into the limit.
- if (I + 2 == E || I[2]->Type == LT_Invalid)
- return 0;
- Limit = limitConsideringMacros(I + 2, E, Limit);
-
- if (!nextTwoLinesFitInto(I, Limit))
- return 0;
-
- // Second, check that the next line does not contain any braces - if it
- // does, readability declines when putting it into a single line.
- if (I[1]->Last->Type == TT_LineComment)
- return 0;
- do {
- if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
- return 0;
- Tok = Tok->Next;
- } while (Tok);
-
- // Last, check that the third line starts with a closing brace.
- Tok = I[2]->First;
- if (Tok->isNot(tok::r_brace))
- return 0;
-
- return 2;
- }
- return 0;
- }
-
- /// Returns the modified column limit for \p I if it is inside a macro and
- /// needs a trailing '\'.
- unsigned
- limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,
- unsigned Limit) {
- if (I[0]->InPPDirective && I + 1 != E &&
- !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {
- return Limit < 2 ? 0 : Limit - 2;
- }
- return Limit;
- }
-
- bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- unsigned Limit) {
- if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
- return false;
- return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
- }
-
- bool containsMustBreak(const AnnotatedLine *Line) {
- for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
- if (Tok->MustBreakBefore)
- return true;
- }
- return false;
- }
-
- const FormatStyle &Style;
-};
-
-class UnwrappedLineFormatter {
-public:
- UnwrappedLineFormatter(ContinuationIndenter *Indenter,
- WhitespaceManager *Whitespaces,
- const FormatStyle &Style)
- : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
- Joiner(Style) {}
-
- unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
- int AdditionalIndent = 0, bool FixBadIndentation = false) {
- // Try to look up already computed penalty in DryRun-mode.
- std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
- &Lines, AdditionalIndent);
- auto CacheIt = PenaltyCache.find(CacheKey);
- if (DryRun && CacheIt != PenaltyCache.end())
- return CacheIt->second;
-
- assert(!Lines.empty());
- unsigned Penalty = 0;
- std::vector<int> IndentForLevel;
- for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)
- IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
- const AnnotatedLine *PreviousLine = nullptr;
- for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),
- E = Lines.end();
- I != E; ++I) {
- const AnnotatedLine &TheLine = **I;
- const FormatToken *FirstTok = TheLine.First;
- int Offset = getIndentOffset(*FirstTok);
-
- // Determine indent and try to merge multiple unwrapped lines.
- unsigned Indent;
- if (TheLine.InPPDirective) {
- Indent = TheLine.Level * Style.IndentWidth;
- } else {
- while (IndentForLevel.size() <= TheLine.Level)
- IndentForLevel.push_back(-1);
- IndentForLevel.resize(TheLine.Level + 1);
- Indent = getIndent(IndentForLevel, TheLine.Level);
- }
- unsigned LevelIndent = Indent;
- if (static_cast<int>(Indent) + Offset >= 0)
- Indent += Offset;
-
- // Merge multiple lines if possible.
- unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E);
- if (MergedLines > 0 && Style.ColumnLimit == 0) {
- // Disallow line merging if there is a break at the start of one of the
- // input lines.
- for (unsigned i = 0; i < MergedLines; ++i) {
- if (I[i + 1]->First->NewlinesBefore > 0)
- MergedLines = 0;
- }
- }
- if (!DryRun) {
- for (unsigned i = 0; i < MergedLines; ++i) {
- join(*I[i], *I[i + 1]);
- }
- }
- I += MergedLines;
-
- bool FixIndentation =
- FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);
- if (TheLine.First->is(tok::eof)) {
- if (PreviousLine && PreviousLine->Affected && !DryRun) {
- // Remove the file's trailing whitespace.
- unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);
- Whitespaces->replaceWhitespace(*TheLine.First, Newlines,
- /*IndentLevel=*/0, /*Spaces=*/0,
- /*TargetColumn=*/0);
- }
- } else if (TheLine.Type != LT_Invalid &&
- (TheLine.Affected || FixIndentation)) {
- if (FirstTok->WhitespaceRange.isValid()) {
- if (!DryRun)
- formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level,
- Indent, TheLine.InPPDirective);
- } else {
- Indent = LevelIndent = FirstTok->OriginalColumn;
- }
-
- // If everything fits on a single line, just put it there.
- unsigned ColumnLimit = Style.ColumnLimit;
- if (I + 1 != E) {
- AnnotatedLine *NextLine = I[1];
- if (NextLine->InPPDirective && !NextLine->First->HasUnescapedNewline)
- ColumnLimit = getColumnLimit(TheLine.InPPDirective);
- }
-
- if (TheLine.Last->TotalLength + Indent <= ColumnLimit) {
- LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun);
- while (State.NextToken) {
- formatChildren(State, /*Newline=*/false, /*DryRun=*/false, Penalty);
- Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
- }
- } else if (Style.ColumnLimit == 0) {
- // FIXME: Implement nested blocks for ColumnLimit = 0.
- NoColumnLimitFormatter Formatter(Indenter);
- if (!DryRun)
- Formatter.format(Indent, &TheLine);
- } else {
- Penalty += format(TheLine, Indent, DryRun);
- }
-
- if (!TheLine.InPPDirective)
- IndentForLevel[TheLine.Level] = LevelIndent;
- } else if (TheLine.ChildrenAffected) {
- format(TheLine.Children, DryRun);
- } else {
- // Format the first token if necessary, and notify the WhitespaceManager
- // about the unchanged whitespace.
- for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
- if (Tok == TheLine.First &&
- (Tok->NewlinesBefore > 0 || Tok->IsFirst)) {
- unsigned LevelIndent = Tok->OriginalColumn;
- if (!DryRun) {
- // Remove trailing whitespace of the previous line.
- if ((PreviousLine && PreviousLine->Affected) ||
- TheLine.LeadingEmptyLinesAffected) {
- formatFirstToken(*Tok, PreviousLine, TheLine.Level, LevelIndent,
- TheLine.InPPDirective);
- } else {
- Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
- }
- }
-
- if (static_cast<int>(LevelIndent) - Offset >= 0)
- LevelIndent -= Offset;
- if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)
- IndentForLevel[TheLine.Level] = LevelIndent;
- } else if (!DryRun) {
- Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
- }
- }
- }
- if (!DryRun) {
- for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
- Tok->Finalized = true;
- }
- }
- PreviousLine = *I;
- }
- PenaltyCache[CacheKey] = Penalty;
- return Penalty;
- }
-
-private:
- /// \brief Formats an \c AnnotatedLine and returns the penalty.
- ///
- /// If \p DryRun is \c false, directly applies the changes.
- unsigned format(const AnnotatedLine &Line, unsigned FirstIndent,
- bool DryRun) {
- LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
-
- // If the ObjC method declaration does not fit on a line, we should format
- // it with one arg per line.
- if (State.Line->Type == LT_ObjCMethodDecl)
- State.Stack.back().BreakBeforeParameter = true;
-
- // Find best solution in solution space.
- return analyzeSolutionSpace(State, DryRun);
- }
-
- /// \brief An edge in the solution space from \c Previous->State to \c State,
- /// inserting a newline dependent on the \c NewLine.
- struct StateNode {
- StateNode(const LineState &State, bool NewLine, StateNode *Previous)
- : State(State), NewLine(NewLine), Previous(Previous) {}
- LineState State;
- bool NewLine;
- StateNode *Previous;
- };
-
- /// \brief A pair of <penalty, count> that is used to prioritize the BFS on.
- ///
- /// In case of equal penalties, we want to prefer states that were inserted
- /// first. During state generation we make sure that we insert states first
- /// that break the line as late as possible.
- typedef std::pair<unsigned, unsigned> OrderedPenalty;
-
- /// \brief An item in the prioritized BFS search queue. The \c StateNode's
- /// \c State has the given \c OrderedPenalty.
- typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
-
- /// \brief The BFS queue type.
- typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
- std::greater<QueueItem> > QueueType;
-
- /// \brief Get the offset of the line relatively to the level.
- ///
- /// For example, 'public:' labels in classes are offset by 1 or 2
- /// characters to the left from their level.
- int getIndentOffset(const FormatToken &RootToken) {
- if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())
- return Style.AccessModifierOffset;
- return 0;
- }
-
- /// \brief Add a new line and the required indent before the first Token
- /// of the \c UnwrappedLine if there was no structural parsing error.
- void formatFirstToken(FormatToken &RootToken,
- const AnnotatedLine *PreviousLine, unsigned IndentLevel,
- unsigned Indent, bool InPPDirective) {
- unsigned Newlines =
- std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
- // Remove empty lines before "}" where applicable.
- if (RootToken.is(tok::r_brace) &&
- (!RootToken.Next ||
- (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))
- Newlines = std::min(Newlines, 1u);
- if (Newlines == 0 && !RootToken.IsFirst)
- Newlines = 1;
- if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
- Newlines = 0;
-
- // Remove empty lines after "{".
- if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
- PreviousLine->Last->is(tok::l_brace) &&
- PreviousLine->First->isNot(tok::kw_namespace))
- Newlines = 1;
-
- // Insert extra new line before access specifiers.
- if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&
- RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)
- ++Newlines;
-
- // Remove empty lines after access specifiers.
- if (PreviousLine && PreviousLine->First->isAccessSpecifier())
- Newlines = std::min(1u, Newlines);
-
- Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
- Indent, InPPDirective &&
- !RootToken.HasUnescapedNewline);
- }
-
- /// \brief Get the indent of \p Level from \p IndentForLevel.
- ///
- /// \p IndentForLevel must contain the indent for the level \c l
- /// at \p IndentForLevel[l], or a value < 0 if the indent for
- /// that level is unknown.
- unsigned getIndent(const std::vector<int> IndentForLevel, unsigned Level) {
- if (IndentForLevel[Level] != -1)
- return IndentForLevel[Level];
- if (Level == 0)
- return 0;
- return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;
- }
-
- void join(AnnotatedLine &A, const AnnotatedLine &B) {
- assert(!A.Last->Next);
- assert(!B.First->Previous);
- if (B.Affected)
- A.Affected = true;
- A.Last->Next = B.First;
- B.First->Previous = A.Last;
- B.First->CanBreakBefore = true;
- unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;
- for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {
- Tok->TotalLength += LengthA;
- A.Last = Tok;
- }
- }
-
- unsigned getColumnLimit(bool InPPDirective) const {
- // In preprocessor directives reserve two chars for trailing " \"
- return Style.ColumnLimit - (InPPDirective ? 2 : 0);
- }
-
- struct CompareLineStatePointers {
- bool operator()(LineState *obj1, LineState *obj2) const {
- return *obj1 < *obj2;
- }
- };
-
- /// \brief Analyze the entire solution space starting from \p InitialState.
- ///
- /// This implements a variant of Dijkstra's algorithm on the graph that spans
- /// the solution space (\c LineStates are the nodes). The algorithm tries to
- /// find the shortest path (the one with lowest penalty) from \p InitialState
- /// to a state where all tokens are placed. Returns the penalty.
- ///
- /// If \p DryRun is \c false, directly applies the changes.
- unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false) {
- std::set<LineState *, CompareLineStatePointers> Seen;
-
- // Increasing count of \c StateNode items we have created. This is used to
- // create a deterministic order independent of the container.
- unsigned Count = 0;
- QueueType Queue;
-
- // Insert start element into queue.
- StateNode *Node =
- new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);
- Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
- ++Count;
-
- unsigned Penalty = 0;
-
- // While not empty, take first element and follow edges.
- while (!Queue.empty()) {
- Penalty = Queue.top().first.first;
- StateNode *Node = Queue.top().second;
- if (!Node->State.NextToken) {
- DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");
- break;
- }
- Queue.pop();
-
- // Cut off the analysis of certain solutions if the analysis gets too
- // complex. See description of IgnoreStackForComparison.
- if (Count > 10000)
- Node->State.IgnoreStackForComparison = true;
-
- if (!Seen.insert(&Node->State).second)
- // State already examined with lower penalty.
- continue;
-
- FormatDecision LastFormat = Node->State.NextToken->Decision;
- if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
- addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue);
- if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
- addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue);
- }
-
- if (Queue.empty()) {
- // We were unable to find a solution, do nothing.
- // FIXME: Add diagnostic?
- DEBUG(llvm::dbgs() << "Could not find a solution.\n");
- return 0;
- }
-
- // Reconstruct the solution.
- if (!DryRun)
- reconstructPath(InitialState, Queue.top().second);
-
- DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count << "\n");
- DEBUG(llvm::dbgs() << "---\n");
-
- return Penalty;
- }
-
- void reconstructPath(LineState &State, StateNode *Current) {
- std::deque<StateNode *> Path;
- // We do not need a break before the initial token.
- while (Current->Previous) {
- Path.push_front(Current);
- Current = Current->Previous;
- }
- for (std::deque<StateNode *>::iterator I = Path.begin(), E = Path.end();
- I != E; ++I) {
- unsigned Penalty = 0;
- formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);
- Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);
-
- DEBUG({
- if ((*I)->NewLine) {
- llvm::dbgs() << "Penalty for placing "
- << (*I)->Previous->State.NextToken->Tok.getName() << ": "
- << Penalty << "\n";
- }
- });
- }
- }
-
- /// \brief Add the following state to the analysis queue \c Queue.
- ///
- /// Assume the current state is \p PreviousNode and has been reached with a
- /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
- void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
- bool NewLine, unsigned *Count, QueueType *Queue) {
- if (NewLine && !Indenter->canBreak(PreviousNode->State))
- return;
- if (!NewLine && Indenter->mustBreak(PreviousNode->State))
- return;
-
- StateNode *Node = new (Allocator.Allocate())
- StateNode(PreviousNode->State, NewLine, PreviousNode);
- if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))
- return;
-
- Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
-
- Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
- ++(*Count);
- }
-
- /// \brief If the \p State's next token is an r_brace closing a nested block,
- /// format the nested block before it.
- ///
- /// Returns \c true if all children could be placed successfully and adapts
- /// \p Penalty as well as \p State. If \p DryRun is false, also directly
- /// creates changes using \c Whitespaces.
- ///
- /// The crucial idea here is that children always get formatted upon
- /// encountering the closing brace right after the nested block. Now, if we
- /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is
- /// \c false), the entire block has to be kept on the same line (which is only
- /// possible if it fits on the line, only contains a single statement, etc.
- ///
- /// If \p NewLine is true, we format the nested block on separate lines, i.e.
- /// break after the "{", format all lines with correct indentation and the put
- /// the closing "}" on yet another new line.
- ///
- /// This enables us to keep the simple structure of the
- /// \c UnwrappedLineFormatter, where we only have two options for each token:
- /// break or don't break.
- bool formatChildren(LineState &State, bool NewLine, bool DryRun,
- unsigned &Penalty) {
- FormatToken &Previous = *State.NextToken->Previous;
- const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
- if (!LBrace || LBrace->isNot(tok::l_brace) ||
- LBrace->BlockKind != BK_Block || Previous.Children.size() == 0)
- // The previous token does not open a block. Nothing to do. We don't
- // assert so that we can simply call this function for all tokens.
- return true;
-
- if (NewLine) {
- int AdditionalIndent =
- State.FirstIndent - State.Line->Level * Style.IndentWidth;
- if (State.Stack.size() < 2 ||
- !State.Stack[State.Stack.size() - 2].JSFunctionInlined) {
- AdditionalIndent = State.Stack.back().Indent -
- Previous.Children[0]->Level * Style.IndentWidth;
- }
-
- Penalty += format(Previous.Children, DryRun, AdditionalIndent,
- /*FixBadIndentation=*/true);
- return true;
- }
-
- // Cannot merge multiple statements into a single line.
- if (Previous.Children.size() > 1)
- return false;
-
- // Cannot merge into one line if this line ends on a comment.
- if (Previous.is(tok::comment))
- return false;
-
- // We can't put the closing "}" on a line with a trailing comment.
- if (Previous.Children[0]->Last->isTrailingComment())
- return false;
-
- // If the child line exceeds the column limit, we wouldn't want to merge it.
- // We add +2 for the trailing " }".
- if (Style.ColumnLimit > 0 &&
- Previous.Children[0]->Last->TotalLength + State.Column + 2 >
- Style.ColumnLimit)
- return false;
-
- if (!DryRun) {
- Whitespaces->replaceWhitespace(
- *Previous.Children[0]->First,
- /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,
- /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
- }
- Penalty += format(*Previous.Children[0], State.Column + 1, DryRun);
-
- State.Column += 1 + Previous.Children[0]->Last->TotalLength;
- return true;
- }
-
- ContinuationIndenter *Indenter;
- WhitespaceManager *Whitespaces;
- FormatStyle Style;
- LineJoiner Joiner;
-
- llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
-
- // Cache to store the penalty of formatting a vector of AnnotatedLines
- // starting from a specific additional offset. Improves performance if there
- // are many nested blocks.
- std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
- unsigned> PenaltyCache;
-};
-
class FormatTokenLexer {
public:
- FormatTokenLexer(Lexer &Lex, SourceManager &SourceMgr, FormatStyle &Style,
+ FormatTokenLexer(SourceManager &SourceMgr, FileID ID, FormatStyle &Style,
encoding::Encoding Encoding)
: FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false),
- Column(0), TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr),
- Style(Style), IdentTable(getFormattingLangOpts()), Encoding(Encoding),
- FirstInLineIndex(0) {
- Lex.SetKeepWhitespaceMode(true);
+ Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID),
+ Style(Style), IdentTable(getFormattingLangOpts(Style)),
+ Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0),
+ FormattingDisabled(false) {
+ Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr,
+ getFormattingLangOpts(Style)));
+ Lex->SetKeepWhitespaceMode(true);
for (const std::string &ForEachMacro : Style.ForEachMacros)
ForEachMacros.push_back(&IdentTable.get(ForEachMacro));
@@ -1290,7 +625,7 @@ public:
return Tokens;
}
- IdentifierTable &getIdentTable() { return IdentTable; }
+ const AdditionalKeywords &getKeywords() { return Keywords; }
private:
void tryMergePreviousTokens() {
@@ -1300,10 +635,10 @@ private:
return;
if (Style.Language == FormatStyle::LK_JavaScript) {
- if (tryMergeEscapeSequence())
- return;
if (tryMergeJSRegexLiteral())
return;
+ if (tryMergeEscapeSequence())
+ return;
static tok::TokenKind JSIdentity[] = { tok::equalequal, tok::equal };
static tok::TokenKind JSNotIdentity[] = { tok::exclaimequal, tok::equal };
@@ -1351,14 +686,14 @@ private:
if (Tokens.size() < 2)
return false;
FormatToken *Previous = Tokens[Tokens.size() - 2];
- if (Previous->isNot(tok::unknown) || Previous->TokenText != "\\" ||
- Tokens.back()->NewlinesBefore != 0)
+ if (Previous->isNot(tok::unknown) || Previous->TokenText != "\\")
return false;
- Previous->ColumnWidth += Tokens.back()->ColumnWidth;
+ ++Previous->ColumnWidth;
StringRef Text = Previous->TokenText;
- Previous->TokenText =
- StringRef(Text.data(), Text.size() + Tokens.back()->TokenText.size());
+ Previous->TokenText = StringRef(Text.data(), Text.size() + 1);
+ resetLexer(SourceMgr.getFileOffset(Tokens.back()->Tok.getLocation()) + 1);
Tokens.resize(Tokens.size() - 1);
+ Column = Previous->OriginalColumn + Previous->ColumnWidth;
return true;
}
@@ -1368,9 +703,18 @@ private:
// "(;,{}![:?", a binary operator or 'return', as those cannot be followed by
// a division.
bool tryMergeJSRegexLiteral() {
- if (Tokens.size() < 2 || Tokens.back()->isNot(tok::slash) ||
- (Tokens[Tokens.size() - 2]->is(tok::unknown) &&
- Tokens[Tokens.size() - 2]->TokenText == "\\"))
+ if (Tokens.size() < 2)
+ return false;
+ // If a regex literal ends in "\//", this gets represented by an unknown
+ // token "\" and a comment.
+ bool MightEndWithEscapedSlash =
+ Tokens.back()->is(tok::comment) &&
+ Tokens.back()->TokenText.startswith("//") &&
+ Tokens[Tokens.size() - 2]->TokenText == "\\";
+ if (!MightEndWithEscapedSlash &&
+ (Tokens.back()->isNot(tok::slash) ||
+ (Tokens[Tokens.size() - 2]->is(tok::unknown) &&
+ Tokens[Tokens.size() - 2]->TokenText == "\\")))
return false;
unsigned TokenCount = 0;
unsigned LastColumn = Tokens.back()->OriginalColumn;
@@ -1381,6 +725,12 @@ private:
tok::exclaim, tok::l_square, tok::colon, tok::comma,
tok::question, tok::kw_return) ||
I[1]->isBinaryOperator())) {
+ if (MightEndWithEscapedSlash) {
+ // This regex literal ends in '\//'. Skip past the '//' of the last
+ // token and re-start lexing from there.
+ SourceLocation Loc = Tokens.back()->Tok.getLocation();
+ resetLexer(SourceMgr.getFileOffset(Loc) + 2);
+ }
Tokens.resize(Tokens.size() - TokenCount);
Tokens.back()->Tok.setKind(tok::unknown);
Tokens.back()->Type = TT_RegexLiteral;
@@ -1544,7 +894,6 @@ private:
Column += Style.TabWidth - Column % Style.TabWidth;
break;
case '\\':
- ++Column;
if (i + 1 == e || (FormatTok->TokenText[i + 1] != '\r' &&
FormatTok->TokenText[i + 1] != '\n'))
FormatTok->Type = TT_ImplicitStringLiteral;
@@ -1556,7 +905,7 @@ private:
}
}
- if (FormatTok->Type == TT_ImplicitStringLiteral)
+ if (FormatTok->is(TT_ImplicitStringLiteral))
break;
WhitespaceLength += FormatTok->Tok.getLength();
@@ -1590,6 +939,11 @@ private:
IdentifierInfo &Info = IdentTable.get(FormatTok->TokenText);
FormatTok->Tok.setIdentifierInfo(&Info);
FormatTok->Tok.setKind(Info.getTokenID());
+ if (Style.Language == FormatStyle::LK_Java &&
+ FormatTok->isOneOf(tok::kw_struct, tok::kw_union, tok::kw_delete)) {
+ FormatTok->Tok.setKind(tok::identifier);
+ FormatTok->Tok.setIdentifierInfo(nullptr);
+ }
} else if (FormatTok->Tok.is(tok::greatergreater)) {
FormatTok->Tok.setKind(tok::greater);
FormatTok->TokenText = FormatTok->TokenText.substr(0, 1);
@@ -1633,10 +987,12 @@ private:
bool GreaterStashed;
unsigned Column;
unsigned TrailingWhitespace;
- Lexer &Lex;
+ std::unique_ptr<Lexer> Lex;
SourceManager &SourceMgr;
+ FileID ID;
FormatStyle &Style;
IdentifierTable IdentTable;
+ AdditionalKeywords Keywords;
encoding::Encoding Encoding;
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
// Index (in 'Tokens') of the last token that starts a new line.
@@ -1644,8 +1000,10 @@ private:
SmallVector<FormatToken *, 16> Tokens;
SmallVector<IdentifierInfo *, 8> ForEachMacros;
+ bool FormattingDisabled;
+
void readRawToken(FormatToken &Tok) {
- Lex.LexFromRawLexer(Tok.Tok);
+ Lex->LexFromRawLexer(Tok.Tok);
Tok.TokenText = StringRef(SourceMgr.getCharacterData(Tok.Tok.getLocation()),
Tok.Tok.getLength());
// For formatting, treat unterminated string literals like normal string
@@ -1659,6 +1017,26 @@ private:
Tok.Tok.setKind(tok::char_constant);
}
}
+
+ if (Tok.is(tok::comment) && (Tok.TokenText == "// clang-format on" ||
+ Tok.TokenText == "/* clang-format on */")) {
+ FormattingDisabled = false;
+ }
+
+ Tok.Finalized = FormattingDisabled;
+
+ if (Tok.is(tok::comment) && (Tok.TokenText == "// clang-format off" ||
+ Tok.TokenText == "/* clang-format off */")) {
+ FormattingDisabled = true;
+ }
+ }
+
+ void resetLexer(unsigned Offset) {
+ StringRef Buffer = SourceMgr.getBufferData(ID);
+ Lex.reset(new Lexer(SourceMgr.getLocForStartOfFile(ID),
+ getFormattingLangOpts(Style), Buffer.begin(),
+ Buffer.begin() + Offset, Buffer.end()));
+ Lex->SetKeepWhitespaceMode(true);
}
};
@@ -1666,6 +1044,8 @@ static StringRef getLanguageName(FormatStyle::LanguageKind Language) {
switch (Language) {
case FormatStyle::LK_Cpp:
return "C++";
+ case FormatStyle::LK_Java:
+ return "Java";
case FormatStyle::LK_JavaScript:
return "JavaScript";
case FormatStyle::LK_Proto:
@@ -1677,12 +1057,13 @@ static StringRef getLanguageName(FormatStyle::LanguageKind Language) {
class Formatter : public UnwrappedLineConsumer {
public:
- Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr,
- const std::vector<CharSourceRange> &Ranges)
- : Style(Style), Lex(Lex), SourceMgr(SourceMgr),
- Whitespaces(SourceMgr, Style, inputUsesCRLF(Lex.getBuffer())),
+ Formatter(const FormatStyle &Style, SourceManager &SourceMgr, FileID ID,
+ ArrayRef<CharSourceRange> Ranges)
+ : Style(Style), ID(ID), SourceMgr(SourceMgr),
+ Whitespaces(SourceMgr, Style,
+ inputUsesCRLF(SourceMgr.getBufferData(ID))),
Ranges(Ranges.begin(), Ranges.end()), UnwrappedLines(1),
- Encoding(encoding::detectEncoding(Lex.getBuffer())) {
+ Encoding(encoding::detectEncoding(SourceMgr.getBufferData(ID))) {
DEBUG(llvm::dbgs() << "File encoding: "
<< (Encoding == encoding::Encoding_UTF8 ? "UTF8"
: "unknown")
@@ -1693,9 +1074,10 @@ public:
tooling::Replacements format() {
tooling::Replacements Result;
- FormatTokenLexer Tokens(Lex, SourceMgr, Style, Encoding);
+ FormatTokenLexer Tokens(SourceMgr, ID, Style, Encoding);
- UnwrappedLineParser Parser(Style, Tokens.lex(), *this);
+ UnwrappedLineParser Parser(Style, Tokens.getKeywords(), Tokens.lex(),
+ *this);
bool StructuralError = Parser.parse();
assert(UnwrappedLines.rbegin()->empty());
for (unsigned Run = 0, RunE = UnwrappedLines.size(); Run + 1 != RunE;
@@ -1726,7 +1108,7 @@ public:
tooling::Replacements format(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
bool StructuralError, FormatTokenLexer &Tokens) {
- TokenAnnotator Annotator(Style, Tokens.getIdentTable().get("in"));
+ TokenAnnotator Annotator(Style, Tokens.getKeywords());
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Annotator.annotate(*AnnotatedLines[i]);
}
@@ -1737,7 +1119,8 @@ public:
computeAffectedLines(AnnotatedLines.begin(), AnnotatedLines.end());
Annotator.setCommentLineLevels(AnnotatedLines);
- ContinuationIndenter Indenter(Style, SourceMgr, Whitespaces, Encoding,
+ ContinuationIndenter Indenter(Style, Tokens.getKeywords(), SourceMgr,
+ Whitespaces, Encoding,
BinPackInconclusiveFunctions);
UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style);
Formatter.format(AnnotatedLines, /*DryRun=*/false);
@@ -1852,8 +1235,7 @@ private:
if (!IncludeLeadingNewlines)
Start = Start.getLocWithOffset(First.LastNewlineOffset);
SourceLocation End = Last.getStartOfNonWhitespace();
- if (Last.TokenText.size() > 0)
- End = End.getLocWithOffset(Last.TokenText.size() - 1);
+ End = End.getLocWithOffset(Last.TokenText.size());
CharSourceRange Range = CharSourceRange::getCharRange(Start, End);
return affectsCharSourceRange(Range);
}
@@ -1895,7 +1277,7 @@ private:
continue;
FormatToken *Tok = AnnotatedLines[i]->First->Next;
while (Tok->Next) {
- if (Tok->Type == TT_PointerOrReference) {
+ if (Tok->is(TT_PointerOrReference)) {
bool SpacesBefore =
Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
bool SpacesAfter = Tok->Next->WhitespaceRange.getBegin() !=
@@ -1907,11 +1289,10 @@ private:
}
if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
- if (Tok->is(tok::coloncolon) &&
- Tok->Previous->Type == TT_TemplateOpener)
+ if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
HasCpp03IncompatibleFormat = true;
- if (Tok->Type == TT_TemplateCloser &&
- Tok->Previous->Type == TT_TemplateCloser)
+ if (Tok->is(TT_TemplateCloser) &&
+ Tok->Previous->is(TT_TemplateCloser))
HasCpp03IncompatibleFormat = true;
}
@@ -1947,7 +1328,7 @@ private:
}
FormatStyle Style;
- Lexer &Lex;
+ FileID ID;
SourceManager &SourceMgr;
WhitespaceManager Whitespaces;
SmallVector<CharSourceRange, 8> Ranges;
@@ -1961,49 +1342,59 @@ private:
tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
SourceManager &SourceMgr,
- std::vector<CharSourceRange> Ranges) {
- if (Style.DisableFormat) {
- tooling::Replacements EmptyResult;
- return EmptyResult;
- }
+ ArrayRef<CharSourceRange> Ranges) {
+ if (Style.DisableFormat)
+ return tooling::Replacements();
+ return reformat(Style, SourceMgr,
+ SourceMgr.getFileID(Lex.getSourceLocation()), Ranges);
+}
- Formatter formatter(Style, Lex, SourceMgr, Ranges);
+tooling::Replacements reformat(const FormatStyle &Style,
+ SourceManager &SourceMgr, FileID ID,
+ ArrayRef<CharSourceRange> Ranges) {
+ if (Style.DisableFormat)
+ return tooling::Replacements();
+ Formatter formatter(Style, SourceMgr, ID, Ranges);
return formatter.format();
}
tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
- std::vector<tooling::Range> Ranges,
+ ArrayRef<tooling::Range> Ranges,
StringRef FileName) {
+ if (Style.DisableFormat)
+ return tooling::Replacements();
+
FileManager Files((FileSystemOptions()));
DiagnosticsEngine Diagnostics(
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
new DiagnosticOptions);
SourceManager SourceMgr(Diagnostics, Files);
- llvm::MemoryBuffer *Buf = llvm::MemoryBuffer::getMemBuffer(Code, FileName);
+ std::unique_ptr<llvm::MemoryBuffer> Buf =
+ llvm::MemoryBuffer::getMemBuffer(Code, FileName);
const clang::FileEntry *Entry =
Files.getVirtualFile(FileName, Buf->getBufferSize(), 0);
- SourceMgr.overrideFileContents(Entry, Buf);
+ SourceMgr.overrideFileContents(Entry, std::move(Buf));
FileID ID =
SourceMgr.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User);
- Lexer Lex(ID, SourceMgr.getBuffer(ID), SourceMgr,
- getFormattingLangOpts(Style.Standard));
SourceLocation StartOfFile = SourceMgr.getLocForStartOfFile(ID);
std::vector<CharSourceRange> CharRanges;
- for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
- SourceLocation Start = StartOfFile.getLocWithOffset(Ranges[i].getOffset());
- SourceLocation End = Start.getLocWithOffset(Ranges[i].getLength());
+ for (const tooling::Range &Range : Ranges) {
+ SourceLocation Start = StartOfFile.getLocWithOffset(Range.getOffset());
+ SourceLocation End = Start.getLocWithOffset(Range.getLength());
CharRanges.push_back(CharSourceRange::getCharRange(Start, End));
}
- return reformat(Style, Lex, SourceMgr, CharRanges);
+ return reformat(Style, SourceMgr, ID, CharRanges);
}
-LangOptions getFormattingLangOpts(FormatStyle::LanguageStandard Standard) {
+LangOptions getFormattingLangOpts(const FormatStyle &Style) {
LangOptions LangOpts;
LangOpts.CPlusPlus = 1;
- LangOpts.CPlusPlus11 = Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
- LangOpts.CPlusPlus1y = Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
+ LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
+ LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.LineComment = 1;
- LangOpts.CXXOperatorNames = 1;
+ bool AlternativeOperators = Style.Language != FormatStyle::LK_JavaScript &&
+ Style.Language != FormatStyle::LK_Java;
+ LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
LangOpts.Bool = 1;
LangOpts.ObjC1 = 1;
LangOpts.ObjC2 = 1;
@@ -2022,7 +1413,9 @@ const char *StyleOptionHelpDescription =
" -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
- if (FileName.endswith_lower(".js")) {
+ if (FileName.endswith(".java")) {
+ return FormatStyle::LK_Java;
+ } else if (FileName.endswith_lower(".js")) {
return FormatStyle::LK_JavaScript;
} else if (FileName.endswith_lower(".proto") ||
FileName.endswith_lower(".protodevel")) {
diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp
index c91d25f46de1..badb3a39c82c 100644
--- a/lib/Format/FormatToken.cpp
+++ b/lib/Format/FormatToken.cpp
@@ -131,9 +131,15 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
if (!Token->MatchingParen || Token->isNot(tok::l_brace))
return;
- // In C++11 braced list style, we should not format in columns unless we allow
- // bin-packing of function parameters.
- if (Style.Cpp11BracedListStyle && !Style.BinPackParameters)
+ // In C++11 braced list style, we should not format in columns unless they
+ // have many items (20 or more) or we allow bin-packing of function
+ // parameters.
+ if (Style.Cpp11BracedListStyle && !Style.BinPackParameters &&
+ Commas.size() < 19)
+ return;
+
+ // Column format doesn't really make sense if we don't align after brackets.
+ if (!Style.AlignAfterOpenBracket)
return;
FormatToken *ItemBegin = Token->Next;
@@ -143,6 +149,9 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
// trailing comments which are otherwise ignored for column alignment.
SmallVector<unsigned, 8> EndOfLineItemLength;
+ unsigned MinItemLength = Style.ColumnLimit;
+ unsigned MaxItemLength = 0;
+
for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i) {
// Skip comments on their own line.
while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment())
@@ -169,6 +178,9 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
ItemEnd = Commas[i];
// The comma is counted as part of the item when calculating the length.
ItemLengths.push_back(CodePointsBetween(ItemBegin, ItemEnd));
+ MinItemLength = std::min(MinItemLength, ItemLengths.back());
+ MaxItemLength = std::max(MaxItemLength, ItemLengths.back());
+
// Consume trailing comments so the are included in EndOfLineItemLength.
if (ItemEnd->Next && !ItemEnd->Next->HasUnescapedNewline &&
ItemEnd->Next->isTrailingComment())
@@ -184,8 +196,10 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
// If this doesn't have a nested list, we require at least 6 elements in order
// create a column layout. If it has a nested list, column layout ensures one
- // list element per line.
- if (HasNestedBracedList || Commas.size() < 5 || Token->NestingLevel != 0)
+ // list element per line. If the difference between the shortest and longest
+ // element is too large, column layout would create too much whitespace.
+ if (HasNestedBracedList || Commas.size() < 5 || Token->NestingLevel != 0 ||
+ MaxItemLength - MinItemLength > 10)
return;
// We can never place more than ColumnLimit / 3 items in a row (because of the
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index c376c5009559..4811e02dd228 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -13,9 +13,10 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FORMAT_FORMAT_TOKEN_H
-#define LLVM_CLANG_FORMAT_FORMAT_TOKEN_H
+#ifndef LLVM_CLANG_LIB_FORMAT_FORMATTOKEN_H
+#define LLVM_CLANG_LIB_FORMAT_FORMATTOKEN_H
+#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
@@ -46,7 +47,10 @@ enum TokenType {
TT_ImplicitStringLiteral,
TT_InheritanceColon,
TT_InlineASMColon,
+ TT_JavaAnnotation,
+ TT_LambdaArrow,
TT_LambdaLSquare,
+ TT_LeadingJavaAnnotation,
TT_LineComment,
TT_ObjCBlockLBrace,
TT_ObjCBlockLParen,
@@ -267,29 +271,36 @@ struct FormatToken {
bool IsForEachMacro;
bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
-
- bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
+ bool is(TokenType TT) const { return Type == TT; }
+ bool is(const IdentifierInfo *II) const {
+ return II && II == Tok.getIdentifierInfo();
+ }
+ template <typename A, typename B> bool isOneOf(A K1, B K2) const {
return is(K1) || is(K2);
}
-
- bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3) const {
+ template <typename A, typename B, typename C>
+ bool isOneOf(A K1, B K2, C K3) const {
return is(K1) || is(K2) || is(K3);
}
-
- bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3,
- tok::TokenKind K4, tok::TokenKind K5 = tok::NUM_TOKENS,
- tok::TokenKind K6 = tok::NUM_TOKENS,
- tok::TokenKind K7 = tok::NUM_TOKENS,
- tok::TokenKind K8 = tok::NUM_TOKENS,
- tok::TokenKind K9 = tok::NUM_TOKENS,
- tok::TokenKind K10 = tok::NUM_TOKENS,
- tok::TokenKind K11 = tok::NUM_TOKENS,
- tok::TokenKind K12 = tok::NUM_TOKENS) const {
+ template <typename A, typename B, typename C, typename D>
+ bool isOneOf(A K1, B K2, C K3, D K4) const {
+ return is(K1) || is(K2) || is(K3) || is(K4);
+ }
+ template <typename A, typename B, typename C, typename D, typename E>
+ bool isOneOf(A K1, B K2, C K3, D K4, E K5) const {
+ return is(K1) || is(K2) || is(K3) || is(K4) || is(K5);
+ }
+ template <typename T>
+ bool isOneOf(T K1, T K2, T K3, T K4, T K5, T K6, T K7 = tok::NUM_TOKENS,
+ T K8 = tok::NUM_TOKENS, T K9 = tok::NUM_TOKENS,
+ T K10 = tok::NUM_TOKENS, T K11 = tok::NUM_TOKENS,
+ T K12 = tok::NUM_TOKENS) const {
return is(K1) || is(K2) || is(K3) || is(K4) || is(K5) || is(K6) || is(K7) ||
is(K8) || is(K9) || is(K10) || is(K11) || is(K12);
}
- bool isNot(tok::TokenKind Kind) const { return Tok.isNot(Kind); }
+ template <typename T> bool isNot(T Kind) const { return !is(Kind); }
+
bool isStringLiteral() const { return tok::isStringLiteral(Tok.getKind()); }
bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const {
@@ -313,19 +324,19 @@ struct FormatToken {
/// \brief Returns whether \p Tok is ([{ or a template opening <.
bool opensScope() const {
- return isOneOf(tok::l_paren, tok::l_brace, tok::l_square) ||
- Type == TT_TemplateOpener;
+ return isOneOf(tok::l_paren, tok::l_brace, tok::l_square,
+ TT_TemplateOpener);
}
/// \brief Returns whether \p Tok is )]} or a template closing >.
bool closesScope() const {
- return isOneOf(tok::r_paren, tok::r_brace, tok::r_square) ||
- Type == TT_TemplateCloser;
+ return isOneOf(tok::r_paren, tok::r_brace, tok::r_square,
+ TT_TemplateCloser);
}
/// \brief Returns \c true if this is a "." or "->" accessing a member.
bool isMemberAccess() const {
return isOneOf(tok::arrow, tok::period, tok::arrowstar) &&
- Type != TT_DesignatedInitializerPeriod;
+ !isOneOf(TT_DesignatedInitializerPeriod, TT_TrailingReturnArrow);
}
bool isUnaryOperator() const {
@@ -350,7 +361,28 @@ struct FormatToken {
}
bool isTrailingComment() const {
- return is(tok::comment) && (!Next || Next->NewlinesBefore > 0);
+ return is(tok::comment) &&
+ (is(TT_LineComment) || !Next || Next->NewlinesBefore > 0);
+ }
+
+ /// \brief Returns \c true if this is a keyword that can be used
+ /// like a function call (e.g. sizeof, typeid, ...).
+ bool isFunctionLikeKeyword() const {
+ switch (Tok.getKind()) {
+ case tok::kw_throw:
+ case tok::kw_typeid:
+ case tok::kw_return:
+ case tok::kw_sizeof:
+ case tok::kw_alignof:
+ case tok::kw_alignas:
+ case tok::kw_decltype:
+ case tok::kw_noexcept:
+ case tok::kw_static_assert:
+ case tok::kw___attribute:
+ return true;
+ default:
+ return false;
+ }
}
prec::Level getPrecedence() const {
@@ -376,10 +408,10 @@ struct FormatToken {
/// \brief Returns \c true if this tokens starts a block-type list, i.e. a
/// list that should be indented with a block indent.
bool opensBlockTypeList(const FormatStyle &Style) const {
- return Type == TT_ArrayInitializerLSquare ||
+ return is(TT_ArrayInitializerLSquare) ||
(is(tok::l_brace) &&
- (BlockKind == BK_Block || Type == TT_DictLiteral ||
- !Style.Cpp11BracedListStyle));
+ (BlockKind == BK_Block || is(TT_DictLiteral) ||
+ (!Style.Cpp11BracedListStyle && NestingLevel == 0)));
}
/// \brief Same as opensBlockTypeList, but for the closing token.
@@ -499,7 +531,71 @@ private:
bool HasNestedBracedList;
};
+/// \brief Encapsulates keywords that are context sensitive or for languages not
+/// properly supported by Clang's lexer.
+struct AdditionalKeywords {
+ AdditionalKeywords(IdentifierTable &IdentTable) {
+ kw_in = &IdentTable.get("in");
+ kw_CF_ENUM = &IdentTable.get("CF_ENUM");
+ kw_CF_OPTIONS = &IdentTable.get("CF_OPTIONS");
+ kw_NS_ENUM = &IdentTable.get("NS_ENUM");
+ kw_NS_OPTIONS = &IdentTable.get("NS_OPTIONS");
+
+ kw_finally = &IdentTable.get("finally");
+ kw_function = &IdentTable.get("function");
+ kw_var = &IdentTable.get("var");
+
+ kw_abstract = &IdentTable.get("abstract");
+ kw_extends = &IdentTable.get("extends");
+ kw_final = &IdentTable.get("final");
+ kw_implements = &IdentTable.get("implements");
+ kw_instanceof = &IdentTable.get("instanceof");
+ kw_interface = &IdentTable.get("interface");
+ kw_native = &IdentTable.get("native");
+ kw_package = &IdentTable.get("package");
+ kw_synchronized = &IdentTable.get("synchronized");
+ kw_throws = &IdentTable.get("throws");
+
+ kw_option = &IdentTable.get("option");
+ kw_optional = &IdentTable.get("optional");
+ kw_repeated = &IdentTable.get("repeated");
+ kw_required = &IdentTable.get("required");
+ kw_returns = &IdentTable.get("returns");
+ }
+
+ // ObjC context sensitive keywords.
+ IdentifierInfo *kw_in;
+ IdentifierInfo *kw_CF_ENUM;
+ IdentifierInfo *kw_CF_OPTIONS;
+ IdentifierInfo *kw_NS_ENUM;
+ IdentifierInfo *kw_NS_OPTIONS;
+
+ // JavaScript keywords.
+ IdentifierInfo *kw_finally;
+ IdentifierInfo *kw_function;
+ IdentifierInfo *kw_var;
+
+ // Java keywords.
+ IdentifierInfo *kw_abstract;
+ IdentifierInfo *kw_extends;
+ IdentifierInfo *kw_final;
+ IdentifierInfo *kw_implements;
+ IdentifierInfo *kw_instanceof;
+ IdentifierInfo *kw_interface;
+ IdentifierInfo *kw_native;
+ IdentifierInfo *kw_package;
+ IdentifierInfo *kw_synchronized;
+ IdentifierInfo *kw_throws;
+
+ // Proto keywords.
+ IdentifierInfo *kw_option;
+ IdentifierInfo *kw_optional;
+ IdentifierInfo *kw_repeated;
+ IdentifierInfo *kw_required;
+ IdentifierInfo *kw_returns;
+};
+
} // namespace format
} // namespace clang
-#endif // LLVM_CLANG_FORMAT_FORMAT_TOKEN_H
+#endif
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 017afe1a370b..4ba3f9196977 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -32,9 +32,9 @@ namespace {
class AnnotatingParser {
public:
AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line,
- IdentifierInfo &Ident_in)
- : Style(Style), Line(Line), CurrentToken(Line.First),
- KeywordVirtualFound(false), AutoFound(false), Ident_in(Ident_in) {
+ const AdditionalKeywords &Keywords)
+ : Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
+ Keywords(Keywords) {
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
resetTokenMetadata(CurrentToken);
}
@@ -51,6 +51,10 @@ private:
Contexts.back().InTemplateArgument =
Left->Previous && Left->Previous->Tok.isNot(tok::kw_template);
+ if (Style.Language == FormatStyle::LK_Java &&
+ CurrentToken->is(tok::question))
+ next();
+
while (CurrentToken) {
if (CurrentToken->is(tok::greater)) {
Left->MatchingParen = CurrentToken;
@@ -59,8 +63,13 @@ private:
next();
return true;
}
+ if (CurrentToken->is(tok::question) &&
+ Style.Language == FormatStyle::LK_Java) {
+ next();
+ continue;
+ }
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace,
- tok::question, tok::colon))
+ tok::colon, tok::question))
return false;
// If a && or || is found and interpreted as a binary operator, this set
// of angles is likely part of something like "a < b && c > d". If the
@@ -69,12 +78,8 @@ private:
// parameters.
// FIXME: This is getting out of hand, write a decent parser.
if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) &&
- ((CurrentToken->Previous->Type == TT_BinaryOperator &&
- // Toplevel bool expressions do not make lots of sense;
- // If we're on the top level, it contains only the base context and
- // the context for the current opening angle bracket.
- Contexts.size() > 2) ||
- Contexts[Contexts.size() - 2].IsExpression) &&
+ CurrentToken->Previous->is(TT_BinaryOperator) &&
+ Contexts[Contexts.size() - 2].IsExpression &&
Line.First->isNot(tok::kw_template))
return false;
updateParameterCount(Left, CurrentToken);
@@ -109,17 +114,17 @@ private:
if (Left->Previous &&
(Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_if,
tok::kw_while, tok::l_paren, tok::comma) ||
- Left->Previous->Type == TT_BinaryOperator)) {
+ Left->Previous->is(TT_BinaryOperator))) {
// static_assert, if and while usually contain expressions.
Contexts.back().IsExpression = true;
} else if (Line.InPPDirective &&
(!Left->Previous ||
- (Left->Previous->isNot(tok::identifier) &&
- Left->Previous->Type != TT_OverloadedOperator))) {
+ !Left->Previous->isOneOf(tok::identifier,
+ TT_OverloadedOperator))) {
Contexts.back().IsExpression = true;
} else if (Left->Previous && Left->Previous->is(tok::r_square) &&
Left->Previous->MatchingParen &&
- Left->Previous->MatchingParen->Type == TT_LambdaLSquare) {
+ Left->Previous->MatchingParen->is(TT_LambdaLSquare)) {
// This is a parameter list of a lambda expression.
Contexts.back().IsExpression = false;
} else if (Contexts[Contexts.size() - 2].CaretFound) {
@@ -131,6 +136,9 @@ private:
// The first argument to a foreach macro is a declaration.
Contexts.back().IsForEachMacro = true;
Contexts.back().IsExpression = false;
+ } else if (Left->Previous && Left->Previous->MatchingParen &&
+ Left->Previous->MatchingParen->is(TT_ObjCBlockLParen)) {
+ Contexts.back().IsExpression = false;
}
if (StartsObjCMethodExpr) {
@@ -160,11 +168,11 @@ private:
}
}
- if (CurrentToken->Previous->Type == TT_PointerOrReference &&
+ if (CurrentToken->Previous->is(TT_PointerOrReference) &&
CurrentToken->Previous->Previous->isOneOf(tok::l_paren,
tok::coloncolon))
MightBeFunctionType = true;
- if (CurrentToken->Previous->Type == TT_BinaryOperator)
+ if (CurrentToken->Previous->is(TT_BinaryOperator))
Contexts.back().IsExpression = true;
if (CurrentToken->is(tok::r_paren)) {
if (MightBeFunctionType && CurrentToken->Next &&
@@ -183,8 +191,12 @@ private:
}
}
- if (Left->Type == TT_AttributeParen)
+ if (Left->is(TT_AttributeParen))
CurrentToken->Type = TT_AttributeParen;
+ if (Left->Previous && Left->Previous->is(TT_JavaAnnotation))
+ CurrentToken->Type = TT_JavaAnnotation;
+ if (Left->Previous && Left->Previous->is(TT_LeadingJavaAnnotation))
+ CurrentToken->Type = TT_LeadingJavaAnnotation;
if (!HasMultipleLines)
Left->PackingKind = PPK_Inconclusive;
@@ -227,12 +239,13 @@ private:
FormatToken *Left = CurrentToken->Previous;
FormatToken *Parent = Left->getPreviousNonComment();
bool StartsObjCMethodExpr =
- Contexts.back().CanBeExpression && Left->Type != TT_LambdaLSquare &&
+ Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
CurrentToken->isNot(tok::l_brace) &&
- (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
- tok::kw_return, tok::kw_throw) ||
- Parent->isUnaryOperator() || Parent->Type == TT_ObjCForIn ||
- Parent->Type == TT_CastRParen ||
+ (!Parent ||
+ Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
+ tok::kw_return, tok::kw_throw) ||
+ Parent->isUnaryOperator() ||
+ Parent->isOneOf(TT_ObjCForIn, TT_CastRParen) ||
getBinOpPrecedence(Parent->Tok.getKind(), true, true) > prec::Unknown);
ScopedContextCreator ContextCreator(*this, tok::l_square, 10);
Contexts.back().IsExpression = true;
@@ -243,14 +256,14 @@ private:
Left->Type = TT_ObjCMethodExpr;
} else if (Parent && Parent->is(tok::at)) {
Left->Type = TT_ArrayInitializerLSquare;
- } else if (Left->Type == TT_Unknown) {
+ } else if (Left->is(TT_Unknown)) {
Left->Type = TT_ArraySubscriptLSquare;
}
while (CurrentToken) {
if (CurrentToken->is(tok::r_square)) {
if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) &&
- Left->Type == TT_ObjCMethodExpr) {
+ Left->is(TT_ObjCMethodExpr)) {
// An ObjC method call is rarely followed by an open parenthesis.
// FIXME: Do we incorrectly label ":" with this?
StartsObjCMethodExpr = false;
@@ -261,7 +274,7 @@ private:
// determineStarAmpUsage() thinks that '*' '[' is allocating an
// array of pointers, but if '[' starts a selector then '*' is a
// binary operator.
- if (Parent && Parent->Type == TT_PointerOrReference)
+ if (Parent && Parent->is(TT_PointerOrReference))
Parent->Type = TT_BinaryOperator;
}
Left->MatchingParen = CurrentToken;
@@ -277,14 +290,22 @@ private:
}
if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace))
return false;
- if (CurrentToken->is(tok::colon))
+ if (CurrentToken->is(tok::colon)) {
+ if (Left->is(TT_ArraySubscriptLSquare)) {
+ Left->Type = TT_ObjCMethodExpr;
+ StartsObjCMethodExpr = true;
+ Contexts.back().ColonIsObjCMethodExpr = true;
+ if (Parent && Parent->is(tok::r_paren))
+ Parent->Type = TT_CastRParen;
+ }
ColonFound = true;
+ }
if (CurrentToken->is(tok::comma) &&
Style.Language != FormatStyle::LK_Proto &&
- (Left->Type == TT_ArraySubscriptLSquare ||
- (Left->Type == TT_ObjCMethodExpr && !ColonFound)))
+ (Left->is(TT_ArraySubscriptLSquare) ||
+ (Left->is(TT_ObjCMethodExpr) && !ColonFound)))
Left->Type = TT_ArrayInitializerLSquare;
- FormatToken* Tok = CurrentToken;
+ FormatToken *Tok = CurrentToken;
if (!consumeToken())
return false;
updateParameterCount(Left, Tok);
@@ -315,11 +336,14 @@ private:
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
return false;
updateParameterCount(Left, CurrentToken);
- if (CurrentToken->is(tok::colon) &&
- Style.Language != FormatStyle::LK_Proto) {
- if (CurrentToken->getPreviousNonComment()->is(tok::identifier))
- CurrentToken->getPreviousNonComment()->Type = TT_SelectorName;
- Left->Type = TT_DictLiteral;
+ if (CurrentToken->isOneOf(tok::colon, tok::l_brace)) {
+ FormatToken *Previous = CurrentToken->getPreviousNonComment();
+ if ((CurrentToken->is(tok::colon) ||
+ Style.Language == FormatStyle::LK_Proto) &&
+ Previous->is(tok::identifier))
+ Previous->Type = TT_SelectorName;
+ if (CurrentToken->is(tok::colon))
+ Left->Type = TT_DictLiteral;
}
if (!consumeToken())
return false;
@@ -329,10 +353,10 @@ private:
}
void updateParameterCount(FormatToken *Left, FormatToken *Current) {
- if (Current->Type == TT_LambdaLSquare ||
- (Current->is(tok::caret) && Current->Type == TT_UnaryOperator) ||
+ if (Current->is(TT_LambdaLSquare) ||
+ (Current->is(tok::caret) && Current->is(TT_UnaryOperator)) ||
(Style.Language == FormatStyle::LK_JavaScript &&
- Current->TokenText == "function")) {
+ Current->is(Keywords.kw_function))) {
++Left->BlockParameterCount;
}
if (Current->is(tok::comma)) {
@@ -390,7 +414,7 @@ private:
} else if (Contexts.back().ColonIsDictLiteral) {
Tok->Type = TT_DictLiteral;
} else if (Contexts.back().ColonIsObjCMethodExpr ||
- Line.First->Type == TT_ObjCMethodSpecifier) {
+ Line.First->is(TT_ObjCMethodSpecifier)) {
Tok->Type = TT_ObjCMethodExpr;
Tok->Previous->Type = TT_SelectorName;
if (Tok->Previous->ColumnWidth >
@@ -406,6 +430,11 @@ private:
} else if (Contexts.size() == 1 &&
!Line.First->isOneOf(tok::kw_enum, tok::kw_case)) {
Tok->Type = TT_InheritanceColon;
+ } else if (Tok->Previous->is(tok::identifier) && Tok->Next &&
+ Tok->Next->isOneOf(tok::r_paren, tok::comma)) {
+ // This handles a special macro in ObjC code where selectors including
+ // the colon are passed as macro arguments.
+ Tok->Type = TT_ObjCMethodExpr;
} else if (Contexts.back().ContextKind == tok::l_paren) {
Tok->Type = TT_InlineASMColon;
}
@@ -428,9 +457,9 @@ private:
if (!parseParens())
return false;
if (Line.MustBeDeclaration && Contexts.size() == 1 &&
- !Contexts.back().IsExpression &&
- Line.First->Type != TT_ObjCProperty &&
- (!Tok->Previous || Tok->Previous->isNot(tok::kw_decltype)))
+ !Contexts.back().IsExpression && Line.First->isNot(TT_ObjCProperty) &&
+ (!Tok->Previous ||
+ !Tok->Previous->isOneOf(tok::kw_decltype, TT_LeadingJavaAnnotation)))
Line.MightBeFunctionDecl = true;
break;
case tok::l_square:
@@ -442,9 +471,12 @@ private:
return false;
break;
case tok::less:
- if (Tok->Previous && !Tok->Previous->Tok.isLiteral() && parseAngle())
+ if ((!Tok->Previous ||
+ (!Tok->Previous->Tok.isLiteral() &&
+ !(Tok->Previous->is(tok::r_paren) && Contexts.size() > 1))) &&
+ parseAngle()) {
Tok->Type = TT_TemplateOpener;
- else {
+ } else {
Tok->Type = TT_BinaryOperator;
CurrentToken = Tok;
next();
@@ -467,12 +499,12 @@ private:
if (CurrentToken->isOneOf(tok::star, tok::amp))
CurrentToken->Type = TT_PointerOrReference;
consumeToken();
- if (CurrentToken && CurrentToken->Previous->Type == TT_BinaryOperator)
+ if (CurrentToken && CurrentToken->Previous->is(TT_BinaryOperator))
CurrentToken->Previous->Type = TT_OverloadedOperator;
}
if (CurrentToken) {
CurrentToken->Type = TT_OverloadedOperatorLParen;
- if (CurrentToken->Previous->Type == TT_BinaryOperator)
+ if (CurrentToken->Previous->is(TT_BinaryOperator))
CurrentToken->Previous->Type = TT_OverloadedOperator;
}
break;
@@ -483,8 +515,8 @@ private:
parseTemplateDeclaration();
break;
case tok::identifier:
- if (Line.First->is(tok::kw_for) &&
- Tok->Tok.getIdentifierInfo() == &Ident_in)
+ if (Line.First->is(tok::kw_for) && Tok->is(Keywords.kw_in) &&
+ Tok->Previous->isNot(tok::colon))
Tok->Type = TT_ObjCForIn;
break;
case tok::comma:
@@ -502,7 +534,6 @@ private:
}
void parseIncludeDirective() {
- next();
if (CurrentToken && CurrentToken->is(tok::less)) {
next();
while (CurrentToken) {
@@ -510,14 +541,6 @@ private:
CurrentToken->Type = TT_ImplicitStringLiteral;
next();
}
- } else {
- while (CurrentToken) {
- if (CurrentToken->is(tok::string_literal))
- // Mark these string literals as "implicit" literals, too, so that
- // they are not split or line-wrapped.
- CurrentToken->Type = TT_ImplicitStringLiteral;
- next();
- }
}
}
@@ -544,22 +567,25 @@ private:
}
}
- void parsePreprocessorDirective() {
+ LineType parsePreprocessorDirective() {
+ LineType Type = LT_PreprocessorDirective;
next();
if (!CurrentToken)
- return;
+ return Type;
if (CurrentToken->Tok.is(tok::numeric_constant)) {
CurrentToken->SpacesRequiredBefore = 1;
- return;
+ return Type;
}
// Hashes in the middle of a line can lead to any strange token
// sequence.
if (!CurrentToken->Tok.getIdentifierInfo())
- return;
+ return Type;
switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_import:
+ next();
parseIncludeDirective();
+ Type = LT_ImportStatement;
break;
case tok::pp_error:
case tok::pp_warning:
@@ -578,33 +604,53 @@ private:
}
while (CurrentToken)
next();
+ return Type;
}
public:
LineType parseLine() {
if (CurrentToken->is(tok::hash)) {
- parsePreprocessorDirective();
- return LT_PreprocessorDirective;
+ return parsePreprocessorDirective();
}
// Directly allow to 'import <string-literal>' to support protocol buffer
// definitions (code.google.com/p/protobuf) or missing "#" (either way we
// should not break the line).
IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo();
- if (Info && Info->getPPKeywordID() == tok::pp_import &&
- CurrentToken->Next && CurrentToken->Next->is(tok::string_literal))
+ if ((Style.Language == FormatStyle::LK_Java &&
+ CurrentToken->is(Keywords.kw_package)) ||
+ (Info && Info->getPPKeywordID() == tok::pp_import &&
+ CurrentToken->Next &&
+ CurrentToken->Next->isOneOf(tok::string_literal, tok::identifier,
+ tok::kw_static))) {
+ next();
parseIncludeDirective();
+ return LT_ImportStatement;
+ }
+ // If this line starts and ends in '<' and '>', respectively, it is likely
+ // part of "#define <a/b.h>".
+ if (CurrentToken->is(tok::less) && Line.Last->is(tok::greater)) {
+ parseIncludeDirective();
+ return LT_ImportStatement;
+ }
+
+ bool KeywordVirtualFound = false;
+ bool ImportStatement = false;
while (CurrentToken) {
if (CurrentToken->is(tok::kw_virtual))
KeywordVirtualFound = true;
+ if (IsImportStatement(*CurrentToken))
+ ImportStatement = true;
if (!consumeToken())
return LT_Invalid;
}
if (KeywordVirtualFound)
return LT_VirtualFunctionDecl;
+ if (ImportStatement)
+ return LT_ImportStatement;
- if (Line.First->Type == TT_ObjCMethodSpecifier) {
+ if (Line.First->is(TT_ObjCMethodSpecifier)) {
if (Contexts.back().FirstObjCSelectorName)
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
@@ -615,17 +661,26 @@ public:
}
private:
+ bool IsImportStatement(const FormatToken &Tok) {
+ // FIXME: Closure-library specific stuff should not be hard-coded but be
+ // configurable.
+ return Style.Language == FormatStyle::LK_JavaScript &&
+ Tok.TokenText == "goog" && Tok.Next && Tok.Next->is(tok::period) &&
+ Tok.Next->Next && (Tok.Next->Next->TokenText == "module" ||
+ Tok.Next->Next->TokenText == "require" ||
+ Tok.Next->Next->TokenText == "provide") &&
+ Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren);
+ }
+
void resetTokenMetadata(FormatToken *Token) {
if (!Token)
return;
// Reset token type in case we have already looked at it and then
// recovered from an error (e.g. failure to find the matching >).
- if (CurrentToken->Type != TT_LambdaLSquare &&
- CurrentToken->Type != TT_FunctionLBrace &&
- CurrentToken->Type != TT_ImplicitStringLiteral &&
- CurrentToken->Type != TT_RegexLiteral &&
- CurrentToken->Type != TT_TrailingReturnArrow)
+ if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_FunctionLBrace,
+ TT_ImplicitStringLiteral, TT_RegexLiteral,
+ TT_TrailingReturnArrow))
CurrentToken->Type = TT_Unknown;
CurrentToken->Role.reset();
CurrentToken->FakeLParens.clear();
@@ -634,9 +689,10 @@ private:
void next() {
if (CurrentToken) {
- determineTokenType(*CurrentToken);
- CurrentToken->BindingStrength = Contexts.back().BindingStrength;
CurrentToken->NestingLevel = Contexts.size() - 1;
+ CurrentToken->BindingStrength = Contexts.back().BindingStrength;
+ modifyContext(*CurrentToken);
+ determineTokenType(*CurrentToken);
CurrentToken = CurrentToken->Next;
}
@@ -688,23 +744,29 @@ private:
~ScopedContextCreator() { P.Contexts.pop_back(); }
};
- void determineTokenType(FormatToken &Current) {
+ void modifyContext(const FormatToken &Current) {
if (Current.getPrecedence() == prec::Assignment &&
- !Line.First->isOneOf(tok::kw_template, tok::kw_using) &&
+ !Line.First->isOneOf(tok::kw_template, tok::kw_using,
+ TT_UnaryOperator) &&
(!Current.Previous || Current.Previous->isNot(tok::kw_operator))) {
Contexts.back().IsExpression = true;
for (FormatToken *Previous = Current.Previous;
Previous && !Previous->isOneOf(tok::comma, tok::semi);
Previous = Previous->Previous) {
- if (Previous->isOneOf(tok::r_square, tok::r_paren))
+ if (Previous->isOneOf(tok::r_square, tok::r_paren)) {
Previous = Previous->MatchingParen;
- if (Previous->Type == TT_BinaryOperator &&
- Previous->isOneOf(tok::star, tok::amp)) {
- Previous->Type = TT_PointerOrReference;
+ if (!Previous)
+ break;
}
+ if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator) &&
+ Previous->isOneOf(tok::star, tok::amp) && Previous->Previous &&
+ Previous->Previous->isNot(tok::equal))
+ Previous->Type = TT_PointerOrReference;
}
} else if (Current.isOneOf(tok::kw_return, tok::kw_throw)) {
Contexts.back().IsExpression = true;
+ } else if (Current.is(TT_TrailingReturnArrow)) {
+ Contexts.back().IsExpression = false;
} else if (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
!Line.InPPDirective &&
(!Current.Previous ||
@@ -712,7 +774,7 @@ private:
bool ParametersOfFunctionType =
Current.Previous && Current.Previous->is(tok::r_paren) &&
Current.Previous->MatchingParen &&
- Current.Previous->MatchingParen->Type == TT_FunctionTypeLParen;
+ Current.Previous->MatchingParen->is(TT_FunctionTypeLParen);
bool IsForOrCatch = Current.Previous &&
Current.Previous->isOneOf(tok::kw_for, tok::kw_catch);
Contexts.back().IsExpression = !ParametersOfFunctionType && !IsForOrCatch;
@@ -721,8 +783,10 @@ private:
Previous && Previous->isOneOf(tok::star, tok::amp);
Previous = Previous->Previous)
Previous->Type = TT_PointerOrReference;
+ if (Line.MustBeDeclaration)
+ Contexts.back().IsExpression = Contexts.front().InCtorInitializer;
} else if (Current.Previous &&
- Current.Previous->Type == TT_CtorInitializerColon) {
+ Current.Previous->is(TT_CtorInitializerColon)) {
Contexts.back().IsExpression = true;
Contexts.back().InCtorInitializer = true;
} else if (Current.is(tok::kw_new)) {
@@ -731,70 +795,99 @@ private:
// This should be the condition or increment in a for-loop.
Contexts.back().IsExpression = true;
}
+ }
+
+ void determineTokenType(FormatToken &Current) {
+ if (!Current.is(TT_Unknown))
+ // The token type is already known.
+ return;
- if (Current.Type == TT_Unknown) {
+ // Line.MightBeFunctionDecl can only be true after the parentheses of a
+ // function declaration have been found. In this case, 'Current' is a
+ // trailing token of this declaration and thus cannot be a name.
+ if (Current.is(Keywords.kw_instanceof)) {
+ Current.Type = TT_BinaryOperator;
+ } else if (isStartOfName(Current) &&
+ (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) {
+ Contexts.back().FirstStartOfName = &Current;
+ Current.Type = TT_StartOfName;
+ } else if (Current.is(tok::kw_auto)) {
+ AutoFound = true;
+ } else if (Current.is(tok::arrow) &&
+ Style.Language == FormatStyle::LK_Java) {
+ Current.Type = TT_LambdaArrow;
+ } else if (Current.is(tok::arrow) && AutoFound && Line.MustBeDeclaration &&
+ Current.NestingLevel == 0) {
+ Current.Type = TT_TrailingReturnArrow;
+ } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
+ Current.Type =
+ determineStarAmpUsage(Current, Contexts.back().CanBeExpression &&
+ Contexts.back().IsExpression,
+ Contexts.back().InTemplateArgument);
+ } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
+ Current.Type = determinePlusMinusCaretUsage(Current);
+ if (Current.is(TT_UnaryOperator) && Current.is(tok::caret))
+ Contexts.back().CaretFound = true;
+ } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
+ Current.Type = determineIncrementUsage(Current);
+ } else if (Current.isOneOf(tok::exclaim, tok::tilde)) {
+ Current.Type = TT_UnaryOperator;
+ } else if (Current.is(tok::question)) {
+ Current.Type = TT_ConditionalExpr;
+ } else if (Current.isBinaryOperator() &&
+ (!Current.Previous || Current.Previous->isNot(tok::l_square))) {
+ Current.Type = TT_BinaryOperator;
+ } else if (Current.is(tok::comment)) {
+ if (Current.TokenText.startswith("//"))
+ Current.Type = TT_LineComment;
+ else
+ Current.Type = TT_BlockComment;
+ } else if (Current.is(tok::r_paren)) {
+ if (rParenEndsCast(Current))
+ Current.Type = TT_CastRParen;
+ } else if (Current.is(tok::at) && Current.Next) {
+ switch (Current.Next->Tok.getObjCKeywordID()) {
+ case tok::objc_interface:
+ case tok::objc_implementation:
+ case tok::objc_protocol:
+ Current.Type = TT_ObjCDecl;
+ break;
+ case tok::objc_property:
+ Current.Type = TT_ObjCProperty;
+ break;
+ default:
+ break;
+ }
+ } else if (Current.is(tok::period)) {
+ FormatToken *PreviousNoComment = Current.getPreviousNonComment();
+ if (PreviousNoComment &&
+ PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
+ Current.Type = TT_DesignatedInitializerPeriod;
+ else if (Style.Language == FormatStyle::LK_Java && Current.Previous &&
+ Current.Previous->isOneOf(TT_JavaAnnotation,
+ TT_LeadingJavaAnnotation)) {
+ Current.Type = Current.Previous->Type;
+ }
+ } else if (Current.isOneOf(tok::identifier, tok::kw_const) &&
+ Current.Previous &&
+ !Current.Previous->isOneOf(tok::equal, tok::at) &&
+ Line.MightBeFunctionDecl && Contexts.size() == 1) {
// Line.MightBeFunctionDecl can only be true after the parentheses of a
- // function declaration have been found. In this case, 'Current' is a
- // trailing token of this declaration and thus cannot be a name.
- if (isStartOfName(Current) && !Line.MightBeFunctionDecl) {
- Contexts.back().FirstStartOfName = &Current;
- Current.Type = TT_StartOfName;
- } else if (Current.is(tok::kw_auto)) {
- AutoFound = true;
- } else if (Current.is(tok::arrow) && AutoFound &&
- Line.MustBeDeclaration) {
- Current.Type = TT_TrailingReturnArrow;
- } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
- Current.Type =
- determineStarAmpUsage(Current, Contexts.back().CanBeExpression &&
- Contexts.back().IsExpression,
- Contexts.back().InTemplateArgument);
- } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
- Current.Type = determinePlusMinusCaretUsage(Current);
- if (Current.Type == TT_UnaryOperator && Current.is(tok::caret))
- Contexts.back().CaretFound = true;
- } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
- Current.Type = determineIncrementUsage(Current);
- } else if (Current.is(tok::exclaim)) {
- Current.Type = TT_UnaryOperator;
- } else if (Current.is(tok::question)) {
- Current.Type = TT_ConditionalExpr;
- } else if (Current.isBinaryOperator() &&
- (!Current.Previous ||
- Current.Previous->isNot(tok::l_square))) {
- Current.Type = TT_BinaryOperator;
- } else if (Current.is(tok::comment)) {
- if (Current.TokenText.startswith("//"))
- Current.Type = TT_LineComment;
+ // function declaration have been found.
+ Current.Type = TT_TrailingAnnotation;
+ } else if (Style.Language == FormatStyle::LK_Java && Current.Previous) {
+ if (Current.Previous->is(tok::at) &&
+ Current.isNot(Keywords.kw_interface)) {
+ const FormatToken &AtToken = *Current.Previous;
+ const FormatToken *Previous = AtToken.getPreviousNonComment();
+ if (!Previous || Previous->is(TT_LeadingJavaAnnotation))
+ Current.Type = TT_LeadingJavaAnnotation;
else
- Current.Type = TT_BlockComment;
- } else if (Current.is(tok::r_paren)) {
- if (rParenEndsCast(Current))
- Current.Type = TT_CastRParen;
- } else if (Current.is(tok::at) && Current.Next) {
- switch (Current.Next->Tok.getObjCKeywordID()) {
- case tok::objc_interface:
- case tok::objc_implementation:
- case tok::objc_protocol:
- Current.Type = TT_ObjCDecl;
- break;
- case tok::objc_property:
- Current.Type = TT_ObjCProperty;
- break;
- default:
- break;
- }
- } else if (Current.is(tok::period)) {
- FormatToken *PreviousNoComment = Current.getPreviousNonComment();
- if (PreviousNoComment &&
- PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
- Current.Type = TT_DesignatedInitializerPeriod;
- } else if (Current.isOneOf(tok::identifier, tok::kw_const) &&
- Current.Previous && Current.Previous->isNot(tok::equal) &&
- Line.MightBeFunctionDecl && Contexts.size() == 1) {
- // Line.MightBeFunctionDecl can only be true after the parentheses of a
- // function declaration have been found.
- Current.Type = TT_TrailingAnnotation;
+ Current.Type = TT_JavaAnnotation;
+ } else if (Current.Previous->is(tok::period) &&
+ Current.Previous->isOneOf(TT_JavaAnnotation,
+ TT_LeadingJavaAnnotation)) {
+ Current.Type = Current.Previous->Type;
}
}
}
@@ -808,6 +901,9 @@ private:
if (Tok.isNot(tok::identifier) || !Tok.Previous)
return false;
+ if (Tok.Previous->is(TT_LeadingJavaAnnotation))
+ return false;
+
// Skip "const" as it does not have an influence on whether this is a name.
FormatToken *PreviousNotConst = Tok.Previous;
while (PreviousNotConst && PreviousNotConst->is(tok::kw_const))
@@ -820,9 +916,10 @@ private:
PreviousNotConst->Previous &&
PreviousNotConst->Previous->is(tok::hash);
- if (PreviousNotConst->Type == TT_TemplateCloser)
+ if (PreviousNotConst->is(TT_TemplateCloser))
return PreviousNotConst && PreviousNotConst->MatchingParen &&
PreviousNotConst->MatchingParen->Previous &&
+ PreviousNotConst->MatchingParen->Previous->isNot(tok::period) &&
PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template);
if (PreviousNotConst->is(tok::r_paren) && PreviousNotConst->MatchingParen &&
@@ -831,7 +928,7 @@ private:
return true;
return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) ||
- PreviousNotConst->Type == TT_PointerOrReference ||
+ PreviousNotConst->is(TT_PointerOrReference) ||
PreviousNotConst->isSimpleTypeSpecifier();
}
@@ -840,14 +937,28 @@ private:
FormatToken *LeftOfParens = nullptr;
if (Tok.MatchingParen)
LeftOfParens = Tok.MatchingParen->getPreviousNonComment();
- if (LeftOfParens && LeftOfParens->is(tok::r_paren))
+ if (LeftOfParens && LeftOfParens->is(tok::r_paren) &&
+ LeftOfParens->MatchingParen)
+ LeftOfParens = LeftOfParens->MatchingParen->Previous;
+ if (LeftOfParens && LeftOfParens->is(tok::r_square) &&
+ LeftOfParens->MatchingParen &&
+ LeftOfParens->MatchingParen->is(TT_LambdaLSquare))
return false;
+ if (Tok.Next) {
+ if (Tok.Next->is(tok::question))
+ return false;
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ Tok.Next->is(Keywords.kw_in))
+ return false;
+ if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren))
+ return true;
+ }
bool IsCast = false;
bool ParensAreEmpty = Tok.Previous == Tok.MatchingParen;
- bool ParensAreType = !Tok.Previous ||
- Tok.Previous->Type == TT_PointerOrReference ||
- Tok.Previous->Type == TT_TemplateCloser ||
- Tok.Previous->isSimpleTypeSpecifier();
+ bool ParensAreType =
+ !Tok.Previous ||
+ Tok.Previous->isOneOf(TT_PointerOrReference, TT_TemplateCloser) ||
+ Tok.Previous->isSimpleTypeSpecifier();
bool ParensCouldEndDecl =
Tok.Next && Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace);
bool IsSizeOfOrAlignOf =
@@ -862,12 +973,11 @@ private:
IsCast = true;
// If there is an identifier after the (), it is likely a cast, unless
// there is also an identifier before the ().
- else if (LeftOfParens &&
+ else if (LeftOfParens && Tok.Next &&
(LeftOfParens->Tok.getIdentifierInfo() == nullptr ||
LeftOfParens->is(tok::kw_return)) &&
- LeftOfParens->Type != TT_OverloadedOperator &&
- LeftOfParens->isNot(tok::at) &&
- LeftOfParens->Type != TT_TemplateCloser && Tok.Next) {
+ !LeftOfParens->isOneOf(TT_OverloadedOperator, tok::at,
+ TT_TemplateCloser)) {
if (Tok.Next->isOneOf(tok::identifier, tok::numeric_constant)) {
IsCast = true;
} else {
@@ -879,8 +989,9 @@ private:
if (Prev && Tok.Next && Tok.Next->Next) {
bool NextIsUnary = Tok.Next->isUnaryOperator() ||
Tok.Next->isOneOf(tok::amp, tok::star);
- IsCast = NextIsUnary && Tok.Next->Next->isOneOf(
- tok::identifier, tok::numeric_constant);
+ IsCast =
+ NextIsUnary && !Tok.Next->is(tok::plus) &&
+ Tok.Next->Next->isOneOf(tok::identifier, tok::numeric_constant);
}
for (; Prev != Tok.MatchingParen; Prev = Prev->Previous) {
@@ -897,29 +1008,31 @@ private:
/// \brief Return the type of the given token assuming it is * or &.
TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression,
bool InTemplateArgument) {
+ if (Style.Language == FormatStyle::LK_JavaScript)
+ return TT_BinaryOperator;
+
const FormatToken *PrevToken = Tok.getPreviousNonComment();
if (!PrevToken)
return TT_UnaryOperator;
const FormatToken *NextToken = Tok.getNextNonComment();
- if (!NextToken || NextToken->is(tok::l_brace))
+ if (!NextToken ||
+ (NextToken->is(tok::l_brace) && !NextToken->getNextNonComment()))
return TT_Unknown;
- if (PrevToken->is(tok::coloncolon) ||
- (PrevToken->is(tok::l_paren) && !IsExpression))
+ if (PrevToken->is(tok::coloncolon))
return TT_PointerOrReference;
if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace,
tok::comma, tok::semi, tok::kw_return, tok::colon,
tok::equal, tok::kw_delete, tok::kw_sizeof) ||
- PrevToken->Type == TT_BinaryOperator ||
- PrevToken->Type == TT_ConditionalExpr ||
- PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
+ PrevToken->isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
+ TT_UnaryOperator, TT_CastRParen))
return TT_UnaryOperator;
- if (NextToken->is(tok::l_square) && NextToken->Type != TT_LambdaLSquare)
+ if (NextToken->is(tok::l_square) && NextToken->isNot(TT_LambdaLSquare))
return TT_PointerOrReference;
- if (NextToken->is(tok::kw_operator))
+ if (NextToken->isOneOf(tok::kw_operator, tok::comma))
return TT_PointerOrReference;
if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen &&
@@ -930,7 +1043,7 @@ private:
if (PrevToken->Tok.isLiteral() ||
PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true,
- tok::kw_false) ||
+ tok::kw_false, tok::r_brace) ||
NextToken->Tok.isLiteral() ||
NextToken->isOneOf(tok::kw_true, tok::kw_false) ||
NextToken->isUnaryOperator() ||
@@ -940,6 +1053,10 @@ private:
(InTemplateArgument && NextToken->Tok.isAnyIdentifier()))
return TT_BinaryOperator;
+ // "&&(" is quite unlikely to be two successive unary "&".
+ if (Tok.is(tok::ampamp) && NextToken && NextToken->is(tok::l_paren))
+ return TT_BinaryOperator;
+
// This catches some cases where evaluation order is used as control flow:
// aaa && aaa->f();
const FormatToken *NextNextToken = NextToken->getNextNonComment();
@@ -948,7 +1065,7 @@ private:
// It is very unlikely that we are going to find a pointer or reference type
// definition on the RHS of an assignment.
- if (IsExpression)
+ if (IsExpression && !Contexts.back().CaretFound)
return TT_BinaryOperator;
return TT_PointerOrReference;
@@ -956,7 +1073,7 @@ private:
TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
- if (!PrevToken || PrevToken->Type == TT_CastRParen)
+ if (!PrevToken || PrevToken->is(TT_CastRParen))
return TT_UnaryOperator;
// Use heuristics to recognize unary operators.
@@ -966,7 +1083,7 @@ private:
return TT_UnaryOperator;
// There can't be two consecutive binary operators.
- if (PrevToken->Type == TT_BinaryOperator)
+ if (PrevToken->is(TT_BinaryOperator))
return TT_UnaryOperator;
// Fall back to marking the token as binary operator.
@@ -976,7 +1093,7 @@ private:
/// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
TokenType determineIncrementUsage(const FormatToken &Tok) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
- if (!PrevToken || PrevToken->Type == TT_CastRParen)
+ if (!PrevToken || PrevToken->is(TT_CastRParen))
return TT_UnaryOperator;
if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier))
return TT_TrailingUnaryOperator;
@@ -989,9 +1106,8 @@ private:
const FormatStyle &Style;
AnnotatedLine &Line;
FormatToken *CurrentToken;
- bool KeywordVirtualFound;
bool AutoFound;
- IdentifierInfo &Ident_in;
+ const AdditionalKeywords &Keywords;
};
static int PrecedenceUnaryOperator = prec::PointerToMember + 1;
@@ -1001,20 +1117,17 @@ static int PrecedenceArrowAndPeriod = prec::PointerToMember + 2;
/// operator precedence.
class ExpressionParser {
public:
- ExpressionParser(AnnotatedLine &Line) : Current(Line.First) {
- // Skip leading "}", e.g. in "} else if (...) {".
- if (Current->is(tok::r_brace))
- next();
- }
+ ExpressionParser(const FormatStyle &Style, const AdditionalKeywords &Keywords,
+ AnnotatedLine &Line)
+ : Style(Style), Keywords(Keywords), Current(Line.First) {}
/// \brief Parse expressions with the given operatore precedence.
void parse(int Precedence = 0) {
// Skip 'return' and ObjC selector colons as they are not part of a binary
// expression.
- while (Current &&
- (Current->is(tok::kw_return) ||
- (Current->is(tok::colon) && (Current->Type == TT_ObjCMethodExpr ||
- Current->Type == TT_DictLiteral))))
+ while (Current && (Current->is(tok::kw_return) ||
+ (Current->is(tok::colon) &&
+ Current->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral))))
next();
if (!Current || Precedence > PrecedenceArrowAndPeriod)
@@ -1043,7 +1156,7 @@ public:
int CurrentPrecedence = getCurrentPrecedence();
- if (Current && Current->Type == TT_SelectorName &&
+ if (Current && Current->is(TT_SelectorName) &&
Precedence == CurrentPrecedence) {
if (LatestOperator)
addFakeParenthesis(Start, prec::Level(Precedence));
@@ -1052,18 +1165,11 @@ public:
// At the end of the line or when an operator with higher precedence is
// found, insert fake parenthesis and return.
- if (!Current || Current->closesScope() ||
- (CurrentPrecedence != -1 && CurrentPrecedence < Precedence)) {
- if (LatestOperator) {
- LatestOperator->LastOperator = true;
- if (Precedence == PrecedenceArrowAndPeriod) {
- // Call expressions don't have a binary operator precedence.
- addFakeParenthesis(Start, prec::Unknown);
- } else {
- addFakeParenthesis(Start, prec::Level(Precedence));
- }
- }
- return;
+ if (!Current || (Current->closesScope() && Current->MatchingParen) ||
+ (CurrentPrecedence != -1 && CurrentPrecedence < Precedence) ||
+ (CurrentPrecedence == prec::Conditional &&
+ Precedence == prec::Assignment && Current->is(tok::colon))) {
+ break;
}
// Consume scopes: (), [], <> and {}
@@ -1080,8 +1186,17 @@ public:
Current->OperatorIndex = OperatorIndex;
++OperatorIndex;
}
+ next(/*SkipPastLeadingComments=*/Precedence > 0);
+ }
+ }
- next();
+ if (LatestOperator && (Current || Precedence > 0)) {
+ LatestOperator->LastOperator = true;
+ if (Precedence == PrecedenceArrowAndPeriod) {
+ // Call expressions don't have a binary operator precedence.
+ addFakeParenthesis(Start, prec::Unknown);
+ } else {
+ addFakeParenthesis(Start, prec::Level(Precedence));
}
}
}
@@ -1091,17 +1206,29 @@ private:
/// and other tokens that we treat like binary operators.
int getCurrentPrecedence() {
if (Current) {
- if (Current->Type == TT_ConditionalExpr)
+ const FormatToken *NextNonComment = Current->getNextNonComment();
+ if (Current->is(TT_ConditionalExpr))
return prec::Conditional;
- else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon ||
- Current->Type == TT_SelectorName)
+ else if (NextNonComment && NextNonComment->is(tok::colon) &&
+ NextNonComment->is(TT_DictLiteral))
+ return prec::Comma;
+ else if (Current->is(TT_LambdaArrow))
+ return prec::Comma;
+ else if (Current->isOneOf(tok::semi, TT_InlineASMColon,
+ TT_SelectorName) ||
+ (Current->is(tok::comment) && NextNonComment &&
+ NextNonComment->is(TT_SelectorName)))
return 0;
- else if (Current->Type == TT_RangeBasedForLoopColon)
+ else if (Current->is(TT_RangeBasedForLoopColon))
return prec::Comma;
- else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma))
+ else if (Current->is(TT_BinaryOperator) || Current->is(tok::comma))
return Current->getPrecedence();
else if (Current->isOneOf(tok::period, tok::arrow))
return PrecedenceArrowAndPeriod;
+ else if (Style.Language == FormatStyle::LK_Java &&
+ Current->isOneOf(Keywords.kw_extends, Keywords.kw_implements,
+ Keywords.kw_throws))
+ return 0;
}
return -1;
}
@@ -1111,16 +1238,19 @@ private:
if (Precedence > prec::Unknown)
Start->StartsBinaryExpression = true;
if (Current) {
- ++Current->Previous->FakeRParens;
+ FormatToken *Previous = Current->Previous;
+ while (Previous->is(tok::comment) && Previous->Previous)
+ Previous = Previous->Previous;
+ ++Previous->FakeRParens;
if (Precedence > prec::Unknown)
- Current->Previous->EndsBinaryExpression = true;
+ Previous->EndsBinaryExpression = true;
}
}
/// \brief Parse unary operator expressions and surround them with fake
/// parentheses if appropriate.
void parseUnaryOperator() {
- if (!Current || Current->Type != TT_UnaryOperator) {
+ if (!Current || Current->isNot(TT_UnaryOperator)) {
parse(PrecedenceArrowAndPeriod);
return;
}
@@ -1134,33 +1264,40 @@ private:
}
void parseConditionalExpr() {
+ while (Current && Current->isTrailingComment()) {
+ next();
+ }
FormatToken *Start = Current;
parse(prec::LogicalOr);
if (!Current || !Current->is(tok::question))
return;
next();
- parseConditionalExpr();
- if (!Current || Current->Type != TT_ConditionalExpr)
+ parse(prec::Assignment);
+ if (!Current || Current->isNot(TT_ConditionalExpr))
return;
next();
- parseConditionalExpr();
+ parse(prec::Assignment);
addFakeParenthesis(Start, prec::Conditional);
}
- void next() {
+ void next(bool SkipPastLeadingComments = true) {
if (Current)
Current = Current->Next;
- while (Current && Current->isTrailingComment())
+ while (Current &&
+ (Current->NewlinesBefore == 0 || SkipPastLeadingComments) &&
+ Current->isTrailingComment())
Current = Current->Next;
}
+ const FormatStyle &Style;
+ const AdditionalKeywords &Keywords;
FormatToken *Current;
};
} // end anonymous namespace
-void
-TokenAnnotator::setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) {
+void TokenAnnotator::setCommentLineLevels(
+ SmallVectorImpl<AnnotatedLine *> &Lines) {
const AnnotatedLine *NextNonCommentLine = nullptr;
for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(),
E = Lines.rend();
@@ -1181,19 +1318,19 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
I != E; ++I) {
annotate(**I);
}
- AnnotatingParser Parser(Style, Line, Ident_in);
+ AnnotatingParser Parser(Style, Line, Keywords);
Line.Type = Parser.parseLine();
if (Line.Type == LT_Invalid)
return;
- ExpressionParser ExprParser(Line);
+ ExpressionParser ExprParser(Style, Keywords, Line);
ExprParser.parse();
- if (Line.First->Type == TT_ObjCMethodSpecifier)
+ if (Line.First->is(TT_ObjCMethodSpecifier))
Line.Type = LT_ObjCMethodDecl;
- else if (Line.First->Type == TT_ObjCDecl)
+ else if (Line.First->is(TT_ObjCDecl))
Line.Type = LT_ObjCDecl;
- else if (Line.First->Type == TT_ObjCProperty)
+ else if (Line.First->is(TT_ObjCProperty))
Line.Type = LT_ObjCProperty;
Line.First->SpacesRequiredBefore = 1;
@@ -1203,13 +1340,11 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
// This function heuristically determines whether 'Current' starts the name of a
// function declaration.
static bool isFunctionDeclarationName(const FormatToken &Current) {
- if (Current.Type != TT_StartOfName ||
- Current.NestingLevel != 0 ||
- Current.Previous->Type == TT_StartOfName)
+ if (!Current.is(TT_StartOfName) || Current.NestingLevel != 0)
return false;
const FormatToken *Next = Current.Next;
for (; Next; Next = Next->Next) {
- if (Next->Type == TT_TemplateOpener) {
+ if (Next->is(TT_TemplateOpener)) {
Next = Next->MatchingParen;
} else if (Next->is(tok::coloncolon)) {
Next = Next->Next;
@@ -1229,7 +1364,7 @@ static bool isFunctionDeclarationName(const FormatToken &Current) {
for (const FormatToken *Tok = Next->Next; Tok != Next->MatchingParen;
Tok = Tok->Next) {
if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() ||
- Tok->Type == TT_PointerOrReference || Tok->Type == TT_StartOfName)
+ Tok->isOneOf(TT_PointerOrReference, TT_StartOfName))
return true;
if (Tok->isOneOf(tok::l_brace, tok::string_literal) || Tok->Tok.isLiteral())
return false;
@@ -1253,7 +1388,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
while (Current) {
if (isFunctionDeclarationName(*Current))
Current->Type = TT_FunctionDeclarationName;
- if (Current->Type == TT_LineComment) {
+ if (Current->is(TT_LineComment)) {
if (Current->Previous->BlockKind == BK_BracedInit &&
Current->Previous->opensScope())
Current->SpacesRequiredBefore = Style.Cpp11BracedListStyle ? 0 : 1;
@@ -1273,7 +1408,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
if (Parameter->isOneOf(tok::comment, tok::r_brace))
break;
if (Parameter->Previous && Parameter->Previous->is(tok::comma)) {
- if (Parameter->Previous->Type != TT_CtorInitializerComma &&
+ if (!Parameter->Previous->is(TT_CtorInitializerComma) &&
Parameter->HasUnescapedNewline)
Parameter->MustBreakBefore = true;
break;
@@ -1288,6 +1423,13 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
Current->MustBreakBefore =
Current->MustBreakBefore || mustBreakBefore(Line, *Current);
+ if (Style.AlwaysBreakAfterDefinitionReturnType && InFunctionDecl &&
+ Current->is(TT_FunctionDeclarationName) &&
+ !Line.Last->isOneOf(tok::semi, tok::comment)) // Only for definitions.
+ // FIXME: Line.Last points to other characters than tok::semi
+ // and tok::lbrace.
+ Current->MustBreakBefore = true;
+
Current->CanBreakBefore =
Current->MustBreakBefore || canBreakBefore(Line, *Current);
unsigned ChildSize = 0;
@@ -1296,15 +1438,17 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
ChildSize = LastOfChild.isTrailingComment() ? Style.ColumnLimit
: LastOfChild.TotalLength + 1;
}
- if (Current->MustBreakBefore || Current->Previous->Children.size() > 1 ||
+ const FormatToken *Prev = Current->Previous;
+ if (Current->MustBreakBefore || Prev->Children.size() > 1 ||
+ (Prev->Children.size() == 1 &&
+ Prev->Children[0]->First->MustBreakBefore) ||
Current->IsMultiline)
- Current->TotalLength = Current->Previous->TotalLength + Style.ColumnLimit;
+ Current->TotalLength = Prev->TotalLength + Style.ColumnLimit;
else
- Current->TotalLength = Current->Previous->TotalLength +
- Current->ColumnWidth + ChildSize +
- Current->SpacesRequiredBefore;
+ Current->TotalLength = Prev->TotalLength + Current->ColumnWidth +
+ ChildSize + Current->SpacesRequiredBefore;
- if (Current->Type == TT_CtorInitializerColon)
+ if (Current->is(TT_CtorInitializerColon))
InFunctionDecl = false;
// FIXME: Only calculate this if CanBreakBefore is true once static
@@ -1349,20 +1493,34 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.is(tok::semi))
return 0;
+
+ if (Style.Language == FormatStyle::LK_Java) {
+ if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_throws))
+ return 1;
+ if (Right.is(Keywords.kw_implements))
+ return 2;
+ if (Left.is(tok::comma) && Left.NestingLevel == 0)
+ return 3;
+ } else if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Right.is(Keywords.kw_function))
+ return 100;
+ }
+
if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next &&
- Right.Next->Type == TT_DictLiteral))
+ Right.Next->is(TT_DictLiteral)))
return 1;
if (Right.is(tok::l_square)) {
if (Style.Language == FormatStyle::LK_Proto)
return 1;
- if (Right.Type != TT_ObjCMethodExpr && Right.Type != TT_LambdaLSquare)
+ if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare))
return 500;
}
- if (Right.Type == TT_StartOfName ||
- Right.Type == TT_FunctionDeclarationName || Right.is(tok::kw_operator)) {
+
+ if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
+ Right.is(tok::kw_operator)) {
if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
return 3;
- if (Left.Type == TT_StartOfName)
+ if (Left.is(TT_StartOfName))
return 20;
if (InFunctionDecl && Right.NestingLevel == 0)
return Style.PenaltyReturnTypeOnItsOwnLine;
@@ -1370,7 +1528,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
}
if (Left.is(tok::equal) && Right.is(tok::l_brace))
return 150;
- if (Left.Type == TT_CastRParen)
+ if (Left.is(TT_CastRParen))
return 100;
if (Left.is(tok::coloncolon) ||
(Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto))
@@ -1378,8 +1536,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.isOneOf(tok::kw_class, tok::kw_struct))
return 5000;
- if (Left.Type == TT_RangeBasedForLoopColon ||
- Left.Type == TT_InheritanceColon)
+ if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon))
return 2;
if (Right.isMemberAccess()) {
@@ -1389,8 +1546,13 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
return 150;
}
- if (Right.Type == TT_TrailingAnnotation &&
+ if (Right.is(TT_TrailingAnnotation) &&
(!Right.Next || Right.Next->isNot(tok::l_paren))) {
+ // Moving trailing annotations to the next line is fine for ObjC method
+ // declarations.
+ if (Line.First->is(TT_ObjCMethodSpecifier))
+
+ return 10;
// Generally, breaking before a trailing annotation is bad unless it is
// function-like. It seems to be especially preferable to keep standard
// annotations (i.e. "const", "final" and "override") on the same line.
@@ -1406,18 +1568,27 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
// In Objective-C method expressions, prefer breaking before "param:" over
// breaking after it.
- if (Right.Type == TT_SelectorName)
+ if (Right.is(TT_SelectorName))
return 0;
- if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
+ if (Left.is(tok::colon) && Left.is(TT_ObjCMethodExpr))
return Line.MightBeFunctionDecl ? 50 : 500;
- if (Left.is(tok::l_paren) && InFunctionDecl)
+ if (Left.is(tok::l_paren) && InFunctionDecl && Style.AlignAfterOpenBracket)
return 100;
if (Left.is(tok::equal) && InFunctionDecl)
return 110;
- if (Left.opensScope())
+ if (Right.is(tok::r_brace))
+ return 1;
+ if (Left.is(TT_TemplateOpener))
+ return 100;
+ if (Left.opensScope()) {
+ if (!Style.AlignAfterOpenBracket)
+ return 0;
return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter
: 19;
+ }
+ if (Left.is(TT_JavaAnnotation))
+ return 50;
if (Right.is(tok::lessless)) {
if (Left.is(tok::string_literal)) {
@@ -1433,7 +1604,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
}
return 1; // Breaking at a << is really cheap.
}
- if (Left.Type == TT_ConditionalExpr)
+ if (Left.is(TT_ConditionalExpr))
return prec::Conditional;
prec::Level Level = Left.getPrecedence();
@@ -1446,18 +1617,6 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
const FormatToken &Left,
const FormatToken &Right) {
- if (Style.Language == FormatStyle::LK_Proto) {
- if (Right.is(tok::period) &&
- (Left.TokenText == "optional" || Left.TokenText == "required" ||
- Left.TokenText == "repeated"))
- return true;
- if (Right.is(tok::l_paren) &&
- (Left.TokenText == "returns" || Left.TokenText == "option"))
- return true;
- } else if (Style.Language == FormatStyle::LK_JavaScript) {
- if (Left.TokenText == "var")
- return true;
- }
if (Left.is(tok::kw_return) && Right.isNot(tok::semi))
return true;
if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty &&
@@ -1470,21 +1629,16 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Left.is(tok::l_paren) && Right.is(tok::r_paren))
return Style.SpaceInEmptyParentheses;
if (Left.is(tok::l_paren) || Right.is(tok::r_paren))
- return (Right.Type == TT_CastRParen ||
- (Left.MatchingParen && Left.MatchingParen->Type == TT_CastRParen))
+ return (Right.is(TT_CastRParen) ||
+ (Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen)))
? Style.SpacesInCStyleCastParentheses
: Style.SpacesInParentheses;
- if (Style.SpacesInAngles &&
- ((Left.Type == TT_TemplateOpener) != (Right.Type == TT_TemplateCloser)))
- return true;
if (Right.isOneOf(tok::semi, tok::comma))
return false;
if (Right.is(tok::less) &&
- (Left.is(tok::kw_template) ||
+ (Left.isOneOf(tok::kw_template, tok::r_paren) ||
(Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
return true;
- if (Left.is(tok::arrow) || Right.is(tok::arrow))
- return false;
if (Left.isOneOf(tok::exclaim, tok::tilde))
return false;
if (Left.is(tok::at) &&
@@ -1494,69 +1648,72 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return false;
if (Left.is(tok::coloncolon))
return false;
- if (Right.is(tok::coloncolon) && Left.isNot(tok::l_brace))
- return (Left.is(tok::less) && Style.Standard == FormatStyle::LS_Cpp03) ||
- !Left.isOneOf(tok::identifier, tok::greater, tok::l_paren,
- tok::r_paren, tok::less);
if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less))
return false;
if (Right.is(tok::ellipsis))
return Left.Tok.isLiteral();
if (Left.is(tok::l_square) && Right.is(tok::amp))
return false;
- if (Right.Type == TT_PointerOrReference)
+ if (Right.is(TT_PointerOrReference))
return Left.Tok.isLiteral() ||
- ((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) &&
+ (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) &&
Style.PointerAlignment != FormatStyle::PAS_Left);
- if (Right.Type == TT_FunctionTypeLParen && Left.isNot(tok::l_paren) &&
- (Left.Type != TT_PointerOrReference || Style.PointerAlignment != FormatStyle::PAS_Right))
+ if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) &&
+ (!Left.is(TT_PointerOrReference) ||
+ Style.PointerAlignment != FormatStyle::PAS_Right))
return true;
- if (Left.Type == TT_PointerOrReference)
- return Right.Tok.isLiteral() || Right.Type == TT_BlockComment ||
- ((Right.Type != TT_PointerOrReference) &&
- Right.isNot(tok::l_paren) && Style.PointerAlignment != FormatStyle::PAS_Right &&
- Left.Previous &&
+ if (Left.is(TT_PointerOrReference))
+ return Right.Tok.isLiteral() || Right.is(TT_BlockComment) ||
+ (!Right.isOneOf(TT_PointerOrReference, tok::l_paren) &&
+ Style.PointerAlignment != FormatStyle::PAS_Right && Left.Previous &&
!Left.Previous->isOneOf(tok::l_paren, tok::coloncolon));
if (Right.is(tok::star) && Left.is(tok::l_paren))
return false;
if (Left.is(tok::l_square))
- return Left.Type == TT_ArrayInitializerLSquare &&
- Style.SpacesInContainerLiterals && Right.isNot(tok::r_square);
+ return (Left.is(TT_ArrayInitializerLSquare) &&
+ Style.SpacesInContainerLiterals && Right.isNot(tok::r_square)) ||
+ (Left.is(TT_ArraySubscriptLSquare) && Style.SpacesInSquareBrackets &&
+ Right.isNot(tok::r_square));
if (Right.is(tok::r_square))
- return Right.MatchingParen && Style.SpacesInContainerLiterals &&
- Right.MatchingParen->Type == TT_ArrayInitializerLSquare;
- if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr &&
- Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant) &&
- Left.Type != TT_DictLiteral)
+ return Right.MatchingParen &&
+ ((Style.SpacesInContainerLiterals &&
+ Right.MatchingParen->is(TT_ArrayInitializerLSquare)) ||
+ (Style.SpacesInSquareBrackets &&
+ Right.MatchingParen->is(TT_ArraySubscriptLSquare)));
+ if (Right.is(tok::l_square) &&
+ !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare) &&
+ !Left.isOneOf(tok::numeric_constant, TT_DictLiteral))
return false;
if (Left.is(tok::colon))
- return Left.Type != TT_ObjCMethodExpr;
- if (Left.Type == TT_BlockComment)
+ return !Left.is(TT_ObjCMethodExpr);
+ if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
+ return !Left.Children.empty(); // No spaces in "{}".
+ if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) ||
+ (Right.is(tok::r_brace) && Right.MatchingParen &&
+ Right.MatchingParen->BlockKind != BK_Block))
+ return !Style.Cpp11BracedListStyle;
+ if (Left.is(TT_BlockComment))
return !Left.TokenText.endswith("=*/");
if (Right.is(tok::l_paren)) {
- if (Left.is(tok::r_paren) && Left.Type == TT_AttributeParen)
+ if (Left.is(tok::r_paren) && Left.is(TT_AttributeParen))
return true;
- return Line.Type == LT_ObjCDecl ||
- Left.isOneOf(tok::kw_new, tok::kw_delete, tok::semi) ||
+ return Line.Type == LT_ObjCDecl || Left.is(tok::semi) ||
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
(Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while,
- tok::kw_switch, tok::kw_catch, tok::kw_case) ||
+ tok::kw_switch, tok::kw_case) ||
+ (Left.isOneOf(tok::kw_try, tok::kw_catch, tok::kw_new,
+ tok::kw_delete) &&
+ (!Left.Previous || Left.Previous->isNot(tok::period))) ||
Left.IsForEachMacro)) ||
(Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&
- Left.isOneOf(tok::identifier, tok::kw___attribute) &&
+ (Left.is(tok::identifier) || Left.isFunctionLikeKeyword()) &&
Line.Type != LT_PreprocessorDirective);
}
if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword)
return false;
- if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
- return !Left.Children.empty(); // No spaces in "{}".
- if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) ||
- (Right.is(tok::r_brace) && Right.MatchingParen &&
- Right.MatchingParen->BlockKind != BK_Block))
- return !Style.Cpp11BracedListStyle;
- if (Right.Type == TT_UnaryOperator)
+ if (Right.is(TT_UnaryOperator))
return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) &&
- (Left.isNot(tok::colon) || Left.Type != TT_ObjCMethodExpr);
+ (Left.isNot(tok::colon) || Left.isNot(TT_ObjCMethodExpr));
if ((Left.isOneOf(tok::identifier, tok::greater, tok::r_square,
tok::r_paren) ||
Left.isSimpleTypeSpecifier()) &&
@@ -1567,78 +1724,120 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return false;
if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L")
return false;
+ if (Left.is(TT_TemplateCloser) && Left.MatchingParen &&
+ Left.MatchingParen->Previous &&
+ Left.MatchingParen->Previous->is(tok::period))
+ // A.<B>DoSomething();
+ return false;
+ if (Left.is(TT_TemplateCloser) && Right.is(tok::l_square))
+ return false;
return true;
}
bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
- const FormatToken &Tok) {
- if (Tok.Tok.getIdentifierInfo() && Tok.Previous->Tok.getIdentifierInfo())
+ const FormatToken &Right) {
+ const FormatToken &Left = *Right.Previous;
+ if (Style.Language == FormatStyle::LK_Proto) {
+ if (Right.is(tok::period) &&
+ Left.isOneOf(Keywords.kw_optional, Keywords.kw_required,
+ Keywords.kw_repeated))
+ return true;
+ if (Right.is(tok::l_paren) &&
+ Left.isOneOf(Keywords.kw_returns, Keywords.kw_option))
+ return true;
+ } else if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Left.is(Keywords.kw_var))
+ return true;
+ } else if (Style.Language == FormatStyle::LK_Java) {
+ if (Left.is(tok::r_square) && Right.is(tok::l_brace))
+ return true;
+ if (Left.is(TT_LambdaArrow) || Right.is(TT_LambdaArrow))
+ return true;
+ if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren))
+ return Style.SpaceBeforeParens != FormatStyle::SBPO_Never;
+ if ((Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private,
+ tok::kw_protected) ||
+ Left.isOneOf(Keywords.kw_final, Keywords.kw_abstract,
+ Keywords.kw_native)) &&
+ Right.is(TT_TemplateOpener))
+ return true;
+ }
+ if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo())
return true; // Never ever merge two identifiers.
- if (Tok.Previous->Type == TT_ImplicitStringLiteral)
- return Tok.WhitespaceRange.getBegin() != Tok.WhitespaceRange.getEnd();
+ if (Left.is(TT_ImplicitStringLiteral))
+ return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
if (Line.Type == LT_ObjCMethodDecl) {
- if (Tok.Previous->Type == TT_ObjCMethodSpecifier)
+ if (Left.is(TT_ObjCMethodSpecifier))
return true;
- if (Tok.Previous->is(tok::r_paren) && Tok.is(tok::identifier))
+ if (Left.is(tok::r_paren) && Right.is(tok::identifier))
// Don't space between ')' and <id>
return false;
}
if (Line.Type == LT_ObjCProperty &&
- (Tok.is(tok::equal) || Tok.Previous->is(tok::equal)))
+ (Right.is(tok::equal) || Left.is(tok::equal)))
return false;
- if (Tok.Type == TT_TrailingReturnArrow ||
- Tok.Previous->Type == TT_TrailingReturnArrow)
+ if (Right.is(TT_TrailingReturnArrow) || Left.is(TT_TrailingReturnArrow))
return true;
- if (Tok.Previous->is(tok::comma))
+ if (Left.is(tok::comma))
return true;
- if (Tok.is(tok::comma))
+ if (Right.is(tok::comma))
return false;
- if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen)
+ if (Right.isOneOf(TT_CtorInitializerColon, TT_ObjCBlockLParen))
return true;
- if (Tok.Previous->Tok.is(tok::kw_operator))
- return Tok.is(tok::coloncolon);
- if (Tok.Type == TT_OverloadedOperatorLParen)
+ if (Left.is(tok::kw_operator))
+ return Right.is(tok::coloncolon);
+ if (Right.is(TT_OverloadedOperatorLParen))
return false;
- if (Tok.is(tok::colon))
+ if (Right.is(tok::colon))
return !Line.First->isOneOf(tok::kw_case, tok::kw_default) &&
- Tok.getNextNonComment() && Tok.Type != TT_ObjCMethodExpr &&
- !Tok.Previous->is(tok::question) &&
- (Tok.Type != TT_DictLiteral || Style.SpacesInContainerLiterals);
- if (Tok.Previous->Type == TT_UnaryOperator ||
- Tok.Previous->Type == TT_CastRParen)
- return Tok.Type == TT_BinaryOperator;
- if (Tok.Previous->is(tok::greater) && Tok.is(tok::greater)) {
- return Tok.Type == TT_TemplateCloser &&
- Tok.Previous->Type == TT_TemplateCloser &&
+ Right.getNextNonComment() && Right.isNot(TT_ObjCMethodExpr) &&
+ !Left.is(tok::question) &&
+ !(Right.is(TT_InlineASMColon) && Left.is(tok::coloncolon)) &&
+ (Right.isNot(TT_DictLiteral) || Style.SpacesInContainerLiterals);
+ if (Left.is(TT_UnaryOperator))
+ return Right.is(TT_BinaryOperator);
+ if (Left.is(TT_CastRParen))
+ return Style.SpaceAfterCStyleCast || Right.is(TT_BinaryOperator);
+ if (Left.is(tok::greater) && Right.is(tok::greater)) {
+ return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) &&
(Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles);
}
- if (Tok.isOneOf(tok::arrowstar, tok::periodstar) ||
- Tok.Previous->isOneOf(tok::arrowstar, tok::periodstar))
+ if (Right.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
+ Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar))
return false;
if (!Style.SpaceBeforeAssignmentOperators &&
- Tok.getPrecedence() == prec::Assignment)
+ Right.getPrecedence() == prec::Assignment)
return false;
- if ((Tok.Type == TT_BinaryOperator && !Tok.Previous->is(tok::l_paren)) ||
- Tok.Previous->Type == TT_BinaryOperator ||
- Tok.Previous->Type == TT_ConditionalExpr)
+ if (Right.is(tok::coloncolon) && Left.isNot(tok::l_brace))
+ return (Left.is(TT_TemplateOpener) &&
+ Style.Standard == FormatStyle::LS_Cpp03) ||
+ !(Left.isOneOf(tok::identifier, tok::l_paren, tok::r_paren) ||
+ Left.isOneOf(TT_TemplateCloser, TT_TemplateOpener));
+ if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser)))
+ return Style.SpacesInAngles;
+ if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) ||
+ Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr))
return true;
- if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
+ if (Left.is(TT_TemplateCloser) && Right.is(tok::l_paren))
+ return Style.SpaceBeforeParens == FormatStyle::SBPO_Always;
+ if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) &&
+ Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen))
return false;
- if (Tok.is(tok::less) && Tok.Previous->isNot(tok::l_paren) &&
+ if (Right.is(tok::less) && Left.isNot(tok::l_paren) &&
Line.First->is(tok::hash))
return true;
- if (Tok.Type == TT_TrailingUnaryOperator)
+ if (Right.is(TT_TrailingUnaryOperator))
return false;
- if (Tok.Previous->Type == TT_RegexLiteral)
+ if (Left.is(TT_RegexLiteral))
return false;
- return spaceRequiredBetween(Line, *Tok.Previous, Tok);
+ return spaceRequiredBetween(Line, Left, Right);
}
// Returns 'true' if 'Tok' is a brace we'd want to break before in Allman style.
static bool isAllmanBrace(const FormatToken &Tok) {
return Tok.is(tok::l_brace) && Tok.BlockKind == BK_Block &&
- Tok.Type != TT_ObjCBlockLBrace && Tok.Type != TT_DictLiteral;
+ !Tok.isOneOf(TT_ObjCBlockLBrace, TT_DictLiteral);
}
bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
@@ -1646,54 +1845,66 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
const FormatToken &Left = *Right.Previous;
if (Right.NewlinesBefore > 1)
return true;
- if (Right.is(tok::comment)) {
- return Right.Previous->BlockKind != BK_BracedInit &&
- Right.Previous->Type != TT_CtorInitializerColon &&
+
+ // If the last token before a '}' is a comma or a trailing comment, the
+ // intention is to insert a line break after it in order to make shuffling
+ // around entries easier.
+ const FormatToken *BeforeClosingBrace = nullptr;
+ if (Left.is(tok::l_brace) && Left.BlockKind != BK_Block && Left.MatchingParen)
+ BeforeClosingBrace = Left.MatchingParen->Previous;
+ else if (Right.is(tok::r_brace) && Right.BlockKind != BK_Block)
+ BeforeClosingBrace = &Left;
+ if (BeforeClosingBrace && (BeforeClosingBrace->is(tok::comma) ||
+ BeforeClosingBrace->isTrailingComment()))
+ return true;
+
+ if (Right.is(tok::comment))
+ return Left.BlockKind != BK_BracedInit &&
+ Left.isNot(TT_CtorInitializerColon) &&
(Right.NewlinesBefore > 0 && Right.HasUnescapedNewline);
- } else if (Right.Previous->isTrailingComment() ||
- (Right.isStringLiteral() && Right.Previous->isStringLiteral())) {
+ if (Right.Previous->isTrailingComment() ||
+ (Right.isStringLiteral() && Right.Previous->isStringLiteral()))
return true;
- } else if (Right.Previous->IsUnterminatedLiteral) {
+ if (Right.Previous->IsUnterminatedLiteral)
return true;
- } else if (Right.is(tok::lessless) && Right.Next &&
- Right.Previous->is(tok::string_literal) &&
- Right.Next->is(tok::string_literal)) {
+ if (Right.is(tok::lessless) && Right.Next &&
+ Right.Previous->is(tok::string_literal) &&
+ Right.Next->is(tok::string_literal))
return true;
- } else if (Right.Previous->ClosesTemplateDeclaration &&
- Right.Previous->MatchingParen &&
- Right.Previous->MatchingParen->NestingLevel == 0 &&
- Style.AlwaysBreakTemplateDeclarations) {
+ if (Right.Previous->ClosesTemplateDeclaration &&
+ Right.Previous->MatchingParen &&
+ Right.Previous->MatchingParen->NestingLevel == 0 &&
+ Style.AlwaysBreakTemplateDeclarations)
return true;
- } else if ((Right.Type == TT_CtorInitializerComma ||
- Right.Type == TT_CtorInitializerColon) &&
- Style.BreakConstructorInitializersBeforeComma &&
- !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) {
+ if ((Right.isOneOf(TT_CtorInitializerComma, TT_CtorInitializerColon)) &&
+ Style.BreakConstructorInitializersBeforeComma &&
+ !Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
return true;
- } else if (Right.is(tok::string_literal) &&
- Right.TokenText.startswith("R\"")) {
+ if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\""))
// Raw string literals are special wrt. line breaks. The author has made a
// deliberate choice and might have aligned the contents of the string
// literal accordingly. Thus, we try keep existing line breaks.
return Right.NewlinesBefore > 0;
- } else if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
- Style.Language == FormatStyle::LK_Proto) {
- // Don't enums onto single lines in protocol buffers.
+ if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
+ Style.Language == FormatStyle::LK_Proto)
+ // Don't put enums onto single lines in protocol buffers.
return true;
- } else if (isAllmanBrace(Left) || isAllmanBrace(Right)) {
+ if (Style.Language == FormatStyle::LK_JavaScript && Right.is(tok::r_brace) &&
+ Left.is(tok::l_brace) && !Left.Children.empty())
+ // Support AllowShortFunctionsOnASingleLine for JavaScript.
+ return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None ||
+ (Left.NestingLevel == 0 && Line.Level == 0 &&
+ Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline);
+ if (isAllmanBrace(Left) || isAllmanBrace(Right))
return Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
Style.BreakBeforeBraces == FormatStyle::BS_GNU;
- }
-
- // If the last token before a '}' is a comma or a comment, the intention is to
- // insert a line break after it in order to make shuffling around entries
- // easier.
- const FormatToken *BeforeClosingBrace = nullptr;
- if (Left.is(tok::l_brace) && Left.MatchingParen)
- BeforeClosingBrace = Left.MatchingParen->Previous;
- else if (Right.is(tok::r_brace))
- BeforeClosingBrace = Right.Previous;
- if (BeforeClosingBrace &&
- BeforeClosingBrace->isOneOf(tok::comma, tok::comment))
+ if (Style.Language == FormatStyle::LK_Proto && Left.isNot(tok::l_brace) &&
+ Right.is(TT_SelectorName))
+ return true;
+ if (Left.is(TT_ObjCBlockLBrace) && !Style.AllowShortBlocksOnASingleLine)
+ return true;
+ if (Right.is(tok::lessless) && Left.is(tok::identifier) &&
+ Left.TokenText == "endl")
return true;
if (Style.Language == FormatStyle::LK_JavaScript) {
@@ -1701,6 +1912,17 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
if (Right.is(tok::char_constant) && Left.is(tok::plus) && Left.Previous &&
Left.Previous->is(tok::char_constant))
return true;
+ if (Left.is(TT_DictLiteral) && Left.is(tok::l_brace) &&
+ Left.NestingLevel == 0)
+ return true;
+ } else if (Style.Language == FormatStyle::LK_Java) {
+ if (Left.is(TT_LeadingJavaAnnotation) &&
+ Right.isNot(TT_LeadingJavaAnnotation) && Right.isNot(tok::l_paren) &&
+ Line.Last->is(tok::l_brace))
+ return true;
+ if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next &&
+ Right.Next->is(tok::string_literal))
+ return true;
}
return false;
@@ -1709,12 +1931,24 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
const FormatToken &Right) {
const FormatToken &Left = *Right.Previous;
+
+ if (Style.Language == FormatStyle::LK_Java) {
+ if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
+ Keywords.kw_implements))
+ return false;
+ if (Right.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
+ Keywords.kw_implements))
+ return true;
+ }
+
if (Left.is(tok::at))
return false;
if (Left.Tok.getObjCKeywordID() == tok::objc_interface)
return false;
- if (Right.Type == TT_StartOfName ||
- Right.Type == TT_FunctionDeclarationName || Right.is(tok::kw_operator))
+ if (Left.isOneOf(TT_JavaAnnotation, TT_LeadingJavaAnnotation))
+ return !Right.is(tok::l_paren);
+ if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
+ Right.is(tok::kw_operator))
return true;
if (Right.isTrailingComment())
// We rely on MustBreakBefore being set correctly here as we should not
@@ -1725,47 +1959,46 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return Left.BlockKind == BK_BracedInit;
if (Left.is(tok::question) && Right.is(tok::colon))
return false;
- if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
+ if (Right.is(TT_ConditionalExpr) || Right.is(tok::question))
return Style.BreakBeforeTernaryOperators;
- if (Left.Type == TT_ConditionalExpr || Left.is(tok::question))
+ if (Left.is(TT_ConditionalExpr) || Left.is(tok::question))
return !Style.BreakBeforeTernaryOperators;
- if (Right.Type == TT_InheritanceColon)
+ if (Right.is(TT_InheritanceColon))
return true;
- if (Right.is(tok::colon) && (Right.Type != TT_CtorInitializerColon &&
- Right.Type != TT_InlineASMColon))
+ if (Right.is(tok::colon) &&
+ !Right.isOneOf(TT_CtorInitializerColon, TT_InlineASMColon))
return false;
- if (Left.is(tok::colon) &&
- (Left.Type == TT_DictLiteral || Left.Type == TT_ObjCMethodExpr))
+ if (Left.is(tok::colon) && (Left.isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)))
return true;
- if (Right.Type == TT_SelectorName)
+ if (Right.is(TT_SelectorName))
return true;
if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty)
return true;
if (Left.ClosesTemplateDeclaration)
return true;
- if (Right.Type == TT_RangeBasedForLoopColon ||
- Right.Type == TT_OverloadedOperatorLParen ||
- Right.Type == TT_OverloadedOperator)
+ if (Right.isOneOf(TT_RangeBasedForLoopColon, TT_OverloadedOperatorLParen,
+ TT_OverloadedOperator))
return false;
- if (Left.Type == TT_RangeBasedForLoopColon)
+ if (Left.is(TT_RangeBasedForLoopColon))
return true;
- if (Right.Type == TT_RangeBasedForLoopColon)
+ if (Right.is(TT_RangeBasedForLoopColon))
return false;
- if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
- Left.Type == TT_UnaryOperator || Left.is(tok::kw_operator))
+ if (Left.isOneOf(TT_PointerOrReference, TT_TemplateCloser,
+ TT_UnaryOperator) ||
+ Left.is(tok::kw_operator))
return false;
if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
return false;
- if (Left.is(tok::l_paren) && Left.Type == TT_AttributeParen)
+ if (Left.is(tok::l_paren) && Left.is(TT_AttributeParen))
return false;
if (Left.is(tok::l_paren) && Left.Previous &&
- (Left.Previous->Type == TT_BinaryOperator ||
- Left.Previous->Type == TT_CastRParen || Left.Previous->is(tok::kw_if)))
+ (Left.Previous->isOneOf(TT_BinaryOperator, TT_CastRParen) ||
+ Left.Previous->is(tok::kw_if)))
return false;
- if (Right.Type == TT_ImplicitStringLiteral)
+ if (Right.is(TT_ImplicitStringLiteral))
return false;
- if (Right.is(tok::r_paren) || Right.Type == TT_TemplateCloser)
+ if (Right.is(tok::r_paren) || Right.is(TT_TemplateCloser))
return false;
// We only break before r_brace if there was a corresponding break before
@@ -1775,7 +2008,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
// Allow breaking after a trailing annotation, e.g. after a method
// declaration.
- if (Left.Type == TT_TrailingAnnotation)
+ if (Left.is(TT_TrailingAnnotation))
return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal, tok::l_paren,
tok::less, tok::coloncolon);
@@ -1785,29 +2018,35 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Left.is(tok::identifier) && Right.is(tok::string_literal))
return true;
- if (Right.is(tok::identifier) && Right.Next &&
- Right.Next->Type == TT_DictLiteral)
+ if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
return true;
- if (Left.Type == TT_CtorInitializerComma &&
+ if (Left.is(TT_CtorInitializerComma) &&
Style.BreakConstructorInitializersBeforeComma)
return false;
- if (Right.Type == TT_CtorInitializerComma &&
+ if (Right.is(TT_CtorInitializerComma) &&
Style.BreakConstructorInitializersBeforeComma)
return true;
if (Left.is(tok::greater) && Right.is(tok::greater) &&
- Left.Type != TT_TemplateCloser)
+ Left.isNot(TT_TemplateCloser))
return false;
- if (Right.Type == TT_BinaryOperator && Style.BreakBeforeBinaryOperators)
+ if (Right.is(TT_BinaryOperator) &&
+ Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None &&
+ (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_All ||
+ Right.getPrecedence() != prec::Assignment))
+ return true;
+ if (Left.is(TT_ArrayInitializerLSquare))
+ return true;
+ if (Right.is(tok::kw_typename) && Left.isNot(tok::kw_const))
return true;
- if (Left.Type == TT_ArrayInitializerLSquare)
+ if (Left.isBinaryOperator() && !Left.isOneOf(tok::arrowstar, tok::lessless) &&
+ Style.BreakBeforeBinaryOperators != FormatStyle::BOS_All &&
+ (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None ||
+ Left.getPrecedence() == prec::Assignment))
return true;
- return (Left.isBinaryOperator() &&
- !Left.isOneOf(tok::arrowstar, tok::lessless) &&
- !Style.BreakBeforeBinaryOperators) ||
- Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
+ return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
tok::kw_class, tok::kw_struct) ||
- Right.isMemberAccess() ||
+ Right.isMemberAccess() || Right.is(TT_TrailingReturnArrow) ||
Right.isOneOf(tok::lessless, tok::colon, tok::l_square, tok::at) ||
(Left.is(tok::r_paren) &&
Right.isOneOf(tok::identifier, tok::kw_const)) ||
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index 36de010fc940..ff8e32a56afc 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FORMAT_TOKEN_ANNOTATOR_H
-#define LLVM_CLANG_FORMAT_TOKEN_ANNOTATOR_H
+#ifndef LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H
+#define LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H
#include "UnwrappedLineParser.h"
#include "clang/Format/Format.h"
@@ -27,12 +27,13 @@ namespace format {
enum LineType {
LT_Invalid,
- LT_Other,
- LT_PreprocessorDirective,
- LT_VirtualFunctionDecl,
+ LT_ImportStatement,
LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
LT_ObjCMethodDecl,
- LT_ObjCProperty // An @property line.
+ LT_ObjCProperty, // An @property line.
+ LT_Other,
+ LT_PreprocessorDirective,
+ LT_VirtualFunctionDecl
};
class AnnotatedLine {
@@ -108,8 +109,8 @@ private:
/// \c UnwrappedLine.
class TokenAnnotator {
public:
- TokenAnnotator(const FormatStyle &Style, IdentifierInfo &Ident_in)
- : Style(Style), Ident_in(Ident_in) {}
+ TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
+ : Style(Style), Keywords(Keywords) {}
/// \brief Adapts the indent levels of comment lines to the indent of the
/// subsequent line.
@@ -139,11 +140,10 @@ private:
const FormatStyle &Style;
- // Contextual keywords:
- IdentifierInfo &Ident_in;
+ const AdditionalKeywords &Keywords;
};
} // end namespace format
} // end namespace clang
-#endif // LLVM_CLANG_FORMAT_TOKEN_ANNOTATOR_H
+#endif
diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
new file mode 100644
index 000000000000..ca66e7351641
--- /dev/null
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -0,0 +1,706 @@
+//===--- UnwrappedLineFormatter.cpp - Format C++ code ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnwrappedLineFormatter.h"
+#include "WhitespaceManager.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "format-formatter"
+
+namespace clang {
+namespace format {
+
+namespace {
+
+bool startsExternCBlock(const AnnotatedLine &Line) {
+ const FormatToken *Next = Line.First->getNextNonComment();
+ const FormatToken *NextNext = Next ? Next->getNextNonComment() : nullptr;
+ return Line.First->is(tok::kw_extern) && Next && Next->isStringLiteral() &&
+ NextNext && NextNext->is(tok::l_brace);
+}
+
+class LineJoiner {
+public:
+ LineJoiner(const FormatStyle &Style) : Style(Style) {}
+
+ /// \brief Calculates how many lines can be merged into 1 starting at \p I.
+ unsigned
+ tryFitMultipleLinesInOne(unsigned Indent,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
+ // We can never merge stuff if there are trailing line comments.
+ const AnnotatedLine *TheLine = *I;
+ if (TheLine->Last->is(TT_LineComment))
+ return 0;
+
+ if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
+ return 0;
+
+ unsigned Limit =
+ Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;
+ // If we already exceed the column limit, we set 'Limit' to 0. The different
+ // tryMerge..() functions can then decide whether to still do merging.
+ Limit = TheLine->Last->TotalLength > Limit
+ ? 0
+ : Limit - TheLine->Last->TotalLength;
+
+ if (I + 1 == E || I[1]->Type == LT_Invalid || I[1]->First->MustBreakBefore)
+ return 0;
+
+ // FIXME: TheLine->Level != 0 might or might not be the right check to do.
+ // If necessary, change to something smarter.
+ bool MergeShortFunctions =
+ Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
+ (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty &&
+ I[1]->First->is(tok::r_brace)) ||
+ (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
+ TheLine->Level != 0);
+
+ if (TheLine->Last->is(TT_FunctionLBrace) &&
+ TheLine->First != TheLine->Last) {
+ return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
+ }
+ if (TheLine->Last->is(tok::l_brace)) {
+ return Style.BreakBeforeBraces == FormatStyle::BS_Attach
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+ }
+ if (I[1]->First->is(TT_FunctionLBrace) &&
+ Style.BreakBeforeBraces != FormatStyle::BS_Attach) {
+ if (I[1]->Last->is(TT_LineComment))
+ return 0;
+
+ // Check for Limit <= 2 to account for the " {".
+ if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))
+ return 0;
+ Limit -= 2;
+
+ unsigned MergedLines = 0;
+ if (MergeShortFunctions) {
+ MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
+ // If we managed to merge the block, count the function header, which is
+ // on a separate line.
+ if (MergedLines > 0)
+ ++MergedLines;
+ }
+ return MergedLines;
+ }
+ if (TheLine->First->is(tok::kw_if)) {
+ return Style.AllowShortIfStatementsOnASingleLine
+ ? tryMergeSimpleControlStatement(I, E, Limit)
+ : 0;
+ }
+ if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
+ return Style.AllowShortLoopsOnASingleLine
+ ? tryMergeSimpleControlStatement(I, E, Limit)
+ : 0;
+ }
+ if (TheLine->First->isOneOf(tok::kw_case, tok::kw_default)) {
+ return Style.AllowShortCaseLabelsOnASingleLine
+ ? tryMergeShortCaseLabels(I, E, Limit)
+ : 0;
+ }
+ if (TheLine->InPPDirective &&
+ (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {
+ return tryMergeSimplePPDirective(I, E, Limit);
+ }
+ return 0;
+ }
+
+private:
+ unsigned
+ tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ if (Limit == 0)
+ return 0;
+ if (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline)
+ return 0;
+ if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)
+ return 0;
+ if (1 + I[1]->Last->TotalLength > Limit)
+ return 0;
+ return 1;
+ }
+
+ unsigned tryMergeSimpleControlStatement(
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
+ if (Limit == 0)
+ return 0;
+ if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&
+ (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))
+ return 0;
+ if (I[1]->InPPDirective != (*I)->InPPDirective ||
+ (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
+ return 0;
+ Limit = limitConsideringMacros(I + 1, E, Limit);
+ AnnotatedLine &Line = **I;
+ if (Line.Last->isNot(tok::r_paren))
+ return 0;
+ if (1 + I[1]->Last->TotalLength > Limit)
+ return 0;
+ if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,
+ tok::kw_while, TT_LineComment))
+ return 0;
+ // Only inline simple if's (no nested if or else).
+ if (I + 2 != E && Line.First->is(tok::kw_if) &&
+ I[2]->First->is(tok::kw_else))
+ return 0;
+ return 1;
+ }
+
+ unsigned tryMergeShortCaseLabels(
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
+ if (Limit == 0 || I + 1 == E ||
+ I[1]->First->isOneOf(tok::kw_case, tok::kw_default))
+ return 0;
+ unsigned NumStmts = 0;
+ unsigned Length = 0;
+ bool InPPDirective = I[0]->InPPDirective;
+ for (; NumStmts < 3; ++NumStmts) {
+ if (I + 1 + NumStmts == E)
+ break;
+ const AnnotatedLine *Line = I[1 + NumStmts];
+ if (Line->InPPDirective != InPPDirective)
+ break;
+ if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
+ break;
+ if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
+ tok::kw_while, tok::comment))
+ return 0;
+ Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the space.
+ }
+ if (NumStmts == 0 || NumStmts == 3 || Length > Limit)
+ return 0;
+ return NumStmts;
+ }
+
+ unsigned
+ tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ AnnotatedLine &Line = **I;
+
+ // Don't merge ObjC @ keywords and methods.
+ if (Style.Language != FormatStyle::LK_Java &&
+ Line.First->isOneOf(tok::at, tok::minus, tok::plus))
+ return 0;
+
+ // Check that the current line allows merging. This depends on whether we
+ // are in a control flow statements as well as several style flags.
+ if (Line.First->isOneOf(tok::kw_else, tok::kw_case))
+ return 0;
+ if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,
+ tok::kw_catch, tok::kw_for, tok::r_brace)) {
+ if (!Style.AllowShortBlocksOnASingleLine)
+ return 0;
+ if (!Style.AllowShortIfStatementsOnASingleLine &&
+ Line.First->is(tok::kw_if))
+ return 0;
+ if (!Style.AllowShortLoopsOnASingleLine &&
+ Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))
+ return 0;
+ // FIXME: Consider an option to allow short exception handling clauses on
+ // a single line.
+ if (Line.First->isOneOf(tok::kw_try, tok::kw_catch))
+ return 0;
+ }
+
+ FormatToken *Tok = I[1]->First;
+ if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
+ (Tok->getNextNonComment() == nullptr ||
+ Tok->getNextNonComment()->is(tok::semi))) {
+ // We merge empty blocks even if the line exceeds the column limit.
+ Tok->SpacesRequiredBefore = 0;
+ Tok->CanBreakBefore = true;
+ return 1;
+ } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace) &&
+ !startsExternCBlock(Line)) {
+ // We don't merge short records.
+ if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct))
+ return 0;
+
+ // Check that we still have three lines and they fit into the limit.
+ if (I + 2 == E || I[2]->Type == LT_Invalid)
+ return 0;
+ Limit = limitConsideringMacros(I + 2, E, Limit);
+
+ if (!nextTwoLinesFitInto(I, Limit))
+ return 0;
+
+ // Second, check that the next line does not contain any braces - if it
+ // does, readability declines when putting it into a single line.
+ if (I[1]->Last->is(TT_LineComment))
+ return 0;
+ do {
+ if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
+ return 0;
+ Tok = Tok->Next;
+ } while (Tok);
+
+ // Last, check that the third line starts with a closing brace.
+ Tok = I[2]->First;
+ if (Tok->isNot(tok::r_brace))
+ return 0;
+
+ return 2;
+ }
+ return 0;
+ }
+
+ /// Returns the modified column limit for \p I if it is inside a macro and
+ /// needs a trailing '\'.
+ unsigned
+ limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ if (I[0]->InPPDirective && I + 1 != E &&
+ !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {
+ return Limit < 2 ? 0 : Limit - 2;
+ }
+ return Limit;
+ }
+
+ bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ unsigned Limit) {
+ if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
+ return false;
+ return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
+ }
+
+ bool containsMustBreak(const AnnotatedLine *Line) {
+ for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
+ if (Tok->MustBreakBefore)
+ return true;
+ }
+ return false;
+ }
+
+ const FormatStyle &Style;
+};
+
+class NoColumnLimitFormatter {
+public:
+ NoColumnLimitFormatter(ContinuationIndenter *Indenter) : Indenter(Indenter) {}
+
+ /// \brief Formats the line starting at \p State, simply keeping all of the
+ /// input's line breaking decisions.
+ void format(unsigned FirstIndent, const AnnotatedLine *Line) {
+ LineState State =
+ Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);
+ while (State.NextToken) {
+ bool Newline =
+ Indenter->mustBreak(State) ||
+ (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
+ Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
+ }
+ }
+
+private:
+ ContinuationIndenter *Indenter;
+};
+
+} // namespace
+
+unsigned
+UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
+ bool DryRun, int AdditionalIndent,
+ bool FixBadIndentation) {
+ LineJoiner Joiner(Style);
+
+ // Try to look up already computed penalty in DryRun-mode.
+ std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
+ &Lines, AdditionalIndent);
+ auto CacheIt = PenaltyCache.find(CacheKey);
+ if (DryRun && CacheIt != PenaltyCache.end())
+ return CacheIt->second;
+
+ assert(!Lines.empty());
+ unsigned Penalty = 0;
+ std::vector<int> IndentForLevel;
+ for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)
+ IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
+ const AnnotatedLine *PreviousLine = nullptr;
+ for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),
+ E = Lines.end();
+ I != E; ++I) {
+ const AnnotatedLine &TheLine = **I;
+ const FormatToken *FirstTok = TheLine.First;
+ int Offset = getIndentOffset(*FirstTok);
+
+ // Determine indent and try to merge multiple unwrapped lines.
+ unsigned Indent;
+ if (TheLine.InPPDirective) {
+ Indent = TheLine.Level * Style.IndentWidth;
+ } else {
+ while (IndentForLevel.size() <= TheLine.Level)
+ IndentForLevel.push_back(-1);
+ IndentForLevel.resize(TheLine.Level + 1);
+ Indent = getIndent(IndentForLevel, TheLine.Level);
+ }
+ unsigned LevelIndent = Indent;
+ if (static_cast<int>(Indent) + Offset >= 0)
+ Indent += Offset;
+
+ // Merge multiple lines if possible.
+ unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E);
+ if (MergedLines > 0 && Style.ColumnLimit == 0) {
+ // Disallow line merging if there is a break at the start of one of the
+ // input lines.
+ for (unsigned i = 0; i < MergedLines; ++i) {
+ if (I[i + 1]->First->NewlinesBefore > 0)
+ MergedLines = 0;
+ }
+ }
+ if (!DryRun) {
+ for (unsigned i = 0; i < MergedLines; ++i) {
+ join(*I[i], *I[i + 1]);
+ }
+ }
+ I += MergedLines;
+
+ bool FixIndentation =
+ FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);
+ if (TheLine.First->is(tok::eof)) {
+ if (PreviousLine && PreviousLine->Affected && !DryRun) {
+ // Remove the file's trailing whitespace.
+ unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);
+ Whitespaces->replaceWhitespace(*TheLine.First, Newlines,
+ /*IndentLevel=*/0, /*Spaces=*/0,
+ /*TargetColumn=*/0);
+ }
+ } else if (TheLine.Type != LT_Invalid &&
+ (TheLine.Affected || FixIndentation)) {
+ if (FirstTok->WhitespaceRange.isValid()) {
+ if (!DryRun)
+ formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level, Indent,
+ TheLine.InPPDirective);
+ } else {
+ Indent = LevelIndent = FirstTok->OriginalColumn;
+ }
+
+ // If everything fits on a single line, just put it there.
+ unsigned ColumnLimit = Style.ColumnLimit;
+ if (I + 1 != E) {
+ AnnotatedLine *NextLine = I[1];
+ if (NextLine->InPPDirective && !NextLine->First->HasUnescapedNewline)
+ ColumnLimit = getColumnLimit(TheLine.InPPDirective);
+ }
+
+ if (TheLine.Last->TotalLength + Indent <= ColumnLimit ||
+ TheLine.Type == LT_ImportStatement) {
+ LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun);
+ while (State.NextToken) {
+ formatChildren(State, /*Newline=*/false, /*DryRun=*/false, Penalty);
+ Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
+ }
+ } else if (Style.ColumnLimit == 0) {
+ // FIXME: Implement nested blocks for ColumnLimit = 0.
+ NoColumnLimitFormatter Formatter(Indenter);
+ if (!DryRun)
+ Formatter.format(Indent, &TheLine);
+ } else {
+ Penalty += format(TheLine, Indent, DryRun);
+ }
+
+ if (!TheLine.InPPDirective)
+ IndentForLevel[TheLine.Level] = LevelIndent;
+ } else if (TheLine.ChildrenAffected) {
+ format(TheLine.Children, DryRun);
+ } else {
+ // Format the first token if necessary, and notify the WhitespaceManager
+ // about the unchanged whitespace.
+ for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
+ if (Tok == TheLine.First && (Tok->NewlinesBefore > 0 || Tok->IsFirst)) {
+ unsigned LevelIndent = Tok->OriginalColumn;
+ if (!DryRun) {
+ // Remove trailing whitespace of the previous line.
+ if ((PreviousLine && PreviousLine->Affected) ||
+ TheLine.LeadingEmptyLinesAffected) {
+ formatFirstToken(*Tok, PreviousLine, TheLine.Level, LevelIndent,
+ TheLine.InPPDirective);
+ } else {
+ Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
+ }
+ }
+
+ if (static_cast<int>(LevelIndent) - Offset >= 0)
+ LevelIndent -= Offset;
+ if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)
+ IndentForLevel[TheLine.Level] = LevelIndent;
+ } else if (!DryRun) {
+ Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
+ }
+ }
+ }
+ if (!DryRun) {
+ for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
+ Tok->Finalized = true;
+ }
+ }
+ PreviousLine = *I;
+ }
+ PenaltyCache[CacheKey] = Penalty;
+ return Penalty;
+}
+
+unsigned UnwrappedLineFormatter::format(const AnnotatedLine &Line,
+ unsigned FirstIndent, bool DryRun) {
+ LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
+
+ // If the ObjC method declaration does not fit on a line, we should format
+ // it with one arg per line.
+ if (State.Line->Type == LT_ObjCMethodDecl)
+ State.Stack.back().BreakBeforeParameter = true;
+
+ // Find best solution in solution space.
+ return analyzeSolutionSpace(State, DryRun);
+}
+
+void UnwrappedLineFormatter::formatFirstToken(FormatToken &RootToken,
+ const AnnotatedLine *PreviousLine,
+ unsigned IndentLevel,
+ unsigned Indent,
+ bool InPPDirective) {
+ unsigned Newlines =
+ std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
+ // Remove empty lines before "}" where applicable.
+ if (RootToken.is(tok::r_brace) &&
+ (!RootToken.Next ||
+ (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))
+ Newlines = std::min(Newlines, 1u);
+ if (Newlines == 0 && !RootToken.IsFirst)
+ Newlines = 1;
+ if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
+ Newlines = 0;
+
+ // Remove empty lines after "{".
+ if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
+ PreviousLine->Last->is(tok::l_brace) &&
+ PreviousLine->First->isNot(tok::kw_namespace) &&
+ !startsExternCBlock(*PreviousLine))
+ Newlines = 1;
+
+ // Insert extra new line before access specifiers.
+ if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&
+ RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)
+ ++Newlines;
+
+ // Remove empty lines after access specifiers.
+ if (PreviousLine && PreviousLine->First->isAccessSpecifier())
+ Newlines = std::min(1u, Newlines);
+
+ Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
+ Indent, InPPDirective &&
+ !RootToken.HasUnescapedNewline);
+}
+
+/// \brief Get the indent of \p Level from \p IndentForLevel.
+///
+/// \p IndentForLevel must contain the indent for the level \c l
+/// at \p IndentForLevel[l], or a value < 0 if the indent for
+/// that level is unknown.
+unsigned UnwrappedLineFormatter::getIndent(ArrayRef<int> IndentForLevel,
+ unsigned Level) {
+ if (IndentForLevel[Level] != -1)
+ return IndentForLevel[Level];
+ if (Level == 0)
+ return 0;
+ return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;
+}
+
+void UnwrappedLineFormatter::join(AnnotatedLine &A, const AnnotatedLine &B) {
+ assert(!A.Last->Next);
+ assert(!B.First->Previous);
+ if (B.Affected)
+ A.Affected = true;
+ A.Last->Next = B.First;
+ B.First->Previous = A.Last;
+ B.First->CanBreakBefore = true;
+ unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;
+ for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {
+ Tok->TotalLength += LengthA;
+ A.Last = Tok;
+ }
+}
+
+unsigned UnwrappedLineFormatter::analyzeSolutionSpace(LineState &InitialState,
+ bool DryRun) {
+ std::set<LineState *, CompareLineStatePointers> Seen;
+
+ // Increasing count of \c StateNode items we have created. This is used to
+ // create a deterministic order independent of the container.
+ unsigned Count = 0;
+ QueueType Queue;
+
+ // Insert start element into queue.
+ StateNode *Node =
+ new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);
+ Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
+ ++Count;
+
+ unsigned Penalty = 0;
+
+ // While not empty, take first element and follow edges.
+ while (!Queue.empty()) {
+ Penalty = Queue.top().first.first;
+ StateNode *Node = Queue.top().second;
+ if (!Node->State.NextToken) {
+ DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");
+ break;
+ }
+ Queue.pop();
+
+ // Cut off the analysis of certain solutions if the analysis gets too
+ // complex. See description of IgnoreStackForComparison.
+ if (Count > 10000)
+ Node->State.IgnoreStackForComparison = true;
+
+ if (!Seen.insert(&Node->State).second)
+ // State already examined with lower penalty.
+ continue;
+
+ FormatDecision LastFormat = Node->State.NextToken->Decision;
+ if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue);
+ if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue);
+ }
+
+ if (Queue.empty()) {
+ // We were unable to find a solution, do nothing.
+ // FIXME: Add diagnostic?
+ DEBUG(llvm::dbgs() << "Could not find a solution.\n");
+ return 0;
+ }
+
+ // Reconstruct the solution.
+ if (!DryRun)
+ reconstructPath(InitialState, Queue.top().second);
+
+ DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count << "\n");
+ DEBUG(llvm::dbgs() << "---\n");
+
+ return Penalty;
+}
+
+#ifndef NDEBUG
+static void printLineState(const LineState &State) {
+ llvm::dbgs() << "State: ";
+ for (const ParenState &P : State.Stack) {
+ llvm::dbgs() << P.Indent << "|" << P.LastSpace << "|" << P.NestedBlockIndent
+ << " ";
+ }
+ llvm::dbgs() << State.NextToken->TokenText << "\n";
+}
+#endif
+
+void UnwrappedLineFormatter::reconstructPath(LineState &State,
+ StateNode *Current) {
+ std::deque<StateNode *> Path;
+ // We do not need a break before the initial token.
+ while (Current->Previous) {
+ Path.push_front(Current);
+ Current = Current->Previous;
+ }
+ for (std::deque<StateNode *>::iterator I = Path.begin(), E = Path.end();
+ I != E; ++I) {
+ unsigned Penalty = 0;
+ formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);
+ Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);
+
+ DEBUG({
+ printLineState((*I)->Previous->State);
+ if ((*I)->NewLine) {
+ llvm::dbgs() << "Penalty for placing "
+ << (*I)->Previous->State.NextToken->Tok.getName() << ": "
+ << Penalty << "\n";
+ }
+ });
+ }
+}
+
+void UnwrappedLineFormatter::addNextStateToQueue(unsigned Penalty,
+ StateNode *PreviousNode,
+ bool NewLine, unsigned *Count,
+ QueueType *Queue) {
+ if (NewLine && !Indenter->canBreak(PreviousNode->State))
+ return;
+ if (!NewLine && Indenter->mustBreak(PreviousNode->State))
+ return;
+
+ StateNode *Node = new (Allocator.Allocate())
+ StateNode(PreviousNode->State, NewLine, PreviousNode);
+ if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))
+ return;
+
+ Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
+
+ Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
+ ++(*Count);
+}
+
+bool UnwrappedLineFormatter::formatChildren(LineState &State, bool NewLine,
+ bool DryRun, unsigned &Penalty) {
+ FormatToken &Previous = *State.NextToken->Previous;
+ const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
+ if (!LBrace || LBrace->isNot(tok::l_brace) || LBrace->BlockKind != BK_Block ||
+ Previous.Children.size() == 0)
+ // The previous token does not open a block. Nothing to do. We don't
+ // assert so that we can simply call this function for all tokens.
+ return true;
+
+ if (NewLine) {
+ int AdditionalIndent = State.Stack.back().Indent -
+ Previous.Children[0]->Level * Style.IndentWidth;
+
+ Penalty += format(Previous.Children, DryRun, AdditionalIndent,
+ /*FixBadIndentation=*/true);
+ return true;
+ }
+
+ if (Previous.Children[0]->First->MustBreakBefore)
+ return false;
+
+ // Cannot merge multiple statements into a single line.
+ if (Previous.Children.size() > 1)
+ return false;
+
+ // Cannot merge into one line if this line ends on a comment.
+ if (Previous.is(tok::comment))
+ return false;
+
+ // We can't put the closing "}" on a line with a trailing comment.
+ if (Previous.Children[0]->Last->isTrailingComment())
+ return false;
+
+ // If the child line exceeds the column limit, we wouldn't want to merge it.
+ // We add +2 for the trailing " }".
+ if (Style.ColumnLimit > 0 &&
+ Previous.Children[0]->Last->TotalLength + State.Column + 2 >
+ Style.ColumnLimit)
+ return false;
+
+ if (!DryRun) {
+ Whitespaces->replaceWhitespace(
+ *Previous.Children[0]->First,
+ /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,
+ /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
+ }
+ Penalty += format(*Previous.Children[0], State.Column + 1, DryRun);
+
+ State.Column += 1 + Previous.Children[0]->Last->TotalLength;
+ return true;
+}
+
+} // namespace format
+} // namespace clang
diff --git a/lib/Format/UnwrappedLineFormatter.h b/lib/Format/UnwrappedLineFormatter.h
new file mode 100644
index 000000000000..3ae6dbc4db0b
--- /dev/null
+++ b/lib/Format/UnwrappedLineFormatter.h
@@ -0,0 +1,168 @@
+//===--- UnwrappedLineFormatter.h - Format C++ code -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implements a combinartorial exploration of all the different
+/// linebreaks unwrapped lines can be formatted in.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
+#define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
+
+#include "ContinuationIndenter.h"
+#include "clang/Format/Format.h"
+#include <map>
+#include <queue>
+#include <string>
+
+namespace clang {
+namespace format {
+
+class ContinuationIndenter;
+class WhitespaceManager;
+
+class UnwrappedLineFormatter {
+public:
+ UnwrappedLineFormatter(ContinuationIndenter *Indenter,
+ WhitespaceManager *Whitespaces,
+ const FormatStyle &Style)
+ : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style) {}
+
+ unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
+ int AdditionalIndent = 0, bool FixBadIndentation = false);
+
+private:
+ /// \brief Formats an \c AnnotatedLine and returns the penalty.
+ ///
+ /// If \p DryRun is \c false, directly applies the changes.
+ unsigned format(const AnnotatedLine &Line, unsigned FirstIndent,
+ bool DryRun);
+
+ /// \brief An edge in the solution space from \c Previous->State to \c State,
+ /// inserting a newline dependent on the \c NewLine.
+ struct StateNode {
+ StateNode(const LineState &State, bool NewLine, StateNode *Previous)
+ : State(State), NewLine(NewLine), Previous(Previous) {}
+ LineState State;
+ bool NewLine;
+ StateNode *Previous;
+ };
+
+ /// \brief A pair of <penalty, count> that is used to prioritize the BFS on.
+ ///
+ /// In case of equal penalties, we want to prefer states that were inserted
+ /// first. During state generation we make sure that we insert states first
+ /// that break the line as late as possible.
+ typedef std::pair<unsigned, unsigned> OrderedPenalty;
+
+ /// \brief An item in the prioritized BFS search queue. The \c StateNode's
+ /// \c State has the given \c OrderedPenalty.
+ typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
+
+ /// \brief The BFS queue type.
+ typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
+ std::greater<QueueItem> > QueueType;
+
+ /// \brief Get the offset of the line relatively to the level.
+ ///
+ /// For example, 'public:' labels in classes are offset by 1 or 2
+ /// characters to the left from their level.
+ int getIndentOffset(const FormatToken &RootToken) {
+ if (Style.Language == FormatStyle::LK_Java)
+ return 0;
+ if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())
+ return Style.AccessModifierOffset;
+ return 0;
+ }
+
+ /// \brief Add a new line and the required indent before the first Token
+ /// of the \c UnwrappedLine if there was no structural parsing error.
+ void formatFirstToken(FormatToken &RootToken,
+ const AnnotatedLine *PreviousLine, unsigned IndentLevel,
+ unsigned Indent, bool InPPDirective);
+
+ /// \brief Get the indent of \p Level from \p IndentForLevel.
+ ///
+ /// \p IndentForLevel must contain the indent for the level \c l
+ /// at \p IndentForLevel[l], or a value < 0 if the indent for
+ /// that level is unknown.
+ unsigned getIndent(ArrayRef<int> IndentForLevel, unsigned Level);
+
+ void join(AnnotatedLine &A, const AnnotatedLine &B);
+
+ unsigned getColumnLimit(bool InPPDirective) const {
+ // In preprocessor directives reserve two chars for trailing " \"
+ return Style.ColumnLimit - (InPPDirective ? 2 : 0);
+ }
+
+ struct CompareLineStatePointers {
+ bool operator()(LineState *obj1, LineState *obj2) const {
+ return *obj1 < *obj2;
+ }
+ };
+
+ /// \brief Analyze the entire solution space starting from \p InitialState.
+ ///
+ /// This implements a variant of Dijkstra's algorithm on the graph that spans
+ /// the solution space (\c LineStates are the nodes). The algorithm tries to
+ /// find the shortest path (the one with lowest penalty) from \p InitialState
+ /// to a state where all tokens are placed. Returns the penalty.
+ ///
+ /// If \p DryRun is \c false, directly applies the changes.
+ unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false);
+
+ void reconstructPath(LineState &State, StateNode *Current);
+
+ /// \brief Add the following state to the analysis queue \c Queue.
+ ///
+ /// Assume the current state is \p PreviousNode and has been reached with a
+ /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
+ void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
+ bool NewLine, unsigned *Count, QueueType *Queue);
+
+ /// \brief If the \p State's next token is an r_brace closing a nested block,
+ /// format the nested block before it.
+ ///
+ /// Returns \c true if all children could be placed successfully and adapts
+ /// \p Penalty as well as \p State. If \p DryRun is false, also directly
+ /// creates changes using \c Whitespaces.
+ ///
+ /// The crucial idea here is that children always get formatted upon
+ /// encountering the closing brace right after the nested block. Now, if we
+ /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is
+ /// \c false), the entire block has to be kept on the same line (which is only
+ /// possible if it fits on the line, only contains a single statement, etc.
+ ///
+ /// If \p NewLine is true, we format the nested block on separate lines, i.e.
+ /// break after the "{", format all lines with correct indentation and the put
+ /// the closing "}" on yet another new line.
+ ///
+ /// This enables us to keep the simple structure of the
+ /// \c UnwrappedLineFormatter, where we only have two options for each token:
+ /// break or don't break.
+ bool formatChildren(LineState &State, bool NewLine, bool DryRun,
+ unsigned &Penalty);
+
+ ContinuationIndenter *Indenter;
+ WhitespaceManager *Whitespaces;
+ FormatStyle Style;
+
+ llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
+
+ // Cache to store the penalty of formatting a vector of AnnotatedLines
+ // starting from a specific additional offset. Improves performance if there
+ // are many nested blocks.
+ std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
+ unsigned> PenaltyCache;
+};
+} // end namespace format
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 20dd573162cc..ec04af5231be 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -122,14 +122,13 @@ class ScopedLineState {
public:
ScopedLineState(UnwrappedLineParser &Parser,
bool SwitchToPreprocessorLines = false)
- : Parser(Parser) {
- OriginalLines = Parser.CurrentLines;
+ : Parser(Parser), OriginalLines(Parser.CurrentLines) {
if (SwitchToPreprocessorLines)
Parser.CurrentLines = &Parser.PreprocessorDirectives;
else if (!Parser.Line->Tokens.empty())
Parser.CurrentLines = &Parser.Line->Tokens.back().Children;
- PreBlockLine = Parser.Line.release();
- Parser.Line.reset(new UnwrappedLine());
+ PreBlockLine = std::move(Parser.Line);
+ Parser.Line = llvm::make_unique<UnwrappedLine>();
Parser.Line->Level = PreBlockLine->Level;
Parser.Line->InPPDirective = PreBlockLine->InPPDirective;
}
@@ -139,7 +138,7 @@ public:
Parser.addUnwrappedLine();
}
assert(Parser.Line->Tokens.empty());
- Parser.Line.reset(PreBlockLine);
+ Parser.Line = std::move(PreBlockLine);
if (Parser.CurrentLines == &Parser.PreprocessorDirectives)
Parser.MustBreakBeforeNextToken = true;
Parser.CurrentLines = OriginalLines;
@@ -148,7 +147,7 @@ public:
private:
UnwrappedLineParser &Parser;
- UnwrappedLine *PreBlockLine;
+ std::unique_ptr<UnwrappedLine> PreBlockLine;
SmallVectorImpl<UnwrappedLine> *OriginalLines;
};
@@ -203,12 +202,13 @@ private:
} // end anonymous namespace
UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
+ const AdditionalKeywords &Keywords,
ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), StructuralError(false), Style(Style),
- Tokens(nullptr), Callback(Callback), AllTokens(Tokens),
- PPBranchLevel(-1) {}
+ Keywords(Keywords), Tokens(nullptr), Callback(Callback),
+ AllTokens(Tokens), PPBranchLevel(-1) {}
void UnwrappedLineParser::reset() {
PPBranchLevel = -1;
@@ -311,7 +311,6 @@ void UnwrappedLineParser::calculateBraceTypes() {
// parse macros, so this will magically work inside macro
// definitions, too.
unsigned StoredPosition = Tokens->getPosition();
- unsigned Position = StoredPosition;
FormatToken *Tok = FormatTok;
// Keep a stack of positions of lbrace tokens. We will
// update information about whether an lbrace starts a
@@ -354,7 +353,7 @@ void UnwrappedLineParser::calculateBraceTypes() {
ProbablyBracedList =
NextTok->isOneOf(tok::comma, tok::semi, tok::period, tok::colon,
tok::r_paren, tok::r_square, tok::l_brace,
- tok::l_paren) ||
+ tok::l_paren, tok::ellipsis) ||
(NextTok->isBinaryOperator() && !NextIsObjCMethod);
}
if (ProbablyBracedList) {
@@ -382,7 +381,6 @@ void UnwrappedLineParser::calculateBraceTypes() {
break;
}
Tok = NextTok;
- Position += ReadTokens;
} while (Tok->Tok.isNot(tok::eof) && !LBraceStack.empty());
// Assume other blocks for all unclosed opening braces.
for (unsigned i = 0, e = LBraceStack.size(); i != e; ++i) {
@@ -420,6 +418,8 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
}
static bool IsGoogScope(const UnwrappedLine &Line) {
+ // FIXME: Closure-library specific stuff should not be hard-coded but be
+ // configurable.
if (Line.Tokens.size() < 4)
return false;
auto I = Line.Tokens.begin();
@@ -435,6 +435,19 @@ static bool IsGoogScope(const UnwrappedLine &Line) {
return I->Tok->is(tok::l_paren);
}
+static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
+ const FormatToken &InitialToken) {
+ switch (Style.BreakBeforeBraces) {
+ case FormatStyle::BS_Linux:
+ return InitialToken.isOneOf(tok::kw_namespace, tok::kw_class);
+ case FormatStyle::BS_Allman:
+ case FormatStyle::BS_GNU:
+ return true;
+ default:
+ return false;
+ }
+}
+
void UnwrappedLineParser::parseChildBlock() {
FormatTok->BlockKind = BK_Block;
nextToken();
@@ -646,6 +659,20 @@ void UnwrappedLineParser::parseStructuralElement() {
break;
}
break;
+ case tok::kw_asm:
+ nextToken();
+ if (FormatTok->is(tok::l_brace)) {
+ nextToken();
+ while (FormatTok && FormatTok->isNot(tok::eof)) {
+ if (FormatTok->is(tok::r_brace)) {
+ nextToken();
+ break;
+ }
+ FormatTok->Finalized = true;
+ nextToken();
+ }
+ }
+ break;
case tok::kw_namespace:
parseNamespace();
return;
@@ -659,7 +686,10 @@ void UnwrappedLineParser::parseStructuralElement() {
case tok::kw_public:
case tok::kw_protected:
case tok::kw_private:
- parseAccessSpecifier();
+ if (Style.Language == FormatStyle::LK_Java)
+ nextToken();
+ else
+ parseAccessSpecifier();
return;
case tok::kw_if:
parseIfThenElse();
@@ -717,8 +747,8 @@ void UnwrappedLineParser::parseStructuralElement() {
break;
case tok::kw_typedef:
nextToken();
- // FIXME: Use the IdentifierTable instead.
- if (FormatTok->TokenText == "NS_ENUM")
+ if (FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
+ Keywords.kw_CF_ENUM, Keywords.kw_CF_OPTIONS))
parseEnum();
break;
case tok::kw_struct:
@@ -728,6 +758,13 @@ void UnwrappedLineParser::parseStructuralElement() {
// A record declaration or definition is always the start of a structural
// element.
break;
+ case tok::period:
+ nextToken();
+ // In Java, classes have an implicit static member "class".
+ if (Style.Language == FormatStyle::LK_Java && FormatTok &&
+ FormatTok->is(tok::kw_class))
+ nextToken();
+ break;
case tok::semi:
nextToken();
addUnwrappedLine();
@@ -783,17 +820,14 @@ void UnwrappedLineParser::parseStructuralElement() {
parseLabel();
return;
}
- // Recognize function-like macro usages without trailing semicolon.
- if (FormatTok->Tok.is(tok::l_paren)) {
+ // Recognize function-like macro usages without trailing semicolon as
+ // well as free-standing macrose like Q_OBJECT.
+ bool FunctionLike = FormatTok->is(tok::l_paren);
+ if (FunctionLike)
parseParens();
- if (FormatTok->NewlinesBefore > 0 &&
- tokenCanStartNewLine(FormatTok->Tok) && Text == Text.upper()) {
- addUnwrappedLine();
- return;
- }
- } else if (FormatTok->HasUnescapedNewline && Text.size() >= 5 &&
- Text == Text.upper()) {
- // Recognize free-standing macros like Q_OBJECT.
+ if (FormatTok->NewlinesBefore > 0 &&
+ (Text.size() >= 5 || FunctionLike) &&
+ tokenCanStartNewLine(FormatTok->Tok) && Text == Text.upper()) {
addUnwrappedLine();
return;
}
@@ -820,7 +854,8 @@ bool UnwrappedLineParser::tryToParseLambda() {
// FIXME: This is a dirty way to access the previous token. Find a better
// solution.
if (!Line->Tokens.empty() &&
- (Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator) ||
+ (Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator,
+ tok::kw_new, tok::kw_delete) ||
Line->Tokens.back().Tok->closesScope() ||
Line->Tokens.back().Tok->isSimpleTypeSpecifier())) {
nextToken();
@@ -842,6 +877,10 @@ bool UnwrappedLineParser::tryToParseLambda() {
case tok::l_paren:
parseParens();
break;
+ case tok::amp:
+ case tok::star:
+ case tok::kw_const:
+ case tok::comma:
case tok::less:
case tok::greater:
case tok::identifier:
@@ -947,7 +986,7 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
// replace this by using parseAssigmentExpression() inside.
do {
if (Style.Language == FormatStyle::LK_JavaScript &&
- FormatTok->TokenText == "function") {
+ FormatTok->is(Keywords.kw_function)) {
tryToParseJSFunction();
continue;
}
@@ -994,6 +1033,8 @@ void UnwrappedLineParser::parseParens() {
switch (FormatTok->Tok.getKind()) {
case tok::l_paren:
parseParens();
+ if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_brace))
+ parseChildBlock();
break;
case tok::r_paren:
nextToken();
@@ -1004,17 +1045,23 @@ void UnwrappedLineParser::parseParens() {
case tok::l_square:
tryToParseLambda();
break;
- case tok::l_brace: {
+ case tok::l_brace:
if (!tryToParseBracedList()) {
parseChildBlock();
}
break;
- }
case tok::at:
nextToken();
if (FormatTok->Tok.is(tok::l_brace))
parseBracedList();
break;
+ case tok::identifier:
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->is(Keywords.kw_function))
+ tryToParseJSFunction();
+ else
+ nextToken();
+ break;
default:
nextToken();
break;
@@ -1080,6 +1127,8 @@ void UnwrappedLineParser::parseIfThenElse() {
--Line->Level;
}
if (FormatTok->Tok.is(tok::kw_else)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup)
+ addUnwrappedLine();
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level);
@@ -1115,6 +1164,10 @@ void UnwrappedLineParser::parseTryCatch() {
nextToken();
}
}
+ // Parse try with resource.
+ if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren)) {
+ parseParens();
+ }
if (FormatTok->is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
@@ -1136,8 +1189,9 @@ void UnwrappedLineParser::parseTryCatch() {
--Line->Level;
}
while (FormatTok->is(tok::kw_catch) ||
- (Style.Language == FormatStyle::LK_JavaScript &&
- FormatTok->TokenText == "finally")) {
+ ((Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript) &&
+ FormatTok->is(Keywords.kw_finally))) {
nextToken();
while (FormatTok->isNot(tok::l_brace)) {
if (FormatTok->is(tok::l_paren)) {
@@ -1166,13 +1220,13 @@ void UnwrappedLineParser::parseTryCatch() {
void UnwrappedLineParser::parseNamespace() {
assert(FormatTok->Tok.is(tok::kw_namespace) && "'namespace' expected");
+
+ const FormatToken &InitialToken = *FormatTok;
nextToken();
if (FormatTok->Tok.is(tok::identifier))
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
- Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
- Style.BreakBeforeBraces == FormatStyle::BS_GNU)
+ if (ShouldBreakBeforeBrace(Style, InitialToken))
addUnwrappedLine();
bool AddLevel = Style.NamespaceIndentation == FormatStyle::NI_All ||
@@ -1294,43 +1348,115 @@ void UnwrappedLineParser::parseAccessSpecifier() {
}
void UnwrappedLineParser::parseEnum() {
- if (FormatTok->Tok.is(tok::kw_enum)) {
- // Won't be 'enum' for NS_ENUMs.
+ // Won't be 'enum' for NS_ENUMs.
+ if (FormatTok->Tok.is(tok::kw_enum))
nextToken();
- }
+
// Eat up enum class ...
if (FormatTok->Tok.is(tok::kw_class) || FormatTok->Tok.is(tok::kw_struct))
nextToken();
while (FormatTok->Tok.getIdentifierInfo() ||
- FormatTok->isOneOf(tok::colon, tok::coloncolon)) {
+ FormatTok->isOneOf(tok::colon, tok::coloncolon, tok::less,
+ tok::greater, tok::comma, tok::question)) {
nextToken();
// We can have macros or attributes in between 'enum' and the enum name.
- if (FormatTok->Tok.is(tok::l_paren)) {
+ if (FormatTok->is(tok::l_paren))
parseParens();
- }
- if (FormatTok->Tok.is(tok::identifier))
+ if (FormatTok->is(tok::identifier))
nextToken();
}
- if (FormatTok->Tok.is(tok::l_brace)) {
- FormatTok->BlockKind = BK_Block;
- bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true);
- if (HasError) {
- if (FormatTok->is(tok::semi))
- nextToken();
- addUnwrappedLine();
- }
+
+ // Just a declaration or something is wrong.
+ if (FormatTok->isNot(tok::l_brace))
+ return;
+ FormatTok->BlockKind = BK_Block;
+
+ if (Style.Language == FormatStyle::LK_Java) {
+ // Java enums are different.
+ parseJavaEnumBody();
+ return;
}
+
+ // Parse enum body.
+ bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true);
+ if (HasError) {
+ if (FormatTok->is(tok::semi))
+ nextToken();
+ addUnwrappedLine();
+ }
+
// We fall through to parsing a structural element afterwards, so that in
// enum A {} n, m;
// "} n, m;" will end up in one unwrapped line.
}
+void UnwrappedLineParser::parseJavaEnumBody() {
+ // Determine whether the enum is simple, i.e. does not have a semicolon or
+ // constants with class bodies. Simple enums can be formatted like braced
+ // lists, contracted to a single line, etc.
+ unsigned StoredPosition = Tokens->getPosition();
+ bool IsSimple = true;
+ FormatToken *Tok = Tokens->getNextToken();
+ while (Tok) {
+ if (Tok->is(tok::r_brace))
+ break;
+ if (Tok->isOneOf(tok::l_brace, tok::semi)) {
+ IsSimple = false;
+ break;
+ }
+ // FIXME: This will also mark enums with braces in the arguments to enum
+ // constants as "not simple". This is probably fine in practice, though.
+ Tok = Tokens->getNextToken();
+ }
+ FormatTok = Tokens->setPosition(StoredPosition);
+
+ if (IsSimple) {
+ parseBracedList();
+ addUnwrappedLine();
+ return;
+ }
+
+ // Parse the body of a more complex enum.
+ // First add a line for everything up to the "{".
+ nextToken();
+ addUnwrappedLine();
+ ++Line->Level;
+
+ // Parse the enum constants.
+ while (FormatTok) {
+ if (FormatTok->is(tok::l_brace)) {
+ // Parse the constant's class body.
+ parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
+ /*MunchSemi=*/false);
+ } else if (FormatTok->is(tok::l_paren)) {
+ parseParens();
+ } else if (FormatTok->is(tok::comma)) {
+ nextToken();
+ addUnwrappedLine();
+ } else if (FormatTok->is(tok::semi)) {
+ nextToken();
+ addUnwrappedLine();
+ break;
+ } else if (FormatTok->is(tok::r_brace)) {
+ addUnwrappedLine();
+ break;
+ } else {
+ nextToken();
+ }
+ }
+
+ // Parse the class body after the enum's ";" if any.
+ parseLevel(/*HasOpeningBrace=*/true);
+ nextToken();
+ --Line->Level;
+ addUnwrappedLine();
+}
+
void UnwrappedLineParser::parseRecord() {
+ const FormatToken &InitialToken = *FormatTok;
nextToken();
- if (FormatTok->Tok.is(tok::identifier) ||
- FormatTok->Tok.is(tok::kw___attribute) ||
- FormatTok->Tok.is(tok::kw___declspec) ||
- FormatTok->Tok.is(tok::kw_alignas)) {
+ if (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw___attribute,
+ tok::kw___declspec, tok::kw_alignas)) {
nextToken();
// We can have macros or attributes in between 'class' and the class name.
if (FormatTok->Tok.is(tok::l_paren)) {
@@ -1338,9 +1464,10 @@ void UnwrappedLineParser::parseRecord() {
}
// The actual identifier can be a nested name specifier, and in macros
// it is often token-pasted.
- while (FormatTok->Tok.is(tok::identifier) ||
- FormatTok->Tok.is(tok::coloncolon) ||
- FormatTok->Tok.is(tok::hashhash))
+ while (FormatTok->is(tok::identifier) || FormatTok->is(tok::coloncolon) ||
+ FormatTok->is(tok::hashhash) ||
+ (Style.Language == FormatStyle::LK_Java &&
+ FormatTok->isOneOf(tok::period, tok::comma)))
nextToken();
// Note that parsing away template declarations here leads to incorrectly
@@ -1362,9 +1489,7 @@ void UnwrappedLineParser::parseRecord() {
}
}
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
- Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
- Style.BreakBeforeBraces == FormatStyle::BS_GNU)
+ if (ShouldBreakBeforeBrace(Style, InitialToken))
addUnwrappedLine();
parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
@@ -1373,6 +1498,9 @@ void UnwrappedLineParser::parseRecord() {
// We fall through to parsing a structural element afterwards, so
// class A {} n, m;
// will end up in one unwrapped line.
+ // This does not apply for Java.
+ if (Style.Language == FormatStyle::LK_Java)
+ addUnwrappedLine();
}
void UnwrappedLineParser::parseObjCProtocolList() {
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index c9182e9d71d3..3218afecad30 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -13,13 +13,14 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
-#define LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
+#ifndef LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEPARSER_H
+#define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEPARSER_H
#include "FormatToken.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Format/Format.h"
#include <list>
+#include <stack>
namespace clang {
namespace format {
@@ -59,7 +60,9 @@ class FormatTokenSource;
class UnwrappedLineParser {
public:
- UnwrappedLineParser(const FormatStyle &Style, ArrayRef<FormatToken *> Tokens,
+ UnwrappedLineParser(const FormatStyle &Style,
+ const AdditionalKeywords &Keywords,
+ ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback);
/// Returns true in case of a structural error.
@@ -94,6 +97,7 @@ private:
void parseNamespace();
void parseAccessSpecifier();
void parseEnum();
+ void parseJavaEnumBody();
void parseRecord();
void parseObjCProtocolList();
void parseObjCUntilAtEnd();
@@ -157,6 +161,8 @@ private:
bool StructuralError;
const FormatStyle &Style;
+ const AdditionalKeywords &Keywords;
+
FormatTokenSource *Tokens;
UnwrappedLineConsumer &Callback;
@@ -214,4 +220,4 @@ inline UnwrappedLine::UnwrappedLine()
} // end namespace format
} // end namespace clang
-#endif // LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
+#endif
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 47b94de4c6f7..bf1207e59c90 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -81,7 +81,7 @@ void WhitespaceManager::replaceWhitespaceInToken(
// FIXME: We still need to take this change in account to properly
// calculate the new length of the comment and to calculate the changes
// for which to do the alignment when aligning comments.
- Tok.Type == TT_LineComment && Newlines > 0 ? tok::comment : tok::unknown,
+ Tok.is(TT_LineComment) && Newlines > 0 ? tok::comment : tok::unknown,
InPPDirective && !Tok.IsFirst));
}
@@ -163,15 +163,17 @@ void WhitespaceManager::alignTrailingComments() {
Changes[i - 1].StartOfTokenColumn == 0;
bool WasAlignedWithStartOfNextLine = false;
if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
+ unsigned CommentColumn = SourceMgr.getSpellingColumnNumber(
+ Changes[i].OriginalWhitespaceRange.getEnd());
for (unsigned j = i + 1; j != e; ++j) {
if (Changes[j].Kind != tok::comment) { // Skip over comments.
+ unsigned NextColumn = SourceMgr.getSpellingColumnNumber(
+ Changes[j].OriginalWhitespaceRange.getEnd());
// The start of the next token was previously aligned with the
// start of this comment.
WasAlignedWithStartOfNextLine =
- (SourceMgr.getSpellingColumnNumber(
- Changes[i].OriginalWhitespaceRange.getEnd()) ==
- SourceMgr.getSpellingColumnNumber(
- Changes[j].OriginalWhitespaceRange.getEnd()));
+ CommentColumn == NextColumn ||
+ CommentColumn == NextColumn + Style.IndentWidth;
break;
}
}
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index 189b1aefa03f..28730d457eba 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -13,8 +13,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FORMAT_WHITESPACEMANAGER_H
-#define LLVM_CLANG_FORMAT_WHITESPACEMANAGER_H
+#ifndef LLVM_CLANG_LIB_FORMAT_WHITESPACEMANAGER_H
+#define LLVM_CLANG_LIB_FORMAT_WHITESPACEMANAGER_H
#include "TokenAnnotator.h"
#include "clang/Basic/SourceManager.h"
@@ -200,4 +200,4 @@ private:
} // namespace format
} // namespace clang
-#endif // LLVM_CLANG_FORMAT_WHITESPACEMANAGER_H
+#endif
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 54a6d474c18a..f53c614b0a30 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -57,7 +57,8 @@ namespace {
bool ShowColors = Out.has_colors();
if (ShowColors)
Out.changeColor(raw_ostream::BLUE);
- Out << (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
+ Out << ((Dump || DumpLookups) ? "Dumping " : "Printing ") << getName(D)
+ << ":\n";
if (ShowColors)
Out.resetColor();
print(D);
@@ -79,9 +80,13 @@ namespace {
}
void print(Decl *D) {
if (DumpLookups) {
- if (DeclContext *DC = dyn_cast<DeclContext>(D))
- DC->dumpLookups(Out);
- else
+ if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
+ if (DC == DC->getPrimaryContext())
+ DC->dumpLookups(Out, Dump);
+ else
+ Out << "Lookup map is in primary DeclContext "
+ << DC->getPrimaryContext() << "\n";
+ } else
Out << "Not a DeclContext\n";
} else if (Dump)
D->dump(Out);
@@ -118,17 +123,21 @@ namespace {
};
} // end anonymous namespace
-ASTConsumer *clang::CreateASTPrinter(raw_ostream *Out,
- StringRef FilterString) {
- return new ASTPrinter(Out, /*Dump=*/ false, FilterString);
+std::unique_ptr<ASTConsumer> clang::CreateASTPrinter(raw_ostream *Out,
+ StringRef FilterString) {
+ return llvm::make_unique<ASTPrinter>(Out, /*Dump=*/false, FilterString);
}
-ASTConsumer *clang::CreateASTDumper(StringRef FilterString, bool DumpLookups) {
- return new ASTPrinter(nullptr, /*Dump=*/true, FilterString, DumpLookups);
+std::unique_ptr<ASTConsumer> clang::CreateASTDumper(StringRef FilterString,
+ bool DumpDecls,
+ bool DumpLookups) {
+ assert((DumpDecls || DumpLookups) && "nothing to dump");
+ return llvm::make_unique<ASTPrinter>(nullptr, DumpDecls, FilterString,
+ DumpLookups);
}
-ASTConsumer *clang::CreateASTDeclNodeLister() {
- return new ASTDeclNodeLister(nullptr);
+std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {
+ return llvm::make_unique<ASTDeclNodeLister>(nullptr);
}
//===----------------------------------------------------------------------===//
@@ -164,8 +173,9 @@ void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
}
}
-
-ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
+std::unique_ptr<ASTConsumer> clang::CreateASTViewer() {
+ return llvm::make_unique<ASTViewer>();
+}
//===----------------------------------------------------------------------===//
/// DeclContextPrinter - Decl and DeclContext Visualization
@@ -475,6 +485,6 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
}
}
}
-ASTConsumer *clang::CreateDeclContextPrinter() {
- return new DeclContextPrinter();
+std::unique_ptr<ASTConsumer> clang::CreateDeclContextPrinter() {
+ return llvm::make_unique<DeclContextPrinter>();
}
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index ff6434c56945..216ac6a16984 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -16,8 +16,8 @@
using namespace clang;
-ASTConsumer *ASTMergeAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+ASTMergeAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return AdaptedAction->CreateASTConsumer(CI, InFile);
}
@@ -45,8 +45,8 @@ void ASTMergeAction::ExecuteAction() {
new ForwardingDiagnosticConsumer(
*CI.getDiagnostics().getClient()),
/*ShouldOwnClient=*/true));
- ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags,
- CI.getFileSystemOpts(), false);
+ std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
+ ASTFiles[I], Diags, CI.getFileSystemOpts(), false);
if (!Unit)
continue;
@@ -66,8 +66,6 @@ void ASTMergeAction::ExecuteAction() {
Importer.Import(D);
}
-
- delete Unit;
}
AdaptedAction->ExecuteAction();
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index fc44d9f1b4c0..a3998fa351de 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -105,7 +105,8 @@ static llvm::sys::SmartMutex<false> &getOnDiskMutex() {
static void cleanupOnDiskMapAtExit();
-typedef llvm::DenseMap<const ASTUnit *, OnDiskData *> OnDiskDataMap;
+typedef llvm::DenseMap<const ASTUnit *,
+ std::unique_ptr<OnDiskData>> OnDiskDataMap;
static OnDiskDataMap &getOnDiskDataMap() {
static OnDiskDataMap M;
static bool hasRegisteredAtExit = false;
@@ -132,9 +133,9 @@ static OnDiskData &getOnDiskData(const ASTUnit *AU) {
// DenseMap.
llvm::MutexGuard Guard(getOnDiskMutex());
OnDiskDataMap &M = getOnDiskDataMap();
- OnDiskData *&D = M[AU];
+ auto &D = M[AU];
if (!D)
- D = new OnDiskData();
+ D = llvm::make_unique<OnDiskData>();
return *D;
}
@@ -150,7 +151,6 @@ static void removeOnDiskEntry(const ASTUnit *AU) {
OnDiskDataMap::iterator I = M.find(AU);
if (I != M.end()) {
I->second->Cleanup();
- delete I->second;
M.erase(AU);
}
}
@@ -219,8 +219,8 @@ ASTUnit::ASTUnit(bool _MainFileIsAST)
TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")),
OwnsRemappedFileBuffers(true),
NumStoredDiagnosticsFromDriver(0),
- PreambleRebuildCounter(0), SavedMainFileBuffer(nullptr),
- PreambleBuffer(nullptr), NumWarningsInPreamble(0),
+ PreambleRebuildCounter(0),
+ NumWarningsInPreamble(0),
ShouldCacheCodeCompletionResults(false),
IncludeBriefCommentsInCodeCompletion(false), UserFilesAreVolatile(false),
CompletionCacheTopLevelHashValue(0),
@@ -251,9 +251,6 @@ ASTUnit::~ASTUnit() {
for (const auto &RB : PPOpts.RemappedFileBuffers)
delete RB.second;
}
-
- delete SavedMainFileBuffer;
- delete PreambleBuffer;
ClearCachedCompletionResults();
@@ -511,8 +508,8 @@ public:
: PP(PP), Context(Context), LangOpt(LangOpt), TargetOpts(TargetOpts),
Target(Target), Counter(Counter), InitializedLanguage(false) {}
- bool ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) override {
+ bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
+ bool AllowCompatibleDifferences) override {
if (InitializedLanguage)
return false;
@@ -592,6 +589,7 @@ class CaptureDroppedDiagnostics {
DiagnosticsEngine &Diags;
StoredDiagnosticConsumer Client;
DiagnosticConsumer *PreviousClient;
+ std::unique_ptr<DiagnosticConsumer> OwningPreviousClient;
public:
CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags,
@@ -599,16 +597,15 @@ public:
: Diags(Diags), Client(StoredDiags), PreviousClient(nullptr)
{
if (RequestCapture || Diags.getClient() == nullptr) {
- PreviousClient = Diags.takeClient();
- Diags.setClient(&Client);
+ OwningPreviousClient = Diags.takeClient();
+ PreviousClient = Diags.getClient();
+ Diags.setClient(&Client, false);
}
}
~CaptureDroppedDiagnostics() {
- if (Diags.getClient() == &Client) {
- Diags.takeClient();
- Diags.setClient(PreviousClient);
- }
+ if (Diags.getClient() == &Client)
+ Diags.setClient(PreviousClient, !!OwningPreviousClient.release());
}
};
@@ -638,38 +635,30 @@ ASTDeserializationListener *ASTUnit::getDeserializationListener() {
return nullptr;
}
-llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename,
- std::string *ErrorStr) {
+std::unique_ptr<llvm::MemoryBuffer>
+ASTUnit::getBufferForFile(StringRef Filename, std::string *ErrorStr) {
assert(FileMgr);
- return FileMgr->getBufferForFile(Filename, ErrorStr);
+ auto Buffer = FileMgr->getBufferForFile(Filename);
+ if (Buffer)
+ return std::move(*Buffer);
+ if (ErrorStr)
+ *ErrorStr = Buffer.getError().message();
+ return nullptr;
}
/// \brief Configure the diagnostics object for use with ASTUnit.
-void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
- const char **ArgBegin, const char **ArgEnd,
+void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
ASTUnit &AST, bool CaptureDiagnostics) {
- if (!Diags.get()) {
- // No diagnostics engine was provided, so create our own diagnostics object
- // with the default options.
- DiagnosticConsumer *Client = nullptr;
- if (CaptureDiagnostics)
- Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics);
- Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(),
- Client,
- /*ShouldOwnClient=*/true);
- } else if (CaptureDiagnostics) {
+ assert(Diags.get() && "no DiagnosticsEngine was provided");
+ if (CaptureDiagnostics)
Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics));
- }
}
-ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
- const FileSystemOptions &FileSystemOpts,
- bool OnlyLocalDecls,
- ArrayRef<RemappedFile> RemappedFiles,
- bool CaptureDiagnostics,
- bool AllowPCHWithCompilerErrors,
- bool UserFilesAreVolatile) {
+std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
+ const std::string &Filename, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ const FileSystemOptions &FileSystemOpts, bool OnlyLocalDecls,
+ ArrayRef<RemappedFile> RemappedFiles, bool CaptureDiagnostics,
+ bool AllowPCHWithCompilerErrors, bool UserFilesAreVolatile) {
std::unique_ptr<ASTUnit> AST(new ASTUnit(true));
// Recover resources if we crash before exiting this method.
@@ -679,7 +668,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.get());
- ConfigureDiags(Diags, nullptr, nullptr, *AST, CaptureDiagnostics);
+ ConfigureDiags(Diags, *AST, CaptureDiagnostics);
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
@@ -705,7 +694,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// Gather Info for preprocessor construction later on.
- HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
+ HeaderSearch &HeaderInfo = *AST->HeaderInfo;
unsigned Counter;
AST->PP =
@@ -728,10 +717,9 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
/*DisableValidation=*/disableValid,
AllowPCHWithCompilerErrors);
- AST->Reader->setListener(new ASTInfoCollector(*AST->PP, Context,
- AST->ASTFileLangOpts,
- AST->TargetOpts, AST->Target,
- Counter));
+ AST->Reader->setListener(llvm::make_unique<ASTInfoCollector>(
+ *AST->PP, Context, AST->ASTFileLangOpts, AST->TargetOpts, AST->Target,
+ Counter));
switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile,
SourceLocation(), ASTReader::ARR_None)) {
@@ -768,7 +756,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// Tell the diagnostic client that we have started a source file.
AST->getDiagnostics().getClient()->BeginSourceFile(Context.getLangOpts(),&PP);
- return AST.release();
+ return AST;
}
namespace {
@@ -891,12 +879,13 @@ class TopLevelDeclTrackerAction : public ASTFrontendAction {
public:
ASTUnit &Unit;
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override {
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override {
CI.getPreprocessor().addPPCallbacks(
- new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
- return new TopLevelDeclTrackerConsumer(Unit,
- Unit.getCurrentTopLevelHashValue());
+ llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(
+ Unit.getCurrentTopLevelHashValue()));
+ return llvm::make_unique<TopLevelDeclTrackerConsumer>(
+ Unit, Unit.getCurrentTopLevelHashValue());
}
public:
@@ -916,8 +905,8 @@ public:
explicit PrecompilePreambleAction(ASTUnit &Unit)
: Unit(Unit), HasEmittedPreamblePCH(false) {}
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
void setHasEmittedPreamblePCH() { HasEmittedPreamblePCH = true; }
bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
@@ -979,8 +968,9 @@ public:
}
-ASTConsumer *PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
raw_ostream *OS = nullptr;
@@ -991,10 +981,11 @@ ASTConsumer *PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
if (!CI.getFrontendOpts().RelocatablePCH)
Sysroot.clear();
- CI.getPreprocessor().addPPCallbacks(new MacroDefinitionTrackerPPCallbacks(
- Unit.getCurrentTopLevelHashValue()));
- return new PrecompilePreambleConsumer(Unit, this, CI.getPreprocessor(),
- Sysroot, OS);
+ CI.getPreprocessor().addPPCallbacks(
+ llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(
+ Unit.getCurrentTopLevelHashValue()));
+ return llvm::make_unique<PrecompilePreambleConsumer>(
+ Unit, this, CI.getPreprocessor(), Sysroot, OS);
}
static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) {
@@ -1031,15 +1022,12 @@ static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> &
///
/// \returns True if a failure occurred that causes the ASTUnit not to
/// contain any translation-unit information, false otherwise.
-bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
- delete SavedMainFileBuffer;
- SavedMainFileBuffer = nullptr;
+bool ASTUnit::Parse(std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer) {
+ SavedMainFileBuffer.reset();
- if (!Invocation) {
- delete OverrideMainBuffer;
+ if (!Invocation)
return true;
- }
-
+
// Create the compiler instance to use for building the AST.
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
@@ -1060,10 +1048,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// Create the target instance.
Clang->setTarget(TargetInfo::CreateTargetInfo(
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
- if (!Clang->hasTarget()) {
- delete OverrideMainBuffer;
+ if (!Clang->hasTarget())
return true;
- }
// Inform the target of the language options.
//
@@ -1083,10 +1069,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
FileSystemOpts = Clang->getFileSystemOpts();
IntrusiveRefCntPtr<vfs::FileSystem> VFS =
createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics());
- if (!VFS) {
- delete OverrideMainBuffer;
+ if (!VFS)
return true;
- }
FileMgr = new FileManager(FileSystemOpts, VFS);
SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
UserFilesAreVolatile);
@@ -1115,7 +1099,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// make that override happen and introduce the preamble.
PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
if (OverrideMainBuffer) {
- PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
+ PreprocessorOpts.addRemappedFile(OriginalSourceFile,
+ OverrideMainBuffer.get());
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
PreprocessorOpts.PrecompiledPreambleBytes.second
= PreambleEndsAtStartOfLine;
@@ -1130,7 +1115,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
checkAndSanitizeDiags(StoredDiagnostics, getSourceManager());
// Keep track of the override buffer;
- SavedMainFileBuffer = OverrideMainBuffer;
+ SavedMainFileBuffer = std::move(OverrideMainBuffer);
}
std::unique_ptr<TopLevelDeclTrackerAction> Act(
@@ -1143,7 +1128,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
goto error;
- if (OverrideMainBuffer) {
+ if (SavedMainFileBuffer) {
std::string ModName = getPreambleFile(this);
TranslateStoredDiagnostics(getFileManager(), getSourceManager(),
PreambleDiagnostics, StoredDiagnostics);
@@ -1162,10 +1147,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
error:
// Remove the overridden buffer we used for the preamble.
- if (OverrideMainBuffer) {
- delete OverrideMainBuffer;
- SavedMainFileBuffer = nullptr;
- }
+ SavedMainFileBuffer = nullptr;
// Keep the ownership of the data in the ASTUnit because the client may
// want to see the diagnostics.
@@ -1194,17 +1176,16 @@ static std::string GetPreamblePCHPath() {
/// \brief Compute the preamble for the main file, providing the source buffer
/// that corresponds to the main file along with a pair (bytes, start-of-line)
/// that describes the preamble.
-std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> >
-ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
- unsigned MaxLines, bool &CreatedBuffer) {
+ASTUnit::ComputedPreamble
+ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) {
FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts();
- CreatedBuffer = false;
// Try to determine if the main file has been remapped, either from the
// command line (to another file) or directly through the compiler invocation
// (to a memory buffer).
llvm::MemoryBuffer *Buffer = nullptr;
+ std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
std::string MainFilePath(FrontendOpts.Inputs[0].getFile());
llvm::sys::fs::UniqueID MainFileID;
if (!llvm::sys::fs::getUniqueID(MainFilePath, MainFileID)) {
@@ -1215,15 +1196,9 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
if (MainFileID == MID) {
// We found a remapping. Try to load the resulting, remapped source.
- if (CreatedBuffer) {
- delete Buffer;
- CreatedBuffer = false;
- }
-
- Buffer = getBufferForFile(RF.second);
- if (!Buffer)
- return std::make_pair(nullptr, std::make_pair(0, true));
- CreatedBuffer = true;
+ BufferOwner = getBufferForFile(RF.second);
+ if (!BufferOwner)
+ return ComputedPreamble(nullptr, nullptr, 0, true);
}
}
}
@@ -1236,11 +1211,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
if (MainFileID == MID) {
// We found a remapping.
- if (CreatedBuffer) {
- delete Buffer;
- CreatedBuffer = false;
- }
-
+ BufferOwner.reset();
Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
}
}
@@ -1248,17 +1219,18 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
}
// If the main source file was not remapped, load it now.
- if (!Buffer) {
- Buffer = getBufferForFile(FrontendOpts.Inputs[0].getFile());
- if (!Buffer)
- return std::make_pair(nullptr, std::make_pair(0, true));
-
- CreatedBuffer = true;
+ if (!Buffer && !BufferOwner) {
+ BufferOwner = getBufferForFile(FrontendOpts.Inputs[0].getFile());
+ if (!BufferOwner)
+ return ComputedPreamble(nullptr, nullptr, 0, true);
}
-
- return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer,
- *Invocation.getLangOpts(),
- MaxLines));
+
+ if (!Buffer)
+ Buffer = BufferOwner.get();
+ auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(),
+ *Invocation.getLangOpts(), MaxLines);
+ return ComputedPreamble(Buffer, std::move(BufferOwner), Pre.first,
+ Pre.second);
}
ASTUnit::PreambleFileHash
@@ -1300,42 +1272,44 @@ makeStandaloneRange(CharSourceRange Range, const SourceManager &SM,
return std::make_pair(Offset, EndOffset);
}
-static void makeStandaloneFixIt(const SourceManager &SM,
- const LangOptions &LangOpts,
- const FixItHint &InFix,
- ASTUnit::StandaloneFixIt &OutFix) {
+static ASTUnit::StandaloneFixIt makeStandaloneFixIt(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const FixItHint &InFix) {
+ ASTUnit::StandaloneFixIt OutFix;
OutFix.RemoveRange = makeStandaloneRange(InFix.RemoveRange, SM, LangOpts);
OutFix.InsertFromRange = makeStandaloneRange(InFix.InsertFromRange, SM,
LangOpts);
OutFix.CodeToInsert = InFix.CodeToInsert;
OutFix.BeforePreviousInsertions = InFix.BeforePreviousInsertions;
+ return OutFix;
}
-static void makeStandaloneDiagnostic(const LangOptions &LangOpts,
- const StoredDiagnostic &InDiag,
- ASTUnit::StandaloneDiagnostic &OutDiag) {
+static ASTUnit::StandaloneDiagnostic
+makeStandaloneDiagnostic(const LangOptions &LangOpts,
+ const StoredDiagnostic &InDiag) {
+ ASTUnit::StandaloneDiagnostic OutDiag;
OutDiag.ID = InDiag.getID();
OutDiag.Level = InDiag.getLevel();
OutDiag.Message = InDiag.getMessage();
OutDiag.LocOffset = 0;
if (InDiag.getLocation().isInvalid())
- return;
+ return OutDiag;
const SourceManager &SM = InDiag.getLocation().getManager();
SourceLocation FileLoc = SM.getFileLoc(InDiag.getLocation());
OutDiag.Filename = SM.getFilename(FileLoc);
if (OutDiag.Filename.empty())
- return;
+ return OutDiag;
OutDiag.LocOffset = SM.getFileOffset(FileLoc);
for (StoredDiagnostic::range_iterator
I = InDiag.range_begin(), E = InDiag.range_end(); I != E; ++I) {
OutDiag.Ranges.push_back(makeStandaloneRange(*I, SM, LangOpts));
}
- for (StoredDiagnostic::fixit_iterator
- I = InDiag.fixit_begin(), E = InDiag.fixit_end(); I != E; ++I) {
- ASTUnit::StandaloneFixIt Fix;
- makeStandaloneFixIt(SM, LangOpts, *I, Fix);
- OutDiag.FixIts.push_back(Fix);
- }
+ for (StoredDiagnostic::fixit_iterator I = InDiag.fixit_begin(),
+ E = InDiag.fixit_end();
+ I != E; ++I)
+ OutDiag.FixIts.push_back(makeStandaloneFixIt(SM, LangOpts, *I));
+
+ return OutDiag;
}
/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing
@@ -1358,27 +1332,20 @@ static void makeStandaloneDiagnostic(const LangOptions &LangOpts,
/// \returns If the precompiled preamble can be used, returns a newly-allocated
/// buffer that should be used in place of the main file when doing so.
/// Otherwise, returns a NULL pointer.
-llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
- const CompilerInvocation &PreambleInvocationIn,
- bool AllowRebuild,
- unsigned MaxLines) {
-
+std::unique_ptr<llvm::MemoryBuffer>
+ASTUnit::getMainBufferWithPrecompiledPreamble(
+ const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild,
+ unsigned MaxLines) {
+
IntrusiveRefCntPtr<CompilerInvocation>
PreambleInvocation(new CompilerInvocation(PreambleInvocationIn));
FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
PreprocessorOptions &PreprocessorOpts
= PreambleInvocation->getPreprocessorOpts();
- bool CreatedPreambleBuffer = false;
- std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble
- = ComputePreamble(*PreambleInvocation, MaxLines, CreatedPreambleBuffer);
-
- // If ComputePreamble() Take ownership of the preamble buffer.
- std::unique_ptr<llvm::MemoryBuffer> OwnedPreambleBuffer;
- if (CreatedPreambleBuffer)
- OwnedPreambleBuffer.reset(NewPreamble.first);
+ ComputedPreamble NewPreamble = ComputePreamble(*PreambleInvocation, MaxLines);
- if (!NewPreamble.second.first) {
+ if (!NewPreamble.Size) {
// We couldn't find a preamble in the main source. Clear out the current
// preamble, if we have one. It's obviously no good any more.
Preamble.clear();
@@ -1394,10 +1361,10 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// preamble now that we did before, and that there's enough space in
// the main-file buffer within the precompiled preamble to fit the
// new main file.
- if (Preamble.size() == NewPreamble.second.first &&
- PreambleEndsAtStartOfLine == NewPreamble.second.second &&
- memcmp(Preamble.getBufferStart(), NewPreamble.first->getBufferStart(),
- NewPreamble.second.first) == 0) {
+ if (Preamble.size() == NewPreamble.Size &&
+ PreambleEndsAtStartOfLine == NewPreamble.PreambleEndsAtStartOfLine &&
+ memcmp(Preamble.getBufferStart(), NewPreamble.Buffer->getBufferStart(),
+ NewPreamble.Size) == 0) {
// The preamble has not changed. We may be able to re-use the precompiled
// preamble.
@@ -1467,7 +1434,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
getDiagnostics().setNumWarnings(NumWarningsInPreamble);
return llvm::MemoryBuffer::getMemBufferCopy(
- NewPreamble.first->getBuffer(), FrontendOpts.Inputs[0].getFile());
+ NewPreamble.Buffer->getBuffer(), FrontendOpts.Inputs[0].getFile());
}
}
@@ -1512,19 +1479,16 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// subsequent reparses.
StringRef MainFilename = FrontendOpts.Inputs[0].getFile();
Preamble.assign(FileMgr->getFile(MainFilename),
- NewPreamble.first->getBufferStart(),
- NewPreamble.first->getBufferStart()
- + NewPreamble.second.first);
- PreambleEndsAtStartOfLine = NewPreamble.second.second;
+ NewPreamble.Buffer->getBufferStart(),
+ NewPreamble.Buffer->getBufferStart() + NewPreamble.Size);
+ PreambleEndsAtStartOfLine = NewPreamble.PreambleEndsAtStartOfLine;
- delete PreambleBuffer;
- PreambleBuffer
- = llvm::MemoryBuffer::getMemBufferCopy(
- NewPreamble.first->getBuffer().slice(0, Preamble.size()), MainFilename);
+ PreambleBuffer = llvm::MemoryBuffer::getMemBufferCopy(
+ NewPreamble.Buffer->getBuffer().slice(0, Preamble.size()), MainFilename);
// Remap the main source file to the preamble buffer.
StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
- PreprocessorOpts.addRemappedFile(MainFilePath, PreambleBuffer);
+ PreprocessorOpts.addRemappedFile(MainFilePath, PreambleBuffer.get());
// Tell the compiler invocation to generate a temporary precompiled header.
FrontendOpts.ProgramAction = frontend::GeneratePCH;
@@ -1607,13 +1571,11 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Transfer any diagnostics generated when parsing the preamble into the set
// of preamble diagnostics.
- for (stored_diag_iterator
- I = stored_diag_afterDriver_begin(),
- E = stored_diag_end(); I != E; ++I) {
- StandaloneDiagnostic Diag;
- makeStandaloneDiagnostic(Clang->getLangOpts(), *I, Diag);
- PreambleDiagnostics.push_back(Diag);
- }
+ for (stored_diag_iterator I = stored_diag_afterDriver_begin(),
+ E = stored_diag_end();
+ I != E; ++I)
+ PreambleDiagnostics.push_back(
+ makeStandaloneDiagnostic(Clang->getLangOpts(), *I));
Act->EndSourceFile();
@@ -1663,8 +1625,8 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
CompletionCacheTopLevelHashValue = 0;
PreambleTopLevelHashValue = CurrentTopLevelHashValue;
}
-
- return llvm::MemoryBuffer::getMemBufferCopy(NewPreamble.first->getBuffer(),
+
+ return llvm::MemoryBuffer::getMemBufferCopy(NewPreamble.Buffer->getBuffer(),
MainFilename);
}
@@ -1688,8 +1650,8 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
// created.
assert(CI.hasInvocation() && "missing invocation");
LangOpts = CI.getInvocation().LangOpts;
- TheSema.reset(CI.takeSema());
- Consumer.reset(CI.takeASTConsumer());
+ TheSema = CI.takeSema();
+ Consumer = CI.takeASTConsumer();
if (CI.hasASTContext())
Ctx = &CI.getASTContext();
if (CI.hasPreprocessor())
@@ -1735,7 +1697,7 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI,
bool UserFilesAreVolatile) {
std::unique_ptr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
- ConfigureDiags(Diags, nullptr, nullptr, *AST, CaptureDiagnostics);
+ ConfigureDiags(Diags, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
AST->Invocation = CI;
AST->FileSystemOpts = CI->getFileSystemOpts();
@@ -1862,13 +1824,15 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
if (Persistent && !TrackerAct) {
Clang->getPreprocessor().addPPCallbacks(
- new MacroDefinitionTrackerPPCallbacks(AST->getCurrentTopLevelHashValue()));
- std::vector<ASTConsumer*> Consumers;
+ llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(
+ AST->getCurrentTopLevelHashValue()));
+ std::vector<std::unique_ptr<ASTConsumer>> Consumers;
if (Clang->hasASTConsumer())
Consumers.push_back(Clang->takeASTConsumer());
- Consumers.push_back(new TopLevelDeclTrackerConsumer(*AST,
- AST->getCurrentTopLevelHashValue()));
- Clang->setASTConsumer(new MultiplexConsumer(Consumers));
+ Consumers.push_back(llvm::make_unique<TopLevelDeclTrackerConsumer>(
+ *AST, AST->getCurrentTopLevelHashValue()));
+ Clang->setASTConsumer(
+ llvm::make_unique<MultiplexConsumer>(std::move(Consumers)));
}
if (!Act->Execute()) {
AST->transferASTDataFromCompilerInstance(*Clang);
@@ -1898,11 +1862,10 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
Invocation->getFrontendOpts().DisableFree = false;
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
- llvm::MemoryBuffer *OverrideMainBuffer = nullptr;
+ std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
if (PrecompilePreamble) {
PreambleRebuildCounter = 2;
- OverrideMainBuffer
- = getMainBufferWithPrecompiledPreamble(*Invocation);
+ OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation);
}
SimpleTimer ParsingTimer(WantTiming);
@@ -1910,9 +1873,9 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer>
- MemBufferCleanup(OverrideMainBuffer);
-
- return Parse(OverrideMainBuffer);
+ MemBufferCleanup(OverrideMainBuffer.get());
+
+ return Parse(std::move(OverrideMainBuffer));
}
std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
@@ -1922,7 +1885,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile) {
// Create the AST unit.
std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
- ConfigureDiags(Diags, nullptr, nullptr, *AST, CaptureDiagnostics);
+ ConfigureDiags(Diags, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
@@ -1961,11 +1924,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies,
bool UserFilesAreVolatile, bool ForSerialization,
std::unique_ptr<ASTUnit> *ErrAST) {
- if (!Diags.get()) {
- // No diagnostics engine was provided, so create our own diagnostics object
- // with the default options.
- Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions());
- }
+ assert(Diags.get() && "no DiagnosticsEngine was provided");
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
@@ -2000,9 +1959,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
// Create the AST unit.
std::unique_ptr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
- ConfigureDiags(Diags, ArgBegin, ArgEnd, *AST, CaptureDiagnostics);
+ ConfigureDiags(Diags, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
- Diags = nullptr; // Zero out now to ease cleanup during crash recovery.
AST->FileSystemOpts = CI->getFileSystemOpts();
IntrusiveRefCntPtr<vfs::FileSystem> VFS =
createVFSFromCompilerInvocation(*CI, *Diags);
@@ -2021,7 +1979,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
AST->Invocation = CI;
if (ForSerialization)
AST->WriterData.reset(new ASTWriterData());
- CI = nullptr; // Zero out now to ease cleanup during crash recovery.
+ // Zero out now to ease cleanup during crash recovery.
+ CI = nullptr;
+ Diags = nullptr;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
@@ -2062,7 +2022,7 @@ bool ASTUnit::Reparse(ArrayRef<RemappedFile> RemappedFiles) {
// If we have a preamble file lying around, or if we might try to
// build a precompiled preamble, do so now.
- llvm::MemoryBuffer *OverrideMainBuffer = nullptr;
+ std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0)
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation);
@@ -2073,8 +2033,8 @@ bool ASTUnit::Reparse(ArrayRef<RemappedFile> RemappedFiles) {
getDiagnostics().setNumWarnings(NumWarningsInPreamble);
// Parse the sources
- bool Result = Parse(OverrideMainBuffer);
-
+ bool Result = Parse(std::move(OverrideMainBuffer));
+
// If we're caching global code-completion results, and the top-level
// declarations have changed, clear out the code-completion cache.
if (!Result && ShouldCacheCodeCompletionResults &&
@@ -2366,6 +2326,10 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// Set the language options appropriately.
LangOpts = *CCInvocation->getLangOpts();
+ // Spell-checking and warnings are wasteful during code-completion.
+ LangOpts.SpellChecking = false;
+ CCInvocation->getDiagnosticOpts().IgnoreWarnings = true;
+
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
// Recover resources if we crash before exiting this method.
@@ -2427,7 +2391,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// the use of the precompiled preamble if we're if the completion
// point is within the main file, after the end of the precompiled
// preamble.
- llvm::MemoryBuffer *OverrideMainBuffer = nullptr;
+ std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
if (!getPreambleFile(this).empty()) {
std::string CompleteFilePath(File);
llvm::sys::fs::UniqueID CompleteFileID;
@@ -2437,9 +2401,8 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
llvm::sys::fs::UniqueID MainID;
if (!llvm::sys::fs::getUniqueID(MainPath, MainID)) {
if (CompleteFileID == MainID && Line > 1)
- OverrideMainBuffer
- = getMainBufferWithPrecompiledPreamble(*CCInvocation, false,
- Line - 1);
+ OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
+ *CCInvocation, false, Line - 1);
}
}
}
@@ -2447,14 +2410,15 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
if (OverrideMainBuffer) {
- PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
+ PreprocessorOpts.addRemappedFile(OriginalSourceFile,
+ OverrideMainBuffer.get());
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
PreprocessorOpts.PrecompiledPreambleBytes.second
= PreambleEndsAtStartOfLine;
PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
PreprocessorOpts.DisablePCHValidation = true;
-
- OwnedBuffers.push_back(OverrideMainBuffer);
+
+ OwnedBuffers.push_back(OverrideMainBuffer.release());
} else {
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
@@ -2821,7 +2785,8 @@ struct PCHLocatorInfo {
static bool PCHLocator(serialization::ModuleFile &M, void *UserData) {
PCHLocatorInfo &Info = *static_cast<PCHLocatorInfo*>(UserData);
switch (M.Kind) {
- case serialization::MK_Module:
+ case serialization::MK_ImplicitModule:
+ case serialization::MK_ExplicitModule:
return true; // skip dependencies.
case serialization::MK_PCH:
Info.Mod = &M;
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 403cc42927a6..7c5fca54d1e1 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -1,6 +1,7 @@
add_subdirectory(Rewrite)
set(LLVM_LINK_COMPONENTS
+ BitReader
Option
Support
)
@@ -12,6 +13,7 @@ add_clang_library(clangFrontend
CacheTokens.cpp
ChainedDiagnosticConsumer.cpp
ChainedIncludesSource.cpp
+ CodeGenOptions.cpp
CompilerInstance.cpp
CompilerInvocation.cpp
CreateInvocationFromCommandLine.cpp
@@ -31,6 +33,7 @@ add_clang_library(clangFrontend
MultiplexConsumer.cpp
PrintPreprocessedOutput.cpp
SerializedDiagnosticPrinter.cpp
+ SerializedDiagnosticReader.cpp
TextDiagnostic.cpp
TextDiagnosticBuffer.cpp
TextDiagnosticPrinter.cpp
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 14f7027e4687..d909d526b518 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -270,17 +270,17 @@ void PTHWriter::EmitToken(const Token& T) {
StringRef s(T.getLiteralData(), T.getLength());
// Get the string entry.
- llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s);
+ auto &E = *CachedStrs.insert(std::make_pair(s, OffsetOpt())).first;
// If this is a new string entry, bump the PTH offset.
- if (!E->getValue().hasOffset()) {
- E->getValue().setOffset(CurStrOffset);
- StrEntries.push_back(E);
+ if (!E.second.hasOffset()) {
+ E.second.setOffset(CurStrOffset);
+ StrEntries.push_back(&E);
CurStrOffset += s.size() + 1;
}
// Emit the relative offset into the PTH file for the spelling string.
- Emit32(E->getValue().getOffset());
+ Emit32(E.second.getOffset());
}
// Emit the offset into the original source file of this token so that we
@@ -572,8 +572,10 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
PTHWriter PW(*OS, PP);
// Install the 'stat' system call listener in the FileManager.
- StatListener *StatCache = new StatListener(PW.getPM());
- PP.getFileManager().addStatCache(StatCache, /*AtBeginning=*/true);
+ auto StatCacheOwner = llvm::make_unique<StatListener>(PW.getPM());
+ StatListener *StatCache = StatCacheOwner.get();
+ PP.getFileManager().addStatCache(std::move(StatCacheOwner),
+ /*AtBeginning=*/true);
// Lex through the entire file. This will populate SourceManager with
// all of the header information.
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index e6e73ac963fb..cb260b4f4c69 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -74,7 +74,7 @@ protected:
static ASTReader *
createASTReader(CompilerInstance &CI, StringRef pchFile,
- SmallVectorImpl<llvm::MemoryBuffer *> &memBufs,
+ SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,
SmallVectorImpl<std::string> &bufNames,
ASTDeserializationListener *deserialListener = nullptr) {
Preprocessor &PP = CI.getPreprocessor();
@@ -83,7 +83,7 @@ createASTReader(CompilerInstance &CI, StringRef pchFile,
/*DisableValidation=*/true));
for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
StringRef sr(bufNames[ti]);
- Reader->addInMemoryBuffer(sr, memBufs[ti]);
+ Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));
}
Reader->setDeserializationListener(deserialListener);
switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
@@ -118,7 +118,7 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
IntrusiveRefCntPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
- SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
+ SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> SerialBufs;
SmallVector<std::string, 4> serialBufNames;
for (unsigned i = 0, e = includes.size(); i != e; ++i) {
@@ -158,12 +158,12 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
SmallVector<char, 256> serialAST;
llvm::raw_svector_ostream OS(serialAST);
- std::unique_ptr<ASTConsumer> consumer;
- consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", nullptr,
- /*isysroot=*/"", &OS));
+ auto consumer =
+ llvm::make_unique<PCHGenerator>(Clang->getPreprocessor(), "-", nullptr,
+ /*isysroot=*/"", &OS);
Clang->getASTContext().setASTMutationListener(
consumer->GetASTMutationListener());
- Clang->setASTConsumer(consumer.release());
+ Clang->setASTConsumer(std::move(consumer));
Clang->createSema(TU_Prefix, nullptr);
if (firstInclude) {
@@ -171,20 +171,21 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
PP.getLangOpts());
} else {
- assert(!serialBufs.empty());
- SmallVector<llvm::MemoryBuffer *, 4> bufs;
+ assert(!SerialBufs.empty());
+ SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> Bufs;
// TODO: Pass through the existing MemoryBuffer instances instead of
// allocating new ones.
- for (auto *SB : serialBufs)
- bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
+ for (auto &SB : SerialBufs)
+ Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
std::string pchName = includes[i-1];
llvm::raw_string_ostream os(pchName);
os << ".pch" << i-1;
serialBufNames.push_back(os.str());
IntrusiveRefCntPtr<ASTReader> Reader;
- Reader = createASTReader(*Clang, pchName, bufs, serialBufNames,
- Clang->getASTConsumer().GetASTDeserializationListener());
+ Reader = createASTReader(
+ *Clang, pchName, Bufs, serialBufNames,
+ Clang->getASTConsumer().GetASTDeserializationListener());
if (!Reader)
return nullptr;
Clang->setModuleManager(Reader);
@@ -196,14 +197,14 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
ParseAST(Clang->getSema());
Clang->getDiagnosticClient().EndSourceFile();
- serialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(OS.str()));
+ SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(OS.str()));
source->CIs.push_back(Clang.release());
}
- assert(!serialBufs.empty());
+ assert(!SerialBufs.empty());
std::string pchName = includes.back() + ".pch-final";
serialBufNames.push_back(pchName);
- Reader = createASTReader(CI, pchName, serialBufs, serialBufNames);
+ Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);
if (!Reader)
return nullptr;
diff --git a/lib/Frontend/CodeGenOptions.cpp b/lib/Frontend/CodeGenOptions.cpp
new file mode 100644
index 000000000000..75ee47f86806
--- /dev/null
+++ b/lib/Frontend/CodeGenOptions.cpp
@@ -0,0 +1,24 @@
+//===--- CodeGenOptions.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CodeGenOptions.h"
+#include <string.h>
+
+namespace clang {
+
+CodeGenOptions::CodeGenOptions() {
+#define CODEGENOPT(Name, Bits, Default) Name = Default;
+#define ENUM_CODEGENOPT(Name, Type, Bits, Default) set##Name(Default);
+#include "clang/Frontend/CodeGenOptions.def"
+
+ RelocationModel = "pic";
+ memcpy(CoverageVersion, "402*", 4);
+}
+
+} // end namespace clang
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 6af920d9fd78..93a34b722274 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -101,14 +101,18 @@ void CompilerInstance::setSema(Sema *S) {
TheSema.reset(S);
}
-void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
- Consumer.reset(Value);
+void CompilerInstance::setASTConsumer(std::unique_ptr<ASTConsumer> Value) {
+ Consumer = std::move(Value);
}
void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
CompletionConsumer.reset(Value);
}
-
+
+std::unique_ptr<Sema> CompilerInstance::takeSema() {
+ return std::move(TheSema);
+}
+
IntrusiveRefCntPtr<ASTReader> CompilerInstance::getModuleManager() const {
return ModuleManager;
}
@@ -130,52 +134,48 @@ void CompilerInstance::setModuleDepCollector(
static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
const CodeGenOptions *CodeGenOpts,
DiagnosticsEngine &Diags) {
- std::string ErrorInfo;
- bool OwnsStream = false;
+ std::error_code EC;
+ std::unique_ptr<raw_ostream> StreamOwner;
raw_ostream *OS = &llvm::errs();
if (DiagOpts->DiagnosticLogFile != "-") {
// Create the output stream.
- llvm::raw_fd_ostream *FileOS(new llvm::raw_fd_ostream(
- DiagOpts->DiagnosticLogFile.c_str(), ErrorInfo,
- llvm::sys::fs::F_Append | llvm::sys::fs::F_Text));
- if (!ErrorInfo.empty()) {
+ auto FileOS = llvm::make_unique<llvm::raw_fd_ostream>(
+ DiagOpts->DiagnosticLogFile, EC,
+ llvm::sys::fs::F_Append | llvm::sys::fs::F_Text);
+ if (EC) {
Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
- << DiagOpts->DiagnosticLogFile << ErrorInfo;
+ << DiagOpts->DiagnosticLogFile << EC.message();
} else {
FileOS->SetUnbuffered();
FileOS->SetUseAtomicWrites(true);
- OS = FileOS;
- OwnsStream = true;
+ OS = FileOS.get();
+ StreamOwner = std::move(FileOS);
}
}
// Chain in the diagnostic client which will log the diagnostics.
- LogDiagnosticPrinter *Logger = new LogDiagnosticPrinter(*OS, DiagOpts,
- OwnsStream);
+ auto Logger = llvm::make_unique<LogDiagnosticPrinter>(*OS, DiagOpts,
+ std::move(StreamOwner));
if (CodeGenOpts)
Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags);
- Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger));
+ assert(Diags.ownsClient());
+ Diags.setClient(
+ new ChainedDiagnosticConsumer(Diags.takeClient(), std::move(Logger)));
}
static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
DiagnosticsEngine &Diags,
StringRef OutputFile) {
- std::string ErrorInfo;
- std::unique_ptr<llvm::raw_fd_ostream> OS;
- OS.reset(new llvm::raw_fd_ostream(OutputFile.str().c_str(), ErrorInfo,
- llvm::sys::fs::F_None));
+ auto SerializedConsumer =
+ clang::serialized_diags::create(OutputFile, DiagOpts);
- if (!ErrorInfo.empty()) {
- Diags.Report(diag::warn_fe_serialized_diag_failure)
- << OutputFile << ErrorInfo;
- return;
+ if (Diags.ownsClient()) {
+ Diags.setClient(new ChainedDiagnosticConsumer(
+ Diags.takeClient(), std::move(SerializedConsumer)));
+ } else {
+ Diags.setClient(new ChainedDiagnosticConsumer(
+ Diags.getClient(), std::move(SerializedConsumer)));
}
-
- DiagnosticConsumer *SerializedConsumer =
- clang::serialized_diags::create(OS.release(), DiagOpts);
-
- Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(),
- SerializedConsumer));
}
void CompilerInstance::createDiagnostics(DiagnosticConsumer *Client,
@@ -371,6 +371,14 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/false, /*OutputPath=*/"",
/*ShowDepth=*/true, /*MSStyle=*/true);
}
+
+ // Load all explictly-specified module map files.
+ for (const auto &Filename : getFrontendOpts().ModuleMapFiles) {
+ if (auto *File = getFileManager().getFile(Filename))
+ PP->getHeaderSearchInfo().loadModuleMapFile(File, /*IsSystem*/false);
+ else
+ getDiagnostics().Report(diag::err_module_map_not_found) << Filename;
+ }
}
// ASTContext
@@ -569,17 +577,14 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
StringRef Extension,
bool UseTemporary,
bool CreateMissingDirectories) {
- std::string Error, OutputPathName, TempPathName;
- llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
- RemoveFileOnSignal,
- InFile, Extension,
- UseTemporary,
- CreateMissingDirectories,
- &OutputPathName,
- &TempPathName);
+ std::string OutputPathName, TempPathName;
+ std::error_code EC;
+ llvm::raw_fd_ostream *OS = createOutputFile(
+ OutputPath, EC, Binary, RemoveFileOnSignal, InFile, Extension,
+ UseTemporary, CreateMissingDirectories, &OutputPathName, &TempPathName);
if (!OS) {
- getDiagnostics().Report(diag::err_fe_unable_to_open_output)
- << OutputPath << Error;
+ getDiagnostics().Report(diag::err_fe_unable_to_open_output) << OutputPath
+ << EC.message();
return nullptr;
}
@@ -591,17 +596,11 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
return OS;
}
-llvm::raw_fd_ostream *
-CompilerInstance::createOutputFile(StringRef OutputPath,
- std::string &Error,
- bool Binary,
- bool RemoveFileOnSignal,
- StringRef InFile,
- StringRef Extension,
- bool UseTemporary,
- bool CreateMissingDirectories,
- std::string *ResultPathName,
- std::string *TempPathName) {
+llvm::raw_fd_ostream *CompilerInstance::createOutputFile(
+ StringRef OutputPath, std::error_code &Error, bool Binary,
+ bool RemoveFileOnSignal, StringRef InFile, StringRef Extension,
+ bool UseTemporary, bool CreateMissingDirectories,
+ std::string *ResultPathName, std::string *TempPathName) {
assert((!CreateMissingDirectories || UseTemporary) &&
"CreateMissingDirectories is only allowed when using temporary files");
@@ -670,9 +669,9 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
if (!OS) {
OSFile = OutFile;
OS.reset(new llvm::raw_fd_ostream(
- OSFile.c_str(), Error,
+ OSFile, Error,
(Binary ? llvm::sys::fs::F_None : llvm::sys::fs::F_Text)));
- if (!Error.empty())
+ if (Error)
return nullptr;
}
@@ -705,7 +704,8 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
if (Input.isBuffer()) {
- SourceMgr.setMainFileID(SourceMgr.createFileID(Input.getBuffer(), Kind));
+ SourceMgr.setMainFileID(SourceMgr.createFileID(
+ std::unique_ptr<llvm::MemoryBuffer>(Input.getBuffer()), Kind));
assert(!SourceMgr.getMainFileID().isInvalid() &&
"Couldn't establish MainFileID!");
return true;
@@ -727,14 +727,14 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
// pick up the correct size, and simply override their contents as we do for
// STDIN.
if (File->isNamedPipe()) {
- std::string ErrorStr;
- if (llvm::MemoryBuffer *MB =
- FileMgr.getBufferForFile(File, &ErrorStr, /*isVolatile=*/true)) {
+ auto MB = FileMgr.getBufferForFile(File, /*isVolatile=*/true);
+ if (MB) {
// Create a new virtual file that will have the correct size.
- File = FileMgr.getVirtualFile(InputFile, MB->getBufferSize(), 0);
- SourceMgr.overrideFileContents(File, MB);
+ File = FileMgr.getVirtualFile(InputFile, (*MB)->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(File, std::move(*MB));
} else {
- Diags.Report(diag::err_cannot_open_file) << InputFile << ErrorStr;
+ Diags.Report(diag::err_cannot_open_file) << InputFile
+ << MB.getError().message();
return false;
}
}
@@ -754,7 +754,7 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
SB->getBufferSize(), 0);
SourceMgr.setMainFileID(
SourceMgr.createFileID(File, SourceLocation(), Kind));
- SourceMgr.overrideFileContents(File, SB.release());
+ SourceMgr.overrideFileContents(File, std::move(SB));
}
assert(!SourceMgr.getMainFileID().isInvalid() &&
@@ -802,8 +802,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
llvm::EnableStatistics();
for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
- // Reset the ID tables if we are reusing the SourceManager.
- if (hasSourceManager())
+ // Reset the ID tables if we are reusing the SourceManager and parsing
+ // regular files.
+ if (hasSourceManager() && !Act.isModelParsingAction())
getSourceManager().clearIDTables();
if (Act.BeginSourceFile(*this, getFrontendOpts().Inputs[i])) {
@@ -951,17 +952,22 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
FrontendOpts.Inputs.push_back(
FrontendInputFile("__inferred_module.map", IK));
- llvm::MemoryBuffer *ModuleMapBuffer =
+ std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
ModuleMapFile = Instance.getFileManager().getVirtualFile(
"__inferred_module.map", InferredModuleMapContent.size(), 0);
- SourceMgr.overrideFileContents(ModuleMapFile, ModuleMapBuffer);
+ SourceMgr.overrideFileContents(ModuleMapFile, std::move(ModuleMapBuffer));
}
- // Construct a module-generating action. Passing through Module->ModuleMap is
+ // Construct a module-generating action. Passing through the module map is
// safe because the FileManager is shared between the compiler instances.
- GenerateModuleAction CreateModuleAction(Module->ModuleMap, Module->IsSystem);
-
+ GenerateModuleAction CreateModuleAction(
+ ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem);
+
+ ImportingInstance.getDiagnostics().Report(ImportLoc,
+ diag::remark_module_build)
+ << Module->Name << ModuleFileName;
+
// Execute the action to actually build the module in-place. Use a separate
// thread so that we get a stack large enough.
const unsigned ThreadStackSize = 8 << 20;
@@ -969,6 +975,10 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); },
ThreadStackSize);
+ ImportingInstance.getDiagnostics().Report(ImportLoc,
+ diag::remark_module_build_done)
+ << Module->Name;
+
// Delete the temporary module map file.
// FIXME: Even though we're executing under crash protection, it would still
// be nice to do this with RemoveFileOnSignal when we can. However, that
@@ -988,9 +998,10 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
SourceLocation ImportLoc,
SourceLocation ModuleNameLoc, Module *Module,
StringRef ModuleFileName) {
+ DiagnosticsEngine &Diags = ImportingInstance.getDiagnostics();
+
auto diagnoseBuildFailure = [&] {
- ImportingInstance.getDiagnostics().Report(ModuleNameLoc,
- diag::err_module_not_built)
+ Diags.Report(ModuleNameLoc, diag::err_module_not_built)
<< Module->Name << SourceRange(ImportLoc, ModuleNameLoc);
};
@@ -1004,6 +1015,8 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
llvm::LockFileManager Locked(ModuleFileName);
switch (Locked) {
case llvm::LockFileManager::LFS_Error:
+ Diags.Report(ModuleNameLoc, diag::err_module_lock_failure)
+ << Module->Name;
return false;
case llvm::LockFileManager::LFS_Owned:
@@ -1027,7 +1040,7 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
// Try to read the module file, now that we've compiled it.
ASTReader::ASTReadResult ReadResult =
ImportingInstance.getModuleManager()->ReadAST(
- ModuleFileName, serialization::MK_Module, ImportLoc,
+ ModuleFileName, serialization::MK_ImplicitModule, ImportLoc,
ModuleLoadCapabilities);
if (ReadResult == ASTReader::OutOfDate &&
@@ -1038,6 +1051,10 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
continue;
} else if (ReadResult == ASTReader::Missing) {
diagnoseBuildFailure();
+ } else if (ReadResult != ASTReader::Success &&
+ !Diags.hasErrorOccurred()) {
+ // The ASTReader didn't diagnose the error, so conservatively report it.
+ diagnoseBuildFailure();
}
return ReadResult == ASTReader::Success;
}
@@ -1131,9 +1148,8 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
/// \brief Write a new timestamp file with the given path.
static void writeTimestampFile(StringRef TimestampFile) {
- std::string ErrorInfo;
- llvm::raw_fd_ostream Out(TimestampFile.str().c_str(), ErrorInfo,
- llvm::sys::fs::F_None);
+ std::error_code EC;
+ llvm::raw_fd_ostream Out(TimestampFile.str(), EC, llvm::sys::fs::F_None);
}
/// \brief Prune the module cache of modules that haven't been accessed in
@@ -1251,6 +1267,65 @@ void CompilerInstance::createModuleManager() {
}
}
+bool CompilerInstance::loadModuleFile(StringRef FileName) {
+ // Helper to recursively read the module names for all modules we're adding.
+ // We mark these as known and redirect any attempt to load that module to
+ // the files we were handed.
+ struct ReadModuleNames : ASTReaderListener {
+ CompilerInstance &CI;
+ std::vector<StringRef> ModuleFileStack;
+ bool Failed;
+ bool TopFileIsModule;
+
+ ReadModuleNames(CompilerInstance &CI)
+ : CI(CI), Failed(false), TopFileIsModule(false) {}
+
+ bool needsImportVisitation() const override { return true; }
+
+ void visitImport(StringRef FileName) override {
+ ModuleFileStack.push_back(FileName);
+ if (ASTReader::readASTFileControlBlock(FileName, CI.getFileManager(),
+ *this)) {
+ CI.getDiagnostics().Report(SourceLocation(),
+ diag::err_module_file_not_found)
+ << FileName;
+ // FIXME: Produce a note stack explaining how we got here.
+ Failed = true;
+ }
+ ModuleFileStack.pop_back();
+ }
+
+ void ReadModuleName(StringRef ModuleName) override {
+ if (ModuleFileStack.size() == 1)
+ TopFileIsModule = true;
+
+ auto &ModuleFile = CI.ModuleFileOverrides[ModuleName];
+ if (!ModuleFile.empty() &&
+ CI.getFileManager().getFile(ModuleFile) !=
+ CI.getFileManager().getFile(ModuleFileStack.back()))
+ CI.getDiagnostics().Report(SourceLocation(),
+ diag::err_conflicting_module_files)
+ << ModuleName << ModuleFile << ModuleFileStack.back();
+ ModuleFile = ModuleFileStack.back();
+ }
+ } RMN(*this);
+
+ RMN.visitImport(FileName);
+
+ if (RMN.Failed)
+ return false;
+
+ // If we never found a module name for the top file, then it's not a module,
+ // it's a PCH or preamble or something.
+ if (!RMN.TopFileIsModule) {
+ getDiagnostics().Report(SourceLocation(), diag::err_module_file_not_module)
+ << FileName;
+ return false;
+ }
+
+ return true;
+}
+
ModuleLoadResult
CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleIdPath Path,
@@ -1265,7 +1340,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
// when both the preprocessor and parser see the same import declaration.
if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc) {
// Make the named module visible.
- if (LastModuleImportResult && ModuleName != getLangOpts().CurrentModule)
+ if (LastModuleImportResult && ModuleName != getLangOpts().CurrentModule &&
+ ModuleName != getLangOpts().ImplementationOfModule)
ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility,
ImportLoc, /*Complain=*/false);
return LastModuleImportResult;
@@ -1279,7 +1355,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
if (Known != KnownModules.end()) {
// Retrieve the cached top-level module.
Module = Known->second;
- } else if (ModuleName == getLangOpts().CurrentModule) {
+ } else if (ModuleName == getLangOpts().CurrentModule ||
+ ModuleName == getLangOpts().ImplementationOfModule) {
// This is the module we're building.
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
@@ -1294,8 +1371,12 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return ModuleLoadResult();
}
+ auto Override = ModuleFileOverrides.find(ModuleName);
+ bool Explicit = Override != ModuleFileOverrides.end();
+
std::string ModuleFileName =
- PP->getHeaderSearchInfo().getModuleFileName(Module);
+ Explicit ? Override->second
+ : PP->getHeaderSearchInfo().getModuleFileName(Module);
// If we don't already have an ASTReader, create one now.
if (!ModuleManager)
@@ -1311,14 +1392,24 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
Listener->attachToASTReader(*ModuleManager);
// Try to load the module file.
- unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
- switch (ModuleManager->ReadAST(ModuleFileName, serialization::MK_Module,
+ unsigned ARRFlags =
+ Explicit ? 0 : ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
+ switch (ModuleManager->ReadAST(ModuleFileName,
+ Explicit ? serialization::MK_ExplicitModule
+ : serialization::MK_ImplicitModule,
ImportLoc, ARRFlags)) {
case ASTReader::Success:
break;
case ASTReader::OutOfDate:
case ASTReader::Missing: {
+ if (Explicit) {
+ // ReadAST has already complained for us.
+ ModuleLoader::HadFatalFailure = true;
+ KnownModules[Path[0].first] = nullptr;
+ return ModuleLoadResult();
+ }
+
// The module file is missing or out-of-date. Build it.
assert(Module && "missing module file");
// Check whether there is a cycle in the module graph.
@@ -1342,9 +1433,6 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return ModuleLoadResult();
}
- getDiagnostics().Report(ImportLoc, diag::remark_module_build)
- << ModuleName << ModuleFileName;
-
// Check whether we have already attempted to build this module (but
// failed).
if (getPreprocessorOpts().FailedModules &&
@@ -1359,6 +1447,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
// Try to compile and then load the module.
if (!compileAndLoadModule(*this, ImportLoc, ModuleNameLoc, Module,
ModuleFileName)) {
+ assert(getDiagnostics().hasErrorOccurred() &&
+ "undiagnosed error in compileAndLoadModule");
if (getPreprocessorOpts().FailedModules)
getPreprocessorOpts().FailedModules->addFailed(ModuleName);
KnownModules[Path[0].first] = nullptr;
@@ -1448,6 +1538,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
Module = Sub;
}
}
+
+ // Don't make the module visible if we are in the implementation.
+ if (ModuleName == getLangOpts().ImplementationOfModule)
+ return ModuleLoadResult(Module, false);
// Make the named module visible, if it's not already part of the module
// we are parsing.
@@ -1468,7 +1562,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
// Check whether this module is available.
clang::Module::Requirement Requirement;
- clang::Module::HeaderDirective MissingHeader;
+ clang::Module::UnresolvedHeaderDirective MissingHeader;
if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement,
MissingHeader)) {
if (MissingHeader.FileNameLoc.isValid()) {
@@ -1497,9 +1591,16 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
Module, ImportLoc);
}
+ // Determine whether we're in the #include buffer for a module. The #includes
+ // in that buffer do not qualify as module imports; they're just an
+ // implementation detail of us building the module.
+ bool IsInModuleIncludes = !getLangOpts().CurrentModule.empty() &&
+ getSourceManager().getFileID(ImportLoc) ==
+ getSourceManager().getMainFileID();
+
// If this module import was due to an inclusion directive, create an
// implicit import declaration to capture it in the AST.
- if (IsInclusionDirective && hasASTContext()) {
+ if (IsInclusionDirective && hasASTContext() && !IsInModuleIncludes) {
TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
ImportLoc, Module,
@@ -1602,3 +1703,4 @@ CompilerInstance::lookupMissingImports(StringRef Name,
return false;
}
+void CompilerInstance::resetAndLeakSema() { BuryPointer(takeSema()); }
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index ce61a4653d2e..54025b06557a 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -10,6 +10,7 @@
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Version.h"
+#include "clang/Config/config.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Util.h"
@@ -19,8 +20,8 @@
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
@@ -215,6 +216,8 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
+ Opts.DisableAllChecks = Args.hasArg(OPT_analyzer_disable_all_checks);
+
Opts.visualizeExplodedGraphWithGraphViz =
Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
Opts.visualizeExplodedGraphWithUbiGraph =
@@ -322,21 +325,38 @@ GenerateOptimizationRemarkRegex(DiagnosticsEngine &Diags, ArgList &Args,
return Pattern;
}
+static void parseSanitizerKinds(StringRef FlagName,
+ const std::vector<std::string> &Sanitizers,
+ DiagnosticsEngine &Diags, SanitizerSet &S) {
+ for (const auto &Sanitizer : Sanitizers) {
+ SanitizerKind K = llvm::StringSwitch<SanitizerKind>(Sanitizer)
+#define SANITIZER(NAME, ID) .Case(NAME, SanitizerKind::ID)
+#include "clang/Basic/Sanitizers.def"
+ .Default(SanitizerKind::Unknown);
+ if (K == SanitizerKind::Unknown)
+ Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer;
+ else
+ S.set(K, true);
+ }
+}
+
static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags,
const TargetOptions &TargetOpts) {
using namespace options;
bool Success = true;
- Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags);
+ unsigned OptimizationLevel = getOptimizationLevel(Args, IK, Diags);
// TODO: This could be done in Driver
unsigned MaxOptLevel = 3;
- if (Opts.OptimizationLevel > MaxOptLevel) {
- // If the optimization level is not supported, fall back on the default optimization
+ if (OptimizationLevel > MaxOptLevel) {
+ // If the optimization level is not supported, fall back on the default
+ // optimization
Diags.Report(diag::warn_drv_optimization_value)
<< Args.getLastArg(OPT_O)->getAsString(Args) << "-O" << MaxOptLevel;
- Opts.OptimizationLevel = MaxOptLevel;
+ OptimizationLevel = MaxOptLevel;
}
+ Opts.OptimizationLevel = OptimizationLevel;
// We must always run at least the always inlining pass.
Opts.setInlining(
@@ -399,6 +419,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.SampleProfileFile = Args.getLastArgValue(OPT_fprofile_sample_use_EQ);
Opts.ProfileInstrGenerate = Args.hasArg(OPT_fprofile_instr_generate);
Opts.InstrProfileInput = Args.getLastArgValue(OPT_fprofile_instr_use_EQ);
+ Opts.CoverageMapping = Args.hasArg(OPT_fcoverage_mapping);
+ Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping);
Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions);
Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device);
@@ -413,16 +435,19 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable);
Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision);
Opts.NoInfsFPMath = (Args.hasArg(OPT_menable_no_infinities) ||
- Args.hasArg(OPT_cl_finite_math_only)||
+ Args.hasArg(OPT_cl_finite_math_only) ||
Args.hasArg(OPT_cl_fast_relaxed_math));
Opts.NoNaNsFPMath = (Args.hasArg(OPT_menable_no_nans) ||
- Args.hasArg(OPT_cl_finite_math_only)||
+ Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
+ Args.hasArg(OPT_cl_finite_math_only) ||
Args.hasArg(OPT_cl_fast_relaxed_math));
+ Opts.NoSignedZeros = Args.hasArg(OPT_cl_no_signed_zeros);
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option);
Opts.NumRegisterParameters = getLastArgIntValue(Args, OPT_mregparm, 0, Diags);
Opts.NoGlobalMerge = Args.hasArg(OPT_mno_global_merge);
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
+ Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks);
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
@@ -435,6 +460,11 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
+ Opts.ThreadModel = Args.getLastArgValue(OPT_mthread_model, "posix");
+ if (Opts.ThreadModel != "posix" && Opts.ThreadModel != "single")
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_mthread_model)->getAsString(Args)
+ << Opts.ThreadModel;
Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ);
Opts.UseInitArray = Args.hasArg(OPT_fuse_init_array);
@@ -442,6 +472,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
OPT_fno_function_sections, false);
Opts.DataSections = Args.hasFlag(OPT_fdata_sections,
OPT_fno_data_sections, false);
+ Opts.MergeFunctions = Args.hasArg(OPT_fmerge_functions);
Opts.VectorizeBB = Args.hasArg(OPT_vectorize_slp_aggressive);
Opts.VectorizeLoop = Args.hasArg(OPT_vectorize_loops);
@@ -449,13 +480,12 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
- Opts.SanitizeRecover = !Args.hasArg(OPT_fno_sanitize_recover);
Opts.DisableGCov = Args.hasArg(OPT_test_coverage);
Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data);
Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes);
if (Opts.EmitGcovArcs || Opts.EmitGcovNotes) {
- Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
+ Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum);
Opts.CoverageNoFunctionNamesInData =
Args.hasArg(OPT_coverage_no_function_names_in_data);
@@ -477,7 +507,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections);
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file);
- Opts.SanitizerBlacklistFile = Args.getLastArgValue(OPT_fsanitize_blacklist);
+ Opts.SanitizeCoverage =
+ getLastArgIntValue(Args, OPT_fsanitize_coverage, 0, Diags);
Opts.SanitizeMemoryTrackOrigins =
getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags);
Opts.SanitizeUndefinedTrapOnError =
@@ -566,11 +597,25 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
NeedLocTracking = true;
}
- // If the user requested one of the flags in the -Rpass family, make sure
- // that the backend tracks source location information.
+ // If the user requested to use a sample profile for PGO, then the
+ // backend will need to track source location information so the profile
+ // can be incorporated into the IR.
+ if (!Opts.SampleProfileFile.empty())
+ NeedLocTracking = true;
+
+ // If the user requested a flag that requires source locations available in
+ // the backend, make sure that the backend tracks source location information.
if (NeedLocTracking && Opts.getDebugInfo() == CodeGenOptions::NoDebugInfo)
Opts.setDebugInfo(CodeGenOptions::LocTrackingOnly);
+ Opts.RewriteMapFiles = Args.getAllArgValues(OPT_frewrite_map_file);
+
+ // Parse -fsanitize-recover= arguments.
+ // FIXME: Report unrecoverable sanitizers incorrectly specified here.
+ parseSanitizerKinds("-fsanitize-recover=",
+ Args.getAllArgValues(OPT_fsanitize_recover_EQ), Diags,
+ Opts.SanitizeRecover);
+
return Success;
}
@@ -597,8 +642,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
bool Success = true;
Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file);
- Opts.DiagnosticSerializationFile =
- Args.getLastArgValue(OPT_diagnostic_serialized_file);
+ if (Arg *A =
+ Args.getLastArg(OPT_diagnostic_serialized_file, OPT__serialize_diags))
+ Opts.DiagnosticSerializationFile = A->getValue();
Opts.IgnoreWarnings = Args.hasArg(OPT_w);
Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros);
Opts.Pedantic = Args.hasArg(OPT_pedantic);
@@ -686,6 +732,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ConstexprBacktraceLimit = getLastArgIntValue(
Args, OPT_fconstexpr_backtrace_limit,
DiagnosticOptions::DefaultConstexprBacktraceLimit, Diags);
+ Opts.SpellCheckingLimit = getLastArgIntValue(
+ Args, OPT_fspell_checking_limit,
+ DiagnosticOptions::DefaultSpellCheckingLimit, Diags);
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
@@ -716,6 +765,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
case OPT_ast_list:
Opts.ProgramAction = frontend::ASTDeclList; break;
case OPT_ast_dump:
+ case OPT_ast_dump_lookups:
Opts.ProgramAction = frontend::ASTDump; break;
case OPT_ast_print:
Opts.ProgramAction = frontend::ASTPrint; break;
@@ -823,11 +873,14 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.FixOnlyWarnings = Args.hasArg(OPT_fix_only_warnings);
Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
+ Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump);
Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter);
Opts.ASTDumpLookups = Args.hasArg(OPT_ast_dump_lookups);
Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index);
Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex;
-
+ Opts.ModuleMapFiles = Args.getAllArgValues(OPT_fmodule_map_file);
+ Opts.ModuleFiles = Args.getAllArgValues(OPT_fmodule_file);
+
Opts.CodeCompleteOpts.IncludeMacros
= Args.hasArg(OPT_code_completion_macros);
Opts.CodeCompleteOpts.IncludeCodePatterns
@@ -866,6 +919,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Literals;
if (Args.hasArg(OPT_objcmt_migrate_subscripting))
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Subscripting;
+ if (Args.hasArg(OPT_objcmt_migrate_property_dot_syntax))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_PropertyDotSyntax;
if (Args.hasArg(OPT_objcmt_migrate_property))
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Property;
if (Args.hasArg(OPT_objcmt_migrate_readonly_property))
@@ -950,14 +1005,19 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
void *MainAddr) {
- SmallString<128> P(llvm::sys::fs::getMainExecutable(Argv0, MainAddr));
-
- if (!P.empty()) {
- llvm::sys::path::remove_filename(P); // Remove /clang from foo/bin/clang
- llvm::sys::path::remove_filename(P); // Remove /bin from foo/bin
-
- // Get foo/lib/clang/<version>/include
- llvm::sys::path::append(P, "lib", "clang", CLANG_VERSION_STRING);
+ std::string ClangExecutable =
+ llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
+ StringRef Dir = llvm::sys::path::parent_path(ClangExecutable);
+
+ // Compute the path to the resource directory.
+ StringRef ClangResourceDir(CLANG_RESOURCE_DIR);
+ SmallString<128> P(Dir);
+ if (ClangResourceDir != "") {
+ llvm::sys::path::append(P, ClangResourceDir);
+ } else {
+ StringRef ClangLibdirSuffix(CLANG_LIBDIR_SUFFIX);
+ llvm::sys::path::append(P, "..", Twine("lib") + ClangLibdirSuffix, "clang",
+ CLANG_VERSION_STRING);
}
return P.str();
@@ -978,6 +1038,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
// -fmodules implies -fmodule-maps
Opts.ModuleMaps = Args.hasArg(OPT_fmodule_maps) || Args.hasArg(OPT_fmodules);
+ Opts.ModuleMapFileHomeIsCwd = Args.hasArg(OPT_fmodule_map_file_home_is_cwd);
Opts.ModuleCachePruneInterval =
getLastArgIntValue(Args, OPT_fmodules_prune_interval, 7 * 24 * 60 * 60);
Opts.ModuleCachePruneAfter =
@@ -995,9 +1056,6 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
StringRef MacroDef = (*it)->getValue();
Opts.ModulesIgnoreMacros.insert(MacroDef.split('=').first);
}
- std::vector<std::string> ModuleMapFiles =
- Args.getAllArgValues(OPT_fmodule_map_file);
- Opts.ModuleMapFiles.insert(ModuleMapFiles.begin(), ModuleMapFiles.end());
// Add -I..., -F..., and -index-header-map options in order.
bool IsIndexHeaderMap = false;
@@ -1118,7 +1176,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
case IK_PreprocessedC:
case IK_ObjC:
case IK_PreprocessedObjC:
- LangStd = LangStandard::lang_gnu99;
+ LangStd = LangStandard::lang_gnu11;
break;
case IK_CXX:
case IK_PreprocessedCXX:
@@ -1135,7 +1193,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.C11 = Std.isC11();
Opts.CPlusPlus = Std.isCPlusPlus();
Opts.CPlusPlus11 = Std.isCPlusPlus11();
- Opts.CPlusPlus1y = Std.isCPlusPlus1y();
+ Opts.CPlusPlus14 = Std.isCPlusPlus14();
Opts.CPlusPlus1z = Std.isCPlusPlus1z();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
@@ -1148,10 +1206,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
if (LangStd == LangStandard::lang_opencl)
Opts.OpenCLVersion = 100;
else if (LangStd == LangStandard::lang_opencl11)
- Opts.OpenCLVersion = 110;
+ Opts.OpenCLVersion = 110;
else if (LangStd == LangStandard::lang_opencl12)
Opts.OpenCLVersion = 120;
-
+ else if (LangStd == LangStandard::lang_opencl20)
+ Opts.OpenCLVersion = 200;
+
// OpenCL has some additional defaults.
if (Opts.OpenCL) {
Opts.AltiVec = 0;
@@ -1175,15 +1235,10 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.GNUKeywords = Opts.GNUMode;
Opts.CXXOperatorNames = Opts.CPlusPlus;
- // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
- // is specified, or -std is set to a conforming mode.
- // Trigraphs are disabled by default in c++1z onwards.
- Opts.Trigraphs = !Opts.GNUMode && !Opts.CPlusPlus1z;
-
Opts.DollarIdents = !Opts.AsmPreprocessor;
- // C++1y onwards has sized global deallocation functions.
- Opts.SizedDeallocation = Opts.CPlusPlus1y;
+ // C++14 onwards has sized global deallocation functions.
+ Opts.SizedDeallocation = Opts.CPlusPlus14;
}
/// Attempt to parse a visibility value out of the given argument.
@@ -1299,6 +1354,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
.Case("CL", LangStandard::lang_opencl)
.Case("CL1.1", LangStandard::lang_opencl11)
.Case("CL1.2", LangStandard::lang_opencl12)
+ .Case("CL2.0", LangStandard::lang_opencl20)
.Default(LangStandard::lang_unspecified);
if (OpenCLLangStd == LangStandard::lang_unspecified) {
@@ -1322,6 +1378,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fno_operator_names))
Opts.CXXOperatorNames = 0;
+ if (Args.hasArg(OPT_fcuda_is_device))
+ Opts.CUDAIsDevice = 1;
+
if (Opts.ObjC1) {
if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) {
StringRef value = arg->getValue();
@@ -1400,17 +1459,22 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
else if (Args.hasArg(OPT_fwrapv))
Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined);
- if (Args.hasArg(OPT_trigraphs))
- Opts.Trigraphs = 1;
+ Opts.MSVCCompat = Args.hasArg(OPT_fms_compatibility);
+ Opts.MicrosoftExt = Opts.MSVCCompat || Args.hasArg(OPT_fms_extensions);
+ Opts.AsmBlocks = Args.hasArg(OPT_fasm_blocks) || Opts.MicrosoftExt;
+ Opts.MSCompatibilityVersion = parseMSCVersion(Args, Diags);
+
+ // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
+ // is specified, or -std is set to a conforming mode.
+ // Trigraphs are disabled by default in c++1z onwards.
+ Opts.Trigraphs = !Opts.GNUMode && !Opts.MSVCCompat && !Opts.CPlusPlus1z;
+ Opts.Trigraphs =
+ Args.hasFlag(OPT_ftrigraphs, OPT_fno_trigraphs, Opts.Trigraphs);
Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers,
OPT_fno_dollars_in_identifiers,
Opts.DollarIdents);
Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
- Opts.MSVCCompat = Args.hasArg(OPT_fms_compatibility);
- Opts.MicrosoftExt = Opts.MSVCCompat || Args.hasArg(OPT_fms_extensions);
- Opts.AsmBlocks = Args.hasArg(OPT_fasm_blocks) || Opts.MicrosoftExt;
- Opts.MSCompatibilityVersion = parseMSCVersion(Args, Diags);
Opts.VtorDispMode = getLastArgIntValue(Args, OPT_vtordisp_mode_EQ, 1, Diags);
Opts.Borland = Args.hasArg(OPT_fborland_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
@@ -1438,6 +1502,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
!Args.hasArg(OPT_fno_modules_search_all) &&
Args.hasArg(OPT_fmodules_search_all);
Opts.ModulesErrorRecovery = !Args.hasArg(OPT_fno_modules_error_recovery);
+ Opts.ModulesImplicitMaps = Args.hasFlag(OPT_fmodules_implicit_maps,
+ OPT_fno_modules_implicit_maps, true);
Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char);
Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar);
Opts.ShortWChar = Args.hasFlag(OPT_fshort_wchar, OPT_fno_short_wchar, false);
@@ -1472,6 +1538,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_fencode_extended_block_signature);
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
Opts.PackStruct = getLastArgIntValue(Args, OPT_fpack_struct_EQ, 0, Diags);
+ Opts.MaxTypeAlign = getLastArgIntValue(Args, OPT_fmax_type_align_EQ, 0, Diags);
Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
Opts.PIELevel = getLastArgIntValue(Args, OPT_pie_level, 0, Diags);
Opts.Static = Args.hasArg(OPT_static_define);
@@ -1492,6 +1559,16 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal);
Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name);
+ Opts.ImplementationOfModule =
+ Args.getLastArgValue(OPT_fmodule_implementation_of);
+ Opts.NativeHalfType = Opts.NativeHalfType;
+ Opts.HalfArgsAndReturns = Args.hasArg(OPT_fallow_half_arguments_and_returns);
+
+ if (!Opts.CurrentModule.empty() && !Opts.ImplementationOfModule.empty() &&
+ Opts.CurrentModule != Opts.ImplementationOfModule) {
+ Diags.Report(diag::err_conflicting_module_names)
+ << Opts.CurrentModule << Opts.ImplementationOfModule;
+ }
if (Arg *A = Args.getLastArg(OPT_faddress_space_map_mangling_EQ)) {
switch (llvm::StringSwitch<unsigned>(A->getValue())
@@ -1556,8 +1633,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// inlining enabled.
Opts.NoInlineDefine = !Opt || Args.hasArg(OPT_fno_inline);
- Opts.FastMath = Args.hasArg(OPT_ffast_math);
- Opts.FiniteMathOnly = Args.hasArg(OPT_ffinite_math_only);
+ Opts.FastMath = Args.hasArg(OPT_ffast_math) ||
+ Args.hasArg(OPT_cl_fast_relaxed_math);
+ Opts.FiniteMathOnly = Args.hasArg(OPT_ffinite_math_only) ||
+ Args.hasArg(OPT_cl_finite_math_only) ||
+ Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.RetainCommentsFromSystemHeaders =
Args.hasArg(OPT_fretain_comments_from_system_headers);
@@ -1575,35 +1655,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
}
// Parse -fsanitize= arguments.
- std::vector<std::string> Sanitizers = Args.getAllArgValues(OPT_fsanitize_EQ);
- for (unsigned I = 0, N = Sanitizers.size(); I != N; ++I) {
- // Since the Opts.Sanitize* values are bitfields, it's a little tricky to
- // efficiently map string values to them. Perform the mapping indirectly:
- // convert strings to enumerated values, then switch over the enum to set
- // the right bitfield value.
- enum Sanitizer {
-#define SANITIZER(NAME, ID) \
- ID,
-#include "clang/Basic/Sanitizers.def"
- Unknown
- };
- switch (llvm::StringSwitch<unsigned>(Sanitizers[I])
-#define SANITIZER(NAME, ID) \
- .Case(NAME, ID)
-#include "clang/Basic/Sanitizers.def"
- .Default(Unknown)) {
-#define SANITIZER(NAME, ID) \
- case ID: \
- Opts.Sanitize.ID = true; \
- break;
-#include "clang/Basic/Sanitizers.def"
-
- case Unknown:
- Diags.Report(diag::err_drv_invalid_value)
- << "-fsanitize=" << Sanitizers[I];
- break;
- }
- }
+ parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
+ Diags, Opts.Sanitize);
+ // -fsanitize-address-field-padding=N has to be a LangOpt, parse it here.
+ Opts.SanitizeAddressFieldPadding =
+ getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags);
+ Opts.SanitizerBlacklistFile = Args.getLastArgValue(OPT_fsanitize_blacklist);
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
@@ -2021,7 +2078,7 @@ createVFSFromCompilerInvocation(const CompilerInvocation &CI,
}
IntrusiveRefCntPtr<vfs::FileSystem> FS =
- vfs::getVFSFromYAML(Buffer->release(), /*DiagHandler*/ nullptr);
+ vfs::getVFSFromYAML(std::move(Buffer.get()), /*DiagHandler*/ nullptr);
if (!FS.get()) {
Diags.Report(diag::err_invalid_vfs_overlay) << File;
return IntrusiveRefCntPtr<vfs::FileSystem>();
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index f2f36e4cacb2..4a8a8a029e79 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -71,13 +71,13 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
return nullptr;
}
- const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
- if (StringRef(Cmd->getCreator().getName()) != "clang") {
+ const driver::Command &Cmd = cast<driver::Command>(*Jobs.begin());
+ if (StringRef(Cmd.getCreator().getName()) != "clang") {
Diags->Report(diag::err_fe_expected_clang_command);
return nullptr;
}
- const ArgStringList &CCArgs = Cmd->getArguments();
+ const ArgStringList &CCArgs = Cmd.getArguments();
std::unique_ptr<CompilerInvocation> CI(new CompilerInvocation());
if (!CompilerInvocation::CreateFromArgs(*CI,
const_cast<const char **>(CCArgs.data()),
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 0b9c0d47dc36..6ea8f5193ef7 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -22,6 +22,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -108,23 +109,32 @@ struct DepCollectorASTListener : public ASTReaderListener {
void DependencyCollector::maybeAddDependency(StringRef Filename, bool FromModule,
bool IsSystem, bool IsModuleFile,
bool IsMissing) {
- if (Seen.insert(Filename) &&
+ if (Seen.insert(Filename).second &&
sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
Dependencies.push_back(Filename);
}
+static bool isSpecialFilename(StringRef Filename) {
+ return llvm::StringSwitch<bool>(Filename)
+ .Case("<built-in>", true)
+ .Case("<stdin>", true)
+ .Default(false);
+}
+
bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
bool IsSystem, bool IsModuleFile,
bool IsMissing) {
- return Filename != "<built-in>" && (needSystemDependencies() || !IsSystem);
+ return !isSpecialFilename(Filename) &&
+ (needSystemDependencies() || !IsSystem);
}
DependencyCollector::~DependencyCollector() { }
void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
- PP.addPPCallbacks(new DepCollectorPPCallbacks(*this, PP.getSourceManager()));
+ PP.addPPCallbacks(
+ llvm::make_unique<DepCollectorPPCallbacks>(*this, PP.getSourceManager()));
}
void DependencyCollector::attachToASTReader(ASTReader &R) {
- R.addListener(new DepCollectorASTListener(*this));
+ R.addListener(llvm::make_unique<DepCollectorASTListener>(*this));
}
namespace {
@@ -203,21 +213,21 @@ DependencyFileGenerator *DependencyFileGenerator::CreateAndAttachToPreprocessor(
PP.SetSuppressIncludeNotFoundError(true);
DFGImpl *Callback = new DFGImpl(&PP, Opts);
- PP.addPPCallbacks(Callback); // PP owns the Callback
+ PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callback));
return new DependencyFileGenerator(Callback);
}
void DependencyFileGenerator::AttachToASTReader(ASTReader &R) {
DFGImpl *I = reinterpret_cast<DFGImpl *>(Impl);
assert(I && "missing implementation");
- R.addListener(new DFGASTReaderListener(*I));
+ R.addListener(llvm::make_unique<DFGASTReaderListener>(*I));
}
/// FileMatchesDepCriteria - Determine whether the given Filename should be
/// considered as a dependency.
bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
SrcMgr::CharacteristicKind FileType) {
- if (strcmp("<built-in>", Filename) == 0)
+ if (isSpecialFilename(Filename))
return false;
if (IncludeSystemHeaders)
@@ -275,7 +285,7 @@ void DFGImpl::InclusionDirective(SourceLocation HashLoc,
}
void DFGImpl::AddFilename(StringRef Filename) {
- if (FilesSet.insert(Filename))
+ if (FilesSet.insert(Filename).second)
Files.push_back(Filename);
}
@@ -297,11 +307,11 @@ void DFGImpl::OutputDependencyFile() {
return;
}
- std::string Err;
- llvm::raw_fd_ostream OS(OutputFile.c_str(), Err, llvm::sys::fs::F_Text);
- if (!Err.empty()) {
- PP->getDiagnostics().Report(diag::err_fe_error_opening)
- << OutputFile << Err;
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
+ if (EC) {
+ PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
+ << EC.message();
return;
}
diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp
index 051b7f9e1412..67a977e38be2 100644
--- a/lib/Frontend/DependencyGraph.cpp
+++ b/lib/Frontend/DependencyGraph.cpp
@@ -61,7 +61,8 @@ public:
void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
StringRef SysRoot) {
- PP.addPPCallbacks(new DependencyGraphCallback(&PP, OutputFile, SysRoot));
+ PP.addPPCallbacks(llvm::make_unique<DependencyGraphCallback>(&PP, OutputFile,
+ SysRoot));
}
void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
@@ -96,11 +97,11 @@ DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
}
void DependencyGraphCallback::OutputGraphFile() {
- std::string Err;
- llvm::raw_fd_ostream OS(OutputFile.c_str(), Err, llvm::sys::fs::F_Text);
- if (!Err.empty()) {
- PP->getDiagnostics().Report(diag::err_fe_error_opening)
- << OutputFile << Err;
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
+ if (EC) {
+ PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
+ << EC.message();
return;
}
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp
index cff32b852bf4..c63e98dbe4f1 100644
--- a/lib/Frontend/DiagnosticRenderer.cpp
+++ b/lib/Frontend/DiagnosticRenderer.cpp
@@ -193,7 +193,7 @@ void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
void DiagnosticRenderer::emitBasicNote(StringRef Message) {
emitDiagnosticMessage(
SourceLocation(), PresumedLoc(), DiagnosticsEngine::Note, Message,
- ArrayRef<CharSourceRange>(), nullptr, DiagOrStoredDiag());
+ None, nullptr, DiagOrStoredDiag());
}
/// \brief Prints an include stack when appropriate for a particular
@@ -509,6 +509,6 @@ DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
Message << "while building module '" << ModuleName << "' imported from "
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":";
else
- Message << "while building module '" << ModuleName << ":";
+ Message << "while building module '" << ModuleName << "':";
emitNote(Loc, Message.str(), &SM);
}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 791017924d69..c81c81aba4d2 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -129,14 +129,15 @@ FrontendAction::FrontendAction() : Instance(nullptr) {}
FrontendAction::~FrontendAction() {}
void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput,
- ASTUnit *AST) {
+ std::unique_ptr<ASTUnit> AST) {
this->CurrentInput = CurrentInput;
- CurrentASTUnit.reset(AST);
+ CurrentASTUnit = std::move(AST);
}
-ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- ASTConsumer* Consumer = CreateASTConsumer(CI, InFile);
+std::unique_ptr<ASTConsumer>
+FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ std::unique_ptr<ASTConsumer> Consumer = CreateASTConsumer(CI, InFile);
if (!Consumer)
return nullptr;
@@ -145,7 +146,8 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
// Make sure the non-plugin consumer is first, so that plugins can't
// modifiy the AST.
- std::vector<ASTConsumer*> Consumers(1, Consumer);
+ std::vector<std::unique_ptr<ASTConsumer>> Consumers;
+ Consumers.push_back(std::move(Consumer));
for (size_t i = 0, e = CI.getFrontendOpts().AddPluginActions.size();
i != e; ++i) {
@@ -155,16 +157,15 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
it = FrontendPluginRegistry::begin(),
ie = FrontendPluginRegistry::end();
it != ie; ++it) {
- if (it->getName() == CI.getFrontendOpts().AddPluginActions[i]) {
- std::unique_ptr<PluginASTAction> P(it->instantiate());
- FrontendAction* c = P.get();
- if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i]))
- Consumers.push_back(c->CreateASTConsumer(CI, InFile));
- }
+ if (it->getName() != CI.getFrontendOpts().AddPluginActions[i])
+ continue;
+ std::unique_ptr<PluginASTAction> P = it->instantiate();
+ if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i]))
+ Consumers.push_back(P->CreateASTConsumer(CI, InFile));
}
}
- return new MultiplexConsumer(Consumers);
+ return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
}
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
@@ -189,13 +190,12 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
- ASTUnit *AST = ASTUnit::LoadFromASTFile(InputFile, Diags,
- CI.getFileSystemOpts());
+ std::unique_ptr<ASTUnit> AST =
+ ASTUnit::LoadFromASTFile(InputFile, Diags, CI.getFileSystemOpts());
+
if (!AST)
goto failure;
- setCurrentInput(Input, AST);
-
// Inform the diagnostic client we are processing a source file.
CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), nullptr);
HasBegunSourceFile = true;
@@ -207,6 +207,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.setPreprocessor(&AST->getPreprocessor());
CI.setASTContext(&AST->getASTContext());
+ setCurrentInput(Input, std::move(AST));
+
// Initialize the action.
if (!BeginSourceFileAction(CI, InputFile))
goto failure;
@@ -285,8 +287,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
}
}
- // Set up the preprocessor.
- CI.createPreprocessor(getTranslationUnitKind());
+ // Set up the preprocessor if needed. When parsing model files the
+ // preprocessor of the original source is reused.
+ if (!isModelParsingAction())
+ CI.createPreprocessor(getTranslationUnitKind());
// Inform the diagnostic client we are processing a source file.
CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
@@ -305,15 +309,19 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// Create the AST context and consumer unless this is a preprocessor only
// action.
if (!usesPreprocessorOnly()) {
- CI.createASTContext();
+ // Parsing a model file should reuse the existing ASTContext.
+ if (!isModelParsingAction())
+ CI.createASTContext();
- std::unique_ptr<ASTConsumer> Consumer(
- CreateWrappedASTConsumer(CI, InputFile));
+ std::unique_ptr<ASTConsumer> Consumer =
+ CreateWrappedASTConsumer(CI, InputFile);
if (!Consumer)
goto failure;
- CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
-
+ // FIXME: should not overwrite ASTMutationListener when parsing model files?
+ if (!isModelParsingAction())
+ CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
+
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
IntrusiveRefCntPtr<ExternalSemaSource> source, FinalReader;
@@ -349,7 +357,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
goto failure;
}
- CI.setASTConsumer(Consumer.release());
+ CI.setASTConsumer(std::move(Consumer));
if (!CI.hasASTConsumer())
goto failure;
}
@@ -375,6 +383,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
"doesn't support modules");
}
+ // If we were asked to load any module files, do so now.
+ for (const auto &ModuleFile : CI.getFrontendOpts().ModuleFiles)
+ if (!CI.loadModuleFile(ModuleFile))
+ goto failure;
+
// If there is a layout overrides file, attach an external AST source that
// provides the layouts from that file.
if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
@@ -432,6 +445,10 @@ void FrontendAction::EndSourceFile() {
// Inform the diagnostic client we are done with this source file.
CI.getDiagnosticClient().EndSourceFile();
+ // Inform the preprocessor we are done.
+ if (CI.hasPreprocessor())
+ CI.getPreprocessor().EndSourceFile();
+
// Finalize the action.
EndSourceFileAction();
@@ -444,7 +461,7 @@ void FrontendAction::EndSourceFile() {
CI.resetAndLeakSema();
CI.resetAndLeakASTContext();
}
- BuryPointer(CI.takeASTConsumer());
+ BuryPointer(CI.takeASTConsumer().get());
} else {
if (!isCurrentFileAST()) {
CI.setSema(nullptr);
@@ -453,10 +470,6 @@ void FrontendAction::EndSourceFile() {
CI.setASTConsumer(nullptr);
}
- // Inform the preprocessor we are done.
- if (CI.hasPreprocessor())
- CI.getPreprocessor().EndSourceFile();
-
if (CI.getFrontendOpts().ShowStats) {
llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
CI.getPreprocessor().PrintStats();
@@ -516,14 +529,15 @@ void ASTFrontendAction::ExecuteAction() {
void PluginASTAction::anchor() { }
-ASTConsumer *
+std::unique_ptr<ASTConsumer>
PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
}
-ASTConsumer *WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
return WrappedAction->CreateASTConsumer(CI, InFile);
}
bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) {
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 6dcaf382c3c4..701ef026d49c 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -33,9 +33,9 @@ using namespace clang;
// Custom Actions
//===----------------------------------------------------------------------===//
-ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- return new ASTConsumer();
+std::unique_ptr<ASTConsumer>
+InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+ return llvm::make_unique<ASTConsumer>();
}
void InitOnlyAction::ExecuteAction() {
@@ -45,36 +45,38 @@ void InitOnlyAction::ExecuteAction() {
// AST Consumer Actions
//===----------------------------------------------------------------------===//
-ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
return CreateASTPrinter(OS, CI.getFrontendOpts().ASTDumpFilter);
return nullptr;
}
-ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return CreateASTDumper(CI.getFrontendOpts().ASTDumpFilter,
+ CI.getFrontendOpts().ASTDumpDecls,
CI.getFrontendOpts().ASTDumpLookups);
}
-ASTConsumer *ASTDeclListAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+ASTDeclListAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return CreateASTDeclNodeLister();
}
-ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+ASTViewAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return CreateASTViewer();
}
-ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
return CreateDeclContextPrinter();
}
-ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
raw_ostream *OS = nullptr;
@@ -83,8 +85,8 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
if (!CI.getFrontendOpts().RelocatablePCH)
Sysroot.clear();
- return new PCHGenerator(CI.getPreprocessor(), OutputFile, nullptr, Sysroot,
- OS);
+ return llvm::make_unique<PCHGenerator>(CI.getPreprocessor(), OutputFile,
+ nullptr, Sysroot, OS);
}
bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
@@ -111,16 +113,17 @@ bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
return false;
}
-ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
raw_ostream *OS = nullptr;
if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS))
return nullptr;
- return new PCHGenerator(CI.getPreprocessor(), OutputFile, Module,
- Sysroot, OS);
+ return llvm::make_unique<PCHGenerator>(CI.getPreprocessor(), OutputFile,
+ Module, Sysroot, OS);
}
static SmallVectorImpl<char> &
@@ -139,17 +142,9 @@ static std::error_code addHeaderInclude(StringRef HeaderName,
Includes += "#import \"";
else
Includes += "#include \"";
- // Use an absolute path for the include; there's no reason to think that
- // a relative path will work (. might not be on our include path) or that
- // it will find the same file.
- if (llvm::sys::path::is_absolute(HeaderName)) {
- Includes += HeaderName;
- } else {
- SmallString<256> Header = HeaderName;
- if (std::error_code Err = llvm::sys::fs::make_absolute(Header))
- return Err;
- Includes += Header;
- }
+
+ Includes += HeaderName;
+
Includes += "\"\n";
if (IsExternC && LangOpts.CPlusPlus)
Includes += "}\n";
@@ -160,7 +155,16 @@ static std::error_code addHeaderInclude(const FileEntry *Header,
SmallVectorImpl<char> &Includes,
const LangOptions &LangOpts,
bool IsExternC) {
- return addHeaderInclude(Header->getName(), Includes, LangOpts, IsExternC);
+ // Use an absolute path if we don't have a filename as written in the module
+ // map file; this ensures that we will identify the right file independent of
+ // header search paths.
+ if (llvm::sys::path::is_absolute(Header->getName()))
+ return addHeaderInclude(Header->getName(), Includes, LangOpts, IsExternC);
+
+ SmallString<256> AbsName(Header->getName());
+ if (std::error_code Err = llvm::sys::fs::make_absolute(AbsName))
+ return Err;
+ return addHeaderInclude(AbsName, Includes, LangOpts, IsExternC);
}
/// \brief Collect the set of header includes needed to construct the given
@@ -179,16 +183,20 @@ collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
return std::error_code();
// Add includes for each of these headers.
- for (unsigned I = 0, N = Module->NormalHeaders.size(); I != N; ++I) {
- const FileEntry *Header = Module->NormalHeaders[I];
- Module->addTopHeader(Header);
- if (std::error_code Err =
- addHeaderInclude(Header, Includes, LangOpts, Module->IsExternC))
+ for (Module::Header &H : Module->Headers[Module::HK_Normal]) {
+ Module->addTopHeader(H.Entry);
+ // Use the path as specified in the module map file. We'll look for this
+ // file relative to the module build directory (the directory containing
+ // the module map file) so this will find the same file that we found
+ // while parsing the module map.
+ if (std::error_code Err = addHeaderInclude(H.NameAsWritten, Includes,
+ LangOpts, Module->IsExternC))
return Err;
}
// Note that Module->PrivateHeaders will not be a TopHeader.
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
+ // FIXME: Track the name as written here.
Module->addTopHeader(UmbrellaHeader);
if (Module->Parent) {
// Include the umbrella header for submodules.
@@ -210,25 +218,30 @@ collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
.Cases(".h", ".H", ".hh", ".hpp", true)
.Default(false))
continue;
-
+
+ const FileEntry *Header = FileMgr.getFile(Dir->path());
+ // FIXME: This shouldn't happen unless there is a file system race. Is
+ // that worth diagnosing?
+ if (!Header)
+ continue;
+
// If this header is marked 'unavailable' in this module, don't include
// it.
- if (const FileEntry *Header = FileMgr.getFile(Dir->path())) {
- if (ModMap.isHeaderUnavailableInModule(Header, Module))
- continue;
- Module->addTopHeader(Header);
- }
-
+ if (ModMap.isHeaderUnavailableInModule(Header, Module))
+ continue;
+
// Include this header as part of the umbrella directory.
- if (std::error_code Err = addHeaderInclude(Dir->path(), Includes,
- LangOpts, Module->IsExternC))
+ // FIXME: Track the name as written through to here.
+ Module->addTopHeader(Header);
+ if (std::error_code Err =
+ addHeaderInclude(Header, Includes, LangOpts, Module->IsExternC))
return Err;
}
if (EC)
return EC;
}
-
+
// Recurse into submodules.
for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
SubEnd = Module->submodule_end();
@@ -285,7 +298,7 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
// Check whether we can build this module at all.
clang::Module::Requirement Requirement;
- clang::Module::HeaderDirective MissingHeader;
+ clang::Module::UnresolvedHeaderDirective MissingHeader;
if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
MissingHeader)) {
if (MissingHeader.FileNameLoc.isValid()) {
@@ -301,10 +314,12 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
return false;
}
- if (!ModuleMapForUniquing)
+ if (ModuleMapForUniquing && ModuleMapForUniquing != ModuleMap) {
+ Module->IsInferred = true;
+ HS.getModuleMap().setInferredModuleAllowedBy(Module, ModuleMapForUniquing);
+ } else {
ModuleMapForUniquing = ModuleMap;
- Module->ModuleMap = ModuleMapForUniquing;
- assert(Module->ModuleMap && "missing module map file");
+ }
FileManager &FileMgr = CI.getFileManager();
@@ -312,6 +327,7 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
SmallString<256> HeaderContents;
std::error_code Err = std::error_code();
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader())
+ // FIXME: Track the file name as written.
Err = addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts(),
Module->IsExternC);
if (!Err)
@@ -326,11 +342,15 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
return false;
}
- llvm::MemoryBuffer *InputBuffer =
+ // Inform the preprocessor that includes from within the input buffer should
+ // be resolved relative to the build directory of the module map file.
+ CI.getPreprocessor().setMainFileDir(Module->Directory);
+
+ std::unique_ptr<llvm::MemoryBuffer> InputBuffer =
llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
Module::getModuleInputBufferName());
// Ownership of InputBuffer will be transferred to the SourceManager.
- setCurrentInput(FrontendInputFile(InputBuffer, getCurrentFileKind(),
+ setCurrentInput(FrontendInputFile(InputBuffer.release(), getCurrentFileKind(),
Module->IsSystem));
return true;
}
@@ -363,19 +383,20 @@ bool GenerateModuleAction::ComputeASTConsumerArguments(CompilerInstance &CI,
return false;
}
-ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- return new ASTConsumer();
+std::unique_ptr<ASTConsumer>
+SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+ return llvm::make_unique<ASTConsumer>();
}
-ASTConsumer *DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- return new ASTConsumer();
+std::unique_ptr<ASTConsumer>
+DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ return llvm::make_unique<ASTConsumer>();
}
-ASTConsumer *VerifyPCHAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- return new ASTConsumer();
+std::unique_ptr<ASTConsumer>
+VerifyPCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+ return llvm::make_unique<ASTConsumer>();
}
void VerifyPCHAction::ExecuteAction() {
@@ -425,8 +446,8 @@ namespace {
Out.indent(2) << "Module map file: " << ModuleMapPath << "\n";
}
- bool ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) override {
+ bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
+ bool AllowCompatibleDifferences) override {
Out.indent(2) << "Language options:\n";
#define LANGOPT(Name, Bits, Default, Description) \
DUMP_BOOLEAN(LangOpts.Name, Description);
@@ -528,9 +549,9 @@ void DumpModuleInfoAction::ExecuteAction() {
std::unique_ptr<llvm::raw_fd_ostream> OutFile;
StringRef OutputFileName = getCompilerInstance().getFrontendOpts().OutputFile;
if (!OutputFileName.empty() && OutputFileName != "-") {
- std::string ErrorInfo;
- OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str().c_str(),
- ErrorInfo, llvm::sys::fs::F_Text));
+ std::error_code EC;
+ OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC,
+ llvm::sys::fs::F_Text));
}
llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs();
@@ -675,13 +696,12 @@ void PrintPreambleAction::ExecuteAction() {
// We can't do anything with these.
return;
}
-
+
CompilerInstance &CI = getCompilerInstance();
- llvm::MemoryBuffer *Buffer
- = CI.getFileManager().getBufferForFile(getCurrentFile());
+ auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile());
if (Buffer) {
- unsigned Preamble = Lexer::ComputePreamble(Buffer, CI.getLangOpts()).first;
- llvm::outs().write(Buffer->getBufferStart(), Preamble);
- delete Buffer;
+ unsigned Preamble =
+ Lexer::ComputePreamble((*Buffer)->getBuffer(), CI.getLangOpts()).first;
+ llvm::outs().write((*Buffer)->getBufferStart(), Preamble);
}
}
diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp
index a2f5896746af..27011945712a 100644
--- a/lib/Frontend/HeaderIncludeGen.cpp
+++ b/lib/Frontend/HeaderIncludeGen.cpp
@@ -54,13 +54,12 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
// Open the output file, if used.
if (!OutputPath.empty()) {
- std::string Error;
+ std::error_code EC;
llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
- OutputPath.str().c_str(), Error,
- llvm::sys::fs::F_Append | llvm::sys::fs::F_Text);
- if (!Error.empty()) {
- PP.getDiagnostics().Report(
- clang::diag::warn_fe_cc_print_header_failure) << Error;
+ OutputPath.str(), EC, llvm::sys::fs::F_Append | llvm::sys::fs::F_Text);
+ if (EC) {
+ PP.getDiagnostics().Report(clang::diag::warn_fe_cc_print_header_failure)
+ << EC.message();
delete OS;
} else {
OS->SetUnbuffered();
@@ -70,9 +69,12 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
}
}
- PP.addPPCallbacks(new HeaderIncludesCallback(&PP, ShowAllHeaders,
- OutputFile, OwnsOutputFile,
- ShowDepth, MSStyle));
+ PP.addPPCallbacks(llvm::make_unique<HeaderIncludesCallback>(&PP,
+ ShowAllHeaders,
+ OutputFile,
+ OwnsOutputFile,
+ ShowDepth,
+ MSStyle));
}
void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index d2edc9479f6b..a518a0a27a23 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -380,7 +380,6 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
break;
case llvm::Triple::aarch64:
- case llvm::Triple::arm64:
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
"arm64-apple-darwin10", "", "", triple);
break;
@@ -391,7 +390,7 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
switch (os) {
case llvm::Triple::Linux:
llvm_unreachable("Include management is handled in the driver.");
-
+ break;
case llvm::Triple::Win32:
switch (triple.getEnvironment()) {
default: llvm_unreachable("Include management is handled in the driver.");
@@ -445,11 +444,6 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
case llvm::Triple::Solaris:
AddGnuCPlusPlusIncludePaths("/usr/gcc/4.5/include/c++/4.5.2/",
"i386-pc-solaris2.11", "", "", triple);
- // Solaris - Fall though..
- case llvm::Triple::AuroraUX:
- // AuroraUX
- AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4",
- "i386-pc-solaris2.11", "", "", triple);
break;
default:
break;
@@ -473,7 +467,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
case llvm::Triple::Win32:
if (triple.getEnvironment() == llvm::Triple::MSVC ||
triple.getEnvironment() == llvm::Triple::Itanium ||
- triple.getObjectFormat() == llvm::Triple::MachO)
+ triple.isOSBinFormatMachO())
return;
break;
}
@@ -535,16 +529,16 @@ static unsigned RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
if (CurEntry.isNormalDir()) {
// If this isn't the first time we've seen this dir, remove it.
- if (SeenDirs.insert(CurEntry.getDir()))
+ if (SeenDirs.insert(CurEntry.getDir()).second)
continue;
} else if (CurEntry.isFramework()) {
// If this isn't the first time we've seen this framework dir, remove it.
- if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()))
+ if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()).second)
continue;
} else {
assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
// If this isn't the first time we've seen this headermap, remove it.
- if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()))
+ if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()).second)
continue;
}
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 7a9d09a5e7ac..f4241a94ae02 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -65,17 +65,14 @@ static void DefineBuiltinMacro(MacroBuilder &Builder, StringRef Macro,
/// AddImplicitInclude - Add an implicit \#include of the specified file to the
/// predefines buffer.
-static void AddImplicitInclude(MacroBuilder &Builder, StringRef File,
- FileManager &FileMgr) {
- Builder.append(Twine("#include \"") +
- HeaderSearch::NormalizeDashIncludePath(File, FileMgr) + "\"");
+/// As these includes are generated by -include arguments the header search
+/// logic is going to search relatively to the current working directory.
+static void AddImplicitInclude(MacroBuilder &Builder, StringRef File) {
+ Builder.append(Twine("#include \"") + File + "\"");
}
-static void AddImplicitIncludeMacros(MacroBuilder &Builder,
- StringRef File,
- FileManager &FileMgr) {
- Builder.append(Twine("#__include_macros \"") +
- HeaderSearch::NormalizeDashIncludePath(File, FileMgr) + "\"");
+static void AddImplicitIncludeMacros(MacroBuilder &Builder, StringRef File) {
+ Builder.append(Twine("#__include_macros \"") + File + "\"");
// Marker token to stop the __include_macros fetch loop.
Builder.append("##"); // ##?
}
@@ -94,7 +91,7 @@ static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP,
return;
}
- AddImplicitInclude(Builder, OriginalFile, PP.getFileManager());
+ AddImplicitInclude(Builder, OriginalFile);
}
/// \brief Add an implicit \#include using the original file used to generate
@@ -107,7 +104,7 @@ static void AddImplicitIncludePCH(MacroBuilder &Builder, Preprocessor &PP,
if (OriginalFile.empty())
return;
- AddImplicitInclude(Builder, OriginalFile, PP.getFileManager());
+ AddImplicitInclude(Builder, OriginalFile);
}
/// PickFP - This is used to pick a value based on the FP semantics of the
@@ -378,7 +375,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
// C++1y [cpp.predefined]p1:
// The name __cplusplus is defined to the value 201402L when compiling a
// C++ translation unit.
- else if (LangOpts.CPlusPlus1y)
+ else if (LangOpts.CPlusPlus14)
Builder.defineMacro("__cplusplus", "201402L");
// C++11 [cpp.predefined]p1:
// The name __cplusplus is defined to the value 201103L when compiling a
@@ -412,6 +409,12 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
/// ISO/IEC JTC1/SC22/WG21 (C++) SD-6: "SG10 Feature Test Recommendations".
static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
MacroBuilder &Builder) {
+ // C++98 features.
+ if (LangOpts.RTTI)
+ Builder.defineMacro("__cpp_rtti", "199711");
+ if (LangOpts.CXXExceptions)
+ Builder.defineMacro("__cpp_exceptions", "199711");
+
// C++11 features.
if (LangOpts.CPlusPlus11) {
Builder.defineMacro("__cpp_unicode_characters", "200704");
@@ -420,17 +423,25 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_user_defined_literals", "200809");
Builder.defineMacro("__cpp_lambdas", "200907");
Builder.defineMacro("__cpp_constexpr",
- LangOpts.CPlusPlus1y ? "201304" : "200704");
+ LangOpts.CPlusPlus14 ? "201304" : "200704");
+ Builder.defineMacro("__cpp_range_based_for", "200907");
Builder.defineMacro("__cpp_static_assert", "200410");
Builder.defineMacro("__cpp_decltype", "200707");
Builder.defineMacro("__cpp_attributes", "200809");
Builder.defineMacro("__cpp_rvalue_references", "200610");
Builder.defineMacro("__cpp_variadic_templates", "200704");
+ Builder.defineMacro("__cpp_initializer_lists", "200806");
+ Builder.defineMacro("__cpp_delegating_constructors", "200604");
+ Builder.defineMacro("__cpp_nsdmi", "200809");
+ Builder.defineMacro("__cpp_inheriting_constructors", "200802");
+ Builder.defineMacro("__cpp_ref_qualifiers", "200710");
+ Builder.defineMacro("__cpp_alias_templates", "200704");
}
// C++14 features.
- if (LangOpts.CPlusPlus1y) {
+ if (LangOpts.CPlusPlus14) {
Builder.defineMacro("__cpp_binary_literals", "201304");
+ Builder.defineMacro("__cpp_digit_separators", "201309");
Builder.defineMacro("__cpp_init_captures", "201304");
Builder.defineMacro("__cpp_generic_lambdas", "201304");
Builder.defineMacro("__cpp_decltype_auto", "201304");
@@ -438,6 +449,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_aggregate_nsdmi", "201304");
Builder.defineMacro("__cpp_variable_templates", "201304");
}
+ if (LangOpts.SizedDeallocation)
+ Builder.defineMacro("__cpp_sized_deallocation", "201309");
}
static void InitializePredefinedMacros(const TargetInfo &TI,
@@ -530,6 +543,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("IBOutletCollection(ClassName)",
"__attribute__((iboutletcollection(ClassName)))");
Builder.defineMacro("IBAction", "void)__attribute__((ibaction)");
+ Builder.defineMacro("IBInspectable", "");
+ Builder.defineMacro("IB_DESIGNABLE", "");
}
if (LangOpts.CPlusPlus)
@@ -551,7 +566,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__BLOCKS__");
}
- if (!LangOpts.MSVCCompat && LangOpts.CXXExceptions)
+ if (!LangOpts.MSVCCompat && LangOpts.Exceptions)
Builder.defineMacro("__EXCEPTIONS");
if (!LangOpts.MSVCCompat && LangOpts.RTTI)
Builder.defineMacro("__GXX_RTTI");
@@ -626,12 +641,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder);
DefineTypeSize("__SIZE_MAX__", TI.getSizeType(), TI, Builder);
- if (!LangOpts.MSVCCompat) {
- DefineTypeSize("__UINTMAX_MAX__", TI.getUIntMaxType(), TI, Builder);
- DefineTypeSize("__PTRDIFF_MAX__", TI.getPtrDiffType(0), TI, Builder);
- DefineTypeSize("__INTPTR_MAX__", TI.getIntPtrType(), TI, Builder);
- DefineTypeSize("__UINTPTR_MAX__", TI.getUIntPtrType(), TI, Builder);
- }
+ DefineTypeSize("__UINTMAX_MAX__", TI.getUIntMaxType(), TI, Builder);
+ DefineTypeSize("__PTRDIFF_MAX__", TI.getPtrDiffType(0), TI, Builder);
+ DefineTypeSize("__INTPTR_MAX__", TI.getIntPtrType(), TI, Builder);
+ DefineTypeSize("__UINTPTR_MAX__", TI.getUIntPtrType(), TI, Builder);
DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder);
@@ -649,7 +662,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
TI.getTypeWidth(TI.getWCharType()), TI, Builder);
DefineTypeSizeof("__SIZEOF_WINT_T__",
TI.getTypeWidth(TI.getWIntType()), TI, Builder);
- if (TI.hasInt128Type())
+ // This is a temporary workaround while MIPS64 has not yet fully supported
+ // 128-bit integers. But declaration of int128 type is necessary even though
+ // __SIZEOF_INT128__ is undefined because c++ standard header files like
+ // limits throw error message if __int128 is not available.
+ if (TI.hasInt128Type() && !(TI.getTriple().getArch() == llvm::Triple::mips64el
+ || TI.getTriple().getArch() == llvm::Triple::mips64))
DefineTypeSizeof("__SIZEOF_INT128__", 128, TI, Builder);
DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder);
@@ -679,12 +697,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineType("__CHAR16_TYPE__", TI.getChar16Type(), Builder);
DefineType("__CHAR32_TYPE__", TI.getChar32Type(), Builder);
- if (!LangOpts.MSVCCompat) {
- DefineTypeWidth("__UINTMAX_WIDTH__", TI.getUIntMaxType(), TI, Builder);
- DefineType("__UINTPTR_TYPE__", TI.getUIntPtrType(), Builder);
- DefineFmt("__UINTPTR", TI.getUIntPtrType(), TI, Builder);
- DefineTypeWidth("__UINTPTR_WIDTH__", TI.getUIntPtrType(), TI, Builder);
- }
+ DefineTypeWidth("__UINTMAX_WIDTH__", TI.getUIntMaxType(), TI, Builder);
+ DefineType("__UINTPTR_TYPE__", TI.getUIntPtrType(), Builder);
+ DefineFmt("__UINTPTR", TI.getUIntPtrType(), TI, Builder);
+ DefineTypeWidth("__UINTPTR_WIDTH__", TI.getUIntPtrType(), TI, Builder);
DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F");
DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), "");
@@ -718,54 +734,52 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (TI.getLongLongWidth() > TI.getLongWidth())
DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Builder);
- if (!LangOpts.MSVCCompat) {
- DefineExactWidthIntType(TargetInfo::UnsignedChar, TI, Builder);
- DefineExactWidthIntTypeSize(TargetInfo::UnsignedChar, TI, Builder);
- DefineExactWidthIntTypeSize(TargetInfo::SignedChar, TI, Builder);
-
- if (TI.getShortWidth() > TI.getCharWidth()) {
- DefineExactWidthIntType(TargetInfo::UnsignedShort, TI, Builder);
- DefineExactWidthIntTypeSize(TargetInfo::UnsignedShort, TI, Builder);
- DefineExactWidthIntTypeSize(TargetInfo::SignedShort, TI, Builder);
- }
+ DefineExactWidthIntType(TargetInfo::UnsignedChar, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::UnsignedChar, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::SignedChar, TI, Builder);
- if (TI.getIntWidth() > TI.getShortWidth()) {
- DefineExactWidthIntType(TargetInfo::UnsignedInt, TI, Builder);
- DefineExactWidthIntTypeSize(TargetInfo::UnsignedInt, TI, Builder);
- DefineExactWidthIntTypeSize(TargetInfo::SignedInt, TI, Builder);
- }
+ if (TI.getShortWidth() > TI.getCharWidth()) {
+ DefineExactWidthIntType(TargetInfo::UnsignedShort, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::UnsignedShort, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::SignedShort, TI, Builder);
+ }
- if (TI.getLongWidth() > TI.getIntWidth()) {
- DefineExactWidthIntType(TargetInfo::UnsignedLong, TI, Builder);
- DefineExactWidthIntTypeSize(TargetInfo::UnsignedLong, TI, Builder);
- DefineExactWidthIntTypeSize(TargetInfo::SignedLong, TI, Builder);
- }
+ if (TI.getIntWidth() > TI.getShortWidth()) {
+ DefineExactWidthIntType(TargetInfo::UnsignedInt, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::UnsignedInt, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::SignedInt, TI, Builder);
+ }
- if (TI.getLongLongWidth() > TI.getLongWidth()) {
- DefineExactWidthIntType(TargetInfo::UnsignedLongLong, TI, Builder);
- DefineExactWidthIntTypeSize(TargetInfo::UnsignedLongLong, TI, Builder);
- DefineExactWidthIntTypeSize(TargetInfo::SignedLongLong, TI, Builder);
- }
+ if (TI.getLongWidth() > TI.getIntWidth()) {
+ DefineExactWidthIntType(TargetInfo::UnsignedLong, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::UnsignedLong, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::SignedLong, TI, Builder);
+ }
- DefineLeastWidthIntType(8, true, TI, Builder);
- DefineLeastWidthIntType(8, false, TI, Builder);
- DefineLeastWidthIntType(16, true, TI, Builder);
- DefineLeastWidthIntType(16, false, TI, Builder);
- DefineLeastWidthIntType(32, true, TI, Builder);
- DefineLeastWidthIntType(32, false, TI, Builder);
- DefineLeastWidthIntType(64, true, TI, Builder);
- DefineLeastWidthIntType(64, false, TI, Builder);
-
- DefineFastIntType(8, true, TI, Builder);
- DefineFastIntType(8, false, TI, Builder);
- DefineFastIntType(16, true, TI, Builder);
- DefineFastIntType(16, false, TI, Builder);
- DefineFastIntType(32, true, TI, Builder);
- DefineFastIntType(32, false, TI, Builder);
- DefineFastIntType(64, true, TI, Builder);
- DefineFastIntType(64, false, TI, Builder);
+ if (TI.getLongLongWidth() > TI.getLongWidth()) {
+ DefineExactWidthIntType(TargetInfo::UnsignedLongLong, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::UnsignedLongLong, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::SignedLongLong, TI, Builder);
}
+ DefineLeastWidthIntType(8, true, TI, Builder);
+ DefineLeastWidthIntType(8, false, TI, Builder);
+ DefineLeastWidthIntType(16, true, TI, Builder);
+ DefineLeastWidthIntType(16, false, TI, Builder);
+ DefineLeastWidthIntType(32, true, TI, Builder);
+ DefineLeastWidthIntType(32, false, TI, Builder);
+ DefineLeastWidthIntType(64, true, TI, Builder);
+ DefineLeastWidthIntType(64, false, TI, Builder);
+
+ DefineFastIntType(8, true, TI, Builder);
+ DefineFastIntType(8, false, TI, Builder);
+ DefineFastIntType(16, true, TI, Builder);
+ DefineFastIntType(16, false, TI, Builder);
+ DefineFastIntType(32, true, TI, Builder);
+ DefineFastIntType(32, false, TI, Builder);
+ DefineFastIntType(64, true, TI, Builder);
+ DefineFastIntType(64, false, TI, Builder);
+
if (const char *Prefix = TI.getUserLabelPrefix())
Builder.defineMacro("__USER_LABEL_PREFIX__", Prefix);
@@ -861,6 +875,13 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("_OPENMP", "201307");
}
+ // CUDA device path compilaton
+ if (LangOpts.CUDAIsDevice) {
+ // The CUDA_ARCH value is set for the GPU target specified in the NVPTX
+ // backend's target defines.
+ Builder.defineMacro("__CUDA_ARCH__");
+ }
+
// Get other target #defines.
TI.getTargetDefines(LangOpts, Builder);
}
@@ -925,8 +946,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
// If -imacros are specified, include them now. These are processed before
// any -include directives.
for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i)
- AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i],
- PP.getFileManager());
+ AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i]);
// Process -include-pch/-include-pth directives.
if (!InitOpts.ImplicitPCHInclude.empty())
@@ -937,7 +957,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
// Process -include directives.
for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) {
const std::string &Path = InitOpts.Includes[i];
- AddImplicitInclude(Builder, Path, PP.getFileManager());
+ AddImplicitInclude(Builder, Path);
}
// Exit the command line and go back to <built-in> (2 is LC_LEAVE).
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
index 19539e0a5eb2..c6a18e0d80d2 100644
--- a/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -18,17 +18,11 @@
using namespace clang;
using namespace markup;
-LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
- DiagnosticOptions *diags,
- bool _OwnsOutputStream)
- : OS(os), LangOpts(nullptr), DiagOpts(diags),
- OwnsOutputStream(_OwnsOutputStream) {
-}
-
-LogDiagnosticPrinter::~LogDiagnosticPrinter() {
- if (OwnsOutputStream)
- delete &OS;
-}
+LogDiagnosticPrinter::LogDiagnosticPrinter(
+ raw_ostream &os, DiagnosticOptions *diags,
+ std::unique_ptr<raw_ostream> StreamOwner)
+ : OS(os), StreamOwner(std::move(StreamOwner)), LangOpts(nullptr),
+ DiagOpts(diags) {}
static StringRef getLevelName(DiagnosticsEngine::Level Level) {
switch (Level) {
@@ -69,6 +63,14 @@ LogDiagnosticPrinter::EmitDiagEntry(llvm::raw_ostream &OS,
<< " ";
EmitString(OS, DE.Message) << '\n';
}
+ OS << " <key>ID</key>\n"
+ << " ";
+ EmitInteger(OS, DE.DiagnosticID) << '\n';
+ if (!DE.WarningOption.empty()) {
+ OS << " <key>WarningOption</key>\n"
+ << " ";
+ EmitString(OS, DE.WarningOption) << '\n';
+ }
OS << " </dict>\n";
}
@@ -128,6 +130,8 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
DE.DiagnosticID = Info.getID();
DE.DiagnosticLevel = Level;
+ DE.WarningOption = DiagnosticIDs::getWarningOptionForDiag(DE.DiagnosticID);
+
// Format the message.
SmallString<100> MessageStr;
Info.FormatDiagnostic(MessageStr);
diff --git a/lib/Frontend/ModuleDependencyCollector.cpp b/lib/Frontend/ModuleDependencyCollector.cpp
index d30f9214f82e..62865e984f65 100644
--- a/lib/Frontend/ModuleDependencyCollector.cpp
+++ b/lib/Frontend/ModuleDependencyCollector.cpp
@@ -13,8 +13,8 @@
#include "clang/Frontend/Utils.h"
#include "clang/Serialization/ASTReader.h"
-#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -38,7 +38,7 @@ public:
}
void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
- R.addListener(new ModuleDependencyListener(*this));
+ R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
}
void ModuleDependencyCollector::writeFileMap() {
@@ -48,49 +48,26 @@ void ModuleDependencyCollector::writeFileMap() {
SmallString<256> Dest = getDest();
llvm::sys::path::append(Dest, "vfs.yaml");
- std::string ErrorInfo;
- llvm::raw_fd_ostream OS(Dest.c_str(), ErrorInfo, llvm::sys::fs::F_Text);
- if (!ErrorInfo.empty()) {
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(Dest, EC, llvm::sys::fs::F_Text);
+ if (EC) {
setHasErrors();
return;
}
VFSWriter.write(OS);
}
-/// Remove traversal (ie, . or ..) from the given absolute path.
-static void removePathTraversal(SmallVectorImpl<char> &Path) {
- using namespace llvm::sys;
- SmallVector<StringRef, 16> ComponentStack;
- StringRef P(Path.data(), Path.size());
-
- // Skip the root path, then look for traversal in the components.
- StringRef Rel = path::relative_path(P);
- for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) {
- if (C == ".")
- continue;
- if (C == "..") {
- assert(ComponentStack.size() && "Path traverses out of parent");
- ComponentStack.pop_back();
- } else
- ComponentStack.push_back(C);
- }
-
- // The stack is now the path without any directory traversal.
- SmallString<256> Buffer = path::root_path(P);
- for (StringRef C : ComponentStack)
- path::append(Buffer, C);
-
- // Put the result in Path.
- Path.swap(Buffer);
-}
-
std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) {
using namespace llvm::sys;
// We need an absolute path to append to the root.
SmallString<256> AbsoluteSrc = Src;
fs::make_absolute(AbsoluteSrc);
- removePathTraversal(AbsoluteSrc);
+ // Canonicalize to a native path to avoid mixed separator styles.
+ path::native(AbsoluteSrc);
+ // TODO: We probably need to handle .. as well as . in order to have valid
+ // input to the YAMLVFSWriter.
+ FileManager::removeDotPaths(AbsoluteSrc);
// Build the destination path.
SmallString<256> Dest = Collector.getDest();
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 0e933a3f165f..019882833d41 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -107,6 +107,7 @@ public:
const ObjCPropertyDecl *OrigProp,
const ObjCCategoryDecl *ClassExt) override;
void DeclarationMarkedUsed(const Decl *D) override;
+ void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
private:
std::vector<ASTMutationListener*> Listeners;
@@ -180,121 +181,121 @@ void MultiplexASTMutationListener::DeclarationMarkedUsed(const Decl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->DeclarationMarkedUsed(D);
}
+void MultiplexASTMutationListener::DeclarationMarkedOpenMPThreadPrivate(
+ const Decl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D);
+}
} // end namespace clang
-MultiplexConsumer::MultiplexConsumer(ArrayRef<ASTConsumer *> C)
- : Consumers(C.begin(), C.end()), MutationListener(),
- DeserializationListener() {
+MultiplexConsumer::MultiplexConsumer(
+ std::vector<std::unique_ptr<ASTConsumer>> C)
+ : Consumers(std::move(C)), MutationListener(), DeserializationListener() {
// Collect the mutation listeners and deserialization listeners of all
// children, and create a multiplex listener each if so.
std::vector<ASTMutationListener*> mutationListeners;
std::vector<ASTDeserializationListener*> serializationListeners;
- for (size_t i = 0, e = Consumers.size(); i != e; ++i) {
- ASTMutationListener* mutationListener =
- Consumers[i]->GetASTMutationListener();
- if (mutationListener)
+ for (auto &Consumer : Consumers) {
+ if (auto *mutationListener = Consumer->GetASTMutationListener())
mutationListeners.push_back(mutationListener);
- ASTDeserializationListener* serializationListener =
- Consumers[i]->GetASTDeserializationListener();
- if (serializationListener)
+ if (auto *serializationListener = Consumer->GetASTDeserializationListener())
serializationListeners.push_back(serializationListener);
}
- if (mutationListeners.size()) {
- MutationListener.reset(new MultiplexASTMutationListener(mutationListeners));
+ if (!mutationListeners.empty()) {
+ MutationListener =
+ llvm::make_unique<MultiplexASTMutationListener>(mutationListeners);
}
- if (serializationListeners.size()) {
- DeserializationListener.reset(
- new MultiplexASTDeserializationListener(serializationListeners));
+ if (!serializationListeners.empty()) {
+ DeserializationListener =
+ llvm::make_unique<MultiplexASTDeserializationListener>(
+ serializationListeners);
}
}
-MultiplexConsumer::~MultiplexConsumer() {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- delete Consumers[i];
-}
+MultiplexConsumer::~MultiplexConsumer() {}
void MultiplexConsumer::Initialize(ASTContext &Context) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->Initialize(Context);
+ for (auto &Consumer : Consumers)
+ Consumer->Initialize(Context);
}
bool MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) {
bool Continue = true;
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Continue = Continue && Consumers[i]->HandleTopLevelDecl(D);
+ for (auto &Consumer : Consumers)
+ Continue = Continue && Consumer->HandleTopLevelDecl(D);
return Continue;
}
void MultiplexConsumer::HandleInlineMethodDefinition(CXXMethodDecl *D) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleInlineMethodDefinition(D);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleInlineMethodDefinition(D);
}
-void MultiplexConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleCXXStaticMemberVarInstantiation(VD);
+void MultiplexConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
+ for (auto &Consumer : Consumers)
+ Consumer->HandleCXXStaticMemberVarInstantiation(VD);
}
void MultiplexConsumer::HandleInterestingDecl(DeclGroupRef D) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleInterestingDecl(D);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleInterestingDecl(D);
}
void MultiplexConsumer::HandleTranslationUnit(ASTContext &Ctx) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleTranslationUnit(Ctx);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleTranslationUnit(Ctx);
}
void MultiplexConsumer::HandleTagDeclDefinition(TagDecl *D) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleTagDeclDefinition(D);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleTagDeclDefinition(D);
}
void MultiplexConsumer::HandleTagDeclRequiredDefinition(const TagDecl *D) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleTagDeclRequiredDefinition(D);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleTagDeclRequiredDefinition(D);
}
void MultiplexConsumer::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D){
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleCXXImplicitFunctionInstantiation(D);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleCXXImplicitFunctionInstantiation(D);
}
void MultiplexConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleTopLevelDeclInObjCContainer(D);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleTopLevelDeclInObjCContainer(D);
}
void MultiplexConsumer::HandleImplicitImportDecl(ImportDecl *D) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleImplicitImportDecl(D);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleImplicitImportDecl(D);
}
void MultiplexConsumer::HandleLinkerOptionPragma(llvm::StringRef Opts) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleLinkerOptionPragma(Opts);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleLinkerOptionPragma(Opts);
}
void MultiplexConsumer::HandleDetectMismatch(llvm::StringRef Name, llvm::StringRef Value) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleDetectMismatch(Name, Value);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleDetectMismatch(Name, Value);
}
void MultiplexConsumer::HandleDependentLibrary(llvm::StringRef Lib) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleDependentLibrary(Lib);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleDependentLibrary(Lib);
}
void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->CompleteTentativeDefinition(D);
+ for (auto &Consumer : Consumers)
+ Consumer->CompleteTentativeDefinition(D);
}
void MultiplexConsumer::HandleVTable(
CXXRecordDecl *RD, bool DefinitionRequired) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleVTable(RD, DefinitionRequired);
+ for (auto &Consumer : Consumers)
+ Consumer->HandleVTable(RD, DefinitionRequired);
}
ASTMutationListener *MultiplexConsumer::GetASTMutationListener() {
@@ -306,18 +307,18 @@ ASTDeserializationListener *MultiplexConsumer::GetASTDeserializationListener() {
}
void MultiplexConsumer::PrintStats() {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->PrintStats();
+ for (auto &Consumer : Consumers)
+ Consumer->PrintStats();
}
void MultiplexConsumer::InitializeSema(Sema &S) {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumers[i]))
+ for (auto &Consumer : Consumers)
+ if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumer.get()))
SC->InitializeSema(S);
}
void MultiplexConsumer::ForgetSema() {
- for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumers[i]))
+ for (auto &Consumer : Consumers)
+ if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumer.get()))
SC->ForgetSema();
}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 4a6f8dbef928..7c1d9a568831 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -332,7 +332,10 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc,
MoveToLine(HashLoc);
OS << "@import " << Imported->getFullModuleName() << ";"
<< " /* clang -E: implicit import for \"" << File->getName() << "\" */";
+ // Since we want a newline after the @import, but not a #<line>, start a new
+ // line immediately.
EmittedTokensOnThisLine = true;
+ startNewLineIfNeeded();
}
}
@@ -724,7 +727,7 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
PP.AddPragmaHandler("clang",
new UnknownPragmaHandler("#pragma clang", Callbacks));
- PP.addPPCallbacks(Callbacks);
+ PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
// After we have configured the preprocessor, enter the main file.
PP.EnterMainSourceFile();
diff --git a/lib/Frontend/Rewrite/FixItRewriter.cpp b/lib/Frontend/Rewrite/FixItRewriter.cpp
index 8b7af7166c8f..a3e14f9f020e 100644
--- a/lib/Frontend/Rewrite/FixItRewriter.cpp
+++ b/lib/Frontend/Rewrite/FixItRewriter.cpp
@@ -36,14 +36,13 @@ FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
FixItOpts(FixItOpts),
NumFailures(0),
PrevDiagSilenced(false) {
- OwnsClient = Diags.ownsClient();
- Client = Diags.takeClient();
- Diags.setClient(this);
+ Owner = Diags.takeClient();
+ Client = Diags.getClient();
+ Diags.setClient(this, false);
}
FixItRewriter::~FixItRewriter() {
- Diags.takeClient();
- Diags.setClient(Client, OwnsClient);
+ Diags.setClient(Client, Owner.release() != nullptr);
}
bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) {
@@ -86,17 +85,16 @@ bool FixItRewriter::WriteFixedFiles(
const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
int fd;
std::string Filename = FixItOpts->RewriteFilename(Entry->getName(), fd);
- std::string Err;
+ std::error_code EC;
std::unique_ptr<llvm::raw_fd_ostream> OS;
if (fd != -1) {
OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
} else {
- OS.reset(new llvm::raw_fd_ostream(Filename.c_str(), Err,
- llvm::sys::fs::F_None));
+ OS.reset(new llvm::raw_fd_ostream(Filename, EC, llvm::sys::fs::F_None));
}
- if (!Err.empty()) {
- Diags.Report(clang::diag::err_fe_unable_to_open_output)
- << Filename << Err;
+ if (EC) {
+ Diags.Report(clang::diag::err_fe_unable_to_open_output) << Filename
+ << EC.message();
continue;
}
RewriteBuffer &RewriteBuf = I->second;
@@ -189,12 +187,10 @@ void FixItRewriter::Diag(SourceLocation Loc, unsigned DiagID) {
// When producing this diagnostic, we temporarily bypass ourselves,
// clear out any current diagnostic, and let the downstream client
// format the diagnostic.
- Diags.takeClient();
- Diags.setClient(Client);
+ Diags.setClient(Client, false);
Diags.Clear();
Diags.Report(Loc, DiagID);
- Diags.takeClient();
- Diags.setClient(this);
+ Diags.setClient(this, false);
}
FixItOptions::~FixItOptions() {}
diff --git a/lib/Frontend/Rewrite/FrontendActions.cpp b/lib/Frontend/Rewrite/FrontendActions.cpp
index 59fef736f16a..1b5eb2855bea 100644
--- a/lib/Frontend/Rewrite/FrontendActions.cpp
+++ b/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -30,8 +30,8 @@ using namespace clang;
// AST Consumer Actions
//===----------------------------------------------------------------------===//
-ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
return CreateHTMLPrinter(OS, CI.getPreprocessor());
return nullptr;
@@ -40,9 +40,9 @@ ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI,
FixItAction::FixItAction() {}
FixItAction::~FixItAction() {}
-ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- return new ASTConsumer();
+std::unique_ptr<ASTConsumer>
+FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+ return llvm::make_unique<ASTConsumer>();
}
namespace {
@@ -148,8 +148,8 @@ bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
#ifdef CLANG_ENABLE_OBJC_REWRITER
-ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+std::unique_ptr<ASTConsumer>
+RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) {
if (CI.getLangOpts().ObjCRuntime.isNonFragile())
return CreateModernObjCRewriter(InFile, OS,
diff --git a/lib/Frontend/Rewrite/HTMLPrint.cpp b/lib/Frontend/Rewrite/HTMLPrint.cpp
index 64da05fdde61..22ccfe6936b7 100644
--- a/lib/Frontend/Rewrite/HTMLPrint.cpp
+++ b/lib/Frontend/Rewrite/HTMLPrint.cpp
@@ -47,11 +47,12 @@ namespace {
};
}
-ASTConsumer* clang::CreateHTMLPrinter(raw_ostream *OS,
- Preprocessor &PP,
- bool SyntaxHighlight,
- bool HighlightMacros) {
- return new HTMLPrinter(OS, PP, SyntaxHighlight, HighlightMacros);
+std::unique_ptr<ASTConsumer> clang::CreateHTMLPrinter(raw_ostream *OS,
+ Preprocessor &PP,
+ bool SyntaxHighlight,
+ bool HighlightMacros) {
+ return llvm::make_unique<HTMLPrinter>(OS, PP, SyntaxHighlight,
+ HighlightMacros);
}
void HTMLPrinter::Initialize(ASTContext &context) {
diff --git a/lib/Frontend/Rewrite/InclusionRewriter.cpp b/lib/Frontend/Rewrite/InclusionRewriter.cpp
index aa7017baee26..140055735a99 100644
--- a/lib/Frontend/Rewrite/InclusionRewriter.cpp
+++ b/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -40,6 +40,7 @@ class InclusionRewriter : public PPCallbacks {
Preprocessor &PP; ///< Used to find inclusion directives.
SourceManager &SM; ///< Used to read and manage source files.
raw_ostream &OS; ///< The destination stream for rewritten contents.
+ StringRef MainEOL; ///< The line ending marker to use.
const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines.
bool ShowLineMarkers; ///< Show #line markers.
bool UseLineDirective; ///< Use of line directives or line markers.
@@ -54,6 +55,7 @@ public:
void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) {
PredefinesBuffer = Buf;
}
+ void detectMainFileEOL();
private:
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
@@ -67,8 +69,8 @@ private:
const Module *Imported) override;
void WriteLineInfo(const char *Filename, int Line,
SrcMgr::CharacteristicKind FileType,
- StringRef EOL, StringRef Extra = StringRef());
- void WriteImplicitModuleImport(const Module *Mod, StringRef EOL);
+ StringRef Extra = StringRef());
+ void WriteImplicitModuleImport(const Module *Mod);
void OutputContentUpTo(const MemoryBuffer &FromFile,
unsigned &WriteFrom, unsigned WriteTo,
StringRef EOL, int &lines,
@@ -88,9 +90,9 @@ private:
/// Initializes an InclusionRewriter with a \p PP source and \p OS destination.
InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS,
bool ShowLineMarkers)
- : PP(PP), SM(PP.getSourceManager()), OS(OS), PredefinesBuffer(nullptr),
- ShowLineMarkers(ShowLineMarkers),
- LastInsertedFileChange(FileChanges.end()) {
+ : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL("\n"),
+ PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers),
+ LastInsertedFileChange(FileChanges.end()) {
// If we're in microsoft mode, use normal #line instead of line markers.
UseLineDirective = PP.getLangOpts().MicrosoftExt;
}
@@ -101,7 +103,7 @@ InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS,
/// any \p Extra context specifiers in GNU line directives.
void InclusionRewriter::WriteLineInfo(const char *Filename, int Line,
SrcMgr::CharacteristicKind FileType,
- StringRef EOL, StringRef Extra) {
+ StringRef Extra) {
if (!ShowLineMarkers)
return;
if (UseLineDirective) {
@@ -125,13 +127,12 @@ void InclusionRewriter::WriteLineInfo(const char *Filename, int Line,
// should be treated as being wrapped in an implicit extern "C" block."
OS << " 3 4";
}
- OS << EOL;
+ OS << MainEOL;
}
-void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod,
- StringRef EOL) {
+void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) {
OS << "@import " << Mod->getFullModuleName() << ";"
- << " /* clang -frewrite-includes: implicit import */" << EOL;
+ << " /* clang -frewrite-includes: implicit import */" << MainEOL;
}
/// FileChanged - Whenever the preprocessor enters or exits a #include file
@@ -197,23 +198,33 @@ InclusionRewriter::FindFileChangeLocation(SourceLocation Loc) const {
/// Detect the likely line ending style of \p FromFile by examining the first
/// newline found within it.
static StringRef DetectEOL(const MemoryBuffer &FromFile) {
- // detect what line endings the file uses, so that added content does not mix
- // the style
+ // Detect what line endings the file uses, so that added content does not mix
+ // the style. We need to check for "\r\n" first because "\n\r" will match
+ // "\r\n\r\n".
const char *Pos = strchr(FromFile.getBufferStart(), '\n');
if (!Pos)
return "\n";
- if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r')
- return "\n\r";
if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r')
return "\r\n";
+ if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r')
+ return "\n\r";
return "\n";
}
+void InclusionRewriter::detectMainFileEOL() {
+ bool Invalid;
+ const MemoryBuffer &FromFile = *SM.getBuffer(SM.getMainFileID(), &Invalid);
+ assert(!Invalid);
+ if (Invalid)
+ return; // Should never happen, but whatever.
+ MainEOL = DetectEOL(FromFile);
+}
+
/// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at
/// \p WriteTo - 1.
void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile,
unsigned &WriteFrom, unsigned WriteTo,
- StringRef EOL, int &Line,
+ StringRef LocalEOL, int &Line,
bool EnsureNewline) {
if (WriteTo <= WriteFrom)
return;
@@ -222,14 +233,37 @@ void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile,
WriteFrom = WriteTo;
return;
}
- OS.write(FromFile.getBufferStart() + WriteFrom, WriteTo - WriteFrom);
- // count lines manually, it's faster than getPresumedLoc()
- Line += std::count(FromFile.getBufferStart() + WriteFrom,
- FromFile.getBufferStart() + WriteTo, '\n');
- if (EnsureNewline) {
- char LastChar = FromFile.getBufferStart()[WriteTo - 1];
- if (LastChar != '\n' && LastChar != '\r')
- OS << EOL;
+
+ // If we would output half of a line ending, advance one character to output
+ // the whole line ending. All buffers are null terminated, so looking ahead
+ // one byte is safe.
+ if (LocalEOL.size() == 2 &&
+ LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] &&
+ LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0])
+ WriteTo++;
+
+ StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom,
+ WriteTo - WriteFrom);
+
+ if (MainEOL == LocalEOL) {
+ OS << TextToWrite;
+ // count lines manually, it's faster than getPresumedLoc()
+ Line += TextToWrite.count(LocalEOL);
+ if (EnsureNewline && !TextToWrite.endswith(LocalEOL))
+ OS << MainEOL;
+ } else {
+ // Output the file one line at a time, rewriting the line endings as we go.
+ StringRef Rest = TextToWrite;
+ while (!Rest.empty()) {
+ StringRef LineText;
+ std::tie(LineText, Rest) = Rest.split(LocalEOL);
+ OS << LineText;
+ Line++;
+ if (!Rest.empty())
+ OS << MainEOL;
+ }
+ if (TextToWrite.endswith(LocalEOL) || EnsureNewline)
+ OS << MainEOL;
}
WriteFrom = WriteTo;
}
@@ -242,10 +276,11 @@ void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile,
void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex,
const Token &StartToken,
const MemoryBuffer &FromFile,
- StringRef EOL,
+ StringRef LocalEOL,
unsigned &NextToWrite, int &Line) {
OutputContentUpTo(FromFile, NextToWrite,
- SM.getFileOffset(StartToken.getLocation()), EOL, Line, false);
+ SM.getFileOffset(StartToken.getLocation()), LocalEOL, Line,
+ false);
Token DirectiveToken;
do {
DirectiveLex.LexFromRawLexer(DirectiveToken);
@@ -254,11 +289,12 @@ void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex,
// OutputContentUpTo() would not output anything anyway.
return;
}
- OS << "#if 0 /* expanded by -frewrite-includes */" << EOL;
+ OS << "#if 0 /* expanded by -frewrite-includes */" << MainEOL;
OutputContentUpTo(FromFile, NextToWrite,
- SM.getFileOffset(DirectiveToken.getLocation()) + DirectiveToken.getLength(),
- EOL, Line, true);
- OS << "#endif /* expanded by -frewrite-includes */" << EOL;
+ SM.getFileOffset(DirectiveToken.getLocation()) +
+ DirectiveToken.getLength(),
+ LocalEOL, Line, true);
+ OS << "#endif /* expanded by -frewrite-includes */" << MainEOL;
}
/// Find the next identifier in the pragma directive specified by \p RawToken.
@@ -333,10 +369,13 @@ bool InclusionRewriter::HandleHasInclude(
// FIXME: Subframeworks aren't handled here. Do we care?
bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
const DirectoryLookup *CurDir;
+ const FileEntry *FileEnt = PP.getSourceManager().getFileEntryForID(FileId);
+ SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 1>
+ Includers;
+ Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
- Filename, SourceLocation(), isAngled, nullptr, CurDir,
- PP.getSourceManager().getFileEntryForID(FileId), nullptr, nullptr,
- nullptr, false);
+ Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr,
+ nullptr, nullptr, false);
FileExists = File != nullptr;
return true;
@@ -355,13 +394,13 @@ bool InclusionRewriter::Process(FileID FileId,
Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts());
RawLex.SetCommentRetentionState(false);
- StringRef EOL = DetectEOL(FromFile);
+ StringRef LocalEOL = DetectEOL(FromFile);
// Per the GNU docs: "1" indicates entering a new file.
if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID())
- WriteLineInfo(FileName, 1, FileType, EOL, "");
+ WriteLineInfo(FileName, 1, FileType, "");
else
- WriteLineInfo(FileName, 1, FileType, EOL, " 1");
+ WriteLineInfo(FileName, 1, FileType, " 1");
if (SM.getFileIDSize(FileId) == 0)
return false;
@@ -389,15 +428,15 @@ bool InclusionRewriter::Process(FileID FileId,
case tok::pp_include:
case tok::pp_include_next:
case tok::pp_import: {
- CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite,
+ CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, NextToWrite,
Line);
if (FileId != PP.getPredefinesFileID())
- WriteLineInfo(FileName, Line - 1, FileType, EOL, "");
+ WriteLineInfo(FileName, Line - 1, FileType, "");
StringRef LineInfoExtra;
if (const FileChange *Change = FindFileChangeLocation(
HashToken.getLocation())) {
if (Change->Mod) {
- WriteImplicitModuleImport(Change->Mod, EOL);
+ WriteImplicitModuleImport(Change->Mod);
// else now include and recursively process the file
} else if (Process(Change->Id, Change->FileType)) {
@@ -410,7 +449,7 @@ bool InclusionRewriter::Process(FileID FileId,
}
// fix up lineinfo (since commented out directive changed line
// numbers) for inclusions that were skipped due to header guards
- WriteLineInfo(FileName, Line, FileType, EOL, LineInfoExtra);
+ WriteLineInfo(FileName, Line, FileType, LineInfoExtra);
break;
}
case tok::pp_pragma: {
@@ -418,17 +457,17 @@ bool InclusionRewriter::Process(FileID FileId,
if (Identifier == "clang" || Identifier == "GCC") {
if (NextIdentifierName(RawLex, RawToken) == "system_header") {
// keep the directive in, commented out
- CommentOutDirective(RawLex, HashToken, FromFile, EOL,
+ CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
NextToWrite, Line);
// update our own type
FileType = SM.getFileCharacteristic(RawToken.getLocation());
- WriteLineInfo(FileName, Line, FileType, EOL);
+ WriteLineInfo(FileName, Line, FileType);
}
} else if (Identifier == "once") {
// keep the directive in, commented out
- CommentOutDirective(RawLex, HashToken, FromFile, EOL,
+ CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL,
NextToWrite, Line);
- WriteLineInfo(FileName, Line, FileType, EOL);
+ WriteLineInfo(FileName, Line, FileType);
}
break;
}
@@ -468,12 +507,12 @@ bool InclusionRewriter::Process(FileID FileId,
// Replace the macro with (0) or (1), followed by the commented
// out macro for reference.
OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc),
- EOL, Line, false);
+ LocalEOL, Line, false);
OS << '(' << (int) HasFile << ")/*";
OutputContentUpTo(FromFile, NextToWrite,
SM.getFileOffset(RawToken.getLocation()) +
- RawToken.getLength(),
- EOL, Line, false);
+ RawToken.getLength(),
+ LocalEOL, Line, false);
OS << "*/";
}
} while (RawToken.isNot(tok::eod));
@@ -481,8 +520,8 @@ bool InclusionRewriter::Process(FileID FileId,
OutputContentUpTo(FromFile, NextToWrite,
SM.getFileOffset(RawToken.getLocation()) +
RawToken.getLength(),
- EOL, Line, /*EnsureNewLine*/ true);
- WriteLineInfo(FileName, Line, FileType, EOL);
+ LocalEOL, Line, /*EnsureNewline=*/ true);
+ WriteLineInfo(FileName, Line, FileType);
}
break;
}
@@ -497,11 +536,11 @@ bool InclusionRewriter::Process(FileID FileId,
do {
RawLex.LexFromRawLexer(RawToken);
} while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof));
- OutputContentUpTo(
- FromFile, NextToWrite,
- SM.getFileOffset(RawToken.getLocation()) + RawToken.getLength(),
- EOL, Line, /*EnsureNewLine*/ true);
- WriteLineInfo(FileName, Line, FileType, EOL);
+ OutputContentUpTo(FromFile, NextToWrite,
+ SM.getFileOffset(RawToken.getLocation()) +
+ RawToken.getLength(),
+ LocalEOL, Line, /*EnsureNewline=*/ true);
+ WriteLineInfo(FileName, Line, FileType);
RawLex.SetKeepWhitespaceMode(false);
}
default:
@@ -513,8 +552,8 @@ bool InclusionRewriter::Process(FileID FileId,
RawLex.LexFromRawLexer(RawToken);
}
OutputContentUpTo(FromFile, NextToWrite,
- SM.getFileOffset(SM.getLocForEndOfFile(FileId)), EOL, Line,
- /*EnsureNewline*/true);
+ SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL,
+ Line, /*EnsureNewline=*/true);
return true;
}
@@ -524,7 +563,9 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
SourceManager &SM = PP.getSourceManager();
InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS,
Opts.ShowLineMarkers);
- PP.addPPCallbacks(Rewrite);
+ Rewrite->detectMainFileEOL();
+
+ PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Rewrite));
PP.IgnorePragmas();
// First let the preprocessor process the entire file and call callbacks.
diff --git a/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index 3e18a8b415a3..47f8189f2313 100644
--- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -249,27 +249,16 @@ namespace {
void HandleTranslationUnit(ASTContext &C) override;
void ReplaceStmt(Stmt *Old, Stmt *New) {
- Stmt *ReplacingStmt = ReplacedNodes[Old];
-
- if (ReplacingStmt)
- return; // We can't rewrite the same node twice.
-
- if (DisableReplaceStmt)
- return;
-
- // If replacement succeeded or warning disabled return with no warning.
- if (!Rewrite.ReplaceStmt(Old, New)) {
- ReplacedNodes[Old] = New;
- return;
- }
- if (SilenceRewriteMacroWarning)
- return;
- Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag)
- << Old->getSourceRange();
+ ReplaceStmtWithRange(Old, New, Old->getSourceRange());
}
void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) {
assert(Old != nullptr && New != nullptr && "Expected non-null Stmt's");
+
+ Stmt *ReplacingStmt = ReplacedNodes[Old];
+ if (ReplacingStmt)
+ return; // We can't rewrite the same node twice.
+
if (DisableReplaceStmt)
return;
@@ -508,7 +497,7 @@ namespace {
void GetBlockDeclRefExprs(Stmt *S);
void GetInnerBlockDeclRefExprs(Stmt *S,
SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs,
- llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts);
+ llvm::SmallPtrSetImpl<const DeclContext *> &InnerContexts);
// We avoid calling Type::isBlockPointerType(), since it operates on the
// canonical type. We only care if the top-level type is a closure pointer.
@@ -675,14 +664,11 @@ RewriteModernObjC::RewriteModernObjC(std::string inFile, raw_ostream* OS,
"for @try/@finally (code may not execute properly)");
}
-ASTConsumer *clang::CreateModernObjCRewriter(const std::string& InFile,
- raw_ostream* OS,
- DiagnosticsEngine &Diags,
- const LangOptions &LOpts,
- bool SilenceRewriteMacroWarning,
- bool LineInfo) {
- return new RewriteModernObjC(InFile, OS, Diags, LOpts,
- SilenceRewriteMacroWarning, LineInfo);
+std::unique_ptr<ASTConsumer> clang::CreateModernObjCRewriter(
+ const std::string &InFile, raw_ostream *OS, DiagnosticsEngine &Diags,
+ const LangOptions &LOpts, bool SilenceRewriteMacroWarning, bool LineInfo) {
+ return llvm::make_unique<RewriteModernObjC>(
+ InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning, LineInfo);
}
void RewriteModernObjC::InitializeCommon(ASTContext &context) {
@@ -4055,7 +4041,7 @@ void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
ReplaceText(LocStart, endBuf-startBuf, Result);
// Mark this struct as having been generated.
- if (!ObjCSynthesizedStructs.insert(CDecl))
+ if (!ObjCSynthesizedStructs.insert(CDecl).second)
llvm_unreachable("struct already synthesize- RewriteObjCInternalStruct");
}
@@ -4070,9 +4056,7 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
return;
llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput;
- for (llvm::SmallPtrSet<ObjCIvarDecl *, 8>::iterator i = Ivars.begin(),
- e = Ivars.end(); i != e; i++) {
- ObjCIvarDecl *IvarDecl = (*i);
+ for (ObjCIvarDecl *IvarDecl : Ivars) {
const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface();
unsigned GroupNo = 0;
if (IvarDecl->isBitField()) {
@@ -4256,14 +4240,12 @@ std::string RewriteModernObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += "(" + StructRef;
S += "*dst, " + StructRef;
S += "*src) {";
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
- E = ImportedBlockDecls.end(); I != E; ++I) {
- ValueDecl *VD = (*I);
+ for (ValueDecl *VD : ImportedBlockDecls) {
S += "_Block_object_assign((void*)&dst->";
- S += (*I)->getNameAsString();
+ S += VD->getNameAsString();
S += ", (void*)src->";
- S += (*I)->getNameAsString();
- if (BlockByRefDeclsPtrSet.count((*I)))
+ S += VD->getNameAsString();
+ if (BlockByRefDeclsPtrSet.count(VD))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
else if (VD->getType()->isBlockPointerType())
S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
@@ -4277,12 +4259,10 @@ std::string RewriteModernObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += "_block_dispose_" + utostr(i);
S += "(" + StructRef;
S += "*src) {";
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
- E = ImportedBlockDecls.end(); I != E; ++I) {
- ValueDecl *VD = (*I);
+ for (ValueDecl *VD : ImportedBlockDecls) {
S += "_Block_object_dispose((void*)src->";
- S += (*I)->getNameAsString();
- if (BlockByRefDeclsPtrSet.count((*I)))
+ S += VD->getNameAsString();
+ if (BlockByRefDeclsPtrSet.count(VD))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
else if (VD->getType()->isBlockPointerType())
S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
@@ -4583,22 +4563,18 @@ void RewriteModernObjC::GetBlockDeclRefExprs(Stmt *S) {
GetBlockDeclRefExprs(*CI);
}
// Handle specific things.
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
- if (DRE->refersToEnclosingLocal()) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S))
+ if (DRE->refersToEnclosingVariableOrCapture() ||
+ HasLocalVariableExternalStorage(DRE->getDecl()))
// FIXME: Handle enums.
- if (!isa<FunctionDecl>(DRE->getDecl()))
- BlockDeclRefs.push_back(DRE);
- if (HasLocalVariableExternalStorage(DRE->getDecl()))
- BlockDeclRefs.push_back(DRE);
- }
- }
-
+ BlockDeclRefs.push_back(DRE);
+
return;
}
void RewriteModernObjC::GetInnerBlockDeclRefExprs(Stmt *S,
SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs,
- llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) {
+ llvm::SmallPtrSetImpl<const DeclContext *> &InnerContexts) {
for (Stmt::child_range CI = S->children(); CI; ++CI)
if (*CI) {
if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
@@ -4615,11 +4591,11 @@ void RewriteModernObjC::GetInnerBlockDeclRefExprs(Stmt *S,
}
// Handle specific things.
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
- if (DRE->refersToEnclosingLocal()) {
- if (!isa<FunctionDecl>(DRE->getDecl()) &&
- !InnerContexts.count(DRE->getDecl()->getDeclContext()))
+ if (DRE->refersToEnclosingVariableOrCapture() ||
+ HasLocalVariableExternalStorage(DRE->getDecl())) {
+ if (!InnerContexts.count(DRE->getDecl()->getDeclContext()))
InnerBlockDeclRefs.push_back(DRE);
- if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (VarDecl *Var = cast<VarDecl>(DRE->getDecl()))
if (Var->isFunctionOrMethodVarDecl())
ImportedLocalExternalDecls.insert(Var);
}
@@ -4796,7 +4772,8 @@ Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
// Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR
// for each DeclRefExp where BYREFVAR is name of the variable.
ValueDecl *VD = DeclRefExp->getDecl();
- bool isArrow = DeclRefExp->refersToEnclosingLocal();
+ bool isArrow = DeclRefExp->refersToEnclosingVariableOrCapture() ||
+ HasLocalVariableExternalStorage(DeclRefExp->getDecl());
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
@@ -5546,6 +5523,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
VK_RValue, OK_Ordinary, SourceLocation());
NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
NewRep);
+ // Put Paren around the call.
+ NewRep = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
+ NewRep);
+
BlockDeclRefs.clear();
BlockByRefDecls.clear();
BlockByRefDeclsPtrSet.clear();
@@ -5978,10 +5959,9 @@ void RewriteModernObjC::HandleTranslationUnit(ASTContext &C) {
// Here's a great place to add any extra declarations that may be needed.
// Write out meta data for each @protocol(<expr>).
- for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
- E = ProtocolExprDecls.end(); I != E; ++I) {
- RewriteObjCProtocolMetaData(*I, Preamble);
- Write_ProtocolExprReferencedMetadata(Context, (*I), Preamble);
+ for (ObjCProtocolDecl *ProtDecl : ProtocolExprDecls) {
+ RewriteObjCProtocolMetaData(ProtDecl, Preamble);
+ Write_ProtocolExprReferencedMetadata(Context, ProtDecl, Preamble);
}
InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false);
@@ -7122,7 +7102,7 @@ void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl,
Result += ";\n";
// Mark this protocol as having been generated.
- if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl()))
+ if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl()).second)
llvm_unreachable("protocol already synthesized");
}
diff --git a/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp
index 7a721771759a..519681085f56 100644
--- a/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -198,27 +198,16 @@ namespace {
void HandleTranslationUnit(ASTContext &C) override;
void ReplaceStmt(Stmt *Old, Stmt *New) {
- Stmt *ReplacingStmt = ReplacedNodes[Old];
-
- if (ReplacingStmt)
- return; // We can't rewrite the same node twice.
-
- if (DisableReplaceStmt)
- return;
-
- // If replacement succeeded or warning disabled return with no warning.
- if (!Rewrite.ReplaceStmt(Old, New)) {
- ReplacedNodes[Old] = New;
- return;
- }
- if (SilenceRewriteMacroWarning)
- return;
- Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag)
- << Old->getSourceRange();
+ ReplaceStmtWithRange(Old, New, Old->getSourceRange());
}
void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) {
assert(Old != nullptr && New != nullptr && "Expected non-null Stmt's");
+
+ Stmt *ReplacingStmt = ReplacedNodes[Old];
+ if (ReplacingStmt)
+ return; // We can't rewrite the same node twice.
+
if (DisableReplaceStmt)
return;
@@ -332,7 +321,7 @@ namespace {
void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
std::string &Result);
- virtual void Initialize(ASTContext &context) override = 0;
+ void Initialize(ASTContext &context) override = 0;
// Metadata Rewriting.
virtual void RewriteMetaDataIntoBuffer(std::string &Result) = 0;
@@ -413,7 +402,7 @@ namespace {
void GetBlockDeclRefExprs(Stmt *S);
void GetInnerBlockDeclRefExprs(Stmt *S,
SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs,
- llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts);
+ llvm::SmallPtrSetImpl<const DeclContext *> &InnerContexts);
// We avoid calling Type::isBlockPointerType(), since it operates on the
// canonical type. We only care if the top-level type is a closure pointer.
@@ -524,7 +513,7 @@ namespace {
silenceMacroWarn) {}
~RewriteObjCFragileABI() {}
- virtual void Initialize(ASTContext &context) override;
+ void Initialize(ASTContext &context) override;
// Rewriting metadata
template<typename MethodIterator>
@@ -600,12 +589,12 @@ RewriteObjC::RewriteObjC(std::string inFile, raw_ostream* OS,
"for @try/@finally (code may not execute properly)");
}
-ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile,
- raw_ostream* OS,
- DiagnosticsEngine &Diags,
- const LangOptions &LOpts,
- bool SilenceRewriteMacroWarning) {
- return new RewriteObjCFragileABI(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
+std::unique_ptr<ASTConsumer>
+clang::CreateObjCRewriter(const std::string &InFile, raw_ostream *OS,
+ DiagnosticsEngine &Diags, const LangOptions &LOpts,
+ bool SilenceRewriteMacroWarning) {
+ return llvm::make_unique<RewriteObjCFragileABI>(InFile, OS, Diags, LOpts,
+ SilenceRewriteMacroWarning);
}
void RewriteObjC::InitializeCommon(ASTContext &context) {
@@ -3238,7 +3227,7 @@ void RewriteObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
ReplaceText(LocStart, endBuf-startBuf, Result);
}
// Mark this struct as having been generated.
- if (!ObjCSynthesizedStructs.insert(CDecl))
+ if (!ObjCSynthesizedStructs.insert(CDecl).second)
llvm_unreachable("struct already synthesize- SynthesizeObjCInternalStruct");
}
@@ -3382,14 +3371,12 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += "(" + StructRef;
S += "*dst, " + StructRef;
S += "*src) {";
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
- E = ImportedBlockDecls.end(); I != E; ++I) {
- ValueDecl *VD = (*I);
+ for (ValueDecl *VD : ImportedBlockDecls) {
S += "_Block_object_assign((void*)&dst->";
- S += (*I)->getNameAsString();
+ S += VD->getNameAsString();
S += ", (void*)src->";
- S += (*I)->getNameAsString();
- if (BlockByRefDeclsPtrSet.count((*I)))
+ S += VD->getNameAsString();
+ if (BlockByRefDeclsPtrSet.count(VD))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
else if (VD->getType()->isBlockPointerType())
S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
@@ -3403,12 +3390,10 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += "_block_dispose_" + utostr(i);
S += "(" + StructRef;
S += "*src) {";
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
- E = ImportedBlockDecls.end(); I != E; ++I) {
- ValueDecl *VD = (*I);
+ for (ValueDecl *VD : ImportedBlockDecls) {
S += "_Block_object_dispose((void*)src->";
- S += (*I)->getNameAsString();
- if (BlockByRefDeclsPtrSet.count((*I)))
+ S += VD->getNameAsString();
+ if (BlockByRefDeclsPtrSet.count(VD))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
else if (VD->getType()->isBlockPointerType())
S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
@@ -3686,22 +3671,18 @@ void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) {
GetBlockDeclRefExprs(*CI);
}
// Handle specific things.
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
- if (DRE->refersToEnclosingLocal()) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S))
+ if (DRE->refersToEnclosingVariableOrCapture() ||
+ HasLocalVariableExternalStorage(DRE->getDecl()))
// FIXME: Handle enums.
- if (!isa<FunctionDecl>(DRE->getDecl()))
- BlockDeclRefs.push_back(DRE);
- if (HasLocalVariableExternalStorage(DRE->getDecl()))
- BlockDeclRefs.push_back(DRE);
- }
- }
-
+ BlockDeclRefs.push_back(DRE);
+
return;
}
void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs,
- llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) {
+ llvm::SmallPtrSetImpl<const DeclContext *> &InnerContexts) {
for (Stmt::child_range CI = S->children(); CI; ++CI)
if (*CI) {
if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
@@ -3718,11 +3699,11 @@ void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
}
// Handle specific things.
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
- if (DRE->refersToEnclosingLocal()) {
- if (!isa<FunctionDecl>(DRE->getDecl()) &&
- !InnerContexts.count(DRE->getDecl()->getDeclContext()))
+ if (DRE->refersToEnclosingVariableOrCapture() ||
+ HasLocalVariableExternalStorage(DRE->getDecl())) {
+ if (!InnerContexts.count(DRE->getDecl()->getDeclContext()))
InnerBlockDeclRefs.push_back(DRE);
- if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (VarDecl *Var = cast<VarDecl>(DRE->getDecl()))
if (Var->isFunctionOrMethodVarDecl())
ImportedLocalExternalDecls.insert(Var);
}
@@ -3880,7 +3861,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
// Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR
// for each DeclRefExp where BYREFVAR is name of the variable.
ValueDecl *VD = DeclRefExp->getDecl();
- bool isArrow = DeclRefExp->refersToEnclosingLocal();
+ bool isArrow = DeclRefExp->refersToEnclosingVariableOrCapture() ||
+ HasLocalVariableExternalStorage(DeclRefExp->getDecl());
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
@@ -4967,9 +4949,8 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
// Here's a great place to add any extra declarations that may be needed.
// Write out meta data for each @protocol(<expr>).
- for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
- E = ProtocolExprDecls.end(); I != E; ++I)
- RewriteObjCProtocolMetaData(*I, "", "", Preamble);
+ for (ObjCProtocolDecl *ProtDecl : ProtocolExprDecls)
+ RewriteObjCProtocolMetaData(ProtDecl, "", "", Preamble);
InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false);
if (ClassImplementation.size() || CategoryImplementation.size())
@@ -5276,7 +5257,7 @@ void RewriteObjCFragileABI::RewriteObjCProtocolMetaData(
Result += "};\n";
// Mark this protocol as having been generated.
- if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl()))
+ if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl()).second)
llvm_unreachable("protocol already synthesized");
}
@@ -5657,12 +5638,11 @@ void RewriteObjCFragileABI::RewriteMetaDataIntoBuffer(std::string &Result) {
if (ProtocolExprDecls.size()) {
Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n";
Result += "#pragma data_seg(push, \".objc_protocol$B\")\n";
- for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
- E = ProtocolExprDecls.end(); I != E; ++I) {
+ for (ObjCProtocolDecl *ProtDecl : ProtocolExprDecls) {
Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_";
- Result += (*I)->getNameAsString();
+ Result += ProtDecl->getNameAsString();
Result += " = &_OBJC_PROTOCOL_";
- Result += (*I)->getNameAsString();
+ Result += ProtDecl->getNameAsString();
Result += ";\n";
}
Result += "#pragma data_seg(pop)\n\n";
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 29c58a8ac34e..f701f723a320 100644
--- a/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -14,6 +14,10 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/SerializedDiagnosticReader.h"
+#include "clang/Frontend/SerializedDiagnostics.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
@@ -86,20 +90,70 @@ protected:
void endDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) override;
};
-
+
+typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
+
+class SDiagsMerger : SerializedDiagnosticReader {
+ SDiagsWriter &Writer;
+ AbbrevLookup FileLookup;
+ AbbrevLookup CategoryLookup;
+ AbbrevLookup DiagFlagLookup;
+
+public:
+ SDiagsMerger(SDiagsWriter &Writer)
+ : SerializedDiagnosticReader(), Writer(Writer) {}
+
+ std::error_code mergeRecordsFromFile(const char *File) {
+ return readDiagnostics(File);
+ }
+
+protected:
+ std::error_code visitStartOfDiagnostic() override;
+ std::error_code visitEndOfDiagnostic() override;
+ std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override;
+ std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override;
+ std::error_code visitDiagnosticRecord(
+ unsigned Severity, const serialized_diags::Location &Location,
+ unsigned Category, unsigned Flag, StringRef Message) override;
+ std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
+ unsigned Timestamp,
+ StringRef Name) override;
+ std::error_code visitFixitRecord(const serialized_diags::Location &Start,
+ const serialized_diags::Location &End,
+ StringRef CodeToInsert) override;
+ std::error_code
+ visitSourceRangeRecord(const serialized_diags::Location &Start,
+ const serialized_diags::Location &End) override;
+
+private:
+ std::error_code adjustSourceLocFilename(RecordData &Record,
+ unsigned int offset);
+
+ void adjustAbbrevID(RecordData &Record, AbbrevLookup &Lookup,
+ unsigned NewAbbrev);
+
+ void writeRecordWithAbbrev(unsigned ID, RecordData &Record);
+
+ void writeRecordWithBlob(unsigned ID, RecordData &Record, StringRef Blob);
+};
+
class SDiagsWriter : public DiagnosticConsumer {
friend class SDiagsRenderer;
+ friend class SDiagsMerger;
struct SharedState;
explicit SDiagsWriter(IntrusiveRefCntPtr<SharedState> State)
- : LangOpts(nullptr), OriginalInstance(false), State(State) {}
+ : LangOpts(nullptr), OriginalInstance(false), MergeChildRecords(false),
+ State(State) {}
public:
- SDiagsWriter(raw_ostream *os, DiagnosticOptions *diags)
- : LangOpts(nullptr), OriginalInstance(true),
- State(new SharedState(os, diags))
- {
+ SDiagsWriter(StringRef File, DiagnosticOptions *Diags, bool MergeChildRecords)
+ : LangOpts(nullptr), OriginalInstance(true),
+ MergeChildRecords(MergeChildRecords),
+ State(new SharedState(File, Diags)) {
+ if (MergeChildRecords)
+ RemoveOldDiagnostics();
EmitPreamble();
}
@@ -115,6 +169,14 @@ public:
void finish() override;
private:
+ /// \brief Build a DiagnosticsEngine to emit diagnostics about the diagnostics
+ DiagnosticsEngine *getMetaDiags();
+
+ /// \brief Remove old copies of the serialized diagnostics. This is necessary
+ /// so that we can detect when subprocesses write diagnostics that we should
+ /// merge into our own.
+ void RemoveOldDiagnostics();
+
/// \brief Emit the preamble for the serialized diagnostics.
void EmitPreamble();
@@ -152,7 +214,9 @@ private:
/// \brief Emit the string information for diagnostic flags.
unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
unsigned DiagID = 0);
-
+
+ unsigned getEmitDiagnosticFlag(StringRef DiagName);
+
/// \brief Emit (lazily) the file string and retrieved the file identifier.
unsigned getEmitFile(const char *Filename);
@@ -173,9 +237,6 @@ private:
void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
const SourceManager &SM);
- /// \brief The version of the diagnostics file.
- enum { Version = 2 };
-
/// \brief Language options, which can differ from one clone of this client
/// to another.
const LangOptions *LangOpts;
@@ -184,11 +245,16 @@ private:
/// clones), responsible for writing the file at the end.
bool OriginalInstance;
+ /// \brief Whether this instance should aggregate diagnostics that are
+ /// generated from child processes.
+ bool MergeChildRecords;
+
/// \brief State that is shared among the various clones of this diagnostic
/// consumer.
struct SharedState : RefCountedBase<SharedState> {
- SharedState(raw_ostream *os, DiagnosticOptions *diags)
- : DiagOpts(diags), Stream(Buffer), OS(os), EmittedAnyDiagBlocks(false) { }
+ SharedState(StringRef File, DiagnosticOptions *Diags)
+ : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()),
+ EmittedAnyDiagBlocks(false) {}
/// \brief Diagnostic options.
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
@@ -200,7 +266,7 @@ private:
llvm::BitstreamWriter Stream;
/// \brief The name of the diagnostics file.
- std::unique_ptr<raw_ostream> OS;
+ std::string OutputFile;
/// \brief The set of constructed record abbreviations.
AbbreviationMap Abbrevs;
@@ -227,6 +293,9 @@ private:
/// this becomes \c true, we never close a DIAG block until we know that we're
/// starting another one or we're done.
bool EmittedAnyDiagBlocks;
+
+ /// \brief Engine for emitting diagnostics about the diagnostics.
+ std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
};
/// \brief State shared among the various clones of this diagnostic consumer.
@@ -236,9 +305,11 @@ private:
namespace clang {
namespace serialized_diags {
-DiagnosticConsumer *create(raw_ostream *OS, DiagnosticOptions *diags) {
- return new SDiagsWriter(OS, diags);
+std::unique_ptr<DiagnosticConsumer>
+create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords) {
+ return llvm::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
}
+
} // end namespace serialized_diags
} // end namespace clang
@@ -465,17 +536,15 @@ void SDiagsWriter::EmitMetaBlock() {
Stream.EnterSubblock(BLOCK_META, 3);
Record.clear();
Record.push_back(RECORD_VERSION);
- Record.push_back(Version);
+ Record.push_back(VersionNumber);
Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
Stream.ExitBlock();
}
unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
- if (State->Categories.count(category))
+ if (!State->Categories.insert(category).second)
return category;
-
- State->Categories.insert(category);
-
+
// We use a local version of 'Record' so that we can be generating
// another record when we lazily generate one for the category entry.
RecordData Record;
@@ -495,6 +564,10 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
return 0; // No flag for notes.
StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
+ return getEmitDiagnosticFlag(FlagName);
+}
+
+unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
if (FlagName.empty())
return 0;
@@ -689,6 +762,40 @@ void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
Writer.ExitDiagBlock();
}
+DiagnosticsEngine *SDiagsWriter::getMetaDiags() {
+ // FIXME: It's slightly absurd to create a new diagnostics engine here, but
+ // the other options that are available today are worse:
+ //
+ // 1. Teach DiagnosticsConsumers to emit diagnostics to the engine they are a
+ // part of. The DiagnosticsEngine would need to know not to send
+ // diagnostics back to the consumer that failed. This would require us to
+ // rework ChainedDiagnosticsConsumer and teach the engine about multiple
+ // consumers, which is difficult today because most APIs interface with
+ // consumers rather than the engine itself.
+ //
+ // 2. Pass a DiagnosticsEngine to SDiagsWriter on creation - this would need
+ // to be distinct from the engine the writer was being added to and would
+ // normally not be used.
+ if (!State->MetaDiagnostics) {
+ IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs());
+ auto Client =
+ new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts.get());
+ State->MetaDiagnostics = llvm::make_unique<DiagnosticsEngine>(
+ IDs, State->DiagOpts.get(), Client);
+ }
+ return State->MetaDiagnostics.get();
+}
+
+void SDiagsWriter::RemoveOldDiagnostics() {
+ if (!llvm::sys::fs::remove(State->OutputFile))
+ return;
+
+ getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
+ // Disable merging child records, as whatever is in this file may be
+ // misleading.
+ MergeChildRecords = false;
+}
+
void SDiagsWriter::finish() {
// The original instance is responsible for writing the file.
if (!OriginalInstance)
@@ -698,9 +805,113 @@ void SDiagsWriter::finish() {
if (State->EmittedAnyDiagBlocks)
ExitDiagBlock();
+ if (MergeChildRecords) {
+ if (!State->EmittedAnyDiagBlocks)
+ // We have no diagnostics of our own, so we can just leave the child
+ // process' output alone
+ return;
+
+ if (llvm::sys::fs::exists(State->OutputFile))
+ if (SDiagsMerger(*this).mergeRecordsFromFile(State->OutputFile.c_str()))
+ getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
+ }
+
+ std::error_code EC;
+ auto OS = llvm::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(),
+ EC, llvm::sys::fs::F_None);
+ if (EC) {
+ getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
+ << State->OutputFile << EC.message();
+ return;
+ }
+
// Write the generated bitstream to "Out".
- State->OS->write((char *)&State->Buffer.front(), State->Buffer.size());
- State->OS->flush();
+ OS->write((char *)&State->Buffer.front(), State->Buffer.size());
+ OS->flush();
+}
+
+std::error_code SDiagsMerger::visitStartOfDiagnostic() {
+ Writer.EnterDiagBlock();
+ return std::error_code();
+}
+
+std::error_code SDiagsMerger::visitEndOfDiagnostic() {
+ Writer.ExitDiagBlock();
+ return std::error_code();
+}
+
+std::error_code
+SDiagsMerger::visitSourceRangeRecord(const serialized_diags::Location &Start,
+ const serialized_diags::Location &End) {
+ RecordData Record;
+ Record.push_back(RECORD_SOURCE_RANGE);
+ Record.push_back(FileLookup[Start.FileID]);
+ Record.push_back(Start.Line);
+ Record.push_back(Start.Col);
+ Record.push_back(Start.Offset);
+ Record.push_back(FileLookup[End.FileID]);
+ Record.push_back(End.Line);
+ Record.push_back(End.Col);
+ Record.push_back(End.Offset);
+
+ Writer.State->Stream.EmitRecordWithAbbrev(
+ Writer.State->Abbrevs.get(RECORD_SOURCE_RANGE), Record);
+ return std::error_code();
+}
+
+std::error_code SDiagsMerger::visitDiagnosticRecord(
+ unsigned Severity, const serialized_diags::Location &Location,
+ unsigned Category, unsigned Flag, StringRef Message) {
+ RecordData MergedRecord;
+ MergedRecord.push_back(RECORD_DIAG);
+ MergedRecord.push_back(Severity);
+ MergedRecord.push_back(FileLookup[Location.FileID]);
+ MergedRecord.push_back(Location.Line);
+ MergedRecord.push_back(Location.Col);
+ MergedRecord.push_back(Location.Offset);
+ MergedRecord.push_back(CategoryLookup[Category]);
+ MergedRecord.push_back(Flag ? DiagFlagLookup[Flag] : 0);
+ MergedRecord.push_back(Message.size());
+
+ Writer.State->Stream.EmitRecordWithBlob(
+ Writer.State->Abbrevs.get(RECORD_DIAG), MergedRecord, Message);
+ return std::error_code();
+}
+
+std::error_code
+SDiagsMerger::visitFixitRecord(const serialized_diags::Location &Start,
+ const serialized_diags::Location &End,
+ StringRef Text) {
+ RecordData Record;
+ Record.push_back(RECORD_FIXIT);
+ Record.push_back(FileLookup[Start.FileID]);
+ Record.push_back(Start.Line);
+ Record.push_back(Start.Col);
+ Record.push_back(Start.Offset);
+ Record.push_back(FileLookup[End.FileID]);
+ Record.push_back(End.Line);
+ Record.push_back(End.Col);
+ Record.push_back(End.Offset);
+ Record.push_back(Text.size());
+
+ Writer.State->Stream.EmitRecordWithBlob(
+ Writer.State->Abbrevs.get(RECORD_FIXIT), Record, Text);
+ return std::error_code();
+}
+
+std::error_code SDiagsMerger::visitFilenameRecord(unsigned ID, unsigned Size,
+ unsigned Timestamp,
+ StringRef Name) {
+ FileLookup[ID] = Writer.getEmitFile(Name.str().c_str());
+ return std::error_code();
+}
+
+std::error_code SDiagsMerger::visitCategoryRecord(unsigned ID, StringRef Name) {
+ CategoryLookup[ID] = Writer.getEmitCategory(ID);
+ return std::error_code();
+}
- State->OS.reset();
+std::error_code SDiagsMerger::visitDiagFlagRecord(unsigned ID, StringRef Name) {
+ DiagFlagLookup[ID] = Writer.getEmitDiagnosticFlag(Name);
+ return std::error_code();
}
diff --git a/lib/Frontend/SerializedDiagnosticReader.cpp b/lib/Frontend/SerializedDiagnosticReader.cpp
new file mode 100644
index 000000000000..0ebbd22af274
--- /dev/null
+++ b/lib/Frontend/SerializedDiagnosticReader.cpp
@@ -0,0 +1,295 @@
+//===--- SerializedDiagnosticReader.cpp - Reads diagnostics ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/SerializedDiagnosticReader.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/SerializedDiagnostics.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace clang;
+using namespace clang::serialized_diags;
+
+std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
+ // Open the diagnostics file.
+ FileSystemOptions FO;
+ FileManager FileMgr(FO);
+
+ auto Buffer = FileMgr.getBufferForFile(File);
+ if (!Buffer)
+ return SDError::CouldNotLoad;
+
+ llvm::BitstreamReader StreamFile;
+ StreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(),
+ (const unsigned char *)(*Buffer)->getBufferEnd());
+
+ llvm::BitstreamCursor Stream(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'D' ||
+ Stream.Read(8) != 'I' ||
+ Stream.Read(8) != 'A' ||
+ Stream.Read(8) != 'G')
+ return SDError::InvalidSignature;
+
+ // Read the top level blocks.
+ while (!Stream.AtEndOfStream()) {
+ if (Stream.ReadCode() != llvm::bitc::ENTER_SUBBLOCK)
+ return SDError::InvalidDiagnostics;
+
+ std::error_code EC;
+ switch (Stream.ReadSubBlockID()) {
+ case llvm::bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock())
+ return SDError::MalformedBlockInfoBlock;
+ continue;
+ case BLOCK_META:
+ if ((EC = readMetaBlock(Stream)))
+ return EC;
+ continue;
+ case BLOCK_DIAG:
+ if ((EC = readDiagnosticBlock(Stream)))
+ return EC;
+ continue;
+ default:
+ if (!Stream.SkipBlock())
+ return SDError::MalformedTopLevelBlock;
+ continue;
+ }
+ }
+ return std::error_code();
+}
+
+enum class SerializedDiagnosticReader::Cursor {
+ Record = 1,
+ BlockEnd,
+ BlockBegin
+};
+
+llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
+SerializedDiagnosticReader::skipUntilRecordOrBlock(
+ llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
+ BlockOrRecordID = 0;
+
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ switch ((llvm::bitc::FixedAbbrevIDs)Code) {
+ case llvm::bitc::ENTER_SUBBLOCK:
+ BlockOrRecordID = Stream.ReadSubBlockID();
+ return Cursor::BlockBegin;
+
+ case llvm::bitc::END_BLOCK:
+ if (Stream.ReadBlockEnd())
+ return SDError::InvalidDiagnostics;
+ return Cursor::BlockEnd;
+
+ case llvm::bitc::DEFINE_ABBREV:
+ Stream.ReadAbbrevRecord();
+ continue;
+
+ case llvm::bitc::UNABBREV_RECORD:
+ return SDError::UnsupportedConstruct;
+
+ default:
+ // We found a record.
+ BlockOrRecordID = Code;
+ return Cursor::Record;
+ }
+ }
+
+ return SDError::InvalidDiagnostics;
+}
+
+std::error_code
+SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
+ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META))
+ return SDError::MalformedMetadataBlock;
+
+ bool VersionChecked = false;
+
+ while (true) {
+ unsigned BlockOrCode = 0;
+ llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
+ if (!Res)
+ Res.getError();
+
+ switch (Res.get()) {
+ case Cursor::Record:
+ break;
+ case Cursor::BlockBegin:
+ if (Stream.SkipBlock())
+ return SDError::MalformedMetadataBlock;
+ case Cursor::BlockEnd:
+ if (!VersionChecked)
+ return SDError::MissingVersion;
+ return std::error_code();
+ }
+
+ SmallVector<uint64_t, 1> Record;
+ unsigned RecordID = Stream.readRecord(BlockOrCode, Record);
+
+ if (RecordID == RECORD_VERSION) {
+ if (Record.size() < 1)
+ return SDError::MissingVersion;
+ if (Record[0] > VersionNumber)
+ return SDError::VersionMismatch;
+ VersionChecked = true;
+ }
+ }
+}
+
+std::error_code
+SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
+ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG))
+ return SDError::MalformedDiagnosticBlock;
+
+ std::error_code EC;
+ if ((EC = visitStartOfDiagnostic()))
+ return EC;
+
+ SmallVector<uint64_t, 16> Record;
+ while (true) {
+ unsigned BlockOrCode = 0;
+ llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
+ if (!Res)
+ Res.getError();
+
+ switch (Res.get()) {
+ case Cursor::BlockBegin:
+ // The only blocks we care about are subdiagnostics.
+ if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
+ if ((EC = readDiagnosticBlock(Stream)))
+ return EC;
+ } else if (!Stream.SkipBlock())
+ return SDError::MalformedSubBlock;
+ continue;
+ case Cursor::BlockEnd:
+ if ((EC = visitEndOfDiagnostic()))
+ return EC;
+ return std::error_code();
+ case Cursor::Record:
+ break;
+ }
+
+ // Read the record.
+ Record.clear();
+ StringRef Blob;
+ unsigned RecID = Stream.readRecord(BlockOrCode, Record, &Blob);
+
+ if (RecID < serialized_diags::RECORD_FIRST ||
+ RecID > serialized_diags::RECORD_LAST)
+ continue;
+
+ switch ((RecordIDs)RecID) {
+ case RECORD_CATEGORY:
+ // A category has ID and name size.
+ if (Record.size() != 2)
+ return SDError::MalformedDiagnosticRecord;
+ if ((EC = visitCategoryRecord(Record[0], Blob)))
+ return EC;
+ continue;
+ case RECORD_DIAG:
+ // A diagnostic has severity, location (4), category, flag, and message
+ // size.
+ if (Record.size() != 8)
+ return SDError::MalformedDiagnosticRecord;
+ if ((EC = visitDiagnosticRecord(
+ Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
+ Record[5], Record[6], Blob)))
+ return EC;
+ continue;
+ case RECORD_DIAG_FLAG:
+ // A diagnostic flag has ID and name size.
+ if (Record.size() != 2)
+ return SDError::MalformedDiagnosticRecord;
+ if ((EC = visitDiagFlagRecord(Record[0], Blob)))
+ return EC;
+ continue;
+ case RECORD_FILENAME:
+ // A filename has ID, size, timestamp, and name size. The size and
+ // timestamp are legacy fields that are always zero these days.
+ if (Record.size() != 4)
+ return SDError::MalformedDiagnosticRecord;
+ if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
+ return EC;
+ continue;
+ case RECORD_FIXIT:
+ // A fixit has two locations (4 each) and message size.
+ if (Record.size() != 9)
+ return SDError::MalformedDiagnosticRecord;
+ if ((EC = visitFixitRecord(
+ Location(Record[0], Record[1], Record[2], Record[3]),
+ Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
+ return EC;
+ continue;
+ case RECORD_SOURCE_RANGE:
+ // A source range is two locations (4 each).
+ if (Record.size() != 8)
+ return SDError::MalformedDiagnosticRecord;
+ if ((EC = visitSourceRangeRecord(
+ Location(Record[0], Record[1], Record[2], Record[3]),
+ Location(Record[4], Record[5], Record[6], Record[7]))))
+ return EC;
+ continue;
+ case RECORD_VERSION:
+ // A version is just a number.
+ if (Record.size() != 1)
+ return SDError::MalformedDiagnosticRecord;
+ if ((EC = visitVersionRecord(Record[0])))
+ return EC;
+ continue;
+ }
+ }
+}
+
+namespace {
+class SDErrorCategoryType final : public std::error_category {
+ const char *name() const LLVM_NOEXCEPT override {
+ return "clang.serialized_diags";
+ }
+ std::string message(int IE) const override {
+ SDError E = static_cast<SDError>(IE);
+ switch (E) {
+ case SDError::CouldNotLoad:
+ return "Failed to open diagnostics file";
+ case SDError::InvalidSignature:
+ return "Invalid diagnostics signature";
+ case SDError::InvalidDiagnostics:
+ return "Parse error reading diagnostics";
+ case SDError::MalformedTopLevelBlock:
+ return "Malformed block at top-level of diagnostics";
+ case SDError::MalformedSubBlock:
+ return "Malformed sub-block in a diagnostic";
+ case SDError::MalformedBlockInfoBlock:
+ return "Malformed BlockInfo block";
+ case SDError::MalformedMetadataBlock:
+ return "Malformed Metadata block";
+ case SDError::MalformedDiagnosticBlock:
+ return "Malformed Diagnostic block";
+ case SDError::MalformedDiagnosticRecord:
+ return "Malformed Diagnostic record";
+ case SDError::MissingVersion:
+ return "No version provided in diagnostics";
+ case SDError::VersionMismatch:
+ return "Unsupported diagnostics version";
+ case SDError::UnsupportedConstruct:
+ return "Bitcode constructs that are not supported in diagnostics appear";
+ case SDError::HandlerFailed:
+ return "Generic error occurred while handling a record";
+ }
+ llvm_unreachable("Unknown error type!");
+ }
+};
+}
+
+static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
+const std::error_category &clang::serialized_diags::SDErrorCategory() {
+ return *ErrorCategory;
+}
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index 6e6f3dd1bfee..bbc99141f072 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -176,7 +176,7 @@ static void expandTabs(std::string &SourceLine, unsigned TabStop) {
/// of the printable representation of the line to the columns those printable
/// characters will appear at (numbering the first column as 0).
///
-/// If a byte 'i' corresponds to muliple columns (e.g. the byte contains a tab
+/// If a byte 'i' corresponds to multiple columns (e.g. the byte contains a tab
/// character) then the array will map that byte to the first column the
/// tab appears at and the next value in the map will have been incremented
/// more than once.
@@ -293,14 +293,14 @@ struct SourceColumnMap {
/// \brief Map from a byte index to the next byte which starts a column.
int startOfNextColumn(int N) const {
- assert(0 <= N && N < static_cast<int>(m_columnToByte.size() - 1));
+ assert(0 <= N && N < static_cast<int>(m_byteToColumn.size() - 1));
while (byteToColumn(++N) == -1) {}
return N;
}
/// \brief Map from a byte index to the previous byte which starts a column.
int startOfPreviousColumn(int N) const {
- assert(0 < N && N < static_cast<int>(m_columnToByte.size()));
+ assert(0 < N && N < static_cast<int>(m_byteToColumn.size()));
while (byteToColumn(--N) == -1) {}
return N;
}
@@ -323,9 +323,10 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
std::string &FixItInsertionLine,
unsigned Columns,
const SourceColumnMap &map) {
- unsigned MaxColumns = std::max<unsigned>(map.columns(),
- std::max(CaretLine.size(),
- FixItInsertionLine.size()));
+ unsigned CaretColumns = CaretLine.size();
+ unsigned FixItColumns = llvm::sys::locale::columnWidth(FixItInsertionLine);
+ unsigned MaxColumns = std::max(static_cast<unsigned>(map.columns()),
+ std::max(CaretColumns, FixItColumns));
// if the number of columns is less than the desired number we're done
if (MaxColumns <= Columns)
return;
@@ -487,7 +488,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
// We checked up front that the line needed truncation
assert(FrontColumnsRemoved+ColumnsKept+BackColumnsRemoved > Columns);
- // The line needs some trunctiona, and we'd prefer to keep the front
+ // The line needs some truncation, and we'd prefer to keep the front
// if possible, so remove the back
if (BackColumnsRemoved > strlen(back_ellipse))
SourceLine.replace(SourceEnd, std::string::npos, back_ellipse);
@@ -1110,12 +1111,13 @@ void TextDiagnostic::emitSnippetAndCaret(
// Copy the line of code into an std::string for ease of manipulation.
std::string SourceLine(LineStart, LineEnd);
- // Create a line for the caret that is filled with spaces that is the same
- // length as the line of source code.
- std::string CaretLine(LineEnd-LineStart, ' ');
-
+ // Build the byte to column map.
const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
+ // Create a line for the caret that is filled with spaces that is the same
+ // number of columns as the line of source code.
+ std::string CaretLine(sourceColMap.columns(), ' ');
+
// Highlight all of the characters covered by Ranges with ~ characters.
for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
E = Ranges.end();
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index b50950e9b300..3ff6b18e2199 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -27,14 +27,13 @@ typedef VerifyDiagnosticConsumer::Directive Directive;
typedef VerifyDiagnosticConsumer::DirectiveList DirectiveList;
typedef VerifyDiagnosticConsumer::ExpectedData ExpectedData;
-VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags)
- : Diags(_Diags),
- PrimaryClient(Diags.getClient()), OwnsPrimaryClient(Diags.ownsClient()),
+VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &Diags_)
+ : Diags(Diags_),
+ PrimaryClient(Diags.getClient()), PrimaryClientOwner(Diags.takeClient()),
Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(nullptr),
LangOpts(nullptr), SrcManager(nullptr), ActiveSourceFiles(0),
Status(HasNoDirectives)
{
- Diags.takeClient();
if (Diags.hasSourceManager())
setSourceManager(Diags.getSourceManager());
}
@@ -43,10 +42,8 @@ VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
assert(!ActiveSourceFiles && "Incomplete parsing of source files!");
assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");
SrcManager = nullptr;
- CheckDiagnostics();
- Diags.takeClient();
- if (OwnsPrimaryClient)
- delete PrimaryClient;
+ CheckDiagnostics();
+ Diags.takeClient().release();
}
#ifndef NDEBUG
@@ -84,8 +81,8 @@ void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
const_cast<Preprocessor*>(PP)->addCommentHandler(this);
#ifndef NDEBUG
// Debug build tracks parsed files.
- VerifyFileTracker *V = new VerifyFileTracker(*this, *SrcManager);
- const_cast<Preprocessor*>(PP)->addPPCallbacks(V);
+ const_cast<Preprocessor*>(PP)->addPPCallbacks(
+ llvm::make_unique<VerifyFileTracker>(*this, *SrcManager));
#endif
}
}
@@ -402,8 +399,9 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
// Lookup file via Preprocessor, like a #include.
const DirectoryLookup *CurDir;
- const FileEntry *FE = PP->LookupFile(Pos, Filename, false, nullptr,
- CurDir, nullptr, nullptr, nullptr);
+ const FileEntry *FE =
+ PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
+ nullptr, nullptr, nullptr);
if (!FE) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_file) << Filename << KindStr;
@@ -502,13 +500,12 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
}
// Construct new directive.
- std::unique_ptr<Directive> D(
- Directive::create(RegexKind, Pos, ExpectedLoc, MatchAnyLine, Text,
- Min, Max));
+ std::unique_ptr<Directive> D = Directive::create(
+ RegexKind, Pos, ExpectedLoc, MatchAnyLine, Text, Min, Max);
std::string Error;
if (D->isValid(Error)) {
- DL->push_back(D.release());
+ DL->push_back(std::move(D));
FoundDirective = true;
} else {
Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
@@ -644,15 +641,16 @@ static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceM
/// \brief Takes a list of diagnostics that were expected to have been generated
/// but were not and produces a diagnostic to the user from this.
-static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
- DirectiveList &DL, const char *Kind) {
+static unsigned PrintExpected(DiagnosticsEngine &Diags,
+ SourceManager &SourceMgr,
+ std::vector<Directive *> &DL, const char *Kind) {
if (DL.empty())
return 0;
SmallString<256> Fmt;
llvm::raw_svector_ostream OS(Fmt);
- for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
- Directive &D = **I;
+ for (auto *DirPtr : DL) {
+ Directive &D = *DirPtr;
OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc);
if (D.MatchAnyLine)
OS << " Line *";
@@ -694,11 +692,11 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
DirectiveList &Left,
const_diag_iterator d2_begin,
const_diag_iterator d2_end) {
- DirectiveList LeftOnly;
+ std::vector<Directive *> LeftOnly;
DiagList Right(d2_begin, d2_end);
- for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
- Directive& D = **I;
+ for (auto &Owner : Left) {
+ Directive &D = *Owner;
unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
for (unsigned i = 0; i < D.Max; ++i) {
@@ -720,7 +718,7 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
if (II == IE) {
// Not found.
if (i >= D.Min) break;
- LeftOnly.push_back(*I);
+ LeftOnly.push_back(&D);
} else {
// Found. The same cannot be found twice.
Right.erase(II);
@@ -801,8 +799,8 @@ void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,
void VerifyDiagnosticConsumer::CheckDiagnostics() {
// Ensure any diagnostics go to the primary client.
- bool OwnsCurClient = Diags.ownsClient();
- DiagnosticConsumer *CurClient = Diags.takeClient();
+ DiagnosticConsumer *CurClient = Diags.getClient();
+ std::unique_ptr<DiagnosticConsumer> Owner = Diags.takeClient();
Diags.setClient(PrimaryClient, false);
#ifndef NDEBUG
@@ -864,20 +862,21 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
Buffer->note_end(), "note"));
}
- Diags.takeClient();
- Diags.setClient(CurClient, OwnsCurClient);
+ Diags.setClient(CurClient, Owner.release() != nullptr);
// Reset the buffer, we have processed all the diagnostics in it.
Buffer.reset(new TextDiagnosticBuffer());
ED.Reset();
}
-Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
- SourceLocation DiagnosticLoc, bool MatchAnyLine,
- StringRef Text, unsigned Min, unsigned Max) {
+std::unique_ptr<Directive> Directive::create(bool RegexKind,
+ SourceLocation DirectiveLoc,
+ SourceLocation DiagnosticLoc,
+ bool MatchAnyLine, StringRef Text,
+ unsigned Min, unsigned Max) {
if (!RegexKind)
- return new StandardDirective(DirectiveLoc, DiagnosticLoc, MatchAnyLine,
- Text, Min, Max);
+ return llvm::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
+ MatchAnyLine, Text, Min, Max);
// Parse the directive into a regular expression.
std::string RegexStr;
@@ -902,6 +901,6 @@ Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
}
}
- return new RegexDirective(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text,
- Min, Max, RegexStr);
+ return llvm::make_unique<RegexDirective>(
+ DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max, RegexStr);
}
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index de864f653562..79cf0049a7b2 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -221,6 +221,6 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
return false;
bool Success = Clang->ExecuteAction(*Act);
if (Clang->getFrontendOpts().DisableFree)
- BuryPointer(Act.release());
+ BuryPointer(std::move(Act));
return Success;
}
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index edee7d764250..080550f7c77f 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -1,11 +1,18 @@
set(files
+ adxintrin.h
altivec.h
ammintrin.h
arm_acle.h
- avxintrin.h
avx2intrin.h
- bmiintrin.h
+ avx512bwintrin.h
+ avx512erintrin.h
+ avx512fintrin.h
+ avx512vlbwintrin.h
+ avx512vlintrin.h
+ avxintrin.h
bmi2intrin.h
+ bmiintrin.h
+ cpuid.h
emmintrin.h
f16cintrin.h
float.h
@@ -13,13 +20,14 @@ set(files
fmaintrin.h
ia32intrin.h
immintrin.h
- iso646.h
Intrin.h
+ iso646.h
limits.h
lzcntintrin.h
mm3dnow.h
mmintrin.h
mm_malloc.h
+ module.modulemap
nmmintrin.h
pmmintrin.h
popcntintrin.h
@@ -30,23 +38,24 @@ set(files
smmintrin.h
stdalign.h
stdarg.h
+ stdatomic.h
stdbool.h
stddef.h
+ __stddef_max_align_t.h
stdint.h
stdnoreturn.h
tbmintrin.h
tgmath.h
tmmintrin.h
+ unwind.h
+ vadefs.h
varargs.h
- wmmintrin.h
__wmmintrin_aes.h
+ wmmintrin.h
__wmmintrin_pclmul.h
x86intrin.h
xmmintrin.h
xopintrin.h
- cpuid.h
- unwind.h
- module.modulemap
)
set(output_dir ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION}/include)
diff --git a/lib/Headers/Intrin.h b/lib/Headers/Intrin.h
index 13e105ec1782..84bc4303a133 100644
--- a/lib/Headers/Intrin.h
+++ b/lib/Headers/Intrin.h
@@ -160,9 +160,6 @@ void __writefsword(unsigned long, unsigned short);
void __writemsr(unsigned long, unsigned __int64);
static __inline__
void *_AddressOfReturnAddress(void);
-unsigned int _andn_u32(unsigned int, unsigned int);
-unsigned int _bextr_u32(unsigned int, unsigned int, unsigned int);
-unsigned int _bextri_u32(unsigned int, unsigned int);
static __inline__
unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
static __inline__
@@ -175,20 +172,9 @@ static __inline__
unsigned char _bittestandreset(long *, long);
static __inline__
unsigned char _bittestandset(long *, long);
-unsigned int _blcfill_u32(unsigned int);
-unsigned int _blci_u32(unsigned int);
-unsigned int _blcic_u32(unsigned int);
-unsigned int _blcmsk_u32(unsigned int);
-unsigned int _blcs_u32(unsigned int);
-unsigned int _blsfill_u32(unsigned int);
-unsigned int _blsi_u32(unsigned int);
-unsigned int _blsic_u32(unsigned int);
-unsigned int _blsmsk_u32(unsigned int);
-unsigned int _blsr_u32(unsigned int);
unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64);
unsigned long __cdecl _byteswap_ulong(unsigned long);
unsigned short __cdecl _byteswap_ushort(unsigned short);
-unsigned _bzhi_u32(unsigned int, unsigned int);
void __cdecl _disable(void);
void __cdecl _enable(void);
void __cdecl _fxrstor(void const *);
@@ -266,7 +252,6 @@ unsigned long __cdecl _lrotl(unsigned long, int);
static __inline__
unsigned long __cdecl _lrotr(unsigned long, int);
static __inline__
-unsigned int _lzcnt_u32(unsigned int);
static __inline__
void _ReadBarrier(void);
static __inline__
@@ -274,8 +259,6 @@ void _ReadWriteBarrier(void);
static __inline__
void *_ReturnAddress(void);
unsigned int _rorx_u32(unsigned int, const unsigned int);
-int __cdecl _rdrand16_step(unsigned short *);
-int __cdecl _rdrand32_step(unsigned int *);
static __inline__
unsigned int __cdecl _rotl(unsigned int _Value, int _Shift);
static __inline__
@@ -301,12 +284,8 @@ unsigned int _shrx_u32(unsigned int, unsigned int);
void _Store_HLERelease(long volatile *, long);
void _Store64_HLERelease(__int64 volatile *, __int64);
void _StorePointer_HLERelease(void *volatile *, void *);
-unsigned int _t1mskc_u32(unsigned int);
-unsigned int _tzcnt_u32(unsigned int);
-unsigned int _tzmsk_u32(unsigned int);
static __inline__
void _WriteBarrier(void);
-void _xabort(const unsigned int imm);
unsigned __int32 xbegin(void);
void _xend(void);
static __inline__
@@ -315,7 +294,6 @@ void __cdecl _xrstor(void const *, unsigned __int64);
void __cdecl _xsave(void *, unsigned __int64);
void __cdecl _xsaveopt(void *, unsigned __int64);
void __cdecl _xsetbv(unsigned int, unsigned __int64);
-unsigned char _xtest(void);
/* These additional intrinsics are turned on in x64/amd64/x86_64 mode. */
#ifdef __x86_64__
@@ -352,7 +330,6 @@ unsigned __int64 __shiftright128(unsigned __int64 _LowPart,
unsigned char _Shift);
static __inline__
void __stosq(unsigned __int64 *, unsigned __int64, size_t);
-unsigned __int64 __umulh(unsigned __int64, unsigned __int64);
unsigned char __vmx_on(unsigned __int64 *);
unsigned char __vmx_vmclear(unsigned __int64 *);
unsigned char __vmx_vmlaunch(void);
@@ -364,9 +341,6 @@ void __writegsbyte(unsigned long, unsigned char);
void __writegsdword(unsigned long, unsigned long);
void __writegsqword(unsigned long, unsigned __int64);
void __writegsword(unsigned long, unsigned short);
-unsigned __int64 _andn_u64(unsigned __int64, unsigned __int64);
-unsigned __int64 _bextr_u64(unsigned __int64, unsigned int, unsigned int);
-unsigned __int64 _bextri_u64(unsigned __int64, unsigned int);
static __inline__
unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
static __inline__
@@ -379,18 +353,7 @@ static __inline__
unsigned char _bittestandreset64(__int64 *, __int64);
static __inline__
unsigned char _bittestandset64(__int64 *, __int64);
-unsigned __int64 _blcfill_u64(unsigned __int64);
-unsigned __int64 _blci_u64(unsigned __int64);
-unsigned __int64 _blcic_u64(unsigned __int64);
-unsigned __int64 _blcmsk_u64(unsigned __int64);
-unsigned __int64 _blcs_u64(unsigned __int64);
-unsigned __int64 _blsfill_u64(unsigned __int64);
-unsigned __int64 _blsi_u64(unsigned __int64);
-unsigned __int64 _blsic_u64(unsigned __int64);
-unsigned __int64 _blsmsk_u64(unsigned __int64);
-unsigned __int64 _blsr_u64(unsigned __int64);
unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64);
-unsigned __int64 _bzhi_u64(unsigned __int64, unsigned int);
void __cdecl _fxrstor64(void const *);
void __cdecl _fxsave64(void *);
long _InterlockedAnd_np(long volatile *_Value, long _Mask);
@@ -444,29 +407,33 @@ __int64 _InterlockedXor64(__int64 volatile *_Value, __int64 _Mask);
__int64 _InterlockedXor64_np(__int64 volatile *_Value, __int64 _Mask);
char _InterlockedXor8_np(char volatile *_Value, char _Mask);
static __inline__
-unsigned __int64 _lzcnt_u64(unsigned __int64);
__int64 _mul128(__int64 _Multiplier, __int64 _Multiplicand,
__int64 *_HighProduct);
-unsigned int __cdecl _readfsbase_u32(void);
-unsigned __int64 __cdecl _readfsbase_u64(void);
-unsigned int __cdecl _readgsbase_u32(void);
-unsigned __int64 __cdecl _readgsbase_u64(void);
unsigned __int64 _rorx_u64(unsigned __int64, const unsigned int);
__int64 _sarx_i64(__int64, unsigned int);
#if __STDC_HOSTED__
int __cdecl _setjmpex(jmp_buf);
#endif
unsigned __int64 _shlx_u64(unsigned __int64, unsigned int);
-unsigned __int64 shrx_u64(unsigned __int64, unsigned int);
-unsigned __int64 _tzcnt_u64(unsigned __int64);
-unsigned __int64 _tzmsk_u64(unsigned __int64);
-unsigned __int64 _umul128(unsigned __int64 _Multiplier,
- unsigned __int64 _Multiplicand,
- unsigned __int64 *_HighProduct);
-void __cdecl _writefsbase_u32(unsigned int);
-void _cdecl _writefsbase_u64(unsigned __int64);
-void __cdecl _writegsbase_u32(unsigned int);
-void __cdecl _writegsbase_u64(unsigned __int64);
+unsigned __int64 _shrx_u64(unsigned __int64, unsigned int);
+/*
+ * Multiply two 64-bit integers and obtain a 64-bit result.
+ * The low-half is returned directly and the high half is in an out parameter.
+ */
+static __inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
+_umul128(unsigned __int64 _Multiplier, unsigned __int64 _Multiplicand,
+ unsigned __int64 *_HighProduct) {
+ unsigned __int128 _FullProduct =
+ (unsigned __int128)_Multiplier * (unsigned __int128)_Multiplicand;
+ *_HighProduct = _FullProduct >> 64;
+ return _FullProduct;
+}
+static __inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
+__umulh(unsigned __int64 _Multiplier, unsigned __int64 _Multiplicand) {
+ unsigned __int128 _FullProduct =
+ (unsigned __int128)_Multiplier * (unsigned __int128)_Multiplicand;
+ return _FullProduct >> 64;
+}
void __cdecl _xrstor64(void const *, unsigned __int64);
void __cdecl _xsave64(void *, unsigned __int64);
void __cdecl _xsaveopt64(void *, unsigned __int64);
@@ -545,12 +512,6 @@ _BitScanReverse(unsigned long *_Index, unsigned long _Mask) {
*_Index = 31 - __builtin_clzl(_Mask);
return 1;
}
-static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
-_lzcnt_u32(unsigned int a) {
- if (!a)
- return 32;
- return __builtin_clzl(a);
-}
static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
__popcnt16(unsigned short value) {
return __builtin_popcount((int)value);
@@ -608,13 +569,6 @@ _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask) {
*_Index = 63 - __builtin_clzll(_Mask);
return 1;
}
-static
-__inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
-_lzcnt_u64(unsigned __int64 a) {
- if (!a)
- return 64;
- return __builtin_clzll(a);
-}
static __inline__
unsigned __int64 __attribute__((__always_inline__, __nodebug__))
__popcnt64(unsigned __int64 value) {
@@ -861,10 +815,6 @@ static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
__readfsbyte(unsigned long __offset) {
return *__ptr_to_addr_space(257, unsigned char, __offset);
}
-static __inline__ unsigned long __attribute__((__always_inline__, __nodebug__))
-__readfsdword(unsigned long __offset) {
- return *__ptr_to_addr_space(257, unsigned long, __offset);
-}
static __inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
__readfsqword(unsigned long __offset) {
return *__ptr_to_addr_space(257, unsigned __int64, __offset);
diff --git a/lib/Headers/__stddef_max_align_t.h b/lib/Headers/__stddef_max_align_t.h
new file mode 100644
index 000000000000..a06f412c53fb
--- /dev/null
+++ b/lib/Headers/__stddef_max_align_t.h
@@ -0,0 +1,40 @@
+/*===---- __stddef_max_align_t.h - Definition of max_align_t for modules ---===
+ *
+ * Copyright (c) 2014 Chandler Carruth
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __CLANG_MAX_ALIGN_T_DEFINED
+#define __CLANG_MAX_ALIGN_T_DEFINED
+
+#ifndef _MSC_VER
+typedef struct {
+ long long __clang_max_align_nonce1
+ __attribute__((__aligned__(__alignof__(long long))));
+ long double __clang_max_align_nonce2
+ __attribute__((__aligned__(__alignof__(long double))));
+} max_align_t;
+#else
+typedef double max_align_t;
+#endif
+
+#endif
diff --git a/lib/Headers/adxintrin.h b/lib/Headers/adxintrin.h
new file mode 100644
index 000000000000..9db8bcbd9030
--- /dev/null
+++ b/lib/Headers/adxintrin.h
@@ -0,0 +1,83 @@
+/*===---- adxintrin.h - ADX intrinsics -------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __IMMINTRIN_H
+#error "Never use <adxintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __ADXINTRIN_H
+#define __ADXINTRIN_H
+
+/* Intrinsics that are available only if __ADX__ defined */
+#ifdef __ADX__
+static __inline unsigned char __attribute__((__always_inline__, __nodebug__))
+_addcarryx_u32(unsigned char __cf, unsigned int __x, unsigned int __y,
+ unsigned int *__p)
+{
+ return __builtin_ia32_addcarryx_u32(__cf, __x, __y, __p);
+}
+
+#ifdef __x86_64__
+static __inline unsigned char __attribute__((__always_inline__, __nodebug__))
+_addcarryx_u64(unsigned char __cf, unsigned long long __x,
+ unsigned long long __y, unsigned long long *__p)
+{
+ return __builtin_ia32_addcarryx_u64(__cf, __x, __y, __p);
+}
+#endif
+#endif
+
+/* Intrinsics that are also available if __ADX__ undefined */
+static __inline unsigned char __attribute__((__always_inline__, __nodebug__))
+_addcarry_u32(unsigned char __cf, unsigned int __x, unsigned int __y,
+ unsigned int *__p)
+{
+ return __builtin_ia32_addcarry_u32(__cf, __x, __y, __p);
+}
+
+#ifdef __x86_64__
+static __inline unsigned char __attribute__((__always_inline__, __nodebug__))
+_addcarry_u64(unsigned char __cf, unsigned long long __x,
+ unsigned long long __y, unsigned long long *__p)
+{
+ return __builtin_ia32_addcarry_u64(__cf, __x, __y, __p);
+}
+#endif
+
+static __inline unsigned char __attribute__((__always_inline__, __nodebug__))
+_subborrow_u32(unsigned char __cf, unsigned int __x, unsigned int __y,
+ unsigned int *__p)
+{
+ return __builtin_ia32_subborrow_u32(__cf, __x, __y, __p);
+}
+
+#ifdef __x86_64__
+static __inline unsigned char __attribute__((__always_inline__, __nodebug__))
+_subborrow_u64(unsigned char __cf, unsigned long long __x,
+ unsigned long long __y, unsigned long long *__p)
+{
+ return __builtin_ia32_subborrow_u64(__cf, __x, __y, __p);
+}
+#endif
+
+#endif /* __ADXINTRIN_H */
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index f9fc64af3e74..0ac0841ae482 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -1623,6 +1623,21 @@ vec_vctuxs(vector float __a, int __b)
return __builtin_altivec_vctuxs(__a, __b);
}
+/* vec_div */
+#ifdef __VSX__
+static vector float __ATTRS_o_ai
+vec_div(vector float __a, vector float __b)
+{
+ return __builtin_vsx_xvdivsp(__a, __b);
+}
+
+static vector double __ATTRS_o_ai
+vec_div(vector double __a, vector double __b)
+{
+ return __builtin_vsx_xvdivdp(__a, __b);
+}
+#endif
+
/* vec_dss */
static void __attribute__((__always_inline__))
@@ -2253,91 +2268,273 @@ vec_vlogefp(vector float __a)
/* vec_lvsl */
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsl(int __a, const signed char *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsl(int __a, const signed char *__b)
{
return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsl(int __a, const unsigned char *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsl(int __a, const unsigned char *__b)
{
return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsl(int __a, const short *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsl(int __a, const short *__b)
{
return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsl(int __a, const unsigned short *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsl(int __a, const unsigned short *__b)
{
return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsl(int __a, const int *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsl(int __a, const int *__b)
{
return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsl(int __a, const unsigned int *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsl(int __a, const unsigned int *__b)
{
return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsl(int __a, const float *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsl(int __a, const float *__b)
{
return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
+#endif
/* vec_lvsr */
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsr(int __a, const signed char *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsr(int __a, const signed char *__b)
{
return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsr(int __a, const unsigned char *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsr(int __a, const unsigned char *__b)
{
return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsr(int __a, const short *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsr(int __a, const short *__b)
{
return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsr(int __a, const unsigned short *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsr(int __a, const unsigned short *__b)
{
return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsr(int __a, const int *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsr(int __a, const int *__b)
{
return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsr(int __a, const unsigned int *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsr(int __a, const unsigned int *__b)
{
return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
+#endif
+#ifdef __LITTLE_ENDIAN__
+static vector unsigned char __ATTRS_o_ai
+__attribute__((deprecated("use assignment for unaligned little endian \
+loads/stores")))
+vec_lvsr(int __a, const float *__b)
+{
+ vector unsigned char mask =
+ (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
+ vector unsigned char reverse = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+ return vec_perm(mask, mask, reverse);
+}
+#else
static vector unsigned char __ATTRS_o_ai
vec_lvsr(int __a, const float *__b)
{
return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
+#endif
/* vec_madd */
@@ -2485,8 +2682,20 @@ vec_max(vector unsigned int __a, vector bool int __b)
static vector float __ATTRS_o_ai
vec_max(vector float __a, vector float __b)
{
+#ifdef __VSX__
+ return __builtin_vsx_xvmaxsp(__a, __b);
+#else
return __builtin_altivec_vmaxfp(__a, __b);
+#endif
+}
+
+#ifdef __VSX__
+static vector double __ATTRS_o_ai
+vec_max(vector double __a, vector double __b)
+{
+ return __builtin_vsx_xvmaxdp(__a, __b);
}
+#endif
/* vec_vmaxsb */
@@ -2613,7 +2822,11 @@ vec_vmaxuw(vector unsigned int __a, vector bool int __b)
static vector float __attribute__((__always_inline__))
vec_vmaxfp(vector float __a, vector float __b)
{
+#ifdef __VSX__
+ return __builtin_vsx_xvmaxsp(__a, __b);
+#else
return __builtin_altivec_vmaxfp(__a, __b);
+#endif
}
/* vec_mergeh */
@@ -3117,9 +3330,21 @@ vec_min(vector unsigned int __a, vector bool int __b)
static vector float __ATTRS_o_ai
vec_min(vector float __a, vector float __b)
{
+#ifdef __VSX__
+ return __builtin_vsx_xvminsp(__a, __b);
+#else
return __builtin_altivec_vminfp(__a, __b);
+#endif
}
+#ifdef __VSX__
+static vector double __ATTRS_o_ai
+vec_min(vector double __a, vector double __b)
+{
+ return __builtin_vsx_xvmindp(__a, __b);
+}
+#endif
+
/* vec_vminsb */
static vector signed char __ATTRS_o_ai
@@ -3245,7 +3470,11 @@ vec_vminuw(vector unsigned int __a, vector bool int __b)
static vector float __attribute__((__always_inline__))
vec_vminfp(vector float __a, vector float __b)
{
+#ifdef __VSX__
+ return __builtin_vsx_xvminsp(__a, __b);
+#else
return __builtin_altivec_vminfp(__a, __b);
+#endif
}
/* vec_mladd */
@@ -4506,7 +4735,7 @@ vec_vpkswus(vector unsigned int __a, vector unsigned int __b)
// in that the vec_xor can be recognized as a vec_nor (and for P8 and
// later, possibly a vec_nand).
-vector signed char __ATTRS_o_ai
+static vector signed char __ATTRS_o_ai
vec_perm(vector signed char __a, vector signed char __b, vector unsigned char __c)
{
#ifdef __LITTLE_ENDIAN__
@@ -4521,7 +4750,7 @@ vec_perm(vector signed char __a, vector signed char __b, vector unsigned char __
#endif
}
-vector unsigned char __ATTRS_o_ai
+static vector unsigned char __ATTRS_o_ai
vec_perm(vector unsigned char __a,
vector unsigned char __b,
vector unsigned char __c)
@@ -4538,7 +4767,7 @@ vec_perm(vector unsigned char __a,
#endif
}
-vector bool char __ATTRS_o_ai
+static vector bool char __ATTRS_o_ai
vec_perm(vector bool char __a, vector bool char __b, vector unsigned char __c)
{
#ifdef __LITTLE_ENDIAN__
@@ -4553,7 +4782,7 @@ vec_perm(vector bool char __a, vector bool char __b, vector unsigned char __c)
#endif
}
-vector short __ATTRS_o_ai
+static vector short __ATTRS_o_ai
vec_perm(vector short __a, vector short __b, vector unsigned char __c)
{
#ifdef __LITTLE_ENDIAN__
@@ -4568,7 +4797,7 @@ vec_perm(vector short __a, vector short __b, vector unsigned char __c)
#endif
}
-vector unsigned short __ATTRS_o_ai
+static vector unsigned short __ATTRS_o_ai
vec_perm(vector unsigned short __a,
vector unsigned short __b,
vector unsigned char __c)
@@ -4585,7 +4814,7 @@ vec_perm(vector unsigned short __a,
#endif
}
-vector bool short __ATTRS_o_ai
+static vector bool short __ATTRS_o_ai
vec_perm(vector bool short __a, vector bool short __b, vector unsigned char __c)
{
#ifdef __LITTLE_ENDIAN__
@@ -4600,7 +4829,7 @@ vec_perm(vector bool short __a, vector bool short __b, vector unsigned char __c)
#endif
}
-vector pixel __ATTRS_o_ai
+static vector pixel __ATTRS_o_ai
vec_perm(vector pixel __a, vector pixel __b, vector unsigned char __c)
{
#ifdef __LITTLE_ENDIAN__
@@ -4615,7 +4844,7 @@ vec_perm(vector pixel __a, vector pixel __b, vector unsigned char __c)
#endif
}
-vector int __ATTRS_o_ai
+static vector int __ATTRS_o_ai
vec_perm(vector int __a, vector int __b, vector unsigned char __c)
{
#ifdef __LITTLE_ENDIAN__
@@ -4628,7 +4857,7 @@ vec_perm(vector int __a, vector int __b, vector unsigned char __c)
#endif
}
-vector unsigned int __ATTRS_o_ai
+static vector unsigned int __ATTRS_o_ai
vec_perm(vector unsigned int __a, vector unsigned int __b, vector unsigned char __c)
{
#ifdef __LITTLE_ENDIAN__
@@ -4643,7 +4872,7 @@ vec_perm(vector unsigned int __a, vector unsigned int __b, vector unsigned char
#endif
}
-vector bool int __ATTRS_o_ai
+static vector bool int __ATTRS_o_ai
vec_perm(vector bool int __a, vector bool int __b, vector unsigned char __c)
{
#ifdef __LITTLE_ENDIAN__
@@ -4658,7 +4887,7 @@ vec_perm(vector bool int __a, vector bool int __b, vector unsigned char __c)
#endif
}
-vector float __ATTRS_o_ai
+static vector float __ATTRS_o_ai
vec_perm(vector float __a, vector float __b, vector unsigned char __c)
{
#ifdef __LITTLE_ENDIAN__
@@ -4673,6 +4902,52 @@ vec_perm(vector float __a, vector float __b, vector unsigned char __c)
#endif
}
+#ifdef __VSX__
+static vector long long __ATTRS_o_ai
+vec_perm(vector long long __a, vector long long __b, vector unsigned char __c)
+{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector long long)__builtin_altivec_vperm_4si(__b, __a, __d);
+#else
+ return (vector long long)__builtin_altivec_vperm_4si(__a, __b, __c);
+#endif
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_perm(vector unsigned long long __a, vector unsigned long long __b,
+ vector unsigned char __c)
+{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector unsigned long long)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
+ return (vector unsigned long long)
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
+}
+
+static vector double __ATTRS_o_ai
+vec_perm(vector double __a, vector double __b, vector unsigned char __c)
+{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector double)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
+ return (vector double)
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
+}
+#endif
+
/* vec_vperm */
static vector signed char __ATTRS_o_ai
@@ -4745,6 +5020,27 @@ vec_vperm(vector float __a, vector float __b, vector unsigned char __c)
return vec_perm(__a, __b, __c);
}
+#ifdef __VSX__
+static vector long long __ATTRS_o_ai
+vec_vperm(vector long long __a, vector long long __b, vector unsigned char __c)
+{
+ return vec_perm(__a, __b, __c);
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_vperm(vector unsigned long long __a, vector unsigned long long __b,
+ vector unsigned char __c)
+{
+ return vec_perm(__a, __b, __c);
+}
+
+static vector double __ATTRS_o_ai
+vec_vperm(vector double __a, vector double __b, vector unsigned char __c)
+{
+ return vec_perm(__a, __b, __c);
+}
+#endif
+
/* vec_re */
static vector float __attribute__((__always_inline__))
@@ -8368,11 +8664,11 @@ vec_sum2s(vector int __a, vector int __b)
#ifdef __LITTLE_ENDIAN__
vector int __c = (vector signed int)
vec_perm(__b, __b, (vector unsigned char)
- (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
+ (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
__c = __builtin_altivec_vsum2sws(__a, __c);
return (vector signed int)
vec_perm(__c, __c, (vector unsigned char)
- (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
+ (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
#else
return __builtin_altivec_vsum2sws(__a, __b);
#endif
@@ -8386,11 +8682,11 @@ vec_vsum2sws(vector int __a, vector int __b)
#ifdef __LITTLE_ENDIAN__
vector int __c = (vector signed int)
vec_perm(__b, __b, (vector unsigned char)
- (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
+ (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
__c = __builtin_altivec_vsum2sws(__a, __c);
return (vector signed int)
vec_perm(__c, __c, (vector unsigned char)
- (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
+ (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
#else
return __builtin_altivec_vsum2sws(__a, __b);
#endif
@@ -8661,6 +8957,91 @@ vec_vupklsh(vector pixel __a)
#endif
}
+/* vec_vsx_ld */
+
+#ifdef __VSX__
+
+static vector signed int __ATTRS_o_ai
+vec_vsx_ld(int __a, const vector signed int *__b)
+{
+ return (vector signed int)__builtin_vsx_lxvw4x(__a, __b);
+}
+
+static vector unsigned int __ATTRS_o_ai
+vec_vsx_ld(int __a, const vector unsigned int *__b)
+{
+ return (vector unsigned int)__builtin_vsx_lxvw4x(__a, __b);
+}
+
+static vector float __ATTRS_o_ai
+vec_vsx_ld(int __a, const vector float *__b)
+{
+ return (vector float)__builtin_vsx_lxvw4x(__a, __b);
+}
+
+static vector signed long long __ATTRS_o_ai
+vec_vsx_ld(int __a, const vector signed long long *__b)
+{
+ return (vector signed long long)__builtin_vsx_lxvd2x(__a, __b);
+}
+
+static vector unsigned long long __ATTRS_o_ai
+vec_vsx_ld(int __a, const vector unsigned long long *__b)
+{
+ return (vector unsigned long long)__builtin_vsx_lxvd2x(__a, __b);
+}
+
+static vector double __ATTRS_o_ai
+vec_vsx_ld(int __a, const vector double *__b)
+{
+ return (vector double)__builtin_vsx_lxvd2x(__a, __b);
+}
+
+#endif
+
+/* vec_vsx_st */
+
+#ifdef __VSX__
+
+static void __ATTRS_o_ai
+vec_vsx_st(vector signed int __a, int __b, vector signed int *__c)
+{
+ __builtin_vsx_stxvw4x((vector int)__a, __b, __c);
+}
+
+static void __ATTRS_o_ai
+vec_vsx_st(vector unsigned int __a, int __b, vector unsigned int *__c)
+{
+ __builtin_vsx_stxvw4x((vector int)__a, __b, __c);
+}
+
+static void __ATTRS_o_ai
+vec_vsx_st(vector float __a, int __b, vector float *__c)
+{
+ __builtin_vsx_stxvw4x((vector int)__a, __b, __c);
+}
+
+static void __ATTRS_o_ai
+vec_vsx_st(vector signed long long __a, int __b, vector signed long long *__c)
+{
+ __builtin_vsx_stxvd2x((vector double)__a, __b, __c);
+}
+
+static void __ATTRS_o_ai
+vec_vsx_st(vector unsigned long long __a, int __b,
+ vector unsigned long long *__c)
+{
+ __builtin_vsx_stxvd2x((vector double)__a, __b, __c);
+}
+
+static void __ATTRS_o_ai
+vec_vsx_st(vector double __a, int __b, vector double *__c)
+{
+ __builtin_vsx_stxvd2x((vector double)__a, __b, __c);
+}
+
+#endif
+
/* vec_xor */
#define __builtin_altivec_vxor vec_xor
diff --git a/lib/Headers/arm_acle.h b/lib/Headers/arm_acle.h
index a0fd6894ab96..814df2c3d782 100644
--- a/lib/Headers/arm_acle.h
+++ b/lib/Headers/arm_acle.h
@@ -66,6 +66,41 @@ static __inline__ void __attribute__((always_inline, nodebug)) __yield(void) {
}
#endif
+#if __ARM_32BIT_STATE
+#define __dbg(t) __builtin_arm_dbg(t)
+#endif
+
+/* 8.5 Swap */
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __swp(uint32_t x, volatile uint32_t *p) {
+ uint32_t v;
+ do v = __builtin_arm_ldrex(p); while (__builtin_arm_strex(x, p));
+ return v;
+}
+
+/* 8.6 Memory prefetch intrinsics */
+/* 8.6.1 Data prefetch */
+#define __pld(addr) __pldx(0, 0, 0, addr)
+
+#if __ARM_32BIT_STATE
+#define __pldx(access_kind, cache_level, retention_policy, addr) \
+ __builtin_arm_prefetch(addr, access_kind, 1)
+#else
+#define __pldx(access_kind, cache_level, retention_policy, addr) \
+ __builtin_arm_prefetch(addr, access_kind, cache_level, retention_policy, 1)
+#endif
+
+/* 8.6.2 Instruction prefetch */
+#define __pli(addr) __plix(0, 0, addr)
+
+#if __ARM_32BIT_STATE
+#define __plix(cache_level, retention_policy, addr) \
+ __builtin_arm_prefetch(addr, 0, 0)
+#else
+#define __plix(cache_level, retention_policy, addr) \
+ __builtin_arm_prefetch(addr, 0, cache_level, retention_policy, 0)
+#endif
+
/* 8.7 NOP */
static __inline__ void __attribute__((always_inline, nodebug)) __nop(void) {
__builtin_arm_nop();
@@ -73,6 +108,32 @@ static __inline__ void __attribute__((always_inline, nodebug)) __nop(void) {
/* 9 DATA-PROCESSING INTRINSICS */
/* 9.2 Miscellaneous data-processing intrinsics */
+/* ROR */
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __ror(uint32_t x, uint32_t y) {
+ y %= 32;
+ if (y == 0) return x;
+ return (x >> y) | (x << (32 - y));
+}
+
+static __inline__ uint64_t __attribute__((always_inline, nodebug))
+ __rorll(uint64_t x, uint32_t y) {
+ y %= 64;
+ if (y == 0) return x;
+ return (x >> y) | (x << (64 - y));
+}
+
+static __inline__ unsigned long __attribute__((always_inline, nodebug))
+ __rorl(unsigned long x, uint32_t y) {
+#if __SIZEOF_LONG__ == 4
+ return __ror(x, y);
+#else
+ return __rorll(x, y);
+#endif
+}
+
+
+/* CLZ */
static __inline__ uint32_t __attribute__((always_inline, nodebug))
__clz(uint32_t t) {
return __builtin_clz(t);
@@ -85,13 +146,10 @@ static __inline__ unsigned long __attribute__((always_inline, nodebug))
static __inline__ uint64_t __attribute__((always_inline, nodebug))
__clzll(uint64_t t) {
-#if __SIZEOF_LONG_LONG__ == 8
return __builtin_clzll(t);
-#else
- return __builtin_clzl(t);
-#endif
}
+/* REV */
static __inline__ uint32_t __attribute__((always_inline, nodebug))
__rev(uint32_t t) {
return __builtin_bswap32(t);
@@ -111,6 +169,53 @@ static __inline__ uint64_t __attribute__((always_inline, nodebug))
return __builtin_bswap64(t);
}
+/* REV16 */
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __rev16(uint32_t t) {
+ return __ror(__rev(t), 16);
+}
+
+static __inline__ unsigned long __attribute__((always_inline, nodebug))
+ __rev16l(unsigned long t) {
+ return __rorl(__revl(t), sizeof(long) / 2);
+}
+
+static __inline__ uint64_t __attribute__((always_inline, nodebug))
+ __rev16ll(uint64_t t) {
+ return __rorll(__revll(t), 32);
+}
+
+/* REVSH */
+static __inline__ int16_t __attribute__((always_inline, nodebug))
+ __revsh(int16_t t) {
+ return __builtin_bswap16(t);
+}
+
+/* RBIT */
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __rbit(uint32_t t) {
+ return __builtin_arm_rbit(t);
+}
+
+static __inline__ uint64_t __attribute__((always_inline, nodebug))
+ __rbitll(uint64_t t) {
+#if __ARM_32BIT_STATE
+ return (((uint64_t) __builtin_arm_rbit(t)) << 32) |
+ __builtin_arm_rbit(t >> 32);
+#else
+ return __builtin_arm_rbit64(t);
+#endif
+}
+
+static __inline__ unsigned long __attribute__((always_inline, nodebug))
+ __rbitl(unsigned long t) {
+#if __SIZEOF_LONG__ == 4
+ return __rbit(t);
+#else
+ return __rbitll(t);
+#endif
+}
+
/*
* 9.4 Saturating intrinsics
*
diff --git a/lib/Headers/avx512bwintrin.h b/lib/Headers/avx512bwintrin.h
new file mode 100644
index 000000000000..bc4d4ac6afdd
--- /dev/null
+++ b/lib/Headers/avx512bwintrin.h
@@ -0,0 +1,60 @@
+/*===------------- avx512bwintrin.h - AVX512BW intrinsics ------------------===
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __AVX512BWINTRIN_H
+#define __AVX512BWINTRIN_H
+
+typedef unsigned int __mmask32;
+typedef unsigned long long __mmask64;
+typedef char __v64qi __attribute__ ((vector_size (64)));
+typedef short __v32hi __attribute__ ((__vector_size__ (64)));
+
+
+/* Integer compare */
+
+static __inline__ __mmask64 __attribute__((__always_inline__, __nodebug__))
+_mm512_cmpeq_epi8_mask(__m512i __a, __m512i __b) {
+ return (__mmask64)__builtin_ia32_pcmpeqb512_mask((__v64qi)__a, (__v64qi)__b,
+ (__mmask64)-1);
+}
+
+static __inline__ __mmask64 __attribute__((__always_inline__, __nodebug__))
+_mm512_mask_cmpeq_epi8_mask(__mmask64 __u, __m512i __a, __m512i __b) {
+ return (__mmask64)__builtin_ia32_pcmpeqb512_mask((__v64qi)__a, (__v64qi)__b,
+ __u);
+}
+
+static __inline__ __mmask32 __attribute__((__always_inline__, __nodebug__))
+_mm512_cmpeq_epi16_mask(__m512i __a, __m512i __b) {
+ return (__mmask32)__builtin_ia32_pcmpeqw512_mask((__v32hi)__a, (__v32hi)__b,
+ (__mmask32)-1);
+}
+
+static __inline__ __mmask32 __attribute__((__always_inline__, __nodebug__))
+_mm512_mask_cmpeq_epi16_mask(__mmask32 __u, __m512i __a, __m512i __b) {
+ return (__mmask32)__builtin_ia32_pcmpeqw512_mask((__v32hi)__a, (__v32hi)__b,
+ __u);
+}
+
+#endif
diff --git a/lib/Headers/avx512erintrin.h b/lib/Headers/avx512erintrin.h
new file mode 100644
index 000000000000..1a5ea153adf3
--- /dev/null
+++ b/lib/Headers/avx512erintrin.h
@@ -0,0 +1,112 @@
+/*===---- avx512fintrin.h - AVX2 intrinsics -----------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+#ifndef __IMMINTRIN_H
+#error "Never use <avx512erintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __AVX512ERINTRIN_H
+#define __AVX512ERINTRIN_H
+
+
+// rsqrt28
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_rsqrt28_round_pd (__m512d __A, int __R)
+{
+ return (__m512d)__builtin_ia32_rsqrt28pd_mask ((__v8df)__A,
+ (__v8df)_mm512_setzero_pd(),
+ (__mmask8)-1,
+ __R);
+}
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_rsqrt28_round_ps(__m512 __A, int __R)
+{
+ return (__m512)__builtin_ia32_rsqrt28ps_mask ((__v16sf)__A,
+ (__v16sf)_mm512_setzero_ps(),
+ (__mmask16)-1,
+ __R);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_rsqrt28_round_ss(__m128 __A, __m128 __B, int __R)
+{
+ return (__m128) __builtin_ia32_rsqrt28ss_mask ((__v4sf) __A,
+ (__v4sf) __B,
+ (__v4sf)
+ _mm_setzero_ps (),
+ (__mmask8) -1,
+ __R);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_rsqrt28_round_sd (__m128d __A, __m128d __B, int __R)
+{
+ return (__m128d) __builtin_ia32_rsqrt28sd_mask ((__v2df) __A,
+ (__v2df) __B,
+ (__v2df)
+ _mm_setzero_pd (),
+ (__mmask8) -1,
+ __R);
+}
+
+
+// rcp28
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_rcp28_round_pd (__m512d __A, int __R)
+{
+ return (__m512d)__builtin_ia32_rcp28pd_mask ((__v8df)__A,
+ (__v8df)_mm512_setzero_pd(),
+ (__mmask8)-1,
+ __R);
+}
+
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_rcp28_round_ps (__m512 __A, int __R)
+{
+ return (__m512)__builtin_ia32_rcp28ps_mask ((__v16sf)__A,
+ (__v16sf)_mm512_setzero_ps (),
+ (__mmask16)-1,
+ __R);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_rcp28_round_ss (__m128 __A, __m128 __B, int __R)
+{
+ return (__m128) __builtin_ia32_rcp28ss_mask ((__v4sf) __A,
+ (__v4sf) __B,
+ (__v4sf)
+ _mm_setzero_ps (),
+ (__mmask8) -1,
+ __R);
+}
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_rcp28_round_sd (__m128d __A, __m128d __B, int __R)
+{
+ return (__m128d) __builtin_ia32_rcp28sd_mask ((__v2df) __A,
+ (__v2df) __B,
+ (__v2df)
+ _mm_setzero_pd (),
+ (__mmask8) -1,
+ __R);
+}
+
+#endif // __AVX512ERINTRIN_H
diff --git a/lib/Headers/avx512fintrin.h b/lib/Headers/avx512fintrin.h
new file mode 100644
index 000000000000..9c80710110b0
--- /dev/null
+++ b/lib/Headers/avx512fintrin.h
@@ -0,0 +1,1036 @@
+/*===---- avx512fintrin.h - AVX2 intrinsics --------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+#ifndef __IMMINTRIN_H
+#error "Never use <avx512fintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __AVX512FINTRIN_H
+#define __AVX512FINTRIN_H
+
+typedef double __v8df __attribute__((__vector_size__(64)));
+typedef float __v16sf __attribute__((__vector_size__(64)));
+typedef long long __v8di __attribute__((__vector_size__(64)));
+typedef int __v16si __attribute__((__vector_size__(64)));
+
+typedef float __m512 __attribute__((__vector_size__(64)));
+typedef double __m512d __attribute__((__vector_size__(64)));
+typedef long long __m512i __attribute__((__vector_size__(64)));
+
+typedef unsigned char __mmask8;
+typedef unsigned short __mmask16;
+
+/* Rounding mode macros. */
+#define _MM_FROUND_TO_NEAREST_INT 0x00
+#define _MM_FROUND_TO_NEG_INF 0x01
+#define _MM_FROUND_TO_POS_INF 0x02
+#define _MM_FROUND_TO_ZERO 0x03
+#define _MM_FROUND_CUR_DIRECTION 0x04
+
+/* Create vectors with repeated elements */
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_setzero_si512(void)
+{
+ return (__m512i)(__v8di){ 0, 0, 0, 0, 0, 0, 0, 0 };
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_maskz_set1_epi32(__mmask16 __M, int __A)
+{
+ return (__m512i) __builtin_ia32_pbroadcastd512_gpr_mask (__A,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ __M);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_maskz_set1_epi64(__mmask8 __M, long long __A)
+{
+#ifdef __x86_64__
+ return (__m512i) __builtin_ia32_pbroadcastq512_gpr_mask (__A,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ __M);
+#else
+ return (__m512i) __builtin_ia32_pbroadcastq512_mem_mask (__A,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ __M);
+#endif
+}
+
+static __inline __m512 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_setzero_ps(void)
+{
+ return (__m512){ 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.0, 0.0, 0.0 };
+}
+static __inline __m512d __attribute__ ((__always_inline__, __nodebug__))
+_mm512_setzero_pd(void)
+{
+ return (__m512d){ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+}
+
+static __inline __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_set1_ps(float __w)
+{
+ return (__m512){ __w, __w, __w, __w, __w, __w, __w, __w,
+ __w, __w, __w, __w, __w, __w, __w, __w };
+}
+
+static __inline __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_set1_pd(double __w)
+{
+ return (__m512d){ __w, __w, __w, __w, __w, __w, __w, __w };
+}
+
+static __inline __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_set1_epi32(int __s)
+{
+ return (__m512i)(__v16si){ __s, __s, __s, __s, __s, __s, __s, __s,
+ __s, __s, __s, __s, __s, __s, __s, __s };
+}
+
+static __inline __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_set1_epi64(long long __d)
+{
+ return (__m512i)(__v8di){ __d, __d, __d, __d, __d, __d, __d, __d };
+}
+
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_broadcastss_ps(__m128 __X)
+{
+ float __f = __X[0];
+ return (__v16sf){ __f, __f, __f, __f,
+ __f, __f, __f, __f,
+ __f, __f, __f, __f,
+ __f, __f, __f, __f };
+}
+
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_broadcastsd_pd(__m128d __X)
+{
+ double __d = __X[0];
+ return (__v8df){ __d, __d, __d, __d,
+ __d, __d, __d, __d };
+}
+
+/* Cast between vector types */
+
+static __inline __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_castpd256_pd512(__m256d __a)
+{
+ return __builtin_shufflevector(__a, __a, 0, 1, 2, 3, -1, -1, -1, -1);
+}
+
+static __inline __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_castps256_ps512(__m256 __a)
+{
+ return __builtin_shufflevector(__a, __a, 0, 1, 2, 3, 4, 5, 6, 7,
+ -1, -1, -1, -1, -1, -1, -1, -1);
+}
+
+static __inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm512_castpd512_pd128(__m512d __a)
+{
+ return __builtin_shufflevector(__a, __a, 0, 1);
+}
+
+static __inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm512_castps512_ps128(__m512 __a)
+{
+ return __builtin_shufflevector(__a, __a, 0, 1, 2, 3);
+}
+
+/* Arithmetic */
+
+static __inline __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_add_pd(__m512d __a, __m512d __b)
+{
+ return __a + __b;
+}
+
+static __inline __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_add_ps(__m512 __a, __m512 __b)
+{
+ return __a + __b;
+}
+
+static __inline __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_mul_pd(__m512d __a, __m512d __b)
+{
+ return __a * __b;
+}
+
+static __inline __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_mul_ps(__m512 __a, __m512 __b)
+{
+ return __a * __b;
+}
+
+static __inline __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_sub_pd(__m512d __a, __m512d __b)
+{
+ return __a - __b;
+}
+
+static __inline __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_sub_ps(__m512 __a, __m512 __b)
+{
+ return __a - __b;
+}
+
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_max_pd(__m512d __A, __m512d __B)
+{
+ return (__m512d) __builtin_ia32_maxpd512_mask ((__v8df) __A,
+ (__v8df) __B,
+ (__v8df)
+ _mm512_setzero_pd (),
+ (__mmask8) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_max_ps(__m512 __A, __m512 __B)
+{
+ return (__m512) __builtin_ia32_maxps512_mask ((__v16sf) __A,
+ (__v16sf) __B,
+ (__v16sf)
+ _mm512_setzero_ps (),
+ (__mmask16) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __m512i
+__attribute__ ((__always_inline__, __nodebug__))
+_mm512_max_epi32(__m512i __A, __m512i __B)
+{
+ return (__m512i) __builtin_ia32_pmaxsd512_mask ((__v16si) __A,
+ (__v16si) __B,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) -1);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_max_epu32(__m512i __A, __m512i __B)
+{
+ return (__m512i) __builtin_ia32_pmaxud512_mask ((__v16si) __A,
+ (__v16si) __B,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) -1);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_max_epi64(__m512i __A, __m512i __B)
+{
+ return (__m512i) __builtin_ia32_pmaxsq512_mask ((__v8di) __A,
+ (__v8di) __B,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) -1);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_max_epu64(__m512i __A, __m512i __B)
+{
+ return (__m512i) __builtin_ia32_pmaxuq512_mask ((__v8di) __A,
+ (__v8di) __B,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) -1);
+}
+
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_min_pd(__m512d __A, __m512d __B)
+{
+ return (__m512d) __builtin_ia32_minpd512_mask ((__v8df) __A,
+ (__v8df) __B,
+ (__v8df)
+ _mm512_setzero_pd (),
+ (__mmask8) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_min_ps(__m512 __A, __m512 __B)
+{
+ return (__m512) __builtin_ia32_minps512_mask ((__v16sf) __A,
+ (__v16sf) __B,
+ (__v16sf)
+ _mm512_setzero_ps (),
+ (__mmask16) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __m512i
+__attribute__ ((__always_inline__, __nodebug__))
+_mm512_min_epi32(__m512i __A, __m512i __B)
+{
+ return (__m512i) __builtin_ia32_pminsd512_mask ((__v16si) __A,
+ (__v16si) __B,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) -1);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_min_epu32(__m512i __A, __m512i __B)
+{
+ return (__m512i) __builtin_ia32_pminud512_mask ((__v16si) __A,
+ (__v16si) __B,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) -1);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_min_epi64(__m512i __A, __m512i __B)
+{
+ return (__m512i) __builtin_ia32_pminsq512_mask ((__v8di) __A,
+ (__v8di) __B,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) -1);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_min_epu64(__m512i __A, __m512i __B)
+{
+ return (__m512i) __builtin_ia32_pminuq512_mask ((__v8di) __A,
+ (__v8di) __B,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) -1);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_mul_epi32(__m512i __X, __m512i __Y)
+{
+ return (__m512i) __builtin_ia32_pmuldq512_mask ((__v16si) __X,
+ (__v16si) __Y,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) -1);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_mul_epu32(__m512i __X, __m512i __Y)
+{
+ return (__m512i) __builtin_ia32_pmuludq512_mask ((__v16si) __X,
+ (__v16si) __Y,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) -1);
+}
+
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_sqrt_pd(__m512d a)
+{
+ return (__m512d)__builtin_ia32_sqrtpd512_mask((__v8df)a,
+ (__v8df) _mm512_setzero_pd (),
+ (__mmask8) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_sqrt_ps(__m512 a)
+{
+ return (__m512)__builtin_ia32_sqrtps512_mask((__v16sf)a,
+ (__v16sf) _mm512_setzero_ps (),
+ (__mmask16) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_rsqrt14_pd(__m512d __A)
+{
+ return (__m512d) __builtin_ia32_rsqrt14pd512_mask ((__v8df) __A,
+ (__v8df)
+ _mm512_setzero_pd (),
+ (__mmask8) -1);}
+
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_rsqrt14_ps(__m512 __A)
+{
+ return (__m512) __builtin_ia32_rsqrt14ps512_mask ((__v16sf) __A,
+ (__v16sf)
+ _mm512_setzero_ps (),
+ (__mmask16) -1);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_rsqrt14_ss(__m128 __A, __m128 __B)
+{
+ return (__m128) __builtin_ia32_rsqrt14ss_mask ((__v4sf) __A,
+ (__v4sf) __B,
+ (__v4sf)
+ _mm_setzero_ps (),
+ (__mmask8) -1);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_rsqrt14_sd(__m128d __A, __m128d __B)
+{
+ return (__m128d) __builtin_ia32_rsqrt14sd_mask ((__v2df) __A,
+ (__v2df) __B,
+ (__v2df)
+ _mm_setzero_pd (),
+ (__mmask8) -1);
+}
+
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_rcp14_pd(__m512d __A)
+{
+ return (__m512d) __builtin_ia32_rcp14pd512_mask ((__v8df) __A,
+ (__v8df)
+ _mm512_setzero_pd (),
+ (__mmask8) -1);
+}
+
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_rcp14_ps(__m512 __A)
+{
+ return (__m512) __builtin_ia32_rcp14ps512_mask ((__v16sf) __A,
+ (__v16sf)
+ _mm512_setzero_ps (),
+ (__mmask16) -1);
+}
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_rcp14_ss(__m128 __A, __m128 __B)
+{
+ return (__m128) __builtin_ia32_rcp14ss_mask ((__v4sf) __A,
+ (__v4sf) __B,
+ (__v4sf)
+ _mm_setzero_ps (),
+ (__mmask8) -1);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_rcp14_sd(__m128d __A, __m128d __B)
+{
+ return (__m128d) __builtin_ia32_rcp14sd_mask ((__v2df) __A,
+ (__v2df) __B,
+ (__v2df)
+ _mm_setzero_pd (),
+ (__mmask8) -1);
+}
+
+static __inline __m512 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_floor_ps(__m512 __A)
+{
+ return (__m512) __builtin_ia32_rndscaleps_mask ((__v16sf) __A,
+ _MM_FROUND_FLOOR,
+ (__v16sf) __A, -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __m512d __attribute__ ((__always_inline__, __nodebug__))
+_mm512_floor_pd(__m512d __A)
+{
+ return (__m512d) __builtin_ia32_rndscalepd_mask ((__v8df) __A,
+ _MM_FROUND_FLOOR,
+ (__v8df) __A, -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __m512 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_ceil_ps(__m512 __A)
+{
+ return (__m512) __builtin_ia32_rndscaleps_mask ((__v16sf) __A,
+ _MM_FROUND_CEIL,
+ (__v16sf) __A, -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __m512d __attribute__ ((__always_inline__, __nodebug__))
+_mm512_ceil_pd(__m512d __A)
+{
+ return (__m512d) __builtin_ia32_rndscalepd_mask ((__v8df) __A,
+ _MM_FROUND_CEIL,
+ (__v8df) __A, -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __m512i __attribute__ (( __always_inline__, __nodebug__))
+_mm512_abs_epi64(__m512i __A)
+{
+ return (__m512i) __builtin_ia32_pabsq512_mask ((__v8di) __A,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) -1);
+}
+
+static __inline __m512i __attribute__ (( __always_inline__, __nodebug__))
+_mm512_abs_epi32(__m512i __A)
+{
+ return (__m512i) __builtin_ia32_pabsd512_mask ((__v16si) __A,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) -1);
+}
+
+static __inline __m512 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_roundscale_ps(__m512 __A, const int __imm)
+{
+ return (__m512) __builtin_ia32_rndscaleps_mask ((__v16sf) __A, __imm,
+ (__v16sf) __A, -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+static __inline __m512d __attribute__ ((__always_inline__, __nodebug__))
+_mm512_roundscale_pd(__m512d __A, const int __imm)
+{
+ return (__m512d) __builtin_ia32_rndscalepd_mask ((__v8df) __A, __imm,
+ (__v8df) __A, -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_fmadd_pd(__m512d __A, __m512d __B, __m512d __C)
+{
+ return (__m512d)
+ __builtin_ia32_vfmaddpd512_mask(__A,
+ __B,
+ __C,
+ (__mmask8) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_fmsub_pd(__m512d __A, __m512d __B, __m512d __C)
+{
+ return (__m512d)
+ __builtin_ia32_vfmsubpd512_mask(__A,
+ __B,
+ __C,
+ (__mmask8) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline__ __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_fnmadd_pd(__m512d __A, __m512d __B, __m512d __C)
+{
+ return (__m512d)
+ __builtin_ia32_vfnmaddpd512_mask(__A,
+ __B,
+ __C,
+ (__mmask8) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_fmadd_ps(__m512 __A, __m512 __B, __m512 __C)
+{
+ return (__m512)
+ __builtin_ia32_vfmaddps512_mask(__A,
+ __B,
+ __C,
+ (__mmask16) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_fmsub_ps(__m512 __A, __m512 __B, __m512 __C)
+{
+ return (__m512)
+ __builtin_ia32_vfmsubps512_mask(__A,
+ __B,
+ __C,
+ (__mmask16) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline__ __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_fnmadd_ps(__m512 __A, __m512 __B, __m512 __C)
+{
+ return (__m512)
+ __builtin_ia32_vfnmaddps512_mask(__A,
+ __B,
+ __C,
+ (__mmask16) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+/* Vector permutations */
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_permutex2var_epi32(__m512i __A, __m512i __I, __m512i __B)
+{
+ return (__m512i) __builtin_ia32_vpermt2vard512_mask ((__v16si) __I
+ /* idx */ ,
+ (__v16si) __A,
+ (__v16si) __B,
+ (__mmask16) -1);
+}
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_permutex2var_epi64(__m512i __A, __m512i __I, __m512i __B)
+{
+ return (__m512i) __builtin_ia32_vpermt2varq512_mask ((__v8di) __I
+ /* idx */ ,
+ (__v8di) __A,
+ (__v8di) __B,
+ (__mmask8) -1);
+}
+
+static __inline __m512d __attribute__ ((__always_inline__, __nodebug__))
+_mm512_permutex2var_pd(__m512d __A, __m512i __I, __m512d __B)
+{
+ return (__m512d) __builtin_ia32_vpermt2varpd512_mask ((__v8di) __I
+ /* idx */ ,
+ (__v8df) __A,
+ (__v8df) __B,
+ (__mmask8) -1);
+}
+static __inline __m512 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_permutex2var_ps(__m512 __A, __m512i __I, __m512 __B)
+{
+ return (__m512) __builtin_ia32_vpermt2varps512_mask ((__v16si) __I
+ /* idx */ ,
+ (__v16sf) __A,
+ (__v16sf) __B,
+ (__mmask16) -1);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_valign_epi64(__m512i __A, __m512i __B, const int __I)
+{
+ return (__m512i) __builtin_ia32_alignq512_mask((__v8di)__A,
+ (__v8di)__B,
+ __I,
+ (__v8di)_mm512_setzero_si512(),
+ (__mmask8) -1);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_valign_epi32(__m512i __A, __m512i __B, const int __I)
+{
+ return (__m512i)__builtin_ia32_alignd512_mask((__v16si)__A,
+ (__v16si)__B,
+ __I,
+ (__v16si)_mm512_setzero_si512(),
+ (__mmask16) -1);
+}
+
+/* Vector Blend */
+
+static __inline __m512d __attribute__ ((__always_inline__, __nodebug__))
+_mm512_mask_blend_pd(__mmask8 __U, __m512d __A, __m512d __W)
+{
+ return (__m512d) __builtin_ia32_blendmpd_512_mask ((__v8df) __A,
+ (__v8df) __W,
+ (__mmask8) __U);
+}
+
+static __inline __m512 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_mask_blend_ps(__mmask16 __U, __m512 __A, __m512 __W)
+{
+ return (__m512) __builtin_ia32_blendmps_512_mask ((__v16sf) __A,
+ (__v16sf) __W,
+ (__mmask16) __U);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_mask_blend_epi64(__mmask8 __U, __m512i __A, __m512i __W)
+{
+ return (__m512i) __builtin_ia32_blendmq_512_mask ((__v8di) __A,
+ (__v8di) __W,
+ (__mmask8) __U);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_mask_blend_epi32(__mmask16 __U, __m512i __A, __m512i __W)
+{
+ return (__m512i) __builtin_ia32_blendmd_512_mask ((__v16si) __A,
+ (__v16si) __W,
+ (__mmask16) __U);
+}
+
+/* Compare */
+
+static __inline __mmask16 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cmp_ps_mask(__m512 a, __m512 b, const int p)
+{
+ return (__mmask16) __builtin_ia32_cmpps512_mask ((__v16sf) a,
+ (__v16sf) b, p, (__mmask16) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __mmask8 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cmp_pd_mask(__m512d __X, __m512d __Y, const int __P)
+{
+ return (__mmask8) __builtin_ia32_cmppd512_mask ((__v8df) __X,
+ (__v8df) __Y, __P,
+ (__mmask8) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+/* Conversion */
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cvttps_epu32(__m512 __A)
+{
+ return (__m512i) __builtin_ia32_cvttps2udq512_mask ((__v16sf) __A,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __m512 __attribute__ (( __always_inline__, __nodebug__))
+_mm512_cvt_roundepi32_ps(__m512i __A, const int __R)
+{
+ return (__m512) __builtin_ia32_cvtdq2ps512_mask ((__v16si) __A,
+ (__v16sf)
+ _mm512_setzero_ps (),
+ (__mmask16) -1,
+ __R);
+}
+
+static __inline __m512 __attribute__ (( __always_inline__, __nodebug__))
+_mm512_cvt_roundepu32_ps(__m512i __A, const int __R)
+{
+ return (__m512) __builtin_ia32_cvtudq2ps512_mask ((__v16si) __A,
+ (__v16sf)
+ _mm512_setzero_ps (),
+ (__mmask16) -1,
+ __R);
+}
+
+static __inline __m512d __attribute__ (( __always_inline__, __nodebug__))
+_mm512_cvtepi32_pd(__m256i __A)
+{
+ return (__m512d) __builtin_ia32_cvtdq2pd512_mask ((__v8si) __A,
+ (__v8df)
+ _mm512_setzero_pd (),
+ (__mmask8) -1);
+}
+
+static __inline __m512d __attribute__ (( __always_inline__, __nodebug__))
+_mm512_cvtepu32_pd(__m256i __A)
+{
+ return (__m512d) __builtin_ia32_cvtudq2pd512_mask ((__v8si) __A,
+ (__v8df)
+ _mm512_setzero_pd (),
+ (__mmask8) -1);
+}
+static __inline __m256 __attribute__ (( __always_inline__, __nodebug__))
+_mm512_cvt_roundpd_ps(__m512d __A, const int __R)
+{
+ return (__m256) __builtin_ia32_cvtpd2ps512_mask ((__v8df) __A,
+ (__v8sf)
+ _mm256_setzero_ps (),
+ (__mmask8) -1,
+ __R);
+}
+
+static __inline __m256i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cvtps_ph(__m512 __A, const int __I)
+{
+ return (__m256i) __builtin_ia32_vcvtps2ph512_mask ((__v16sf) __A,
+ __I,
+ (__v16hi)
+ _mm256_setzero_si256 (),
+ -1);
+}
+
+static __inline __m512 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cvtph_ps(__m256i __A)
+{
+ return (__m512) __builtin_ia32_vcvtph2ps512_mask ((__v16hi) __A,
+ (__v16sf)
+ _mm512_setzero_ps (),
+ (__mmask16) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_cvttps_epi32(__m512 a)
+{
+ return (__m512i)
+ __builtin_ia32_cvttps2dq512_mask((__v16sf) a,
+ (__v16si) _mm512_setzero_si512 (),
+ (__mmask16) -1, _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __m256i __attribute__((__always_inline__, __nodebug__))
+_mm512_cvttpd_epi32(__m512d a)
+{
+ return (__m256i)__builtin_ia32_cvttpd2dq512_mask((__v8df) a,
+ (__v8si)_mm256_setzero_si256(),
+ (__mmask8) -1,
+ _MM_FROUND_CUR_DIRECTION);
+}
+
+static __inline __m256i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cvtt_roundpd_epi32(__m512d __A, const int __R)
+{
+ return (__m256i) __builtin_ia32_cvttpd2dq512_mask ((__v8df) __A,
+ (__v8si)
+ _mm256_setzero_si256 (),
+ (__mmask8) -1,
+ __R);
+}
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cvtt_roundps_epi32(__m512 __A, const int __R)
+{
+ return (__m512i) __builtin_ia32_cvttps2dq512_mask ((__v16sf) __A,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) -1,
+ __R);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cvt_roundps_epi32(__m512 __A, const int __R)
+{
+ return (__m512i) __builtin_ia32_cvtps2dq512_mask ((__v16sf) __A,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) -1,
+ __R);
+}
+static __inline __m256i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cvt_roundpd_epi32(__m512d __A, const int __R)
+{
+ return (__m256i) __builtin_ia32_cvtpd2dq512_mask ((__v8df) __A,
+ (__v8si)
+ _mm256_setzero_si256 (),
+ (__mmask8) -1,
+ __R);
+}
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cvt_roundps_epu32(__m512 __A, const int __R)
+{
+ return (__m512i) __builtin_ia32_cvtps2udq512_mask ((__v16sf) __A,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) -1,
+ __R);
+}
+static __inline __m256i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_cvt_roundpd_epu32(__m512d __A, const int __R)
+{
+ return (__m256i) __builtin_ia32_cvtpd2udq512_mask ((__v8df) __A,
+ (__v8si)
+ _mm256_setzero_si256 (),
+ (__mmask8) -1,
+ __R);
+}
+
+/* Unpack and Interleave */
+static __inline __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_unpackhi_pd(__m512d __a, __m512d __b)
+{
+ return __builtin_shufflevector(__a, __b, 1, 9, 1+2, 9+2, 1+4, 9+4, 1+6, 9+6);
+}
+
+static __inline __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_unpacklo_pd(__m512d __a, __m512d __b)
+{
+ return __builtin_shufflevector(__a, __b, 0, 8, 0+2, 8+2, 0+4, 8+4, 0+6, 8+6);
+}
+
+static __inline __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_unpackhi_ps(__m512 __a, __m512 __b)
+{
+ return __builtin_shufflevector(__a, __b,
+ 2, 18, 3, 19,
+ 2+4, 18+4, 3+4, 19+4,
+ 2+8, 18+8, 3+8, 19+8,
+ 2+12, 18+12, 3+12, 19+12);
+}
+
+static __inline __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_unpacklo_ps(__m512 __a, __m512 __b)
+{
+ return __builtin_shufflevector(__a, __b,
+ 0, 16, 1, 17,
+ 0+4, 16+4, 1+4, 17+4,
+ 0+8, 16+8, 1+8, 17+8,
+ 0+12, 16+12, 1+12, 17+12);
+}
+
+/* Bit Test */
+
+static __inline __mmask16 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_test_epi32_mask(__m512i __A, __m512i __B)
+{
+ return (__mmask16) __builtin_ia32_ptestmd512 ((__v16si) __A,
+ (__v16si) __B,
+ (__mmask16) -1);
+}
+
+static __inline __mmask8 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_test_epi64_mask(__m512i __A, __m512i __B)
+{
+ return (__mmask8) __builtin_ia32_ptestmq512 ((__v8di) __A,
+ (__v8di) __B,
+ (__mmask8) -1);
+}
+
+/* SIMD load ops */
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_maskz_loadu_epi32(__mmask16 __U, void const *__P)
+{
+ return (__m512i) __builtin_ia32_loaddqusi512_mask ((const __v16si *)__P,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) __U);
+}
+
+static __inline __m512i __attribute__ ((__always_inline__, __nodebug__))
+_mm512_maskz_loadu_epi64(__mmask8 __U, void const *__P)
+{
+ return (__m512i) __builtin_ia32_loaddqudi512_mask ((const __v8di *)__P,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) __U);
+}
+
+static __inline __m512 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_maskz_loadu_ps(__mmask16 __U, void const *__P)
+{
+ return (__m512) __builtin_ia32_loadups512_mask ((const __v16sf *)__P,
+ (__v16sf)
+ _mm512_setzero_ps (),
+ (__mmask16) __U);
+}
+
+static __inline __m512d __attribute__ ((__always_inline__, __nodebug__))
+_mm512_maskz_loadu_pd(__mmask8 __U, void const *__P)
+{
+ return (__m512d) __builtin_ia32_loadupd512_mask ((const __v8df *)__P,
+ (__v8df)
+ _mm512_setzero_pd (),
+ (__mmask8) __U);
+}
+
+static __inline __m512d __attribute__((__always_inline__, __nodebug__))
+_mm512_loadu_pd(double const *__p)
+{
+ struct __loadu_pd {
+ __m512d __v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_pd*)__p)->__v;
+}
+
+static __inline __m512 __attribute__((__always_inline__, __nodebug__))
+_mm512_loadu_ps(float const *__p)
+{
+ struct __loadu_ps {
+ __m512 __v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_ps*)__p)->__v;
+}
+
+/* SIMD store ops */
+
+static __inline void __attribute__ ((__always_inline__, __nodebug__))
+_mm512_mask_storeu_epi64(void *__P, __mmask8 __U, __m512i __A)
+{
+ __builtin_ia32_storedqudi512_mask ((__v8di *)__P, (__v8di) __A,
+ (__mmask8) __U);
+}
+
+static __inline void __attribute__ ((__always_inline__, __nodebug__))
+_mm512_mask_storeu_epi32(void *__P, __mmask16 __U, __m512i __A)
+{
+ __builtin_ia32_storedqusi512_mask ((__v16si *)__P, (__v16si) __A,
+ (__mmask16) __U);
+}
+
+static __inline void __attribute__ ((__always_inline__, __nodebug__))
+_mm512_mask_storeu_pd(void *__P, __mmask8 __U, __m512d __A)
+{
+ __builtin_ia32_storeupd512_mask ((__v8df *)__P, (__v8df) __A, (__mmask8) __U);
+}
+
+static __inline void __attribute__ ((__always_inline__, __nodebug__))
+_mm512_storeu_pd(void *__P, __m512d __A)
+{
+ __builtin_ia32_storeupd512_mask((__v8df *)__P, (__v8df)__A, (__mmask8)-1);
+}
+
+static __inline void __attribute__ ((__always_inline__, __nodebug__))
+_mm512_mask_storeu_ps(void *__P, __mmask16 __U, __m512 __A)
+{
+ __builtin_ia32_storeups512_mask ((__v16sf *)__P, (__v16sf) __A,
+ (__mmask16) __U);
+}
+
+static __inline void __attribute__ ((__always_inline__, __nodebug__))
+_mm512_storeu_ps(void *__P, __m512 __A)
+{
+ __builtin_ia32_storeups512_mask((__v16sf *)__P, (__v16sf)__A, (__mmask16)-1);
+}
+
+static __inline void __attribute__ ((__always_inline__, __nodebug__))
+_mm512_store_ps(void *__P, __m512 __A)
+{
+ *(__m512*)__P = __A;
+}
+
+static __inline void __attribute__ ((__always_inline__, __nodebug__))
+_mm512_store_pd(void *__P, __m512d __A)
+{
+ *(__m512d*)__P = __A;
+}
+
+/* Mask ops */
+
+static __inline __mmask16 __attribute__ ((__always_inline__, __nodebug__))
+_mm512_knot(__mmask16 __M)
+{
+ return __builtin_ia32_knothi(__M);
+}
+
+/* Integer compare */
+
+static __inline__ __mmask16 __attribute__((__always_inline__, __nodebug__))
+_mm512_cmpeq_epi32_mask(__m512i __a, __m512i __b) {
+ return (__mmask16)__builtin_ia32_pcmpeqd512_mask((__v16si)__a, (__v16si)__b,
+ (__mmask16)-1);
+}
+
+static __inline__ __mmask16 __attribute__((__always_inline__, __nodebug__))
+_mm512_mask_cmpeq_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
+ return (__mmask16)__builtin_ia32_pcmpeqd512_mask((__v16si)__a, (__v16si)__b,
+ __u);
+}
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm512_mask_cmpeq_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqq512_mask((__v8di)__a, (__v8di)__b,
+ __u);
+}
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm512_cmpeq_epi64_mask(__m512i __a, __m512i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqq512_mask((__v8di)__a, (__v8di)__b,
+ (__mmask8)-1);
+}
+
+#endif // __AVX512FINTRIN_H
diff --git a/lib/Headers/avx512vlbwintrin.h b/lib/Headers/avx512vlbwintrin.h
new file mode 100644
index 000000000000..11333f851756
--- /dev/null
+++ b/lib/Headers/avx512vlbwintrin.h
@@ -0,0 +1,83 @@
+/*===---- avx512vlbwintrin.h - AVX512VL and AVX512BW intrinsics ----------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __IMMINTRIN_H
+#error "Never use <avx512vlbwintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __AVX512VLBWINTRIN_H
+#define __AVX512VLBWINTRIN_H
+
+/* Integer compare */
+
+static __inline__ __mmask16 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_epi8_mask(__m128i __a, __m128i __b) {
+ return (__mmask16)__builtin_ia32_pcmpeqb128_mask((__v16qi)__a, (__v16qi)__b,
+ (__mmask16)-1);
+}
+
+static __inline__ __mmask16 __attribute__((__always_inline__, __nodebug__))
+_mm_mask_cmpeq_epi8_mask(__mmask16 __u, __m128i __a, __m128i __b) {
+ return (__mmask16)__builtin_ia32_pcmpeqb128_mask((__v16qi)__a, (__v16qi)__b,
+ __u);
+}
+
+
+static __inline__ __mmask32 __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpeq_epi8_mask(__m256i __a, __m256i __b) {
+ return (__mmask32)__builtin_ia32_pcmpeqb256_mask((__v32qi)__a, (__v32qi)__b,
+ (__mmask32)-1);
+}
+
+static __inline__ __mmask32 __attribute__((__always_inline__, __nodebug__))
+_mm256_mask_cmpeq_epi8_mask(__mmask32 __u, __m256i __a, __m256i __b) {
+ return (__mmask32)__builtin_ia32_pcmpeqb256_mask((__v32qi)__a, (__v32qi)__b,
+ __u);
+}
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_epi16_mask(__m128i __a, __m128i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqw128_mask((__v8hi)__a, (__v8hi)__b,
+ (__mmask8)-1);
+}
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm_mask_cmpeq_epi16_mask(__mmask8 __u, __m128i __a, __m128i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqw128_mask((__v8hi)__a, (__v8hi)__b,
+ __u);
+}
+
+
+static __inline__ __mmask16 __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpeq_epi16_mask(__m256i __a, __m256i __b) {
+ return (__mmask16)__builtin_ia32_pcmpeqw256_mask((__v16hi)__a, (__v16hi)__b,
+ (__mmask16)-1);
+}
+
+static __inline__ __mmask16 __attribute__((__always_inline__, __nodebug__))
+_mm256_mask_cmpeq_epi16_mask(__mmask16 __u, __m256i __a, __m256i __b) {
+ return (__mmask16)__builtin_ia32_pcmpeqw256_mask((__v16hi)__a, (__v16hi)__b,
+ __u);
+}
+
+#endif /* __AVX512VLBWINTRIN_H */
diff --git a/lib/Headers/avx512vlintrin.h b/lib/Headers/avx512vlintrin.h
new file mode 100644
index 000000000000..8a374b102676
--- /dev/null
+++ b/lib/Headers/avx512vlintrin.h
@@ -0,0 +1,83 @@
+/*===---- avx512vlintrin.h - AVX512VL intrinsics ---------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __IMMINTRIN_H
+#error "Never use <avx512vlintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __AVX512VLINTRIN_H
+#define __AVX512VLINTRIN_H
+
+/* Integer compare */
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_epi32_mask(__m128i __a, __m128i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqd128_mask((__v4si)__a, (__v4si)__b,
+ (__mmask8)-1);
+}
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm_mask_cmpeq_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqd128_mask((__v4si)__a, (__v4si)__b,
+ __u);
+}
+
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpeq_epi32_mask(__m256i __a, __m256i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqd256_mask((__v8si)__a, (__v8si)__b,
+ (__mmask8)-1);
+}
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm256_mask_cmpeq_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqd256_mask((__v8si)__a, (__v8si)__b,
+ __u);
+}
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_epi64_mask(__m128i __a, __m128i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqq128_mask((__v2di)__a, (__v2di)__b,
+ (__mmask8)-1);
+}
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm_mask_cmpeq_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqq128_mask((__v2di)__a, (__v2di)__b,
+ __u);
+}
+
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpeq_epi64_mask(__m256i __a, __m256i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqq256_mask((__v4di)__a, (__v4di)__b,
+ (__mmask8)-1);
+}
+
+static __inline__ __mmask8 __attribute__((__always_inline__, __nodebug__))
+_mm256_mask_cmpeq_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) {
+ return (__mmask8)__builtin_ia32_pcmpeqq256_mask((__v4di)__a, (__v4di)__b,
+ __u);
+}
+
+#endif /* __AVX512VLINTRIN_H */
diff --git a/lib/Headers/bmiintrin.h b/lib/Headers/bmiintrin.h
index 43c4a5e5de3c..0e5fd5551fb3 100644
--- a/lib/Headers/bmiintrin.h
+++ b/lib/Headers/bmiintrin.h
@@ -43,7 +43,7 @@
static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
__tzcnt_u16(unsigned short __X)
{
- return __builtin_ctzs(__X);
+ return __X ? __builtin_ctzs(__X) : 16;
}
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
@@ -87,7 +87,7 @@ __blsr_u32(unsigned int __X)
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
__tzcnt_u32(unsigned int __X)
{
- return __builtin_ctz(__X);
+ return __X ? __builtin_ctz(__X) : 32;
}
#ifdef __x86_64__
@@ -140,7 +140,7 @@ __blsr_u64(unsigned long long __X)
static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
__tzcnt_u64(unsigned long long __X)
{
- return __builtin_ctzll(__X);
+ return __X ? __builtin_ctzll(__X) : 64;
}
#endif /* __x86_64__ */
diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h
index f9254e9738e7..5da02e0e5152 100644
--- a/lib/Headers/cpuid.h
+++ b/lib/Headers/cpuid.h
@@ -25,6 +25,60 @@
#error this header is for x86 only
#endif
+/* Responses identification request with %eax 0 */
+/* AMD: "AuthenticAMD" */
+#define signature_AMD_ebx 0x68747541
+#define signature_AMD_edx 0x69746e65
+#define signature_AMD_ecx 0x444d4163
+/* CENTAUR: "CentaurHauls" */
+#define signature_CENTAUR_ebx 0x746e6543
+#define signature_CENTAUR_edx 0x48727561
+#define signature_CENTAUR_ecx 0x736c7561
+/* CYRIX: "CyrixInstead" */
+#define signature_CYRIX_ebx 0x69727943
+#define signature_CYRIX_edx 0x736e4978
+#define signature_CYRIX_ecx 0x64616574
+/* INTEL: "GenuineIntel" */
+#define signature_INTEL_ebx 0x756e6547
+#define signature_INTEL_edx 0x49656e69
+#define signature_INTEL_ecx 0x6c65746e
+/* TM1: "TransmetaCPU" */
+#define signature_TM1_ebx 0x6e617254
+#define signature_TM1_edx 0x74656d73
+#define signature_TM1_ecx 0x55504361
+/* TM2: "GenuineTMx86" */
+#define signature_TM2_ebx 0x756e6547
+#define signature_TM2_edx 0x54656e69
+#define signature_TM2_ecx 0x3638784d
+/* NSC: "Geode by NSC" */
+#define signature_NSC_ebx 0x646f6547
+#define signature_NSC_edx 0x43534e20
+#define signature_NSC_ecx 0x79622065
+/* NEXGEN: "NexGenDriven" */
+#define signature_NEXGEN_ebx 0x4778654e
+#define signature_NEXGEN_edx 0x72446e65
+#define signature_NEXGEN_ecx 0x6e657669
+/* RISE: "RiseRiseRise" */
+#define signature_RISE_ebx 0x65736952
+#define signature_RISE_edx 0x65736952
+#define signature_RISE_ecx 0x65736952
+/* SIS: "SiS SiS SiS " */
+#define signature_SIS_ebx 0x20536953
+#define signature_SIS_edx 0x20536953
+#define signature_SIS_ecx 0x20536953
+/* UMC: "UMC UMC UMC " */
+#define signature_UMC_ebx 0x20434d55
+#define signature_UMC_edx 0x20434d55
+#define signature_UMC_ecx 0x20434d55
+/* VIA: "VIA VIA VIA " */
+#define signature_VIA_ebx 0x20414956
+#define signature_VIA_edx 0x20414956
+#define signature_VIA_ecx 0x20414956
+/* VORTEX: "Vortex86 SoC" */
+#define signature_VORTEX_ebx 0x74726f56
+#define signature_VORTEX_edx 0x36387865
+#define signature_VORTEX_ecx 0x436f5320
+
/* Features in %ecx for level 1 */
#define bit_SSE3 0x00000001
#define bit_PCLMULQDQ 0x00000002
@@ -53,7 +107,7 @@
#define bit_XSAVE 0x04000000
#define bit_OSXSAVE 0x08000000
#define bit_AVX 0x10000000
-#define bit_RDRAND 0x40000000
+#define bit_RDRND 0x40000000
/* Features in %edx for level 1 */
#define bit_FPU 0x00000001
@@ -92,31 +146,29 @@
#define bit_SMEP 0x00000080
#define bit_ENH_MOVSB 0x00000200
-/* PIC on i386 uses %ebx, so preserve it. */
#if __i386__
#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \
- __asm(" pushl %%ebx\n" \
+ __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
+ : "0"(__level))
+
+#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \
+ __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
+ : "0"(__level), "2"(__count))
+#else
+/* x86-64 uses %rbx as the base register, so preserve it. */
+#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \
+ __asm(" xchgq %%rbx,%q1\n" \
" cpuid\n" \
- " mov %%ebx,%1\n" \
- " popl %%ebx" \
+ " xchgq %%rbx,%q1" \
: "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \
: "0"(__level))
#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \
- __asm(" pushl %%ebx\n" \
+ __asm(" xchgq %%rbx,%q1\n" \
" cpuid\n" \
- " mov %%ebx,%1\n" \
- " popl %%ebx" \
+ " xchgq %%rbx,%q1" \
: "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \
: "0"(__level), "2"(__count))
-#else
-#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \
- __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
- : "0"(__level))
-
-#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \
- __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
- : "0"(__level), "2"(__count))
#endif
static __inline int __get_cpuid (unsigned int __level, unsigned int *__eax,
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index b3f8569524b9..28d004309cf4 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -155,148 +155,148 @@ _mm_xor_pd(__m128d __a, __m128d __b)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__a, __b, 0);
+ return (__m128d)__builtin_ia32_cmpeqpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__a, __b, 1);
+ return (__m128d)__builtin_ia32_cmpltpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmple_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__a, __b, 2);
+ return (__m128d)__builtin_ia32_cmplepd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__b, __a, 1);
+ return (__m128d)__builtin_ia32_cmpltpd(__b, __a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpge_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__b, __a, 2);
+ return (__m128d)__builtin_ia32_cmplepd(__b, __a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpord_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__a, __b, 7);
+ return (__m128d)__builtin_ia32_cmpordpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpunord_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__a, __b, 3);
+ return (__m128d)__builtin_ia32_cmpunordpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpneq_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__a, __b, 4);
+ return (__m128d)__builtin_ia32_cmpneqpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnlt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__a, __b, 5);
+ return (__m128d)__builtin_ia32_cmpnltpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnle_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__a, __b, 6);
+ return (__m128d)__builtin_ia32_cmpnlepd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpngt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__b, __a, 5);
+ return (__m128d)__builtin_ia32_cmpnltpd(__b, __a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnge_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(__b, __a, 6);
+ return (__m128d)__builtin_ia32_cmpnlepd(__b, __a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__a, __b, 0);
+ return (__m128d)__builtin_ia32_cmpeqsd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__a, __b, 1);
+ return (__m128d)__builtin_ia32_cmpltsd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmple_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__a, __b, 2);
+ return (__m128d)__builtin_ia32_cmplesd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_sd(__m128d __a, __m128d __b)
{
- __m128d __c = __builtin_ia32_cmpsd(__b, __a, 1);
+ __m128d __c = __builtin_ia32_cmpltsd(__b, __a);
return (__m128d) { __c[0], __a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpge_sd(__m128d __a, __m128d __b)
{
- __m128d __c = __builtin_ia32_cmpsd(__b, __a, 2);
+ __m128d __c = __builtin_ia32_cmplesd(__b, __a);
return (__m128d) { __c[0], __a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpord_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__a, __b, 7);
+ return (__m128d)__builtin_ia32_cmpordsd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpunord_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__a, __b, 3);
+ return (__m128d)__builtin_ia32_cmpunordsd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpneq_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__a, __b, 4);
+ return (__m128d)__builtin_ia32_cmpneqsd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnlt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__a, __b, 5);
+ return (__m128d)__builtin_ia32_cmpnltsd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnle_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(__a, __b, 6);
+ return (__m128d)__builtin_ia32_cmpnlesd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpngt_sd(__m128d __a, __m128d __b)
{
- __m128d __c = __builtin_ia32_cmpsd(__b, __a, 5);
+ __m128d __c = __builtin_ia32_cmpnltsd(__b, __a);
return (__m128d) { __c[0], __a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnge_sd(__m128d __a, __m128d __b)
{
- __m128d __c = __builtin_ia32_cmpsd(__b, __a, 6);
+ __m128d __c = __builtin_ia32_cmpnlesd(__b, __a);
return (__m128d) { __c[0], __a[1] };
}
diff --git a/lib/Headers/float.h b/lib/Headers/float.h
index 02ef6bf611a3..238cf76b053c 100644
--- a/lib/Headers/float.h
+++ b/lib/Headers/float.h
@@ -28,7 +28,7 @@
* additional definitions provided for Windows.
* For more details see http://msdn.microsoft.com/en-us/library/y0ybw9fy.aspx
*/
-#if (defined(__MINGW32__) || defined(_MSC_VER)) && \
+#if (defined(__MINGW32__) || defined(_MSC_VER)) && __STDC_HOSTED__ && \
__has_include_next(<float.h>)
# include_next <float.h>
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index df4bea8c950e..2400fea499bd 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -76,6 +76,26 @@
#include <fmaintrin.h>
#endif
+#ifdef __AVX512F__
+#include <avx512fintrin.h>
+#endif
+
+#ifdef __AVX512VL__
+#include <avx512vlintrin.h>
+#endif
+
+#ifdef __AVX512BW__
+#include <avx512bwintrin.h>
+#endif
+
+#if defined (__AVX512VL__) && defined (__AVX512BW__)
+#include <avx512vlbwintrin.h>
+#endif
+
+#ifdef __AVX512ER__
+#include <avx512erintrin.h>
+#endif
+
#ifdef __RDRND__
static __inline__ int __attribute__((__always_inline__, __nodebug__))
_rdrand16_step(unsigned short *__p)
@@ -98,6 +118,58 @@ _rdrand64_step(unsigned long long *__p)
#endif
#endif /* __RDRND__ */
+#ifdef __FSGSBASE__
+#ifdef __x86_64__
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_readfsbase_u32(void)
+{
+ return __builtin_ia32_rdfsbase32();
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+_readfsbase_u64(void)
+{
+ return __builtin_ia32_rdfsbase64();
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_readgsbase_u32(void)
+{
+ return __builtin_ia32_rdgsbase32();
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+_readgsbase_u64(void)
+{
+ return __builtin_ia32_rdgsbase64();
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_writefsbase_u32(unsigned int __V)
+{
+ return __builtin_ia32_wrfsbase32(__V);
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_writefsbase_u64(unsigned long long __V)
+{
+ return __builtin_ia32_wrfsbase64(__V);
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_writegsbase_u32(unsigned int __V)
+{
+ return __builtin_ia32_wrgsbase32(__V);
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_writegsbase_u64(unsigned long long __V)
+{
+ return __builtin_ia32_wrgsbase64(__V);
+}
+#endif
+#endif /* __FSGSBASE__ */
+
#ifdef __RTM__
#include <rtmintrin.h>
#endif
@@ -115,4 +187,8 @@ _xtest(void)
#include <shaintrin.h>
#endif
+/* Some intrinsics inside adxintrin.h are available only if __ADX__ defined,
+ * whereas others are also available if __ADX__ undefined */
+#include <adxintrin.h>
+
#endif /* __IMMINTRIN_H */
diff --git a/lib/Headers/lzcntintrin.h b/lib/Headers/lzcntintrin.h
index 62ab5ca2f358..35d6659d245b 100644
--- a/lib/Headers/lzcntintrin.h
+++ b/lib/Headers/lzcntintrin.h
@@ -35,20 +35,32 @@
static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
__lzcnt16(unsigned short __X)
{
- return __builtin_clzs(__X);
+ return __X ? __builtin_clzs(__X) : 16;
}
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
__lzcnt32(unsigned int __X)
{
- return __builtin_clz(__X);
+ return __X ? __builtin_clz(__X) : 32;
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_lzcnt_u32(unsigned int __X)
+{
+ return __X ? __builtin_clz(__X) : 32;
}
#ifdef __x86_64__
static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
__lzcnt64(unsigned long long __X)
{
- return __builtin_clzll(__X);
+ return __X ? __builtin_clzll(__X) : 64;
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+_lzcnt_u64(unsigned long long __X)
+{
+ return __X ? __builtin_clzll(__X) : 64;
}
#endif
diff --git a/lib/Headers/module.modulemap b/lib/Headers/module.modulemap
index 9f7944dedbb0..062464ed2e53 100644
--- a/lib/Headers/module.modulemap
+++ b/lib/Headers/module.modulemap
@@ -1,4 +1,4 @@
-module _Builtin_intrinsics [system] {
+module _Builtin_intrinsics [system] [extern_c] {
explicit module altivec {
requires altivec
header "altivec.h"
@@ -7,6 +7,11 @@ module _Builtin_intrinsics [system] {
explicit module arm {
requires arm
+ explicit module acle {
+ header "arm_acle.h"
+ export *
+ }
+
explicit module neon {
requires neon
header "arm_neon.h"
@@ -96,6 +101,17 @@ module _Builtin_intrinsics [system] {
header "avx2intrin.h"
}
+ explicit module avx512f {
+ requires avx512f
+ export avx2
+ header "avx512fintrin.h"
+ }
+
+ explicit module avx512er {
+ requires avx512er
+ header "avx512erintrin.h"
+ }
+
explicit module bmi {
requires bmi
header "bmiintrin.h"
@@ -154,3 +170,7 @@ module _Builtin_intrinsics [system] {
}
}
}
+
+module _Builtin_stddef_max_align_t [system] [extern_c] {
+ header "__stddef_max_align_t.h"
+}
diff --git a/lib/Headers/shaintrin.h b/lib/Headers/shaintrin.h
index 66ed0554b64d..391a4bbc4f0e 100644
--- a/lib/Headers/shaintrin.h
+++ b/lib/Headers/shaintrin.h
@@ -38,37 +38,37 @@
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sha1nexte_epu32(__m128i __X, __m128i __Y)
{
- return __builtin_ia32_sha1nexte(__X, __Y);
+ return (__m128i)__builtin_ia32_sha1nexte((__v4si)__X, (__v4si)__Y);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sha1msg1_epu32(__m128i __X, __m128i __Y)
{
- return __builtin_ia32_sha1msg1(__X, __Y);
+ return (__m128i)__builtin_ia32_sha1msg1((__v4si)__X, (__v4si)__Y);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sha1msg2_epu32(__m128i __X, __m128i __Y)
{
- return __builtin_ia32_sha1msg2(__X, __Y);
+ return (__m128i)__builtin_ia32_sha1msg2((__v4si)__X, (__v4si)__Y);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sha256rnds2_epu32(__m128i __X, __m128i __Y, __m128i __Z)
{
- return __builtin_ia32_sha256rnds2(__X, __Y, __Z);
+ return (__m128i)__builtin_ia32_sha256rnds2((__v4si)__X, (__v4si)__Y, (__v4si)__Z);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sha256msg1_epu32(__m128i __X, __m128i __Y)
{
- return __builtin_ia32_sha256msg1(__X, __Y);
+ return (__m128i)__builtin_ia32_sha256msg1((__v4si)__X, (__v4si)__Y);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sha256msg2_epu32(__m128i __X, __m128i __Y)
{
- return __builtin_ia32_sha256msg2(__X, __Y);
+ return (__m128i)__builtin_ia32_sha256msg2((__v4si)__X, (__v4si)__Y);
}
#endif /* __SHAINTRIN_H */
diff --git a/lib/Headers/stdatomic.h b/lib/Headers/stdatomic.h
new file mode 100644
index 000000000000..e3c34767a21a
--- /dev/null
+++ b/lib/Headers/stdatomic.h
@@ -0,0 +1,190 @@
+/*===---- stdatomic.h - Standard header for atomic types and operations -----===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __CLANG_STDATOMIC_H
+#define __CLANG_STDATOMIC_H
+
+/* If we're hosted, fall back to the system's stdatomic.h. FreeBSD, for
+ * example, already has a Clang-compatible stdatomic.h header.
+ */
+#if __STDC_HOSTED__ && __has_include_next(<stdatomic.h>)
+# include_next <stdatomic.h>
+#else
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 7.17.1 Introduction */
+
+#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
+#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
+#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
+#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
+#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
+#define ATOMIC_SHORT_T_LOCK_FREE __GCC_ATOMIC_SHORT_T_LOCK_FREE
+#define ATOMIC_INT_T_LOCK_FREE __GCC_ATOMIC_INT_T_LOCK_FREE
+#define ATOMIC_LONG_T_LOCK_FREE __GCC_ATOMIC_LONG_T_LOCK_FREE
+#define ATOMIC_LLONG_T_LOCK_FREE __GCC_ATOMIC_LLONG_T_LOCK_FREE
+#define ATOMIC_POINTER_T_LOCK_FREE __GCC_ATOMIC_POINTER_T_LOCK_FREE
+
+/* 7.17.2 Initialization */
+
+#define ATOMIC_VAR_INIT(value) (value)
+#define atomic_init __c11_atomic_init
+
+/* 7.17.3 Order and consistency */
+
+typedef enum memory_order {
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_consume = __ATOMIC_CONSUME,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
+} memory_order;
+
+#define kill_dependency(y) (y)
+
+/* 7.17.4 Fences */
+
+// These should be provided by the libc implementation.
+void atomic_thread_fence(memory_order);
+void atomic_signal_fence(memory_order);
+
+#define atomic_thread_fence(order) __c11_atomic_thread_fence(order)
+#define atomic_signal_fence(order) __c11_atomic_signal_fence(order)
+
+/* 7.17.5 Lock-free property */
+
+#define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj)))
+
+/* 7.17.6 Atomic integer types */
+
+#ifdef __cplusplus
+typedef _Atomic(bool) atomic_bool;
+#else
+typedef _Atomic(_Bool) atomic_bool;
+#endif
+typedef _Atomic(char) atomic_char;
+typedef _Atomic(signed char) atomic_schar;
+typedef _Atomic(unsigned char) atomic_uchar;
+typedef _Atomic(short) atomic_short;
+typedef _Atomic(unsigned short) atomic_ushort;
+typedef _Atomic(int) atomic_int;
+typedef _Atomic(unsigned int) atomic_uint;
+typedef _Atomic(long) atomic_long;
+typedef _Atomic(unsigned long) atomic_ulong;
+typedef _Atomic(long long) atomic_llong;
+typedef _Atomic(unsigned long long) atomic_ullong;
+typedef _Atomic(uint_least16_t) atomic_char16_t;
+typedef _Atomic(uint_least32_t) atomic_char32_t;
+typedef _Atomic(wchar_t) atomic_wchar_t;
+typedef _Atomic(int_least8_t) atomic_int_least8_t;
+typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
+typedef _Atomic(int_least16_t) atomic_int_least16_t;
+typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
+typedef _Atomic(int_least32_t) atomic_int_least32_t;
+typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
+typedef _Atomic(int_least64_t) atomic_int_least64_t;
+typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
+typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
+typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
+typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
+typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
+typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
+typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
+typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
+typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
+typedef _Atomic(intptr_t) atomic_intptr_t;
+typedef _Atomic(uintptr_t) atomic_uintptr_t;
+typedef _Atomic(size_t) atomic_size_t;
+typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
+typedef _Atomic(intmax_t) atomic_intmax_t;
+typedef _Atomic(uintmax_t) atomic_uintmax_t;
+
+/* 7.17.7 Operations on atomic types */
+
+#define atomic_store(object, desired) __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST)
+#define atomic_store_explicit __c11_atomic_store
+
+#define atomic_load(object) __c11_atomic_load(object, __ATOMIC_SEQ_CST)
+#define atomic_load_explicit __c11_atomic_load
+
+#define atomic_exchange(object, desired) __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST)
+#define atomic_exchange_explicit __c11_atomic_exchange
+
+#define atomic_compare_exchange_strong(object, expected, desired) __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong
+
+#define atomic_compare_exchange_weak(object, expected, desired) __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak
+
+#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_add_explicit __c11_atomic_fetch_add
+
+#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub
+
+#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_or_explicit __c11_atomic_fetch_or
+
+#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor
+
+#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_and_explicit __c11_atomic_fetch_and
+
+/* 7.17.8 Atomic flag type and operations */
+
+typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
+
+#define ATOMIC_FLAG_INIT { 0 }
+
+// These should be provided by the libc implementation.
+#ifdef __cplusplus
+bool atomic_flag_test_and_set(volatile atomic_flag *);
+bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order);
+#else
+_Bool atomic_flag_test_and_set(volatile atomic_flag *);
+_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order);
+#endif
+void atomic_flag_clear(volatile atomic_flag *);
+void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order);
+
+#define atomic_flag_test_and_set(object) __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST)
+#define atomic_flag_test_and_set_explicit(object, order) __c11_atomic_exchange(&(object)->_Value, 1, order)
+
+#define atomic_flag_clear(object) __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST)
+#define atomic_flag_clear_explicit(object, order) __c11_atomic_store(&(object)->_Value, 0, order)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STDC_HOSTED__ */
+#endif /* __CLANG_STDATOMIC_H */
+
diff --git a/lib/Headers/stddef.h b/lib/Headers/stddef.h
index 2dfe0a29b2a2..735499671156 100644
--- a/lib/Headers/stddef.h
+++ b/lib/Headers/stddef.h
@@ -30,11 +30,15 @@
#if !defined(__need_ptrdiff_t) && !defined(__need_size_t) && \
!defined(__need_wchar_t) && !defined(__need_NULL) && \
!defined(__need_wint_t)
+/* Always define miscellaneous pieces when modules are available. */
+#if !__has_feature(modules)
#define __STDDEF_H
+#endif
#define __need_ptrdiff_t
#define __need_size_t
#define __need_wchar_t
#define __need_NULL
+#define __need_STDDEF_H_misc
/* __need_wint_t is intentionally not defined here. */
#endif
@@ -60,7 +64,7 @@ typedef __SIZE_TYPE__ size_t;
#undef __need_size_t
#endif /*defined(__need_size_t) */
-#if defined(__STDDEF_H)
+#if defined(__need_STDDEF_H_misc)
/* ISO9899:2011 7.20 (C11 Annex K): Define rsize_t if __STDC_WANT_LIB_EXT1__ is
* enabled. */
#if (defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1 && \
@@ -71,7 +75,7 @@ typedef __SIZE_TYPE__ size_t;
#endif
typedef __SIZE_TYPE__ rsize_t;
#endif
-#endif /* defined(__STDDEF_H) */
+#endif /* defined(__need_STDDEF_H_misc) */
#if defined(__need_wchar_t)
#ifndef __cplusplus
@@ -109,26 +113,13 @@ using ::std::nullptr_t;
#undef __need_NULL
#endif /* defined(__need_NULL) */
-#if defined(__STDDEF_H)
-
+#if defined(__need_STDDEF_H_misc)
#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L
-#if !defined(__CLANG_MAX_ALIGN_T_DEFINED) || __has_feature(modules)
-#ifndef _MSC_VER
-typedef struct {
- long long __clang_max_align_nonce1
- __attribute__((__aligned__(__alignof__(long long))));
- long double __clang_max_align_nonce2
- __attribute__((__aligned__(__alignof__(long double))));
-} max_align_t;
-#else
-typedef double max_align_t;
+#include "__stddef_max_align_t.h"
#endif
-#define __CLANG_MAX_ALIGN_T_DEFINED
-#endif
-#endif
-
#define offsetof(t, d) __builtin_offsetof(t, d)
-#endif /* __STDDEF_H */
+#undef __need_STDDEF_H_misc
+#endif /* defined(__need_STDDEF_H_misc) */
/* Some C libraries expect to see a wint_t here. Others (notably MinGW) will use
__WINT_TYPE__ directly; accommodate both by requiring __need_wint_t */
diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h
index 685c1dfd04e8..90aca16aca39 100644
--- a/lib/Headers/unwind.h
+++ b/lib/Headers/unwind.h
@@ -26,8 +26,8 @@
#ifndef __CLANG_UNWIND_H
#define __CLANG_UNWIND_H
-#if __has_include_next(<unwind.h>)
-/* Darwin (from 11.x on) and libunwind provide an unwind.h. If that's available,
+#if defined(__APPLE__) && __has_include_next(<unwind.h>)
+/* Darwin (from 11.x on) provide an unwind.h. If that's available,
* use it. libunwind wraps some of its definitions in #ifdef _GNU_SOURCE,
* so define that around the include.*/
# ifndef _GNU_SOURCE
@@ -199,6 +199,8 @@ _Unwind_Word _Unwind_GetIPInfo(struct _Unwind_Context *, int *);
_Unwind_Word _Unwind_GetCFA(struct _Unwind_Context *);
+_Unwind_Word _Unwind_GetBSP(struct _Unwind_Context *);
+
void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context *);
_Unwind_Ptr _Unwind_GetRegionStart(struct _Unwind_Context *);
diff --git a/lib/Headers/vadefs.h b/lib/Headers/vadefs.h
new file mode 100644
index 000000000000..7fe9a74e3f69
--- /dev/null
+++ b/lib/Headers/vadefs.h
@@ -0,0 +1,65 @@
+/* ===-------- vadefs.h ---------------------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+/* Only include this if we are aiming for MSVC compatibility. */
+#ifndef _MSC_VER
+#include_next <vadefs.h>
+#else
+
+#ifndef __clang_vadefs_h
+#define __clang_vadefs_h
+
+#include_next <vadefs.h>
+
+/* Override macros from vadefs.h with definitions that work with Clang. */
+#ifdef _crt_va_start
+#undef _crt_va_start
+#define _crt_va_start(ap, param) __builtin_va_start(ap, param)
+#endif
+#ifdef _crt_va_end
+#undef _crt_va_end
+#define _crt_va_end(ap) __builtin_va_end(ap)
+#endif
+#ifdef _crt_va_arg
+#undef _crt_va_arg
+#define _crt_va_arg(ap, type) __builtin_va_arg(ap, type)
+#endif
+
+/* VS 2015 switched to double underscore names, which is an improvement, but now
+ * we have to intercept those names too.
+ */
+#ifdef __crt_va_start
+#undef __crt_va_start
+#define __crt_va_start(ap, param) __builtin_va_start(ap, param)
+#endif
+#ifdef __crt_va_end
+#undef __crt_va_end
+#define __crt_va_end(ap) __builtin_va_end(ap)
+#endif
+#ifdef __crt_va_arg
+#undef __crt_va_arg
+#define __crt_va_arg(ap, type) __builtin_va_arg(ap, type)
+#endif
+
+#endif
+#endif
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index c9befcb456f6..d1afe81601c3 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -182,153 +182,153 @@ _mm_xor_ps(__m128 __a, __m128 __b)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__a, __b, 0);
+ return (__m128)__builtin_ia32_cmpeqss(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__a, __b, 0);
+ return (__m128)__builtin_ia32_cmpeqps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__a, __b, 1);
+ return (__m128)__builtin_ia32_cmpltss(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__a, __b, 1);
+ return (__m128)__builtin_ia32_cmpltps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmple_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__a, __b, 2);
+ return (__m128)__builtin_ia32_cmpless(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmple_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__a, __b, 2);
+ return (__m128)__builtin_ia32_cmpleps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_ss(__m128 __a, __m128 __b)
{
return (__m128)__builtin_shufflevector(__a,
- __builtin_ia32_cmpss(__b, __a, 1),
+ __builtin_ia32_cmpltss(__b, __a),
4, 1, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__b, __a, 1);
+ return (__m128)__builtin_ia32_cmpltps(__b, __a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpge_ss(__m128 __a, __m128 __b)
{
return (__m128)__builtin_shufflevector(__a,
- __builtin_ia32_cmpss(__b, __a, 2),
+ __builtin_ia32_cmpless(__b, __a),
4, 1, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpge_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__b, __a, 2);
+ return (__m128)__builtin_ia32_cmpleps(__b, __a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpneq_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__a, __b, 4);
+ return (__m128)__builtin_ia32_cmpneqss(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpneq_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__a, __b, 4);
+ return (__m128)__builtin_ia32_cmpneqps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnlt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__a, __b, 5);
+ return (__m128)__builtin_ia32_cmpnltss(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnlt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__a, __b, 5);
+ return (__m128)__builtin_ia32_cmpnltps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnle_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__a, __b, 6);
+ return (__m128)__builtin_ia32_cmpnless(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnle_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__a, __b, 6);
+ return (__m128)__builtin_ia32_cmpnleps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpngt_ss(__m128 __a, __m128 __b)
{
return (__m128)__builtin_shufflevector(__a,
- __builtin_ia32_cmpss(__b, __a, 5),
+ __builtin_ia32_cmpnltss(__b, __a),
4, 1, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpngt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__b, __a, 5);
+ return (__m128)__builtin_ia32_cmpnltps(__b, __a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnge_ss(__m128 __a, __m128 __b)
{
return (__m128)__builtin_shufflevector(__a,
- __builtin_ia32_cmpss(__b, __a, 6),
+ __builtin_ia32_cmpnless(__b, __a),
4, 1, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnge_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__b, __a, 6);
+ return (__m128)__builtin_ia32_cmpnleps(__b, __a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpord_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__a, __b, 7);
+ return (__m128)__builtin_ia32_cmpordss(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpord_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__a, __b, 7);
+ return (__m128)__builtin_ia32_cmpordps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpunord_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(__a, __b, 3);
+ return (__m128)__builtin_ia32_cmpunordss(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpunord_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(__a, __b, 3);
+ return (__m128)__builtin_ia32_cmpunordps(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
index 1ebb636e8eca..3869c32c879a 100644
--- a/lib/Index/CMakeLists.txt
+++ b/lib/Index/CMakeLists.txt
@@ -13,7 +13,6 @@ add_clang_library(clangIndex
clangAST
clangBasic
clangFormat
- clangLex
clangRewrite
- clangTooling
+ clangToolingCore
)
diff --git a/lib/Index/CommentToXML.cpp b/lib/Index/CommentToXML.cpp
index a67c806550d8..ef6aeefa6526 100644
--- a/lib/Index/CommentToXML.cpp
+++ b/lib/Index/CommentToXML.cpp
@@ -15,7 +15,6 @@
#include "clang/AST/CommentVisitor.h"
#include "clang/Format/Format.h"
#include "clang/Index/USRGeneration.h"
-#include "clang/Lex/Lexer.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/raw_ostream.h"
@@ -609,14 +608,9 @@ void CommentASTToXMLConverter::formatTextOfDeclaration(
.getLocWithOffset(0);
unsigned Length = Declaration.size();
- std::vector<CharSourceRange> Ranges(
- 1, CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
- ASTContext &Context = DI->CurrentDecl->getASTContext();
- const LangOptions &LangOpts = Context.getLangOpts();
- Lexer Lex(ID, FormatRewriterContext.Sources.getBuffer(ID),
- FormatRewriterContext.Sources, LangOpts);
tooling::Replacements Replace = reformat(
- format::getLLVMStyle(), Lex, FormatRewriterContext.Sources, Ranges);
+ format::getLLVMStyle(), FormatRewriterContext.Sources, ID,
+ CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
applyAllReplacements(Replace, FormatRewriterContext.Rewrite);
Declaration = FormatRewriterContext.getRewrittenText(ID);
}
diff --git a/lib/Index/SimpleFormatContext.h b/lib/Index/SimpleFormatContext.h
index a460863f803e..080a4ad04ddf 100644
--- a/lib/Index/SimpleFormatContext.h
+++ b/lib/Index/SimpleFormatContext.h
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SIMPLE_FORM_CONTEXT_H
-#define LLVM_CLANG_SIMPLE_FORM_CONTEXT_H
+#ifndef LLVM_CLANG_LIB_INDEX_SIMPLEFORMATCONTEXT_H
+#define LLVM_CLANG_LIB_INDEX_SIMPLEFORMATCONTEXT_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
@@ -47,10 +47,11 @@ public:
~SimpleFormatContext() { }
FileID createInMemoryFile(StringRef Name, StringRef Content) {
- llvm::MemoryBuffer *Source = llvm::MemoryBuffer::getMemBuffer(Content);
+ std::unique_ptr<llvm::MemoryBuffer> Source =
+ llvm::MemoryBuffer::getMemBuffer(Content);
const FileEntry *Entry =
Files.getVirtualFile(Name, Source->getBufferSize(), 0);
- Sources.overrideFileContents(Entry, Source);
+ Sources.overrideFileContents(Entry, std::move(Source));
assert(Entry != nullptr);
return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
}
diff --git a/lib/Index/USRGeneration.cpp b/lib/Index/USRGeneration.cpp
index e08b85e9f868..baa166ee2802 100644
--- a/lib/Index/USRGeneration.cpp
+++ b/lib/Index/USRGeneration.cpp
@@ -198,7 +198,9 @@ void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
return;
VisitDeclContext(D->getDeclContext());
+ bool IsTemplate = false;
if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) {
+ IsTemplate = true;
Out << "@FT@";
VisitTemplateParameterList(FunTmpl->getTemplateParameters());
} else
@@ -226,12 +228,26 @@ void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
}
if (D->isVariadic())
Out << '.';
+ if (IsTemplate) {
+ // Function templates can be overloaded by return type, for example:
+ // \code
+ // template <class T> typename T::A foo() {}
+ // template <class T> typename T::B foo() {}
+ // \endcode
+ Out << '#';
+ VisitType(D->getReturnType());
+ }
Out << '#';
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
if (MD->isStatic())
Out << 'S';
if (unsigned quals = MD->getTypeQualifiers())
Out << (char)('0' + quals);
+ switch (MD->getRefQualifier()) {
+ case RQ_None: break;
+ case RQ_LValue: Out << '&'; break;
+ case RQ_RValue: Out << "&&"; break;
+ }
}
}
@@ -414,8 +430,8 @@ void USRGenerator::VisitTagDecl(const TagDecl *D) {
switch (D->getTagKind()) {
case TTK_Interface:
+ case TTK_Class:
case TTK_Struct: Out << "@ST"; break;
- case TTK_Class: Out << "@CT"; break;
case TTK_Union: Out << "@UT"; break;
case TTK_Enum: llvm_unreachable("enum template");
}
@@ -426,8 +442,8 @@ void USRGenerator::VisitTagDecl(const TagDecl *D) {
switch (D->getTagKind()) {
case TTK_Interface:
+ case TTK_Class:
case TTK_Struct: Out << "@SP"; break;
- case TTK_Class: Out << "@CP"; break;
case TTK_Union: Out << "@UP"; break;
case TTK_Enum: llvm_unreachable("enum partial specialization");
}
@@ -438,8 +454,8 @@ void USRGenerator::VisitTagDecl(const TagDecl *D) {
if (!AlreadyStarted) {
switch (D->getTagKind()) {
case TTK_Interface:
+ case TTK_Class:
case TTK_Struct: Out << "@S"; break;
- case TTK_Class: Out << "@C"; break;
case TTK_Union: Out << "@U"; break;
case TTK_Enum: Out << "@E"; break;
}
@@ -455,9 +471,13 @@ void USRGenerator::VisitTagDecl(const TagDecl *D) {
Buf[off] = 'A';
Out << '@' << *TD;
}
- else
+ else {
+ if (D->isEmbeddedInDeclarator() && !D->isFreeStanding()) {
+ printLoc(Out, D->getLocation(), Context->getSourceManager(), true);
+ } else
Buf[off] = 'a';
}
+ }
// For a class template specialization, mangle the template arguments.
if (const ClassTemplateSpecializationDecl *Spec
@@ -540,7 +560,6 @@ void USRGenerator::VisitType(QualType T) {
c = 'v'; break;
case BuiltinType::Bool:
c = 'b'; break;
- case BuiltinType::Char_U:
case BuiltinType::UChar:
c = 'c'; break;
case BuiltinType::Char16:
@@ -557,9 +576,11 @@ void USRGenerator::VisitType(QualType T) {
c = 'k'; break;
case BuiltinType::UInt128:
c = 'j'; break;
+ case BuiltinType::Char_U:
case BuiltinType::Char_S:
- case BuiltinType::SChar:
c = 'C'; break;
+ case BuiltinType::SChar:
+ c = 'r'; break;
case BuiltinType::WChar_S:
case BuiltinType::WChar_U:
c = 'W'; break;
@@ -626,6 +647,11 @@ void USRGenerator::VisitType(QualType T) {
T = PT->getPointeeType();
continue;
}
+ if (const RValueReferenceType *RT = T->getAs<RValueReferenceType>()) {
+ Out << "&&";
+ T = RT->getPointeeType();
+ continue;
+ }
if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
Out << '&';
T = RT->getPointeeType();
@@ -668,6 +694,22 @@ void USRGenerator::VisitType(QualType T) {
VisitTemplateArgument(Spec->getArg(I));
return;
}
+ if (const DependentNameType *DNT = T->getAs<DependentNameType>()) {
+ Out << '^';
+ // FIXME: Encode the qualifier, don't just print it.
+ PrintingPolicy PO(Ctx.getLangOpts());
+ PO.SuppressTagKeyword = true;
+ PO.SuppressUnwrittenScope = true;
+ PO.ConstantArraySizeAsWritten = false;
+ PO.AnonymousTagLocations = false;
+ DNT->getQualifier()->print(Out, PO);
+ Out << ':' << DNT->getIdentifier()->getName();
+ return;
+ }
+ if (const InjectedClassNameType *InjT = T->getAs<InjectedClassNameType>()) {
+ T = InjT->getInjectedSpecializationType();
+ continue;
+ }
// Unhandled type.
Out << ' ';
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index f6c658e11926..09d53846d4cf 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -81,9 +81,9 @@ const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) {
unsigned FileSize = FE->getSize();
if (FileSize <= sizeof(HMapHeader)) return nullptr;
- std::unique_ptr<const llvm::MemoryBuffer> FileBuffer(FM.getBufferForFile(FE));
+ auto FileBuffer = FM.getBufferForFile(FE);
if (!FileBuffer) return nullptr; // Unreadable file?
- const char *FileStart = FileBuffer->getBufferStart();
+ const char *FileStart = (*FileBuffer)->getBufferStart();
// We know the file is at least as big as the header, check it now.
const HMapHeader *Header = reinterpret_cast<const HMapHeader*>(FileStart);
@@ -103,11 +103,7 @@ const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) {
if (Header->Reserved != 0) return nullptr;
// Okay, everything looks good, create the header map.
- return new HeaderMap(FileBuffer.release(), NeedsByteSwap);
-}
-
-HeaderMap::~HeaderMap() {
- delete FileBuffer;
+ return new HeaderMap(std::move(*FileBuffer), NeedsByteSwap);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index c12d7314ee23..d6b255fb014e 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -50,7 +50,8 @@ HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
const LangOptions &LangOpts,
const TargetInfo *Target)
: HSOpts(HSOpts), Diags(Diags), FileMgr(SourceMgr.getFileManager()),
- FrameworkMap(64), ModMap(SourceMgr, Diags, LangOpts, Target, *this) {
+ FrameworkMap(64), ModMap(SourceMgr, Diags, LangOpts, Target, *this),
+ LangOpts(LangOpts) {
AngledDirIdx = 0;
SystemDirIdx = 0;
NoCurDirSearch = false;
@@ -60,8 +61,6 @@ HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
NumIncluded = 0;
NumMultiIncludeFileOptzn = 0;
NumFrameworkLookups = NumSubFrameworkLookups = 0;
-
- EnabledModules = LangOpts.Modules;
}
HeaderSearch::~HeaderSearch() {
@@ -114,7 +113,9 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
}
std::string HeaderSearch::getModuleFileName(Module *Module) {
- return getModuleFileName(Module->Name, Module->ModuleMap->getName());
+ const FileEntry *ModuleMap =
+ getModuleMap().getModuleMapFileForUniquing(Module);
+ return getModuleFileName(Module->Name, ModuleMap->getName());
}
std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
@@ -130,15 +131,24 @@ std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
llvm::sys::path::append(Result, ModuleName + ".pcm");
} else {
// Construct the name <ModuleName>-<hash of ModuleMapPath>.pcm which should
- // be globally unique to this particular module. To avoid false-negatives
- // on case-insensitive filesystems, we use lower-case, which is safe because
- // to cause a collision the modules must have the same name, which is an
- // error if they are imported in the same translation.
- SmallString<256> AbsModuleMapPath(ModuleMapPath);
- llvm::sys::fs::make_absolute(AbsModuleMapPath);
- llvm::APInt Code(64, llvm::hash_value(AbsModuleMapPath.str().lower()));
+ // ideally be globally unique to this particular module. Name collisions
+ // in the hash are safe (because any translation unit can only import one
+ // module with each name), but result in a loss of caching.
+ //
+ // To avoid false-negatives, we form as canonical a path as we can, and map
+ // to lower-case in case we're on a case-insensitive file system.
+ auto *Dir =
+ FileMgr.getDirectory(llvm::sys::path::parent_path(ModuleMapPath));
+ if (!Dir)
+ return std::string();
+ auto DirName = FileMgr.getCanonicalName(Dir);
+ auto FileName = llvm::sys::path::filename(ModuleMapPath);
+
+ llvm::hash_code Hash =
+ llvm::hash_combine(DirName.lower(), FileName.lower());
+
SmallString<128> HashStr;
- Code.toStringUnsigned(HashStr, /*Radix*/36);
+ llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36);
llvm::sys::path::append(Result, ModuleName + "-" + HashStr.str() + ".pcm");
}
return Result.str().str();
@@ -147,7 +157,7 @@ std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
// Look in the module map to determine if there is a module by this name.
Module *Module = ModMap.findModule(ModuleName);
- if (Module || !AllowSearch)
+ if (Module || !AllowSearch || !LangOpts.ModulesImplicitMaps)
return Module;
// Look through the various header search paths to load any available module
@@ -564,27 +574,9 @@ static const char *copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) {
const FileEntry *HeaderSearch::LookupFile(
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
- ArrayRef<const FileEntry *> Includers, SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath,
+ ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
+ SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
ModuleMap::KnownHeader *SuggestedModule, bool SkipCache) {
- if (!HSOpts->ModuleMapFiles.empty()) {
- // Preload all explicitly specified module map files. This enables modules
- // map files lying in a directory structure separate from the header files
- // that they describe. These cannot be loaded lazily upon encountering a
- // header file, as there is no other known mapping from a header file to its
- // module map file.
- for (llvm::SetVector<std::string>::iterator
- I = HSOpts->ModuleMapFiles.begin(),
- E = HSOpts->ModuleMapFiles.end();
- I != E; ++I) {
- const FileEntry *File = FileMgr.getFile(*I);
- if (!File)
- continue;
- loadModuleMapFile(File, /*IsSystem=*/false);
- }
- HSOpts->ModuleMapFiles.clear();
- }
-
if (SuggestedModule)
*SuggestedModule = ModuleMap::KnownHeader();
@@ -616,25 +608,33 @@ const FileEntry *HeaderSearch::LookupFile(
// This search is not done for <> headers.
if (!Includers.empty() && !isAngled && !NoCurDirSearch) {
SmallString<1024> TmpDir;
- for (ArrayRef<const FileEntry *>::iterator I = Includers.begin(),
- E = Includers.end();
- I != E; ++I) {
- const FileEntry *Includer = *I;
+ bool First = true;
+ for (const auto &IncluderAndDir : Includers) {
+ const FileEntry *Includer = IncluderAndDir.first;
+
// Concatenate the requested file onto the directory.
// FIXME: Portability. Filename concatenation should be in sys::Path.
- TmpDir = Includer->getDir()->getName();
+ TmpDir = IncluderAndDir.second->getName();
TmpDir.push_back('/');
TmpDir.append(Filename.begin(), Filename.end());
// FIXME: We don't cache the result of getFileInfo across the call to
// getFileAndSuggestModule, because it's a reference to an element of
// a container that could be reallocated across this call.
+ //
+ // FIXME: If we have no includer, that means we're processing a #include
+ // from a module build. We should treat this as a system header if we're
+ // building a [system] module.
bool IncluderIsSystemHeader =
- getFileInfo(Includer).DirInfo != SrcMgr::C_User;
- if (const FileEntry *FE =
- getFileAndSuggestModule(*this, TmpDir.str(), Includer->getDir(),
- IncluderIsSystemHeader,
- SuggestedModule)) {
+ Includer && getFileInfo(Includer).DirInfo != SrcMgr::C_User;
+ if (const FileEntry *FE = getFileAndSuggestModule(
+ *this, TmpDir.str(), IncluderAndDir.second,
+ IncluderIsSystemHeader, SuggestedModule)) {
+ if (!Includer) {
+ assert(First && "only first includer can have no file");
+ return FE;
+ }
+
// Leave CurDir unset.
// This file is a system header or C++ unfriendly if the old file is.
//
@@ -652,7 +652,7 @@ const FileEntry *HeaderSearch::LookupFile(
ToHFI.Framework = Framework;
if (SearchPath) {
- StringRef SearchPathRef(Includer->getDir()->getName());
+ StringRef SearchPathRef(IncluderAndDir.second->getName());
SearchPath->clear();
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
}
@@ -660,7 +660,7 @@ const FileEntry *HeaderSearch::LookupFile(
RelativePath->clear();
RelativePath->append(Filename.begin(), Filename.end());
}
- if (I == Includers.begin())
+ if (First)
return FE;
// Otherwise, we found the path via MSVC header search rules. If
@@ -677,6 +677,7 @@ const FileEntry *HeaderSearch::LookupFile(
break;
}
}
+ First = false;
}
}
@@ -694,8 +695,7 @@ const FileEntry *HeaderSearch::LookupFile(
// multiply included, and the "pragma once" optimization prevents them from
// being relex/pp'd, but they would still have to search through a
// (potentially huge) series of SearchDirs to find it.
- LookupFileCacheInfo &CacheLookup =
- LookupFileCache.GetOrCreateValue(Filename).getValue();
+ LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename];
// If the entry has been previously looked up, the first value will be
// non-zero. If the value is equal to i (the start point of our search), then
@@ -776,9 +776,9 @@ const FileEntry *HeaderSearch::LookupFile(
// a header in a framework that is currently being built, and we couldn't
// resolve "foo.h" any other way, change the include to <Foo/foo.h>, where
// "Foo" is the name of the framework in which the including header was found.
- if (!Includers.empty() && !isAngled &&
+ if (!Includers.empty() && Includers.front().first && !isAngled &&
Filename.find('/') == StringRef::npos) {
- HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front());
+ HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front().first);
if (IncludingHFI.IndexHeaderMapHeader) {
SmallString<128> ScratchFilename;
ScratchFilename += IncludingHFI.Framework;
@@ -795,10 +795,8 @@ const FileEntry *HeaderSearch::LookupFile(
return MSFE;
}
- LookupFileCacheInfo &CacheLookup
- = LookupFileCache.GetOrCreateValue(Filename).getValue();
- CacheLookup.HitIdx
- = LookupFileCache.GetOrCreateValue(ScratchFilename).getValue().HitIdx;
+ LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename];
+ CacheLookup.HitIdx = LookupFileCache[ScratchFilename].HitIdx;
// FIXME: SuggestedModule.
return FE;
}
@@ -851,18 +849,19 @@ LookupSubframeworkHeader(StringRef Filename,
FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
FrameworkName += ".framework/";
- llvm::StringMapEntry<FrameworkCacheEntry> &CacheLookup =
- FrameworkMap.GetOrCreateValue(Filename.substr(0, SlashPos));
+ auto &CacheLookup =
+ *FrameworkMap.insert(std::make_pair(Filename.substr(0, SlashPos),
+ FrameworkCacheEntry())).first;
// Some other location?
- if (CacheLookup.getValue().Directory &&
- CacheLookup.getKeyLength() == FrameworkName.size() &&
- memcmp(CacheLookup.getKeyData(), &FrameworkName[0],
- CacheLookup.getKeyLength()) != 0)
+ if (CacheLookup.second.Directory &&
+ CacheLookup.first().size() == FrameworkName.size() &&
+ memcmp(CacheLookup.first().data(), &FrameworkName[0],
+ CacheLookup.first().size()) != 0)
return nullptr;
// Cache subframework.
- if (!CacheLookup.getValue().Directory) {
+ if (!CacheLookup.second.Directory) {
++NumSubFrameworkLookups;
// If the framework dir doesn't exist, we fail.
@@ -871,7 +870,7 @@ LookupSubframeworkHeader(StringRef Filename,
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
- CacheLookup.getValue().Directory = Dir;
+ CacheLookup.second.Directory = Dir;
}
const FileEntry *FE = nullptr;
@@ -937,28 +936,6 @@ LookupSubframeworkHeader(StringRef Filename,
return FE;
}
-/// \brief Helper static function to normalize a path for injection into
-/// a synthetic header.
-/*static*/ std::string
-HeaderSearch::NormalizeDashIncludePath(StringRef File, FileManager &FileMgr) {
- // Implicit include paths should be resolved relative to the current
- // working directory first, and then use the regular header search
- // mechanism. The proper way to handle this is to have the
- // predefines buffer located at the current working directory, but
- // it has no file entry. For now, workaround this by using an
- // absolute path if we find the file here, and otherwise letting
- // header search handle it.
- SmallString<128> Path(File);
- llvm::sys::fs::make_absolute(Path);
- bool exists;
- if (llvm::sys::fs::exists(Path.str(), exists) || !exists)
- Path = File;
- else if (exists)
- FileMgr.getFile(File);
-
- return Lexer::Stringify(Path.str());
-}
-
//===----------------------------------------------------------------------===//
// File Info Management.
//===----------------------------------------------------------------------===//
@@ -1084,13 +1061,13 @@ size_t HeaderSearch::getTotalMemory() const {
}
StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
- return FrameworkNames.GetOrCreateValue(Framework).getKey();
+ return FrameworkNames.insert(Framework).first->first();
}
bool HeaderSearch::hasModuleMap(StringRef FileName,
const DirectoryEntry *Root,
bool IsSystem) {
- if (!enabledModules())
+ if (!enabledModules() || !LangOpts.ModulesImplicitMaps)
return false;
SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
@@ -1108,7 +1085,9 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
return false;
// Try to load the module map file in this directory.
- switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/false)) {
+ switch (loadModuleMapFile(Dir, IsSystem,
+ llvm::sys::path::extension(Dir->getName()) ==
+ ".framework")) {
case LMM_NewlyLoaded:
case LMM_AlreadyLoaded:
// Success. All of the directories we stepped through inherit this module
@@ -1142,11 +1121,10 @@ HeaderSearch::findModuleForHeader(const FileEntry *File) const {
return ModMap.findModuleForHeader(File);
}
-static const FileEntry *getPrivateModuleMap(StringRef ModuleMapPath,
- const DirectoryEntry *Directory,
+static const FileEntry *getPrivateModuleMap(const FileEntry *File,
FileManager &FileMgr) {
- StringRef Filename = llvm::sys::path::filename(ModuleMapPath);
- SmallString<128> PrivateFilename(Directory->getName());
+ StringRef Filename = llvm::sys::path::filename(File->getName());
+ SmallString<128> PrivateFilename(File->getDir()->getName());
if (Filename == "module.map")
llvm::sys::path::append(PrivateFilename, "module_private.map");
else if (Filename == "module.modulemap")
@@ -1157,7 +1135,25 @@ static const FileEntry *getPrivateModuleMap(StringRef ModuleMapPath,
}
bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) {
- switch (loadModuleMapFileImpl(File, IsSystem)) {
+ // Find the directory for the module. For frameworks, that may require going
+ // up from the 'Modules' directory.
+ const DirectoryEntry *Dir = nullptr;
+ if (getHeaderSearchOpts().ModuleMapFileHomeIsCwd)
+ Dir = FileMgr.getDirectory(".");
+ else {
+ Dir = File->getDir();
+ StringRef DirName(Dir->getName());
+ if (llvm::sys::path::filename(DirName) == "Modules") {
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.endswith(".framework"))
+ Dir = FileMgr.getDirectory(DirName);
+ // FIXME: This assert can fail if there's a race between the above check
+ // and the removal of the directory.
+ assert(Dir && "parent must exist");
+ }
+ }
+
+ switch (loadModuleMapFileImpl(File, IsSystem, Dir)) {
case LMM_AlreadyLoaded:
case LMM_NewlyLoaded:
return false;
@@ -1169,35 +1165,37 @@ bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) {
}
HeaderSearch::LoadModuleMapResult
-HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem) {
+HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem,
+ const DirectoryEntry *Dir) {
assert(File && "expected FileEntry");
- const DirectoryEntry *Dir = File->getDir();
- auto KnownDir = DirectoryHasModuleMap.find(Dir);
- if (KnownDir != DirectoryHasModuleMap.end())
- return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
+ // Check whether we've already loaded this module map, and mark it as being
+ // loaded in case we recursively try to load it from itself.
+ auto AddResult = LoadedModuleMaps.insert(std::make_pair(File, true));
+ if (!AddResult.second)
+ return AddResult.first->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
- if (ModMap.parseModuleMapFile(File, IsSystem)) {
- DirectoryHasModuleMap[Dir] = false;
+ if (ModMap.parseModuleMapFile(File, IsSystem, Dir)) {
+ LoadedModuleMaps[File] = false;
return LMM_InvalidModuleMap;
}
// Try to load a corresponding private module map.
- if (const FileEntry *PMMFile =
- getPrivateModuleMap(File->getName(), Dir, FileMgr)) {
- if (ModMap.parseModuleMapFile(PMMFile, IsSystem)) {
- DirectoryHasModuleMap[Dir] = false;
+ if (const FileEntry *PMMFile = getPrivateModuleMap(File, FileMgr)) {
+ if (ModMap.parseModuleMapFile(PMMFile, IsSystem, Dir)) {
+ LoadedModuleMaps[File] = false;
return LMM_InvalidModuleMap;
}
}
// This directory has a module map.
- DirectoryHasModuleMap[Dir] = true;
return LMM_NewlyLoaded;
}
const FileEntry *
HeaderSearch::lookupModuleMapFile(const DirectoryEntry *Dir, bool IsFramework) {
+ if (!LangOpts.ModulesImplicitMaps)
+ return nullptr;
// For frameworks, the preferred spelling is Modules/module.modulemap, but
// module.map at the framework root is also accepted.
SmallString<128> ModuleMapFileName(Dir->getName());
@@ -1218,12 +1216,12 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
bool IsSystem) {
if (Module *Module = ModMap.findModule(Name))
return Module;
-
+
// Try to load a module map file.
switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/true)) {
case LMM_InvalidModuleMap:
break;
-
+
case LMM_AlreadyLoaded:
case LMM_NoDirectory:
return nullptr;
@@ -1234,7 +1232,10 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
// Try to infer a module map from the framework directory.
- return ModMap.inferFrameworkModule(Name, Dir, IsSystem, /*Parent=*/nullptr);
+ if (LangOpts.ModulesImplicitMaps)
+ return ModMap.inferFrameworkModule(Name, Dir, IsSystem, /*Parent=*/nullptr);
+
+ return nullptr;
}
@@ -1252,15 +1253,18 @@ HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem,
bool IsFramework) {
auto KnownDir = DirectoryHasModuleMap.find(Dir);
if (KnownDir != DirectoryHasModuleMap.end())
- return KnownDir->second? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
+ return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
if (const FileEntry *ModuleMapFile = lookupModuleMapFile(Dir, IsFramework)) {
- LoadModuleMapResult Result = loadModuleMapFileImpl(ModuleMapFile, IsSystem);
+ LoadModuleMapResult Result =
+ loadModuleMapFileImpl(ModuleMapFile, IsSystem, Dir);
// Add Dir explicitly in case ModuleMapFile is in a subdirectory.
// E.g. Foo.framework/Modules/module.modulemap
// ^Dir ^ModuleMapFile
if (Result == LMM_NewlyLoaded)
DirectoryHasModuleMap[Dir] = true;
+ else if (Result == LMM_InvalidModuleMap)
+ DirectoryHasModuleMap[Dir] = false;
return Result;
}
return LMM_InvalidModuleMap;
@@ -1268,45 +1272,49 @@ HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem,
void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
Modules.clear();
-
- // Load module maps for each of the header search directories.
- for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
- bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
- if (SearchDirs[Idx].isFramework()) {
- std::error_code EC;
- SmallString<128> DirNative;
- llvm::sys::path::native(SearchDirs[Idx].getFrameworkDir()->getName(),
- DirNative);
-
- // Search each of the ".framework" directories to load them as modules.
- for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
- Dir != DirEnd && !EC; Dir.increment(EC)) {
- if (llvm::sys::path::extension(Dir->path()) != ".framework")
- continue;
-
- const DirectoryEntry *FrameworkDir = FileMgr.getDirectory(Dir->path());
- if (!FrameworkDir)
- continue;
-
- // Load this framework module.
- loadFrameworkModule(llvm::sys::path::stem(Dir->path()), FrameworkDir,
- IsSystem);
+
+ if (LangOpts.ModulesImplicitMaps) {
+ // Load module maps for each of the header search directories.
+ for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
+ bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
+ if (SearchDirs[Idx].isFramework()) {
+ std::error_code EC;
+ SmallString<128> DirNative;
+ llvm::sys::path::native(SearchDirs[Idx].getFrameworkDir()->getName(),
+ DirNative);
+
+ // Search each of the ".framework" directories to load them as modules.
+ for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ if (llvm::sys::path::extension(Dir->path()) != ".framework")
+ continue;
+
+ const DirectoryEntry *FrameworkDir =
+ FileMgr.getDirectory(Dir->path());
+ if (!FrameworkDir)
+ continue;
+
+ // Load this framework module.
+ loadFrameworkModule(llvm::sys::path::stem(Dir->path()), FrameworkDir,
+ IsSystem);
+ }
+ continue;
}
- continue;
+
+ // FIXME: Deal with header maps.
+ if (SearchDirs[Idx].isHeaderMap())
+ continue;
+
+ // Try to load a module map file for the search directory.
+ loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem,
+ /*IsFramework*/ false);
+
+ // Try to load module map files for immediate subdirectories of this
+ // search directory.
+ loadSubdirectoryModuleMaps(SearchDirs[Idx]);
}
-
- // FIXME: Deal with header maps.
- if (SearchDirs[Idx].isHeaderMap())
- continue;
-
- // Try to load a module map file for the search directory.
- loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem, /*IsFramework*/false);
-
- // Try to load module map files for immediate subdirectories of this search
- // directory.
- loadSubdirectoryModuleMaps(SearchDirs[Idx]);
}
-
+
// Populate the list of modules.
for (ModuleMap::module_iterator M = ModMap.module_begin(),
MEnd = ModMap.module_end();
@@ -1316,6 +1324,9 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
}
void HeaderSearch::loadTopLevelSystemModules() {
+ if (!LangOpts.ModulesImplicitMaps)
+ return;
+
// Load module maps for each of the header search directories.
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
// We only care about normal header directories.
@@ -1331,6 +1342,9 @@ void HeaderSearch::loadTopLevelSystemModules() {
}
void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
+ assert(LangOpts.ModulesImplicitMaps &&
+ "Should not be loading subdirectory module maps");
+
if (SearchDir.haveSearchedAllModuleMaps())
return;
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 6f6b50b246d7..ca5252e1c9ce 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -540,16 +540,16 @@ namespace {
};
}
-std::pair<unsigned, bool>
-Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
- const LangOptions &LangOpts, unsigned MaxLines) {
+std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer,
+ const LangOptions &LangOpts,
+ unsigned MaxLines) {
// Create a lexer starting at the beginning of the file. Note that we use a
// "fake" file source location at offset 1 so that the lexer will track our
// position within the file.
const unsigned StartOffset = 1;
SourceLocation FileLoc = SourceLocation::getFromRawEncoding(StartOffset);
- Lexer TheLexer(FileLoc, LangOpts, Buffer->getBufferStart(),
- Buffer->getBufferStart(), Buffer->getBufferEnd());
+ Lexer TheLexer(FileLoc, LangOpts, Buffer.begin(), Buffer.begin(),
+ Buffer.end());
TheLexer.SetCommentRetentionState(true);
// StartLoc will differ from FileLoc if there is a BOM that was skipped.
@@ -563,9 +563,9 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
unsigned MaxLineOffset = 0;
if (MaxLines) {
- const char *CurPtr = Buffer->getBufferStart();
+ const char *CurPtr = Buffer.begin();
unsigned CurLine = 0;
- while (CurPtr != Buffer->getBufferEnd()) {
+ while (CurPtr != Buffer.end()) {
char ch = *CurPtr++;
if (ch == '\n') {
++CurLine;
@@ -573,8 +573,8 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
break;
}
}
- if (CurPtr != Buffer->getBufferEnd())
- MaxLineOffset = CurPtr - Buffer->getBufferStart();
+ if (CurPtr != Buffer.end())
+ MaxLineOffset = CurPtr - Buffer.begin();
}
do {
@@ -1597,7 +1597,7 @@ bool Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
}
// If we have a digit separator, continue.
- if (C == '\'' && getLangOpts().CPlusPlus1y) {
+ if (C == '\'' && getLangOpts().CPlusPlus14) {
unsigned NextSize;
char Next = getCharAndSizeNoWarn(CurPtr + Size, NextSize, getLangOpts());
if (isIdentifierBody(Next)) {
@@ -1660,7 +1660,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr,
bool IsUDSuffix = false;
if (C == '_')
IsUDSuffix = true;
- else if (IsStringLiteral && getLangOpts().CPlusPlus1y) {
+ else if (IsStringLiteral && getLangOpts().CPlusPlus14) {
// In C++1y, we need to look ahead a few characters to see if this is a
// valid suffix for a string literal or a numeric literal (this could be
// the 'operator""if' defining a numeric literal operator).
@@ -1889,17 +1889,20 @@ bool Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
/// LexCharConstant - Lex the remainder of a character constant, after having
-/// lexed either ' or L' or u' or U'.
+/// lexed either ' or L' or u8' or u' or U'.
bool Lexer::LexCharConstant(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
// Does this character contain the \0 character?
const char *NulCharacter = nullptr;
- if (!isLexingRawMode() &&
- (Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant))
- Diag(BufferPtr, getLangOpts().CPlusPlus
- ? diag::warn_cxx98_compat_unicode_literal
- : diag::warn_c99_compat_unicode_literal);
+ if (!isLexingRawMode()) {
+ if (Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant)
+ Diag(BufferPtr, getLangOpts().CPlusPlus
+ ? diag::warn_cxx98_compat_unicode_literal
+ : diag::warn_c99_compat_unicode_literal);
+ else if (Kind == tok::utf8_char_constant)
+ Diag(BufferPtr, diag::warn_cxx14_compat_u8_character_literal);
+ }
char C = getAndAdvanceChar(CurPtr, Result);
if (C == '\'') {
@@ -2319,7 +2322,7 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
'/', '/', '/', '/', '/', '/', '/', '/'
};
while (CurPtr+16 <= BufferEnd &&
- !vec_any_eq(*(vector unsigned char*)CurPtr, Slashes))
+ !vec_any_eq(*(const vector unsigned char*)CurPtr, Slashes))
CurPtr += 16;
#else
// Scan for '/' quickly. Many block comments are very large.
@@ -2585,8 +2588,8 @@ static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd,
size_t Pos = RestOfBuffer.find(Terminator);
while (Pos != StringRef::npos) {
// Must occur at start of line.
- if (RestOfBuffer[Pos-1] != '\r' &&
- RestOfBuffer[Pos-1] != '\n') {
+ if (Pos == 0 ||
+ (RestOfBuffer[Pos - 1] != '\r' && RestOfBuffer[Pos - 1] != '\n')) {
RestOfBuffer = RestOfBuffer.substr(Pos+TermLen);
Pos = RestOfBuffer.find(Terminator);
continue;
@@ -3068,6 +3071,11 @@ LexNextToken:
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
tok::utf8_string_literal);
+ if (Char2 == '\'' && LangOpts.CPlusPlus1z)
+ return LexCharConstant(
+ Result, ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result),
+ tok::utf8_char_constant);
if (Char2 == 'R' && LangOpts.CPlusPlus11) {
unsigned SizeTmp3;
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 6417d0f0f5f2..03331fb33eb2 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -28,6 +28,7 @@ static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target) {
default: llvm_unreachable("Unknown token type!");
case tok::char_constant:
case tok::string_literal:
+ case tok::utf8_char_constant:
case tok::utf8_string_literal:
return Target.getCharWidth();
case tok::wide_char_constant:
@@ -656,7 +657,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
}
}
// "i", "if", and "il" are user-defined suffixes in C++1y.
- if (PP.getLangOpts().CPlusPlus1y && *s == 'i')
+ if (PP.getLangOpts().CPlusPlus14 && *s == 'i')
break;
// fall through.
case 'j':
@@ -716,7 +717,7 @@ bool NumericLiteralParser::isValidUDSuffix(const LangOptions &LangOpts,
return true;
// In C++11, there are no library suffixes.
- if (!LangOpts.CPlusPlus1y)
+ if (!LangOpts.CPlusPlus14)
return false;
// In C++1y, "s", "h", "min", "ms", "us", and "ns" are used in the library.
@@ -813,10 +814,10 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
if ((c1 == 'b' || c1 == 'B') && (c2 == '0' || c2 == '1')) {
// 0b101010 is a C++1y / GCC extension.
PP.Diag(TokLoc,
- PP.getLangOpts().CPlusPlus1y
+ PP.getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_binary_literal
: PP.getLangOpts().CPlusPlus
- ? diag::ext_binary_literal_cxx1y
+ ? diag::ext_binary_literal_cxx14
: diag::ext_binary_literal);
++s;
radix = 2;
@@ -1031,9 +1032,10 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
const char *TokBegin = begin;
// Skip over wide character determinant.
- if (Kind != tok::char_constant) {
+ if (Kind != tok::char_constant)
+ ++begin;
+ if (Kind == tok::utf8_char_constant)
++begin;
- }
// Skip over the entry quote.
assert(begin[0] == '\'' && "Invalid token lexed");
@@ -1077,6 +1079,8 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
if (tok::wide_char_constant == Kind) {
largest_character_for_kind =
0xFFFFFFFFu >> (32-PP.getTargetInfo().getWCharWidth());
+ } else if (tok::utf8_char_constant == Kind) {
+ largest_character_for_kind = 0x7F;
} else if (tok::utf16_char_constant == Kind) {
largest_character_for_kind = 0xFFFF;
} else if (tok::utf32_char_constant == Kind) {
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index a746fb7f48bf..9967f3f0e493 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -218,6 +218,7 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
if (tok::isStringLiteral(Tok.getKind()) || // "foo", u8R"x(foo)x"_bar, etc.
Tok.is(tok::char_constant) || // 'x'
Tok.is(tok::wide_char_constant) || // L'x'.
+ Tok.is(tok::utf8_char_constant) || // u8'x'.
Tok.is(tok::utf16_char_constant) || // u'x'.
Tok.is(tok::utf32_char_constant)) { // U'x'.
bool Invalid = false;
@@ -233,14 +234,14 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
// in place and avoid copies where possible.
unsigned CurStrLen = Result.size();
Result.resize(CurStrLen+Tok.getLength());
- const char *BufPtr = &Result[CurStrLen];
+ const char *BufPtr = Result.data() + CurStrLen;
bool Invalid = false;
unsigned ActualTokLen = PP.getSpelling(Tok, BufPtr, &Invalid);
if (!Invalid) {
// If getSpelling returned a pointer to an already uniqued version of
// the string instead of filling in BufPtr, memcpy it onto our string.
- if (BufPtr != &Result[CurStrLen])
+ if (ActualTokLen && BufPtr != &Result[CurStrLen])
memcpy(&Result[CurStrLen], BufPtr, ActualTokLen);
// If the token was dirty, the spelling may be shorter than the token.
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 8fae9c933d33..ef322d8cdc4c 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -19,6 +19,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/LiteralSupport.h"
@@ -202,7 +203,7 @@ ModuleMap::findHeaderInUmbrellaDirs(const FileEntry *File,
return KnownHeader();
}
-// Returns 'true' if 'RequestingModule directly uses 'RequestedModule'.
+// Returns true if RequestingModule directly uses RequestedModule.
static bool directlyUses(const Module *RequestingModule,
const Module *RequestedModule) {
return std::find(RequestingModule->DirectUses.begin(),
@@ -214,19 +215,23 @@ static bool violatesPrivateInclude(Module *RequestingModule,
const FileEntry *IncFileEnt,
ModuleMap::ModuleHeaderRole Role,
Module *RequestedModule) {
- #ifndef NDEBUG
+ bool IsPrivateRole = Role & ModuleMap::PrivateHeader;
+#ifndef NDEBUG
// Check for consistency between the module header role
// as obtained from the lookup and as obtained from the module.
// This check is not cheap, so enable it only for debugging.
- SmallVectorImpl<const FileEntry *> &PvtHdrs
- = RequestedModule->PrivateHeaders;
- SmallVectorImpl<const FileEntry *>::iterator Look
- = std::find(PvtHdrs.begin(), PvtHdrs.end(), IncFileEnt);
- bool IsPrivate = Look != PvtHdrs.end();
- assert((IsPrivate && Role == ModuleMap::PrivateHeader)
- || (!IsPrivate && Role != ModuleMap::PrivateHeader));
- #endif
- return Role == ModuleMap::PrivateHeader &&
+ bool IsPrivate = false;
+ SmallVectorImpl<Module::Header> *HeaderList[] =
+ {&RequestedModule->Headers[Module::HK_Private],
+ &RequestedModule->Headers[Module::HK_PrivateTextual]};
+ for (auto *Hdrs : HeaderList)
+ IsPrivate |=
+ std::find_if(Hdrs->begin(), Hdrs->end(), [&](const Module::Header &H) {
+ return H.Entry == IncFileEnt;
+ }) != Hdrs->end();
+ assert(IsPrivate == IsPrivateRole && "inconsistent headers and roles");
+#endif
+ return IsPrivateRole &&
RequestedModule->getTopLevelModule() != RequestingModule;
}
@@ -253,12 +258,6 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
HeadersMap::iterator Known = findKnownHeader(File);
if (Known != Headers.end()) {
for (const KnownHeader &Header : Known->second) {
- // Excluded headers don't really belong to a module.
- if (Header.getRole() == ModuleMap::ExcludedHeader) {
- Excluded = true;
- continue;
- }
-
// If 'File' is part of 'RequestingModule' we can definitely include it.
if (Header.getModule() == RequestingModule)
return;
@@ -281,6 +280,8 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
// We have found a module that we can happily use.
return;
}
+
+ Excluded = true;
}
// We have found a header, but it is private.
@@ -315,20 +316,23 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
ModuleMap::KnownHeader
ModuleMap::findModuleForHeader(const FileEntry *File,
- Module *RequestingModule) {
+ Module *RequestingModule,
+ bool IncludeTextualHeaders) {
HeadersMap::iterator Known = findKnownHeader(File);
+ auto MakeResult = [&](ModuleMap::KnownHeader R) -> ModuleMap::KnownHeader {
+ if (!IncludeTextualHeaders && (R.getRole() & ModuleMap::TextualHeader))
+ return ModuleMap::KnownHeader();
+ return R;
+ };
+
if (Known != Headers.end()) {
- ModuleMap::KnownHeader Result = KnownHeader();
+ ModuleMap::KnownHeader Result;
// Iterate over all modules that 'File' is part of to find the best fit.
for (SmallVectorImpl<KnownHeader>::iterator I = Known->second.begin(),
E = Known->second.end();
I != E; ++I) {
- // Cannot use a module if the header is excluded in it.
- if (I->getRole() == ModuleMap::ExcludedHeader)
- continue;
-
// Cannot use a module if it is unavailable.
if (!I->getModule()->isAvailable())
continue;
@@ -336,7 +340,7 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
// If 'File' is part of 'RequestingModule', 'RequestingModule' is the
// module we are looking for.
if (I->getModule() == RequestingModule)
- return *I;
+ return MakeResult(*I);
// If uses need to be specified explicitly, we are only allowed to return
// modules that are explicitly used by the requesting module.
@@ -344,15 +348,11 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
!directlyUses(RequestingModule, I->getModule()))
continue;
- Result = *I;
- // If 'File' is a public header of this module, this is as good as we
- // are going to get.
- // FIXME: If we have a RequestingModule, we should prefer the header from
- // that module.
- if (I->getRole() == ModuleMap::NormalHeader)
- break;
+ // Prefer a public header over a private header.
+ if (!Result || (Result.getRole() & ModuleMap::PrivateHeader))
+ Result = *I;
}
- return Result;
+ return MakeResult(Result);
}
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
@@ -367,6 +367,9 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
UmbrellaModule = UmbrellaModule->Parent;
if (UmbrellaModule->InferSubmodules) {
+ const FileEntry *UmbrellaModuleMap =
+ getModuleMapFileForUniquing(UmbrellaModule);
+
// Infer submodules for each of the directories we found between
// the directory of the umbrella header and the directory where
// the actual header is located.
@@ -377,8 +380,9 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
SmallString<32> NameBuf;
StringRef Name = sanitizeFilenameAsIdentifier(
llvm::sys::path::stem(SkippedDirs[I-1]->getName()), NameBuf);
- Result = findOrCreateModule(Name, Result, UmbrellaModule->ModuleMap,
- /*IsFramework=*/false, Explicit).first;
+ Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
+ Explicit).first;
+ InferredModuleAllowedBy[Result] = UmbrellaModuleMap;
Result->IsInferred = true;
// Associate the module and the directory.
@@ -394,8 +398,9 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
SmallString<32> NameBuf;
StringRef Name = sanitizeFilenameAsIdentifier(
llvm::sys::path::stem(File->getName()), NameBuf);
- Result = findOrCreateModule(Name, Result, UmbrellaModule->ModuleMap,
- /*IsFramework=*/false, Explicit).first;
+ Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
+ Explicit).first;
+ InferredModuleAllowedBy[Result] = UmbrellaModuleMap;
Result->IsInferred = true;
Result->addTopHeader(File);
@@ -417,9 +422,9 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
if (!Result->isAvailable())
return KnownHeader();
- return Headers[File].back();
+ return MakeResult(Headers[File].back());
}
-
+
return KnownHeader();
}
@@ -535,15 +540,14 @@ Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{
}
std::pair<Module *, bool>
-ModuleMap::findOrCreateModule(StringRef Name, Module *Parent,
- const FileEntry *ModuleMap, bool IsFramework,
+ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
bool IsExplicit) {
// Try to find an existing module with this name.
if (Module *Sub = lookupModuleQualified(Name, Parent))
return std::make_pair(Sub, false);
// Create a new module with this name.
- Module *Result = new Module(Name, SourceLocation(), Parent, ModuleMap,
+ Module *Result = new Module(Name, SourceLocation(), Parent,
IsFramework, IsExplicit);
if (LangOpts.CurrentModule == Name) {
SourceModule = Result;
@@ -559,30 +563,6 @@ ModuleMap::findOrCreateModule(StringRef Name, Module *Parent,
return std::make_pair(Result, true);
}
-bool ModuleMap::canInferFrameworkModule(const DirectoryEntry *ParentDir,
- StringRef Name, bool &IsSystem) const {
- // Check whether we have already looked into the parent directory
- // for a module map.
- llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator
- inferred = InferredDirectories.find(ParentDir);
- if (inferred == InferredDirectories.end())
- return false;
-
- if (!inferred->second.InferModules)
- return false;
-
- // We're allowed to infer for this directory, but make sure it's okay
- // to infer this particular module.
- bool canInfer = std::find(inferred->second.ExcludedModules.begin(),
- inferred->second.ExcludedModules.end(),
- Name) == inferred->second.ExcludedModules.end();
-
- if (canInfer && inferred->second.InferSystemModules)
- IsSystem = true;
-
- return canInfer;
-}
-
/// \brief For a framework module, infer the framework against which we
/// should link.
static void inferFrameworkLink(Module *Mod, const DirectoryEntry *FrameworkDir,
@@ -605,6 +585,15 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
const DirectoryEntry *FrameworkDir,
bool IsSystem,
Module *Parent) {
+ Attributes Attrs;
+ Attrs.IsSystem = IsSystem;
+ return inferFrameworkModule(ModuleName, FrameworkDir, Attrs, Parent);
+}
+
+Module *ModuleMap::inferFrameworkModule(StringRef ModuleName,
+ const DirectoryEntry *FrameworkDir,
+ Attributes Attrs, Module *Parent) {
+
// Check whether we've already found this module.
if (Module *Mod = lookupModuleQualified(ModuleName, Parent))
return Mod;
@@ -645,7 +634,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
bool IsFrameworkDir = Parent.endswith(".framework");
if (const FileEntry *ModMapFile =
HeaderInfo.lookupModuleMapFile(ParentDir, IsFrameworkDir)) {
- parseModuleMapFile(ModMapFile, IsSystem);
+ parseModuleMapFile(ModMapFile, Attrs.IsSystem, ParentDir);
inferred = InferredDirectories.find(ParentDir);
}
@@ -662,8 +651,9 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
inferred->second.ExcludedModules.end(),
Name) == inferred->second.ExcludedModules.end();
- if (inferred->second.InferSystemModules)
- IsSystem = true;
+ Attrs.IsSystem |= inferred->second.Attrs.IsSystem;
+ Attrs.IsExternC |= inferred->second.Attrs.IsExternC;
+ Attrs.IsExhaustive |= inferred->second.Attrs.IsExhaustive;
ModuleMapFile = inferred->second.ModuleMapFile;
}
}
@@ -673,7 +663,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (!canInfer)
return nullptr;
} else
- ModuleMapFile = Parent->ModuleMap;
+ ModuleMapFile = getModuleMapFileForUniquing(Parent);
// Look for an umbrella header.
@@ -687,15 +677,19 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (!UmbrellaHeader)
return nullptr;
- Module *Result = new Module(ModuleName, SourceLocation(), Parent, ModuleMapFile,
+ Module *Result = new Module(ModuleName, SourceLocation(), Parent,
/*IsFramework=*/true, /*IsExplicit=*/false);
+ InferredModuleAllowedBy[Result] = ModuleMapFile;
+ Result->IsInferred = true;
if (LangOpts.CurrentModule == ModuleName) {
SourceModule = Result;
SourceModuleName = ModuleName;
}
- if (IsSystem)
- Result->IsSystem = IsSystem;
-
+
+ Result->IsSystem |= Attrs.IsSystem;
+ Result->IsExternC |= Attrs.IsExternC;
+ Result->ConfigMacrosExhaustive |= Attrs.IsExhaustive;
+
if (!Parent)
Modules[ModuleName] = Result;
@@ -750,8 +744,8 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// FIXME: Do we want to warn about subframeworks without umbrella headers?
SmallString<32> NameBuf;
inferFrameworkModule(sanitizeFilenameAsIdentifier(
- llvm::sys::path::stem(Dir->path()), NameBuf),
- SubframeworkDir, IsSystem, Result);
+ llvm::sys::path::stem(Dir->path()), NameBuf),
+ SubframeworkDir, Attrs, Result);
}
}
@@ -775,23 +769,44 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
UmbrellaDirs[UmbrellaDir] = Mod;
}
-void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
+static Module::HeaderKind headerRoleToKind(ModuleMap::ModuleHeaderRole Role) {
+ switch ((int)Role) {
+ default: llvm_unreachable("unknown header role");
+ case ModuleMap::NormalHeader:
+ return Module::HK_Normal;
+ case ModuleMap::PrivateHeader:
+ return Module::HK_Private;
+ case ModuleMap::TextualHeader:
+ return Module::HK_Textual;
+ case ModuleMap::PrivateHeader | ModuleMap::TextualHeader:
+ return Module::HK_PrivateTextual;
+ }
+}
+
+void ModuleMap::addHeader(Module *Mod, Module::Header Header,
ModuleHeaderRole Role) {
- if (Role == ExcludedHeader) {
- Mod->ExcludedHeaders.push_back(Header);
- } else {
- if (Role == PrivateHeader)
- Mod->PrivateHeaders.push_back(Header);
- else
- Mod->NormalHeaders.push_back(Header);
+ if (!(Role & TextualHeader)) {
bool isCompilingModuleHeader = Mod->getTopLevelModule() == CompilingModule;
- HeaderInfo.MarkFileModuleHeader(Header, Role, isCompilingModuleHeader);
+ HeaderInfo.MarkFileModuleHeader(Header.Entry, Role,
+ isCompilingModuleHeader);
}
- Headers[Header].push_back(KnownHeader(Mod, Role));
+ Headers[Header.Entry].push_back(KnownHeader(Mod, Role));
+
+ Mod->Headers[headerRoleToKind(Role)].push_back(std::move(Header));
+}
+
+void ModuleMap::excludeHeader(Module *Mod, Module::Header Header) {
+ // Add this as a known header so we won't implicitly add it to any
+ // umbrella directory module.
+ // FIXME: Should we only exclude it from umbrella modules within the
+ // specified module?
+ (void) Headers[Header.Entry];
+
+ Mod->Headers[Module::HK_Excluded].push_back(std::move(Header));
}
const FileEntry *
-ModuleMap::getContainingModuleMapFile(Module *Module) const {
+ModuleMap::getContainingModuleMapFile(const Module *Module) const {
if (Module->DefinitionLoc.isInvalid())
return nullptr;
@@ -799,6 +814,19 @@ ModuleMap::getContainingModuleMapFile(Module *Module) const {
SourceMgr.getFileID(Module->DefinitionLoc));
}
+const FileEntry *ModuleMap::getModuleMapFileForUniquing(const Module *M) const {
+ if (M->IsInferred) {
+ assert(InferredModuleAllowedBy.count(M) && "missing inferred module map");
+ return InferredModuleAllowedBy.find(M)->second;
+ }
+ return getContainingModuleMapFile(M);
+}
+
+void ModuleMap::setInferredModuleAllowedBy(Module *M, const FileEntry *ModMap) {
+ assert(M->IsInferred && "module not inferred");
+ InferredModuleAllowedBy[M] = ModMap;
+}
+
void ModuleMap::dump() {
llvm::errs() << "Modules:";
for (llvm::StringMap<Module *>::iterator M = Modules.begin(),
@@ -927,6 +955,7 @@ namespace clang {
RequiresKeyword,
Star,
StringLiteral,
+ TextualKeyword,
LBrace,
RBrace,
LSquare,
@@ -955,21 +984,6 @@ namespace clang {
}
};
- /// \brief The set of attributes that can be attached to a module.
- struct Attributes {
- Attributes() : IsSystem(), IsExternC(), IsExhaustive() { }
-
- /// \brief Whether this is a system module.
- unsigned IsSystem : 1;
-
- /// \brief Whether this is an extern "C" module.
- unsigned IsExternC : 1;
-
- /// \brief Whether this is an exhaustive set of configuration macros.
- unsigned IsExhaustive : 1;
- };
-
-
class ModuleMapParser {
Lexer &L;
SourceManager &SourceMgr;
@@ -984,7 +998,8 @@ namespace clang {
/// \brief The current module map file.
const FileEntry *ModuleMapFile;
- /// \brief The directory that this module map resides in.
+ /// \brief The directory that file names in this module map file should
+ /// be resolved relative to.
const DirectoryEntry *Directory;
/// \brief The directory containing Clang-supplied headers.
@@ -1027,6 +1042,8 @@ namespace clang {
void parseConfigMacros();
void parseConflict();
void parseInferredModuleDecl(bool Framework, bool Explicit);
+
+ typedef ModuleMap::Attributes Attributes;
bool parseOptionalAttributes(Attributes &Attrs);
public:
@@ -1077,6 +1094,7 @@ retry:
.Case("module", MMToken::ModuleKeyword)
.Case("private", MMToken::PrivateKeyword)
.Case("requires", MMToken::RequiresKeyword)
+ .Case("textual", MMToken::TextualKeyword)
.Case("umbrella", MMToken::UmbrellaKeyword)
.Case("use", MMToken::UseKeyword)
.Default(MMToken::Identifier);
@@ -1328,8 +1346,11 @@ void ModuleMapParser::parseModuleDecl() {
// This module map defines a submodule. Go find the module of which it
// is a submodule.
ActiveModule = nullptr;
+ const Module *TopLevelModule = nullptr;
for (unsigned I = 0, N = Id.size() - 1; I != N; ++I) {
if (Module *Next = Map.lookupModuleQualified(Id[I].first, ActiveModule)) {
+ if (I == 0)
+ TopLevelModule = Next;
ActiveModule = Next;
continue;
}
@@ -1344,7 +1365,14 @@ void ModuleMapParser::parseModuleDecl() {
HadError = true;
return;
}
- }
+
+ if (ModuleMapFile != Map.getContainingModuleMapFile(TopLevelModule)) {
+ assert(ModuleMapFile != Map.getModuleMapFileForUniquing(TopLevelModule) &&
+ "submodule defined in same file as 'module *' that allowed its "
+ "top-level module");
+ Map.addAdditionalModuleMapFile(TopLevelModule, ModuleMapFile);
+ }
+ }
StringRef ModuleName = Id.back().first;
SourceLocation ModuleNameLoc = Id.back().second;
@@ -1390,19 +1418,15 @@ void ModuleMapParser::parseModuleDecl() {
return;
}
- // If this is a submodule, use the parent's module map, since we don't want
- // the private module map file.
- const FileEntry *ModuleMap = ActiveModule ? ActiveModule->ModuleMap
- : ModuleMapFile;
-
// Start defining this module.
- ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, ModuleMap,
- Framework, Explicit).first;
+ ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
+ Explicit).first;
ActiveModule->DefinitionLoc = ModuleNameLoc;
if (Attrs.IsSystem || IsSystem)
ActiveModule->IsSystem = true;
if (Attrs.IsExternC)
ActiveModule->IsExternC = true;
+ ActiveModule->Directory = Directory;
bool Done = false;
do {
@@ -1439,6 +1463,10 @@ void ModuleMapParser::parseModuleDecl() {
parseRequiresDecl();
break;
+ case MMToken::TextualKeyword:
+ parseHeaderDecl(MMToken::TextualKeyword, consumeToken());
+ break;
+
case MMToken::UmbrellaKeyword: {
SourceLocation UmbrellaLoc = consumeToken();
if (Tok.is(MMToken::HeaderKeyword))
@@ -1447,31 +1475,17 @@ void ModuleMapParser::parseModuleDecl() {
parseUmbrellaDirDecl(UmbrellaLoc);
break;
}
-
- case MMToken::ExcludeKeyword: {
- SourceLocation ExcludeLoc = consumeToken();
- if (Tok.is(MMToken::HeaderKeyword)) {
- parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc);
- } else {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
- << "exclude";
- }
+
+ case MMToken::ExcludeKeyword:
+ parseHeaderDecl(MMToken::ExcludeKeyword, consumeToken());
break;
- }
-
- case MMToken::PrivateKeyword: {
- SourceLocation PrivateLoc = consumeToken();
- if (Tok.is(MMToken::HeaderKeyword)) {
- parseHeaderDecl(MMToken::PrivateKeyword, PrivateLoc);
- } else {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
- << "private";
- }
+
+ case MMToken::PrivateKeyword:
+ parseHeaderDecl(MMToken::PrivateKeyword, consumeToken());
break;
- }
-
+
case MMToken::HeaderKeyword:
- parseHeaderDecl(MMToken::HeaderKeyword, SourceLocation());
+ parseHeaderDecl(MMToken::HeaderKeyword, consumeToken());
break;
case MMToken::LinkKeyword:
@@ -1554,7 +1568,11 @@ void ModuleMapParser::parseExternModuleDecl() {
FileNameRef = ModuleMapFileName.str();
}
if (const FileEntry *File = SourceMgr.getFileManager().getFile(FileNameRef))
- Map.parseModuleMapFile(File, /*IsSystem=*/false);
+ Map.parseModuleMapFile(
+ File, /*IsSystem=*/false,
+ Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd
+ ? Directory
+ : File->getDir());
}
/// \brief Parse a requires declaration.
@@ -1626,12 +1644,37 @@ static void appendSubframeworkPaths(Module *Mod,
/// \brief Parse a header declaration.
///
/// header-declaration:
-/// 'umbrella'[opt] 'header' string-literal
-/// 'exclude'[opt] 'header' string-literal
+/// 'textual'[opt] 'header' string-literal
+/// 'private' 'textual'[opt] 'header' string-literal
+/// 'exclude' 'header' string-literal
+/// 'umbrella' 'header' string-literal
+///
+/// FIXME: Support 'private textual header'.
void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
SourceLocation LeadingLoc) {
- assert(Tok.is(MMToken::HeaderKeyword));
- consumeToken();
+ // We've already consumed the first token.
+ ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader;
+ if (LeadingToken == MMToken::PrivateKeyword) {
+ Role = ModuleMap::PrivateHeader;
+ // 'private' may optionally be followed by 'textual'.
+ if (Tok.is(MMToken::TextualKeyword)) {
+ LeadingToken = Tok.Kind;
+ consumeToken();
+ }
+ }
+ if (LeadingToken == MMToken::TextualKeyword)
+ Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);
+
+ if (LeadingToken != MMToken::HeaderKeyword) {
+ if (!Tok.is(MMToken::HeaderKeyword)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
+ << (LeadingToken == MMToken::PrivateKeyword ? "private" :
+ LeadingToken == MMToken::ExcludeKeyword ? "exclude" :
+ LeadingToken == MMToken::TextualKeyword ? "textual" : "umbrella");
+ return;
+ }
+ consumeToken();
+ }
// Parse the header name.
if (!Tok.is(MMToken::StringLiteral)) {
@@ -1640,7 +1683,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
HadError = true;
return;
}
- Module::HeaderDirective Header;
+ Module::UnresolvedHeaderDirective Header;
Header.FileName = Tok.getString();
Header.FileNameLoc = consumeToken();
@@ -1655,33 +1698,39 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
// Look for this file.
const FileEntry *File = nullptr;
const FileEntry *BuiltinFile = nullptr;
- SmallString<128> PathName;
+ SmallString<128> RelativePathName;
if (llvm::sys::path::is_absolute(Header.FileName)) {
- PathName = Header.FileName;
- File = SourceMgr.getFileManager().getFile(PathName);
+ RelativePathName = Header.FileName;
+ File = SourceMgr.getFileManager().getFile(RelativePathName);
} else {
// Search for the header file within the search directory.
- PathName = Directory->getName();
- unsigned PathLength = PathName.size();
+ SmallString<128> FullPathName(Directory->getName());
+ unsigned FullPathLength = FullPathName.size();
if (ActiveModule->isPartOfFramework()) {
- appendSubframeworkPaths(ActiveModule, PathName);
+ appendSubframeworkPaths(ActiveModule, RelativePathName);
// Check whether this file is in the public headers.
- llvm::sys::path::append(PathName, "Headers", Header.FileName);
- File = SourceMgr.getFileManager().getFile(PathName);
+ llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
+ llvm::sys::path::append(FullPathName, RelativePathName.str());
+ File = SourceMgr.getFileManager().getFile(FullPathName);
if (!File) {
// Check whether this file is in the private headers.
- PathName.resize(PathLength);
- llvm::sys::path::append(PathName, "PrivateHeaders", Header.FileName);
- File = SourceMgr.getFileManager().getFile(PathName);
+ // FIXME: Should we retain the subframework paths here?
+ RelativePathName.clear();
+ FullPathName.resize(FullPathLength);
+ llvm::sys::path::append(RelativePathName, "PrivateHeaders",
+ Header.FileName);
+ llvm::sys::path::append(FullPathName, RelativePathName.str());
+ File = SourceMgr.getFileManager().getFile(FullPathName);
}
} else {
// Lookup for normal headers.
- llvm::sys::path::append(PathName, Header.FileName);
- File = SourceMgr.getFileManager().getFile(PathName);
-
+ llvm::sys::path::append(RelativePathName, Header.FileName);
+ llvm::sys::path::append(FullPathName, RelativePathName.str());
+ File = SourceMgr.getFileManager().getFile(FullPathName);
+
// If this is a system module with a top-level header, this header
// may have a counterpart (or replacement) in the set of headers
// supplied by Clang. Find that builtin header.
@@ -1691,18 +1740,19 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
llvm::sys::path::append(BuiltinPathName, Header.FileName);
BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
-
+
// If Clang supplies this header but the underlying system does not,
// just silently swap in our builtin version. Otherwise, we'll end
// up adding both (later).
if (!File && BuiltinFile) {
File = BuiltinFile;
+ RelativePathName = BuiltinPathName;
BuiltinFile = nullptr;
}
}
}
}
-
+
// FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
// Come up with a lazy way to do this.
if (File) {
@@ -1716,21 +1766,24 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
// Record this umbrella header.
Map.setUmbrellaHeader(ActiveModule, File);
}
+ } else if (LeadingToken == MMToken::ExcludeKeyword) {
+ Module::Header H = {RelativePathName.str(), File};
+ Map.excludeHeader(ActiveModule, H);
} else {
+ // If there is a builtin counterpart to this file, add it now, before
+ // the "real" header, so we build the built-in one first when building
+ // the module.
+ if (BuiltinFile) {
+ // FIXME: Taking the name from the FileEntry is unstable and can give
+ // different results depending on how we've previously named that file
+ // in this build.
+ Module::Header H = { BuiltinFile->getName(), BuiltinFile };
+ Map.addHeader(ActiveModule, H, Role);
+ }
+
// Record this header.
- ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader;
- if (LeadingToken == MMToken::ExcludeKeyword)
- Role = ModuleMap::ExcludedHeader;
- else if (LeadingToken == MMToken::PrivateKeyword)
- Role = ModuleMap::PrivateHeader;
- else
- assert(LeadingToken == MMToken::HeaderKeyword);
-
- Map.addHeader(ActiveModule, File, Role);
-
- // If there is a builtin counterpart to this file, add it now.
- if (BuiltinFile)
- Map.addHeader(ActiveModule, BuiltinFile, Role);
+ Module::Header H = { RelativePathName.str(), File };
+ Map.addHeader(ActiveModule, H, Role);
}
} else if (LeadingToken != MMToken::ExcludeKeyword) {
// Ignore excluded header files. They're optional anyway.
@@ -1813,6 +1866,7 @@ void ModuleMapParser::parseExportDecl() {
ModuleId ParsedModuleId;
bool Wildcard = false;
do {
+ // FIXME: Support string-literal module names here.
if (Tok.is(MMToken::Identifier)) {
ParsedModuleId.push_back(std::make_pair(Tok.getString(),
Tok.getLocation()));
@@ -1910,6 +1964,7 @@ void ModuleMapParser::parseConfigMacros() {
}
// If we don't have an identifier, we're done.
+ // FIXME: Support macros with the same name as a keyword here.
if (!Tok.is(MMToken::Identifier))
return;
@@ -1926,6 +1981,7 @@ void ModuleMapParser::parseConfigMacros() {
consumeToken();
// We expect to see a macro name here.
+ // FIXME: Support macros with the same name as a keyword here.
if (!Tok.is(MMToken::Identifier)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro);
break;
@@ -2060,7 +2116,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
} else {
// We'll be inferring framework modules for this directory.
Map.InferredDirectories[Directory].InferModules = true;
- Map.InferredDirectories[Directory].InferSystemModules = Attrs.IsSystem;
+ Map.InferredDirectories[Directory].Attrs = Attrs;
Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile;
// FIXME: Handle the 'framework' keyword.
}
@@ -2091,6 +2147,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
}
consumeToken();
+ // FIXME: Support string-literal module names here.
if (!Tok.is(MMToken::Identifier)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_missing_exclude_name);
break;
@@ -2246,6 +2303,7 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::RequiresKeyword:
case MMToken::Star:
case MMToken::StringLiteral:
+ case MMToken::TextualKeyword:
case MMToken::UmbrellaKeyword:
case MMToken::UseKeyword:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
@@ -2256,7 +2314,8 @@ bool ModuleMapParser::parseModuleMapFile() {
} while (true);
}
-bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) {
+bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem,
+ const DirectoryEntry *Dir) {
llvm::DenseMap<const FileEntry *, bool>::iterator Known
= ParsedModuleMap.find(File);
if (Known != ParsedModuleMap.end())
@@ -2269,17 +2328,6 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) {
if (!Buffer)
return ParsedModuleMap[File] = true;
- // Find the directory for the module. For frameworks, that may require going
- // up from the 'Modules' directory.
- const DirectoryEntry *Dir = File->getDir();
- StringRef DirName(Dir->getName());
- if (llvm::sys::path::filename(DirName) == "Modules") {
- DirName = llvm::sys::path::parent_path(DirName);
- if (DirName.endswith(".framework"))
- Dir = SourceMgr.getFileManager().getDirectory(DirName);
- assert(Dir && "parent must exist");
- }
-
// Parse this module map file.
Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts);
ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir,
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 1741c302f338..bf0ce72f6668 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -25,7 +25,7 @@
#include "clang/Lex/Pragma.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -34,23 +34,10 @@ using namespace clang;
//===----------------------------------------------------------------------===//
MacroInfo *Preprocessor::AllocateMacroInfo() {
- MacroInfoChain *MIChain;
-
- if (MICache) {
- MIChain = MICache;
- MICache = MICache->Next;
- }
- else {
- MIChain = BP.Allocate<MacroInfoChain>();
- }
-
+ MacroInfoChain *MIChain = BP.Allocate<MacroInfoChain>();
MIChain->Next = MIChainHead;
- MIChain->Prev = nullptr;
- if (MIChainHead)
- MIChainHead->Prev = MIChain;
MIChainHead = MIChain;
-
- return &(MIChain->MI);
+ return &MIChain->MI;
}
MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
@@ -77,45 +64,30 @@ MacroInfo *Preprocessor::AllocateDeserializedMacroInfo(SourceLocation L,
DefMacroDirective *
Preprocessor::AllocateDefMacroDirective(MacroInfo *MI, SourceLocation Loc,
- bool isImported) {
- DefMacroDirective *MD = BP.Allocate<DefMacroDirective>();
- new (MD) DefMacroDirective(MI, Loc, isImported);
- return MD;
+ unsigned ImportedFromModuleID,
+ ArrayRef<unsigned> Overrides) {
+ unsigned NumExtra = (ImportedFromModuleID ? 1 : 0) + Overrides.size();
+ return new (BP.Allocate(sizeof(DefMacroDirective) +
+ sizeof(unsigned) * NumExtra,
+ llvm::alignOf<DefMacroDirective>()))
+ DefMacroDirective(MI, Loc, ImportedFromModuleID, Overrides);
}
UndefMacroDirective *
-Preprocessor::AllocateUndefMacroDirective(SourceLocation UndefLoc) {
- UndefMacroDirective *MD = BP.Allocate<UndefMacroDirective>();
- new (MD) UndefMacroDirective(UndefLoc);
- return MD;
+Preprocessor::AllocateUndefMacroDirective(SourceLocation UndefLoc,
+ unsigned ImportedFromModuleID,
+ ArrayRef<unsigned> Overrides) {
+ unsigned NumExtra = (ImportedFromModuleID ? 1 : 0) + Overrides.size();
+ return new (BP.Allocate(sizeof(UndefMacroDirective) +
+ sizeof(unsigned) * NumExtra,
+ llvm::alignOf<UndefMacroDirective>()))
+ UndefMacroDirective(UndefLoc, ImportedFromModuleID, Overrides);
}
VisibilityMacroDirective *
Preprocessor::AllocateVisibilityMacroDirective(SourceLocation Loc,
bool isPublic) {
- VisibilityMacroDirective *MD = BP.Allocate<VisibilityMacroDirective>();
- new (MD) VisibilityMacroDirective(Loc, isPublic);
- return MD;
-}
-
-/// \brief Release the specified MacroInfo to be reused for allocating
-/// new MacroInfo objects.
-void Preprocessor::ReleaseMacroInfo(MacroInfo *MI) {
- MacroInfoChain *MIChain = (MacroInfoChain *)MI;
- if (MacroInfoChain *Prev = MIChain->Prev) {
- MacroInfoChain *Next = MIChain->Next;
- Prev->Next = Next;
- if (Next)
- Next->Prev = Prev;
- } else {
- assert(MIChainHead == MIChain);
- MIChainHead = MIChain->Next;
- MIChainHead->Prev = nullptr;
- }
- MIChain->Next = MICache;
- MICache = MIChain;
-
- MI->Destroy();
+ return new (BP) VisibilityMacroDirective(Loc, isPublic);
}
/// \brief Read and discard all tokens remaining on the current line until
@@ -128,7 +100,56 @@ void Preprocessor::DiscardUntilEndOfDirective() {
} while (Tmp.isNot(tok::eod));
}
-bool Preprocessor::CheckMacroName(Token &MacroNameTok, char isDefineUndef) {
+/// \brief Enumerates possible cases of #define/#undef a reserved identifier.
+enum MacroDiag {
+ MD_NoWarn, //> Not a reserved identifier
+ MD_KeywordDef, //> Macro hides keyword, enabled by default
+ MD_ReservedMacro //> #define of #undef reserved id, disabled by default
+};
+
+/// \brief Checks if the specified identifier is reserved in the specified
+/// language.
+/// This function does not check if the identifier is a keyword.
+static bool isReservedId(StringRef Text, const LangOptions &Lang) {
+ // C++ [macro.names], C11 7.1.3:
+ // All identifiers that begin with an underscore and either an uppercase
+ // letter or another underscore are always reserved for any use.
+ if (Text.size() >= 2 && Text[0] == '_' &&
+ (isUppercase(Text[1]) || Text[1] == '_'))
+ return true;
+ // C++ [global.names]
+ // Each name that contains a double underscore ... is reserved to the
+ // implementation for any use.
+ if (Lang.CPlusPlus) {
+ if (Text.find("__") != StringRef::npos)
+ return true;
+ }
+ return false;
+}
+
+static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) {
+ const LangOptions &Lang = PP.getLangOpts();
+ StringRef Text = II->getName();
+ if (isReservedId(Text, Lang))
+ return MD_ReservedMacro;
+ if (II->isKeyword(Lang))
+ return MD_KeywordDef;
+ if (Lang.CPlusPlus11 && (Text.equals("override") || Text.equals("final")))
+ return MD_KeywordDef;
+ return MD_NoWarn;
+}
+
+static MacroDiag shouldWarnOnMacroUndef(Preprocessor &PP, IdentifierInfo *II) {
+ const LangOptions &Lang = PP.getLangOpts();
+ StringRef Text = II->getName();
+ // Do not warn on keyword undef. It is generally harmless and widely used.
+ if (isReservedId(Text, Lang))
+ return MD_ReservedMacro;
+ return MD_NoWarn;
+}
+
+bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
+ bool *ShadowFlag) {
// Missing macro name?
if (MacroNameTok.is(tok::eod))
return Diag(MacroNameTok, diag::err_pp_missing_macro_name);
@@ -156,18 +177,42 @@ bool Preprocessor::CheckMacroName(Token &MacroNameTok, char isDefineUndef) {
MacroNameTok.setIdentifierInfo(II);
}
- if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) {
+ if ((isDefineUndef != MU_Other) && II->getPPKeywordID() == tok::pp_defined) {
// Error if defining "defined": C99 6.10.8/4, C++ [cpp.predefined]p4.
return Diag(MacroNameTok, diag::err_defined_macro_name);
}
- if (isDefineUndef == 2 && II->hasMacroDefinition() &&
+ if (isDefineUndef == MU_Undef && II->hasMacroDefinition() &&
getMacroInfo(II)->isBuiltinMacro()) {
// Warn if undefining "__LINE__" and other builtins, per C99 6.10.8/4
// and C++ [cpp.predefined]p4], but allow it as an extension.
Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro);
}
+ // If defining/undefining reserved identifier or a keyword, we need to issue
+ // a warning.
+ SourceLocation MacroNameLoc = MacroNameTok.getLocation();
+ if (ShadowFlag)
+ *ShadowFlag = false;
+ if (!SourceMgr.isInSystemHeader(MacroNameLoc) &&
+ (strcmp(SourceMgr.getBufferName(MacroNameLoc), "<built-in>") != 0)) {
+ MacroDiag D = MD_NoWarn;
+ if (isDefineUndef == MU_Define) {
+ D = shouldWarnOnMacroDef(*this, II);
+ }
+ else if (isDefineUndef == MU_Undef)
+ D = shouldWarnOnMacroUndef(*this, II);
+ if (D == MD_KeywordDef) {
+ // We do not want to warn on some patterns widely used in configuration
+ // scripts. This requires analyzing next tokens, so do not issue warnings
+ // now, only inform caller.
+ if (ShadowFlag)
+ *ShadowFlag = true;
+ }
+ if (D == MD_ReservedMacro)
+ Diag(MacroNameTok, diag::warn_pp_macro_is_reserved_id);
+ }
+
// Okay, we got a good identifier.
return false;
}
@@ -175,22 +220,25 @@ bool Preprocessor::CheckMacroName(Token &MacroNameTok, char isDefineUndef) {
/// \brief Lex and validate a macro name, which occurs after a
/// \#define or \#undef.
///
-/// This sets the token kind to eod and discards the rest
-/// of the macro line if the macro name is invalid. \p isDefineUndef is 1 if
-/// this is due to a a \#define, 2 if \#undef directive, 0 if it is something
-/// else (e.g. \#ifdef).
-void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
+/// This sets the token kind to eod and discards the rest of the macro line if
+/// the macro name is invalid.
+///
+/// \param MacroNameTok Token that is expected to be a macro name.
+/// \param isDefineUndef Context in which macro is used.
+/// \param ShadowFlag Points to a flag that is set if macro shadows a keyword.
+void Preprocessor::ReadMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
+ bool *ShadowFlag) {
// Read the token, don't allow macro expansion on it.
LexUnexpandedToken(MacroNameTok);
if (MacroNameTok.is(tok::code_completion)) {
if (CodeComplete)
- CodeComplete->CodeCompleteMacroName(isDefineUndef == 1);
+ CodeComplete->CodeCompleteMacroName(isDefineUndef == MU_Define);
setCodeCompletionReached();
LexUnexpandedToken(MacroNameTok);
}
- if (!CheckMacroName(MacroNameTok, isDefineUndef))
+ if (!CheckMacroName(MacroNameTok, isDefineUndef, ShadowFlag))
return;
// Invalid macro name, read and discard the rest of the line and set the
@@ -562,6 +610,7 @@ const FileEntry *Preprocessor::LookupFile(
StringRef Filename,
bool isAngled,
const DirectoryLookup *FromDir,
+ const FileEntry *FromFile,
const DirectoryLookup *&CurDir,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
@@ -569,22 +618,33 @@ const FileEntry *Preprocessor::LookupFile(
bool SkipCache) {
// If the header lookup mechanism may be relative to the current inclusion
// stack, record the parent #includes.
- SmallVector<const FileEntry *, 16> Includers;
- if (!FromDir) {
+ SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 16>
+ Includers;
+ if (!FromDir && !FromFile) {
FileID FID = getCurrentFileLexer()->getFileID();
const FileEntry *FileEnt = SourceMgr.getFileEntryForID(FID);
// If there is no file entry associated with this file, it must be the
- // predefines buffer. Any other file is not lexed with a normal lexer, so
- // it won't be scanned for preprocessor directives. If we have the
- // predefines buffer, resolve #include references (which come from the
- // -include command line argument) as if they came from the main file, this
- // affects file lookup etc.
- if (!FileEnt)
- FileEnt = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
-
- if (FileEnt)
- Includers.push_back(FileEnt);
+ // predefines buffer or the module includes buffer. Any other file is not
+ // lexed with a normal lexer, so it won't be scanned for preprocessor
+ // directives.
+ //
+ // If we have the predefines buffer, resolve #include references (which come
+ // from the -include command line argument) from the current working
+ // directory instead of relative to the main file.
+ //
+ // If we have the module includes buffer, resolve #include references (which
+ // come from header declarations in the module map) relative to the module
+ // map file.
+ if (!FileEnt) {
+ if (FID == SourceMgr.getMainFileID() && MainFileDir)
+ Includers.push_back(std::make_pair(nullptr, MainFileDir));
+ else if ((FileEnt =
+ SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())))
+ Includers.push_back(std::make_pair(FileEnt, FileMgr.getDirectory(".")));
+ } else {
+ Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
+ }
// MSVC searches the current include stack from top to bottom for
// headers included by quoted include directives.
@@ -595,13 +655,35 @@ const FileEntry *Preprocessor::LookupFile(
if (IsFileLexer(ISEntry))
if ((FileEnt = SourceMgr.getFileEntryForID(
ISEntry.ThePPLexer->getFileID())))
- Includers.push_back(FileEnt);
+ Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
}
}
}
- // Do a standard file entry lookup.
CurDir = CurDirLookup;
+
+ if (FromFile) {
+ // We're supposed to start looking from after a particular file. Search
+ // the include path until we find that file or run out of files.
+ const DirectoryLookup *TmpCurDir = CurDir;
+ const DirectoryLookup *TmpFromDir = nullptr;
+ while (const FileEntry *FE = HeaderInfo.LookupFile(
+ Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir,
+ Includers, SearchPath, RelativePath, SuggestedModule,
+ SkipCache)) {
+ // Keep looking as if this file did a #include_next.
+ TmpFromDir = TmpCurDir;
+ ++TmpFromDir;
+ if (FE == FromFile) {
+ // Found it.
+ FromDir = TmpFromDir;
+ CurDir = TmpCurDir;
+ break;
+ }
+ }
+ }
+
+ // Do a standard file entry lookup.
const FileEntry *FE = HeaderInfo.LookupFile(
Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
RelativePath, SuggestedModule, SkipCache);
@@ -716,7 +798,8 @@ void Preprocessor::HandleDirective(Token &Result) {
case tok::pp_import:
case tok::pp_include_next:
case tok::pp___include_macros:
- Diag(Result, diag::err_embedded_include) << II->getName();
+ case tok::pp_pragma:
+ Diag(Result, diag::err_embedded_directive) << II->getName();
DiscardUntilEndOfDirective();
return;
default:
@@ -1196,7 +1279,7 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
/// \brief Handle a #public directive.
void Preprocessor::HandleMacroPublicDirective(Token &Tok) {
Token MacroNameTok;
- ReadMacroName(MacroNameTok, 2);
+ ReadMacroName(MacroNameTok, MU_Undef);
// Error reading macro name? If so, diagnostic already issued.
if (MacroNameTok.is(tok::eod))
@@ -1223,7 +1306,7 @@ void Preprocessor::HandleMacroPublicDirective(Token &Tok) {
/// \brief Handle a #private directive.
void Preprocessor::HandleMacroPrivateDirective(Token &Tok) {
Token MacroNameTok;
- ReadMacroName(MacroNameTok, 2);
+ ReadMacroName(MacroNameTok, MU_Undef);
// Error reading macro name? If so, diagnostic already issued.
if (MacroNameTok.is(tok::eod))
@@ -1378,6 +1461,7 @@ static void EnterAnnotationToken(Preprocessor &PP,
void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
Token &IncludeTok,
const DirectoryLookup *LookupFrom,
+ const FileEntry *LookupFromFile,
bool isImport) {
Token FilenameTok;
@@ -1469,12 +1553,14 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
SmallString<128> NormalizedPath;
if (LangOpts.MSVCCompat) {
NormalizedPath = Filename.str();
- llvm::sys::fs::normalize_separators(NormalizedPath);
+#ifndef LLVM_ON_WIN32
+ llvm::sys::path::native(NormalizedPath);
+#endif
}
const FileEntry *File = LookupFile(
FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
- isAngled, LookupFrom, CurDir, Callbacks ? &SearchPath : nullptr,
- Callbacks ? &RelativePath : nullptr,
+ isAngled, LookupFrom, LookupFromFile, CurDir,
+ Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule : nullptr);
if (Callbacks) {
@@ -1488,14 +1574,13 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
HeaderInfo.AddSearchPath(DL, isAngled);
// Try the lookup again, skipping the cache.
- File = LookupFile(FilenameLoc,
- LangOpts.MSVCCompat ? NormalizedPath.c_str()
- : Filename,
- isAngled, LookupFrom, CurDir, nullptr, nullptr,
- HeaderInfo.getHeaderSearchOpts().ModuleMaps
- ? &SuggestedModule
- : nullptr,
- /*SkipCache*/ true);
+ File = LookupFile(
+ FilenameLoc,
+ LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
+ LookupFrom, LookupFromFile, CurDir, nullptr, nullptr,
+ HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule
+ : nullptr,
+ /*SkipCache*/ true);
}
}
}
@@ -1517,8 +1602,10 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// provide the user with a possible fixit.
if (isAngled) {
File = LookupFile(
- FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
- false, LookupFrom, CurDir, Callbacks ? &SearchPath : nullptr,
+ FilenameLoc,
+ LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, false,
+ LookupFrom, LookupFromFile, CurDir,
+ Callbacks ? &SearchPath : nullptr,
Callbacks ? &RelativePath : nullptr,
HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule
: nullptr);
@@ -1539,7 +1626,9 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// If we are supposed to import a module rather than including the header,
// do so now.
- if (SuggestedModule && getLangOpts().Modules) {
+ if (SuggestedModule && getLangOpts().Modules &&
+ SuggestedModule.getModule()->getTopLevelModuleName() !=
+ getLangOpts().ImplementationOfModule) {
// Compute the module access path corresponding to this module.
// FIXME: Should we have a second loadModule() overload to avoid this
// extra lookup step?
@@ -1713,9 +1802,16 @@ void Preprocessor::HandleIncludeNextDirective(SourceLocation HashLoc,
// the current found directory. If we can't do this, issue a
// diagnostic.
const DirectoryLookup *Lookup = CurDirLookup;
+ const FileEntry *LookupFromFile = nullptr;
if (isInPrimaryFile()) {
Lookup = nullptr;
Diag(IncludeNextTok, diag::pp_include_next_in_primary);
+ } else if (CurSubmodule) {
+ // Start looking up in the directory *after* the one in which the current
+ // file would be found, if any.
+ assert(CurPPLexer && "#include_next directive in macro?");
+ LookupFromFile = CurPPLexer->getFileEntry();
+ Lookup = nullptr;
} else if (!Lookup) {
Diag(IncludeNextTok, diag::pp_include_next_absolute_path);
} else {
@@ -1723,7 +1819,8 @@ void Preprocessor::HandleIncludeNextDirective(SourceLocation HashLoc,
++Lookup;
}
- return HandleIncludeDirective(HashLoc, IncludeNextTok, Lookup);
+ return HandleIncludeDirective(HashLoc, IncludeNextTok, Lookup,
+ LookupFromFile);
}
/// HandleMicrosoftImportDirective - Implements \#import for Microsoft Mode
@@ -1749,7 +1846,7 @@ void Preprocessor::HandleImportDirective(SourceLocation HashLoc,
return HandleMicrosoftImportDirective(ImportTok);
Diag(ImportTok, diag::ext_pp_import_directive);
}
- return HandleIncludeDirective(HashLoc, ImportTok, nullptr, true);
+ return HandleIncludeDirective(HashLoc, ImportTok, nullptr, nullptr, true);
}
/// HandleIncludeMacrosDirective - The -imacros command line option turns into a
@@ -1770,7 +1867,7 @@ void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc,
// Treat this as a normal #include for checking purposes. If this is
// successful, it will push a new lexer onto the include stack.
- HandleIncludeDirective(HashLoc, IncludeMacrosTok, nullptr, false);
+ HandleIncludeDirective(HashLoc, IncludeMacrosTok);
Token TmpTok;
do {
@@ -1878,6 +1975,52 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
}
}
+static bool isConfigurationPattern(Token &MacroName, MacroInfo *MI,
+ const LangOptions &LOptions) {
+ if (MI->getNumTokens() == 1) {
+ const Token &Value = MI->getReplacementToken(0);
+
+ // Macro that is identity, like '#define inline inline' is a valid pattern.
+ if (MacroName.getKind() == Value.getKind())
+ return true;
+
+ // Macro that maps a keyword to the same keyword decorated with leading/
+ // trailing underscores is a valid pattern:
+ // #define inline __inline
+ // #define inline __inline__
+ // #define inline _inline (in MS compatibility mode)
+ StringRef MacroText = MacroName.getIdentifierInfo()->getName();
+ if (IdentifierInfo *II = Value.getIdentifierInfo()) {
+ if (!II->isKeyword(LOptions))
+ return false;
+ StringRef ValueText = II->getName();
+ StringRef TrimmedValue = ValueText;
+ if (!ValueText.startswith("__")) {
+ if (ValueText.startswith("_"))
+ TrimmedValue = TrimmedValue.drop_front(1);
+ else
+ return false;
+ } else {
+ TrimmedValue = TrimmedValue.drop_front(2);
+ if (TrimmedValue.endswith("__"))
+ TrimmedValue = TrimmedValue.drop_back(2);
+ }
+ return TrimmedValue.equals(MacroText);
+ } else {
+ return false;
+ }
+ }
+
+ // #define inline
+ if ((MacroName.is(tok::kw_extern) || MacroName.is(tok::kw_inline) ||
+ MacroName.is(tok::kw_static) || MacroName.is(tok::kw_const)) &&
+ MI->getNumTokens() == 0) {
+ return true;
+ }
+
+ return false;
+}
+
/// HandleDefineDirective - Implements \#define. This consumes the entire macro
/// line then lets the caller lex the next real token.
void Preprocessor::HandleDefineDirective(Token &DefineTok,
@@ -1885,7 +2028,8 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
++NumDefined;
Token MacroNameTok;
- ReadMacroName(MacroNameTok, 1);
+ bool MacroShadowsKeyword;
+ ReadMacroName(MacroNameTok, MU_Define, &MacroShadowsKeyword);
// Error reading macro name? If so, diagnostic already issued.
if (MacroNameTok.is(tok::eod))
@@ -1921,8 +2065,6 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
// This is a function-like macro definition. Read the argument list.
MI->setIsFunctionLike();
if (ReadMacroDefinitionArgList(MI, LastTok)) {
- // Forget about MI.
- ReleaseMacroInfo(MI);
// Throw away the rest of the line.
if (CurPPLexer->ParsingPreprocessorDirective)
DiscardUntilEndOfDirective();
@@ -2047,7 +2189,6 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
continue;
} else {
Diag(Tok, diag::err_pp_stringize_not_parameter);
- ReleaseMacroInfo(MI);
// Disable __VA_ARGS__ again.
Ident__VA_ARGS__->setIsPoisoned(true);
@@ -2065,6 +2206,10 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
}
}
+ if (MacroShadowsKeyword &&
+ !isConfigurationPattern(MacroNameTok, MI, getLangOpts())) {
+ Diag(MacroNameTok, diag::warn_pp_macro_hides_keyword);
+ }
// Disable __VA_ARGS__ again.
Ident__VA_ARGS__->setIsPoisoned(true);
@@ -2075,12 +2220,10 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
if (NumTokens != 0) {
if (MI->getReplacementToken(0).is(tok::hashhash)) {
Diag(MI->getReplacementToken(0), diag::err_paste_at_start);
- ReleaseMacroInfo(MI);
return;
}
if (MI->getReplacementToken(NumTokens-1).is(tok::hashhash)) {
Diag(MI->getReplacementToken(NumTokens-1), diag::err_paste_at_end);
- ReleaseMacroInfo(MI);
return;
}
}
@@ -2138,7 +2281,7 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
++NumUndefined;
Token MacroNameTok;
- ReadMacroName(MacroNameTok, 2);
+ ReadMacroName(MacroNameTok, MU_Undef);
// Error reading macro name? If so, diagnostic already issued.
if (MacroNameTok.is(tok::eod))
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 2260bf98f7a5..9cf72cf8f8fb 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -103,7 +103,7 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
}
// If we don't have a pp-identifier now, this is an error.
- if (PP.CheckMacroName(PeekTok, 0))
+ if (PP.CheckMacroName(PeekTok, MU_Other))
return true;
// Otherwise, we got an identifier, is it defined to something?
@@ -244,7 +244,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// Parse the integer literal into Result.
if (Literal.GetIntegerValue(Result.Val)) {
// Overflow parsing integer literal.
- if (ValueLive) PP.Diag(PeekTok, diag::err_integer_too_large);
+ if (ValueLive)
+ PP.Diag(PeekTok, diag::err_integer_literal_too_large)
+ << /* Unsigned */ 1;
Result.Val.setIsUnsigned(true);
} else {
// Set the signedness of the result to match whether there was a U suffix
@@ -259,7 +261,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// Octal, hexadecimal, and binary literals are implicitly unsigned if
// the value does not fit into a signed integer type.
if (ValueLive && Literal.getRadix() == 10)
- PP.Diag(PeekTok, diag::ext_integer_too_large_for_signed);
+ PP.Diag(PeekTok, diag::ext_integer_literal_too_large_for_signed);
Result.Val.setIsUnsigned(true);
}
}
@@ -271,6 +273,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
}
case tok::char_constant: // 'x'
case tok::wide_char_constant: // L'x'
+ case tok::utf8_char_constant: // u8'x'
case tok::utf16_char_constant: // u'x'
case tok::utf32_char_constant: { // U'x'
// Complain about, and drop, any ud-suffix.
@@ -597,15 +600,10 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
break;
case tok::lessless: {
// Determine whether overflow is about to happen.
- unsigned ShAmt = static_cast<unsigned>(RHS.Val.getLimitedValue());
- if (LHS.isUnsigned()) {
- Overflow = ShAmt >= LHS.Val.getBitWidth();
- if (Overflow)
- ShAmt = LHS.Val.getBitWidth()-1;
- Res = LHS.Val << ShAmt;
- } else {
- Res = llvm::APSInt(LHS.Val.sshl_ov(ShAmt, Overflow), false);
- }
+ if (LHS.isUnsigned())
+ Res = LHS.Val.ushl_ov(RHS.Val, Overflow);
+ else
+ Res = llvm::APSInt(LHS.Val.sshl_ov(RHS.Val, Overflow), false);
break;
}
case tok::greatergreater: {
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 22ee971f4889..fb5e2b05808c 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -160,17 +160,17 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
/// tokens from it instead of the current buffer.
void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
MacroInfo *Macro, MacroArgs *Args) {
- TokenLexer *TokLexer;
+ std::unique_ptr<TokenLexer> TokLexer;
if (NumCachedTokenLexers == 0) {
- TokLexer = new TokenLexer(Tok, ILEnd, Macro, Args, *this);
+ TokLexer = llvm::make_unique<TokenLexer>(Tok, ILEnd, Macro, Args, *this);
} else {
- TokLexer = TokenLexerCache[--NumCachedTokenLexers];
+ TokLexer = std::move(TokenLexerCache[--NumCachedTokenLexers]);
TokLexer->Init(Tok, ILEnd, Macro, Args);
}
PushIncludeMacroStack();
CurDirLookup = nullptr;
- CurTokenLexer.reset(TokLexer);
+ CurTokenLexer = std::move(TokLexer);
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_TokenLexer;
}
@@ -190,20 +190,39 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
bool DisableMacroExpansion,
bool OwnsTokens) {
+ if (CurLexerKind == CLK_CachingLexer) {
+ if (CachedLexPos < CachedTokens.size()) {
+ // We're entering tokens into the middle of our cached token stream. We
+ // can't represent that, so just insert the tokens into the buffer.
+ CachedTokens.insert(CachedTokens.begin() + CachedLexPos,
+ Toks, Toks + NumToks);
+ if (OwnsTokens)
+ delete [] Toks;
+ return;
+ }
+
+ // New tokens are at the end of the cached token sequnece; insert the
+ // token stream underneath the caching lexer.
+ ExitCachingLexMode();
+ EnterTokenStream(Toks, NumToks, DisableMacroExpansion, OwnsTokens);
+ EnterCachingLexMode();
+ return;
+ }
+
// Create a macro expander to expand from the specified token stream.
- TokenLexer *TokLexer;
+ std::unique_ptr<TokenLexer> TokLexer;
if (NumCachedTokenLexers == 0) {
- TokLexer = new TokenLexer(Toks, NumToks, DisableMacroExpansion,
- OwnsTokens, *this);
+ TokLexer = llvm::make_unique<TokenLexer>(
+ Toks, NumToks, DisableMacroExpansion, OwnsTokens, *this);
} else {
- TokLexer = TokenLexerCache[--NumCachedTokenLexers];
+ TokLexer = std::move(TokenLexerCache[--NumCachedTokenLexers]);
TokLexer->Init(Toks, NumToks, DisableMacroExpansion, OwnsTokens);
}
// Save our current state.
PushIncludeMacroStack();
CurDirLookup = nullptr;
- CurTokenLexer.reset(TokLexer);
+ CurTokenLexer = std::move(TokLexer);
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_TokenLexer;
}
@@ -480,33 +499,6 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
}
}
}
-
- // Check whether there are any headers that were included, but not
- // mentioned at all in the module map. Such headers
- SourceLocation StartLoc
- = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
- if (!getDiagnostics().isIgnored(diag::warn_forgotten_module_header,
- StartLoc)) {
- ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
- for (unsigned I = 0, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
- // We only care about file entries.
- const SrcMgr::SLocEntry &Entry = SourceMgr.getLocalSLocEntry(I);
- if (!Entry.isFile())
- continue;
-
- // Dig out the actual file.
- const FileEntry *File = Entry.getFile().getContentCache()->OrigEntry;
- if (!File)
- continue;
-
- // If it's not part of a module and not unknown, complain.
- if (!ModMap.findModuleForHeader(File) &&
- !ModMap.isHeaderInUnavailableModule(File)) {
- Diag(StartLoc, diag::warn_forgotten_module_header)
- << File->getName() << Mod->getFullModuleName();
- }
- }
- }
}
return true;
@@ -526,7 +518,7 @@ bool Preprocessor::HandleEndOfTokenLexer(Token &Result) {
if (NumCachedTokenLexers == TokenLexerCacheSize)
CurTokenLexer.reset();
else
- TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer.release();
+ TokenLexerCache[NumCachedTokenLexers++] = std::move(CurTokenLexer);
// Handle this like a #include file being popped off the stack.
return HandleEndOfFile(Result, true);
@@ -543,7 +535,7 @@ void Preprocessor::RemoveTopOfLexerStack() {
if (NumCachedTokenLexers == TokenLexerCacheSize)
CurTokenLexer.reset();
else
- TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer.release();
+ TokenLexerCache[NumCachedTokenLexers++] = std::move(CurTokenLexer);
}
PopIncludeMacroStack();
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 2d7c6d4b5227..cd05d06633f2 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -49,7 +49,10 @@ void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective *MD){
MacroDirective *&StoredMD = Macros[II];
MD->setPrevious(StoredMD);
StoredMD = MD;
- II->setHasMacroDefinition(MD->isDefined());
+ // Setup the identifier as having associated macro history.
+ II->setHasMacroDefinition(true);
+ if (!MD->isDefined())
+ II->setHasMacroDefinition(false);
bool isImportedMacro = isa<DefMacroDirective>(MD) &&
cast<DefMacroDirective>(MD)->isImported();
if (II->isFromAST() && !isImportedMacro)
@@ -93,6 +96,9 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__");
Ident_Pragma = RegisterBuiltinMacro(*this, "_Pragma");
+ // C++ Standing Document Extensions.
+ Ident__has_cpp_attribute = RegisterBuiltinMacro(*this, "__has_cpp_attribute");
+
// GCC Extensions.
Ident__BASE_FILE__ = RegisterBuiltinMacro(*this, "__BASE_FILE__");
Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__");
@@ -112,6 +118,7 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension");
Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin");
Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute");
+ Ident__has_declspec = RegisterBuiltinMacro(*this, "__has_declspec_attribute");
Ident__has_include = RegisterBuiltinMacro(*this, "__has_include");
Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning");
@@ -857,144 +864,148 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
Feature = Feature.substr(2, Feature.size() - 4);
return llvm::StringSwitch<bool>(Feature)
- .Case("address_sanitizer", LangOpts.Sanitize.Address)
- .Case("attribute_analyzer_noreturn", true)
- .Case("attribute_availability", true)
- .Case("attribute_availability_with_message", true)
- .Case("attribute_cf_returns_not_retained", true)
- .Case("attribute_cf_returns_retained", true)
- .Case("attribute_deprecated_with_message", true)
- .Case("attribute_ext_vector_type", true)
- .Case("attribute_ns_returns_not_retained", true)
- .Case("attribute_ns_returns_retained", true)
- .Case("attribute_ns_consumes_self", true)
- .Case("attribute_ns_consumed", true)
- .Case("attribute_cf_consumed", true)
- .Case("attribute_objc_ivar_unused", true)
- .Case("attribute_objc_method_family", true)
- .Case("attribute_overloadable", true)
- .Case("attribute_unavailable_with_message", true)
- .Case("attribute_unused_on_fields", true)
- .Case("blocks", LangOpts.Blocks)
- .Case("c_thread_safety_attributes", true)
- .Case("cxx_exceptions", LangOpts.CXXExceptions)
- .Case("cxx_rtti", LangOpts.RTTI)
- .Case("enumerator_attributes", true)
- .Case("memory_sanitizer", LangOpts.Sanitize.Memory)
- .Case("thread_sanitizer", LangOpts.Sanitize.Thread)
- .Case("dataflow_sanitizer", LangOpts.Sanitize.DataFlow)
- // Objective-C features
- .Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
- .Case("objc_arc", LangOpts.ObjCAutoRefCount)
- .Case("objc_arc_weak", LangOpts.ObjCARCWeak)
- .Case("objc_default_synthesize_properties", LangOpts.ObjC2)
- .Case("objc_fixed_enum", LangOpts.ObjC2)
- .Case("objc_instancetype", LangOpts.ObjC2)
- .Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules)
- .Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile())
- .Case("objc_property_explicit_atomic", true) // Does clang support explicit "atomic" keyword?
- .Case("objc_protocol_qualifier_mangling", true)
- .Case("objc_weak_class", LangOpts.ObjCRuntime.hasWeakClassImport())
- .Case("ownership_holds", true)
- .Case("ownership_returns", true)
- .Case("ownership_takes", true)
- .Case("objc_bool", true)
- .Case("objc_subscripting", LangOpts.ObjCRuntime.isNonFragile())
- .Case("objc_array_literals", LangOpts.ObjC2)
- .Case("objc_dictionary_literals", LangOpts.ObjC2)
- .Case("objc_boxed_expressions", LangOpts.ObjC2)
- .Case("arc_cf_code_audited", true)
- // C11 features
- .Case("c_alignas", LangOpts.C11)
- .Case("c_atomic", LangOpts.C11)
- .Case("c_generic_selections", LangOpts.C11)
- .Case("c_static_assert", LangOpts.C11)
- .Case("c_thread_local",
- LangOpts.C11 && PP.getTargetInfo().isTLSSupported())
- // C++11 features
- .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus11)
- .Case("cxx_alias_templates", LangOpts.CPlusPlus11)
- .Case("cxx_alignas", LangOpts.CPlusPlus11)
- .Case("cxx_atomic", LangOpts.CPlusPlus11)
- .Case("cxx_attributes", LangOpts.CPlusPlus11)
- .Case("cxx_auto_type", LangOpts.CPlusPlus11)
- .Case("cxx_constexpr", LangOpts.CPlusPlus11)
- .Case("cxx_decltype", LangOpts.CPlusPlus11)
- .Case("cxx_decltype_incomplete_return_types", LangOpts.CPlusPlus11)
- .Case("cxx_default_function_template_args", LangOpts.CPlusPlus11)
- .Case("cxx_defaulted_functions", LangOpts.CPlusPlus11)
- .Case("cxx_delegating_constructors", LangOpts.CPlusPlus11)
- .Case("cxx_deleted_functions", LangOpts.CPlusPlus11)
- .Case("cxx_explicit_conversions", LangOpts.CPlusPlus11)
- .Case("cxx_generalized_initializers", LangOpts.CPlusPlus11)
- .Case("cxx_implicit_moves", LangOpts.CPlusPlus11)
- .Case("cxx_inheriting_constructors", LangOpts.CPlusPlus11)
- .Case("cxx_inline_namespaces", LangOpts.CPlusPlus11)
- .Case("cxx_lambdas", LangOpts.CPlusPlus11)
- .Case("cxx_local_type_template_args", LangOpts.CPlusPlus11)
- .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus11)
- .Case("cxx_noexcept", LangOpts.CPlusPlus11)
- .Case("cxx_nullptr", LangOpts.CPlusPlus11)
- .Case("cxx_override_control", LangOpts.CPlusPlus11)
- .Case("cxx_range_for", LangOpts.CPlusPlus11)
- .Case("cxx_raw_string_literals", LangOpts.CPlusPlus11)
- .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus11)
- .Case("cxx_rvalue_references", LangOpts.CPlusPlus11)
- .Case("cxx_strong_enums", LangOpts.CPlusPlus11)
- .Case("cxx_static_assert", LangOpts.CPlusPlus11)
- .Case("cxx_thread_local",
- LangOpts.CPlusPlus11 && PP.getTargetInfo().isTLSSupported())
- .Case("cxx_trailing_return", LangOpts.CPlusPlus11)
- .Case("cxx_unicode_literals", LangOpts.CPlusPlus11)
- .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus11)
- .Case("cxx_user_literals", LangOpts.CPlusPlus11)
- .Case("cxx_variadic_templates", LangOpts.CPlusPlus11)
- // C++1y features
- .Case("cxx_aggregate_nsdmi", LangOpts.CPlusPlus1y)
- .Case("cxx_binary_literals", LangOpts.CPlusPlus1y)
- .Case("cxx_contextual_conversions", LangOpts.CPlusPlus1y)
- .Case("cxx_decltype_auto", LangOpts.CPlusPlus1y)
- .Case("cxx_generic_lambdas", LangOpts.CPlusPlus1y)
- .Case("cxx_init_captures", LangOpts.CPlusPlus1y)
- .Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus1y)
- .Case("cxx_return_type_deduction", LangOpts.CPlusPlus1y)
- .Case("cxx_variable_templates", LangOpts.CPlusPlus1y)
- // C++ TSes
- //.Case("cxx_runtime_arrays", LangOpts.CPlusPlusTSArrays)
- //.Case("cxx_concepts", LangOpts.CPlusPlusTSConcepts)
- // FIXME: Should this be __has_feature or __has_extension?
- //.Case("raw_invocation_type", LangOpts.CPlusPlus)
- // Type traits
- .Case("has_nothrow_assign", LangOpts.CPlusPlus)
- .Case("has_nothrow_copy", LangOpts.CPlusPlus)
- .Case("has_nothrow_constructor", LangOpts.CPlusPlus)
- .Case("has_trivial_assign", LangOpts.CPlusPlus)
- .Case("has_trivial_copy", LangOpts.CPlusPlus)
- .Case("has_trivial_constructor", LangOpts.CPlusPlus)
- .Case("has_trivial_destructor", LangOpts.CPlusPlus)
- .Case("has_virtual_destructor", LangOpts.CPlusPlus)
- .Case("is_abstract", LangOpts.CPlusPlus)
- .Case("is_base_of", LangOpts.CPlusPlus)
- .Case("is_class", LangOpts.CPlusPlus)
- .Case("is_constructible", LangOpts.CPlusPlus)
- .Case("is_convertible_to", LangOpts.CPlusPlus)
- .Case("is_empty", LangOpts.CPlusPlus)
- .Case("is_enum", LangOpts.CPlusPlus)
- .Case("is_final", 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_sealed", LangOpts.MicrosoftExt)
- .Case("is_trivial", LangOpts.CPlusPlus)
- .Case("is_trivially_assignable", LangOpts.CPlusPlus)
- .Case("is_trivially_constructible", LangOpts.CPlusPlus)
- .Case("is_trivially_copyable", LangOpts.CPlusPlus)
- .Case("is_union", LangOpts.CPlusPlus)
- .Case("modules", LangOpts.Modules)
- .Case("tls", PP.getTargetInfo().isTLSSupported())
- .Case("underlying_type", LangOpts.CPlusPlus)
- .Default(false);
+ .Case("address_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Address))
+ .Case("attribute_analyzer_noreturn", true)
+ .Case("attribute_availability", true)
+ .Case("attribute_availability_with_message", true)
+ .Case("attribute_cf_returns_not_retained", true)
+ .Case("attribute_cf_returns_retained", true)
+ .Case("attribute_deprecated_with_message", true)
+ .Case("attribute_ext_vector_type", true)
+ .Case("attribute_ns_returns_not_retained", true)
+ .Case("attribute_ns_returns_retained", true)
+ .Case("attribute_ns_consumes_self", true)
+ .Case("attribute_ns_consumed", true)
+ .Case("attribute_cf_consumed", true)
+ .Case("attribute_objc_ivar_unused", true)
+ .Case("attribute_objc_method_family", true)
+ .Case("attribute_overloadable", true)
+ .Case("attribute_unavailable_with_message", true)
+ .Case("attribute_unused_on_fields", true)
+ .Case("blocks", LangOpts.Blocks)
+ .Case("c_thread_safety_attributes", true)
+ .Case("cxx_exceptions", LangOpts.CXXExceptions)
+ .Case("cxx_rtti", LangOpts.RTTI)
+ .Case("enumerator_attributes", true)
+ .Case("memory_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Memory))
+ .Case("thread_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Thread))
+ .Case("dataflow_sanitizer", LangOpts.Sanitize.has(SanitizerKind::DataFlow))
+ // Objective-C features
+ .Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
+ .Case("objc_arc", LangOpts.ObjCAutoRefCount)
+ .Case("objc_arc_weak", LangOpts.ObjCARCWeak)
+ .Case("objc_default_synthesize_properties", LangOpts.ObjC2)
+ .Case("objc_fixed_enum", LangOpts.ObjC2)
+ .Case("objc_instancetype", LangOpts.ObjC2)
+ .Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules)
+ .Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile())
+ .Case("objc_property_explicit_atomic",
+ true) // Does clang support explicit "atomic" keyword?
+ .Case("objc_protocol_qualifier_mangling", true)
+ .Case("objc_weak_class", LangOpts.ObjCRuntime.hasWeakClassImport())
+ .Case("ownership_holds", true)
+ .Case("ownership_returns", true)
+ .Case("ownership_takes", true)
+ .Case("objc_bool", true)
+ .Case("objc_subscripting", LangOpts.ObjCRuntime.isNonFragile())
+ .Case("objc_array_literals", LangOpts.ObjC2)
+ .Case("objc_dictionary_literals", LangOpts.ObjC2)
+ .Case("objc_boxed_expressions", LangOpts.ObjC2)
+ .Case("arc_cf_code_audited", true)
+ .Case("objc_bridge_id", LangOpts.ObjC2)
+ // C11 features
+ .Case("c_alignas", LangOpts.C11)
+ .Case("c_alignof", LangOpts.C11)
+ .Case("c_atomic", LangOpts.C11)
+ .Case("c_generic_selections", LangOpts.C11)
+ .Case("c_static_assert", LangOpts.C11)
+ .Case("c_thread_local",
+ LangOpts.C11 && PP.getTargetInfo().isTLSSupported())
+ // C++11 features
+ .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus11)
+ .Case("cxx_alias_templates", LangOpts.CPlusPlus11)
+ .Case("cxx_alignas", LangOpts.CPlusPlus11)
+ .Case("cxx_alignof", LangOpts.CPlusPlus11)
+ .Case("cxx_atomic", LangOpts.CPlusPlus11)
+ .Case("cxx_attributes", LangOpts.CPlusPlus11)
+ .Case("cxx_auto_type", LangOpts.CPlusPlus11)
+ .Case("cxx_constexpr", LangOpts.CPlusPlus11)
+ .Case("cxx_decltype", LangOpts.CPlusPlus11)
+ .Case("cxx_decltype_incomplete_return_types", LangOpts.CPlusPlus11)
+ .Case("cxx_default_function_template_args", LangOpts.CPlusPlus11)
+ .Case("cxx_defaulted_functions", LangOpts.CPlusPlus11)
+ .Case("cxx_delegating_constructors", LangOpts.CPlusPlus11)
+ .Case("cxx_deleted_functions", LangOpts.CPlusPlus11)
+ .Case("cxx_explicit_conversions", LangOpts.CPlusPlus11)
+ .Case("cxx_generalized_initializers", LangOpts.CPlusPlus11)
+ .Case("cxx_implicit_moves", LangOpts.CPlusPlus11)
+ .Case("cxx_inheriting_constructors", LangOpts.CPlusPlus11)
+ .Case("cxx_inline_namespaces", LangOpts.CPlusPlus11)
+ .Case("cxx_lambdas", LangOpts.CPlusPlus11)
+ .Case("cxx_local_type_template_args", LangOpts.CPlusPlus11)
+ .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus11)
+ .Case("cxx_noexcept", LangOpts.CPlusPlus11)
+ .Case("cxx_nullptr", LangOpts.CPlusPlus11)
+ .Case("cxx_override_control", LangOpts.CPlusPlus11)
+ .Case("cxx_range_for", LangOpts.CPlusPlus11)
+ .Case("cxx_raw_string_literals", LangOpts.CPlusPlus11)
+ .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus11)
+ .Case("cxx_rvalue_references", LangOpts.CPlusPlus11)
+ .Case("cxx_strong_enums", LangOpts.CPlusPlus11)
+ .Case("cxx_static_assert", LangOpts.CPlusPlus11)
+ .Case("cxx_thread_local",
+ LangOpts.CPlusPlus11 && PP.getTargetInfo().isTLSSupported())
+ .Case("cxx_trailing_return", LangOpts.CPlusPlus11)
+ .Case("cxx_unicode_literals", LangOpts.CPlusPlus11)
+ .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus11)
+ .Case("cxx_user_literals", LangOpts.CPlusPlus11)
+ .Case("cxx_variadic_templates", LangOpts.CPlusPlus11)
+ // C++1y features
+ .Case("cxx_aggregate_nsdmi", LangOpts.CPlusPlus14)
+ .Case("cxx_binary_literals", LangOpts.CPlusPlus14)
+ .Case("cxx_contextual_conversions", LangOpts.CPlusPlus14)
+ .Case("cxx_decltype_auto", LangOpts.CPlusPlus14)
+ .Case("cxx_generic_lambdas", LangOpts.CPlusPlus14)
+ .Case("cxx_init_captures", LangOpts.CPlusPlus14)
+ .Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus14)
+ .Case("cxx_return_type_deduction", LangOpts.CPlusPlus14)
+ .Case("cxx_variable_templates", LangOpts.CPlusPlus14)
+ // C++ TSes
+ //.Case("cxx_runtime_arrays", LangOpts.CPlusPlusTSArrays)
+ //.Case("cxx_concepts", LangOpts.CPlusPlusTSConcepts)
+ // FIXME: Should this be __has_feature or __has_extension?
+ //.Case("raw_invocation_type", LangOpts.CPlusPlus)
+ // Type traits
+ .Case("has_nothrow_assign", LangOpts.CPlusPlus)
+ .Case("has_nothrow_copy", LangOpts.CPlusPlus)
+ .Case("has_nothrow_constructor", LangOpts.CPlusPlus)
+ .Case("has_trivial_assign", LangOpts.CPlusPlus)
+ .Case("has_trivial_copy", LangOpts.CPlusPlus)
+ .Case("has_trivial_constructor", LangOpts.CPlusPlus)
+ .Case("has_trivial_destructor", LangOpts.CPlusPlus)
+ .Case("has_virtual_destructor", LangOpts.CPlusPlus)
+ .Case("is_abstract", LangOpts.CPlusPlus)
+ .Case("is_base_of", LangOpts.CPlusPlus)
+ .Case("is_class", LangOpts.CPlusPlus)
+ .Case("is_constructible", LangOpts.CPlusPlus)
+ .Case("is_convertible_to", LangOpts.CPlusPlus)
+ .Case("is_empty", LangOpts.CPlusPlus)
+ .Case("is_enum", LangOpts.CPlusPlus)
+ .Case("is_final", 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_sealed", LangOpts.MicrosoftExt)
+ .Case("is_trivial", LangOpts.CPlusPlus)
+ .Case("is_trivially_assignable", LangOpts.CPlusPlus)
+ .Case("is_trivially_constructible", LangOpts.CPlusPlus)
+ .Case("is_trivially_copyable", LangOpts.CPlusPlus)
+ .Case("is_union", LangOpts.CPlusPlus)
+ .Case("modules", LangOpts.Modules)
+ .Case("tls", PP.getTargetInfo().isTLSSupported())
+ .Case("underlying_type", LangOpts.CPlusPlus)
+ .Default(false);
}
/// HasExtension - Return true if we recognize and implement the feature
@@ -1023,6 +1034,7 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
return llvm::StringSwitch<bool>(Extension)
// C11 features supported by other languages as extensions.
.Case("c_alignas", true)
+ .Case("c_alignof", true)
.Case("c_atomic", true)
.Case("c_generic_selections", true)
.Case("c_static_assert", true)
@@ -1050,7 +1062,8 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
/// Returns true if successful.
static bool EvaluateHasIncludeCommon(Token &Tok,
IdentifierInfo *II, Preprocessor &PP,
- const DirectoryLookup *LookupFrom) {
+ const DirectoryLookup *LookupFrom,
+ const FileEntry *LookupFromFile) {
// Save the location of the current token. If a '(' is later found, use
// that location. If not, use the end of this location instead.
SourceLocation LParenLoc = Tok.getLocation();
@@ -1145,8 +1158,8 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Search include directories.
const DirectoryLookup *CurDir;
const FileEntry *File =
- PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, CurDir,
- nullptr, nullptr, nullptr);
+ PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile,
+ CurDir, nullptr, nullptr, nullptr);
// Get the result value. A result of true means the file exists.
return File != nullptr;
@@ -1156,7 +1169,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
/// Returns true if successful.
static bool EvaluateHasInclude(Token &Tok, IdentifierInfo *II,
Preprocessor &PP) {
- return EvaluateHasIncludeCommon(Tok, II, PP, nullptr);
+ return EvaluateHasIncludeCommon(Tok, II, PP, nullptr, nullptr);
}
/// EvaluateHasIncludeNext - Process '__has_include_next("path")' expression.
@@ -1166,10 +1179,19 @@ static bool EvaluateHasIncludeNext(Token &Tok,
// __has_include_next is like __has_include, except that we start
// searching after the current found directory. If we can't do this,
// issue a diagnostic.
+ // FIXME: Factor out duplication wiht
+ // Preprocessor::HandleIncludeNextDirective.
const DirectoryLookup *Lookup = PP.GetCurDirLookup();
+ const FileEntry *LookupFromFile = nullptr;
if (PP.isInPrimaryFile()) {
Lookup = nullptr;
PP.Diag(Tok, diag::pp_include_next_in_primary);
+ } else if (PP.getCurrentSubmodule()) {
+ // Start looking up in the directory *after* the one in which the current
+ // file would be found, if any.
+ assert(PP.getCurrentLexer() && "#include_next directive in macro?");
+ LookupFromFile = PP.getCurrentLexer()->getFileEntry();
+ Lookup = nullptr;
} else if (!Lookup) {
PP.Diag(Tok, diag::pp_include_next_absolute_path);
} else {
@@ -1177,7 +1199,7 @@ static bool EvaluateHasIncludeNext(Token &Tok,
++Lookup;
}
- return EvaluateHasIncludeCommon(Tok, II, PP, Lookup);
+ return EvaluateHasIncludeCommon(Tok, II, PP, Lookup, LookupFromFile);
}
/// \brief Process __building_module(identifier) expression.
@@ -1360,12 +1382,15 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
II == Ident__has_extension ||
II == Ident__has_builtin ||
II == Ident__is_identifier ||
- II == Ident__has_attribute) {
+ II == Ident__has_attribute ||
+ II == Ident__has_declspec ||
+ II == Ident__has_cpp_attribute) {
// The argument to these builtins should be a parenthesized identifier.
SourceLocation StartLoc = Tok.getLocation();
bool IsValid = false;
IdentifierInfo *FeatureII = nullptr;
+ IdentifierInfo *ScopeII = nullptr;
// Read the '('.
LexUnexpandedToken(Tok);
@@ -1373,14 +1398,30 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// Read the identifier
LexUnexpandedToken(Tok);
if ((FeatureII = Tok.getIdentifierInfo())) {
- // Read the ')'.
+ // If we're checking __has_cpp_attribute, it is possible to receive a
+ // scope token. Read the "::", if it's available.
LexUnexpandedToken(Tok);
- if (Tok.is(tok::r_paren))
+ bool IsScopeValid = true;
+ if (II == Ident__has_cpp_attribute && Tok.is(tok::coloncolon)) {
+ LexUnexpandedToken(Tok);
+ // The first thing we read was not the feature, it was the scope.
+ ScopeII = FeatureII;
+ if ((FeatureII = Tok.getIdentifierInfo()))
+ LexUnexpandedToken(Tok);
+ else
+ IsScopeValid = false;
+ }
+ // Read the closing paren.
+ if (IsScopeValid && Tok.is(tok::r_paren))
IsValid = true;
}
+ // Eat tokens until ')'.
+ while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eod) &&
+ Tok.isNot(tok::eof))
+ LexUnexpandedToken(Tok);
}
- bool Value = false;
+ int Value = 0;
if (!IsValid)
Diag(StartLoc, diag::err_feature_check_malformed);
else if (II == Ident__is_identifier)
@@ -1389,7 +1430,13 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// Check for a builtin is trivial.
Value = FeatureII->getBuiltinID() != 0;
} else if (II == Ident__has_attribute)
- Value = hasAttribute(AttrSyntax::Generic, nullptr, FeatureII,
+ Value = hasAttribute(AttrSyntax::GNU, nullptr, FeatureII,
+ getTargetInfo().getTriple(), getLangOpts());
+ else if (II == Ident__has_cpp_attribute)
+ Value = hasAttribute(AttrSyntax::CXX, ScopeII, FeatureII,
+ getTargetInfo().getTriple(), getLangOpts());
+ else if (II == Ident__has_declspec)
+ Value = hasAttribute(AttrSyntax::Declspec, nullptr, FeatureII,
getTargetInfo().getTriple(), getLangOpts());
else if (II == Ident__has_extension)
Value = HasExtension(*this, FeatureII);
@@ -1398,9 +1445,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Value = HasFeature(*this, FeatureII);
}
- OS << (int)Value;
- if (IsValid)
- Tok.setKind(tok::numeric_constant);
+ if (!IsValid)
+ return;
+ OS << Value;
+ Tok.setKind(tok::numeric_constant);
} else if (II == Ident__has_include ||
II == Ident__has_include_next) {
// The argument to these two builtins should be a parenthesized
@@ -1464,9 +1512,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
WarningName.substr(2), Diags);
} while (false);
+ if (!IsValid)
+ return;
OS << (int)Value;
- if (IsValid)
- Tok.setKind(tok::numeric_constant);
+ Tok.setKind(tok::numeric_constant);
} else if (II == Ident__building_module) {
// The argument to this builtin should be an identifier. The
// builtin evaluates to 1 when that identifier names the module we are
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index fce31c4be296..af7a15384e35 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -24,7 +24,6 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/OnDiskHashTable.h"
#include <memory>
#include <system_error>
using namespace clang;
@@ -342,7 +341,9 @@ public:
}
};
-class PTHFileLookupTrait : public PTHFileLookupCommonTrait {
+} // end anonymous namespace
+
+class PTHManager::PTHFileLookupTrait : public PTHFileLookupCommonTrait {
public:
typedef const FileEntry* external_key_type;
typedef PTHFileData data_type;
@@ -365,7 +366,7 @@ public:
}
};
-class PTHStringLookupTrait {
+class PTHManager::PTHStringLookupTrait {
public:
typedef uint32_t data_type;
typedef const std::pair<const char*, unsigned> external_key_type;
@@ -408,31 +409,22 @@ public:
}
};
-} // end anonymous namespace
-
-typedef llvm::OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup;
-typedef llvm::OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup;
-
//===----------------------------------------------------------------------===//
// PTHManager methods.
//===----------------------------------------------------------------------===//
-PTHManager::PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup,
- const unsigned char* idDataTable,
- IdentifierInfo** perIDCache,
- void* stringIdLookup, unsigned numIds,
- const unsigned char* spellingBase,
- const char* originalSourceFile)
-: Buf(buf), PerIDCache(perIDCache), FileLookup(fileLookup),
- IdDataTable(idDataTable), StringIdLookup(stringIdLookup),
- NumIds(numIds), PP(nullptr), SpellingBase(spellingBase),
- OriginalSourceFile(originalSourceFile) {}
+PTHManager::PTHManager(
+ std::unique_ptr<const llvm::MemoryBuffer> buf,
+ std::unique_ptr<PTHFileLookup> fileLookup, const unsigned char *idDataTable,
+ std::unique_ptr<IdentifierInfo *[], llvm::FreeDeleter> perIDCache,
+ std::unique_ptr<PTHStringIdLookup> stringIdLookup, unsigned numIds,
+ const unsigned char *spellingBase, const char *originalSourceFile)
+ : Buf(std::move(buf)), PerIDCache(std::move(perIDCache)),
+ FileLookup(std::move(fileLookup)), IdDataTable(idDataTable),
+ StringIdLookup(std::move(stringIdLookup)), NumIds(numIds), PP(nullptr),
+ SpellingBase(spellingBase), OriginalSourceFile(originalSourceFile) {}
PTHManager::~PTHManager() {
- delete Buf;
- delete (PTHFileLookup*) FileLookup;
- delete (PTHStringIdLookup*) StringIdLookup;
- free(PerIDCache);
}
static void InvalidPTH(DiagnosticsEngine &Diags, const char *Msg) {
@@ -543,10 +535,10 @@ PTHManager *PTHManager::Create(const std::string &file,
// Pre-allocate the persistent ID -> IdentifierInfo* cache. We use calloc()
// so that we in the best case only zero out memory once when the OS returns
// us new pages.
- IdentifierInfo **PerIDCache = nullptr;
+ std::unique_ptr<IdentifierInfo *[], llvm::FreeDeleter> PerIDCache;
if (NumIds) {
- PerIDCache = (IdentifierInfo**)calloc(NumIds, sizeof(*PerIDCache));
+ PerIDCache.reset((IdentifierInfo **)calloc(NumIds, sizeof(PerIDCache[0])));
if (!PerIDCache) {
InvalidPTH(Diags, "Could not allocate memory for processing PTH file");
return nullptr;
@@ -560,9 +552,9 @@ PTHManager *PTHManager::Create(const std::string &file,
if (!len) originalSourceBase = nullptr;
// Create the new PTHManager.
- return new PTHManager(File.release(), FL.release(), IData, PerIDCache,
- SL.release(), NumIds, spellingBase,
- (const char *)originalSourceBase);
+ return new PTHManager(std::move(File), std::move(FL), IData,
+ std::move(PerIDCache), std::move(SL), NumIds,
+ spellingBase, (const char *)originalSourceBase);
}
IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) {
@@ -589,12 +581,11 @@ IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) {
}
IdentifierInfo* PTHManager::get(StringRef Name) {
- PTHStringIdLookup& SL = *((PTHStringIdLookup*)StringIdLookup);
// Double check our assumption that the last character isn't '\0'.
assert(Name.empty() || Name.back() != '\0');
- PTHStringIdLookup::iterator I = SL.find(std::make_pair(Name.data(),
- Name.size()));
- if (I == SL.end()) // No identifier found?
+ PTHStringIdLookup::iterator I =
+ StringIdLookup->find(std::make_pair(Name.data(), Name.size()));
+ if (I == StringIdLookup->end()) // No identifier found?
return nullptr;
// Match found. Return the identifier!
@@ -612,10 +603,9 @@ PTHLexer *PTHManager::CreateLexer(FileID FID) {
// Lookup the FileEntry object in our file lookup data structure. It will
// return a variant that indicates whether or not there is an offset within
// the PTH file that contains cached tokens.
- PTHFileLookup& PFL = *((PTHFileLookup*)FileLookup);
- PTHFileLookup::iterator I = PFL.find(FE);
+ PTHFileLookup::iterator I = FileLookup->find(FE);
- if (I == PFL.end()) // No tokens available?
+ if (I == FileLookup->end()) // No tokens available?
return nullptr;
const PTHFileData& FileData = *I;
@@ -684,7 +674,7 @@ public:
uint64_t File = endian::readNext<uint64_t, little, unaligned>(d);
uint64_t Device = endian::readNext<uint64_t, little, unaligned>(d);
- llvm::sys::fs::UniqueID UniqueID(File, Device);
+ llvm::sys::fs::UniqueID UniqueID(Device, File);
time_t ModTime = endian::readNext<uint64_t, little, unaligned>(d);
uint64_t Size = endian::readNext<uint64_t, little, unaligned>(d);
return data_type(Size, ModTime, UniqueID, IsDirectory);
@@ -694,15 +684,17 @@ public:
return data_type();
}
};
+} // end anonymous namespace
+namespace clang {
class PTHStatCache : public FileSystemStatCache {
typedef llvm::OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy;
CacheTy Cache;
public:
- PTHStatCache(PTHFileLookup &FL) :
- Cache(FL.getNumBuckets(), FL.getNumEntries(), FL.getBuckets(),
- FL.getBase()) {}
+ PTHStatCache(PTHManager::PTHFileLookup &FL)
+ : Cache(FL.getNumBuckets(), FL.getNumEntries(), FL.getBuckets(),
+ FL.getBase()) {}
LookupResult getStat(const char *Path, FileData &Data, bool isFile,
std::unique_ptr<vfs::File> *F,
@@ -730,8 +722,8 @@ public:
return CacheExists;
}
};
-} // end anonymous namespace
+}
-FileSystemStatCache *PTHManager::createStatCache() {
- return new PTHStatCache(*((PTHFileLookup*) FileLookup));
+std::unique_ptr<FileSystemStatCache> PTHManager::createStatCache() {
+ return llvm::make_unique<PTHStatCache>(*FileLookup);
}
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index cf76bdb7a913..8ed832893771 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -65,9 +65,7 @@ PragmaHandler *PragmaNamespace::FindHandler(StringRef Name,
void PragmaNamespace::AddPragma(PragmaHandler *Handler) {
assert(!Handlers.lookup(Handler->getName()) &&
"A handler with this name is already registered in this namespace");
- llvm::StringMapEntry<PragmaHandler *> &Entry =
- Handlers.GetOrCreateValue(Handler->getName());
- Entry.setValue(Handler);
+ Handlers[Handler->getName()] = Handler;
}
void PragmaNamespace::RemovePragmaHandler(PragmaHandler *Handler) {
@@ -193,7 +191,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
if (!tok::isStringLiteral(Tok.getKind())) {
Diag(PragmaLoc, diag::err__Pragma_malformed);
// Skip this token, and the ')', if present.
- if (Tok.isNot(tok::r_paren))
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eof))
Lex(Tok);
if (Tok.is(tok::r_paren))
Lex(Tok);
@@ -472,9 +470,9 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Search include directories for this file.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(FilenameTok.getLocation(), Filename,
- isAngled, nullptr, CurDir, nullptr,
- nullptr, nullptr);
+ const FileEntry *File =
+ LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
+ nullptr, CurDir, nullptr, nullptr, nullptr);
if (!File) {
if (!SuppressIncludeNotFoundError)
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
@@ -605,7 +603,7 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
if (MacroToReInstall) {
// Reinstall the previously pushed macro.
appendDefMacroDirective(IdentInfo, MacroToReInstall, MessageLoc,
- /*isImported=*/false);
+ /*isImported=*/false, /*Overrides*/None);
}
// Pop PragmaPushMacroInfo stack.
@@ -728,7 +726,7 @@ void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) {
/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
void Preprocessor::AddPragmaHandler(StringRef Namespace,
PragmaHandler *Handler) {
- PragmaNamespace *InsertNS = PragmaHandlers;
+ PragmaNamespace *InsertNS = PragmaHandlers.get();
// If this is specified to be in a namespace, step down into it.
if (!Namespace.empty()) {
@@ -759,7 +757,7 @@ void Preprocessor::AddPragmaHandler(StringRef Namespace,
/// a handler that has not been registered.
void Preprocessor::RemovePragmaHandler(StringRef Namespace,
PragmaHandler *Handler) {
- PragmaNamespace *NS = PragmaHandlers;
+ PragmaNamespace *NS = PragmaHandlers.get();
// If this is specified to be in a namespace, step down into it.
if (!Namespace.empty()) {
@@ -772,9 +770,8 @@ void Preprocessor::RemovePragmaHandler(StringRef Namespace,
NS->RemovePragmaHandler(Handler);
- // If this is a non-default namespace and it is now empty, remove
- // it.
- if (NS != PragmaHandlers && NS->IsEmpty()) {
+ // If this is a non-default namespace and it is now empty, remove it.
+ if (NS != PragmaHandlers.get() && NS->IsEmpty()) {
PragmaHandlers->RemovePragmaHandler(NS);
delete NS;
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 4a11803aa954..b2a6d933a0f2 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -27,6 +27,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/CodeCompletionHandler.h"
@@ -61,19 +62,21 @@ Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
IdentifierInfoLookup *IILookup, bool OwnsHeaders,
TranslationUnitKind TUKind)
: PPOpts(PPOpts), Diags(&diags), LangOpts(opts), Target(nullptr),
- FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers),
+ FileMgr(Headers.getFileMgr()), SourceMgr(SM),
+ ScratchBuf(new ScratchBuffer(SourceMgr)),HeaderInfo(Headers),
TheModuleLoader(TheModuleLoader), ExternalSource(nullptr),
- Identifiers(opts, IILookup), IncrementalProcessing(false), TUKind(TUKind),
+ Identifiers(opts, IILookup),
+ PragmaHandlers(new PragmaNamespace(StringRef())),
+ IncrementalProcessing(false), TUKind(TUKind),
CodeComplete(nullptr), CodeCompletionFile(nullptr),
CodeCompletionOffset(0), LastTokenWasAt(false),
ModuleImportExpectsIdentifier(false), CodeCompletionReached(0),
- SkipMainFilePreamble(0, true), CurPPLexer(nullptr),
+ MainFileDir(nullptr), SkipMainFilePreamble(0, true), CurPPLexer(nullptr),
CurDirLookup(nullptr), CurLexerKind(CLK_Lexer), CurSubmodule(nullptr),
Callbacks(nullptr), MacroArgCache(nullptr), Record(nullptr),
- MIChainHead(nullptr), MICache(nullptr), DeserialMIChainHead(nullptr) {
+ MIChainHead(nullptr), DeserialMIChainHead(nullptr) {
OwnsHeaderSearch = OwnsHeaders;
- ScratchBuf = new ScratchBuffer(SourceMgr);
CounterValue = 0; // __COUNTER__ starts at 0.
// Clear stats.
@@ -111,7 +114,6 @@ Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use);
// Initialize the pragma handlers.
- PragmaHandlers = new PragmaNamespace(StringRef());
RegisterBuiltinPragmas();
// Initialize builtin macros like __LINE__ and friends.
@@ -141,35 +143,30 @@ Preprocessor::~Preprocessor() {
IncludeMacroStack.clear();
- // Free any macro definitions.
- for (MacroInfoChain *I = MIChainHead ; I ; I = I->Next)
- I->MI.Destroy();
+ // Destroy any macro definitions.
+ while (MacroInfoChain *I = MIChainHead) {
+ MIChainHead = I->Next;
+ I->~MacroInfoChain();
+ }
// Free any cached macro expanders.
// This populates MacroArgCache, so all TokenLexers need to be destroyed
// before the code below that frees up the MacroArgCache list.
- for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i)
- delete TokenLexerCache[i];
+ std::fill(TokenLexerCache, TokenLexerCache + NumCachedTokenLexers, nullptr);
CurTokenLexer.reset();
- for (DeserializedMacroInfoChain *I = DeserialMIChainHead ; I ; I = I->Next)
- I->MI.Destroy();
+ while (DeserializedMacroInfoChain *I = DeserialMIChainHead) {
+ DeserialMIChainHead = I->Next;
+ I->~DeserializedMacroInfoChain();
+ }
// Free any cached MacroArgs.
for (MacroArgs *ArgList = MacroArgCache; ArgList;)
ArgList = ArgList->deallocate();
- // Release pragma information.
- delete PragmaHandlers;
-
- // Delete the scratch buffer info.
- delete ScratchBuf;
-
// Delete the header search info, if we own it.
if (OwnsHeaderSearch)
delete &HeaderInfo;
-
- delete Callbacks;
}
void Preprocessor::Initialize(const TargetInfo &Target) {
@@ -182,6 +179,24 @@ void Preprocessor::Initialize(const TargetInfo &Target) {
HeaderInfo.setTarget(Target);
}
+void Preprocessor::InitializeForModelFile() {
+ NumEnteredSourceFiles = 0;
+
+ // Reset pragmas
+ PragmaHandlersBackup = std::move(PragmaHandlers);
+ PragmaHandlers = llvm::make_unique<PragmaNamespace>(StringRef());
+ RegisterBuiltinPragmas();
+
+ // Reset PredefinesFileID
+ PredefinesFileID = FileID();
+}
+
+void Preprocessor::FinalizeForModelFile() {
+ NumEnteredSourceFiles = 1;
+
+ PragmaHandlers = std::move(PragmaHandlersBackup);
+}
+
void Preprocessor::setPTHManager(PTHManager* pm) {
PTH.reset(pm);
FileMgr.addStatCache(PTH->createStatCache());
@@ -370,21 +385,29 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
Position += CompleteColumn - 1;
- // Insert '\0' at the code-completion point.
- if (Position < Buffer->getBufferEnd()) {
- CodeCompletionFile = File;
- CodeCompletionOffset = Position - Buffer->getBufferStart();
-
- MemoryBuffer *NewBuffer =
- MemoryBuffer::getNewUninitMemBuffer(Buffer->getBufferSize() + 1,
- Buffer->getBufferIdentifier());
- char *NewBuf = const_cast<char*>(NewBuffer->getBufferStart());
- char *NewPos = std::copy(Buffer->getBufferStart(), Position, NewBuf);
- *NewPos = '\0';
- std::copy(Position, Buffer->getBufferEnd(), NewPos+1);
- SourceMgr.overrideFileContents(File, NewBuffer);
+ // If pointing inside the preamble, adjust the position at the beginning of
+ // the file after the preamble.
+ if (SkipMainFilePreamble.first &&
+ SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()) == File) {
+ if (Position - Buffer->getBufferStart() < SkipMainFilePreamble.first)
+ Position = Buffer->getBufferStart() + SkipMainFilePreamble.first;
}
+ if (Position > Buffer->getBufferEnd())
+ Position = Buffer->getBufferEnd();
+
+ CodeCompletionFile = File;
+ CodeCompletionOffset = Position - Buffer->getBufferStart();
+
+ std::unique_ptr<MemoryBuffer> NewBuffer =
+ MemoryBuffer::getNewUninitMemBuffer(Buffer->getBufferSize() + 1,
+ Buffer->getBufferIdentifier());
+ char *NewBuf = const_cast<char*>(NewBuffer->getBufferStart());
+ char *NewPos = std::copy(Buffer->getBufferStart(), Position, NewBuf);
+ *NewPos = '\0';
+ std::copy(Position, Buffer->getBufferEnd(), NewPos+1);
+ SourceMgr.overrideFileContents(File, std::move(NewBuffer));
+
return false;
}
@@ -479,10 +502,10 @@ void Preprocessor::EnterMainSourceFile() {
}
// Preprocess Predefines to populate the initial preprocessor state.
- llvm::MemoryBuffer *SB =
+ std::unique_ptr<llvm::MemoryBuffer> SB =
llvm::MemoryBuffer::getMemBufferCopy(Predefines, "<built-in>");
assert(SB && "Cannot create predefined source buffer");
- FileID FID = SourceMgr.createFileID(SB);
+ FileID FID = SourceMgr.createFileID(std::move(SB));
assert(!FID.isInvalid() && "Could not create FileID for predefines?");
setPredefinesFileID(FID);
@@ -649,7 +672,8 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
// keyword when we're in a caching lexer, because caching lexers only get
// used in contexts where import declarations are disallowed.
if (LastTokenWasAt && II.isModulesImport() && !InMacroArgs &&
- !DisableMacroExpansion && getLangOpts().Modules &&
+ !DisableMacroExpansion &&
+ (getLangOpts().Modules || getLangOpts().DebuggerSupport) &&
CurLexerKind != CLK_CachingLexer) {
ModuleImportLoc = Identifier.getLocation();
ModuleImportPath.clear();
@@ -722,12 +746,14 @@ void Preprocessor::LexAfterModuleImport(Token &Result) {
}
// If we have a non-empty module path, load the named module.
- if (!ModuleImportPath.empty() && getLangOpts().Modules) {
- Module *Imported = TheModuleLoader.loadModule(ModuleImportLoc,
- ModuleImportPath,
- Module::MacrosVisible,
- /*IsIncludeDirective=*/false);
- if (Callbacks)
+ if (!ModuleImportPath.empty()) {
+ Module *Imported = nullptr;
+ if (getLangOpts().Modules)
+ Imported = TheModuleLoader.loadModule(ModuleImportLoc,
+ ModuleImportPath,
+ Module::MacrosVisible,
+ /*IsIncludeDirective=*/false);
+ if (Callbacks && (getLangOpts().Modules || getLangOpts().DebuggerSupport))
Callbacks->moduleImport(ModuleImportLoc, ModuleImportPath, Imported);
}
}
@@ -830,5 +856,5 @@ void Preprocessor::createPreprocessingRecord() {
return;
Record = new PreprocessingRecord(getSourceManager());
- addPPCallbacks(Record);
+ addPPCallbacks(std::unique_ptr<PPCallbacks>(Record));
}
diff --git a/lib/Lex/ScratchBuffer.cpp b/lib/Lex/ScratchBuffer.cpp
index d7104b178860..3bac8891c646 100644
--- a/lib/Lex/ScratchBuffer.cpp
+++ b/lib/Lex/ScratchBuffer.cpp
@@ -64,11 +64,12 @@ void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) {
if (RequestLen < ScratchBufSize)
RequestLen = ScratchBufSize;
- llvm::MemoryBuffer *Buf =
- llvm::MemoryBuffer::getNewMemBuffer(RequestLen, "<scratch space>");
- FileID FID = SourceMgr.createFileID(Buf);
+ std::unique_ptr<llvm::MemoryBuffer> OwnBuf =
+ llvm::MemoryBuffer::getNewMemBuffer(RequestLen, "<scratch space>");
+ llvm::MemoryBuffer &Buf = *OwnBuf;
+ FileID FID = SourceMgr.createFileID(std::move(OwnBuf));
BufferStartLoc = SourceMgr.getLocForStartOfFile(FID);
- CurBuffer = const_cast<char*>(Buf->getBufferStart());
+ CurBuffer = const_cast<char*>(Buf.getBufferStart());
BytesUsed = 1;
CurBuffer[0] = '0'; // Start out with a \0 for cleanliness.
}
diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp
index 0a66bba91fcd..08327496ab8a 100644
--- a/lib/Lex/TokenConcatenation.cpp
+++ b/lib/Lex/TokenConcatenation.cpp
@@ -99,6 +99,10 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
TokenInfo[tok::utf32_char_constant ] |= aci_custom;
}
+ // These tokens have custom code in C++1z mode.
+ if (PP.getLangOpts().CPlusPlus1z)
+ TokenInfo[tok::utf8_char_constant] |= aci_custom;
+
// These tokens change behavior if followed by an '='.
TokenInfo[tok::amp ] |= aci_avoid_equal; // &=
TokenInfo[tok::plus ] |= aci_avoid_equal; // +=
@@ -163,8 +167,8 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
return false;
tok::TokenKind PrevKind = PrevTok.getKind();
- if (PrevTok.getIdentifierInfo()) // Language keyword or named operator.
- PrevKind = tok::identifier;
+ if (!PrevTok.isAnnotation() && PrevTok.getIdentifierInfo())
+ PrevKind = tok::identifier; // Language keyword or named operator.
// Look up information on when we should avoid concatenation with prevtok.
unsigned ConcatInfo = TokenInfo[PrevKind];
@@ -178,6 +182,14 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
return true;
ConcatInfo &= ~aci_avoid_equal;
}
+ if (Tok.isAnnotation()) {
+ // Modules annotation can show up when generated automatically for includes.
+ assert((Tok.is(tok::annot_module_include) ||
+ Tok.is(tok::annot_module_begin) ||
+ Tok.is(tok::annot_module_end)) &&
+ "unexpected annotation in AvoidConcat");
+ ConcatInfo = 0;
+ }
if (ConcatInfo == 0) return false;
@@ -205,6 +217,7 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
case tok::utf32_string_literal:
case tok::char_constant:
case tok::wide_char_constant:
+ case tok::utf8_char_constant:
case tok::utf16_char_constant:
case tok::utf32_char_constant:
if (!PP.getLangOpts().CPlusPlus11)
@@ -228,7 +241,8 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
if (Tok.getIdentifierInfo() || Tok.is(tok::wide_string_literal) ||
Tok.is(tok::utf8_string_literal) || Tok.is(tok::utf16_string_literal) ||
Tok.is(tok::utf32_string_literal) || Tok.is(tok::wide_char_constant) ||
- Tok.is(tok::utf16_char_constant) || Tok.is(tok::utf32_char_constant))
+ Tok.is(tok::utf8_char_constant) || Tok.is(tok::utf16_char_constant) ||
+ Tok.is(tok::utf32_char_constant))
return true;
// If this isn't identifier + string, we're done.
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index 9d03e8d30b8b..5f4705eff697 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -206,6 +206,7 @@ void TokenLexer::ExpandFunctionArguments() {
ExpansionLocStart,
ExpansionLocEnd);
}
+ Res.setFlag(Token::StringifiedInMacro);
// The stringified/charified string leading space flag gets set to match
// the #/#@ operator.
@@ -405,6 +406,14 @@ void TokenLexer::ExpandFunctionArguments() {
}
}
+/// \brief Checks if two tokens form wide string literal.
+static bool isWideStringLiteralFromMacro(const Token &FirstTok,
+ const Token &SecondTok) {
+ return FirstTok.is(tok::identifier) &&
+ FirstTok.getIdentifierInfo()->isStr("L") && SecondTok.isLiteral() &&
+ SecondTok.stringifiedInMacro();
+}
+
/// Lex - Lex and return a token from this macro stream.
///
bool TokenLexer::Lex(Token &Tok) {
@@ -435,7 +444,13 @@ bool TokenLexer::Lex(Token &Tok) {
// If this token is followed by a token paste (##) operator, paste the tokens!
// Note that ## is a normal token when not expanding a macro.
- if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash) && Macro) {
+ if (!isAtEnd() && Macro &&
+ (Tokens[CurToken].is(tok::hashhash) ||
+ // Special processing of L#x macros in -fms-compatibility mode.
+ // Microsoft compiler is able to form a wide string literal from
+ // 'L#macro_arg' construct in a function-like macro.
+ (PP.getLangOpts().MSVCCompat &&
+ isWideStringLiteralFromMacro(Tok, Tokens[CurToken])))) {
// When handling the microsoft /##/ extension, the final token is
// returned by PasteTokens, not the pasted token.
if (PasteTokens(Tok))
@@ -511,9 +526,10 @@ bool TokenLexer::PasteTokens(Token &Tok) {
SourceLocation StartLoc = Tok.getLocation();
SourceLocation PasteOpLoc;
do {
- // Consume the ## operator.
+ // Consume the ## operator if any.
PasteOpLoc = Tokens[CurToken].getLocation();
- ++CurToken;
+ if (Tokens[CurToken].is(tok::hashhash))
+ ++CurToken;
assert(!isAtEnd() && "No token on the RHS of a paste operator!");
// Get the RHS token.
@@ -531,12 +547,13 @@ bool TokenLexer::PasteTokens(Token &Tok) {
memcpy(&Buffer[0], BufPtr, LHSLen);
if (Invalid)
return true;
-
- BufPtr = &Buffer[LHSLen];
+
+ BufPtr = Buffer.data() + LHSLen;
unsigned RHSLen = PP.getSpelling(RHS, BufPtr, &Invalid);
if (Invalid)
return true;
- if (BufPtr != &Buffer[LHSLen]) // Really, we want the chars in Buffer!
+ if (RHSLen && BufPtr != &Buffer[LHSLen])
+ // Really, we want the chars in Buffer!
memcpy(&Buffer[LHSLen], BufPtr, RHSLen);
// Trim excess space.
diff --git a/lib/Lex/UnicodeCharSets.h b/lib/Lex/UnicodeCharSets.h
index 12b24564bfd3..116d553d2040 100644
--- a/lib/Lex/UnicodeCharSets.h
+++ b/lib/Lex/UnicodeCharSets.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef CLANG_LEX_UNICODECHARSETS_H
-#define CLANG_LEX_UNICODECHARSETS_H
+#ifndef LLVM_CLANG_LIB_LEX_UNICODECHARSETS_H
+#define LLVM_CLANG_LIB_LEX_UNICODECHARSETS_H
#include "llvm/Support/UnicodeCharRanges.h"
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index 0f5a1b3ffbd6..6727afc1dd6c 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -14,7 +14,6 @@
#include "clang/Parse/ParseAST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Stmt.h"
#include "clang/Parse/ParseDiagnostic.h"
@@ -146,10 +145,8 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
}
// Process any TopLevelDecls generated by #pragma weak.
- for (SmallVectorImpl<Decl *>::iterator
- I = S.WeakTopLevelDecls().begin(),
- E = S.WeakTopLevelDecls().end(); I != E; ++I)
- Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
+ for (Decl *D : S.WeakTopLevelDecls())
+ Consumer->HandleTopLevelDecl(DeclGroupRef(D));
Consumer->HandleTranslationUnit(S.getASTContext());
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 30a9120a5106..59b491abfd15 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -218,6 +218,7 @@ void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) {
Eof.startToken();
Eof.setKind(tok::eof);
Eof.setLocation(Tok.getLocation());
+ Eof.setEofData(VarD);
Toks.push_back(Eof);
}
@@ -308,10 +309,17 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
// Introduce the parameter into scope.
Actions.ActOnDelayedCXXMethodParameter(getCurScope(),
LM.DefaultArgs[I].Param);
-
if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
- // Save the current token position.
- SourceLocation origLoc = Tok.getLocation();
+ // Mark the end of the default argument so that we know when to stop when
+ // we parse it later on.
+ Token LastDefaultArgToken = Toks->back();
+ Token DefArgEnd;
+ DefArgEnd.startToken();
+ DefArgEnd.setKind(tok::eof);
+ DefArgEnd.setLocation(LastDefaultArgToken.getLocation().getLocWithOffset(
+ LastDefaultArgToken.getLength()));
+ DefArgEnd.setEofData(LM.DefaultArgs[I].Param);
+ Toks->push_back(DefArgEnd);
// Parse the default argument from its saved token stream.
Toks->push_back(Tok); // So that the current token doesn't get lost
@@ -336,11 +344,13 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
DefArgResult = ParseBraceInitializer();
} else
DefArgResult = ParseAssignmentExpression();
- if (DefArgResult.isInvalid())
+ DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult);
+ if (DefArgResult.isInvalid()) {
Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param,
EqualLoc);
- else {
- if (!TryConsumeToken(tok::cxx_defaultarg_end)) {
+ } else {
+ if (Tok.isNot(tok::eof) ||
+ Tok.getEofData() != LM.DefaultArgs[I].Param) {
// The last two tokens are the terminator and the saved value of
// Tok; the last token in the default argument is the one before
// those.
@@ -353,12 +363,12 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
DefArgResult.get());
}
- assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
- Tok.getLocation()) &&
- "ParseAssignmentExpression went over the default arg tokens!");
// There could be leftover tokens (e.g. because of an error).
- // Skip through until we reach the original token position.
- while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
+ // Skip through until we reach the 'end of default argument' token.
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+
+ if (Tok.is(tok::eof) && Tok.getEofData() == LM.DefaultArgs[I].Param)
ConsumeAnyToken();
delete Toks;
@@ -366,6 +376,80 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
}
}
+ // Parse a delayed exception-specification, if there is one.
+ if (CachedTokens *Toks = LM.ExceptionSpecTokens) {
+ // Add the 'stop' token.
+ Token LastExceptionSpecToken = Toks->back();
+ Token ExceptionSpecEnd;
+ ExceptionSpecEnd.startToken();
+ ExceptionSpecEnd.setKind(tok::eof);
+ ExceptionSpecEnd.setLocation(
+ LastExceptionSpecToken.getLocation().getLocWithOffset(
+ LastExceptionSpecToken.getLength()));
+ ExceptionSpecEnd.setEofData(LM.Method);
+ Toks->push_back(ExceptionSpecEnd);
+
+ // Parse the default argument from its saved token stream.
+ Toks->push_back(Tok); // So that the current token doesn't get lost
+ PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);
+
+ // Consume the previously-pushed token.
+ ConsumeAnyToken();
+
+ // C++11 [expr.prim.general]p3:
+ // If a declaration declares a member function or member function
+ // template of a class X, the expression this is a prvalue of type
+ // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
+ // and the end of the function-definition, member-declarator, or
+ // declarator.
+ CXXMethodDecl *Method;
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(LM.Method))
+ Method = cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ Method = cast<CXXMethodDecl>(LM.Method);
+
+ Sema::CXXThisScopeRAII ThisScope(Actions, Method->getParent(),
+ Method->getTypeQualifiers(),
+ getLangOpts().CPlusPlus11);
+
+ // Parse the exception-specification.
+ SourceRange SpecificationRange;
+ SmallVector<ParsedType, 4> DynamicExceptions;
+ SmallVector<SourceRange, 4> DynamicExceptionRanges;
+ ExprResult NoexceptExpr;
+ CachedTokens *ExceptionSpecTokens;
+
+ ExceptionSpecificationType EST
+ = tryParseExceptionSpecification(/*Delayed=*/false, SpecificationRange,
+ DynamicExceptions,
+ DynamicExceptionRanges, NoexceptExpr,
+ ExceptionSpecTokens);
+
+ if (Tok.isNot(tok::eof) || Tok.getEofData() != LM.Method)
+ Diag(Tok.getLocation(), diag::err_except_spec_unparsed);
+
+ // Attach the exception-specification to the method.
+ Actions.actOnDelayedExceptionSpecification(LM.Method, EST,
+ SpecificationRange,
+ DynamicExceptions,
+ DynamicExceptionRanges,
+ NoexceptExpr.isUsable()?
+ NoexceptExpr.get() : nullptr);
+
+ // There could be leftover tokens (e.g. because of an error).
+ // Skip through until we reach the original token position.
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+
+ // Clean up the remaining EOF token.
+ if (Tok.is(tok::eof) && Tok.getEofData() == LM.Method)
+ ConsumeAnyToken();
+
+ delete Toks;
+ LM.ExceptionSpecTokens = nullptr;
+ }
+
PrototypeScope.Exit();
// Finish the delayed C++ method declaration.
@@ -400,10 +484,16 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
Actions.ActOnReenterTemplateScope(getCurScope(), LM.D);
++CurTemplateDepthTracker;
}
- // Save the current token position.
- SourceLocation origLoc = Tok.getLocation();
assert(!LM.Toks.empty() && "Empty body!");
+ Token LastBodyToken = LM.Toks.back();
+ Token BodyEnd;
+ BodyEnd.startToken();
+ BodyEnd.setKind(tok::eof);
+ BodyEnd.setLocation(
+ LastBodyToken.getLocation().getLocWithOffset(LastBodyToken.getLength()));
+ BodyEnd.setEofData(LM.D);
+ LM.Toks.push_back(BodyEnd);
// Append the current token at the end of the new token stream so that it
// doesn't get lost.
LM.Toks.push_back(Tok);
@@ -421,12 +511,11 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
if (Tok.is(tok::kw_try)) {
ParseFunctionTryBlock(LM.D, FnScope);
- assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
- Tok.getLocation()) &&
- "ParseFunctionTryBlock went over the cached tokens!");
- // There could be leftover tokens (e.g. because of an error).
- // Skip through until we reach the original token position.
- while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
+
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+
+ if (Tok.is(tok::eof) && Tok.getEofData() == LM.D)
ConsumeAnyToken();
return;
}
@@ -437,7 +526,11 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
if (!Tok.is(tok::l_brace)) {
FnScope.Exit();
Actions.ActOnFinishFunctionBody(LM.D, nullptr);
- while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
+
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+
+ if (Tok.is(tok::eof) && Tok.getEofData() == LM.D)
ConsumeAnyToken();
return;
}
@@ -457,17 +550,11 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
if (LM.D)
LM.D->getAsFunction()->setLateTemplateParsed(false);
- if (Tok.getLocation() != origLoc) {
- // Due to parsing error, we either went over the cached tokens or
- // there are still cached tokens left. If it's the latter case skip the
- // leftover tokens.
- // Since this is an uncommon situation that should be avoided, use the
- // expensive isBeforeInTranslationUnit call.
- if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
- origLoc))
- while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
- ConsumeAnyToken();
- }
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+
+ if (Tok.is(tok::eof) && Tok.getEofData() == LM.D)
+ ConsumeAnyToken();
if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(LM.D))
Actions.ActOnFinishInlineMethodDef(MD);
@@ -540,17 +627,21 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
// 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);
+ if (!Init.isInvalid()) {
+ 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();
+ // Make sure this is *our* artificial EOF token.
+ if (Tok.getEofData() == MI.Field)
+ ConsumeAnyToken();
}
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
@@ -891,11 +982,13 @@ private:
/// ConsumeAndStoreInitializer - Consume and store the token at the passed token
/// container until the end of the current initializer expression (either a
/// default argument or an in-class initializer for a non-static data member).
-/// The final token is not consumed.
+///
+/// Returns \c true if we reached the end of something initializer-shaped,
+/// \c false if we bailed out.
bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
CachedInitKind CIK) {
// We always want this function to consume at least one token if not at EOF.
- bool IsFirstTokenConsumed = true;
+ bool IsFirstToken = true;
// Number of possible unclosed <s we've seen so far. These might be templates,
// and might not, but if there were none of them (or we know for sure that
@@ -942,7 +1035,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
case CIK_DefaultArgument:
bool InvalidAsDeclaration = false;
Result = TryParseParameterDeclarationClause(
- &InvalidAsDeclaration, /*VersusTemplateArgument*/true);
+ &InvalidAsDeclaration, /*VersusTemplateArgument=*/true);
// If this is an expression or a declaration with a missing
// 'typename', assume it's not a declaration.
if (Result == TPResult::Ambiguous && InvalidAsDeclaration)
@@ -1014,6 +1107,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
Toks.push_back(Tok);
ConsumeToken();
if (Tok.is(tok::less)) {
+ ++AngleCount;
++KnownTemplateCount;
Toks.push_back(Tok);
ConsumeToken();
@@ -1063,21 +1157,28 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
// Since the user wasn't looking for this token (if they were, it would
// already be handled), this isn't balanced. If there is a LHS token at a
// higher level, we will assume that this matches the unbalanced token
- // and return it. Otherwise, this is a spurious RHS token, which we skip.
+ // and return it. Otherwise, this is a spurious RHS token, which we
+ // consume and pass on to downstream code to diagnose.
case tok::r_paren:
if (CIK == CIK_DefaultArgument)
return true; // End of the default argument.
- if (ParenCount && !IsFirstTokenConsumed)
- return false; // Matches something.
- goto consume_token;
+ if (ParenCount && !IsFirstToken)
+ return false;
+ Toks.push_back(Tok);
+ ConsumeParen();
+ continue;
case tok::r_square:
- if (BracketCount && !IsFirstTokenConsumed)
- return false; // Matches something.
- goto consume_token;
+ if (BracketCount && !IsFirstToken)
+ return false;
+ Toks.push_back(Tok);
+ ConsumeBracket();
+ continue;
case tok::r_brace:
- if (BraceCount && !IsFirstTokenConsumed)
- return false; // Matches something.
- goto consume_token;
+ if (BraceCount && !IsFirstToken)
+ return false;
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ continue;
case tok::code_completion:
Toks.push_back(Tok);
@@ -1102,6 +1203,6 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
ConsumeToken();
break;
}
- IsFirstTokenConsumed = false;
+ IsFirstToken = false;
}
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 62d43768bff4..4d05e16491b0 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -143,10 +143,12 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
continue;
// Expect an identifier or declaration specifier (const, int, etc.)
- if (Tok.isNot(tok::identifier) && !isDeclarationSpecifier())
+ if (Tok.isAnnotation())
break;
-
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ if (!AttrName)
+ break;
+
SourceLocation AttrNameLoc = ConsumeToken();
if (Tok.isNot(tok::l_paren)) {
@@ -302,7 +304,8 @@ unsigned Parser::ParseAttributeArgsCommon(
Unevaluated.reset(
new EnterExpressionEvaluationContext(Actions, Sema::Unevaluated));
- ExprResult ArgExpr(ParseAssignmentExpression());
+ ExprResult ArgExpr(
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
if (ArgExpr.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return 0;
@@ -588,15 +591,64 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) {
void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
// Treat these like attributes
- while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) ||
- Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) ||
- Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) ||
- Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned) ||
- Tok.is(tok::kw___sptr) || Tok.is(tok::kw___uptr)) {
- IdentifierInfo *AttrName = Tok.getIdentifierInfo();
- SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
- AttributeList::AS_Keyword);
+ while (true) {
+ switch (Tok.getKind()) {
+ case tok::kw___fastcall:
+ case tok::kw___stdcall:
+ case tok::kw___thiscall:
+ case tok::kw___cdecl:
+ case tok::kw___vectorcall:
+ case tok::kw___ptr64:
+ case tok::kw___w64:
+ case tok::kw___ptr32:
+ case tok::kw___unaligned:
+ case tok::kw___sptr:
+ case tok::kw___uptr: {
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+ attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ AttributeList::AS_Keyword);
+ break;
+ }
+ default:
+ return;
+ }
+ }
+}
+
+void Parser::DiagnoseAndSkipExtendedMicrosoftTypeAttributes() {
+ SourceLocation StartLoc = Tok.getLocation();
+ SourceLocation EndLoc = SkipExtendedMicrosoftTypeAttributes();
+
+ if (EndLoc.isValid()) {
+ SourceRange Range(StartLoc, EndLoc);
+ Diag(StartLoc, diag::warn_microsoft_qualifiers_ignored) << Range;
+ }
+}
+
+SourceLocation Parser::SkipExtendedMicrosoftTypeAttributes() {
+ SourceLocation EndLoc;
+
+ while (true) {
+ switch (Tok.getKind()) {
+ case tok::kw_const:
+ case tok::kw_volatile:
+ case tok::kw___fastcall:
+ case tok::kw___stdcall:
+ case tok::kw___thiscall:
+ case tok::kw___cdecl:
+ case tok::kw___vectorcall:
+ case tok::kw___ptr32:
+ case tok::kw___ptr64:
+ case tok::kw___w64:
+ case tok::kw___unaligned:
+ case tok::kw___sptr:
+ case tok::kw___uptr:
+ EndLoc = ConsumeToken();
+ break;
+ default:
+ return EndLoc;
+ }
}
}
@@ -627,6 +679,10 @@ void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) {
AttributeList::AS_Keyword);
}
+static bool VersionNumberSeparator(const char Separator) {
+ return (Separator == '.' || Separator == '_');
+}
+
/// \brief Parse a version number.
///
/// version:
@@ -684,7 +740,9 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
return VersionTuple(Major);
}
- if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) {
+ const char AfterMajorSeparator = ThisTokBegin[AfterMajor];
+ if (!VersionNumberSeparator(AfterMajorSeparator)
+ || (AfterMajor + 1 == ActualLength)) {
Diag(Tok, diag::err_expected_version);
SkipUntil(tok::comma, tok::r_paren,
StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
@@ -708,16 +766,21 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
return VersionTuple();
}
- return VersionTuple(Major, Minor);
+ return VersionTuple(Major, Minor, (AfterMajorSeparator == '_'));
}
- // If what follows is not a '.', we have a problem.
- if (ThisTokBegin[AfterMinor] != '.') {
+ const char AfterMinorSeparator = ThisTokBegin[AfterMinor];
+ // If what follows is not a '.' or '_', we have a problem.
+ if (!VersionNumberSeparator(AfterMinorSeparator)) {
Diag(Tok, diag::err_expected_version);
SkipUntil(tok::comma, tok::r_paren,
StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
return VersionTuple();
}
+
+ // Warn if separators, be it '.' or '_', do not match.
+ if (AfterMajorSeparator != AfterMinorSeparator)
+ Diag(Tok, diag::warn_expected_consistent_version_separator);
// Parse the subminor version.
unsigned AfterSubminor = AfterMinor + 1;
@@ -734,7 +797,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
return VersionTuple();
}
ConsumeToken();
- return VersionTuple(Major, Minor, Subminor);
+ return VersionTuple(Major, Minor, Subminor, (AfterMajorSeparator == '_'));
}
/// \brief Parse the contents of the "availability" attribute.
@@ -846,6 +909,19 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
break;
}
+ // Special handling of 'NA' only when applied to introduced or
+ // deprecated.
+ if ((Keyword == Ident_introduced || Keyword == Ident_deprecated) &&
+ Tok.is(tok::identifier)) {
+ IdentifierInfo *NA = Tok.getIdentifierInfo();
+ if (NA->getName() == "NA") {
+ ConsumeToken();
+ if (Keyword == Ident_introduced)
+ UnavailableLoc = KeywordLoc;
+ continue;
+ }
+ }
+
SourceRange VersionRange;
VersionTuple Version = ParseVersionTuple(VersionRange);
@@ -1071,8 +1147,14 @@ void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
/// to the Attribute list for the decl.
void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
bool EnterScope, bool OnDefinition) {
- // Save the current token position.
- SourceLocation OrigLoc = Tok.getLocation();
+ // Create a fake EOF so that attribute parsing won't go off the end of the
+ // attribute.
+ Token AttrEnd;
+ AttrEnd.startToken();
+ AttrEnd.setKind(tok::eof);
+ AttrEnd.setLocation(Tok.getLocation());
+ AttrEnd.setEofData(LA.Toks.data());
+ LA.Toks.push_back(AttrEnd);
// Append the current token at the end of the new token stream so that it
// doesn't get lost.
@@ -1137,16 +1219,13 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i)
Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.Decls[i], Attrs);
- if (Tok.getLocation() != OrigLoc) {
- // Due to a parsing error, we either went over the cached tokens or
- // there are still cached tokens left, so we skip the leftover tokens.
- // Since this is an uncommon situation that should be avoided, use the
- // expensive isBeforeInTranslationUnit call.
- if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
- OrigLoc))
- while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
- ConsumeAnyToken();
- }
+ // Due to a parsing error, we either went over the cached tokens or
+ // there are still cached tokens left, so we skip the leftover tokens.
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+
+ if (Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData())
+ ConsumeAnyToken();
}
void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
@@ -1297,8 +1376,7 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) {
/// [C++11/C11] static_assert-declaration
/// others... [FIXME]
///
-Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
- unsigned Context,
+Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -1322,7 +1400,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc);
break;
}
- return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs,
+ return ParseSimpleDeclaration(Context, DeclEnd, attrs,
true);
case tok::kw_namespace:
ProhibitAttributes(attrs);
@@ -1338,7 +1416,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
break;
default:
- return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, true);
+ return ParseSimpleDeclaration(Context, DeclEnd, attrs, true);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -1364,7 +1442,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
/// of a simple-declaration. If we find that we are, we also parse the
/// for-range-initializer, and place it here.
Parser::DeclGroupPtrTy
-Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
+Parser::ParseSimpleDeclaration(unsigned Context,
SourceLocation &DeclEnd,
ParsedAttributesWithRange &Attrs,
bool RequireSemi, ForRangeInit *FRI) {
@@ -1393,7 +1471,7 @@ Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
}
DS.takeAttributesFrom(Attrs);
- return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI);
+ return ParseDeclGroup(DS, Context, &DeclEnd, FRI);
}
/// Returns true if this might be the start of a declarator, or a common typo
@@ -1548,7 +1626,6 @@ void Parser::SkipMalformedDecl() {
/// result.
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
unsigned Context,
- bool AllowFunctionDefinitions,
SourceLocation *DeclEnd,
ForRangeInit *FRI) {
// Parse the first declarator.
@@ -1565,9 +1642,30 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// appropriate function scope after the function Decl has been constructed.
// These will be parsed in ParseFunctionDefinition or ParseLexedAttrList.
LateParsedAttrList LateParsedAttrs(true);
- if (D.isFunctionDeclarator())
+ if (D.isFunctionDeclarator()) {
MaybeParseGNUAttributes(D, &LateParsedAttrs);
+ // The _Noreturn keyword can't appear here, unlike the GNU noreturn
+ // attribute. If we find the keyword here, tell the user to put it
+ // at the start instead.
+ if (Tok.is(tok::kw__Noreturn)) {
+ SourceLocation Loc = ConsumeToken();
+ const char *PrevSpec;
+ unsigned DiagID;
+
+ // We can offer a fixit if it's valid to mark this function as _Noreturn
+ // and we don't have any other declarators in this declaration.
+ bool Fixit = !DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID);
+ MaybeParseGNUAttributes(D, &LateParsedAttrs);
+ Fixit &= Tok.is(tok::semi) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try);
+
+ Diag(Loc, diag::err_c11_noreturn_misplaced)
+ << (Fixit ? FixItHint::CreateRemoval(Loc) : FixItHint())
+ << (Fixit ? FixItHint::CreateInsertion(D.getLocStart(), "_Noreturn ")
+ : FixItHint());
+ }
+ }
+
// Check to see if we have a function *definition* which must have a body.
if (D.isFunctionDeclarator() &&
// Look at the next token to make sure that this isn't a function
@@ -1575,7 +1673,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// start of a function definition in GCC-extended K&R C.
!isDeclarationAfterDeclarator()) {
- if (AllowFunctionDefinitions) {
+ // Function definitions are only allowed at file scope and in C++ classes.
+ // The C++ inline method definition case is handled elsewhere, so we only
+ // need to handle the file scope definition case.
+ if (Context == Declarator::FileContext) {
if (isStartOfFunctionDefinition(D)) {
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
Diag(Tok, diag::err_function_declared_typedef);
@@ -1674,6 +1775,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// short x, __attribute__((common)) var; -> declarator
MaybeParseGNUAttributes(D);
+ // MSVC parses but ignores qualifiers after the comma as an extension.
+ if (getLangOpts().MicrosoftExt)
+ DiagnoseAndSkipExtendedMicrosoftTypeAttributes();
+
ParseDeclarator(D);
if (!D.isInvalidType()) {
Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
@@ -2449,8 +2554,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DeclSpecContext DSContext,
LateParsedAttrList *LateAttrs) {
if (DS.getSourceRange().isInvalid()) {
+ // Start the range at the current token but make the end of the range
+ // invalid. This will make the entire range invalid unless we successfully
+ // consume a token.
DS.SetRangeStart(Tok.getLocation());
- DS.SetRangeEnd(Tok.getLocation());
+ DS.SetRangeEnd(SourceLocation());
}
bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
@@ -2459,6 +2567,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
while (1) {
bool isInvalid = false;
+ bool isStorageClass = false;
const char *PrevSpec = nullptr;
unsigned DiagID = 0;
@@ -2728,6 +2837,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
goto DoneWithDeclSpec;
// typedef-name
+ case tok::kw___super:
case tok::kw_decltype:
case tok::identifier: {
// This identifier can only be a typedef name if we haven't already seen
@@ -2862,6 +2972,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___unaligned:
ParseMicrosoftTypeAttributes(DS.getAttributes());
continue;
@@ -2880,22 +2991,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw_typedef:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc,
PrevSpec, DiagID, Policy);
+ isStorageClass = true;
break;
case tok::kw_extern:
if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "extern";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc,
PrevSpec, DiagID, Policy);
+ isStorageClass = true;
break;
case tok::kw___private_extern__:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_private_extern,
Loc, PrevSpec, DiagID, Policy);
+ isStorageClass = true;
break;
case tok::kw_static:
if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "static";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc,
PrevSpec, DiagID, Policy);
+ isStorageClass = true;
break;
case tok::kw_auto:
if (getLangOpts().CPlusPlus11) {
@@ -2911,18 +3026,22 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
} else
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
PrevSpec, DiagID, Policy);
+ isStorageClass = true;
break;
case tok::kw_register:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc,
PrevSpec, DiagID, Policy);
+ isStorageClass = true;
break;
case tok::kw_mutable:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_mutable, Loc,
PrevSpec, DiagID, Policy);
+ isStorageClass = true;
break;
case tok::kw___thread:
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS___thread, Loc,
PrevSpec, DiagID);
+ isStorageClass = true;
break;
case tok::kw_thread_local:
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc,
@@ -2931,6 +3050,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw__Thread_local:
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local,
Loc, PrevSpec, DiagID);
+ isStorageClass = true;
break;
// function-specifier
@@ -3083,6 +3203,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___pixel:
isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID, Policy);
break;
+ case tok::kw___bool:
+ isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy);
+ break;
case tok::kw___unknown_anytype:
isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
PrevSpec, DiagID, Policy);
@@ -3169,6 +3292,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
break;
// OpenCL qualifiers:
+ case tok::kw___generic:
+ // generic address space is introduced only in OpenCL v2.0
+ // see OpenCL C Spec v2.0 s6.5.5
+ if (Actions.getLangOpts().OpenCLVersion < 200) {
+ DiagID = diag::err_opencl_unknown_type_specifier;
+ PrevSpec = Tok.getIdentifierInfo()->getNameStart();
+ isInvalid = true;
+ break;
+ };
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -3203,6 +3335,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (DiagID == diag::ext_duplicate_declspec)
Diag(Tok, DiagID)
<< PrevSpec << FixItHint::CreateRemoval(Tok.getLocation());
+ else if (DiagID == diag::err_opencl_unknown_type_specifier)
+ Diag(Tok, DiagID) << PrevSpec << isStorageClass;
else
Diag(Tok, DiagID) << PrevSpec;
}
@@ -3232,14 +3366,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
/// declarator[opt] ':' constant-expression
/// [GNU] declarator[opt] ':' constant-expression attributes[opt]
///
-void Parser::
-ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) {
+void Parser::ParseStructDeclaration(
+ ParsingDeclSpec &DS,
+ llvm::function_ref<void(ParsingFieldDeclarator &)> FieldsCallback) {
if (Tok.is(tok::kw___extension__)) {
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken();
- return ParseStructDeclaration(DS, Fields);
+ return ParseStructDeclaration(DS, FieldsCallback);
}
// Parse the common specifier-qualifiers-list piece.
@@ -3271,7 +3406,8 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) {
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
ColonProtectionRAIIObject X(*this);
ParseDeclarator(DeclaratorInfo.D);
- }
+ } else
+ DeclaratorInfo.D.SetIdentifier(nullptr, Tok.getLocation());
if (TryConsumeToken(tok::colon)) {
ExprResult Res(ParseConstantExpression());
@@ -3285,7 +3421,7 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) {
MaybeParseGNUAttributes(DeclaratorInfo.D);
// We're done with this declarator; invoke the callback.
- Fields.invoke(DeclaratorInfo);
+ FieldsCallback(DeclaratorInfo);
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
@@ -3349,28 +3485,19 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
}
if (!Tok.is(tok::at)) {
- struct CFieldCallback : FieldCallback {
- Parser &P;
- Decl *TagDecl;
- SmallVectorImpl<Decl *> &FieldDecls;
-
- CFieldCallback(Parser &P, Decl *TagDecl,
- SmallVectorImpl<Decl *> &FieldDecls) :
- P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {}
-
- void invoke(ParsingFieldDeclarator &FD) override {
- // Install the declarator into the current TagDecl.
- Decl *Field = P.Actions.ActOnField(P.getCurScope(), TagDecl,
- FD.D.getDeclSpec().getSourceRange().getBegin(),
- FD.D, FD.BitfieldSize);
- FieldDecls.push_back(Field);
- FD.complete(Field);
- }
- } Callback(*this, TagDecl, FieldDecls);
+ auto CFieldCallback = [&](ParsingFieldDeclarator &FD) {
+ // Install the declarator into the current TagDecl.
+ Decl *Field =
+ Actions.ActOnField(getCurScope(), TagDecl,
+ FD.D.getDeclSpec().getSourceRange().getBegin(),
+ FD.D, FD.BitfieldSize);
+ FieldDecls.push_back(Field);
+ FD.complete(Field);
+ };
// Parse all the comma separated declarators.
ParsingDeclSpec DS(*this);
- ParseStructDeclaration(DS, Callback);
+ ParseStructDeclaration(DS, CFieldCallback);
} else { // Handle @defs
ConsumeToken();
if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
@@ -3778,8 +3905,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
/// enumerator
/// enumerator-list ',' enumerator
/// enumerator:
-/// enumeration-constant
-/// enumeration-constant '=' constant-expression
+/// enumeration-constant attributes[opt]
+/// enumeration-constant attributes[opt] '=' constant-expression
/// enumeration-constant:
/// identifier
///
@@ -3816,8 +3943,13 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
// If attributes exist after the enumerator, parse them.
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
- MaybeParseCXX11Attributes(attrs);
- ProhibitAttributes(attrs);
+ ProhibitAttributes(attrs); // GNU-style attributes are prohibited.
+ if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+ if (!getLangOpts().CPlusPlus1z)
+ Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute)
+ << 1 /*enumerator*/;
+ ParseCXX11Attributes(attrs);
+ }
SourceLocation EqualLoc;
ExprResult AssignedVal;
@@ -3921,6 +4053,7 @@ bool Parser::isTypeQualifier() const {
case tok::kw___local:
case tok::kw___global:
case tok::kw___constant:
+ case tok::kw___generic:
case tok::kw___read_only:
case tok::kw___read_write:
case tok::kw___write_only:
@@ -4059,6 +4192,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___w64:
case tok::kw___ptr64:
case tok::kw___ptr32:
@@ -4069,6 +4203,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw___local:
case tok::kw___global:
case tok::kw___constant:
+ case tok::kw___generic:
case tok::kw___read_only:
case tok::kw___read_write:
case tok::kw___write_only:
@@ -4227,6 +4362,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___w64:
case tok::kw___sptr:
case tok::kw___uptr:
@@ -4240,6 +4376,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw___local:
case tok::kw___global:
case tok::kw___constant:
+ case tok::kw___generic:
case tok::kw___read_only:
case tok::kw___read_write:
case tok::kw___write_only:
@@ -4373,20 +4510,18 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) {
/// type-qualifier-list: [C99 6.7.5]
/// type-qualifier
/// [vendor] attributes
-/// [ only if VendorAttributesAllowed=true ]
+/// [ only if AttrReqs & AR_VendorAttributesParsed ]
/// type-qualifier-list type-qualifier
/// [vendor] type-qualifier-list attributes
-/// [ only if VendorAttributesAllowed=true ]
+/// [ only if AttrReqs & AR_VendorAttributesParsed ]
/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq
-/// [ only if CXX11AttributesAllowed=true ]
-/// Note: vendor can be GNU, MS, etc.
-///
-void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
- bool VendorAttributesAllowed,
- bool CXX11AttributesAllowed,
+/// [ only if AttReqs & AR_CXX11AttributesParsed ]
+/// Note: vendor can be GNU, MS, etc and can be explicitly controlled via
+/// AttrRequirements bitmask values.
+void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs,
bool AtomicAllowed,
bool IdentifierRequired) {
- if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed &&
+ if (getLangOpts().CPlusPlus11 && (AttrReqs & AR_CXX11AttributesParsed) &&
isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
ParseCXX11Attributes(attrs);
@@ -4430,6 +4565,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
case tok::kw___global:
case tok::kw___local:
case tok::kw___constant:
+ case tok::kw___generic:
case tok::kw___read_only:
case tok::kw___write_only:
case tok::kw___read_write:
@@ -4439,7 +4575,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
case tok::kw___uptr:
// GNU libc headers in C mode use '__uptr' as an identifer which conflicts
// with the MS modifier keyword.
- if (VendorAttributesAllowed && !getLangOpts().CPlusPlus &&
+ if ((AttrReqs & AR_DeclspecAttributesParsed) && !getLangOpts().CPlusPlus &&
IdentifierRequired && DS.isEmpty() && NextToken().is(tok::semi)) {
if (TryKeywordIdentFallback(false))
continue;
@@ -4452,20 +4588,28 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___unaligned:
- if (VendorAttributesAllowed) {
+ if (AttrReqs & AR_DeclspecAttributesParsed) {
ParseMicrosoftTypeAttributes(DS.getAttributes());
continue;
}
goto DoneWithTypeQuals;
case tok::kw___pascal:
- if (VendorAttributesAllowed) {
+ if (AttrReqs & AR_VendorAttributesParsed) {
ParseBorlandTypeAttributes(DS.getAttributes());
continue;
}
goto DoneWithTypeQuals;
case tok::kw___attribute:
- if (VendorAttributesAllowed) {
+ if (AttrReqs & AR_GNUAttributesParsedAndRejected)
+ // When GNU attributes are expressly forbidden, diagnose their usage.
+ Diag(Tok, diag::err_attributes_not_allowed);
+
+ // Parse the attributes even if they are rejected to ensure that error
+ // recovery is graceful.
+ if (AttrReqs & AR_GNUAttributesParsed ||
+ AttrReqs & AR_GNUAttributesParsedAndRejected) {
ParseGNUAttributes(DS.getAttributes());
continue; // do *not* consume the next token!
}
@@ -4498,15 +4642,27 @@ void Parser::ParseDeclarator(Declarator &D) {
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
}
-static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang) {
+static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang,
+ unsigned TheContext) {
if (Kind == tok::star || Kind == tok::caret)
return true;
- // We parse rvalue refs in C++03, because otherwise the errors are scary.
if (!Lang.CPlusPlus)
return false;
- return Kind == tok::amp || Kind == tok::ampamp;
+ if (Kind == tok::amp)
+ return true;
+
+ // We parse rvalue refs in C++03, because otherwise the errors are scary.
+ // But we must not parse them in conversion-type-ids and new-type-ids, since
+ // those can be legitimately followed by a && operator.
+ // (The same thing can in theory happen after a trailing-return-type, but
+ // since those are a C++11 feature, there is no rejects-valid issue there.)
+ if (Kind == tok::ampamp)
+ return Lang.CPlusPlus11 || (TheContext != Declarator::ConversionIdContext &&
+ TheContext != Declarator::CXXNewContext);
+
+ return false;
}
/// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator
@@ -4577,7 +4733,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// Sema will have to catch (syntactically invalid) pointers into global
// scope. It has to catch pointers into namespace scope anyway.
D.AddTypeInfo(DeclaratorChunk::getMemberPointer(SS,DS.getTypeQualifiers(),
- Loc),
+ DS.getLocEnd()),
DS.getAttributes(),
/* Don't replace range end. */SourceLocation());
return;
@@ -4586,7 +4742,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
tok::TokenKind Kind = Tok.getKind();
// Not a pointer, C++ reference, or block.
- if (!isPtrOperatorToken(Kind, getLangOpts())) {
+ if (!isPtrOperatorToken(Kind, getLangOpts(), D.getContext())) {
if (DirectDeclParser)
(this->*DirectDeclParser)(D);
return;
@@ -4601,8 +4757,13 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// Is a pointer.
DeclSpec DS(AttrFactory);
- // FIXME: GNU attributes are not allowed here in a new-type-id.
- ParseTypeQualifierListOpt(DS, true, true, true, !D.mayOmitIdentifier());
+ // GNU attributes are not allowed here in a new-type-id, but Declspec and
+ // C++11 attributes are allowed.
+ unsigned Reqs = AR_CXX11AttributesParsed | AR_DeclspecAttributesParsed |
+ ((D.getContext() != Declarator::CXXNewContext)
+ ? AR_GNUAttributesParsed
+ : AR_GNUAttributesParsedAndRejected);
+ ParseTypeQualifierListOpt(DS, Reqs, true, !D.mayOmitIdentifier());
D.ExtendWithDeclSpec(DS);
// Recursively parse the declarator.
@@ -4762,21 +4923,22 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
}
// C++0x [dcl.fct]p14:
- // There is a syntactic ambiguity when an ellipsis occurs at the end
- // of a parameter-declaration-clause without a preceding comma. In
- // this case, the ellipsis is parsed as part of the
- // abstract-declarator if the type of the parameter names a template
- // parameter pack that has not been expanded; otherwise, it is parsed
- // as part of the parameter-declaration-clause.
+ // There is a syntactic ambiguity when an ellipsis occurs at the end of a
+ // parameter-declaration-clause without a preceding comma. In this case,
+ // the ellipsis is parsed as part of the abstract-declarator if the type
+ // of the parameter either names a template parameter pack that has not
+ // been expanded or contains auto; otherwise, it is parsed as part of the
+ // parameter-declaration-clause.
if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() &&
!((D.getContext() == Declarator::PrototypeContext ||
D.getContext() == Declarator::LambdaExprParameterContext ||
D.getContext() == Declarator::BlockLiteralContext) &&
NextToken().is(tok::r_paren) &&
!D.hasGroupingParens() &&
- !Actions.containsUnexpandedParameterPacks(D))) {
+ !Actions.containsUnexpandedParameterPacks(D) &&
+ D.getDeclSpec().getTypeSpecType() != TST_auto)) {
SourceLocation EllipsisLoc = ConsumeToken();
- if (isPtrOperatorToken(Tok.getKind(), getLangOpts())) {
+ if (isPtrOperatorToken(Tok.getKind(), getLangOpts(), D.getContext())) {
// The ellipsis was put in the wrong place. Recover, and explain to
// the user what they should have done.
ParseDeclarator(D);
@@ -5102,11 +5264,13 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
SourceLocation RefQualifierLoc;
SourceLocation ConstQualifierLoc;
SourceLocation VolatileQualifierLoc;
+ SourceLocation RestrictQualifierLoc;
ExceptionSpecificationType ESpecType = EST_None;
SourceRange ESpecRange;
SmallVector<ParsedType, 2> DynamicExceptions;
SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
+ CachedTokens *ExceptionSpecTokens = 0;
ParsedAttributes FnAttrs(AttrFactory);
TypeResult TrailingReturnType;
@@ -5149,13 +5313,13 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// with the virt-specifier-seq and pure-specifier in the same way.
// Parse cv-qualifier-seq[opt].
- ParseTypeQualifierListOpt(DS, /*VendorAttributesAllowed*/ false,
- /*CXX11AttributesAllowed*/ false,
+ ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed,
/*AtomicAllowed*/ false);
if (!DS.getSourceRange().getEnd().isInvalid()) {
EndLoc = DS.getSourceRange().getEnd();
ConstQualifierLoc = DS.getConstSpecLoc();
VolatileQualifierLoc = DS.getVolatileSpecLoc();
+ RestrictQualifierLoc = DS.getRestrictSpecLoc();
}
// Parse ref-qualifier[opt].
@@ -5188,15 +5352,36 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
dyn_cast<CXXRecordDecl>(Actions.CurContext),
DS.getTypeQualifiers() |
(D.getDeclSpec().isConstexprSpecified() &&
- !getLangOpts().CPlusPlus1y
+ !getLangOpts().CPlusPlus14
? Qualifiers::Const : 0),
IsCXX11MemberFunction);
// Parse exception-specification[opt].
- ESpecType = tryParseExceptionSpecification(ESpecRange,
+ bool Delayed = D.isFirstDeclarationOfMember() &&
+ D.isFunctionDeclaratorAFunctionDeclaration();
+ if (Delayed && Actions.isLibstdcxxEagerExceptionSpecHack(D) &&
+ GetLookAheadToken(0).is(tok::kw_noexcept) &&
+ GetLookAheadToken(1).is(tok::l_paren) &&
+ GetLookAheadToken(2).is(tok::kw_noexcept) &&
+ GetLookAheadToken(3).is(tok::l_paren) &&
+ GetLookAheadToken(4).is(tok::identifier) &&
+ GetLookAheadToken(4).getIdentifierInfo()->isStr("swap")) {
+ // HACK: We've got an exception-specification
+ // noexcept(noexcept(swap(...)))
+ // or
+ // noexcept(noexcept(swap(...)) && noexcept(swap(...)))
+ // on a 'swap' member function. This is a libstdc++ bug; the lookup
+ // for 'swap' will only find the function we're currently declaring,
+ // whereas it expects to find a non-member swap through ADL. Turn off
+ // delayed parsing to give it a chance to find what it expects.
+ Delayed = false;
+ }
+ ESpecType = tryParseExceptionSpecification(Delayed,
+ ESpecRange,
DynamicExceptions,
DynamicExceptionRanges,
- NoexceptExpr);
+ NoexceptExpr,
+ ExceptionSpecTokens);
if (ESpecType != EST_None)
EndLoc = ESpecRange.getEnd();
@@ -5228,6 +5413,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
RefQualifierIsLValueRef,
RefQualifierLoc, ConstQualifierLoc,
VolatileQualifierLoc,
+ RestrictQualifierLoc,
/*MutableLoc=*/SourceLocation(),
ESpecType, ESpecRange.getBegin(),
DynamicExceptions.data(),
@@ -5235,6 +5421,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : nullptr,
+ ExceptionSpecTokens,
StartLoc, LocalEndLoc, D,
TrailingReturnType),
FnAttrs, EndLoc);
@@ -5306,7 +5493,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
Diag(Tok, diag::err_unexpected_typedef_ident) << ParmII;
// Verify that the argument identifier has not already been mentioned.
- if (!ParamsSoFar.insert(ParmII)) {
+ if (!ParamsSoFar.insert(ParmII).second) {
Diag(Tok, diag::err_param_redefinition) << ParmII;
} else {
// Remember this identifier in ParamInfo.
@@ -5414,10 +5601,18 @@ void Parser::ParseParameterDeclarationClause(
// Otherwise, we have something. Add it and let semantic analysis try
// to grok it and add the result to the ParamInfo we are building.
+ // Last chance to recover from a misplaced ellipsis in an attempted
+ // parameter pack declaration.
+ if (Tok.is(tok::ellipsis) &&
+ (NextToken().isNot(tok::r_paren) ||
+ (!ParmDeclarator.getEllipsisLoc().isValid() &&
+ !Actions.isUnexpandedParameterPackPermitted())) &&
+ Actions.containsUnexpandedParameterPacks(ParmDeclarator))
+ DiagnoseMisplacedEllipsisInDeclarator(ConsumeToken(), ParmDeclarator);
+
// Inform the actions module about the parameter declarator, so it gets
// added to the current scope.
- Decl *Param = Actions.ActOnParamDeclarator(getCurScope(),
- ParmDeclarator);
+ Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator);
// Parse the default argument, if any. We parse the default
// arguments in all dialects; the semantic analysis in
// ActOnParamDefaultArgument will reject the default argument in
@@ -5433,20 +5628,14 @@ void Parser::ParseParameterDeclarationClause(
// FIXME: Can we use a smart pointer for Toks?
DefArgToks = new CachedTokens;
+ SourceLocation ArgStartLoc = NextToken().getLocation();
if (!ConsumeAndStoreInitializer(*DefArgToks, CIK_DefaultArgument)) {
delete DefArgToks;
DefArgToks = nullptr;
Actions.ActOnParamDefaultArgumentError(Param, EqualLoc);
} else {
- // Mark the end of the default argument so that we know when to
- // stop when we parse it later on.
- Token DefArgEnd;
- DefArgEnd.startToken();
- DefArgEnd.setKind(tok::cxx_defaultarg_end);
- DefArgEnd.setLocation(Tok.getLocation());
- DefArgToks->push_back(DefArgEnd);
Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc,
- (*DefArgToks)[1].getLocation());
+ ArgStartLoc);
}
} else {
// Consume the '='.
@@ -5464,6 +5653,7 @@ void Parser::ParseParameterDeclarationClause(
DefArgResult = ParseBraceInitializer();
} else
DefArgResult = ParseAssignmentExpression();
+ DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult);
if (DefArgResult.isInvalid()) {
Actions.ActOnParamDefaultArgumentError(Param, EqualLoc);
SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);
@@ -5480,12 +5670,34 @@ void Parser::ParseParameterDeclarationClause(
Param, DefArgToks));
}
- if (TryConsumeToken(tok::ellipsis, EllipsisLoc) &&
- !getLangOpts().CPlusPlus) {
- // We have ellipsis without a preceding ',', which is ill-formed
- // in C. Complain and provide the fix.
- Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis)
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
+ if (!getLangOpts().CPlusPlus) {
+ // We have ellipsis without a preceding ',', which is ill-formed
+ // in C. Complain and provide the fix.
+ Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis)
+ << FixItHint::CreateInsertion(EllipsisLoc, ", ");
+ } else if (ParmDeclarator.getEllipsisLoc().isValid() ||
+ Actions.containsUnexpandedParameterPacks(ParmDeclarator)) {
+ // It looks like this was supposed to be a parameter pack. Warn and
+ // point out where the ellipsis should have gone.
+ SourceLocation ParmEllipsis = ParmDeclarator.getEllipsisLoc();
+ Diag(EllipsisLoc, diag::warn_misplaced_ellipsis_vararg)
+ << ParmEllipsis.isValid() << ParmEllipsis;
+ if (ParmEllipsis.isValid()) {
+ Diag(ParmEllipsis,
+ diag::note_misplaced_ellipsis_vararg_existing_ellipsis);
+ } else {
+ Diag(ParmDeclarator.getIdentifierLoc(),
+ diag::note_misplaced_ellipsis_vararg_add_ellipsis)
+ << FixItHint::CreateInsertion(ParmDeclarator.getIdentifierLoc(),
+ "...")
+ << !ParmDeclarator.hasName();
+ }
+ Diag(EllipsisLoc, diag::note_misplaced_ellipsis_vararg_add_comma)
<< FixItHint::CreateInsertion(EllipsisLoc, ", ");
+ }
+
+ // We can't have any more parameters after an ellipsis.
break;
}
@@ -5546,7 +5758,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// If there is a type-qualifier-list, read it now.
// Type qualifiers in an array subscript are a C99 feature.
DeclSpec DS(AttrFactory);
- ParseTypeQualifierListOpt(DS, false /*no attributes*/);
+ ParseTypeQualifierListOpt(DS, AR_CXX11AttributesParsed);
// If we haven't already read 'static', check to see if there is one after the
// type-qualifier-list.
@@ -5582,7 +5794,13 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
} else {
EnterExpressionEvaluationContext Unevaluated(Actions,
Sema::ConstantEvaluated);
- NumElements = ParseAssignmentExpression();
+ NumElements =
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
+ }
+ } else {
+ if (StaticLoc.isValid()) {
+ Diag(StaticLoc, diag::err_unspecified_size_with_static);
+ StaticLoc = SourceLocation(); // Drop the static.
}
}
@@ -5716,8 +5934,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
bool isCastExpr;
ParsedType CastTy;
SourceRange CastRange;
- ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr,
- CastTy, CastRange);
+ ExprResult Operand = Actions.CorrectDelayedTyposInExpr(
+ ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange));
if (hasParens)
DS.setTypeofParensRange(CastRange);
@@ -5817,6 +6035,7 @@ bool Parser::TryAltiVecVectorTokenOutOfLine() {
case tok::kw_float:
case tok::kw_double:
case tok::kw_bool:
+ case tok::kw___bool:
case tok::kw___pixel:
Tok.setKind(tok::kw___vector);
return true;
@@ -5850,6 +6069,7 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
case tok::kw_float:
case tok::kw_double:
case tok::kw_bool:
+ case tok::kw___bool:
case tok::kw___pixel:
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy);
return true;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 6200363b3bc5..87d99096440c 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -17,8 +17,8 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/Attributes.h"
#include "clang/Basic/CharInfo.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -73,7 +73,15 @@ Decl *Parser::ParseNamespace(unsigned Context,
std::vector<IdentifierInfo*> ExtraIdent;
std::vector<SourceLocation> ExtraNamespaceLoc;
- Token attrTok;
+ ParsedAttributesWithRange attrs(AttrFactory);
+ SourceLocation attrLoc;
+ if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+ if (!getLangOpts().CPlusPlus1z)
+ Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute)
+ << 0 /*namespace*/;
+ attrLoc = Tok.getLocation();
+ ParseCXX11Attributes(attrs);
+ }
if (Tok.is(tok::identifier)) {
Ident = Tok.getIdentifierInfo();
@@ -85,10 +93,13 @@ Decl *Parser::ParseNamespace(unsigned Context,
}
}
+ // A nested namespace definition cannot have attributes.
+ if (!ExtraNamespaceLoc.empty() && attrLoc.isValid())
+ Diag(attrLoc, diag::err_unexpected_nested_namespace_attribute);
+
// Read label attributes, if present.
- ParsedAttributes attrs(AttrFactory);
if (Tok.is(tok::kw___attribute)) {
- attrTok = Tok;
+ attrLoc = Tok.getLocation();
ParseGNUAttributes(attrs);
}
@@ -99,8 +110,8 @@ Decl *Parser::ParseNamespace(unsigned Context,
SkipUntil(tok::semi);
return nullptr;
}
- if (!attrs.empty())
- Diag(attrTok, diag::err_unexpected_namespace_attributes_alias);
+ if (attrLoc.isValid())
+ Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias);
if (InlineLoc.isValid())
Diag(InlineLoc, diag::err_inline_namespace_alias)
<< FixItHint::CreateRemoval(InlineLoc);
@@ -110,39 +121,36 @@ Decl *Parser::ParseNamespace(unsigned Context,
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen()) {
- if (!ExtraIdent.empty()) {
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
- << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
- }
-
if (Ident)
Diag(Tok, diag::err_expected) << tok::l_brace;
else
Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
-
return nullptr;
}
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(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope);
SkipUntil(tok::r_brace);
return nullptr;
}
- if (!ExtraIdent.empty()) {
+ if (ExtraIdent.empty()) {
+ // Normal namespace definition, not a nested-namespace-definition.
+ } else if (InlineLoc.isValid()) {
+ Diag(InlineLoc, diag::err_inline_nested_namespace_definition);
+ } else if (getLangOpts().CPlusPlus1z) {
+ Diag(ExtraNamespaceLoc[0],
+ diag::warn_cxx14_compat_nested_namespace_definition);
+ } else {
TentativeParsingAction TPA(*this);
SkipUntil(tok::r_brace, StopBeforeMatch);
Token rBraceToken = Tok;
TPA.Revert();
if (!rBraceToken.is(tok::r_brace)) {
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)
<< SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
} else {
std::string NamespaceFix;
@@ -156,7 +164,7 @@ Decl *Parser::ParseNamespace(unsigned Context,
for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i)
RBraces += "} ";
- Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)
<< FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(),
ExtraIdentLoc.back()),
NamespaceFix)
@@ -195,11 +203,11 @@ Decl *Parser::ParseNamespace(unsigned Context,
}
/// 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,
- ParsedAttributes& attrs,
+void Parser::ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc,
+ std::vector<IdentifierInfo *> &Ident,
+ std::vector<SourceLocation> &NamespaceLoc,
+ unsigned int index, SourceLocation &InlineLoc,
+ ParsedAttributes &attrs,
BalancedDelimiterTracker &Tracker) {
if (index == Ident.size()) {
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
@@ -216,7 +224,9 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
return;
}
- // Parse improperly nested namespaces.
+ // Handle a nested namespace definition.
+ // FIXME: Preserve the source information through to the AST rather than
+ // desugaring it here.
ParseScope NamespaceScope(this, Scope::DeclScope);
Decl *NamespcDecl =
Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(),
@@ -493,6 +503,12 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
if (TryConsumeToken(tok::kw_typename, TypenameLoc))
HasTypenameKeyword = true;
+ if (Tok.is(tok::kw___super)) {
+ Diag(Tok.getLocation(), diag::err_super_in_using_declaration);
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
+
// Parse nested-name-specifier.
IdentifierInfo *LastII = nullptr;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false,
@@ -692,7 +708,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
ExprResult AssertMessage;
if (Tok.is(tok::r_paren)) {
Diag(Tok, getLangOpts().CPlusPlus1z
- ? diag::warn_cxx1y_compat_static_assert_no_message
+ ? diag::warn_cxx14_compat_static_assert_no_message
: diag::ext_static_assert_no_message)
<< (getLangOpts().CPlusPlus1z
? FixItHint()
@@ -769,7 +785,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
// because the typename-specifier in a function-style cast operation can't
// be 'auto'.
Diag(Tok.getLocation(),
- getLangOpts().CPlusPlus1y
+ getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_decltype_auto_type_specifier
: diag::ext_decltype_auto_type_specifier);
ConsumeToken();
@@ -780,7 +796,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
// The operand of the decltype specifier is an unevaluated operand.
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
nullptr,/*IsDecltype=*/true);
- Result = ParseExpression();
+ Result = Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (Result.isInvalid()) {
DS.SetTypeSpecError();
if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) {
@@ -903,8 +919,8 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
/// In C++98, instead of base-type-specifier, we have:
///
/// ::[opt] nested-name-specifier[opt] class-name
-Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
- SourceLocation &EndLocation) {
+TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
+ SourceLocation &EndLocation) {
// Ignore attempts to use typename
if (Tok.is(tok::kw_typename)) {
Diag(Tok, diag::err_expected_class_name_not_template)
@@ -1066,6 +1082,11 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::comma: // __builtin_offsetof(struct foo{...} ,
case tok::kw_operator: // struct foo operator ++() {...}
case tok::kw___declspec: // struct foo {...} __declspec(...)
+ case tok::l_square: // void f(struct f [ 3])
+ case tok::ellipsis: // void f(struct f ... [Ns])
+ // FIXME: we should emit semantic diagnostic when declaration
+ // attribute is in type attribute position.
+ case tok::kw___attribute: // struct foo __attribute__((used)) x;
return true;
case tok::colon:
return CouldBeBitfield; // enum E { ... } : 2;
@@ -1073,6 +1094,8 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::kw_const: // struct foo {...} const x;
case tok::kw_volatile: // struct foo {...} volatile x;
case tok::kw_restrict: // struct foo {...} restrict x;
+ case tok::kw__Atomic: // struct foo {...} _Atomic x;
+ case tok::kw___unaligned: // struct foo {...} __unaligned *x;
// Function specifiers
// Note, no 'explicit'. An explicit function must be either a conversion
// operator or a constructor. Either way, it can't have a return type.
@@ -1111,10 +1134,6 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
if (!getLangOpts().CPlusPlus)
return true;
break;
- // C++11 attributes
- case tok::l_square: // enum E [[]] x
- // Note, no tok::kw_alignas here; alignas cannot appertain to a type.
- return getLangOpts().CPlusPlus11 && NextToken().is(tok::l_square);
case tok::greater:
// template<class T = class X>
return getLangOpts().CPlusPlus;
@@ -1224,17 +1243,65 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// C++11 attributes
SourceLocation AttrFixitLoc = Tok.getLocation();
- // GNU libstdc++ and libc++ use certain intrinsic names as the
- // name of struct templates, but some are keywords in GCC >= 4.3
- // MSVC and Clang. For compatibility, convert the token to an identifier
- // and issue a warning diagnostic.
- if (TagType == DeclSpec::TST_struct && !Tok.is(tok::identifier) &&
- !Tok.isAnnotation()) {
- const IdentifierInfo *II = Tok.getIdentifierInfo();
- // We rarely end up here so the following check is efficient.
- if (II && II->getName().startswith("__is_"))
- TryKeywordIdentFallback(true);
- }
+ if (TagType == DeclSpec::TST_struct &&
+ Tok.isNot(tok::identifier) &&
+ !Tok.isAnnotation() &&
+ Tok.getIdentifierInfo() &&
+ (Tok.is(tok::kw___is_abstract) ||
+ Tok.is(tok::kw___is_arithmetic) ||
+ Tok.is(tok::kw___is_array) ||
+ Tok.is(tok::kw___is_base_of) ||
+ Tok.is(tok::kw___is_class) ||
+ Tok.is(tok::kw___is_complete_type) ||
+ Tok.is(tok::kw___is_compound) ||
+ Tok.is(tok::kw___is_const) ||
+ Tok.is(tok::kw___is_constructible) ||
+ Tok.is(tok::kw___is_convertible) ||
+ Tok.is(tok::kw___is_convertible_to) ||
+ Tok.is(tok::kw___is_destructible) ||
+ Tok.is(tok::kw___is_empty) ||
+ Tok.is(tok::kw___is_enum) ||
+ Tok.is(tok::kw___is_floating_point) ||
+ Tok.is(tok::kw___is_final) ||
+ Tok.is(tok::kw___is_function) ||
+ Tok.is(tok::kw___is_fundamental) ||
+ Tok.is(tok::kw___is_integral) ||
+ Tok.is(tok::kw___is_interface_class) ||
+ Tok.is(tok::kw___is_literal) ||
+ Tok.is(tok::kw___is_lvalue_expr) ||
+ Tok.is(tok::kw___is_lvalue_reference) ||
+ Tok.is(tok::kw___is_member_function_pointer) ||
+ Tok.is(tok::kw___is_member_object_pointer) ||
+ Tok.is(tok::kw___is_member_pointer) ||
+ Tok.is(tok::kw___is_nothrow_assignable) ||
+ Tok.is(tok::kw___is_nothrow_constructible) ||
+ Tok.is(tok::kw___is_nothrow_destructible) ||
+ Tok.is(tok::kw___is_object) ||
+ Tok.is(tok::kw___is_pod) ||
+ Tok.is(tok::kw___is_pointer) ||
+ Tok.is(tok::kw___is_polymorphic) ||
+ Tok.is(tok::kw___is_reference) ||
+ Tok.is(tok::kw___is_rvalue_expr) ||
+ Tok.is(tok::kw___is_rvalue_reference) ||
+ Tok.is(tok::kw___is_same) ||
+ Tok.is(tok::kw___is_scalar) ||
+ Tok.is(tok::kw___is_sealed) ||
+ Tok.is(tok::kw___is_signed) ||
+ Tok.is(tok::kw___is_standard_layout) ||
+ Tok.is(tok::kw___is_trivial) ||
+ Tok.is(tok::kw___is_trivially_assignable) ||
+ Tok.is(tok::kw___is_trivially_constructible) ||
+ Tok.is(tok::kw___is_trivially_copyable) ||
+ Tok.is(tok::kw___is_union) ||
+ Tok.is(tok::kw___is_unsigned) ||
+ Tok.is(tok::kw___is_void) ||
+ Tok.is(tok::kw___is_volatile)))
+ // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
+ // name of struct templates, but some are keywords in GCC >= 4.3
+ // and Clang. Therefore, when we see the token sequence "struct
+ // X", make X into a normal identifier rather than a keyword, to
+ // allow libstdc++ 4.2 and libc++ to work properly.
+ TryKeywordIdentFallback(true);
// Parse the (optional) nested-name-specifier.
CXXScopeSpec &SS = DS.getTypeSpecScope();
@@ -1669,7 +1736,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Also enforce C++ [temp]p3:
// In a template-declaration which defines a class, no declarator
// is permitted.
+ //
+ // After a type-specifier, we don't expect a semicolon. This only happens in
+ // C, since definitions are not permitted in this context in C++.
if (TUK == Sema::TUK_Definition &&
+ (getLangOpts().CPlusPlus || !isTypeSpecifier(DSC)) &&
(TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) {
if (Tok.isNot(tok::semi)) {
const PrintingPolicy &PPol = Actions.getASTContext().getPrintingPolicy();
@@ -1731,7 +1802,7 @@ void Parser::ParseBaseClause(Decl *ClassDecl) {
/// base-type-specifier
/// attribute-specifier-seq[opt] access-specifier 'virtual'[opt]
/// base-type-specifier
-Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
+BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
bool IsVirtual = false;
SourceLocation StartLoc = Tok.getLocation();
@@ -1806,16 +1877,34 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const {
}
/// \brief If the given declarator has any parts for which parsing has to be
-/// delayed, e.g., default arguments, create a late-parsed method declaration
-/// record to handle the parsing at the end of the class definition.
+/// delayed, e.g., default arguments or an exception-specification, create a
+/// late-parsed method declaration record to handle the parsing at the end of
+/// the class definition.
void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
Decl *ThisDecl) {
// We just declared a member function. If this member function
- // has any default arguments, we'll need to parse them later.
+ // has any default arguments or an exception-specification, we'll need to
+ // parse them later.
LateParsedMethodDeclaration *LateMethod = nullptr;
DeclaratorChunk::FunctionTypeInfo &FTI
= DeclaratorInfo.getFunctionTypeInfo();
+ // If there was a late-parsed exception-specification, hold onto its tokens.
+ if (FTI.getExceptionSpecType() == EST_Unparsed) {
+ // Push this method onto the stack of late-parsed method
+ // declarations.
+ LateMethod = new LateParsedMethodDeclaration(this, ThisDecl);
+ getCurrentClass().LateParsedDeclarations.push_back(LateMethod);
+ LateMethod->TemplateScope = getCurScope()->isTemplateParamScope();
+
+ // Stash the exception-specification tokens in the late-pased mthod.
+ LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens;
+ FTI.ExceptionSpecTokens = 0;
+
+ // Reserve space for the parameters.
+ LateMethod->DefaultArgs.reserve(FTI.NumParams);
+ }
+
for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) {
if (LateMethod || FTI.Params[ParamIdx].DefaultArgTokens) {
if (!LateMethod) {
@@ -1879,12 +1968,22 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
/// virt-specifier
/// virt-specifier-seq virt-specifier
void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
- bool IsInterface) {
+ bool IsInterface,
+ SourceLocation FriendLoc) {
while (true) {
VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier();
if (Specifier == VirtSpecifiers::VS_None)
return;
+ if (FriendLoc.isValid()) {
+ Diag(Tok.getLocation(), diag::err_friend_decl_spec)
+ << VirtSpecifiers::getSpecifierName(Specifier)
+ << FixItHint::CreateRemoval(Tok.getLocation())
+ << SourceRange(FriendLoc, FriendLoc);
+ ConsumeToken();
+ continue;
+ }
+
// C++ [class.mem]p8:
// A virt-specifier-seq shall contain at most one of each virt-specifier.
const char *PrevSpec = nullptr;
@@ -1929,13 +2028,19 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer(
// identifier[opt] ':' constant-expression
if (Tok.isNot(tok::colon))
ParseDeclarator(DeclaratorInfo);
+ else
+ DeclaratorInfo.SetIdentifier(nullptr, Tok.getLocation());
if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) {
+ assert(DeclaratorInfo.isPastIdentifier() &&
+ "don't know where identifier would go yet?");
BitfieldSize = ParseConstantExpression();
if (BitfieldSize.isInvalid())
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
} else
- ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ ParseOptionalCXX11VirtSpecifierSeq(
+ VS, getCurrentClass().IsInterface,
+ DeclaratorInfo.getDeclSpec().getFriendSpecLoc());
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
@@ -1953,10 +2058,21 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer(
// For compatibility with code written to older Clang, also accept a
// virt-specifier *after* the GNU attributes.
- // FIXME: If we saw any attributes that are known to GCC followed by a
- // virt-specifier, issue a GCC-compat warning.
- if (BitfieldSize.isUnset() && VS.isUnset())
- ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ if (BitfieldSize.isUnset() && VS.isUnset()) {
+ ParseOptionalCXX11VirtSpecifierSeq(
+ VS, getCurrentClass().IsInterface,
+ DeclaratorInfo.getDeclSpec().getFriendSpecLoc());
+ if (!VS.isUnset()) {
+ // If we saw any GNU-style attributes that are known to GCC followed by a
+ // virt-specifier, issue a GCC-compat warning.
+ const AttributeList *Attr = DeclaratorInfo.getAttributes();
+ while (Attr) {
+ if (Attr->isKnownToGCC() && !Attr->isCXX11Attribute())
+ Diag(Attr->getLoc(), diag::warn_gcc_attribute_location);
+ Attr = Attr->getNext();
+ }
+ }
+ }
}
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
@@ -2021,7 +2137,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Access declarations.
bool MalformedTypeSpec = false;
if (!TemplateInfo.Kind &&
- (Tok.is(tok::identifier) || Tok.is(tok::coloncolon))) {
+ (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw___super))) {
if (TryAnnotateCXXScopeToken())
MalformedTypeSpec = true;
@@ -2039,6 +2156,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
/*EnteringContext=*/false);
+ if (SS.isInvalid()) {
+ SkipUntil(tok::semi);
+ return;
+ }
+
// Try to parse an unqualified-id.
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
@@ -2066,9 +2188,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
}
- // static_assert-declaration
- if (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) {
- // FIXME: Check for templates
+ // static_assert-declaration. A templated static_assert declaration is
+ // diagnosed in Parser::ParseSingleDeclarationAfterTemplate.
+ if (!TemplateInfo.Kind &&
+ (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert))) {
SourceLocation DeclEnd;
ParseStaticAssertDeclaration(DeclEnd);
return;
@@ -2309,7 +2432,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
E = Ranges.end(); I != E; ++I)
Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I;
- // TODO: handle initializers, VS, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
TemplateParams);
} else {
@@ -2487,7 +2609,10 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
Diag(ConsumeToken(), diag::err_default_special_members);
return ExprError();
}
-
+ }
+ if (const auto *PD = dyn_cast_or_null<MSPropertyDecl>(D)) {
+ Diag(Tok, diag::err_ms_property_initializer) << PD;
+ return ExprError();
}
return ParseInitializer();
}
@@ -2581,17 +2706,60 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// and the only possible place for them to appertain
// to the class would be between class-key and class-name.
CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc);
+
+ // ParseClassSpecifier() does only a superficial check for attributes before
+ // deciding to call this method. For example, for
+ // `class C final alignas ([l) {` it will decide that this looks like a
+ // misplaced attribute since it sees `alignas '(' ')'`. But the actual
+ // attribute parsing code will try to parse the '[' as a constexpr lambda
+ // and consume enough tokens that the alignas parsing code will eat the
+ // opening '{'. So bail out if the next token isn't one we expect.
+ if (!Tok.is(tok::colon) && !Tok.is(tok::l_brace)) {
+ if (TagDecl)
+ Actions.ActOnTagDefinitionError(getCurScope(), TagDecl);
+ return;
+ }
}
if (Tok.is(tok::colon)) {
ParseBaseClause(TagDecl);
-
if (!Tok.is(tok::l_brace)) {
- Diag(Tok, diag::err_expected_lbrace_after_base_specifiers);
-
- if (TagDecl)
- Actions.ActOnTagDefinitionError(getCurScope(), TagDecl);
- return;
+ bool SuggestFixIt = false;
+ SourceLocation BraceLoc = PP.getLocForEndOfToken(PrevTokLocation);
+ if (Tok.isAtStartOfLine()) {
+ switch (Tok.getKind()) {
+ case tok::kw_private:
+ case tok::kw_protected:
+ case tok::kw_public:
+ SuggestFixIt = NextToken().getKind() == tok::colon;
+ break;
+ case tok::kw_static_assert:
+ case tok::r_brace:
+ case tok::kw_using:
+ // base-clause can have simple-template-id; 'template' can't be there
+ case tok::kw_template:
+ SuggestFixIt = true;
+ break;
+ case tok::identifier:
+ SuggestFixIt = isConstructorDeclarator(true);
+ break;
+ default:
+ SuggestFixIt = isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
+ break;
+ }
+ }
+ DiagnosticBuilder LBraceDiag =
+ Diag(BraceLoc, diag::err_expected_lbrace_after_base_specifiers);
+ if (SuggestFixIt) {
+ LBraceDiag << FixItHint::CreateInsertion(BraceLoc, " {");
+ // Try recovering from missing { after base-clause.
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::l_brace);
+ } else {
+ if (TagDecl)
+ Actions.ActOnTagDefinitionError(getCurScope(), TagDecl);
+ return;
+ }
}
}
@@ -2725,7 +2893,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// C++11 [class.mem]p2:
// Within the class member-specification, the class is regarded as complete
- // within function bodies, default arguments, and
+ // within function bodies, default arguments, exception-specifications, and
// brace-or-equal-initializers for non-static data members (including such
// things in nested classes).
if (TagDecl && NonNestedClass) {
@@ -2854,7 +3022,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
/// [C++] mem-initializer-id:
/// '::'[opt] nested-name-specifier[opt] class-name
/// identifier
-Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
+MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
@@ -2944,13 +3112,51 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
/// 'noexcept'
/// 'noexcept' '(' constant-expression ')'
ExceptionSpecificationType
-Parser::tryParseExceptionSpecification(
+Parser::tryParseExceptionSpecification(bool Delayed,
SourceRange &SpecificationRange,
SmallVectorImpl<ParsedType> &DynamicExceptions,
SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
- ExprResult &NoexceptExpr) {
+ ExprResult &NoexceptExpr,
+ CachedTokens *&ExceptionSpecTokens) {
ExceptionSpecificationType Result = EST_None;
-
+ ExceptionSpecTokens = 0;
+
+ // Handle delayed parsing of exception-specifications.
+ if (Delayed) {
+ if (Tok.isNot(tok::kw_throw) && Tok.isNot(tok::kw_noexcept))
+ return EST_None;
+
+ // Consume and cache the starting token.
+ bool IsNoexcept = Tok.is(tok::kw_noexcept);
+ Token StartTok = Tok;
+ SpecificationRange = SourceRange(ConsumeToken());
+
+ // Check for a '('.
+ if (!Tok.is(tok::l_paren)) {
+ // If this is a bare 'noexcept', we're done.
+ if (IsNoexcept) {
+ Diag(Tok, diag::warn_cxx98_compat_noexcept_decl);
+ NoexceptExpr = 0;
+ return EST_BasicNoexcept;
+ }
+
+ Diag(Tok, diag::err_expected_lparen_after) << "throw";
+ return EST_DynamicNone;
+ }
+
+ // Cache the tokens for the exception-specification.
+ ExceptionSpecTokens = new CachedTokens;
+ ExceptionSpecTokens->push_back(StartTok); // 'throw' or 'noexcept'
+ ExceptionSpecTokens->push_back(Tok); // '('
+ SpecificationRange.setEnd(ConsumeParen()); // '('
+
+ ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens,
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/true);
+ SpecificationRange.setEnd(Tok.getLocation());
+ return EST_Unparsed;
+ }
+
// See if there's a dynamic specification.
if (Tok.is(tok::kw_throw)) {
Result = ParseDynamicExceptionSpecification(SpecificationRange,
@@ -3168,9 +3374,11 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
switch (Tok.getKind()) {
default:
// Identifiers and keywords have identifier info attached.
- if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
- Loc = ConsumeToken();
- return II;
+ if (!Tok.isAnnotation()) {
+ if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ Loc = ConsumeToken();
+ return II;
+ }
}
return nullptr;
@@ -3265,7 +3473,6 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
if (Attr->getMaxArgs() && !NumArgs) {
// The attribute was allowed to have arguments, but none were provided
// even though the attribute parsed successfully. This is an error.
- // FIXME: This is a good place for a fixit which removes the parens.
Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName;
return false;
} else if (!Attr->getMaxArgs()) {
@@ -3273,7 +3480,8 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
// arguments. It doesn't matter whether any were provided -- the
// presence of the argument list (even if empty) is diagnosed.
Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments)
- << AttrName;
+ << AttrName
+ << FixItHint::CreateRemoval(SourceRange(LParenLoc, *EndLoc));
return false;
}
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 0e4dfb91ad5d..d0d97de84c10 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -216,6 +216,13 @@ bool Parser::isNotExpressionStart() {
return isKnownToBeDeclarationSpecifier();
}
+static bool isFoldOperator(prec::Level Level) {
+ return Level > prec::Unknown && Level != prec::Conditional;
+}
+static bool isFoldOperator(tok::TokenKind Kind) {
+ return isFoldOperator(getBinOpPrecedence(Kind, false, true));
+}
+
/// \brief Parse a binary expression that starts with \p LHS and has a
/// precedence of at least \p MinPrec.
ExprResult
@@ -247,6 +254,16 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
return LHS;
}
+ // If the next token is an ellipsis, then this is a fold-expression. Leave
+ // it alone so we can handle it in the paren expression.
+ if (isFoldOperator(NextTokPrec) && Tok.is(tok::ellipsis)) {
+ // FIXME: We can't check this via lookahead before we consume the token
+ // because that tickles a lexer bug.
+ PP.EnterToken(Tok);
+ Tok = OpToken;
+ return LHS;
+ }
+
// Special case handling for the ternary operator.
ExprResult TernaryMiddle(true);
if (NextTokPrec == prec::Conditional) {
@@ -260,6 +277,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// 'logical-OR-expression' as we might expect.
TernaryMiddle = ParseExpression();
if (TernaryMiddle.isInvalid()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
TernaryMiddle = nullptr;
}
@@ -328,9 +346,11 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
else
RHS = ParseCastExpression(false);
- if (RHS.isInvalid())
+ if (RHS.isInvalid()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
-
+ }
+
// Remember the precedence of this operator and get the precedence of the
// operator immediately to the right of the RHS.
prec::Level ThisPrec = NextTokPrec;
@@ -359,13 +379,14 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
static_cast<prec::Level>(ThisPrec + !isRightAssoc));
RHSIsInitList = false;
- if (RHS.isInvalid())
+ if (RHS.isInvalid()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
+ }
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
getLangOpts().CPlusPlus11);
}
- assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
if (!RHS.isInvalid() && RHSIsInitList) {
if (ThisPrec == prec::Assignment) {
@@ -397,7 +418,9 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc,
LHS.get(), TernaryMiddle.get(),
RHS.get());
- }
+ } else
+ // Ensure potential typos in the RHS aren't left undiagnosed.
+ Actions.CorrectDelayedTyposInExpr(RHS);
}
}
@@ -425,7 +448,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
public:
CastExpressionIdValidator(bool AllowTypes, bool AllowNonTypes)
: AllowNonTypes(AllowNonTypes) {
- WantTypeSpecifiers = AllowTypes;
+ WantTypeSpecifiers = WantFunctionLikeCasts = AllowTypes;
}
bool ValidateCandidate(const TypoCorrection &candidate) override {
@@ -688,11 +711,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
ConsumeToken();
break;
+ case tok::kw___super:
case tok::kw_decltype:
// Annotate the token and tail recurse.
if (TryAnnotateTypeOrScopeToken())
return ExprError();
- assert(Tok.isNot(tok::kw_decltype));
+ assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super));
return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
case tok::identifier: { // primary-expression: identifier
@@ -708,11 +732,81 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// If this identifier was reverted from a token ID, and the next token
// is a parenthesis, this is likely to be a use of a type trait. Check
// those tokens.
- if (Next.is(tok::l_paren) && Tok.is(tok::identifier) &&
- Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier() &&
- TryIdentKeywordUpgrade())
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
+ if (Next.is(tok::l_paren) &&
+ Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ // Build up the mapping of revertible type traits, for future use.
+ if (RevertibleTypeTraits.empty()) {
+#define RTT_JOIN(X,Y) X##Y
+#define REVERTIBLE_TYPE_TRAIT(Name) \
+ RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] \
+ = RTT_JOIN(tok::kw_,Name)
+
+ REVERTIBLE_TYPE_TRAIT(__is_abstract);
+ REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
+ REVERTIBLE_TYPE_TRAIT(__is_array);
+ REVERTIBLE_TYPE_TRAIT(__is_base_of);
+ REVERTIBLE_TYPE_TRAIT(__is_class);
+ REVERTIBLE_TYPE_TRAIT(__is_complete_type);
+ REVERTIBLE_TYPE_TRAIT(__is_compound);
+ REVERTIBLE_TYPE_TRAIT(__is_const);
+ REVERTIBLE_TYPE_TRAIT(__is_constructible);
+ REVERTIBLE_TYPE_TRAIT(__is_convertible);
+ REVERTIBLE_TYPE_TRAIT(__is_convertible_to);
+ REVERTIBLE_TYPE_TRAIT(__is_destructible);
+ REVERTIBLE_TYPE_TRAIT(__is_empty);
+ REVERTIBLE_TYPE_TRAIT(__is_enum);
+ REVERTIBLE_TYPE_TRAIT(__is_floating_point);
+ REVERTIBLE_TYPE_TRAIT(__is_final);
+ REVERTIBLE_TYPE_TRAIT(__is_function);
+ REVERTIBLE_TYPE_TRAIT(__is_fundamental);
+ REVERTIBLE_TYPE_TRAIT(__is_integral);
+ REVERTIBLE_TYPE_TRAIT(__is_interface_class);
+ REVERTIBLE_TYPE_TRAIT(__is_literal);
+ REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
+ REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
+ REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
+ REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer);
+ REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
+ REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable);
+ REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible);
+ REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible);
+ REVERTIBLE_TYPE_TRAIT(__is_object);
+ REVERTIBLE_TYPE_TRAIT(__is_pod);
+ REVERTIBLE_TYPE_TRAIT(__is_pointer);
+ REVERTIBLE_TYPE_TRAIT(__is_polymorphic);
+ REVERTIBLE_TYPE_TRAIT(__is_reference);
+ REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr);
+ REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference);
+ REVERTIBLE_TYPE_TRAIT(__is_same);
+ REVERTIBLE_TYPE_TRAIT(__is_scalar);
+ REVERTIBLE_TYPE_TRAIT(__is_sealed);
+ REVERTIBLE_TYPE_TRAIT(__is_signed);
+ REVERTIBLE_TYPE_TRAIT(__is_standard_layout);
+ REVERTIBLE_TYPE_TRAIT(__is_trivial);
+ REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable);
+ REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible);
+ REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable);
+ REVERTIBLE_TYPE_TRAIT(__is_union);
+ REVERTIBLE_TYPE_TRAIT(__is_unsigned);
+ REVERTIBLE_TYPE_TRAIT(__is_void);
+ REVERTIBLE_TYPE_TRAIT(__is_volatile);
+#undef REVERTIBLE_TYPE_TRAIT
+#undef RTT_JOIN
+ }
+
+ // If we find that this is in fact the name of a type trait,
+ // update the token kind in place and parse again to treat it as
+ // the appropriate kind of type trait.
+ llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
+ = RevertibleTypeTraits.find(II);
+ if (Known != RevertibleTypeTraits.end()) {
+ Tok.setKind(Known->second);
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, isTypeCast);
+ }
+ }
if (Next.is(tok::coloncolon) ||
(!ColonIsSacred && Next.is(tok::colon)) ||
@@ -812,17 +906,26 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
UnqualifiedId Name;
CXXScopeSpec ScopeSpec;
SourceLocation TemplateKWLoc;
- CastExpressionIdValidator Validator(isTypeCast != NotTypeCast,
- isTypeCast != IsTypeCast);
- Validator.IsAddressOfOperand = isAddressOfOperand;
+ Token Replacement;
+ auto Validator = llvm::make_unique<CastExpressionIdValidator>(
+ isTypeCast != NotTypeCast, isTypeCast != IsTypeCast);
+ Validator->IsAddressOfOperand = isAddressOfOperand;
+ Validator->WantRemainingKeywords = Tok.isNot(tok::r_paren);
Name.setIdentifier(&II, ILoc);
- Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
- Name, Tok.is(tok::l_paren),
- isAddressOfOperand, &Validator);
+ Res = Actions.ActOnIdExpression(
+ getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren),
+ isAddressOfOperand, std::move(Validator),
+ /*IsInlineAsmIdentifier=*/false, &Replacement);
+ if (!Res.isInvalid() && !Res.get()) {
+ UnconsumeToken(Replacement);
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, isTypeCast);
+ }
break;
}
case tok::char_constant: // constant: character-constant
case tok::wide_char_constant:
+ case tok::utf8_char_constant:
case tok::utf16_char_constant:
case tok::utf32_char_constant:
Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope());
@@ -1261,8 +1364,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (!LHS.isInvalid() && !Idx.isInvalid() && Tok.is(tok::r_square)) {
LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc,
Idx.get(), RLoc);
- } else
+ } else {
+ (void)Actions.CorrectDelayedTyposInExpr(LHS);
+ (void)Actions.CorrectDelayedTyposInExpr(Idx);
LHS = ExprError();
+ Idx = ExprError();
+ }
// Match the ']'.
T.consumeClose();
@@ -1285,6 +1392,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
SourceLocation OpenLoc = ConsumeToken();
if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) {
+ (void)Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
}
@@ -1335,6 +1443,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (Tok.isNot(tok::r_paren)) {
if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall,
LHS.get())) {
+ (void)Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
}
}
@@ -1433,8 +1542,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
/*AllowDestructorName=*/true,
/*AllowConstructorName=*/
getLangOpts().MicrosoftExt,
- ObjectType, TemplateKWLoc, Name))
+ ObjectType, TemplateKWLoc, Name)) {
+ (void)Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
+ }
if (!LHS.isInvalid())
LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc,
@@ -1918,11 +2029,15 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
/// cast-expression: [C99 6.5.4]
/// '(' type-name ')' cast-expression
/// [ARC] bridged-cast-expression
-///
/// [ARC] bridged-cast-expression:
/// (__bridge type-name) cast-expression
/// (__bridge_transfer type-name) cast-expression
/// (__bridge_retained type-name) cast-expression
+/// fold-expression: [C++1z]
+/// '(' cast-expression fold-operator '...' ')'
+/// '(' '...' fold-operator cast-expression ')'
+/// '(' cast-expression fold-operator '...'
+/// fold-operator cast-expression ')'
/// \endverbatim
ExprResult
Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
@@ -1969,16 +2084,21 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// unless they've already reported an error.
if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
Diag(Tok, diag::ext_gnu_statement_expr);
- Actions.ActOnStartStmtExpr();
- StmtResult Stmt(ParseCompoundStatement(true));
- ExprType = CompoundStmt;
-
- // If the substmt parsed correctly, build the AST node.
- if (!Stmt.isInvalid()) {
- Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.get(), Tok.getLocation());
+ if (!getCurScope()->getFnParent() && !getCurScope()->getBlockParent()) {
+ Result = ExprError(Diag(OpenLoc, diag::err_stmtexpr_file_scope));
} else {
- Actions.ActOnStmtExprError();
+ Actions.ActOnStartStmtExpr();
+
+ StmtResult Stmt(ParseCompoundStatement(true));
+ ExprType = CompoundStmt;
+
+ // If the substmt parsed correctly, build the AST node.
+ if (!Stmt.isInvalid()) {
+ Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.get(), Tok.getLocation());
+ } else {
+ Actions.ActOnStmtExprError();
+ }
}
} else if (ExprType >= CompoundLiteral && BridgeCast) {
tok::TokenKind tokenKind = Tok.getKind();
@@ -2111,24 +2231,36 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
return ExprError();
}
+ } else if (Tok.is(tok::ellipsis) &&
+ isFoldOperator(NextToken().getKind())) {
+ return ParseFoldExpression(ExprResult(), T);
} else if (isTypeCast) {
// Parse the expression-list.
InMessageExpressionRAIIObject InMessage(*this, false);
-
+
ExprVector ArgExprs;
CommaLocsTy CommaLocs;
if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) {
+ // FIXME: If we ever support comma expressions as operands to
+ // fold-expressions, we'll need to allow multiple ArgExprs here.
+ if (ArgExprs.size() == 1 && isFoldOperator(Tok.getKind()) &&
+ NextToken().is(tok::ellipsis))
+ return ParseFoldExpression(Result, T);
+
ExprType = SimpleExpr;
Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
ArgExprs);
}
} else {
InMessageExpressionRAIIObject InMessage(*this, false);
-
+
Result = ParseExpression(MaybeTypeCast);
ExprType = SimpleExpr;
+ if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis))
+ return ParseFoldExpression(Result, T);
+
// Don't build a paren expression unless we actually match a ')'.
if (!Result.isInvalid() && Tok.is(tok::r_paren))
Result =
@@ -2286,6 +2418,59 @@ ExprResult Parser::ParseGenericSelectionExpression() {
Types, Exprs);
}
+/// \brief Parse A C++1z fold-expression after the opening paren and optional
+/// left-hand-side expression.
+///
+/// \verbatim
+/// fold-expression:
+/// ( cast-expression fold-operator ... )
+/// ( ... fold-operator cast-expression )
+/// ( cast-expression fold-operator ... fold-operator cast-expression )
+ExprResult Parser::ParseFoldExpression(ExprResult LHS,
+ BalancedDelimiterTracker &T) {
+ if (LHS.isInvalid()) {
+ T.skipToEnd();
+ return true;
+ }
+
+ tok::TokenKind Kind = tok::unknown;
+ SourceLocation FirstOpLoc;
+ if (LHS.isUsable()) {
+ Kind = Tok.getKind();
+ assert(isFoldOperator(Kind) && "missing fold-operator");
+ FirstOpLoc = ConsumeToken();
+ }
+
+ assert(Tok.is(tok::ellipsis) && "not a fold-expression");
+ SourceLocation EllipsisLoc = ConsumeToken();
+
+ ExprResult RHS;
+ if (Tok.isNot(tok::r_paren)) {
+ if (!isFoldOperator(Tok.getKind()))
+ return Diag(Tok.getLocation(), diag::err_expected_fold_operator);
+
+ if (Kind != tok::unknown && Tok.getKind() != Kind)
+ Diag(Tok.getLocation(), diag::err_fold_operator_mismatch)
+ << SourceRange(FirstOpLoc);
+ Kind = Tok.getKind();
+ ConsumeToken();
+
+ RHS = ParseExpression();
+ if (RHS.isInvalid()) {
+ T.skipToEnd();
+ return true;
+ }
+ }
+
+ Diag(EllipsisLoc, getLangOpts().CPlusPlus1z
+ ? diag::warn_cxx14_compat_fold_expression
+ : diag::ext_fold_expression);
+
+ T.consumeClose();
+ return Actions.ActOnCXXFoldExpr(T.getOpenLocation(), LHS.get(), Kind,
+ EllipsisLoc, RHS.get(), T.getCloseLocation());
+}
+
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
///
/// \verbatim
@@ -2342,10 +2527,19 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
}
if (Tok.isNot(tok::comma))
- return SawError;
+ break;
// Move to the next argument, remember where the comma was.
CommaLocs.push_back(ConsumeToken());
}
+ if (SawError) {
+ // Ensure typos get diagnosed when errors were encountered while parsing the
+ // expression list.
+ for (auto &E : Exprs) {
+ ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E);
+ if (Expr.isUsable()) E = Expr.get();
+ }
+ }
+ return SawError;
}
/// ParseSimpleExpressionList - A simple comma-separated list of expressions,
@@ -2477,6 +2671,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
/*RefQualifierLoc=*/NoLoc,
/*ConstQualifierLoc=*/NoLoc,
/*VolatileQualifierLoc=*/NoLoc,
+ /*RestrictQualifierLoc=*/NoLoc,
/*MutableLoc=*/NoLoc,
EST_None,
/*ESpecLoc=*/NoLoc,
@@ -2484,6 +2679,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
/*ExceptionRanges=*/nullptr,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
+ /*ExceptionSpecTokens=*/nullptr,
CaretLoc, CaretLoc,
ParamInfo),
attrs, CaretLoc);
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 83121a8b1a2d..355503caa9be 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -108,35 +108,37 @@ void Parser::CheckForLParenAfterColonColon() {
if (!Tok.is(tok::l_paren))
return;
- SourceLocation l_parenLoc = ConsumeParen(), r_parenLoc;
- Token Tok1 = getCurToken();
- if (!Tok1.is(tok::identifier) && !Tok1.is(tok::star))
+ Token LParen = Tok;
+ Token NextTok = GetLookAheadToken(1);
+ Token StarTok = NextTok;
+ // Check for (identifier or (*identifier
+ Token IdentifierTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : StarTok;
+ if (IdentifierTok.isNot(tok::identifier))
return;
-
- if (Tok1.is(tok::identifier)) {
- Token Tok2 = GetLookAheadToken(1);
- if (Tok2.is(tok::r_paren)) {
+ // Eat the '('.
+ ConsumeParen();
+ Token RParen;
+ // Do we have a ')' ?
+ NextTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : GetLookAheadToken(1);
+ if (NextTok.is(tok::r_paren)) {
+ RParen = NextTok;
+ // Eat the '*' if it is present.
+ if (StarTok.is(tok::star))
ConsumeToken();
- PP.EnterToken(Tok1);
- r_parenLoc = ConsumeParen();
- }
- } else if (Tok1.is(tok::star)) {
- Token Tok2 = GetLookAheadToken(1);
- if (Tok2.is(tok::identifier)) {
- Token Tok3 = GetLookAheadToken(2);
- if (Tok3.is(tok::r_paren)) {
- ConsumeToken();
- ConsumeToken();
- PP.EnterToken(Tok2);
- PP.EnterToken(Tok1);
- r_parenLoc = ConsumeParen();
- }
- }
- }
-
- Diag(l_parenLoc, diag::err_paren_after_colon_colon)
- << FixItHint::CreateRemoval(l_parenLoc)
- << FixItHint::CreateRemoval(r_parenLoc);
+ // Eat the identifier.
+ ConsumeToken();
+ // Add the identifier token back.
+ PP.EnterToken(IdentifierTok);
+ // Add the '*' back if it was present.
+ if (StarTok.is(tok::star))
+ PP.EnterToken(StarTok);
+ // Eat the ')'.
+ ConsumeParen();
+ }
+
+ Diag(LParen.getLocation(), diag::err_paren_after_colon_colon)
+ << FixItHint::CreateRemoval(LParen.getLocation())
+ << FixItHint::CreateRemoval(RParen.getLocation());
}
/// \brief Parse global scope or nested-name-specifier if present.
@@ -217,13 +219,29 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
if (NextKind == tok::kw_new || NextKind == tok::kw_delete)
return false;
- // '::' - Global scope qualifier.
- if (Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), ConsumeToken(), SS))
- return true;
+ if (NextKind == tok::l_brace) {
+ // It is invalid to have :: {, consume the scope qualifier and pretend
+ // like we never saw it.
+ Diag(ConsumeToken(), diag::err_expected) << tok::identifier;
+ } else {
+ // '::' - Global scope qualifier.
+ if (Actions.ActOnCXXGlobalScopeSpecifier(ConsumeToken(), SS))
+ return true;
- CheckForLParenAfterColonColon();
+ CheckForLParenAfterColonColon();
- HasScopeSpecifier = true;
+ HasScopeSpecifier = true;
+ }
+ }
+
+ if (Tok.is(tok::kw___super)) {
+ SourceLocation SuperLoc = ConsumeToken();
+ if (!Tok.is(tok::coloncolon)) {
+ Diag(Tok.getLocation(), diag::err_expected_coloncolon_after_super);
+ return true;
+ }
+
+ return Actions.ActOnSuperScopeSpecifier(SuperLoc, ConsumeToken(), SS);
}
bool CheckForDestructor = false;
@@ -232,7 +250,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
*MayBePseudoDestructor = false;
}
- if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) {
+ if (!HasScopeSpecifier &&
+ (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype))) {
DeclSpec DS(AttrFactory);
SourceLocation DeclLoc = Tok.getLocation();
SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
@@ -423,11 +442,22 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
Next.setKind(tok::coloncolon);
}
}
-
+
+ if (Next.is(tok::coloncolon) && GetLookAheadToken(2).is(tok::l_brace)) {
+ // It is invalid to have :: {, consume the scope qualifier and pretend
+ // like we never saw it.
+ Token Identifier = Tok; // Stash away the identifier.
+ ConsumeToken(); // Eat the identifier, current token is now '::'.
+ Diag(PP.getLocForEndOfToken(ConsumeToken()), diag::err_expected)
+ << tok::identifier;
+ UnconsumeToken(Identifier); // Stick the identifier back.
+ Next = NextToken(); // Point Next at the '{' token.
+ }
+
if (Next.is(tok::coloncolon)) {
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) &&
- !Actions.isNonTypeNestedNameSpecifier(getCurScope(), SS, Tok.getLocation(),
- II, ObjectType)) {
+ !Actions.isNonTypeNestedNameSpecifier(
+ getCurScope(), SS, Tok.getLocation(), II, ObjectType)) {
*MayBePseudoDestructor = true;
return false;
}
@@ -556,6 +586,28 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
+ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand,
+ Token &Replacement) {
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId Name;
+ if (ParseUnqualifiedId(SS,
+ /*EnteringContext=*/false,
+ /*AllowDestructorName=*/false,
+ /*AllowConstructorName=*/false,
+ /*ObjectType=*/ParsedType(), TemplateKWLoc, Name))
+ return ExprError();
+
+ // This is only the direct operand of an & operator if it is not
+ // followed by a postfix-expression suffix.
+ if (isAddressOfOperand && isPostfixExpressionSuffixStart())
+ isAddressOfOperand = false;
+
+ return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name,
+ Tok.is(tok::l_paren), isAddressOfOperand,
+ nullptr, /*IsInlineAsmIdentifier=*/false,
+ &Replacement);
+}
+
/// ParseCXXIdExpression - Handle id-expression.
///
/// id-expression:
@@ -606,24 +658,17 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
- SourceLocation TemplateKWLoc;
- UnqualifiedId Name;
- if (ParseUnqualifiedId(SS,
- /*EnteringContext=*/false,
- /*AllowDestructorName=*/false,
- /*AllowConstructorName=*/false,
- /*ObjectType=*/ ParsedType(),
- TemplateKWLoc,
- Name))
- return ExprError();
-
- // This is only the direct operand of an & operator if it is not
- // followed by a postfix-expression suffix.
- if (isAddressOfOperand && isPostfixExpressionSuffixStart())
- isAddressOfOperand = false;
-
- return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name,
- Tok.is(tok::l_paren), isAddressOfOperand);
+ Token Replacement;
+ ExprResult Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
+ if (Result.isUnset()) {
+ // If the ExprResult is valid but null, then typo correction suggested a
+ // keyword replacement that needs to be reparsed.
+ UnconsumeToken(Replacement);
+ Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
+ }
+ assert(!Result.isUnset() && "Typo correction suggested a keyword replacement "
+ "for a previous keyword suggestion");
+ return Result;
}
/// ParseLambdaExpression - Parse a C++11 lambda expression.
@@ -1007,6 +1052,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
Actions.PushLambdaScope();
+ TypeResult TrailingReturnType;
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
Scope::FunctionPrototypeScope |
@@ -1050,10 +1096,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
SmallVector<ParsedType, 2> DynamicExceptions;
SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
- ESpecType = tryParseExceptionSpecification(ESpecRange,
+ CachedTokens *ExceptionSpecTokens;
+ ESpecType = tryParseExceptionSpecification(/*Delayed=*/false,
+ ESpecRange,
DynamicExceptions,
DynamicExceptionRanges,
- NoexceptExpr);
+ NoexceptExpr,
+ ExceptionSpecTokens);
if (ESpecType != EST_None)
DeclEndLoc = ESpecRange.getEnd();
@@ -1064,7 +1113,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
SourceLocation FunLocalRangeEnd = DeclEndLoc;
// Parse trailing-return-type[opt].
- TypeResult TrailingReturnType;
if (Tok.is(tok::arrow)) {
FunLocalRangeEnd = Tok.getLocation();
SourceRange Range;
@@ -1086,6 +1134,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
/*RefQualifierLoc=*/NoLoc,
/*ConstQualifierLoc=*/NoLoc,
/*VolatileQualifierLoc=*/NoLoc,
+ /*RestrictQualifierLoc=*/NoLoc,
MutableLoc,
ESpecType, ESpecRange.getBegin(),
DynamicExceptions.data(),
@@ -1093,6 +1142,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : nullptr,
+ /*ExceptionSpecTokens*/nullptr,
LParenLoc, FunLocalRangeEnd, D,
TrailingReturnType),
Attr, DeclEndLoc);
@@ -1132,12 +1182,11 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
// Parse the return type, if there is one.
- TypeResult TrailingReturnType;
if (Tok.is(tok::arrow)) {
SourceRange Range;
TrailingReturnType = ParseTrailingReturnType(Range);
if (Range.getEnd().isValid())
- DeclEndLoc = Range.getEnd();
+ DeclEndLoc = Range.getEnd();
}
SourceLocation NoLoc;
@@ -1153,6 +1202,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
/*RefQualifierLoc=*/NoLoc,
/*ConstQualifierLoc=*/NoLoc,
/*VolatileQualifierLoc=*/NoLoc,
+ /*RestrictQualifierLoc=*/NoLoc,
MutableLoc,
EST_None,
/*ESpecLoc=*/NoLoc,
@@ -1160,6 +1210,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
/*ExceptionRanges=*/nullptr,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
+ /*ExceptionSpecTokens=*/nullptr,
DeclLoc, DeclEndLoc, D,
TrailingReturnType),
Attr, DeclEndLoc);
@@ -1183,9 +1234,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
StmtResult Stmt(ParseCompoundStatementBody());
BodyScope.Exit();
- if (!Stmt.isInvalid())
+ if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid())
return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());
-
+
Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
return ExprError();
}
@@ -1389,7 +1440,7 @@ ExprResult Parser::ParseCXXUuidof() {
/// ::[opt] nested-name-specifier[opt] ~type-name
///
ExprResult
-Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
+Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
tok::TokenKind OpKind,
CXXScopeSpec &SS,
ParsedType ObjectType) {
@@ -2452,10 +2503,29 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
return true;
}
+ // If the user wrote ~T::T, correct it to T::~T.
+ if (!TemplateSpecified && NextToken().is(tok::coloncolon)) {
+ if (SS.isSet()) {
+ AnnotateScopeToken(SS, /*NewAnnotation*/true);
+ SS.clear();
+ }
+ if (ParseOptionalCXXScopeSpecifier(SS, ObjectType, EnteringContext))
+ return true;
+ if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon)) {
+ Diag(TildeLoc, diag::err_destructor_tilde_scope);
+ return true;
+ }
+
+ // Recover as if the tilde had been written before the identifier.
+ Diag(TildeLoc, diag::err_destructor_tilde_scope)
+ << FixItHint::CreateRemoval(TildeLoc)
+ << FixItHint::CreateInsertion(Tok.getLocation(), "~");
+ }
+
// Parse the class-name (or template-name in a simple-template-id).
IdentifierInfo *ClassName = Tok.getIdentifierInfo();
SourceLocation ClassNameLoc = ConsumeToken();
-
+
if (TemplateSpecified || Tok.is(tok::less)) {
Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc);
return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc,
@@ -2463,7 +2533,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
EnteringContext, ObjectType,
Result, TemplateSpecified);
}
-
+
// Note that this is a destructor name.
ParsedType Ty = Actions.getDestructorName(TildeLoc, *ClassName,
ClassNameLoc, getCurScope(),
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 8536420088f3..7fe9862d3992 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -423,9 +423,11 @@ ExprResult Parser::ParseBraceInitializer() {
if (Tok.is(tok::ellipsis))
SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken());
-
+
+ SubElt = Actions.CorrectDelayedTyposInExpr(SubElt.get());
+
// If we couldn't parse the subelement, bail out.
- if (!SubElt.isInvalid()) {
+ if (SubElt.isUsable()) {
InitExprs.push_back(SubElt.get());
} else {
InitExprsOk = false;
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 7fe72ec0c3b1..a597a1658cf6 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -79,7 +79,7 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
SingleDecl = ParseObjCPropertyDynamic(AtLoc);
break;
case tok::objc_import:
- if (getLangOpts().Modules)
+ if (getLangOpts().Modules || getLangOpts().DebuggerSupport)
return ParseModuleImport(AtLoc);
Diag(AtLoc, diag::err_atimport);
SkipUntil(tok::semi);
@@ -307,72 +307,6 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
return ClsType;
}
-/// The Objective-C property callback. This should be defined where
-/// it's used, but instead it's been lifted to here to support VS2005.
-struct Parser::ObjCPropertyCallback : FieldCallback {
-private:
- virtual void anchor();
-public:
- Parser &P;
- SmallVectorImpl<Decl *> &Props;
- ObjCDeclSpec &OCDS;
- SourceLocation AtLoc;
- SourceLocation LParenLoc;
- tok::ObjCKeywordKind MethodImplKind;
-
- ObjCPropertyCallback(Parser &P,
- SmallVectorImpl<Decl *> &Props,
- ObjCDeclSpec &OCDS, SourceLocation AtLoc,
- SourceLocation LParenLoc,
- tok::ObjCKeywordKind MethodImplKind) :
- P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc), LParenLoc(LParenLoc),
- MethodImplKind(MethodImplKind) {
- }
-
- void invoke(ParsingFieldDeclarator &FD) override {
- if (FD.D.getIdentifier() == nullptr) {
- P.Diag(AtLoc, diag::err_objc_property_requires_field_name)
- << FD.D.getSourceRange();
- return;
- }
- if (FD.BitfieldSize) {
- P.Diag(AtLoc, diag::err_objc_property_bitfield)
- << FD.D.getSourceRange();
- return;
- }
-
- // Install the property declarator into interfaceDecl.
- IdentifierInfo *SelName =
- OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
-
- Selector GetterSel =
- P.PP.getSelectorTable().getNullarySelector(SelName);
- IdentifierInfo *SetterName = OCDS.getSetterName();
- Selector SetterSel;
- if (SetterName)
- SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName);
- else
- SetterSel =
- SelectorTable::constructSetterSelector(P.PP.getIdentifierTable(),
- P.PP.getSelectorTable(),
- FD.D.getIdentifier());
- bool isOverridingProperty = false;
- Decl *Property =
- P.Actions.ActOnProperty(P.getCurScope(), AtLoc, LParenLoc,
- FD, OCDS,
- GetterSel, SetterSel,
- &isOverridingProperty,
- MethodImplKind);
- if (!isOverridingProperty)
- Props.push_back(Property);
-
- FD.complete(Property);
- }
-};
-
-void Parser::ObjCPropertyCallback::anchor() {
-}
-
/// objc-interface-decl-list:
/// empty
/// objc-interface-decl-list objc-property-decl [OBJC2]
@@ -511,12 +445,44 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
ParseObjCPropertyAttribute(OCDS);
}
- ObjCPropertyCallback Callback(*this, allProperties,
- OCDS, AtLoc, LParenLoc, MethodImplKind);
+ auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
+ if (FD.D.getIdentifier() == nullptr) {
+ Diag(AtLoc, diag::err_objc_property_requires_field_name)
+ << FD.D.getSourceRange();
+ return;
+ }
+ if (FD.BitfieldSize) {
+ Diag(AtLoc, diag::err_objc_property_bitfield)
+ << FD.D.getSourceRange();
+ return;
+ }
+
+ // Install the property declarator into interfaceDecl.
+ IdentifierInfo *SelName =
+ OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
+
+ Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName);
+ IdentifierInfo *SetterName = OCDS.getSetterName();
+ Selector SetterSel;
+ if (SetterName)
+ SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
+ else
+ SetterSel = SelectorTable::constructSetterSelector(
+ PP.getIdentifierTable(), PP.getSelectorTable(),
+ FD.D.getIdentifier());
+ bool isOverridingProperty = false;
+ Decl *Property = Actions.ActOnProperty(
+ getCurScope(), AtLoc, LParenLoc, FD, OCDS, GetterSel, SetterSel,
+ &isOverridingProperty, MethodImplKind);
+ if (!isOverridingProperty)
+ allProperties.push_back(Property);
+
+ FD.complete(Property);
+ };
// Parse all the comma separated declarators.
ParsingDeclSpec DS(*this);
- ParseStructDeclaration(DS, Callback);
+ ParseStructDeclaration(DS, ObjCPropertyCallback);
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
break;
@@ -1338,35 +1304,22 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
Sema::PCC_ObjCInstanceVariableList);
return cutOffParsing();
}
-
- struct ObjCIvarCallback : FieldCallback {
- Parser &P;
- Decl *IDecl;
- tok::ObjCKeywordKind visibility;
- SmallVectorImpl<Decl *> &AllIvarDecls;
-
- ObjCIvarCallback(Parser &P, Decl *IDecl, tok::ObjCKeywordKind V,
- SmallVectorImpl<Decl *> &AllIvarDecls) :
- P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) {
- }
- void invoke(ParsingFieldDeclarator &FD) override {
- P.Actions.ActOnObjCContainerStartDefinition(IDecl);
- // Install the declarator into the interface decl.
- Decl *Field
- = P.Actions.ActOnIvar(P.getCurScope(),
- FD.D.getDeclSpec().getSourceRange().getBegin(),
- FD.D, FD.BitfieldSize, visibility);
- P.Actions.ActOnObjCContainerFinishDefinition();
- if (Field)
- AllIvarDecls.push_back(Field);
- FD.complete(Field);
- }
- } Callback(*this, interfaceDecl, visibility, AllIvarDecls);
-
+ auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
+ Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
+ // Install the declarator into the interface decl.
+ Decl *Field = Actions.ActOnIvar(
+ getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,
+ FD.BitfieldSize, visibility);
+ Actions.ActOnObjCContainerFinishDefinition();
+ if (Field)
+ AllIvarDecls.push_back(Field);
+ FD.complete(Field);
+ };
+
// Parse all the comma separated declarators.
ParsingDeclSpec DS(*this);
- ParseStructDeclaration(DS, Callback);
+ ParseStructDeclaration(DS, ObjCIvarCallback);
if (Tok.is(tok::semi)) {
ConsumeToken();
@@ -2071,7 +2024,13 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))
return ParseObjCAutoreleasePoolStmt(AtLoc);
-
+
+ if (Tok.isObjCAtKeyword(tok::objc_import) &&
+ getLangOpts().DebuggerSupport) {
+ SkipUntil(tok::semi);
+ return Actions.ActOnNullStmt(Tok.getLocation());
+ }
+
ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
if (Res.isInvalid()) {
// If the expression is invalid, skip ahead to the next semicolon. Not
@@ -2217,7 +2176,10 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
// objc-receiver:
// expression
- ExprResult Receiver = ParseExpression();
+ // Make sure any typos in the receiver are corrected or diagnosed, so that
+ // proper recovery can happen. FIXME: Perhaps filter the corrected expr to
+ // only the things that are valid ObjC receivers?
+ ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (Receiver.isInvalid())
return true;
@@ -2394,7 +2356,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
}
// Otherwise, an arbitrary expression can be the receiver of a send.
- ExprResult Res(ParseExpression());
+ ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (Res.isInvalid()) {
SkipUntil(tok::r_square, StopAtSemi);
return Res;
@@ -2446,7 +2408,7 @@ ExprResult
Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SourceLocation SuperLoc,
ParsedType ReceiverType,
- ExprArg ReceiverExpr) {
+ Expr *ReceiverExpr) {
InMessageExpressionRAIIObject InMessage(*this, true);
if (Tok.is(tok::code_completion)) {
@@ -2553,6 +2515,8 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SourceLocation commaLoc = ConsumeToken(); // Eat the ','.
/// Parse the expression after ','
ExprResult Res(ParseAssignmentExpression());
+ if (Tok.is(tok::colon))
+ Res = Actions.CorrectDelayedTyposInExpr(Res);
if (Res.isInvalid()) {
if (Tok.is(tok::colon)) {
Diag(commaLoc, diag::note_extra_comma_message_arg) <<
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index d1544e6baa5b..764619aae6f3 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -26,23 +26,31 @@ using namespace clang;
//===----------------------------------------------------------------------===//
static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
+ // Array of foldings: F[i][0] F[i][1] ===> F[i][2].
+ // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd
+ // TODO: add other combined directives in topological order.
+ const OpenMPDirectiveKind F[][3] = {
+ { OMPD_for, OMPD_simd, OMPD_for_simd },
+ { OMPD_parallel, OMPD_for, OMPD_parallel_for },
+ { OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd },
+ { OMPD_parallel, OMPD_sections, OMPD_parallel_sections }
+ };
auto Tok = P.getCurToken();
auto DKind =
Tok.isAnnotation()
? OMPD_unknown
: getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
- if (DKind == OMPD_parallel) {
- Tok = P.getPreprocessor().LookAhead(0);
- auto SDKind =
- Tok.isAnnotation()
- ? OMPD_unknown
- : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
- if (SDKind == OMPD_for) {
- P.ConsumeToken();
- DKind = OMPD_parallel_for;
- } else if (SDKind == OMPD_sections) {
- P.ConsumeToken();
- DKind = OMPD_parallel_sections;
+ for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) {
+ if (DKind == F[i][0]) {
+ Tok = P.getPreprocessor().LookAhead(0);
+ auto SDKind =
+ Tok.isAnnotation()
+ ? OMPD_unknown
+ : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
+ if (SDKind == F[i][1]) {
+ P.ConsumeToken();
+ DKind = F[i][2];
+ }
}
}
return DKind;
@@ -88,13 +96,19 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
case OMPD_taskwait:
case OMPD_flush:
case OMPD_for:
+ case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
case OMPD_master:
+ case OMPD_ordered:
case OMPD_critical:
case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
+ case OMPD_atomic:
+ case OMPD_target:
+ case OMPD_teams:
Diag(Tok, diag::err_omp_unexpected_directive)
<< getOpenMPDirectiveName(DKind);
break;
@@ -113,7 +127,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
/// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
/// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
/// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' |
-/// 'barrier' | 'taskwait' | 'flush' {clause} annot_pragma_openmp_end
+/// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' |
+/// 'for simd' | 'parallel for simd' | 'target' | 'teams' {clause}
+/// annot_pragma_openmp_end
///
StmtResult
Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
@@ -169,14 +185,20 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
case OMPD_parallel:
case OMPD_simd:
case OMPD_for:
+ case OMPD_for_simd:
case OMPD_sections:
case OMPD_single:
case OMPD_section:
case OMPD_master:
case OMPD_critical:
case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
- case OMPD_task: {
+ case OMPD_task:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_target:
+ case OMPD_teams: {
ConsumeToken();
// Parse directive name of the 'critical' directive if any.
if (DKind == OMPD_critical) {
@@ -337,7 +359,8 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
/// | linear-clause | aligned-clause | collapse-clause |
/// lastprivate-clause | reduction-clause | proc_bind-clause |
/// schedule-clause | copyin-clause | copyprivate-clause | untied-clause |
-/// mergeable-clause | flush-clause
+/// mergeable-clause | flush-clause | read-clause | write-clause |
+/// update-clause | capture-clause | seq_cst-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -368,6 +391,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(CKind);
+ ErrorFound = true;
}
Clause = ParseOpenMPSingleExprClause(CKind);
@@ -382,6 +406,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(CKind);
+ ErrorFound = true;
}
Clause = ParseOpenMPSimpleClause(CKind);
@@ -392,6 +417,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(CKind);
+ ErrorFound = true;
}
Clause = ParseOpenMPSingleExprWithArgClause(CKind);
@@ -400,6 +426,11 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
// OpenMP [2.7.1, Restrictions, p. 9]
// Only one ordered clause can appear on a loop directive.
// OpenMP [2.7.1, Restrictions, C/C++, p. 4]
@@ -407,6 +438,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(CKind);
+ ErrorFound = true;
}
Clause = ParseOpenMPClause(CKind);
@@ -522,6 +554,9 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
/// mergeable-clause:
/// 'mergeable'
///
+/// read-clause:
+/// 'read'
+///
OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
ConsumeAnyToken();
@@ -680,7 +715,8 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
Tok.isNot(tok::annot_pragma_openmp_end))) {
ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
// Parse variable
- ExprResult VarExpr = ParseAssignmentExpression();
+ ExprResult VarExpr =
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (VarExpr.isUsable()) {
Vars.push_back(VarExpr.get());
} else {
@@ -706,7 +742,8 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
if (MustHaveTail) {
ColonLoc = Tok.getLocation();
ConsumeToken();
- ExprResult Tail = ParseAssignmentExpression();
+ ExprResult Tail =
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (Tail.isUsable())
TailExpr = Tail.get();
else
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index d3777f3ea4a0..473be5467eeb 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
@@ -228,6 +229,9 @@ void Parser::initializePragmaHandlers() {
UnrollHintHandler.reset(new PragmaUnrollHintHandler("unroll"));
PP.AddPragmaHandler(UnrollHintHandler.get());
+
+ NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
+ PP.AddPragmaHandler(NoUnrollHintHandler.get());
}
void Parser::resetPragmaHandlers() {
@@ -291,6 +295,9 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler(UnrollHintHandler.get());
UnrollHintHandler.reset();
+
+ PP.RemovePragmaHandler(NoUnrollHintHandler.get());
+ NoUnrollHintHandler.reset();
}
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -525,36 +532,50 @@ bool Parser::HandlePragmaMSSection(StringRef PragmaName,
<< PragmaName;
return false;
}
- int SectionFlags = 0;
+ int SectionFlags = ASTContext::PSF_Read;
+ bool SectionFlagsAreDefault = true;
while (Tok.is(tok::comma)) {
PP.Lex(Tok); // ,
+ // Ignore "long" and "short".
+ // They are undocumented, but widely used, section attributes which appear
+ // to do nothing.
+ if (Tok.is(tok::kw_long) || Tok.is(tok::kw_short)) {
+ PP.Lex(Tok); // long/short
+ continue;
+ }
+
if (!Tok.isAnyIdentifier()) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_action_or_r_paren)
<< PragmaName;
return false;
}
- Sema::PragmaSectionFlag Flag =
- llvm::StringSwitch<Sema::PragmaSectionFlag>(
+ ASTContext::PragmaSectionFlag Flag =
+ llvm::StringSwitch<ASTContext::PragmaSectionFlag>(
Tok.getIdentifierInfo()->getName())
- .Case("read", Sema::PSF_Read)
- .Case("write", Sema::PSF_Write)
- .Case("execute", Sema::PSF_Execute)
- .Case("shared", Sema::PSF_Invalid)
- .Case("nopage", Sema::PSF_Invalid)
- .Case("nocache", Sema::PSF_Invalid)
- .Case("discard", Sema::PSF_Invalid)
- .Case("remove", Sema::PSF_Invalid)
- .Default(Sema::PSF_None);
- if (Flag == Sema::PSF_None || Flag == Sema::PSF_Invalid) {
- PP.Diag(PragmaLocation, Flag == Sema::PSF_None
+ .Case("read", ASTContext::PSF_Read)
+ .Case("write", ASTContext::PSF_Write)
+ .Case("execute", ASTContext::PSF_Execute)
+ .Case("shared", ASTContext::PSF_Invalid)
+ .Case("nopage", ASTContext::PSF_Invalid)
+ .Case("nocache", ASTContext::PSF_Invalid)
+ .Case("discard", ASTContext::PSF_Invalid)
+ .Case("remove", ASTContext::PSF_Invalid)
+ .Default(ASTContext::PSF_None);
+ if (Flag == ASTContext::PSF_None || Flag == ASTContext::PSF_Invalid) {
+ PP.Diag(PragmaLocation, Flag == ASTContext::PSF_None
? diag::warn_pragma_invalid_specific_action
: diag::warn_pragma_unsupported_action)
<< PragmaName << Tok.getIdentifierInfo()->getName();
return false;
}
SectionFlags |= Flag;
+ SectionFlagsAreDefault = false;
PP.Lex(Tok); // Identifier
}
+ // If no section attributes are specified, the section will be marked as
+ // read/write.
+ if (SectionFlagsAreDefault)
+ SectionFlags |= ASTContext::PSF_Write;
if (Tok.isNot(tok::r_paren)) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName;
return false;
@@ -718,42 +739,124 @@ bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
struct PragmaLoopHintInfo {
Token PragmaName;
Token Option;
- Token Value;
- bool HasValue;
+ Token *Toks;
+ size_t TokSize;
+ PragmaLoopHintInfo() : Toks(nullptr), TokSize(0) {}
};
-LoopHint Parser::HandlePragmaLoopHint() {
+static std::string PragmaLoopHintString(Token PragmaName, Token Option) {
+ std::string PragmaString;
+ if (PragmaName.getIdentifierInfo()->getName() == "loop") {
+ PragmaString = "clang loop ";
+ PragmaString += Option.getIdentifierInfo()->getName();
+ } else {
+ assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
+ "Unexpected pragma name");
+ PragmaString = "unroll";
+ }
+ return PragmaString;
+}
+
+bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
assert(Tok.is(tok::annot_pragma_loop_hint));
PragmaLoopHintInfo *Info =
static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
- LoopHint Hint;
- Hint.PragmaNameLoc =
- IdentifierLoc::create(Actions.Context, Info->PragmaName.getLocation(),
- Info->PragmaName.getIdentifierInfo());
- Hint.OptionLoc =
- IdentifierLoc::create(Actions.Context, Info->Option.getLocation(),
- Info->Option.getIdentifierInfo());
- if (Info->HasValue) {
- Hint.Range =
- SourceRange(Info->Option.getLocation(), Info->Value.getLocation());
- Hint.ValueLoc =
- IdentifierLoc::create(Actions.Context, Info->Value.getLocation(),
- Info->Value.getIdentifierInfo());
-
- // FIXME: We should allow non-type template parameters for the loop hint
- // value. See bug report #19610
- if (Info->Value.is(tok::numeric_constant))
- Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
- else
- Hint.ValueExpr = nullptr;
+ IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo();
+ Hint.PragmaNameLoc = IdentifierLoc::create(
+ Actions.Context, Info->PragmaName.getLocation(), PragmaNameInfo);
+
+ // It is possible that the loop hint has no option identifier, such as
+ // #pragma unroll(4).
+ IdentifierInfo *OptionInfo = Info->Option.is(tok::identifier)
+ ? Info->Option.getIdentifierInfo()
+ : nullptr;
+ Hint.OptionLoc = IdentifierLoc::create(
+ Actions.Context, Info->Option.getLocation(), OptionInfo);
+
+ Token *Toks = Info->Toks;
+ size_t TokSize = Info->TokSize;
+
+ // Return a valid hint if pragma unroll or nounroll were specified
+ // without an argument.
+ bool PragmaUnroll = PragmaNameInfo->getName() == "unroll";
+ bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll";
+ if (TokSize == 0 && (PragmaUnroll || PragmaNoUnroll)) {
+ ConsumeToken(); // The annotation token.
+ Hint.Range = Info->PragmaName.getLocation();
+ return true;
+ }
+
+ // The constant expression is always followed by an eof token, which increases
+ // the TokSize by 1.
+ assert(TokSize > 0 &&
+ "PragmaLoopHintInfo::Toks must contain at least one token.");
+
+ // If no option is specified the argument is assumed to be a constant expr.
+ bool StateOption = false;
+ if (OptionInfo) { // Pragma unroll does not specify an option.
+ StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
+ .Case("vectorize", true)
+ .Case("interleave", true)
+ .Case("unroll", true)
+ .Default(false);
+ }
+
+ // Verify loop hint has an argument.
+ if (Toks[0].is(tok::eof)) {
+ ConsumeToken(); // The annotation token.
+ Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument)
+ << /*StateArgument=*/StateOption << /*FullKeyword=*/PragmaUnroll;
+ return false;
+ }
+
+ // Validate the argument.
+ if (StateOption) {
+ ConsumeToken(); // The annotation token.
+ bool OptionUnroll = OptionInfo->isStr("unroll");
+ SourceLocation StateLoc = Toks[0].getLocation();
+ IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
+ if (!StateInfo || ((OptionUnroll ? !StateInfo->isStr("full")
+ : !StateInfo->isStr("enable")) &&
+ !StateInfo->isStr("disable"))) {
+ Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword)
+ << /*FullKeyword=*/OptionUnroll;
+ return false;
+ }
+ if (TokSize > 2)
+ Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaLoopHintString(Info->PragmaName, Info->Option);
+ Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo);
} else {
- Hint.Range = SourceRange(Info->PragmaName.getLocation());
- Hint.ValueLoc = nullptr;
- Hint.ValueExpr = nullptr;
+ // Enter constant expression including eof terminator into token stream.
+ PP.EnterTokenStream(Toks, TokSize, /*DisableMacroExpansion=*/false,
+ /*OwnsTokens=*/false);
+ ConsumeToken(); // The annotation token.
+
+ ExprResult R = ParseConstantExpression();
+
+ // Tokens following an error in an ill-formed constant expression will
+ // remain in the token stream and must be removed.
+ if (Tok.isNot(tok::eof)) {
+ Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaLoopHintString(Info->PragmaName, Info->Option);
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+ }
+
+ ConsumeToken(); // Consume the constant expression eof terminator.
+
+ if (R.isInvalid() ||
+ Actions.CheckLoopHintExpr(R.get(), Toks[0].getLocation()))
+ return false;
+
+ // Argument is a constant expression with an integer type.
+ Hint.ValueExpr = R.get();
}
- return Hint;
+ Hint.Range = SourceRange(Info->PragmaName.getLocation(),
+ Info->Toks[TokSize - 1].getLocation());
+ return true;
}
// #pragma GCC visibility comes in two variants:
@@ -1725,8 +1828,7 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
PP.Lex(Tok);
if (Tok.is(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
- << "clang optimize"
- << "'on' or 'off'";
+ << "clang optimize" << /*Expected=*/true << "'on' or 'off'";
return;
}
if (Tok.isNot(tok::identifier)) {
@@ -1756,44 +1858,48 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
}
/// \brief Parses loop or unroll pragma hint value and fills in Info.
-static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
- Token &Option, bool &ValueInParens,
+static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
+ Token Option, bool ValueInParens,
PragmaLoopHintInfo &Info) {
- ValueInParens = Tok.is(tok::l_paren);
- if (ValueInParens) {
- PP.Lex(Tok);
- if (Tok.is(tok::r_paren)) {
- // Nothing between the parentheses.
- std::string PragmaString;
- if (PragmaName.getIdentifierInfo()->getName() == "loop") {
- PragmaString = "clang loop ";
- PragmaString += Option.getIdentifierInfo()->getName();
- } else {
- assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
- "Unexpected pragma name");
- PragmaString = "unroll";
- }
- PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
- << PragmaString << "a positive integer value";
- return true;
+ SmallVector<Token, 1> ValueList;
+ int OpenParens = ValueInParens ? 1 : 0;
+ // Read constant expression.
+ while (Tok.isNot(tok::eod)) {
+ if (Tok.is(tok::l_paren))
+ OpenParens++;
+ else if (Tok.is(tok::r_paren)) {
+ OpenParens--;
+ if (OpenParens == 0 && ValueInParens)
+ break;
}
- }
- // FIXME: Value should be stored and parsed as a constant expression.
- Token Value = Tok;
+ ValueList.push_back(Tok);
+ PP.Lex(Tok);
+ }
if (ValueInParens) {
- PP.Lex(Tok);
+ // Read ')'
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
return true;
}
+ PP.Lex(Tok);
}
+ Token EOFTok;
+ EOFTok.startToken();
+ EOFTok.setKind(tok::eof);
+ EOFTok.setLocation(Tok.getLocation());
+ ValueList.push_back(EOFTok); // Terminates expression for parsing.
+
+ Token *TokenArray = (Token *)PP.getPreprocessorAllocator().Allocate(
+ ValueList.size() * sizeof(Token), llvm::alignOf<Token>());
+ std::copy(ValueList.begin(), ValueList.end(), TokenArray);
+ Info.Toks = TokenArray;
+ Info.TokSize = ValueList.size();
+
Info.PragmaName = PragmaName;
Info.Option = Option;
- Info.Value = Value;
- Info.HasValue = true;
return false;
}
@@ -1806,7 +1912,7 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
/// loop-hint:
/// 'vectorize' '(' loop-hint-keyword ')'
/// 'interleave' '(' loop-hint-keyword ')'
-/// 'unroll' '(' loop-hint-keyword ')'
+/// 'unroll' '(' unroll-hint-keyword ')'
/// 'vectorize_width' '(' loop-hint-value ')'
/// 'interleave_count' '(' loop-hint-value ')'
/// 'unroll_count' '(' loop-hint-value ')'
@@ -1815,6 +1921,10 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
/// 'enable'
/// 'disable'
///
+/// unroll-hint-keyword:
+/// 'full'
+/// 'disable'
+///
/// loop-hint-value:
/// constant-expression
///
@@ -1829,12 +1939,10 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
/// only works on inner loops.
///
/// The unroll and unroll_count directives control the concatenation
-/// unroller. Specifying unroll(enable) instructs llvm to try to
+/// unroller. Specifying unroll(full) instructs llvm to try to
/// unroll the loop completely, and unroll(disable) disables unrolling
/// for the loop. Specifying unroll_count(_value_) instructs llvm to
/// try to unroll the loop the number of times indicated by the value.
-/// If unroll(enable) and unroll_count are both specified only
-/// unroll_count takes effect.
void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
@@ -1867,17 +1975,19 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
<< /*MissingOption=*/false << OptionInfo;
return;
}
-
- auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
PP.Lex(Tok);
- bool ValueInParens;
- if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info))
- return;
- if (!ValueInParens) {
- PP.Diag(Info->Value.getLocation(), diag::err_expected) << tok::l_paren;
+ // Read '('
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
return;
}
+ PP.Lex(Tok);
+
+ auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
+ if (ParseLoopHintValue(PP, Tok, PragmaName, Option, /*ValueInParens=*/true,
+ *Info))
+ return;
// Generate the loop hint token.
Token LoopHintTok;
@@ -1886,9 +1996,6 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
LoopHintTok.setLocation(PragmaName.getLocation());
LoopHintTok.setAnnotationValue(static_cast<void *>(Info));
TokenList.push_back(LoopHintTok);
-
- // Get next optimization option.
- PP.Lex(Tok);
}
if (Tok.isNot(tok::eod)) {
@@ -1909,44 +2016,54 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
/// #pragma unroll
/// #pragma unroll unroll-hint-value
/// #pragma unroll '(' unroll-hint-value ')'
+/// #pragma nounroll
///
/// unroll-hint-value:
/// constant-expression
///
-/// Loop unrolling hints are specified with '#pragma unroll'. '#pragma unroll'
-/// can take a numeric argument optionally contained in parentheses. With no
-/// argument the directive instructs llvm to try to unroll the loop
-/// completely. A positive integer argument can be specified to indicate the
-/// number of times the loop should be unrolled. To maximize compatibility with
-/// other compilers the unroll count argument can be specified with or without
-/// parentheses.
+/// Loop unrolling hints can be specified with '#pragma unroll' or
+/// '#pragma nounroll'. '#pragma unroll' can take a numeric argument optionally
+/// contained in parentheses. With no argument the directive instructs llvm to
+/// try to unroll the loop completely. A positive integer argument can be
+/// specified to indicate the number of times the loop should be unrolled. To
+/// maximize compatibility with other compilers the unroll count argument can be
+/// specified with or without parentheses. Specifying, '#pragma nounroll'
+/// disables unrolling of the loop.
void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
- // Incoming token is "unroll" of "#pragma unroll".
+ // Incoming token is "unroll" for "#pragma unroll", or "nounroll" for
+ // "#pragma nounroll".
Token PragmaName = Tok;
PP.Lex(Tok);
auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
if (Tok.is(tok::eod)) {
- // Unroll pragma without an argument.
+ // nounroll or unroll pragma without an argument.
Info->PragmaName = PragmaName;
- Info->Option = PragmaName;
- Info->HasValue = false;
+ Info->Option.startToken();
+ } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll") {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "nounroll";
+ return;
} else {
// Unroll pragma with an argument: "#pragma unroll N" or
// "#pragma unroll(N)".
- bool ValueInParens;
- if (ParseLoopHintValue(PP, Tok, PragmaName, PragmaName, ValueInParens,
- *Info))
+ // Read '(' if it exists.
+ bool ValueInParens = Tok.is(tok::l_paren);
+ if (ValueInParens)
+ PP.Lex(Tok);
+
+ Token Option;
+ Option.startToken();
+ if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info))
return;
// In CUDA, the argument to '#pragma unroll' should not be contained in
// parentheses.
if (PP.getLangOpts().CUDA && ValueInParens)
- PP.Diag(Info->Value.getLocation(),
+ PP.Diag(Info->Toks[0].getLocation(),
diag::warn_pragma_unroll_cuda_value_in_parens);
- PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "unroll";
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index ec0ca6b1fdd6..2a5f8406a50c 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -185,9 +185,9 @@ Retry:
if (Next.isNot(tok::coloncolon)) {
// Try to limit which sets of keywords should be included in typo
// correction based on what the next token is.
- StatementFilterCCC Validator(Next);
- if (TryAnnotateName(/*IsAddressOfOperand*/false, &Validator)
- == ANK_Error) {
+ if (TryAnnotateName(/*IsAddressOfOperand*/ false,
+ llvm::make_unique<StatementFilterCCC>(Next)) ==
+ ANK_Error) {
// Handle errors here by skipping up to the next semicolon or '}', and
// eat the semicolon if that's what stopped us.
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
@@ -207,7 +207,7 @@ Retry:
default: {
if ((getLangOpts().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext,
+ DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext,
DeclEnd, Attrs);
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
}
@@ -424,27 +424,11 @@ StmtResult Parser::ParseSEHTryBlock() {
/// seh-finally-block
///
StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
- if (Tok.isNot(tok::l_brace))
+ if(Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- int SEHTryIndex, SEHTryParentIndex;
- StmtResult TryBlock;
- {
- assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
-
- // Enter a scope to hold everything within the compound stmt. Compound
- // statements can always hold declarations.
- ParseScope CompoundScope(this, Scope::DeclScope | Scope::SEHTryScope);
- SEHTryIndex = getCurScope()->getSEHTryIndex();
- SEHTryParentIndex = getCurScope()->getSEHTryParentIndex();
-
- // Parse the statements in the body.
- TryBlock = ParseCompoundStatementBody();
- }
-
- //StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
- // Scope::DeclScope | Scope::SEHTryScope));
-
+ StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
+ Scope::DeclScope | Scope::SEHTryScope));
if(TryBlock.isInvalid())
return TryBlock;
@@ -466,9 +450,7 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
return Actions.ActOnSEHTryBlock(false /* IsCXXTry */,
TryLoc,
TryBlock.get(),
- Handler.get(),
- SEHTryIndex,
- SEHTryParentIndex);
+ Handler.get());
}
/// ParseSEHExceptBlock - Handle __except
@@ -660,6 +642,11 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
ExprResult LHS;
if (!MissingCase) {
LHS = ParseConstantExpression();
+ if (!getLangOpts().CPlusPlus11) {
+ LHS = Actions.CorrectDelayedTyposInExpr(LHS, [this](class Expr *E) {
+ return Actions.VerifyIntegerConstantExpression(E);
+ });
+ }
if (LHS.isInvalid()) {
// If constant-expression is parsed unsuccessfully, recover by skipping
// current case statement (moving to the colon that ends it).
@@ -974,8 +961,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
ExtensionRAIIObject O(Diags);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Res = ParseDeclaration(Stmts,
- Declarator::BlockContext, DeclEnd,
+ DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext, DeclEnd,
attrs);
R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
} else {
@@ -1534,9 +1520,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
else
ForRangeInit.RangeExpr = ParseExpression();
- Diag(Loc, getLangOpts().CPlusPlus1z
- ? diag::warn_cxx1y_compat_for_range_identifier
- : diag::ext_for_range_identifier)
+ Diag(Loc, diag::err_for_range_identifier)
<< ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus1z)
? FixItHint::CreateInsertion(Loc, "auto &&")
: FixItHint());
@@ -1554,9 +1538,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- StmtVector Stmts;
DeclGroupPtrTy DG = ParseSimpleDeclaration(
- Stmts, Declarator::ForContext, DeclEnd, attrs, false,
+ Declarator::ForContext, DeclEnd, attrs, false,
MightBeForRangeStmt ? &ForRangeInit : nullptr);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (ForRangeInit.ParsedForRangeDecl()) {
@@ -1582,7 +1565,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
}
} else {
ProhibitAttributes(attrs);
- Value = ParseExpression();
+ Value = Actions.CorrectDelayedTyposInExpr(ParseExpression());
ForEach = isTokIdentifier_in();
@@ -1818,7 +1801,7 @@ StmtResult Parser::ParseReturnStatement() {
diag::ext_generalized_initializer_lists)
<< R.get()->getSourceRange();
} else
- R = ParseExpression();
+ R = ParseExpression();
if (R.isInvalid()) {
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
return StmtError();
@@ -1835,10 +1818,11 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
// Get loop hints and consume annotated token.
while (Tok.is(tok::annot_pragma_loop_hint)) {
- LoopHint Hint = HandlePragmaLoopHint();
- ConsumeToken();
+ LoopHint Hint;
+ if (!HandlePragmaLoopHint(Hint))
+ continue;
- ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.ValueLoc,
+ ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.StateLoc,
ArgsUnion(Hint.ValueExpr)};
TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr,
Hint.PragmaNameLoc->Loc, ArgHints, 4,
@@ -1975,23 +1959,10 @@ StmtResult Parser::ParseCXXTryBlock() {
StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- // FIXME: Possible draft standard bug: attribute-specifier should be allowed?
- int SEHTryIndex, SEHTryParentIndex;
- StmtResult TryBlock;
- {
- assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
-
- // Enter a scope to hold everything within the compound stmt. Compound
- // statements can always hold declarations.
- ParseScope CompoundScope(this, Scope::DeclScope | Scope::TryScope |
- (FnTry ? Scope::FnTryCatchScope : 0));
- SEHTryIndex = getCurScope()->getSEHTryIndex();
- SEHTryParentIndex = getCurScope()->getSEHTryParentIndex();
-
- // Parse the statements in the body.
- TryBlock = ParseCompoundStatementBody();
- }
+ StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
+ Scope::DeclScope | Scope::TryScope |
+ (FnTry ? Scope::FnTryCatchScope : 0)));
if (TryBlock.isInvalid())
return TryBlock;
@@ -2016,9 +1987,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
return Actions.ActOnSEHTryBlock(true /* IsCXXTry */,
TryLoc,
TryBlock.get(),
- Handler.get(),
- SEHTryIndex,
- SEHTryParentIndex);
+ Handler.get());
}
else {
StmtVector Handlers;
diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp
index f7e8307883de..7bf4da6d1bd4 100644
--- a/lib/Parse/ParseStmtAsm.cpp
+++ b/lib/Parse/ParseStmtAsm.cpp
@@ -93,6 +93,15 @@ public:
return Info.OpDecl;
}
+ StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM,
+ llvm::SMLoc Location,
+ bool Create) override {
+ SourceLocation Loc = translateLocation(LSM, Location);
+ LabelDecl *Label =
+ TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create);
+ return Label->getMSAsmLabel();
+ }
+
bool LookupInlineAsmField(StringRef Base, StringRef Member,
unsigned &Offset) override {
return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset,
@@ -133,14 +142,13 @@ private:
}
}
- void handleDiagnostic(const llvm::SMDiagnostic &D) {
+ SourceLocation translateLocation(const llvm::SourceMgr &LSM, llvm::SMLoc SMLoc) {
// Compute an offset into the inline asm buffer.
// FIXME: This isn't right if .macro is involved (but hopefully, no
// real-world code does that).
- const llvm::SourceMgr &LSM = *D.getSourceMgr();
const llvm::MemoryBuffer *LBuf =
- LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
- unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
+ LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
+ unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();
// Figure out which token that offset points into.
const unsigned *TokOffsetPtr =
@@ -157,6 +165,12 @@ private:
Loc = Tok.getLocation();
Loc = Loc.getLocWithOffset(Offset - TokOffset);
}
+ return Loc;
+ }
+
+ void handleDiagnostic(const llvm::SMDiagnostic &D) {
+ const llvm::SourceMgr &LSM = *D.getSourceMgr();
+ SourceLocation Loc = translateLocation(LSM, D.getLoc());
TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
}
};
@@ -322,6 +336,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
SourceLocation EndLoc = AsmLoc;
SmallVector<Token, 4> AsmToks;
+ bool SingleLineMode = true;
unsigned BraceNesting = 0;
unsigned short savedBraceCount = BraceCount;
bool InAsmComment = false;
@@ -333,6 +348,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
if (Tok.is(tok::l_brace)) {
// Braced inline asm: consume the opening brace.
+ SingleLineMode = false;
BraceNesting = 1;
EndLoc = ConsumeBrace();
LBraceLocs.push_back(EndLoc);
@@ -364,30 +380,39 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
} else if (!InAsmComment && Tok.is(tok::semi)) {
// A semicolon in an asm is the start of a comment.
InAsmComment = true;
- if (BraceNesting) {
+ if (!SingleLineMode) {
// Compute which line the comment is on.
std::pair<FileID, unsigned> ExpSemiLoc =
SrcMgr.getDecomposedExpansionLoc(TokLoc);
FID = ExpSemiLoc.first;
LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
}
- } else if (!BraceNesting || InAsmComment) {
+ } else if (SingleLineMode || InAsmComment) {
// If end-of-line is significant, check whether this token is on a
// new line.
std::pair<FileID, unsigned> ExpLoc =
SrcMgr.getDecomposedExpansionLoc(TokLoc);
if (ExpLoc.first != FID ||
SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
- // If this is a single-line __asm, we're done.
- if (!BraceNesting)
+ // If this is a single-line __asm, we're done, except if the next
+ // line begins with an __asm too, in which case we finish a comment
+ // if needed and then keep processing the next line as a single
+ // line __asm.
+ bool isAsm = Tok.is(tok::kw_asm);
+ if (SingleLineMode && !isAsm)
break;
// We're no longer in a comment.
InAsmComment = false;
+ if (isAsm) {
+ LineNo = SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second);
+ SkippedStartOfLine = Tok.isAtStartOfLine();
+ }
} else if (!InAsmComment && Tok.is(tok::r_brace)) {
- // Single-line asm always ends when a closing brace is seen.
- // FIXME: This is compatible with Apple gcc's -fasm-blocks; what
- // does MSVC do here?
- break;
+ // In MSVC mode, braces only participate in brace matching and
+ // separating the asm statements. This is an intentional
+ // departure from the Apple gcc behavior.
+ if (!BraceNesting)
+ break;
}
}
if (!InAsmComment && BraceNesting && Tok.is(tok::r_brace) &&
@@ -398,7 +423,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
BraceNesting--;
// Finish if all of the opened braces in the inline asm section were
// consumed.
- if (BraceNesting == 0)
+ if (BraceNesting == 0 && !SingleLineMode)
break;
else {
LBraceLocs.pop_back();
@@ -487,11 +512,13 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
llvm::SourceMgr TempSrcMgr;
llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
- llvm::MemoryBuffer *Buffer =
+ MOFI->InitMCObjectFileInfo(TT, llvm::Reloc::Default, llvm::CodeModel::Default,
+ Ctx);
+ std::unique_ptr<llvm::MemoryBuffer> Buffer =
llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
// Tell SrcMgr about this buffer, which is what the parser will pick up.
- TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
+ TempSrcMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc());
std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
std::unique_ptr<llvm::MCAsmParser> Parser(
@@ -590,7 +617,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
DeclSpec DS(AttrFactory);
SourceLocation Loc = Tok.getLocation();
- ParseTypeQualifierListOpt(DS, true, false);
+ ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed);
// GNU asms accept, but warn, about type-qualifiers other than volatile.
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
@@ -747,7 +774,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
// Read the parenthesized expression.
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- ExprResult Res(ParseExpression());
+ ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
T.consumeClose();
if (Res.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index fa6401f083a6..53de72cd3cc5 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -166,6 +166,14 @@ Parser::ParseSingleDeclarationAfterTemplate(
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
"Template information required");
+ if (Tok.is(tok::kw_static_assert)) {
+ // A static_assert declaration may not be templated.
+ Diag(Tok.getLocation(), diag::err_templated_invalid_declaration)
+ << TemplateInfo.getSourceRange();
+ // Parse the static_assert declaration to improve error recovery.
+ return ParseStaticAssertDeclaration(DeclEnd);
+ }
+
if (Context == Declarator::MemberContext) {
// We are parsing a member template.
ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
@@ -223,6 +231,16 @@ Parser::ParseSingleDeclarationAfterTemplate(
if (DeclaratorInfo.isFunctionDeclarator() &&
isStartOfFunctionDefinition(DeclaratorInfo)) {
+
+ // Function definitions are only allowed at file scope and in C++ classes.
+ // The C++ inline method definition case is handled elsewhere, so we only
+ // need to handle the file scope definition case.
+ if (Context != Declarator::FileContext) {
+ Diag(Tok, diag::err_function_definition_not_allowed);
+ SkipMalformedDecl();
+ return nullptr;
+ }
+
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
// Recover by ignoring the 'typedef'. This was probably supposed to be
// the 'typename' keyword, which we should have already suggested adding
@@ -553,7 +571,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
if (Tok.is(tok::kw_typename)) {
Diag(Tok.getLocation(),
getLangOpts().CPlusPlus1z
- ? diag::warn_cxx1y_compat_template_template_param_typename
+ ? diag::warn_cxx14_compat_template_template_param_typename
: diag::ext_template_template_param_typename)
<< (!getLangOpts().CPlusPlus1z
? FixItHint::CreateReplacement(Tok.getLocation(), "class")
@@ -668,7 +686,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
- DefaultArg = ParseAssignmentExpression();
+ DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (DefaultArg.isInvalid())
SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
}
@@ -1327,7 +1345,8 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
// Recreate the containing function DeclContext.
- Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FunD));
+ Sema::ContextRAII FunctionSavedContext(Actions,
+ Actions.getContainingDC(FunD));
Actions.ActOnStartOfFunctionDef(getCurScope(), FunD);
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 8514af2a8c89..abf16fa6222b 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -195,7 +195,9 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
}
}
- if (TryAnnotateCXXScopeToken())
+ if ((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) &&
+ TryAnnotateCXXScopeToken())
return TPResult::Error;
if (Tok.is(tok::annot_cxxscope))
ConsumeToken();
@@ -837,6 +839,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
Tok.is(tok::kw___stdcall) ||
Tok.is(tok::kw___fastcall) ||
Tok.is(tok::kw___thiscall) ||
+ Tok.is(tok::kw___vectorcall) ||
Tok.is(tok::kw___unaligned))
return TPResult::True; // attributes indicate declaration
TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
@@ -891,6 +894,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::numeric_constant:
case tok::char_constant:
case tok::wide_char_constant:
+ case tok::utf8_char_constant:
case tok::utf16_char_constant:
case tok::utf32_char_constant:
case tok::string_literal:
@@ -984,9 +988,11 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___unaligned:
case tok::kw___vector:
case tok::kw___pixel:
+ case tok::kw___bool:
case tok::kw__Atomic:
case tok::kw___unknown_anytype:
return TPResult::False;
@@ -1004,6 +1010,28 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) {
!= TentativelyDeclaredIdentifiers.end();
}
+namespace {
+class TentativeParseCCC : public CorrectionCandidateCallback {
+public:
+ TentativeParseCCC(const Token &Next) {
+ WantRemainingKeywords = false;
+ WantTypeSpecifiers = Next.is(tok::l_paren) || Next.is(tok::r_paren) ||
+ Next.is(tok::greater) || Next.is(tok::l_brace) ||
+ Next.is(tok::identifier);
+ }
+
+ bool ValidateCandidate(const TypoCorrection &Candidate) override {
+ // Reject any candidate that only resolves to instance members since they
+ // aren't viable as standalone identifiers instead of member references.
+ if (Candidate.isResolved() && !Candidate.isKeyword() &&
+ std::all_of(Candidate.begin(), Candidate.end(),
+ [](NamedDecl *ND) { return ND->isCXXInstanceMember(); }))
+ return false;
+
+ return CorrectionCandidateCallback::ValidateCandidate(Candidate);
+ }
+};
+}
/// isCXXDeclarationSpecifier - Returns TPResult::True if it is a declaration
/// specifier, TPResult::False if it is not, TPResult::Ambiguous if it could
/// be either a decl-specifier or a function-style cast, and TPResult::Error
@@ -1129,11 +1157,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// a parse error one way or another. In that case, tell the caller that
// this is ambiguous. Typo-correct to type and expression keywords and
// to types and identifiers, in order to try to recover from errors.
- CorrectionCandidateCallback TypoCorrection;
- TypoCorrection.WantRemainingKeywords = false;
- TypoCorrection.WantTypeSpecifiers = Next.isNot(tok::arrow);
switch (TryAnnotateName(false /* no nested name specifier */,
- &TypoCorrection)) {
+ llvm::make_unique<TentativeParseCCC>(Next))) {
case ANK_Error:
return TPResult::Error;
case ANK_TentativeDecl:
@@ -1181,6 +1206,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
return TPResult::False;
}
// Fall through.
+ case tok::kw___super:
case tok::kw_decltype:
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
@@ -1250,6 +1276,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___vectorcall:
case tok::kw___w64:
case tok::kw___sptr:
case tok::kw___uptr:
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 37ce157e0812..7ccd2092a2d7 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -510,6 +510,13 @@ namespace {
};
}
+void Parser::LateTemplateParserCleanupCallback(void *P) {
+ // While this RAII helper doesn't bracket any actual work, the destructor will
+ // clean up annotations that were created during ActOnEndOfTranslationUnit
+ // when incremental processing is enabled.
+ DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(((Parser *)P)->TemplateIds);
+}
+
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
/// action tells us to. This returns true if the EOF was encountered.
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
@@ -542,7 +549,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
case tok::eof:
// Late template parsing can begin.
if (getLangOpts().DelayedTemplateParsing)
- Actions.SetLateTemplateParser(LateTemplateParserCallback, this);
+ Actions.SetLateTemplateParser(LateTemplateParserCallback,
+ PP.isIncrementalProcessingEnabled() ?
+ LateTemplateParserCleanupCallback : nullptr,
+ this);
if (!PP.isIncrementalProcessingEnabled())
Actions.ActOnEndOfTranslationUnit();
//else don't tell Sema that we ended parsing: more input might come.
@@ -624,8 +634,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
HandlePragmaOpenCLExtension();
return DeclGroupPtrTy();
case tok::annot_pragma_openmp:
- ParseOpenMPDeclarativeDirective();
- return DeclGroupPtrTy();
+ return ParseOpenMPDeclarativeDirective();
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
return DeclGroupPtrTy();
@@ -697,8 +706,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// A function definition cannot start with any of these keywords.
{
SourceLocation DeclEnd;
- StmtVector Stmts;
- return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
+ return ParseDeclaration(Declarator::FileContext, DeclEnd, attrs);
}
case tok::kw_static:
@@ -708,8 +716,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 0;
SourceLocation DeclEnd;
- StmtVector Stmts;
- return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
+ return ParseDeclaration(Declarator::FileContext, DeclEnd, attrs);
}
goto dont_know;
@@ -720,8 +727,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// Inline namespaces. Allowed as an extension even in C++03.
if (NextKind == tok::kw_namespace) {
SourceLocation DeclEnd;
- StmtVector Stmts;
- return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
+ return ParseDeclaration(Declarator::FileContext, DeclEnd, attrs);
}
// Parse (then ignore) 'inline' prior to a template instantiation. This is
@@ -730,8 +736,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 1;
SourceLocation DeclEnd;
- StmtVector Stmts;
- return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
+ return ParseDeclaration(Declarator::FileContext, DeclEnd, attrs);
}
}
goto dont_know;
@@ -885,7 +890,7 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- return ParseDeclGroup(DS, Declarator::FileContext, true);
+ return ParseDeclGroup(DS, Declarator::FileContext);
}
Parser::DeclGroupPtrTy
@@ -922,7 +927,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs,
Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
LateParsedAttrList *LateParsedAttrs) {
- // Poison the SEH identifiers so they are flagged as illegal in function bodies
+ // Poison SEH identifiers so they are flagged as illegal in function bodies.
PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
@@ -1218,27 +1223,24 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
/// [GNU] asm-string-literal:
/// string-literal
///
-Parser::ExprResult Parser::ParseAsmStringLiteral() {
- switch (Tok.getKind()) {
- case tok::string_literal:
- break;
- case tok::utf8_string_literal:
- case tok::utf16_string_literal:
- case tok::utf32_string_literal:
- case tok::wide_string_literal: {
- SourceLocation L = Tok.getLocation();
+ExprResult Parser::ParseAsmStringLiteral() {
+ if (!isTokenStringLiteral()) {
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*Source='in...'*/0 << "'asm'";
+ return ExprError();
+ }
+
+ ExprResult AsmString(ParseStringLiteralExpression());
+ if (!AsmString.isInvalid()) {
+ const auto *SL = cast<StringLiteral>(AsmString.get());
+ if (!SL->isAscii()) {
Diag(Tok, diag::err_asm_operand_wide_string_literal)
- << (Tok.getKind() == tok::wide_string_literal)
- << SourceRange(L, L);
+ << SL->isWide()
+ << SL->getSourceRange();
return ExprError();
}
- default:
- Diag(Tok, diag::err_expected_string_literal)
- << /*Source='in...'*/0 << "'asm'";
- return ExprError();
}
-
- return ParseStringLiteralExpression();
+ return AsmString;
}
/// ParseSimpleAsm
@@ -1246,7 +1248,7 @@ Parser::ExprResult Parser::ParseAsmStringLiteral() {
/// [GNU] simple-asm-expr:
/// 'asm' '(' asm-string-literal ')'
///
-Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
+ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
assert(Tok.is(tok::kw_asm) && "Not an asm!");
SourceLocation Loc = ConsumeToken();
@@ -1321,7 +1323,7 @@ void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) {
/// no typo correction will be performed.
Parser::AnnotatedNameKind
Parser::TryAnnotateName(bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC) {
+ std::unique_ptr<CorrectionCandidateCallback> CCC) {
assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
const bool EnteringContext = false;
@@ -1359,9 +1361,9 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
// after a scope specifier, because in general we can't recover from typos
// there (eg, after correcting 'A::tempalte B<X>::C' [sic], we would need to
// jump back into scope specifier parsing).
- Sema::NameClassification Classification
- = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next,
- IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);
+ Sema::NameClassification Classification = Actions.ClassifyName(
+ getCurScope(), SS, Name, NameLoc, Next, IsAddressOfOperand,
+ SS.isEmpty() ? std::move(CCC) : nullptr);
switch (Classification.getKind()) {
case Sema::NC_Error:
@@ -1431,34 +1433,16 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
}
bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
- assert(!Tok.is(tok::identifier) && !Tok.isAnnotation());
+ assert(Tok.isNot(tok::identifier));
Diag(Tok, diag::ext_keyword_as_ident)
<< PP.getSpelling(Tok)
<< DisableKeyword;
- if (DisableKeyword) {
- IdentifierInfo *II = Tok.getIdentifierInfo();
- ContextualKeywords[II] = Tok.getKind();
- II->RevertTokenIDToIdentifier();
- }
+ if (DisableKeyword)
+ Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
Tok.setKind(tok::identifier);
return true;
}
-bool Parser::TryIdentKeywordUpgrade() {
- assert(Tok.is(tok::identifier));
- const IdentifierInfo *II = Tok.getIdentifierInfo();
- assert(II->hasRevertedTokenIDToIdentifier());
- // If we find that this is in fact the name of a type trait,
- // update the token kind in place and parse again to treat it as
- // the appropriate kind of type trait.
- llvm::SmallDenseMap<const IdentifierInfo *, tok::TokenKind>::iterator Known =
- ContextualKeywords.find(II);
- if (Known == ContextualKeywords.end())
- return false;
- Tok.setKind(Known->second);
- return true;
-}
-
/// TryAnnotateTypeOrScopeToken - If the current token position is on a
/// typename (possibly qualified in C++) or a C++ scope specifier not followed
/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
@@ -1482,10 +1466,11 @@ bool Parser::TryIdentKeywordUpgrade() {
/// Note that this routine emits an error if you call it with ::new or ::delete
/// as the current tokens, so only call it in contexts where these are invalid.
bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
- assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)
- || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)
- || Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id))
- && "Cannot be a type or scope token!");
+ assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) ||
+ Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) ||
+ Tok.is(tok::kw___super)) &&
+ "Cannot be a type or scope token!");
if (Tok.is(tok::kw_typename)) {
// MSVC lets you do stuff like:
@@ -1694,7 +1679,8 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
"Call sites of this function should be guarded by checking for C++");
assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
(Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) ||
- Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!");
+ Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super)) &&
+ "Cannot be a type or scope token!");
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
@@ -1739,7 +1725,8 @@ SourceLocation Parser::handleUnexpectedCodeCompletionToken() {
for (Scope *S = getCurScope(); S; S = S->getParent()) {
if (S->getFlags() & Scope::FnScope) {
- Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_RecoveryInFunction);
+ Actions.CodeCompleteOrdinaryName(getCurScope(),
+ Sema::PCC_RecoveryInFunction);
cutOffParsing();
return PrevTokLocation;
}
@@ -1756,13 +1743,6 @@ SourceLocation Parser::handleUnexpectedCodeCompletionToken() {
return PrevTokLocation;
}
-// Anchor the Parser::FieldCallback vtable to this translation unit.
-// We use a spurious method instead of the destructor because
-// destroying FieldCallbacks can actually be slightly
-// performance-sensitive.
-void Parser::FieldCallback::_anchor() {
-}
-
// Code-completion pass-through functions
void Parser::CodeCompleteDirective(bool InConditional) {
@@ -1784,7 +1764,7 @@ void Parser::CodeCompletePreprocessorExpression() {
void Parser::CodeCompleteMacroArgument(IdentifierInfo *Macro,
MacroInfo *MacroInfo,
unsigned ArgumentIndex) {
- Actions.CodeCompletePreprocessorMacroArgument(getCurScope(), Macro, MacroInfo,
+ Actions.CodeCompletePreprocessorMacroArgument(getCurScope(), Macro, MacroInfo,
ArgumentIndex);
}
@@ -1806,8 +1786,9 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) {
}
// Parse nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(Result.SS, ParsedType(),
- /*EnteringContext=*/false);
+ if (getLangOpts().CPlusPlus)
+ ParseOptionalCXXScopeSpecifier(Result.SS, ParsedType(),
+ /*EnteringContext=*/false);
// Check nested-name specifier.
if (Result.SS.isInvalid()) {
@@ -1828,7 +1809,7 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) {
// Check if the symbol exists.
switch (Actions.CheckMicrosoftIfExistsSymbol(getCurScope(), Result.KeywordLoc,
- Result.IsIfExists, Result.SS,
+ Result.IsIfExists, Result.SS,
Result.Name)) {
case Sema::IER_Exists:
Result.Behavior = Result.IsIfExists ? IEB_Parse : IEB_Skip;
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 4f5f3ab81036..a0c9c1fb6c6f 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H
-#define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H
+#ifndef LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H
+#define LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt
index 0c77536012aa..16550b1b710e 100644
--- a/lib/Rewrite/CMakeLists.txt
+++ b/lib/Rewrite/CMakeLists.txt
@@ -10,7 +10,6 @@ add_clang_library(clangRewrite
TokenRewriter.cpp
LINK_LIBS
- clangAST
clangBasic
clangLex
)
diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/RewriteRope.cpp
index ef8abfcadc03..1c82ee4a67ec 100644
--- a/lib/Rewrite/RewriteRope.cpp
+++ b/lib/Rewrite/RewriteRope.cpp
@@ -788,18 +788,14 @@ RopePiece RewriteRope::MakeRopeString(const char *Start, const char *End) {
// Otherwise, this was a small request but we just don't have space for it
// Make a new chunk and share it with later allocations.
- if (AllocBuffer)
- AllocBuffer->dropRef();
-
unsigned AllocSize = offsetof(RopeRefCountString, Data) + AllocChunkSize;
- AllocBuffer = reinterpret_cast<RopeRefCountString *>(new char[AllocSize]);
- AllocBuffer->RefCount = 0;
- memcpy(AllocBuffer->Data, Start, Len);
+ RopeRefCountString *Res =
+ reinterpret_cast<RopeRefCountString *>(new char[AllocSize]);
+ Res->RefCount = 0;
+ memcpy(Res->Data, Start, Len);
+ AllocBuffer = Res;
AllocOffs = Len;
- // Start out the new allocation with a refcount of 1, since we have an
- // internal reference to it.
- AllocBuffer->addRef();
return RopePiece(AllocBuffer, 0, Len);
}
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index eab4ccfeadc3..60cdcf703172 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -13,9 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/Stmt.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
@@ -328,35 +326,6 @@ bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) {
return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
}
-/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
-/// printer to generate the replacement code. This returns true if the input
-/// could not be rewritten, or false if successful.
-bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
- assert(From != nullptr && To != nullptr && "Expected non-null Stmt's");
-
- // Measaure the old text.
- int Size = getRangeSize(From->getSourceRange());
- if (Size == -1)
- return true;
-
- // Get the new text.
- std::string SStr;
- llvm::raw_string_ostream S(SStr);
- To->printPretty(S, nullptr, PrintingPolicy(*LangOpts));
- const std::string &Str = S.str();
-
- ReplaceText(From->getLocStart(), Size, Str);
- return false;
-}
-
-std::string Rewriter::ConvertToString(Stmt *From) {
- assert(From != nullptr && "Expected non-null Stmt");
- std::string SStr;
- llvm::raw_string_ostream S(SStr);
- From->printPretty(S, nullptr, PrintingPolicy(*LangOpts));
- return S.str();
-}
-
bool Rewriter::IncreaseIndentation(CharSourceRange range,
SourceLocation parentIndent) {
if (range.isInvalid()) return true;
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 213d6fbffffc..f666a9b46384 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -530,44 +530,37 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
return;
- // FIXME: Function try block
- if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(AC)) {
- case UnknownFallThrough:
- break;
+ SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd();
+ // Either in a function body compound statement, or a function-try-block.
+ switch (CheckFallThrough(AC)) {
+ case UnknownFallThrough:
+ break;
- case MaybeFallThrough:
- if (HasNoReturn)
- S.Diag(Compound->getRBracLoc(),
- CD.diag_MaybeFallThrough_HasNoReturn);
- else if (!ReturnsVoid)
- S.Diag(Compound->getRBracLoc(),
- CD.diag_MaybeFallThrough_ReturnsNonVoid);
- break;
- case AlwaysFallThrough:
- if (HasNoReturn)
- S.Diag(Compound->getRBracLoc(),
- CD.diag_AlwaysFallThrough_HasNoReturn);
- else if (!ReturnsVoid)
- S.Diag(Compound->getRBracLoc(),
- CD.diag_AlwaysFallThrough_ReturnsNonVoid);
- break;
- case NeverFallThroughOrReturn:
- if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn)
- << 0 << FD;
- } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn)
- << 1 << MD;
- } else {
- S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn);
- }
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ S.Diag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
+ else if (!ReturnsVoid)
+ S.Diag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ S.Diag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
+ else if (!ReturnsVoid)
+ S.Diag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
+ break;
+ case NeverFallThroughOrReturn:
+ if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
+ } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
+ } else {
+ S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
}
- break;
- case NeverFallThrough:
- break;
- }
+ }
+ break;
+ case NeverFallThrough:
+ break;
}
}
@@ -923,7 +916,7 @@ namespace {
// issue a warn_fallthrough_attr_unreachable for them.
for (const auto *B : *Cfg) {
const Stmt *L = B->getLabel();
- if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B))
+ if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B).second)
BlockQueue.push_back(B);
}
@@ -933,7 +926,7 @@ namespace {
for (CFGBlock::const_succ_iterator I = P->succ_begin(),
E = P->succ_end();
I != E; ++I) {
- if (*I && ReachableBlocks.insert(*I))
+ if (*I && ReachableBlocks.insert(*I).second)
BlockQueue.push_back(*I);
}
}
@@ -1444,13 +1437,51 @@ struct SortDiagBySourceLocation {
// -Wthread-safety
//===----------------------------------------------------------------------===//
namespace clang {
-namespace thread_safety {
-namespace {
-class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
+namespace threadSafety {
+
+class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
Sema &S;
DiagList Warnings;
SourceLocation FunLocation, FunEndLocation;
+ const FunctionDecl *CurrentFunction;
+ bool Verbose;
+
+ OptionalNotes getNotes() const {
+ if (Verbose && CurrentFunction) {
+ PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(),
+ S.PDiag(diag::note_thread_warning_in_fun)
+ << CurrentFunction->getNameAsString());
+ return OptionalNotes(1, FNote);
+ }
+ return OptionalNotes();
+ }
+
+ OptionalNotes getNotes(const PartialDiagnosticAt &Note) const {
+ OptionalNotes ONS(1, Note);
+ if (Verbose && CurrentFunction) {
+ PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(),
+ S.PDiag(diag::note_thread_warning_in_fun)
+ << CurrentFunction->getNameAsString());
+ ONS.push_back(FNote);
+ }
+ return ONS;
+ }
+
+ OptionalNotes getNotes(const PartialDiagnosticAt &Note1,
+ const PartialDiagnosticAt &Note2) const {
+ OptionalNotes ONS;
+ ONS.push_back(Note1);
+ ONS.push_back(Note2);
+ if (Verbose && CurrentFunction) {
+ PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(),
+ S.PDiag(diag::note_thread_warning_in_fun)
+ << CurrentFunction->getNameAsString());
+ ONS.push_back(FNote);
+ }
+ return ONS;
+ }
+
// Helper functions
void warnLockMismatch(unsigned DiagID, StringRef Kind, Name LockName,
SourceLocation Loc) {
@@ -1459,12 +1490,15 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
if (!Loc.isValid())
Loc = FunLocation;
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << LockName);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
public:
ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
- : S(S), FunLocation(FL), FunEndLocation(FEL) {}
+ : S(S), FunLocation(FL), FunEndLocation(FEL),
+ CurrentFunction(nullptr), Verbose(false) {}
+
+ void setVerbose(bool b) { Verbose = b; }
/// \brief Emit all buffered diagnostics in order of sourcelocation.
/// We need to output diagnostics produced while iterating through
@@ -1482,12 +1516,14 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock)
<< Loc);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
+
void handleUnmatchedUnlock(StringRef Kind, Name LockName,
SourceLocation Loc) override {
warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc);
}
+
void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
LockKind Expected, LockKind Received,
SourceLocation Loc) override {
@@ -1496,8 +1532,9 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_kind_mismatch)
<< Kind << LockName << Received
<< Expected);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
+
void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc) override {
warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc);
}
@@ -1529,10 +1566,10 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
if (LocLocked.isValid()) {
PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here)
<< Kind);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
+ Warnings.push_back(DelayedDiag(Warning, getNotes(Note)));
return;
}
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
void handleExclusiveAndShared(StringRef Kind, Name LockName,
@@ -1543,7 +1580,7 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
<< Kind << LockName);
PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared)
<< Kind << LockName);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
+ Warnings.push_back(DelayedDiag(Warning, getNotes(Note)));
}
void handleNoMutexHeld(StringRef Kind, const NamedDecl *D,
@@ -1556,7 +1593,7 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
diag::warn_var_deref_requires_any_lock;
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
<< D->getNameAsString() << getLockKindFromAccessKind(AK));
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
void handleMutexNotHeld(StringRef Kind, const NamedDecl *D,
@@ -1575,13 +1612,25 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
case POK_FunctionCall:
DiagID = diag::warn_fun_requires_lock_precise;
break;
+ case POK_PassByRef:
+ DiagID = diag::warn_guarded_pass_by_reference;
+ break;
+ case POK_PtPassByRef:
+ DiagID = diag::warn_pt_guarded_pass_by_reference;
+ break;
}
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
<< D->getNameAsString()
<< LockName << LK);
PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match)
<< *PossibleMatch);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
+ if (Verbose && POK == POK_VarAccess) {
+ PartialDiagnosticAt VNote(D->getLocation(),
+ S.PDiag(diag::note_guarded_by_declared_here)
+ << D->getNameAsString());
+ Warnings.push_back(DelayedDiag(Warning, getNotes(Note, VNote)));
+ } else
+ Warnings.push_back(DelayedDiag(Warning, getNotes(Note)));
} else {
switch (POK) {
case POK_VarAccess:
@@ -1593,22 +1642,52 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
case POK_FunctionCall:
DiagID = diag::warn_fun_requires_lock;
break;
+ case POK_PassByRef:
+ DiagID = diag::warn_guarded_pass_by_reference;
+ break;
+ case POK_PtPassByRef:
+ DiagID = diag::warn_pt_guarded_pass_by_reference;
+ break;
}
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
<< D->getNameAsString()
<< LockName << LK);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ if (Verbose && POK == POK_VarAccess) {
+ PartialDiagnosticAt Note(D->getLocation(),
+ S.PDiag(diag::note_guarded_by_declared_here)
+ << D->getNameAsString());
+ Warnings.push_back(DelayedDiag(Warning, getNotes(Note)));
+ } else
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
}
+
+ virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
+ SourceLocation Loc) override {
+ PartialDiagnosticAt Warning(Loc,
+ S.PDiag(diag::warn_acquire_requires_negative_cap)
+ << Kind << LockName << Neg);
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
+ }
+
+
void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex)
<< Kind << FunName << LockName);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
+ }
+
+ void enterFunction(const FunctionDecl* FD) override {
+ CurrentFunction = FD;
+ }
+
+ void leaveFunction(const FunctionDecl* FD) override {
+ CurrentFunction = 0;
}
};
-}
+
}
}
@@ -1896,11 +1975,13 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (P.enableThreadSafetyAnalysis) {
SourceLocation FL = AC.getDecl()->getLocation();
SourceLocation FEL = AC.getDecl()->getLocEnd();
- thread_safety::ThreadSafetyReporter Reporter(S, FL, FEL);
+ threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getLocStart()))
Reporter.setIssueBetaWarnings(true);
+ if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getLocStart()))
+ Reporter.setVerbose(true);
- thread_safety::runThreadSafetyAnalysis(AC, Reporter);
+ threadSafety::runThreadSafetyAnalysis(AC, Reporter);
Reporter.emitDiagnostics();
}
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 476a22b628ad..34af6cf63c87 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -206,3 +206,11 @@ bool AttributeList::isKnownToGCC() const {
unsigned AttributeList::getSemanticSpelling() const {
return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
}
+
+bool AttributeList::hasVariadicArg() const {
+ // If the attribute has the maximum number of optional arguments, we will
+ // claim that as being variadic. If we someday get an attribute that
+ // legitimately bumps up against that maximum, we can use another bit to track
+ // whether it's truly variadic or not.
+ return getInfo(*this).OptArgs == 15;
+}
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 7847d2c36e5b..4a772d8972a9 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -21,6 +21,7 @@ add_clang_library(clangSema
SemaChecking.cpp
SemaCodeComplete.cpp
SemaConsumer.cpp
+ SemaCUDA.cpp
SemaDecl.cpp
SemaDeclAttr.cpp
SemaDeclCXX.cpp
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index d7372b7a2768..7bf3e51999b6 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
#include "clang/Sema/LocInfoType.h"
@@ -113,6 +114,18 @@ void CXXScopeSpec::MakeGlobal(ASTContext &Context,
"NestedNameSpecifierLoc range computation incorrect");
}
+void CXXScopeSpec::MakeSuper(ASTContext &Context, CXXRecordDecl *RD,
+ SourceLocation SuperLoc,
+ SourceLocation ColonColonLoc) {
+ Builder.MakeSuper(Context, RD, SuperLoc, ColonColonLoc);
+
+ Range.setBegin(SuperLoc);
+ Range.setEnd(ColonColonLoc);
+
+ assert(Range == Builder.getSourceRange() &&
+ "NestedNameSpecifierLoc range computation incorrect");
+}
+
void CXXScopeSpec::MakeTrivial(ASTContext &Context,
NestedNameSpecifier *Qualifier, SourceRange R) {
Builder.MakeTrivial(Context, Qualifier, R);
@@ -159,6 +172,8 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
SourceLocation ConstQualifierLoc,
SourceLocation
VolatileQualifierLoc,
+ SourceLocation
+ RestrictQualifierLoc,
SourceLocation MutableLoc,
ExceptionSpecificationType
ESpecType,
@@ -167,6 +182,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
SourceRange *ExceptionRanges,
unsigned NumExceptions,
Expr *NoexceptExpr,
+ CachedTokens *ExceptionSpecTokens,
SourceLocation LocalRangeBegin,
SourceLocation LocalRangeEnd,
Declarator &TheDeclarator,
@@ -193,6 +209,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding();
I.Fun.ConstQualifierLoc = ConstQualifierLoc.getRawEncoding();
I.Fun.VolatileQualifierLoc = VolatileQualifierLoc.getRawEncoding();
+ I.Fun.RestrictQualifierLoc = RestrictQualifierLoc.getRawEncoding();
I.Fun.MutableLoc = MutableLoc.getRawEncoding();
I.Fun.ExceptionSpecType = ESpecType;
I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding();
@@ -203,6 +220,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
TrailingReturnType.isInvalid();
I.Fun.TrailingReturnType = TrailingReturnType.get();
+ assert(I.Fun.TypeQuals == TypeQuals && "bitfield overflow");
+ assert(I.Fun.ExceptionSpecType == ESpecType && "bitfield overflow");
+
// new[] a parameter array if needed.
if (NumParams) {
// If the 'InlineParams' in Declarator is unused and big enough, put our
@@ -239,6 +259,10 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
case EST_ComputedNoexcept:
I.Fun.NoexceptExpr = NoexceptExpr;
break;
+
+ case EST_Unparsed:
+ I.Fun.ExceptionSpecTokens = ExceptionSpecTokens;
+ break;
}
return I;
}
@@ -484,14 +508,14 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
case SCS_private_extern:
case SCS_static:
if (S.getLangOpts().OpenCLVersion < 120) {
- DiagID = diag::err_not_opencl_storage_class_specifier;
+ DiagID = diag::err_opencl_unknown_type_specifier;
PrevSpec = getSpecifierName(SC);
return true;
}
break;
case SCS_auto:
case SCS_register:
- DiagID = diag::err_not_opencl_storage_class_specifier;
+ DiagID = diag::err_opencl_unknown_type_specifier;
PrevSpec = getSpecifierName(SC);
return true;
default:
@@ -553,12 +577,6 @@ bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
else if (W != TSW_longlong || TypeSpecWidth != TSW_long)
return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID);
TypeSpecWidth = W;
- if (TypeAltiVecVector && !TypeAltiVecBool &&
- ((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
- DiagID = diag::warn_vector_long_decl_spec_combination;
- return true;
- }
return false;
}
@@ -680,11 +698,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
}
TypeSpecType = T;
TypeSpecOwned = false;
- if (TypeAltiVecVector && !TypeAltiVecBool && (TypeSpecType == TST_double)) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
- DiagID = diag::err_invalid_vector_decl_spec;
- return true;
- }
return false;
}
@@ -978,6 +991,16 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP, const PrintingPoli
if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) ||
(TypeSpecWidth != TSW_unspecified))
TypeSpecSign = TSS_unsigned;
+ } else if (TypeSpecType == TST_double) {
+ // vector long double and vector long long double are never allowed.
+ // vector double is OK for Power7 and later.
+ if (TypeSpecWidth == TSW_long || TypeSpecWidth == TSW_longlong)
+ Diag(D, TSWLoc, diag::err_invalid_vector_long_double_decl_spec);
+ else if (!PP.getTargetInfo().hasFeature("vsx"))
+ Diag(D, TSTLoc, diag::err_invalid_vector_double_decl_spec);
+ } else if (TypeSpecWidth == TSW_long) {
+ Diag(D, TSWLoc, diag::warn_vector_long_decl_spec_combination)
+ << getSpecifierName((TST)TypeSpecType, Policy);
}
if (TypeAltiVecPixel) {
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 2a5bacff0d93..6586fb32787c 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -130,6 +130,9 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
return false;
}
+ // FIXME: If D is a local extern declaration, this check doesn't make sense;
+ // we should be checking its lexical context instead in that case, because
+ // that is its scope.
DeclContext *DCtx = D->getDeclContext()->getRedeclContext();
return AllowInlineNamespace ? Ctx->InEnclosingNamespaceSetOf(DCtx)
: Ctx->Equals(DCtx);
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 255845282dfa..fd75c02bb1ed 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -84,6 +84,7 @@ private:
void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
unsigned JumpDiag, unsigned JumpDiagWarning,
unsigned JumpDiagCXX98Compat);
+ void CheckGotoStmt(GotoStmt *GS);
unsigned GetDeepestCommonScope(unsigned A, unsigned B);
};
@@ -489,10 +490,14 @@ void JumpScopeChecker::VerifyJumps() {
// With a goto,
if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {
- CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(),
- diag::err_goto_into_protected_scope,
- diag::ext_goto_into_protected_scope,
- diag::warn_cxx98_compat_goto_into_protected_scope);
+ // The label may not have a statement if it's coming from inline MS ASM.
+ if (GS->getLabel()->getStmt()) {
+ CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(),
+ diag::err_goto_into_protected_scope,
+ diag::ext_goto_into_protected_scope,
+ diag::warn_cxx98_compat_goto_into_protected_scope);
+ }
+ CheckGotoStmt(GS);
continue;
}
@@ -789,6 +794,15 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
}
}
+void JumpScopeChecker::CheckGotoStmt(GotoStmt *GS) {
+ if (GS->getLabel()->isMSAsmLabel()) {
+ S.Diag(GS->getGotoLoc(), diag::err_goto_ms_asm_label)
+ << GS->getLabel()->getIdentifier();
+ S.Diag(GS->getLabel()->getLocation(), diag::note_goto_ms_asm_label)
+ << GS->getLabel()->getIdentifier();
+ }
+}
+
void Sema::DiagnoseInvalidJumps(Stmt *Body) {
(void)JumpScopeChecker(Body, *this);
}
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index 97237dbf097d..449ddf43114d 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -242,6 +242,12 @@ void MultiplexExternalSemaSource::ReadDynamicClasses(
Sources[i]->ReadDynamicClasses(Decls);
}
+void MultiplexExternalSemaSource::ReadUnusedLocalTypedefNameCandidates(
+ llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadUnusedLocalTypedefNameCandidates(Decls);
+}
+
void MultiplexExternalSemaSource::ReadLocallyScopedExternCDecls(
SmallVectorImpl<NamedDecl*> &Decls) {
for(size_t i = 0; i < Sources.size(); ++i)
diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp
index 35e2075b3826..6c7977882386 100644
--- a/lib/Sema/Scope.cpp
+++ b/lib/Sema/Scope.cpp
@@ -39,9 +39,6 @@ void Scope::Init(Scope *parent, unsigned flags) {
BlockParent = parent->BlockParent;
TemplateParamParent = parent->TemplateParamParent;
MSLocalManglingParent = parent->MSLocalManglingParent;
- SEHTryParent = parent->SEHTryParent;
- if (parent->Flags & SEHTryScope)
- SEHTryParent = parent;
if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
0)
@@ -50,17 +47,13 @@ void Scope::Init(Scope *parent, unsigned flags) {
Depth = 0;
PrototypeDepth = 0;
PrototypeIndex = 0;
- SEHTryParent = MSLocalManglingParent = FnParent = BlockParent = nullptr;
+ MSLocalManglingParent = FnParent = BlockParent = nullptr;
TemplateParamParent = nullptr;
MSLocalManglingNumber = 1;
}
// If this scope is a function or contains breaks/continues, remember it.
if (flags & FnScope) FnParent = this;
- SEHTryIndexPool = 0;
- SEHTryIndex = -1;
- if (flags & SEHTryScope)
- SEHTryIndex = FnParent ? FnParent->SEHTryIndexPool++ : -1;
// The MS mangler uses the number of scopes that can hold declarations as
// part of an external name.
if (Flags & (ClassScope | FnScope)) {
diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp
index 4d079e705f62..63ef3b2355fb 100644
--- a/lib/Sema/ScopeInfo.cpp
+++ b/lib/Sema/ScopeInfo.cpp
@@ -14,6 +14,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@@ -38,6 +39,7 @@ void FunctionScopeInfo::Clear() {
ErrorTrap.reset();
PossiblyUnreachableDiags.clear();
WeakObjectUses.clear();
+ ModifiedNonNullParams.clear();
}
static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) {
@@ -93,6 +95,21 @@ FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) {
return BaseInfoTy(D, IsExact);
}
+bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const {
+ RecordDecl *RD = nullptr;
+ if (auto *LSI = dyn_cast<LambdaScopeInfo>(this))
+ RD = LSI->Lambda;
+ else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(this))
+ RD = CRSI->TheRecordDecl;
+
+ if (RD)
+ for (auto *FD : RD->fields()) {
+ if (FD->hasCapturedVLAType() && FD->getCapturedVLAType() == VAT)
+ return true;
+ }
+ return false;
+}
+
FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
const ObjCPropertyRefExpr *PropE)
: Base(nullptr, true), Property(getBestPropertyDecl(PropE)) {
@@ -159,6 +176,8 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
// Has this weak object been seen before?
FunctionScopeInfo::WeakObjectUseMap::iterator Uses;
if (const ObjCPropertyRefExpr *RefExpr = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ if (!RefExpr->isObjectReceiver())
+ return;
if (isa<OpaqueValueExpr>(RefExpr->getBase()))
Uses = WeakObjectUses.find(WeakObjectProfileTy(RefExpr));
else {
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 2c653325b37b..b9aaf1616d68 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -69,8 +69,6 @@ PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
void Sema::ActOnTranslationUnitScope(Scope *S) {
TUScope = S;
PushDeclContext(S, Context.getTranslationUnitDecl());
-
- VAListTagName = PP.getIdentifierInfo("__va_list_tag");
}
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
@@ -90,12 +88,14 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
IsBuildingRecoveryCallExpr(false),
ExprNeedsCleanups(false), LateTemplateParser(nullptr),
+ LateTemplateParserCleanup(nullptr),
OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr),
CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
NSNumberDecl(nullptr),
NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr),
NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr),
+ MSAsmLabelNameCounter(0),
GlobalNewDeleteDeclared(false),
TUKind(TUKind),
NumSFINAEErrors(0),
@@ -151,6 +151,10 @@ void Sema::Initialize() {
= dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource()))
ExternalSema->InitializeSema(*this);
+ // This needs to happen after ExternalSemaSource::InitializeSema(this) or we
+ // will not be able to merge any duplicate __va_list_tag decls correctly.
+ VAListTagName = PP.getIdentifierInfo("__va_list_tag");
+
// Initialize predefined 128-bit integer types, if needed.
if (Context.getTargetInfo().hasInt128Type()) {
// If either of the 128-bit integer types are unavailable to name lookup,
@@ -241,6 +245,8 @@ Sema::~Sema() {
// Destroys data sharing attributes stack for OpenMP
DestroyDataSharingAttributesStack();
+
+ assert(DelayedTypos.empty() && "Uncorrected typos!");
}
/// makeUnavailableInSystemHeader - There is an error in the current
@@ -538,7 +544,12 @@ static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD,
if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I))
Complete = M->isDefined() || (M->isPure() && !isa<CXXDestructorDecl>(M));
else if (const FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(*I))
- Complete = F->getTemplatedDecl()->isDefined();
+ // If the template function is marked as late template parsed at this point,
+ // it has not been instantiated and therefore we have not performed semantic
+ // analysis on it yet, so we cannot know if the type can be considered
+ // complete.
+ Complete = !F->getTemplatedDecl()->isLateTemplateParsed() &&
+ F->getTemplatedDecl()->isDefined();
else if (const CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(*I)) {
if (R->isInjectedClassName())
continue;
@@ -591,6 +602,19 @@ static bool IsRecordFullyDefined(const CXXRecordDecl *RD,
return Complete;
}
+void Sema::emitAndClearUnusedLocalTypedefWarnings() {
+ if (ExternalSource)
+ ExternalSource->ReadUnusedLocalTypedefNameCandidates(
+ UnusedLocalTypedefNameCandidates);
+ for (const TypedefNameDecl *TD : UnusedLocalTypedefNameCandidates) {
+ if (TD->isReferenced())
+ continue;
+ Diag(TD->getLocation(), diag::warn_unused_local_typedef)
+ << isa<TypeAliasDecl>(TD) << TD->getDeclName();
+ }
+ UnusedLocalTypedefNameCandidates.clear();
+}
+
/// ActOnEndOfTranslationUnit - This is called at the very end of the
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
@@ -647,13 +671,16 @@ void Sema::ActOnEndOfTranslationUnit() {
}
PerformPendingInstantiations();
+ if (LateTemplateParserCleanup)
+ LateTemplateParserCleanup(OpaqueParser);
+
CheckDelayedMemberExceptionSpecs();
}
// All delayed member exception specs should be checked or we end up accepting
// incompatible declarations.
assert(DelayedDefaultedMemberExceptionSpecs.empty());
- assert(DelayedDestructorExceptionSpecChecks.empty());
+ assert(DelayedExceptionSpecChecks.empty());
// Remove file scoped decls that turned out to be used.
UnusedFileScopedDecls.erase(
@@ -713,6 +740,10 @@ void Sema::ActOnEndOfTranslationUnit() {
}
}
+ // Warnings emitted in ActOnEndOfTranslationUnit() should be emitted for
+ // modules when they are built, not every time they are used.
+ emitAndClearUnusedLocalTypedefWarnings();
+
// Modules don't need any of the checking below.
TUScope = nullptr;
return;
@@ -740,7 +771,7 @@ void Sema::ActOnEndOfTranslationUnit() {
// If the tentative definition was completed, getActingDefinition() returns
// null. If we've already seen this variable before, insert()'s second
// return value is false.
- if (!VD || VD->isInvalidDecl() || !Seen.insert(VD))
+ if (!VD || VD->isInvalidDecl() || !Seen.insert(VD).second)
continue;
if (const IncompleteArrayType *ArrayT
@@ -788,8 +819,9 @@ void Sema::ActOnEndOfTranslationUnit() {
!FD->isInlineSpecified() &&
!SourceMgr.isInMainFile(
SourceMgr.getExpansionLoc(FD->getLocation())))
- Diag(DiagD->getLocation(), diag::warn_unneeded_static_internal_decl)
- << DiagD->getDeclName();
+ Diag(DiagD->getLocation(),
+ diag::warn_unneeded_static_internal_decl)
+ << DiagD->getDeclName();
else
Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl)
<< /*function*/0 << DiagD->getDeclName();
@@ -820,6 +852,8 @@ void Sema::ActOnEndOfTranslationUnit() {
if (ExternalSource)
ExternalSource->ReadUndefinedButUsed(UndefinedButUsed);
checkUndefinedButUsed(*this);
+
+ emitAndClearUnusedLocalTypedefWarnings();
}
if (!Diags.isIgnored(diag::warn_unused_private_field, SourceLocation())) {
@@ -1432,8 +1466,8 @@ IdentifierInfo *Sema::getFloat128Identifier() const {
void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD,
CapturedRegionKind K) {
- CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(getDiagnostics(), S, CD, RD,
- CD->getContextParam(), K);
+ CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(
+ getDiagnostics(), S, CD, RD, CD->getContextParam(), K);
CSI->ReturnType = Context.VoidTy;
FunctionScopes.push_back(CSI);
}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index ffdb0aa27a6b..37240c23b691 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -1749,14 +1749,14 @@ Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
return AR_accessible;
CXXMethodDecl *method = cast<CXXMethodDecl>(target->getAsFunction());
- assert(method->getQualifier());
AccessTarget entity(Context, AccessTarget::Member,
cast<CXXRecordDecl>(target->getDeclContext()),
DeclAccessPair::make(target, access),
/*no instance context*/ QualType());
entity.setDiag(diag::err_access_friend_function)
- << method->getQualifierLoc().getSourceRange();
+ << (method->getQualifier() ? method->getQualifierLoc().getSourceRange()
+ : method->getNameInfo().getSourceRange());
// We need to bypass delayed-diagnostics because we might be called
// while the ParsingDeclarator is active.
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index a7d606d545ca..76297977ea0e 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -360,18 +360,18 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
}
}
-bool Sema::UnifySection(const StringRef &SectionName,
+bool Sema::UnifySection(StringRef SectionName,
int SectionFlags,
DeclaratorDecl *Decl) {
- auto Section = SectionInfos.find(SectionName);
- if (Section == SectionInfos.end()) {
- SectionInfos[SectionName] =
- SectionInfo(Decl, SourceLocation(), SectionFlags);
+ auto Section = Context.SectionInfos.find(SectionName);
+ if (Section == Context.SectionInfos.end()) {
+ Context.SectionInfos[SectionName] =
+ ASTContext::SectionInfo(Decl, SourceLocation(), SectionFlags);
return false;
}
// A pre-declared section takes precedence w/o diagnostic.
if (Section->second.SectionFlags == SectionFlags ||
- !(Section->second.SectionFlags & PSF_Implicit))
+ !(Section->second.SectionFlags & ASTContext::PSF_Implicit))
return false;
auto OtherDecl = Section->second.Decl;
Diag(Decl->getLocation(), diag::err_section_conflict)
@@ -384,17 +384,17 @@ bool Sema::UnifySection(const StringRef &SectionName,
if (auto A = OtherDecl->getAttr<SectionAttr>())
if (A->isImplicit())
Diag(A->getLocation(), diag::note_pragma_entered_here);
- return false;
+ return true;
}
-bool Sema::UnifySection(const StringRef &SectionName,
+bool Sema::UnifySection(StringRef SectionName,
int SectionFlags,
SourceLocation PragmaSectionLocation) {
- auto Section = SectionInfos.find(SectionName);
- if (Section != SectionInfos.end()) {
+ auto Section = Context.SectionInfos.find(SectionName);
+ if (Section != Context.SectionInfos.end()) {
if (Section->second.SectionFlags == SectionFlags)
return false;
- if (!(Section->second.SectionFlags & PSF_Implicit)) {
+ if (!(Section->second.SectionFlags & ASTContext::PSF_Implicit)) {
Diag(PragmaSectionLocation, diag::err_section_conflict)
<< "this" << "a prior #pragma section";
Diag(Section->second.PragmaSectionLocation,
@@ -402,8 +402,8 @@ bool Sema::UnifySection(const StringRef &SectionName,
return true;
}
}
- SectionInfos[SectionName] =
- SectionInfo(nullptr, PragmaSectionLocation, SectionFlags);
+ Context.SectionInfos[SectionName] =
+ ASTContext::SectionInfo(nullptr, PragmaSectionLocation, SectionFlags);
return false;
}
diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp
new file mode 100644
index 000000000000..64222fbf8ac8
--- /dev/null
+++ b/lib/Sema/SemaCUDA.cpp
@@ -0,0 +1,263 @@
+//===--- SemaCUDA.cpp - Semantic Analysis for CUDA constructs -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements semantic analysis for CUDA constructs.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+using namespace clang;
+
+ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
+ MultiExprArg ExecConfig,
+ SourceLocation GGGLoc) {
+ FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl();
+ if (!ConfigDecl)
+ return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use)
+ << "cudaConfigureCall");
+ QualType ConfigQTy = ConfigDecl->getType();
+
+ DeclRefExpr *ConfigDR = new (Context)
+ DeclRefExpr(ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc);
+ MarkFunctionReferenced(LLLLoc, ConfigDecl);
+
+ return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr,
+ /*IsExecConfig=*/true);
+}
+
+/// IdentifyCUDATarget - Determine the CUDA compilation target for this function
+Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
+ if (D->hasAttr<CUDAInvalidTargetAttr>())
+ return CFT_InvalidTarget;
+
+ if (D->hasAttr<CUDAGlobalAttr>())
+ return CFT_Global;
+
+ if (D->hasAttr<CUDADeviceAttr>()) {
+ if (D->hasAttr<CUDAHostAttr>())
+ return CFT_HostDevice;
+ return CFT_Device;
+ } else if (D->hasAttr<CUDAHostAttr>()) {
+ return CFT_Host;
+ } else if (D->isImplicit()) {
+ // Some implicit declarations (like intrinsic functions) are not marked.
+ // Set the most lenient target on them for maximal flexibility.
+ return CFT_HostDevice;
+ }
+
+ return CFT_Host;
+}
+
+bool Sema::CheckCUDATarget(const FunctionDecl *Caller,
+ const FunctionDecl *Callee) {
+ CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller),
+ CalleeTarget = IdentifyCUDATarget(Callee);
+
+ // If one of the targets is invalid, the check always fails, no matter what
+ // the other target is.
+ if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget)
+ return true;
+
+ // CUDA B.1.1 "The __device__ qualifier declares a function that is [...]
+ // Callable from the device only."
+ if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device)
+ return true;
+
+ // CUDA B.1.2 "The __global__ qualifier declares a function that is [...]
+ // Callable from the host only."
+ // CUDA B.1.3 "The __host__ qualifier declares a function that is [...]
+ // Callable from the host only."
+ if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) &&
+ (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global))
+ return true;
+
+ // CUDA B.1.3 "The __device__ and __host__ qualifiers can be used together
+ // however, in which case the function is compiled for both the host and the
+ // device. The __CUDA_ARCH__ macro [...] can be used to differentiate code
+ // paths between host and device."
+ if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) {
+ // If the caller is implicit then the check always passes.
+ if (Caller->isImplicit()) return false;
+
+ bool InDeviceMode = getLangOpts().CUDAIsDevice;
+ if ((InDeviceMode && CalleeTarget != CFT_Device) ||
+ (!InDeviceMode && CalleeTarget != CFT_Host))
+ return true;
+ }
+
+ return false;
+}
+
+/// When an implicitly-declared special member has to invoke more than one
+/// base/field special member, conflicts may occur in the targets of these
+/// members. For example, if one base's member __host__ and another's is
+/// __device__, it's a conflict.
+/// This function figures out if the given targets \param Target1 and
+/// \param Target2 conflict, and if they do not it fills in
+/// \param ResolvedTarget with a target that resolves for both calls.
+/// \return true if there's a conflict, false otherwise.
+static bool
+resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1,
+ Sema::CUDAFunctionTarget Target2,
+ Sema::CUDAFunctionTarget *ResolvedTarget) {
+ if (Target1 == Sema::CFT_Global && Target2 == Sema::CFT_Global) {
+ // TODO: this shouldn't happen, really. Methods cannot be marked __global__.
+ // Clang should detect this earlier and produce an error. Then this
+ // condition can be changed to an assertion.
+ return true;
+ }
+
+ if (Target1 == Sema::CFT_HostDevice) {
+ *ResolvedTarget = Target2;
+ } else if (Target2 == Sema::CFT_HostDevice) {
+ *ResolvedTarget = Target1;
+ } else if (Target1 != Target2) {
+ return true;
+ } else {
+ *ResolvedTarget = Target1;
+ }
+
+ return false;
+}
+
+bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
+ CXXSpecialMember CSM,
+ CXXMethodDecl *MemberDecl,
+ bool ConstRHS,
+ bool Diagnose) {
+ llvm::Optional<CUDAFunctionTarget> InferredTarget;
+
+ // We're going to invoke special member lookup; mark that these special
+ // members are called from this one, and not from its caller.
+ ContextRAII MethodContext(*this, MemberDecl);
+
+ // Look for special members in base classes that should be invoked from here.
+ // Infer the target of this member base on the ones it should call.
+ // Skip direct and indirect virtual bases for abstract classes.
+ llvm::SmallVector<const CXXBaseSpecifier *, 16> Bases;
+ for (const auto &B : ClassDecl->bases()) {
+ if (!B.isVirtual()) {
+ Bases.push_back(&B);
+ }
+ }
+
+ if (!ClassDecl->isAbstract()) {
+ for (const auto &VB : ClassDecl->vbases()) {
+ Bases.push_back(&VB);
+ }
+ }
+
+ for (const auto *B : Bases) {
+ const RecordType *BaseType = B->getType()->getAs<RecordType>();
+ if (!BaseType) {
+ continue;
+ }
+
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+ Sema::SpecialMemberOverloadResult *SMOR =
+ LookupSpecialMember(BaseClassDecl, CSM,
+ /* ConstArg */ ConstRHS,
+ /* VolatileArg */ false,
+ /* RValueThis */ false,
+ /* ConstThis */ false,
+ /* VolatileThis */ false);
+
+ if (!SMOR || !SMOR->getMethod()) {
+ continue;
+ }
+
+ CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR->getMethod());
+ if (!InferredTarget.hasValue()) {
+ InferredTarget = BaseMethodTarget;
+ } else {
+ bool ResolutionError = resolveCalleeCUDATargetConflict(
+ InferredTarget.getValue(), BaseMethodTarget,
+ InferredTarget.getPointer());
+ if (ResolutionError) {
+ if (Diagnose) {
+ Diag(ClassDecl->getLocation(),
+ diag::note_implicit_member_target_infer_collision)
+ << (unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget;
+ }
+ MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
+ return true;
+ }
+ }
+ }
+
+ // Same as for bases, but now for special members of fields.
+ for (const auto *F : ClassDecl->fields()) {
+ if (F->isInvalidDecl()) {
+ continue;
+ }
+
+ const RecordType *FieldType =
+ Context.getBaseElementType(F->getType())->getAs<RecordType>();
+ if (!FieldType) {
+ continue;
+ }
+
+ CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(FieldType->getDecl());
+ Sema::SpecialMemberOverloadResult *SMOR =
+ LookupSpecialMember(FieldRecDecl, CSM,
+ /* ConstArg */ ConstRHS && !F->isMutable(),
+ /* VolatileArg */ false,
+ /* RValueThis */ false,
+ /* ConstThis */ false,
+ /* VolatileThis */ false);
+
+ if (!SMOR || !SMOR->getMethod()) {
+ continue;
+ }
+
+ CUDAFunctionTarget FieldMethodTarget =
+ IdentifyCUDATarget(SMOR->getMethod());
+ if (!InferredTarget.hasValue()) {
+ InferredTarget = FieldMethodTarget;
+ } else {
+ bool ResolutionError = resolveCalleeCUDATargetConflict(
+ InferredTarget.getValue(), FieldMethodTarget,
+ InferredTarget.getPointer());
+ if (ResolutionError) {
+ if (Diagnose) {
+ Diag(ClassDecl->getLocation(),
+ diag::note_implicit_member_target_infer_collision)
+ << (unsigned)CSM << InferredTarget.getValue()
+ << FieldMethodTarget;
+ }
+ MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
+ return true;
+ }
+ }
+ }
+
+ if (InferredTarget.hasValue()) {
+ if (InferredTarget.getValue() == CFT_Device) {
+ MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
+ } else if (InferredTarget.getValue() == CFT_Host) {
+ MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
+ } else {
+ MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
+ MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
+ }
+ } else {
+ // If no target was inferred, mark this member as __host__ __device__;
+ // it's the least restrictive option that can be invoked from any target.
+ MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
+ MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
+ }
+
+ return false;
+}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index a70aca2ad86a..3e56e676a15c 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -148,6 +148,9 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
case NestedNameSpecifier::Global:
return Context.getTranslationUnitDecl();
+
+ case NestedNameSpecifier::Super:
+ return NNS->getAsRecordDecl();
}
llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
@@ -240,12 +243,43 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
return true;
}
-bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,
+bool Sema::ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc,
CXXScopeSpec &SS) {
SS.MakeGlobal(Context, CCLoc);
return false;
}
+bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc,
+ SourceLocation ColonColonLoc,
+ CXXScopeSpec &SS) {
+ CXXRecordDecl *RD = nullptr;
+ for (Scope *S = getCurScope(); S; S = S->getParent()) {
+ if (S->isFunctionScope()) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(S->getEntity()))
+ RD = MD->getParent();
+ break;
+ }
+ if (S->isClassScope()) {
+ RD = cast<CXXRecordDecl>(S->getEntity());
+ break;
+ }
+ }
+
+ if (!RD) {
+ Diag(SuperLoc, diag::err_invalid_super_scope);
+ return true;
+ } else if (RD->isLambda()) {
+ Diag(SuperLoc, diag::err_super_in_lambda_unsupported);
+ return true;
+ } else if (RD->getNumBases() == 0) {
+ Diag(SuperLoc, diag::err_no_base_classes) << RD->getName();
+ return true;
+ }
+
+ SS.MakeSuper(Context, RD, SuperLoc, ColonColonLoc);
+ return false;
+}
+
/// \brief Determines whether the given declaration is an valid acceptable
/// result for name lookup of a nested-name-specifier.
bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD) {
@@ -376,9 +410,6 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
/// \brief Build a new nested-name-specifier for "identifier::", as described
/// by ActOnCXXNestedNameSpecifier.
///
-/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
-/// that it contains an extra parameter \p ScopeLookupResult.
-///
/// \param S Scope in which the nested-name-specifier occurs.
/// \param Identifier Identifier in the sequence "identifier" "::".
/// \param IdentifierLoc Location of the \p Identifier.
@@ -541,12 +572,11 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
- NestedNameSpecifierValidatorCCC Validator(*this);
Found.clear();
- if (TypoCorrection Corrected =
- CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S,
- &SS, Validator, CTK_ErrorRecovery, LookupCtx,
- EnteringContext)) {
+ if (TypoCorrection Corrected = CorrectTypo(
+ Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS,
+ llvm::make_unique<NestedNameSpecifierValidatorCCC>(*this),
+ CTK_ErrorRecovery, LookupCtx, EnteringContext)) {
if (LookupCtx) {
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() &&
@@ -612,10 +642,17 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
}
}
+ if (auto *TD = dyn_cast_or_null<TypedefNameDecl>(SD))
+ MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
+
// If we're just performing this lookup for error-recovery purposes,
// don't extend the nested-name-specifier. Just return now.
if (ErrorRecoveryLookup)
return false;
+
+ // The use of a nested name specifier may trigger deprecation warnings.
+ DiagnoseUseOfDecl(SD, CCLoc);
+
if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) {
SS.Extend(Context, Namespace, IdentifierLoc, CCLoc);
@@ -703,8 +740,13 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
if (getLangOpts().MSVCCompat) {
DeclContext *DC = LookupCtx ? LookupCtx : CurContext;
if (DC->isDependentContext() && DC->isFunctionOrMethod()) {
- SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
- return false;
+ CXXRecordDecl *ContainingClass = dyn_cast<CXXRecordDecl>(DC->getParent());
+ if (ContainingClass && ContainingClass->hasAnyDependentBases()) {
+ Diag(IdentifierLoc, diag::ext_undeclared_unqual_id_with_dependent_base)
+ << &Identifier << ContainingClass;
+ SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
+ return false;
+ }
}
}
@@ -945,6 +987,7 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::Super:
// These are never namespace scopes.
return true;
}
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index ae5436cf415c..a4c2d9b51c26 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -142,9 +142,6 @@ namespace {
};
}
-static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
- bool CheckCVR, bool CheckObjCLifetime);
-
// The Try functions attempt a specific way of casting. If they succeed, they
// return TC_Success. If their way of casting is not appropriate for the given
// arguments, they return TC_NotApplicable and *may* set diag to a diagnostic
@@ -243,10 +240,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
QualType DestType = DestTInfo->getType();
// If the type is dependent, we won't do the semantic analysis now.
- // FIXME: should we check this in a more fine-grained manner?
- bool TypeDependent = DestType->isDependentType() ||
- Ex.get()->isTypeDependent() ||
- Ex.get()->isValueDependent();
+ bool TypeDependent =
+ DestType->isDependentType() || Ex.get()->isTypeDependent();
CastOperation Op(*this, DestType, E);
Op.OpRange = SourceRange(OpLoc, Parens.getEnd());
@@ -462,7 +457,10 @@ static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
/// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers.
static bool
CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
- bool CheckCVR, bool CheckObjCLifetime) {
+ bool CheckCVR, bool CheckObjCLifetime,
+ QualType *TheOffendingSrcType = nullptr,
+ QualType *TheOffendingDestType = nullptr,
+ Qualifiers *CastAwayQualifiers = nullptr) {
// If the only checking we care about is for Objective-C lifetime qualifiers,
// and we're not in ARC mode, there's nothing to check.
if (!CheckCVR && CheckObjCLifetime &&
@@ -487,6 +485,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
// Find the qualifiers. We only care about cvr-qualifiers for the
// purpose of this check, because other qualifiers (address spaces,
// Objective-C GC, etc.) are part of the type's identity.
+ QualType PrevUnwrappedSrcType = UnwrappedSrcType;
+ QualType PrevUnwrappedDestType = UnwrappedDestType;
while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
// Determine the relevant qualifiers at this level.
Qualifiers SrcQuals, DestQuals;
@@ -497,6 +497,13 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
if (CheckCVR) {
RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers());
RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers());
+
+ if (RetainedSrcQuals != RetainedDestQuals && TheOffendingSrcType &&
+ TheOffendingDestType && CastAwayQualifiers) {
+ *TheOffendingSrcType = PrevUnwrappedSrcType;
+ *TheOffendingDestType = PrevUnwrappedDestType;
+ *CastAwayQualifiers = RetainedSrcQuals - RetainedDestQuals;
+ }
}
if (CheckObjCLifetime &&
@@ -505,6 +512,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
cv1.push_back(RetainedSrcQuals);
cv2.push_back(RetainedDestQuals);
+
+ PrevUnwrappedSrcType = UnwrappedSrcType;
+ PrevUnwrappedDestType = UnwrappedDestType;
}
if (cv1.empty())
return false;
@@ -2200,8 +2210,8 @@ void CastOperation::CheckCStyleCast() {
// address space B is illegal.
if (Self.getLangOpts().OpenCL && DestType->isPointerType() &&
SrcType->isPointerType()) {
- if (DestType->getPointeeType().getAddressSpace() !=
- SrcType->getPointeeType().getAddressSpace()) {
+ const PointerType *DestPtr = DestType->getAs<PointerType>();
+ if (!DestPtr->isAddressSpaceOverlapping(*SrcType->getAs<PointerType>())) {
Self.Diag(OpRange.getBegin(),
diag::err_typecheck_incompatible_address_space)
<< SrcType << DestType << Sema::AA_Casting
@@ -2371,6 +2381,30 @@ void CastOperation::CheckCStyleCast() {
if (Kind == CK_BitCast)
checkCastAlign();
+
+ // -Wcast-qual
+ QualType TheOffendingSrcType, TheOffendingDestType;
+ Qualifiers CastAwayQualifiers;
+ if (SrcType->isAnyPointerType() && DestType->isAnyPointerType() &&
+ CastsAwayConstness(Self, SrcType, DestType, true, false,
+ &TheOffendingSrcType, &TheOffendingDestType,
+ &CastAwayQualifiers)) {
+ int qualifiers = -1;
+ if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) {
+ qualifiers = 0;
+ } else if (CastAwayQualifiers.hasConst()) {
+ qualifiers = 1;
+ } else if (CastAwayQualifiers.hasVolatile()) {
+ qualifiers = 2;
+ }
+ // This is a variant of int **x; const int **y = (const int **)x;
+ if (qualifiers == -1)
+ Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) <<
+ SrcType << DestType;
+ else
+ Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) <<
+ TheOffendingSrcType << TheOffendingDestType << qualifiers;
+ }
}
ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 66be962fcf33..9fc2bec23b1b 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -111,8 +111,100 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) {
return false;
}
+static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl,
+ CallExpr *TheCall, unsigned SizeIdx,
+ unsigned DstSizeIdx) {
+ if (TheCall->getNumArgs() <= SizeIdx ||
+ TheCall->getNumArgs() <= DstSizeIdx)
+ return;
+
+ const Expr *SizeArg = TheCall->getArg(SizeIdx);
+ const Expr *DstSizeArg = TheCall->getArg(DstSizeIdx);
+
+ llvm::APSInt Size, DstSize;
+
+ // find out if both sizes are known at compile time
+ if (!SizeArg->EvaluateAsInt(Size, S.Context) ||
+ !DstSizeArg->EvaluateAsInt(DstSize, S.Context))
+ return;
+
+ if (Size.ule(DstSize))
+ return;
+
+ // confirmed overflow so generate the diagnostic.
+ IdentifierInfo *FnName = FDecl->getIdentifier();
+ SourceLocation SL = TheCall->getLocStart();
+ SourceRange SR = TheCall->getSourceRange();
+
+ S.Diag(SL, diag::warn_memcpy_chk_overflow) << SR << FnName;
+}
+
+static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) {
+ if (checkArgCount(S, BuiltinCall, 2))
+ return true;
+
+ SourceLocation BuiltinLoc = BuiltinCall->getLocStart();
+ Expr *Builtin = BuiltinCall->getCallee()->IgnoreImpCasts();
+ Expr *Call = BuiltinCall->getArg(0);
+ Expr *Chain = BuiltinCall->getArg(1);
+
+ if (Call->getStmtClass() != Stmt::CallExprClass) {
+ S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_not_call)
+ << Call->getSourceRange();
+ return true;
+ }
+
+ auto CE = cast<CallExpr>(Call);
+ if (CE->getCallee()->getType()->isBlockPointerType()) {
+ S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_block_call)
+ << Call->getSourceRange();
+ return true;
+ }
+
+ const Decl *TargetDecl = CE->getCalleeDecl();
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl))
+ if (FD->getBuiltinID()) {
+ S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_builtin_call)
+ << Call->getSourceRange();
+ return true;
+ }
+
+ if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) {
+ S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_pdtor_call)
+ << Call->getSourceRange();
+ return true;
+ }
+
+ ExprResult ChainResult = S.UsualUnaryConversions(Chain);
+ if (ChainResult.isInvalid())
+ return true;
+ if (!ChainResult.get()->getType()->isPointerType()) {
+ S.Diag(BuiltinLoc, diag::err_second_argument_to_cwsc_not_pointer)
+ << Chain->getSourceRange();
+ return true;
+ }
+
+ QualType ReturnTy = CE->getCallReturnType();
+ QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() };
+ QualType BuiltinTy = S.Context.getFunctionType(
+ ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo());
+ QualType BuiltinPtrTy = S.Context.getPointerType(BuiltinTy);
+
+ Builtin =
+ S.ImpCastExprToType(Builtin, BuiltinPtrTy, CK_BuiltinFnToFnPtr).get();
+
+ BuiltinCall->setType(CE->getType());
+ BuiltinCall->setValueKind(CE->getValueKind());
+ BuiltinCall->setObjectKind(CE->getObjectKind());
+ BuiltinCall->setCallee(Builtin);
+ BuiltinCall->setArg(1, ChainResult.get());
+
+ return false;
+}
+
ExprResult
-Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
+ CallExpr *TheCall) {
ExprResult TheCallResult(TheCall);
// Find out if any arguments are required to be integer constant expressions.
@@ -189,9 +281,14 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return ExprError();
break;
case Builtin::BI__assume:
+ case Builtin::BI__builtin_assume:
if (SemaBuiltinAssume(TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_assume_aligned:
+ if (SemaBuiltinAssumeAligned(TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_object_size:
if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3))
return ExprError();
@@ -239,6 +336,12 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__sync_fetch_and_xor_4:
case Builtin::BI__sync_fetch_and_xor_8:
case Builtin::BI__sync_fetch_and_xor_16:
+ case Builtin::BI__sync_fetch_and_nand:
+ case Builtin::BI__sync_fetch_and_nand_1:
+ case Builtin::BI__sync_fetch_and_nand_2:
+ case Builtin::BI__sync_fetch_and_nand_4:
+ case Builtin::BI__sync_fetch_and_nand_8:
+ case Builtin::BI__sync_fetch_and_nand_16:
case Builtin::BI__sync_add_and_fetch:
case Builtin::BI__sync_add_and_fetch_1:
case Builtin::BI__sync_add_and_fetch_2:
@@ -269,6 +372,12 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__sync_xor_and_fetch_4:
case Builtin::BI__sync_xor_and_fetch_8:
case Builtin::BI__sync_xor_and_fetch_16:
+ case Builtin::BI__sync_nand_and_fetch:
+ case Builtin::BI__sync_nand_and_fetch_1:
+ case Builtin::BI__sync_nand_and_fetch_2:
+ case Builtin::BI__sync_nand_and_fetch_4:
+ case Builtin::BI__sync_nand_and_fetch_8:
+ case Builtin::BI__sync_nand_and_fetch_16:
case Builtin::BI__sync_val_compare_and_swap:
case Builtin::BI__sync_val_compare_and_swap_1:
case Builtin::BI__sync_val_compare_and_swap_2:
@@ -327,6 +436,31 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
// so ensure that they are declared.
DeclareGlobalNewDelete();
break;
+
+ // check secure string manipulation functions where overflows
+ // are detectable at compile time
+ case Builtin::BI__builtin___memcpy_chk:
+ case Builtin::BI__builtin___memmove_chk:
+ case Builtin::BI__builtin___memset_chk:
+ case Builtin::BI__builtin___strlcat_chk:
+ case Builtin::BI__builtin___strlcpy_chk:
+ case Builtin::BI__builtin___strncat_chk:
+ case Builtin::BI__builtin___strncpy_chk:
+ case Builtin::BI__builtin___stpncpy_chk:
+ SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3);
+ break;
+ case Builtin::BI__builtin___memccpy_chk:
+ SemaBuiltinMemChkCall(*this, FDecl, TheCall, 3, 4);
+ break;
+ case Builtin::BI__builtin___snprintf_chk:
+ case Builtin::BI__builtin___vsnprintf_chk:
+ SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3);
+ break;
+
+ case Builtin::BI__builtin_call_with_static_chain:
+ if (SemaBuiltinCallWithStaticChain(*this, TheCall))
+ return ExprError();
+ break;
}
// Since the target specific builtins for each arch overlap, only check those
@@ -342,8 +476,6 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
- case llvm::Triple::arm64:
- case llvm::Triple::arm64_be:
if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
@@ -468,8 +600,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
QualType RHSTy = RHS.get()->getType();
llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
- bool IsPolyUnsigned =
- Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::arm64;
+ bool IsPolyUnsigned = Arch == llvm::Triple::aarch64;
bool IsInt64Long =
Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong;
QualType EltTy =
@@ -627,6 +758,11 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64);
}
+ if (BuiltinID == ARM::BI__builtin_arm_prefetch) {
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) ||
+ SemaBuiltinConstantArgRange(TheCall, 2, 0, 1);
+ }
+
if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
return true;
@@ -641,7 +777,8 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break;
case ARM::BI__builtin_arm_dmb:
case ARM::BI__builtin_arm_dsb:
- case ARM::BI__builtin_arm_isb: l = 0; u = 15; break;
+ case ARM::BI__builtin_arm_isb:
+ case ARM::BI__builtin_arm_dbg: l = 0; u = 15; break;
}
// FIXME: VFP Intrinsics should error if VFP not present.
@@ -659,6 +796,13 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128);
}
+ if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) ||
+ SemaBuiltinConstantArgRange(TheCall, 2, 0, 2) ||
+ SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) ||
+ SemaBuiltinConstantArgRange(TheCall, 4, 0, 1);
+ }
+
if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
return true;
@@ -672,7 +816,6 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break;
}
- // FIXME: VFP Intrinsics should error if VFP not present.
return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
@@ -693,12 +836,16 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+ unsigned i = 0, l = 0, u = 0;
switch (BuiltinID) {
- case X86::BI_mm_prefetch:
- // This is declared to take (const char*, int)
- return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3);
+ default: return false;
+ case X86::BI_mm_prefetch: i = 1; l = 0; u = 3; break;
+ case X86::BI__builtin_ia32_cmpps:
+ case X86::BI__builtin_ia32_cmpss:
+ case X86::BI__builtin_ia32_cmppd:
+ case X86::BI__builtin_ia32_cmpsd: i = 2; l = 0; u = 31; break;
}
- return false;
+ return SemaBuiltinConstantArgRange(TheCall, i, l, u);
}
/// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo
@@ -753,14 +900,79 @@ static void CheckNonNullArgument(Sema &S,
S.Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
}
+bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) {
+ FormatStringInfo FSI;
+ if ((GetFormatStringType(Format) == FST_NSString) &&
+ getFormatStringInfo(Format, false, &FSI)) {
+ Idx = FSI.FormatIdx;
+ return true;
+ }
+ return false;
+}
+/// \brief Diagnose use of %s directive in an NSString which is being passed
+/// as formatting string to formatting method.
+static void
+DiagnoseCStringFormatDirectiveInCFAPI(Sema &S,
+ const NamedDecl *FDecl,
+ Expr **Args,
+ unsigned NumArgs) {
+ unsigned Idx = 0;
+ bool Format = false;
+ ObjCStringFormatFamily SFFamily = FDecl->getObjCFStringFormattingFamily();
+ if (SFFamily == ObjCStringFormatFamily::SFF_CFString) {
+ Idx = 2;
+ Format = true;
+ }
+ else
+ for (const auto *I : FDecl->specific_attrs<FormatAttr>()) {
+ if (S.GetFormatNSStringIdx(I, Idx)) {
+ Format = true;
+ break;
+ }
+ }
+ if (!Format || NumArgs <= Idx)
+ return;
+ const Expr *FormatExpr = Args[Idx];
+ if (const CStyleCastExpr *CSCE = dyn_cast<CStyleCastExpr>(FormatExpr))
+ FormatExpr = CSCE->getSubExpr();
+ const StringLiteral *FormatString;
+ if (const ObjCStringLiteral *OSL =
+ dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts()))
+ FormatString = OSL->getString();
+ else
+ FormatString = dyn_cast<StringLiteral>(FormatExpr->IgnoreParenImpCasts());
+ if (!FormatString)
+ return;
+ if (S.FormatStringHasSArg(FormatString)) {
+ S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
+ << "%s" << 1 << 1;
+ S.Diag(FDecl->getLocation(), diag::note_entity_declared_at)
+ << FDecl->getDeclName();
+ }
+}
+
static void CheckNonNullArguments(Sema &S,
const NamedDecl *FDecl,
- const Expr * const *ExprArgs,
+ ArrayRef<const Expr *> Args,
SourceLocation CallSiteLoc) {
// Check the attributes attached to the method/function itself.
+ llvm::SmallBitVector NonNullArgs;
for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) {
- for (const auto &Val : NonNull->args())
- CheckNonNullArgument(S, ExprArgs[Val], CallSiteLoc);
+ if (!NonNull->args_size()) {
+ // Easy case: all pointer arguments are nonnull.
+ for (const auto *Arg : Args)
+ if (S.isValidPointerAttrType(Arg->getType()))
+ CheckNonNullArgument(S, Arg, CallSiteLoc);
+ return;
+ }
+
+ for (unsigned Val : NonNull->args()) {
+ if (Val >= Args.size())
+ continue;
+ if (NonNullArgs.empty())
+ NonNullArgs.resize(Args.size());
+ NonNullArgs.set(Val);
+ }
}
// Check the attributes on the parameters.
@@ -770,13 +982,19 @@ static void CheckNonNullArguments(Sema &S,
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(FDecl))
parms = MD->parameters();
- unsigned argIndex = 0;
+ unsigned ArgIndex = 0;
for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end();
- I != E; ++I, ++argIndex) {
+ I != E; ++I, ++ArgIndex) {
const ParmVarDecl *PVD = *I;
- if (PVD->hasAttr<NonNullAttr>())
- CheckNonNullArgument(S, ExprArgs[argIndex], CallSiteLoc);
+ if (PVD->hasAttr<NonNullAttr>() ||
+ (ArgIndex < NonNullArgs.size() && NonNullArgs[ArgIndex]))
+ CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc);
}
+
+ // In case this is a variadic call, check any remaining arguments.
+ for (/**/; ArgIndex < NonNullArgs.size(); ++ArgIndex)
+ if (NonNullArgs[ArgIndex])
+ CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc);
}
/// Handles the checks for format strings, non-POD arguments to vararg
@@ -814,7 +1032,7 @@ void Sema::checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args,
}
if (FDecl) {
- CheckNonNullArguments(*this, FDecl, Args.data(), Loc);
+ CheckNonNullArguments(*this, FDecl, Args, Loc);
// Type safety checking.
for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>())
@@ -854,7 +1072,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
++Args;
--NumArgs;
}
- checkCall(FDecl, llvm::makeArrayRef<const Expr *>(Args, NumArgs), NumParams,
+ checkCall(FDecl, llvm::makeArrayRef(Args, NumArgs), NumParams,
IsMemberFunction, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -865,6 +1083,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
return false;
CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo);
+ if (getLangOpts().ObjC1)
+ DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs);
unsigned CMId = FDecl->getMemoryFunctionKind();
if (CMId == 0)
@@ -913,8 +1133,8 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
}
unsigned NumParams = Proto ? Proto->getNumParams() : 0;
- checkCall(NDecl, llvm::makeArrayRef<const Expr *>(TheCall->getArgs(),
- TheCall->getNumArgs()),
+ checkCall(NDecl, llvm::makeArrayRef(TheCall->getArgs(),
+ TheCall->getNumArgs()),
NumParams, /*IsMemberFunction=*/false, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -929,8 +1149,7 @@ bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
unsigned NumParams = Proto ? Proto->getNumParams() : 0;
checkCall(/*FDecl=*/nullptr,
- llvm::makeArrayRef<const Expr *>(TheCall->getArgs(),
- TheCall->getNumArgs()),
+ llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
NumParams, /*IsMemberFunction=*/false, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -1383,12 +1602,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
BUILTIN_ROW(__sync_fetch_and_or),
BUILTIN_ROW(__sync_fetch_and_and),
BUILTIN_ROW(__sync_fetch_and_xor),
+ BUILTIN_ROW(__sync_fetch_and_nand),
BUILTIN_ROW(__sync_add_and_fetch),
BUILTIN_ROW(__sync_sub_and_fetch),
BUILTIN_ROW(__sync_and_and_fetch),
BUILTIN_ROW(__sync_or_and_fetch),
BUILTIN_ROW(__sync_xor_and_fetch),
+ BUILTIN_ROW(__sync_nand_and_fetch),
BUILTIN_ROW(__sync_val_compare_and_swap),
BUILTIN_ROW(__sync_bool_compare_and_swap),
@@ -1418,6 +1639,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// as the number of fixed args.
unsigned BuiltinID = FDecl->getBuiltinID();
unsigned BuiltinIndex, NumFixed = 1;
+ bool WarnAboutSemanticsChange = false;
switch (BuiltinID) {
default: llvm_unreachable("Unknown overloaded atomic builtin!");
case Builtin::BI__sync_fetch_and_add:
@@ -1465,13 +1687,23 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
BuiltinIndex = 4;
break;
+ case Builtin::BI__sync_fetch_and_nand:
+ case Builtin::BI__sync_fetch_and_nand_1:
+ case Builtin::BI__sync_fetch_and_nand_2:
+ case Builtin::BI__sync_fetch_and_nand_4:
+ case Builtin::BI__sync_fetch_and_nand_8:
+ case Builtin::BI__sync_fetch_and_nand_16:
+ BuiltinIndex = 5;
+ WarnAboutSemanticsChange = true;
+ break;
+
case Builtin::BI__sync_add_and_fetch:
case Builtin::BI__sync_add_and_fetch_1:
case Builtin::BI__sync_add_and_fetch_2:
case Builtin::BI__sync_add_and_fetch_4:
case Builtin::BI__sync_add_and_fetch_8:
case Builtin::BI__sync_add_and_fetch_16:
- BuiltinIndex = 5;
+ BuiltinIndex = 6;
break;
case Builtin::BI__sync_sub_and_fetch:
@@ -1480,7 +1712,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
case Builtin::BI__sync_sub_and_fetch_4:
case Builtin::BI__sync_sub_and_fetch_8:
case Builtin::BI__sync_sub_and_fetch_16:
- BuiltinIndex = 6;
+ BuiltinIndex = 7;
break;
case Builtin::BI__sync_and_and_fetch:
@@ -1489,7 +1721,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
case Builtin::BI__sync_and_and_fetch_4:
case Builtin::BI__sync_and_and_fetch_8:
case Builtin::BI__sync_and_and_fetch_16:
- BuiltinIndex = 7;
+ BuiltinIndex = 8;
break;
case Builtin::BI__sync_or_and_fetch:
@@ -1498,7 +1730,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
case Builtin::BI__sync_or_and_fetch_4:
case Builtin::BI__sync_or_and_fetch_8:
case Builtin::BI__sync_or_and_fetch_16:
- BuiltinIndex = 8;
+ BuiltinIndex = 9;
break;
case Builtin::BI__sync_xor_and_fetch:
@@ -1507,7 +1739,17 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
case Builtin::BI__sync_xor_and_fetch_4:
case Builtin::BI__sync_xor_and_fetch_8:
case Builtin::BI__sync_xor_and_fetch_16:
- BuiltinIndex = 9;
+ BuiltinIndex = 10;
+ break;
+
+ case Builtin::BI__sync_nand_and_fetch:
+ case Builtin::BI__sync_nand_and_fetch_1:
+ case Builtin::BI__sync_nand_and_fetch_2:
+ case Builtin::BI__sync_nand_and_fetch_4:
+ case Builtin::BI__sync_nand_and_fetch_8:
+ case Builtin::BI__sync_nand_and_fetch_16:
+ BuiltinIndex = 11;
+ WarnAboutSemanticsChange = true;
break;
case Builtin::BI__sync_val_compare_and_swap:
@@ -1516,7 +1758,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
case Builtin::BI__sync_val_compare_and_swap_4:
case Builtin::BI__sync_val_compare_and_swap_8:
case Builtin::BI__sync_val_compare_and_swap_16:
- BuiltinIndex = 10;
+ BuiltinIndex = 12;
NumFixed = 2;
break;
@@ -1526,7 +1768,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
case Builtin::BI__sync_bool_compare_and_swap_4:
case Builtin::BI__sync_bool_compare_and_swap_8:
case Builtin::BI__sync_bool_compare_and_swap_16:
- BuiltinIndex = 11;
+ BuiltinIndex = 13;
NumFixed = 2;
ResultType = Context.BoolTy;
break;
@@ -1537,7 +1779,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
case Builtin::BI__sync_lock_test_and_set_4:
case Builtin::BI__sync_lock_test_and_set_8:
case Builtin::BI__sync_lock_test_and_set_16:
- BuiltinIndex = 12;
+ BuiltinIndex = 14;
break;
case Builtin::BI__sync_lock_release:
@@ -1546,7 +1788,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
case Builtin::BI__sync_lock_release_4:
case Builtin::BI__sync_lock_release_8:
case Builtin::BI__sync_lock_release_16:
- BuiltinIndex = 13;
+ BuiltinIndex = 15;
NumFixed = 0;
ResultType = Context.VoidTy;
break;
@@ -1557,7 +1799,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
case Builtin::BI__sync_swap_4:
case Builtin::BI__sync_swap_8:
case Builtin::BI__sync_swap_16:
- BuiltinIndex = 14;
+ BuiltinIndex = 16;
break;
}
@@ -1570,6 +1812,11 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
return ExprError();
}
+ if (WarnAboutSemanticsChange) {
+ Diag(TheCall->getLocEnd(), diag::warn_sync_fetch_and_nand_semantics_change)
+ << TheCall->getCallee()->getSourceRange();
+ }
+
// Get the decl for the concrete builtin from this, we can tell what the
// concrete integer type we should convert to is.
unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
@@ -2031,7 +2278,46 @@ bool Sema::SemaBuiltinAssume(CallExpr *TheCall) {
if (Arg->HasSideEffects(Context))
return Diag(Arg->getLocStart(), diag::warn_assume_side_effects)
- << Arg->getSourceRange();
+ << Arg->getSourceRange()
+ << cast<FunctionDecl>(TheCall->getCalleeDecl())->getIdentifier();
+
+ return false;
+}
+
+/// Handle __builtin_assume_aligned. This is declared
+/// as (const void*, size_t, ...) and can take one optional constant int arg.
+bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) {
+ unsigned NumArgs = TheCall->getNumArgs();
+
+ if (NumArgs > 3)
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_many_args_at_most)
+ << 0 /*function call*/ << 3 << NumArgs
+ << TheCall->getSourceRange();
+
+ // The alignment must be a constant integer.
+ Expr *Arg = TheCall->getArg(1);
+
+ // We can't check the value of a dependent argument.
+ if (!Arg->isTypeDependent() && !Arg->isValueDependent()) {
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, 1, Result))
+ return true;
+
+ if (!Result.isPowerOf2())
+ return Diag(TheCall->getLocStart(),
+ diag::err_alignment_not_power_of_two)
+ << Arg->getSourceRange();
+ }
+
+ if (NumArgs > 2) {
+ ExprResult Arg(TheCall->getArg(2));
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
+ Context.getSizeType(), false);
+ Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
+ if (Arg.isInvalid()) return true;
+ TheCall->setArg(2, Arg.get());
+ }
return false;
}
@@ -3178,6 +3464,61 @@ static bool requiresParensToAddCast(const Expr *E) {
}
}
+static std::pair<QualType, StringRef>
+shouldNotPrintDirectly(const ASTContext &Context,
+ QualType IntendedTy,
+ const Expr *E) {
+ // Use a 'while' to peel off layers of typedefs.
+ QualType TyTy = IntendedTy;
+ while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
+ StringRef Name = UserTy->getDecl()->getName();
+ QualType CastTy = llvm::StringSwitch<QualType>(Name)
+ .Case("NSInteger", Context.LongTy)
+ .Case("NSUInteger", Context.UnsignedLongTy)
+ .Case("SInt32", Context.IntTy)
+ .Case("UInt32", Context.UnsignedIntTy)
+ .Default(QualType());
+
+ if (!CastTy.isNull())
+ return std::make_pair(CastTy, Name);
+
+ TyTy = UserTy->desugar();
+ }
+
+ // Strip parens if necessary.
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
+ return shouldNotPrintDirectly(Context,
+ PE->getSubExpr()->getType(),
+ PE->getSubExpr());
+
+ // If this is a conditional expression, then its result type is constructed
+ // via usual arithmetic conversions and thus there might be no necessary
+ // typedef sugar there. Recurse to operands to check for NSInteger &
+ // Co. usage condition.
+ if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ QualType TrueTy, FalseTy;
+ StringRef TrueName, FalseName;
+
+ std::tie(TrueTy, TrueName) =
+ shouldNotPrintDirectly(Context,
+ CO->getTrueExpr()->getType(),
+ CO->getTrueExpr());
+ std::tie(FalseTy, FalseName) =
+ shouldNotPrintDirectly(Context,
+ CO->getFalseExpr()->getType(),
+ CO->getFalseExpr());
+
+ if (TrueTy == FalseTy)
+ return std::make_pair(TrueTy, TrueName);
+ else if (TrueTy.isNull())
+ return std::make_pair(FalseTy, FalseName);
+ else if (FalseTy.isNull())
+ return std::make_pair(TrueTy, TrueName);
+ }
+
+ return std::make_pair(QualType(), StringRef());
+}
+
bool
CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
const char *StartSpecifier,
@@ -3269,25 +3610,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// Special-case some of Darwin's platform-independence types by suggesting
// casts to primitive types that are known to be large enough.
- bool ShouldNotPrintDirectly = false;
+ bool ShouldNotPrintDirectly = false; StringRef CastTyName;
if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
- // Use a 'while' to peel off layers of typedefs.
- QualType TyTy = IntendedTy;
- while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
- StringRef Name = UserTy->getDecl()->getName();
- QualType CastTy = llvm::StringSwitch<QualType>(Name)
- .Case("NSInteger", S.Context.LongTy)
- .Case("NSUInteger", S.Context.UnsignedLongTy)
- .Case("SInt32", S.Context.IntTy)
- .Case("UInt32", S.Context.UnsignedIntTy)
- .Default(QualType());
-
- if (!CastTy.isNull()) {
- ShouldNotPrintDirectly = true;
- IntendedTy = CastTy;
- break;
- }
- TyTy = UserTy->desugar();
+ QualType CastTy;
+ std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E);
+ if (!CastTy.isNull()) {
+ IntendedTy = CastTy;
+ ShouldNotPrintDirectly = true;
}
}
@@ -3304,7 +3633,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
- if (IntendedTy == ExprTy) {
+ if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) {
// In this case, the specifier is wrong and should be changed to match
// the argument.
EmitFormatDiagnostic(
@@ -3358,8 +3687,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// The expression has a type that should not be printed directly.
// We extract the name from the typedef because we don't want to show
// the underlying type in the diagnostic.
- StringRef Name = cast<TypedefType>(ExprTy)->getDecl()->getName();
-
+ StringRef Name;
+ if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(ExprTy))
+ Name = TypedefTy->getDecl()->getName();
+ else
+ Name = CastTyName;
EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast)
<< Name << IntendedTy << IsEnum
<< E->getSourceRange(),
@@ -3395,6 +3727,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
break;
case Sema::VAK_Undefined:
+ case Sema::VAK_MSVCUndefined:
EmitFormatDiagnostic(
S.PDiag(diag::warn_non_pod_vararg_with_format_string)
<< S.getLangOpts().CPlusPlus11
@@ -3672,6 +4005,20 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
} // TODO: handle other formats
}
+bool Sema::FormatStringHasSArg(const StringLiteral *FExpr) {
+ // Str - The format string. NOTE: this is NOT null-terminated!
+ StringRef StrRef = FExpr->getString();
+ const char *Str = StrRef.data();
+ // Account for cases where the string literal is truncated in a declaration.
+ const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType());
+ assert(T && "String literal not of constant array type!");
+ size_t TypeSize = T->getSize().getZExtValue();
+ size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size());
+ return analyze_format_string::ParseFormatStringHasSArg(Str, Str + StrLen,
+ getLangOpts(),
+ Context.getTargetInfo());
+}
+
//===--- CHECK: Warn on use of wrong absolute value function. -------------===//
// Returns the related absolute value function that is larger, of 0 if one
@@ -4346,7 +4693,8 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
IdentifierInfo *FnName) {
// Don't crash if the user has the wrong number of arguments
- if (Call->getNumArgs() != 3)
+ unsigned NumArgs = Call->getNumArgs();
+ if ((NumArgs != 3) && (NumArgs != 4))
return;
const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context);
@@ -4628,7 +4976,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
DeclRefExpr *DR = cast<DeclRefExpr>(E);
// If we leave the immediate function, the lifetime isn't about to end.
- if (DR->refersToEnclosingLocal())
+ if (DR->refersToEnclosingVariableOrCapture())
return nullptr;
if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
@@ -4795,7 +5143,7 @@ do {
DeclRefExpr *DR = cast<DeclRefExpr>(E);
// If we leave the immediate function, the lifetime isn't about to end.
- if (DR->refersToEnclosingLocal())
+ if (DR->refersToEnclosingVariableOrCapture())
return nullptr;
if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) {
@@ -5660,8 +6008,13 @@ static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
// The type the comparison is being performed in.
QualType T = E->getLHS()->getType();
- assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())
- && "comparison with mismatched types");
+
+ // Only analyze comparison operators where both sides have been converted to
+ // the same type.
+ if (!S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType()))
+ return AnalyzeImpConvsInComparison(S, E);
+
+ // Don't analyze value-dependent comparisons directly.
if (E->isValueDependent())
return AnalyzeImpConvsInComparison(S, E);
@@ -5932,6 +6285,41 @@ void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall,
}
}
+static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
+ SourceLocation CC) {
+ if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer,
+ E->getExprLoc()))
+ return;
+
+ // Check for NULL (GNUNull) or nullptr (CXX11_nullptr).
+ const Expr::NullPointerConstantKind NullKind =
+ E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull);
+ if (NullKind != Expr::NPCK_GNUNull && NullKind != Expr::NPCK_CXX11_nullptr)
+ return;
+
+ // Return if target type is a safe conversion.
+ if (T->isAnyPointerType() || T->isBlockPointerType() ||
+ T->isMemberPointerType() || !T->isScalarType() || T->isNullPtrType())
+ return;
+
+ SourceLocation Loc = E->getSourceRange().getBegin();
+
+ // __null is usually wrapped in a macro. Go up a macro if that is the case.
+ if (NullKind == Expr::NPCK_GNUNull) {
+ if (Loc.isMacroID())
+ Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
+ }
+
+ // Only warn if the null and context location are in the same macro expansion.
+ if (S.SourceMgr.getFileID(Loc) != S.SourceMgr.getFileID(CC))
+ return;
+
+ S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
+ << (NullKind == Expr::NPCK_CXX11_nullptr) << T << clang::SourceRange(CC)
+ << FixItHint::CreateReplacement(Loc,
+ S.getFixItZeroLiteralForType(T, Loc));
+}
+
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool *ICContext = nullptr) {
if (E->isTypeDependent() || E->isValueDependent()) return;
@@ -6074,19 +6462,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
}
- if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
- == Expr::NPCK_GNUNull) && !Target->isAnyPointerType()
- && !Target->isBlockPointerType() && !Target->isMemberPointerType()
- && Target->isScalarType() && !Target->isNullPtrType()) {
- SourceLocation Loc = E->getSourceRange().getBegin();
- if (Loc.isMacroID())
- Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
- if (!Loc.isMacroID() || CC.isMacroID())
- S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
- << T << clang::SourceRange(CC)
- << FixItHint::CreateReplacement(Loc,
- S.getFixItZeroLiteralForType(T, Loc));
- }
+ DiagnoseNullConversion(S, E, T, CC);
if (!Source->isIntegerType() || !Target->isIntegerType())
return;
@@ -6196,7 +6572,7 @@ void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
SourceLocation CC, QualType T) {
- AnalyzeImplicitConversions(S, E->getCond(), CC);
+ AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc());
bool Suspicious = false;
CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious);
@@ -6222,6 +6598,14 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
E->getType(), CC, &Suspicious);
}
+/// CheckBoolLikeConversion - Check conversion of given expression to boolean.
+/// Input argument E is a logical expression.
+static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
+ if (S.getLangOpts().Bool)
+ return;
+ CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC);
+}
+
/// AnalyzeImplicitConversions - Find and report any interesting
/// implicit conversions in the given expression. There are a couple
/// of competing diagnostics here, -Wconversion and -Wsign-compare.
@@ -6301,6 +6685,20 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
continue;
AnalyzeImplicitConversions(S, ChildExpr, CC);
}
+
+ if (BO && BO->isLogicalOp()) {
+ Expr *SubExpr = BO->getLHS()->IgnoreParenImpCasts();
+ if (!IsLogicalAndOperator || !isa<StringLiteral>(SubExpr))
+ ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc());
+
+ SubExpr = BO->getRHS()->IgnoreParenImpCasts();
+ if (!IsLogicalAndOperator || !isa<StringLiteral>(SubExpr))
+ ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc());
+ }
+
+ if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E))
+ if (U->getOpcode() == UO_LNot)
+ ::CheckBoolLikeConversion(S, U->getSubExpr(), CC);
}
} // end anonymous namespace
@@ -6343,6 +6741,22 @@ static bool CheckForReference(Sema &SemaRef, const Expr *E,
return true;
}
+// Returns true if the SourceLocation is expanded from any macro body.
+// Returns false if the SourceLocation is invalid, is from not in a macro
+// expansion, or is from expanded from a top-level macro argument.
+static bool IsInAnyMacroBody(const SourceManager &SM, SourceLocation Loc) {
+ if (Loc.isInvalid())
+ return false;
+
+ while (Loc.isMacroID()) {
+ if (SM.isMacroBodyExpansion(Loc))
+ return true;
+ Loc = SM.getImmediateMacroCallerLoc(Loc);
+ }
+
+ return false;
+}
+
/// \brief Diagnose pointers that are always non-null.
/// \param E the expression containing the pointer
/// \param NullKind NPCK_NotNull if E is a cast to bool, otherwise, E is
@@ -6356,8 +6770,12 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
return;
// Don't warn inside macros.
- if (E->getExprLoc().isMacroID())
+ if (E->getExprLoc().isMacroID()) {
+ const SourceManager &SM = getSourceManager();
+ if (IsInAnyMacroBody(SM, E->getExprLoc()) ||
+ IsInAnyMacroBody(SM, Range.getBegin()))
return;
+ }
E = E->IgnoreImpCasts();
const bool IsCompare = NullKind != Expr::NPCK_NotNull;
@@ -6400,7 +6818,40 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
// Weak Decls can be null.
if (!D || D->isWeak())
return;
-
+
+ // Check for parameter decl with nonnull attribute
+ if (const ParmVarDecl* PV = dyn_cast<ParmVarDecl>(D)) {
+ if (getCurFunction() && !getCurFunction()->ModifiedNonNullParams.count(PV))
+ if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
+ unsigned NumArgs = FD->getNumParams();
+ llvm::SmallBitVector AttrNonNull(NumArgs);
+ for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
+ if (!NonNull->args_size()) {
+ AttrNonNull.set(0, NumArgs);
+ break;
+ }
+ for (unsigned Val : NonNull->args()) {
+ if (Val >= NumArgs)
+ continue;
+ AttrNonNull.set(Val);
+ }
+ }
+ if (!AttrNonNull.empty())
+ for (unsigned i = 0; i < NumArgs; ++i)
+ if (FD->getParamDecl(i) == PV &&
+ (AttrNonNull[i] || PV->hasAttr<NonNullAttr>())) {
+ std::string Str;
+ llvm::raw_string_ostream S(Str);
+ E->printPretty(S, nullptr, getPrintingPolicy());
+ unsigned DiagID = IsCompare ? diag::warn_nonnull_parameter_compare
+ : diag::warn_cast_nonnull_to_bool;
+ Diag(E->getExprLoc(), DiagID) << S.str() << E->getSourceRange()
+ << Range << IsEqual;
+ return;
+ }
+ }
+ }
+
QualType T = D->getType();
const bool IsArray = T->isArrayType();
const bool IsFunction = T->isFunctionType();
@@ -6496,11 +6947,17 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
AnalyzeImplicitConversions(*this, E, CC);
}
+/// CheckBoolLikeConversion - Check conversion of given expression to boolean.
+/// Input argument E is a logical expression.
+void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) {
+ ::CheckBoolLikeConversion(*this, E, CC);
+}
+
/// Diagnose when expression is an integer constant expression and its evaluation
/// results in integer overflow
void Sema::CheckForIntOverflow (Expr *E) {
- if (isa<BinaryOperator>(E->IgnoreParens()))
- E->EvaluateForOverflow(Context);
+ if (isa<BinaryOperator>(E->IgnoreParenCasts()))
+ E->IgnoreParenCasts()->EvaluateForOverflow(Context);
}
namespace {
@@ -6630,11 +7087,12 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
Self.ModAsSideEffect = &ModAsSideEffect;
}
~SequencedSubexpression() {
- for (unsigned I = 0, E = ModAsSideEffect.size(); I != E; ++I) {
- UsageInfo &U = Self.UsageMap[ModAsSideEffect[I].first];
- U.Uses[UK_ModAsSideEffect] = ModAsSideEffect[I].second;
- Self.addUsage(U, ModAsSideEffect[I].first,
- ModAsSideEffect[I].second.Use, UK_ModAsValue);
+ for (auto MI = ModAsSideEffect.rbegin(), ME = ModAsSideEffect.rend();
+ MI != ME; ++MI) {
+ UsageInfo &U = Self.UsageMap[MI->first];
+ auto &SideEffectUsage = U.Uses[UK_ModAsSideEffect];
+ Self.addUsage(U, MI->first, SideEffectUsage.Use, UK_ModAsValue);
+ SideEffectUsage = MI->second;
}
Self.ModAsSideEffect = OldModAsSideEffect;
}
@@ -7867,6 +8325,96 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S,
}
}
+//===--- CHECK: Warn on self move with std::move. -------------------------===//
+
+/// DiagnoseSelfMove - Emits a warning if a value is moved to itself.
+void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
+ SourceLocation OpLoc) {
+
+ if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc))
+ return;
+
+ if (!ActiveTemplateInstantiations.empty())
+ return;
+
+ // Strip parens and casts away.
+ LHSExpr = LHSExpr->IgnoreParenImpCasts();
+ RHSExpr = RHSExpr->IgnoreParenImpCasts();
+
+ // Check for a call expression
+ const CallExpr *CE = dyn_cast<CallExpr>(RHSExpr);
+ if (!CE || CE->getNumArgs() != 1)
+ return;
+
+ // Check for a call to std::move
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD || !FD->isInStdNamespace() || !FD->getIdentifier() ||
+ !FD->getIdentifier()->isStr("move"))
+ return;
+
+ // Get argument from std::move
+ RHSExpr = CE->getArg(0);
+
+ const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr);
+ const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr);
+
+ // Two DeclRefExpr's, check that the decls are the same.
+ if (LHSDeclRef && RHSDeclRef) {
+ if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl())
+ return;
+ if (LHSDeclRef->getDecl()->getCanonicalDecl() !=
+ RHSDeclRef->getDecl()->getCanonicalDecl())
+ return;
+
+ Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType()
+ << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
+ return;
+ }
+
+ // Member variables require a different approach to check for self moves.
+ // MemberExpr's are the same if every nested MemberExpr refers to the same
+ // Decl and that the base Expr's are DeclRefExpr's with the same Decl or
+ // the base Expr's are CXXThisExpr's.
+ const Expr *LHSBase = LHSExpr;
+ const Expr *RHSBase = RHSExpr;
+ const MemberExpr *LHSME = dyn_cast<MemberExpr>(LHSExpr);
+ const MemberExpr *RHSME = dyn_cast<MemberExpr>(RHSExpr);
+ if (!LHSME || !RHSME)
+ return;
+
+ while (LHSME && RHSME) {
+ if (LHSME->getMemberDecl()->getCanonicalDecl() !=
+ RHSME->getMemberDecl()->getCanonicalDecl())
+ return;
+
+ LHSBase = LHSME->getBase();
+ RHSBase = RHSME->getBase();
+ LHSME = dyn_cast<MemberExpr>(LHSBase);
+ RHSME = dyn_cast<MemberExpr>(RHSBase);
+ }
+
+ LHSDeclRef = dyn_cast<DeclRefExpr>(LHSBase);
+ RHSDeclRef = dyn_cast<DeclRefExpr>(RHSBase);
+ if (LHSDeclRef && RHSDeclRef) {
+ if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl())
+ return;
+ if (LHSDeclRef->getDecl()->getCanonicalDecl() !=
+ RHSDeclRef->getDecl()->getCanonicalDecl())
+ return;
+
+ Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType()
+ << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
+ return;
+ }
+
+ if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase))
+ Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType()
+ << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
+}
+
//===--- Layout compatibility ----------------------------------------------//
namespace {
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 3d250e3bef11..48bdd2a7d82c 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -292,7 +292,7 @@ namespace {
void MaybeAddResult(Result R, DeclContext *CurContext = nullptr);
/// \brief Add a new result to this result set, where we already know
- /// the hiding declation (if any).
+ /// the hiding declaration (if any).
///
/// \param R the result to add (if it is unique).
///
@@ -894,7 +894,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
}
// Make sure that any given declaration only shows up in the result set once.
- if (!AllDeclsFound.insert(CanonDecl))
+ if (!AllDeclsFound.insert(CanonDecl).second)
return;
// If the filter is for nested-name-specifiers, then this result starts a
@@ -957,7 +957,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
return;
// Make sure that any given declaration only shows up in the result set once.
- if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl()))
+ if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl()).second)
return;
// If the filter is for nested-name-specifiers, then this result starts a
@@ -2575,11 +2575,12 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
const MacroDirective *MD = PP.getMacroDirectiveHistory(Macro);
assert(MD && "Not a macro?");
const MacroInfo *MI = MD->getMacroInfo();
+ assert((!MD->isDefined() || MI) && "missing MacroInfo for define");
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(Macro->getName()));
- if (!MI->isFunctionLike())
+ if (!MI || !MI->isFunctionLike())
return Result.TakeString();
// Format a function-like macro with placeholders for the arguments.
@@ -3466,7 +3467,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
// Add properties in this container.
for (const auto *P : Container->properties())
- if (AddedProperties.insert(P->getIdentifier()))
+ if (AddedProperties.insert(P->getIdentifier()).second)
Results.MaybeAddResult(Result(P, Results.getBasePriority(P), nullptr),
CurContext);
@@ -3477,7 +3478,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
for (auto *M : Container->methods()) {
if (M->getSelector().isUnarySelector())
if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0))
- if (AddedProperties.insert(Name)) {
+ if (AddedProperties.insert(Name).second) {
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
AddResultTypeChunk(Context, Policy, M, Builder);
@@ -4235,7 +4236,8 @@ void Sema::CodeCompleteConstructorInitializer(
bool SawLastInitializer = Initializers.empty();
CXXRecordDecl *ClassDecl = Constructor->getParent();
for (const auto &Base : ClassDecl->bases()) {
- if (!InitializedBases.insert(Context.getCanonicalType(Base.getType()))) {
+ if (!InitializedBases.insert(Context.getCanonicalType(Base.getType()))
+ .second) {
SawLastInitializer
= !Initializers.empty() &&
Initializers.back()->isBaseInitializer() &&
@@ -4258,7 +4260,8 @@ void Sema::CodeCompleteConstructorInitializer(
// Add completions for virtual base classes.
for (const auto &Base : ClassDecl->vbases()) {
- if (!InitializedBases.insert(Context.getCanonicalType(Base.getType()))) {
+ if (!InitializedBases.insert(Context.getCanonicalType(Base.getType()))
+ .second) {
SawLastInitializer
= !Initializers.empty() &&
Initializers.back()->isBaseInitializer() &&
@@ -4281,7 +4284,8 @@ void Sema::CodeCompleteConstructorInitializer(
// Add completions for members.
for (auto *Field : ClassDecl->fields()) {
- if (!InitializedFields.insert(cast<FieldDecl>(Field->getCanonicalDecl()))) {
+ if (!InitializedFields.insert(cast<FieldDecl>(Field->getCanonicalDecl()))
+ .second) {
SawLastInitializer
= !Initializers.empty() &&
Initializers.back()->isAnyMemberInitializer() &&
@@ -4348,7 +4352,7 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
Var->hasAttr<BlocksAttr>())
continue;
- if (Known.insert(Var->getIdentifier()))
+ if (Known.insert(Var->getIdentifier()).second)
Results.AddResult(CodeCompletionResult(Var, CCP_LocalDeclaration),
CurContext, nullptr, false);
}
@@ -4817,7 +4821,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
if (!isAcceptableObjCMethod(M, WantKind, SelIdents, AllowSameLength))
continue;
- if (!Selectors.insert(M->getSelector()))
+ if (!Selectors.insert(M->getSelector()).second)
continue;
Result R = Result(M, Results.getBasePriority(M), nullptr);
@@ -5400,13 +5404,13 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
MEnd = SemaRef.MethodPool.end();
M != MEnd; ++M) {
for (ObjCMethodList *MethList = &M->second.second;
- MethList && MethList->Method;
+ MethList && MethList->getMethod();
MethList = MethList->getNext()) {
- if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents))
+ if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents))
continue;
- Result R(MethList->Method, Results.getBasePriority(MethList->Method),
- nullptr);
+ Result R(MethList->getMethod(),
+ Results.getBasePriority(MethList->getMethod()), nullptr);
R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = false;
Results.MaybeAddResult(R, SemaRef.CurContext);
@@ -5573,16 +5577,16 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
MEnd = MethodPool.end();
M != MEnd; ++M) {
for (ObjCMethodList *MethList = &M->second.first;
- MethList && MethList->Method;
+ MethList && MethList->getMethod();
MethList = MethList->getNext()) {
- if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents))
+ if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents))
continue;
- if (!Selectors.insert(MethList->Method->getSelector()))
+ if (!Selectors.insert(MethList->getMethod()->getSelector()).second)
continue;
- Result R(MethList->Method, Results.getBasePriority(MethList->Method),
- nullptr);
+ Result R(MethList->getMethod(),
+ Results.getBasePriority(MethList->getMethod()), nullptr);
R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = false;
Results.MaybeAddResult(R, CurContext);
@@ -5858,7 +5862,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
for (const auto *D : TU->decls())
if (const auto *Category = dyn_cast<ObjCCategoryDecl>(D))
- if (CategoryNames.insert(Category->getIdentifier()))
+ if (CategoryNames.insert(Category->getIdentifier()).second)
Results.AddResult(Result(Category, Results.getBasePriority(Category),
nullptr),
CurContext, nullptr, false);
@@ -5896,7 +5900,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
while (Class) {
for (const auto *Cat : Class->visible_categories()) {
if ((!IgnoreImplemented || !Cat->getImplementation()) &&
- CategoryNames.insert(Cat->getIdentifier()))
+ CategoryNames.insert(Cat->getIdentifier()).second)
Results.AddResult(Result(Cat, Results.getBasePriority(Cat), nullptr),
CurContext, nullptr, false);
}
@@ -6217,7 +6221,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// Add the normal accessor -(type)key.
if (IsInstanceMethod &&
- KnownSelectors.insert(Selectors.getNullarySelector(PropName)) &&
+ KnownSelectors.insert(Selectors.getNullarySelector(PropName)).second &&
ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) {
if (ReturnType.isNull())
AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0,
@@ -6238,7 +6242,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
Property->getType()->isBooleanType())))) {
std::string SelectorName = (Twine("is") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))
+ .second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("BOOL");
@@ -6257,7 +6262,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
!Property->getSetterMethodDecl()) {
std::string SelectorName = (Twine("set") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6309,7 +6314,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
(ReturnType.isNull() || ReturnType->isIntegerType())) {
std::string SelectorName = (Twine("countOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))
+ .second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSUInteger");
@@ -6332,7 +6338,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (Twine("objectIn") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("id");
@@ -6359,7 +6365,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (Twine(Property->getName()) + "AtIndexes").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSArray *");
@@ -6384,7 +6390,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("range")
};
- if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6418,7 +6424,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get(SelectorName)
};
- if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6450,7 +6456,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("atIndexes")
};
- if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6478,7 +6484,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (Twine("removeObjectFrom") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6500,7 +6506,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (Twine("remove") + UpperKey + "AtIndexes").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6526,7 +6532,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("withObject")
};
- if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6559,7 +6565,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get(SelectorName2)
};
- if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6592,7 +6598,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
->getName() == "NSEnumerator"))) {
std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))
+ .second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSEnumerator *");
@@ -6610,7 +6617,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
(ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) {
std::string SelectorName = (Twine("memberOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("object-type");
@@ -6641,7 +6648,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (Twine("add") + UpperKey + Twine("Object")).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6663,7 +6670,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (Twine("add") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6685,7 +6692,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (Twine("remove") + UpperKey + Twine("Object")).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6707,7 +6714,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (Twine("remove") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6728,7 +6735,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (Twine("intersect") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6756,7 +6763,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (Twine("keyPathsForValuesAffecting") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))
+ .second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSSet *");
@@ -6777,7 +6785,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (Twine("automaticallyNotifiesObserversOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))
+ .second) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("BOOL");
@@ -6985,16 +6994,18 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
M != MEnd; ++M) {
for (ObjCMethodList *MethList = IsInstanceMethod ? &M->second.first :
&M->second.second;
- MethList && MethList->Method;
+ MethList && MethList->getMethod();
MethList = MethList->getNext()) {
- if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents))
+ if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents))
continue;
if (AtParameterName) {
// Suggest parameter names we've seen before.
unsigned NumSelIdents = SelIdents.size();
- if (NumSelIdents && NumSelIdents <= MethList->Method->param_size()) {
- ParmVarDecl *Param = MethList->Method->parameters()[NumSelIdents-1];
+ if (NumSelIdents &&
+ NumSelIdents <= MethList->getMethod()->param_size()) {
+ ParmVarDecl *Param =
+ MethList->getMethod()->parameters()[NumSelIdents - 1];
if (Param->getIdentifier()) {
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
@@ -7007,8 +7018,8 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
continue;
}
- Result R(MethList->Method, Results.getBasePriority(MethList->Method),
- nullptr);
+ Result R(MethList->getMethod(),
+ Results.getBasePriority(MethList->getMethod()), nullptr);
R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = false;
R.DeclaringEntity = true;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 87162273bbe6..007470344f19 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -152,7 +152,10 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
auto *TD = TST->getTemplateName().getAsTemplateDecl();
if (!TD)
continue;
- auto *BasePrimaryTemplate = cast<CXXRecordDecl>(TD->getTemplatedDecl());
+ auto *BasePrimaryTemplate =
+ dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl());
+ if (!BasePrimaryTemplate)
+ continue;
// FIXME: Allow lookup into non-dependent bases of dependent bases, possibly
// by calling or integrating with the main LookupQualifiedName mechanism.
for (NamedDecl *ND : BasePrimaryTemplate->lookup(&II)) {
@@ -283,10 +286,10 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (CorrectedII) {
- TypeNameValidatorCCC Validator(true, isClassName);
- TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(),
- Kind, S, SS, Validator,
- CTK_ErrorRecovery);
+ TypoCorrection Correction = CorrectTypo(
+ Result.getLookupNameInfo(), Kind, S, SS,
+ llvm::make_unique<TypeNameValidatorCCC>(true, isClassName),
+ CTK_ErrorRecovery);
IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
TemplateTy Template;
bool MemberOfUnknownSpecialization;
@@ -377,6 +380,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
DiagnoseUseOfDecl(IIDecl, NameLoc);
T = Context.getTypeDeclType(TD);
+ MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
// NOTE: avoid constructing an ElaboratedType(Loc) if this is a
// constructor or destructor name (in such a case, the scope specifier
@@ -494,6 +498,9 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
/// @endcode
bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) {
if (CurContext->isRecord()) {
+ if (SS->getScopeRep()->getKind() == NestedNameSpecifier::Super)
+ return true;
+
const Type *Ty = SS->getScopeRep()->getAsType();
CXXRecordDecl *RD = cast<CXXRecordDecl>(CurContext);
@@ -516,10 +523,11 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
// There may have been a typo in the name of the type. Look up typo
// results, in case we have something that we can suggest.
- TypeNameValidatorCCC Validator(false, false, AllowClassTemplates);
- if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc),
- LookupOrdinaryName, S, SS,
- Validator, CTK_ErrorRecovery)) {
+ if (TypoCorrection Corrected =
+ CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS,
+ llvm::make_unique<TypeNameValidatorCCC>(
+ false, false, AllowClassTemplates),
+ CTK_ErrorRecovery)) {
if (Corrected.isKeyword()) {
// We corrected to a keyword.
diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II);
@@ -679,13 +687,11 @@ static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS,
return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
}
-Sema::NameClassification Sema::ClassifyName(Scope *S,
- CXXScopeSpec &SS,
- IdentifierInfo *&Name,
- SourceLocation NameLoc,
- const Token &NextToken,
- bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC) {
+Sema::NameClassification
+Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
+ SourceLocation NameLoc, const Token &NextToken,
+ bool IsAddressOfOperand,
+ std::unique_ptr<CorrectionCandidateCallback> CCC) {
DeclarationNameInfo NameInfo(Name, NameLoc);
ObjCMethodDecl *CurMethod = getCurMethodDecl();
@@ -762,7 +768,7 @@ Corrected:
SecondTry = true;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S,
- &SS, *CCC,
+ &SS, std::move(CCC),
CTK_ErrorRecovery)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
@@ -925,6 +931,7 @@ Corrected:
NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl();
if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
DiagnoseUseOfDecl(Type, NameLoc);
+ MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
QualType T = Context.getTypeDeclType(Type);
if (SS.isNotEmpty())
return buildNestedType(*this, SS, T, NameLoc);
@@ -1392,10 +1399,22 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
if (isa<LabelDecl>(D))
return true;
+
+ // Except for labels, we only care about unused decls that are local to
+ // functions.
+ bool WithinFunction = D->getDeclContext()->isFunctionOrMethod();
+ if (const auto *R = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
+ // For dependent types, the diagnostic is deferred.
+ WithinFunction =
+ WithinFunction || (R->isLocalClass() && !R->isDependentType());
+ if (!WithinFunction)
+ return false;
+
+ if (isa<TypedefNameDecl>(D))
+ return true;
// White-list anything that isn't a local variable.
- if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ||
- !D->getDeclContext()->isFunctionOrMethod())
+ if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D))
return false;
// Types of valid local variables should be complete, so this should succeed.
@@ -1458,11 +1477,30 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx,
return;
}
+void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) {
+ if (D->getTypeForDecl()->isDependentType())
+ return;
+
+ for (auto *TmpD : D->decls()) {
+ if (const auto *T = dyn_cast<TypedefNameDecl>(TmpD))
+ DiagnoseUnusedDecl(T);
+ else if(const auto *R = dyn_cast<RecordDecl>(TmpD))
+ DiagnoseUnusedNestedTypedefs(R);
+ }
+}
+
/// DiagnoseUnusedDecl - Emit warnings about declarations that are not used
/// unless they are marked attr(unused).
void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
if (!ShouldDiagnoseUnusedDecl(D))
return;
+
+ if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
+ // typedefs can be referenced later on, so the diagnostics are emitted
+ // at end-of-translation-unit.
+ UnusedLocalTypedefNameCandidates.insert(TD);
+ return;
+ }
FixItHint Hint;
GenerateFixForUnusedDecl(D, Context, Hint);
@@ -1481,8 +1519,14 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
// Verify that we have no forward references left. If so, there was a goto
// or address of a label taken, but no definition of it. Label fwd
- // definitions are indicated with a null substmt.
- if (L->getStmt() == nullptr)
+ // definitions are indicated with a null substmt which is also not a resolved
+ // MS inline assembly label name.
+ bool Diagnose = false;
+ if (L->isMSAsmLabel())
+ Diagnose = !L->isResolvedMSAsmLabel();
+ else
+ Diagnose = L->getStmt() == nullptr;
+ if (Diagnose)
S.Diag(L->getLocation(), diag::err_undeclared_label_use) <<L->getDeclName();
}
@@ -1502,8 +1546,11 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (!D->getDeclName()) continue;
// Diagnose unused variables in this scope.
- if (!S->hasUnrecoverableErrorOccurred())
+ if (!S->hasUnrecoverableErrorOccurred()) {
DiagnoseUnusedDecl(D);
+ if (const auto *RD = dyn_cast<RecordDecl>(D))
+ DiagnoseUnusedNestedTypedefs(RD);
+ }
// If this was a forward reference to a label, verify it was defined.
if (LabelDecl *LD = dyn_cast<LabelDecl>(D))
@@ -1537,10 +1584,10 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
if (!IDecl && DoTypoCorrection) {
// Perform typo correction at the given location, but only if we
// find an Objective-C class name.
- DeclFilterCCC<ObjCInterfaceDecl> Validator;
- if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc),
- LookupOrdinaryName, TUScope, nullptr,
- Validator, CTK_ErrorRecovery)) {
+ if (TypoCorrection C = CorrectTypo(
+ DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName, TUScope, nullptr,
+ llvm::make_unique<DeclFilterCCC<ObjCInterfaceDecl>>(),
+ CTK_ErrorRecovery)) {
diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id);
IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>();
Id = IDecl->getIdentifier();
@@ -1620,32 +1667,30 @@ static StringRef getHeaderName(ASTContext::GetBuiltinTypeError Error) {
/// file scope. lazily create a decl for it. ForRedeclaration is true
/// if we're creating this built-in in anticipation of redeclaring the
/// built-in.
-NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
+NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
Scope *S, bool ForRedeclaration,
SourceLocation Loc) {
LookupPredefedObjCSuperType(*this, S, II);
-
- Builtin::ID BID = (Builtin::ID)bid;
ASTContext::GetBuiltinTypeError Error;
- QualType R = Context.GetBuiltinType(BID, Error);
+ QualType R = Context.GetBuiltinType(ID, Error);
if (Error) {
if (ForRedeclaration)
Diag(Loc, diag::warn_implicit_decl_requires_sysheader)
<< getHeaderName(Error)
- << Context.BuiltinInfo.GetName(BID);
+ << Context.BuiltinInfo.GetName(ID);
return nullptr;
}
- if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
+ if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(ID)) {
Diag(Loc, diag::ext_implicit_lib_function_decl)
- << Context.BuiltinInfo.GetName(BID)
+ << Context.BuiltinInfo.GetName(ID)
<< R;
- if (Context.BuiltinInfo.getHeaderName(BID) &&
+ if (Context.BuiltinInfo.getHeaderName(ID) &&
!Diags.isIgnored(diag::ext_implicit_lib_function_decl, Loc))
Diag(Loc, diag::note_include_header_or_declare)
- << Context.BuiltinInfo.getHeaderName(BID)
- << Context.BuiltinInfo.GetName(BID);
+ << Context.BuiltinInfo.getHeaderName(ID)
+ << Context.BuiltinInfo.GetName(ID);
}
DeclContext *Parent = Context.getTranslationUnitDecl();
@@ -1725,6 +1770,43 @@ static void filterNonConflictingPreviousDecls(ASTContext &context,
filter.done();
}
+/// Typedef declarations don't have linkage, but they still denote the same
+/// entity if their types are the same.
+/// FIXME: This is notionally doing the same thing as ASTReaderDecl's
+/// isSameEntity.
+static void filterNonConflictingPreviousTypedefDecls(ASTContext &Context,
+ TypedefNameDecl *Decl,
+ LookupResult &Previous) {
+ // This is only interesting when modules are enabled.
+ if (!Context.getLangOpts().Modules)
+ return;
+
+ // Empty sets are uninteresting.
+ if (Previous.empty())
+ return;
+
+ LookupResult::Filter Filter = Previous.makeFilter();
+ while (Filter.hasNext()) {
+ NamedDecl *Old = Filter.next();
+
+ // Non-hidden declarations are never ignored.
+ if (!Old->isHidden())
+ continue;
+
+ // Declarations of the same entity are not ignored, even if they have
+ // different linkages.
+ if (auto *OldTD = dyn_cast<TypedefNameDecl>(Old))
+ if (Context.hasSameType(OldTD->getUnderlyingType(),
+ Decl->getUnderlyingType()))
+ continue;
+
+ if (!Old->isExternallyVisible())
+ Filter.erase();
+ }
+
+ Filter.done();
+}
+
bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
QualType OldType;
if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
@@ -2072,6 +2154,14 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(),
AttrSpellingListIndex,
IA->getSemanticSpelling());
+ else if (const auto *AA = dyn_cast<AlwaysInlineAttr>(Attr))
+ NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(),
+ &S.Context.Idents.get(AA->getSpelling()),
+ AttrSpellingListIndex);
+ else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr))
+ NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex);
+ else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr))
+ NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex);
else if (isa<AlignedAttr>(Attr))
// AlignedAttrs are handled separately, because we need to handle all
// such attributes on a declaration at the same time.
@@ -3149,8 +3239,15 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
}
// Merge the types.
- MergeVarDeclTypes(New, Old, mergeTypeWithPrevious(*this, New, Old, Previous));
+ VarDecl *MostRecent = Old->getMostRecentDecl();
+ if (MostRecent != Old) {
+ MergeVarDeclTypes(New, MostRecent,
+ mergeTypeWithPrevious(*this, New, MostRecent, Previous));
+ if (New->isInvalidDecl())
+ return;
+ }
+ MergeVarDeclTypes(New, Old, mergeTypeWithPrevious(*this, New, Old, Previous));
if (New->isInvalidDecl())
return;
@@ -3195,12 +3292,12 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
// Check if extern is followed by non-extern and vice-versa.
if (New->hasExternalStorage() &&
- !Old->hasLinkage() && Old->isLocalVarDecl()) {
+ !Old->hasLinkage() && Old->isLocalVarDeclOrParm()) {
Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName();
Diag(OldLocation, PrevDiag);
return New->setInvalidDecl();
}
- if (Old->hasLinkage() && New->isLocalVarDecl() &&
+ if (Old->hasLinkage() && New->isLocalVarDeclOrParm() &&
!New->hasExternalStorage()) {
Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName();
Diag(OldLocation, PrevDiag);
@@ -3407,21 +3504,39 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
}
- // Check for Microsoft C extension: anonymous struct member.
- if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus &&
- CurContext->isRecord() &&
+ // C11 6.7.2.1p2:
+ // A struct-declaration that does not declare an anonymous structure or
+ // anonymous union shall contain a struct-declarator-list.
+ //
+ // This rule also existed in C89 and C99; the grammar for struct-declaration
+ // did not permit a struct-declaration without a struct-declarator-list.
+ if (!getLangOpts().CPlusPlus && CurContext->isRecord() &&
DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
- // Handle 2 kinds of anonymous struct:
+ // Check for Microsoft C extension: anonymous struct/union member.
+ // Handle 2 kinds of anonymous struct/union:
// struct STRUCT;
+ // union UNION;
// and
// STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct.
- RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag);
- if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) ||
- (DS.getTypeSpecType() == DeclSpec::TST_typename &&
- DS.getRepAsType().get()->isStructureType())) {
- Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct)
- << DS.getSourceRange();
- return BuildMicrosoftCAnonymousStruct(S, DS, Record);
+ // UNION_TYPE; <- where UNION_TYPE is a typedef union.
+ if ((Tag && Tag->getDeclName()) ||
+ DS.getTypeSpecType() == DeclSpec::TST_typename) {
+ RecordDecl *Record = nullptr;
+ if (Tag)
+ Record = dyn_cast<RecordDecl>(Tag);
+ else if (const RecordType *RT =
+ DS.getRepAsType().get()->getAsStructureType())
+ Record = RT->getDecl();
+ else if (const RecordType *UT = DS.getRepAsType().get()->getAsUnionType())
+ Record = UT->getDecl();
+
+ if (Record && getLangOpts().MicrosoftExt) {
+ Diag(DS.getLocStart(), diag::ext_ms_anonymous_record)
+ << Record->isUnion() << DS.getSourceRange();
+ return BuildMicrosoftCAnonymousStruct(S, DS, Record);
+ }
+
+ DeclaresAnything = false;
}
}
@@ -3622,10 +3737,12 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S,
for (unsigned i = 0; i < Chaining.size(); i++)
NamedChain[i] = Chaining[i];
- IndirectFieldDecl* IndirectField =
- IndirectFieldDecl::Create(SemaRef.Context, Owner, VD->getLocation(),
- VD->getIdentifier(), VD->getType(),
- NamedChain, Chaining.size());
+ IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create(
+ SemaRef.Context, Owner, VD->getLocation(), VD->getIdentifier(),
+ VD->getType(), NamedChain, Chaining.size());
+
+ for (const auto *Attr : VD->attrs())
+ IndirectField->addAttr(Attr->clone(SemaRef.Context));
IndirectField->setAccess(AS);
IndirectField->setImplicit();
@@ -3893,7 +4010,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
FieldCollector->Add(cast<FieldDecl>(Anon));
} else {
DeclSpec::SCS SCSpec = DS.getStorageClassSpec();
- VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(DS);
+ StorageClass SC = StorageClassSpecToVarDeclStorageClass(DS);
if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
@@ -3962,28 +4079,28 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
///
/// void foo() {
/// B var;
-/// var.a = 3;
+/// var.a = 3;
/// }
///
Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
RecordDecl *Record) {
-
- // If there is no Record, get the record via the typedef.
- if (!Record)
- Record = DS.getRepAsType().get()->getAsStructureType()->getDecl();
+ assert(Record && "expected a record!");
// Mock up a declarator.
Declarator Dc(DS, Declarator::TypeNameContext);
TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
assert(TInfo && "couldn't build declarator info for anonymous struct");
+ auto *ParentDecl = cast<RecordDecl>(CurContext);
+ QualType RecTy = Context.getTypeDeclType(Record);
+
// Create a declaration for this anonymous struct.
NamedDecl *Anon = FieldDecl::Create(Context,
- cast<RecordDecl>(CurContext),
+ ParentDecl,
DS.getLocStart(),
DS.getLocStart(),
/*IdentifierInfo=*/nullptr,
- Context.getTypeDeclType(Record),
+ RecTy,
TInfo,
/*BitWidth=*/nullptr, /*Mutable=*/false,
/*InitStyle=*/ICIS_NoInit);
@@ -3999,10 +4116,13 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
Chain.push_back(Anon);
RecordDecl *RecordDef = Record->getDefinition();
- if (!RecordDef || InjectAnonymousStructOrUnionMembers(*this, S, CurContext,
- RecordDef, AS_none,
- Chain, true))
+ if (RequireCompleteType(Anon->getLocation(), RecTy,
+ diag::err_field_incomplete) ||
+ InjectAnonymousStructOrUnionMembers(*this, S, CurContext, RecordDef,
+ AS_none, Chain, true)) {
Anon->setInvalidDecl();
+ ParentDecl->setInvalidDecl();
+ }
return Anon;
}
@@ -4835,7 +4955,7 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
// in an outer scope, it isn't the same thing.
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/false,
/*AllowInlineNamespace*/false);
- filterNonConflictingPreviousDecls(Context, NewTD, Previous);
+ filterNonConflictingPreviousTypedefDecls(Context, NewTD, Previous);
if (!Previous.empty()) {
Redeclaration = true;
MergeTypedefNameDecl(NewTD, Previous);
@@ -4995,14 +5115,7 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
}
// dll attributes require external linkage.
- if (const DLLImportAttr *Attr = ND.getAttr<DLLImportAttr>()) {
- if (!ND.isExternallyVisible()) {
- S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern)
- << &ND << Attr;
- ND.setInvalidDecl();
- }
- }
- if (const DLLExportAttr *Attr = ND.getAttr<DLLExportAttr>()) {
+ if (const InheritableAttr *Attr = getDLLAttr(&ND)) {
if (!ND.isExternallyVisible()) {
S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern)
<< &ND << Attr;
@@ -5064,17 +5177,22 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
}
// A redeclaration is not allowed to drop a dllimport attribute, the only
- // exception being inline function definitions.
+ // exceptions being inline function definitions, local extern declarations,
+ // and qualified friend declarations.
// NB: MSVC converts such a declaration to dllexport.
- bool IsInline = false, IsStaticDataMember = false;
+ bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false;
if (const auto *VD = dyn_cast<VarDecl>(NewDecl))
// Ignore static data because out-of-line definitions are diagnosed
// separately.
IsStaticDataMember = VD->isStaticDataMember();
- else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl))
+ else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl)) {
IsInline = FD->isInlined();
+ IsQualifiedFriend = FD->getQualifier() &&
+ FD->getFriendObjectKind() == Decl::FOK_Declared;
+ }
- if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember) {
+ if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember &&
+ !NewDecl->isLocalExternDecl() && !IsQualifiedFriend) {
S.Diag(NewDecl->getLocation(),
diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
<< NewDecl << OldImportAttr;
@@ -5082,6 +5200,14 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute);
OldDecl->dropAttr<DLLImportAttr>();
NewDecl->dropAttr<DLLImportAttr>();
+ } else if (IsInline && OldImportAttr &&
+ !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ // In MinGW, seeing a function declared inline drops the dllimport attribute.
+ OldDecl->dropAttr<DLLImportAttr>();
+ NewDecl->dropAttr<DLLImportAttr>();
+ S.Diag(NewDecl->getLocation(),
+ diag::warn_dllimport_dropped_from_inline_function)
+ << NewDecl << OldImportAttr;
}
}
@@ -5222,8 +5348,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
DeclarationName Name = GetNameForDeclarator(D).getName();
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
- VarDecl::StorageClass SC =
- StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
+ StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
// dllimport globals without explicit storage class are treated as extern. We
// have to change the storage class this early to get the right DeclContext.
@@ -5434,7 +5559,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Only C++1y supports variable templates (N3651).
Diag(D.getIdentifierLoc(),
- getLangOpts().CPlusPlus1y
+ getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_variable_template
: diag::ext_variable_template);
}
@@ -5503,22 +5628,20 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setLocalExternDecl();
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) {
- if (NewVD->hasLocalStorage()) {
- // C++11 [dcl.stc]p4:
- // When thread_local is applied to a variable of block scope the
- // storage-class-specifier static is implied if it does not appear
- // explicitly.
- // Core issue: 'static' is not implied if the variable is declared
- // 'extern'.
- if (SCSpec == DeclSpec::SCS_unspecified &&
- TSCS == DeclSpec::TSCS_thread_local &&
- DC->isFunctionOrMethod())
- NewVD->setTSCSpec(TSCS);
- else
- Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
- diag::err_thread_non_global)
- << DeclSpec::getSpecifierName(TSCS);
- } else if (!Context.getTargetInfo().isTLSSupported())
+ // C++11 [dcl.stc]p4:
+ // When thread_local is applied to a variable of block scope the
+ // storage-class-specifier static is implied if it does not appear
+ // explicitly.
+ // Core issue: 'static' is not implied if the variable is declared
+ // 'extern'.
+ if (NewVD->hasLocalStorage() &&
+ (SCSpec != DeclSpec::SCS_unspecified ||
+ TSCS != DeclSpec::TSCS_thread_local ||
+ !DC->isFunctionOrMethod()))
+ Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
+ diag::err_thread_non_global)
+ << DeclSpec::getSpecifierName(TSCS);
+ else if (!Context.getTargetInfo().isTLSSupported())
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_thread_unsupported);
else
@@ -6198,7 +6321,7 @@ static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD,
/// AddOverriddenMethods - See if a method overrides any in the base classes,
/// and if so, check that it's a valid override and remember it.
bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
- // Look for virtual methods in base classes that this method might override.
+ // Look for methods in base classes that this method might override.
CXXBasePaths Paths;
FindOverriddenMethodData Data;
Data.Method = MD;
@@ -6320,8 +6443,6 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
- DifferentNameValidatorCCC Validator(SemaRef.Context, NewFD,
- MD ? MD->getParent() : nullptr);
if (!Prev.empty()) {
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
Func != FuncEnd; ++Func) {
@@ -6337,9 +6458,11 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
}
// If the qualified name lookup yielded nothing, try typo correction
} else if ((Correction = SemaRef.CorrectTypo(
- Prev.getLookupNameInfo(), Prev.getLookupKind(), S,
- &ExtraArgs.D.getCXXScopeSpec(), Validator,
- Sema::CTK_ErrorRecovery, IsLocalFriend ? nullptr : NewDC))) {
+ Prev.getLookupNameInfo(), Prev.getLookupKind(), S,
+ &ExtraArgs.D.getCXXScopeSpec(),
+ llvm::make_unique<DifferentNameValidatorCCC>(
+ SemaRef.Context, NewFD, MD ? MD->getParent() : nullptr),
+ Sema::CTK_ErrorRecovery, IsLocalFriend ? nullptr : NewDC))) {
// Set up everything for the call to ActOnFunctionDeclarator
ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(),
ExtraArgs.D.getIdentifierLoc());
@@ -6436,8 +6559,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
return nullptr;
}
-static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef,
- Declarator &D) {
+static StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) {
switch (D.getDeclSpec().getStorageClassSpec()) {
default: llvm_unreachable("Unknown storage class!");
case DeclSpec::SCS_auto:
@@ -6475,7 +6597,7 @@ static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef,
static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
DeclContext *DC, QualType &R,
TypeSourceInfo *TInfo,
- FunctionDecl::StorageClass SC,
+ StorageClass SC,
bool &IsVirtualOkay) {
DeclarationNameInfo NameInfo = SemaRef.GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -6500,9 +6622,6 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
if (D.isInvalidType())
NewFD->setInvalidDecl();
- // Set the lexical context.
- NewFD->setLexicalDeclContext(SemaRef.CurContext);
-
return NewFD;
}
@@ -6602,6 +6721,11 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
IsVirtualOkay = !Ret->isStatic();
return Ret;
} else {
+ bool isFriend =
+ SemaRef.getLangOpts().CPlusPlus && D.getDeclSpec().isFriendSpecified();
+ if (!isFriend && SemaRef.CurContext->isRecord())
+ return nullptr;
+
// Determine whether the function was written with a
// prototype. This true when:
// - we're in C++ (where every function has a prototype),
@@ -6655,7 +6779,7 @@ static void checkIsValidOpenCLKernelParameter(
Sema &S,
Declarator &D,
ParmVarDecl *Param,
- llvm::SmallPtrSet<const Type *, 16> &ValidTypes) {
+ llvm::SmallPtrSetImpl<const Type *> &ValidTypes) {
QualType PT = Param->getType();
// Cache the valid types we encounter to avoid rechecking structs that are
@@ -6802,7 +6926,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// TODO: consider using NameInfo for diagnostic.
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
- FunctionDecl::StorageClass SC = getFunctionStorageClass(*this, D);
+ StorageClass SC = getFunctionStorageClass(*this, D);
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
@@ -6990,12 +7114,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setVirtualAsWritten(true);
}
- if (getLangOpts().CPlusPlus1y &&
+ if (getLangOpts().CPlusPlus14 &&
NewFD->getReturnType()->isUndeducedType())
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual);
}
- if (getLangOpts().CPlusPlus1y &&
+ if (getLangOpts().CPlusPlus14 &&
(NewFD->isDependentContext() ||
(isFriend && CurContext->isDependentContext())) &&
NewFD->getReturnType()->isUndeducedType()) {
@@ -7126,12 +7250,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
const FunctionProtoType *FPT = R->getAs<FunctionProtoType>();
if ((Name.getCXXOverloadedOperator() == OO_Delete ||
Name.getCXXOverloadedOperator() == OO_Array_Delete) &&
- getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec()) {
- FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- EPI.ExceptionSpecType = EST_BasicNoexcept;
- NewFD->setType(Context.getFunctionType(FPT->getReturnType(),
- FPT->getParamTypes(), EPI));
- }
+ getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec())
+ NewFD->setType(Context.getFunctionType(
+ FPT->getReturnType(), FPT->getParamTypes(),
+ FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept)));
}
// Filter out previous declarations that don't match the scope.
@@ -7232,7 +7354,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
CodeSegStack.CurrentValue->getString(),
CodeSegStack.CurrentPragmaLocation));
if (UnifySection(CodeSegStack.CurrentValue->getString(),
- PSF_Implicit | PSF_Execute | PSF_Read, NewFD))
+ ASTContext::PSF_Implicit | ASTContext::PSF_Execute |
+ ASTContext::PSF_Read,
+ NewFD))
NewFD->dropAttr<SectionAttr>();
}
@@ -7283,6 +7407,22 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
assert((NewFD->isInvalidDecl() || !D.isRedeclaration() ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
+
+ // Diagnose no-prototype function declarations with calling conventions that
+ // don't support variadic calls. Only do this in C and do it after merging
+ // possibly prototyped redeclarations.
+ const FunctionType *FT = NewFD->getType()->castAs<FunctionType>();
+ if (isa<FunctionNoProtoType>(FT) && !D.isFunctionDefinition()) {
+ CallingConv CC = FT->getExtInfo().getCC();
+ if (!supportsVariadicCall(CC)) {
+ // Windows system headers sometimes accidentally use stdcall without
+ // (void) parameters, so we relax this to a warning.
+ int DiagID =
+ CC == CC_X86StdCall ? diag::warn_cconv_knr : diag::err_cconv_knr;
+ Diag(NewFD->getLocation(), DiagID)
+ << FunctionType::getNameForCallConv(CC);
+ }
+ }
} else {
// C++11 [replacement.functions]p3:
// The program's definitions shall not be specified as inline.
@@ -7749,12 +7889,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// This rule is not present in C++1y, so we produce a backwards
// compatibility warning whenever it happens in C++11.
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
- if (!getLangOpts().CPlusPlus1y && MD && MD->isConstexpr() &&
+ if (!getLangOpts().CPlusPlus14 && MD && MD->isConstexpr() &&
!MD->isStatic() && !isa<CXXConstructorDecl>(MD) &&
(MD->getTypeQualifiers() & Qualifiers::Const) == 0) {
CXXMethodDecl *OldMD = nullptr;
if (OldDecl)
- OldMD = dyn_cast<CXXMethodDecl>(OldDecl->getAsFunction());
+ OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl->getAsFunction());
if (!OldMD || !OldMD->isStatic()) {
const FunctionProtoType *FPT =
MD->getType()->castAs<FunctionProtoType>();
@@ -7771,7 +7911,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
.IgnoreParens().getAs<FunctionTypeLoc>())
AddConstLoc = getLocForEndOfToken(FTL.getRParenLoc());
- Diag(MD->getLocation(), diag::warn_cxx1y_compat_constexpr_not_const)
+ Diag(MD->getLocation(), diag::warn_cxx14_compat_constexpr_not_const)
<< FixItHint::CreateInsertion(AddConstLoc, " const");
}
}
@@ -7838,6 +7978,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
// Semantic checking for this function declaration (in isolation).
+
if (getLangOpts().CPlusPlus) {
// C++-specific checks.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
@@ -7918,7 +8059,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// the function returns a UDT (class, struct, or union type) that is not C
// compatible, and if it does, warn the user.
// But, issue any diagnostic on the first declaration only.
- if (NewFD->isExternC() && Previous.empty()) {
+ if (Previous.empty() && NewFD->isExternC()) {
QualType R = NewFD->getReturnType();
if (R->isIncompleteType() && !R->isVoidType())
Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete)
@@ -8120,6 +8261,8 @@ namespace {
bool isPODType;
bool isReferenceType;
+ bool isInitList;
+ llvm::SmallVector<unsigned, 4> InitFieldIndex;
public:
typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited;
@@ -8128,6 +8271,7 @@ namespace {
isPODType = false;
isRecordType = false;
isReferenceType = false;
+ isInitList = false;
if (ValueDecl *VD = dyn_cast<ValueDecl>(OrigDecl)) {
isPODType = VD->getType().isPODType(S.Context);
isRecordType = VD->getType()->isRecordType();
@@ -8135,25 +8279,122 @@ namespace {
}
}
+ // For most expressions, just call the visitor. For initializer lists,
+ // track the index of the field being initialized since fields are
+ // initialized in order allowing use of previously initialized fields.
+ void CheckExpr(Expr *E) {
+ InitListExpr *InitList = dyn_cast<InitListExpr>(E);
+ if (!InitList) {
+ Visit(E);
+ return;
+ }
+
+ // Track and increment the index here.
+ isInitList = true;
+ InitFieldIndex.push_back(0);
+ for (auto Child : InitList->children()) {
+ CheckExpr(cast<Expr>(Child));
+ ++InitFieldIndex.back();
+ }
+ InitFieldIndex.pop_back();
+ }
+
+ // Returns true if MemberExpr is checked and no futher checking is needed.
+ // Returns false if additional checking is required.
+ bool CheckInitListMemberExpr(MemberExpr *E, bool CheckReference) {
+ llvm::SmallVector<FieldDecl*, 4> Fields;
+ Expr *Base = E;
+ bool ReferenceField = false;
+
+ // Get the field memebers used.
+ while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) {
+ FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (!FD)
+ return false;
+ Fields.push_back(FD);
+ if (FD->getType()->isReferenceType())
+ ReferenceField = true;
+ Base = ME->getBase()->IgnoreParenImpCasts();
+ }
+
+ // Keep checking only if the base Decl is the same.
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base);
+ if (!DRE || DRE->getDecl() != OrigDecl)
+ return false;
+
+ // A reference field can be bound to an unininitialized field.
+ if (CheckReference && !ReferenceField)
+ return true;
+
+ // Convert FieldDecls to their index number.
+ llvm::SmallVector<unsigned, 4> UsedFieldIndex;
+ for (auto I = Fields.rbegin(), E = Fields.rend(); I != E; ++I) {
+ UsedFieldIndex.push_back((*I)->getFieldIndex());
+ }
+
+ // See if a warning is needed by checking the first difference in index
+ // numbers. If field being used has index less than the field being
+ // initialized, then the use is safe.
+ for (auto UsedIter = UsedFieldIndex.begin(),
+ UsedEnd = UsedFieldIndex.end(),
+ OrigIter = InitFieldIndex.begin(),
+ OrigEnd = InitFieldIndex.end();
+ UsedIter != UsedEnd && OrigIter != OrigEnd; ++UsedIter, ++OrigIter) {
+ if (*UsedIter < *OrigIter)
+ return true;
+ if (*UsedIter > *OrigIter)
+ break;
+ }
+
+ // TODO: Add a different warning which will print the field names.
+ HandleDeclRefExpr(DRE);
+ return true;
+ }
+
// For most expressions, the cast is directly above the DeclRefExpr.
// For conditional operators, the cast can be outside the conditional
// operator if both expressions are DeclRefExpr's.
void HandleValue(Expr *E) {
- if (isReferenceType)
- return;
- E = E->IgnoreParenImpCasts();
+ E = E->IgnoreParens();
if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(E)) {
HandleDeclRefExpr(DRE);
return;
}
if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ Visit(CO->getCond());
HandleValue(CO->getTrueExpr());
HandleValue(CO->getFalseExpr());
return;
}
+ if (BinaryConditionalOperator *BCO =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ Visit(BCO->getCond());
+ HandleValue(BCO->getFalseExpr());
+ return;
+ }
+
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) {
+ HandleValue(OVE->getSourceExpr());
+ return;
+ }
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Comma) {
+ Visit(BO->getLHS());
+ HandleValue(BO->getRHS());
+ return;
+ }
+ }
+
if (isa<MemberExpr>(E)) {
+ if (isInitList) {
+ if (CheckInitListMemberExpr(cast<MemberExpr>(E),
+ false /*CheckReference*/))
+ return;
+ }
+
Expr *Base = E->IgnoreParenImpCasts();
while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) {
// Check for static member variables and don't warn on them.
@@ -8165,24 +8406,32 @@ namespace {
HandleDeclRefExpr(DRE);
return;
}
+
+ Visit(E);
}
- // Reference types are handled here since all uses of references are
- // bad, not just r-value uses.
+ // Reference types not handled in HandleValue are handled here since all
+ // uses of references are bad, not just r-value uses.
void VisitDeclRefExpr(DeclRefExpr *E) {
if (isReferenceType)
HandleDeclRefExpr(E);
}
void VisitImplicitCastExpr(ImplicitCastExpr *E) {
- if (E->getCastKind() == CK_LValueToRValue ||
- (isRecordType && E->getCastKind() == CK_NoOp))
+ if (E->getCastKind() == CK_LValueToRValue) {
HandleValue(E->getSubExpr());
+ return;
+ }
Inherited::VisitImplicitCastExpr(E);
}
void VisitMemberExpr(MemberExpr *E) {
+ if (isInitList) {
+ if (CheckInitListMemberExpr(E, true /*CheckReference*/))
+ return;
+ }
+
// Don't warn on arrays since they can be treated as pointers.
if (E->getType()->canDecayToPointerType()) return;
@@ -8209,11 +8458,14 @@ namespace {
}
void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
- if (E->getNumArgs() > 0)
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getArg(0)))
- HandleDeclRefExpr(DRE);
+ Expr *Callee = E->getCallee();
- Inherited::VisitCXXOperatorCallExpr(E);
+ if (isa<UnresolvedLookupExpr>(Callee))
+ return Inherited::VisitCXXOperatorCallExpr(E);
+
+ Visit(Callee);
+ for (auto Arg: E->arguments())
+ HandleValue(Arg->IgnoreParenImpCasts());
}
void VisitUnaryOperator(UnaryOperator *E) {
@@ -8224,11 +8476,65 @@ namespace {
HandleValue(E->getSubExpr());
return;
}
+
+ if (E->isIncrementDecrementOp()) {
+ HandleValue(E->getSubExpr());
+ return;
+ }
+
Inherited::VisitUnaryOperator(E);
}
void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; }
+ void VisitCXXConstructExpr(CXXConstructExpr *E) {
+ if (E->getConstructor()->isCopyConstructor()) {
+ Expr *ArgExpr = E->getArg(0);
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(ArgExpr))
+ if (ILE->getNumInits() == 1)
+ ArgExpr = ILE->getInit(0);
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgExpr))
+ if (ICE->getCastKind() == CK_NoOp)
+ ArgExpr = ICE->getSubExpr();
+ HandleValue(ArgExpr);
+ return;
+ }
+ Inherited::VisitCXXConstructExpr(E);
+ }
+
+ void VisitCallExpr(CallExpr *E) {
+ // Treat std::move as a use.
+ if (E->getNumArgs() == 1) {
+ if (FunctionDecl *FD = E->getDirectCallee()) {
+ if (FD->isInStdNamespace() && FD->getIdentifier() &&
+ FD->getIdentifier()->isStr("move")) {
+ HandleValue(E->getArg(0));
+ return;
+ }
+ }
+ }
+
+ Inherited::VisitCallExpr(E);
+ }
+
+ void VisitBinaryOperator(BinaryOperator *E) {
+ if (E->isCompoundAssignmentOp()) {
+ HandleValue(E->getLHS());
+ Visit(E->getRHS());
+ return;
+ }
+
+ Inherited::VisitBinaryOperator(E);
+ }
+
+ // A custom visitor for BinaryConditionalOperator is needed because the
+ // regular visitor would check the condition and true expression separately
+ // but both point to the same place giving duplicate diagnostics.
+ void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
+ Visit(E->getCond());
+ Visit(E->getFalseExpr());
+ }
+
void HandleDeclRefExpr(DeclRefExpr *DRE) {
Decl* ReferenceDecl = DRE->getDecl();
if (OrigDecl != ReferenceDecl) return;
@@ -8268,7 +8574,7 @@ namespace {
if (DRE->getDecl() == OrigDecl)
return;
- SelfReferenceChecker(S, OrigDecl).Visit(E);
+ SelfReferenceChecker(S, OrigDecl).CheckExpr(E);
}
}
@@ -8279,8 +8585,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
bool DirectInit, bool TypeMayContainAuto) {
// If there is no declaration, there was an error parsing it. Just ignore
// the initializer.
- if (!RealDecl || RealDecl->isInvalidDecl())
+ if (!RealDecl || RealDecl->isInvalidDecl()) {
+ CorrectDelayedTyposInExpr(Init);
return;
+ }
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
// With declarators parsed the way they are, the parser cannot
@@ -8511,6 +8819,21 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
Args = MultiExprArg(CXXDirectInit->getExprs(),
CXXDirectInit->getNumExprs());
+ // Try to correct any TypoExprs in the initialization arguments.
+ for (size_t Idx = 0; Idx < Args.size(); ++Idx) {
+ ExprResult Res =
+ CorrectDelayedTyposInExpr(Args[Idx], [this, Entity, Kind](Expr *E) {
+ InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E));
+ return Init.Failed() ? ExprError() : E;
+ });
+ if (Res.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
+ }
+ if (Res.get() != Args[Idx])
+ Args[Idx] = Res.get();
+ }
+
InitializationSequence InitSeq(*this, Entity, Kind, Args);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
if (Result.isInvalid()) {
@@ -9124,15 +9447,15 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isThisDeclarationADefinition() &&
ActiveTemplateInstantiations.empty()) {
PragmaStack<StringLiteral *> *Stack = nullptr;
- int SectionFlags = PSF_Implicit | PSF_Read;
+ int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read;
if (var->getType().isConstQualified())
Stack = &ConstSegStack;
else if (!var->getInit()) {
Stack = &BSSSegStack;
- SectionFlags |= PSF_Write;
+ SectionFlags |= ASTContext::PSF_Write;
} else {
Stack = &DataSegStack;
- SectionFlags |= PSF_Write;
+ SectionFlags |= ASTContext::PSF_Write;
}
if (!var->hasAttr<SectionAttr>() && Stack->CurrentValue)
var->addAttr(
@@ -9244,7 +9567,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
// Static locals inherit dll attributes from their function.
if (VD->isStaticLocal()) {
if (FunctionDecl *FD =
- dyn_cast<FunctionDecl>(VD->getParentFunctionOrMethod())) {
+ dyn_cast_or_null<FunctionDecl>(VD->getParentFunctionOrMethod())) {
if (Attr *A = getDLLAttr(FD)) {
auto *NewAttr = cast<InheritableAttr>(A->clone(getASTContext()));
NewAttr->setInherited(true);
@@ -9253,8 +9576,11 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
}
}
+ // Grab the dllimport or dllexport attribute off of the VarDecl.
+ const InheritableAttr *DLLAttr = getDLLAttr(VD);
+
// Imported static data members cannot be defined out-of-line.
- if (const DLLImportAttr *IA = VD->getAttr<DLLImportAttr>()) {
+ if (const auto *IA = dyn_cast_or_null<DLLImportAttr>(DLLAttr)) {
if (VD->isStaticDataMember() && VD->isOutOfLine() &&
VD->isThisDeclarationADefinition()) {
// We allow definitions of dllimport class template static data members
@@ -9275,6 +9601,14 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
}
}
+ // dllimport/dllexport variables cannot be thread local, their TLS index
+ // isn't exported with the variable.
+ if (DLLAttr && VD->getTLSKind()) {
+ Diag(VD->getLocation(), diag::err_attribute_dll_thread_local) << VD
+ << DLLAttr;
+ VD->setInvalidDecl();
+ }
+
if (UsedAttr *Attr = VD->getAttr<UsedAttr>()) {
if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) {
Diag(Attr->getLocation(), diag::warn_attribute_ignored) << Attr;
@@ -9466,12 +9800,12 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
// C++03 [dcl.stc]p2 also permits 'auto'.
- VarDecl::StorageClass StorageClass = SC_None;
+ StorageClass SC = SC_None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
- StorageClass = SC_Register;
+ SC = SC_Register;
} else if (getLangOpts().CPlusPlus &&
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
- StorageClass = SC_Auto;
+ SC = SC_Auto;
} else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
Diag(DS.getStorageClassSpecLoc(),
diag::err_invalid_storage_class_in_func_decl);
@@ -9545,7 +9879,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
D.getLocStart(),
D.getIdentifierLoc(), II,
parmDeclType, TInfo,
- StorageClass);
+ SC);
if (D.isInvalidType())
New->setInvalidDecl();
@@ -9637,7 +9971,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
SourceLocation NameLoc, IdentifierInfo *Name,
QualType T, TypeSourceInfo *TSInfo,
- VarDecl::StorageClass StorageClass) {
+ StorageClass SC) {
// In ARC, infer a lifetime qualifier for appropriate parameter types.
if (getLangOpts().ObjCAutoRefCount &&
T.getObjCLifetime() == Qualifiers::OCL_None &&
@@ -9663,8 +9997,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
Context.getAdjustedParameterType(T),
- TSInfo,
- StorageClass, nullptr);
+ TSInfo, SC, nullptr);
// Parameters can not be abstract class types.
// For record types, this is done by the AbstractClassUsageDiagnoser once
@@ -9850,6 +10183,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
// Add the captures to the LSI so they can be noted as already
// captured within tryCaptureVar.
+ auto I = LambdaClass->field_begin();
for (const auto &C : LambdaClass->captures()) {
if (C.capturesVariable()) {
VarDecl *VD = C.getCapturedVar();
@@ -9858,7 +10192,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
QualType CaptureType = VD->getType();
const bool ByRef = C.getCaptureKind() == LCK_ByRef;
LSI->addCapture(VD, /*IsBlock*/false, ByRef,
- /*RefersToEnclosingLocal*/true, C.getLocation(),
+ /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(),
/*EllipsisLoc*/C.isPackExpansion()
? C.getEllipsisLoc() : SourceLocation(),
CaptureType, /*Expr*/ nullptr);
@@ -9866,7 +10200,10 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
} else if (C.capturesThis()) {
LSI->addThisCapture(/*Nested*/ false, C.getLocation(),
S.getCurrentThisType(), /*Expr*/ nullptr);
+ } else {
+ LSI->addVLATypeCapture(C.getLocation(), I->getType());
}
+ ++I;
}
}
@@ -10107,7 +10444,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD) {
FD->setBody(Body);
- if (getLangOpts().CPlusPlus1y && !FD->isInvalidDecl() && Body &&
+ if (getLangOpts().CPlusPlus14 && !FD->isInvalidDecl() && Body &&
!FD->isDependentContext() && FD->getReturnType()->isUndeducedType()) {
// If the function has a deduced result type but contains no 'return'
// statements, the result type as written must be exactly 'auto', and
@@ -10118,8 +10455,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
FD->setInvalidDecl();
} else {
// Substitute 'void' for the 'auto' in the type.
- TypeLoc ResultType = FD->getTypeSourceInfo()->getTypeLoc().
- IgnoreParens().castAs<FunctionProtoTypeLoc>().getReturnLoc();
+ TypeLoc ResultType = getReturnTypeLoc(FD);
Context.adjustDeducedFunctionResultType(
FD, SubstAutoType(ResultType.getType(), Context.VoidTy));
}
@@ -10154,9 +10490,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(),
FD->getReturnType(), FD);
- // If this is a constructor, we need a vtable.
+ // If this is a structor, we need a vtable.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD))
MarkVTableUsed(FD->getLocation(), Constructor->getParent());
+ else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(FD))
+ MarkVTableUsed(FD->getLocation(), Destructor->getParent());
// Try to apply the named return value optimization. We have to check
// if we can do this here because lambdas keep return statements around
@@ -10265,7 +10603,19 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
!CheckConstexprFunctionBody(FD, Body)))
FD->setInvalidDecl();
- assert(ExprCleanupObjects.empty() && "Leftover temporaries in function");
+ if (FD && FD->hasAttr<NakedAttr>()) {
+ for (const Stmt *S : Body->children()) {
+ if (!isa<AsmStmt>(S) && !isa<NullStmt>(S)) {
+ Diag(S->getLocStart(), diag::err_non_asm_stmt_in_naked_function);
+ Diag(FD->getAttr<NakedAttr>()->getLocation(), diag::note_attribute);
+ FD->setInvalidDecl();
+ break;
+ }
+ }
+ }
+
+ assert(ExprCleanupObjects.size() == ExprEvalContexts.back().NumCleanupObjects
+ && "Leftover temporaries in function");
assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
assert(MaybeODRUseExprs.empty() &&
"Leftover expressions for odr-use checking");
@@ -10329,10 +10679,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
// function declaration is going to be treated as an error.
if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) {
TypoCorrection Corrected;
- DeclFilterCCC<FunctionDecl> Validator;
- if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc),
- LookupOrdinaryName, S, nullptr, Validator,
- CTK_NonError)))
+ if (S &&
+ (Corrected = CorrectTypo(
+ DeclarationNameInfo(&II, Loc), LookupOrdinaryName, S, nullptr,
+ llvm::make_unique<DeclFilterCCC<FunctionDecl>>(), CTK_NonError)))
diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
/*ErrorRecovery*/false);
}
@@ -10360,6 +10710,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
/*RefQualifierLoc=*/NoLoc,
/*ConstQualifierLoc=*/NoLoc,
/*VolatileQualifierLoc=*/NoLoc,
+ /*RestrictQualifierLoc=*/NoLoc,
/*MutableLoc=*/NoLoc,
EST_None,
/*ESpecLoc=*/NoLoc,
@@ -10367,6 +10718,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
/*ExceptionRanges=*/nullptr,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
+ /*ExceptionSpecTokens=*/nullptr,
Loc, Loc, D),
DS.getAttributes(),
SourceLocation());
@@ -11262,9 +11614,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
} else {
// If the type is currently being defined, complain
// about a nested redefinition.
- const TagType *Tag
- = cast<TagType>(Context.getTagDeclType(PrevTagDecl));
- if (Tag->isBeingDefined()) {
+ auto *TD = Context.getTagDeclType(PrevTagDecl)->getAsTagDecl();
+ if (TD->isBeingDefined()) {
Diag(NameLoc, diag::err_nested_redefinition) << Name;
Diag(PrevTagDecl->getLocation(),
diag::note_previous_definition);
@@ -11454,7 +11805,7 @@ CreateNewDecl:
// CheckMemberSpecialization, below.
if (!isExplicitSpecialization &&
(TUK == TUK_Definition || TUK == TUK_Declaration) &&
- diagnoseQualifiedDeclaration(SS, DC, OrigName, NameLoc))
+ diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc))
Invalid = true;
New->setQualifierInfo(SS.getWithLocInContext(Context));
@@ -12430,8 +12781,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
continue;
}
// Okay, we have a legal flexible array member at the end of the struct.
- if (Record)
- Record->setHasFlexibleArrayMember(true);
+ Record->setHasFlexibleArrayMember(true);
} else if (!FDTy->isDependentType() &&
RequireCompleteType(FD->getLocation(), FD->getType(),
diag::err_field_incomplete)) {
@@ -12440,11 +12790,11 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
EnclosingDecl->setInvalidDecl();
continue;
} else if (const RecordType *FDTTy = FDTy->getAs<RecordType>()) {
- if (FDTTy->getDecl()->hasFlexibleArrayMember()) {
- // If this is a member of a union, then entire union becomes "flexible".
- if (Record && Record->isUnion()) {
- Record->setHasFlexibleArrayMember(true);
- } else {
+ if (Record && FDTTy->getDecl()->hasFlexibleArrayMember()) {
+ // A type which contains a flexible array member is considered to be a
+ // flexible array member.
+ Record->setHasFlexibleArrayMember(true);
+ if (!Record->isUnion()) {
// If this is a struct/class and this is not the last element, reject
// it. Note that GCC supports variable sized arrays in the middle of
// structures.
@@ -12456,8 +12806,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// other structs as an extension.
Diag(FD->getLocation(), diag::ext_flexible_array_in_struct)
<< FD->getDeclName();
- if (Record)
- Record->setHasFlexibleArrayMember(true);
}
}
}
@@ -13171,6 +13519,49 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements,
}
}
+bool
+Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
+ bool AllowMask) const {
+ FlagEnumAttr *FEAttr = ED->getAttr<FlagEnumAttr>();
+ assert(FEAttr && "looking for value in non-flag enum");
+
+ llvm::APInt FlagMask = ~FEAttr->getFlagBits();
+ unsigned Width = FlagMask.getBitWidth();
+
+ // We will try a zero-extended value for the regular check first.
+ llvm::APInt ExtVal = Val.zextOrSelf(Width);
+
+ // A value is in a flag enum if either its bits are a subset of the enum's
+ // flag bits (the first condition) or we are allowing masks and the same is
+ // true of its complement (the second condition). When masks are allowed, we
+ // allow the common idiom of ~(enum1 | enum2) to be a valid enum value.
+ //
+ // While it's true that any value could be used as a mask, the assumption is
+ // that a mask will have all of the insignificant bits set. Anything else is
+ // likely a logic error.
+ if (!(FlagMask & ExtVal))
+ return true;
+
+ if (AllowMask) {
+ // Try a one-extended value instead. This can happen if the enum is wider
+ // than the constant used, in C with extensions to allow for wider enums.
+ // The mask will still have the correct behaviour, so we give the user the
+ // benefit of the doubt.
+ //
+ // FIXME: This heuristic can cause weird results if the enum was extended
+ // to a larger type and is signed, because then bit-masks of smaller types
+ // that get extended will fall out of range (e.g. ~0x1u). We currently don't
+ // detect that case and will get a false positive for it. In most cases,
+ // though, it can be fixed by making it a signed type (e.g. ~0x1), so it may
+ // be fine just to accept this as a warning.
+ ExtVal |= llvm::APInt::getHighBitsSet(Width, Width - Val.getBitWidth());
+ if (!(FlagMask & ~ExtVal))
+ return true;
+ }
+
+ return false;
+}
+
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, Decl *EnumDeclX,
ArrayRef<Decl *> Elements,
@@ -13256,10 +13647,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
BestPromotionType = Context.getPromotedIntegerType(BestType);
else
BestPromotionType = BestType;
- // We don't need to set BestWidth, because BestType is going to be the type
- // of the enumerators, but we do anyway because otherwise some compilers
- // warn that it might be used uninitialized.
- BestWidth = CharWidth;
+
+ BestWidth = Context.getIntWidth(BestType);
}
else if (NumNegativeBits) {
// If there is a negative value, figure out the smallest integer type (of
@@ -13324,10 +13713,15 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
}
}
+ FlagEnumAttr *FEAttr = Enum->getAttr<FlagEnumAttr>();
+ if (FEAttr)
+ FEAttr->getFlagBits() = llvm::APInt(BestWidth, 0);
+
// Loop over all of the enumerator constants, changing their types to match
- // the type of the enum if needed.
- for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
- EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]);
+ // the type of the enum if needed. If we have a flag type, we also prepare the
+ // FlagBits cache.
+ for (auto *D : Elements) {
+ auto *ECD = cast_or_null<EnumConstantDecl>(D);
if (!ECD) continue; // Already issued a diagnostic.
// Standard C says the enumerators have int type, but we allow, as an
@@ -13357,7 +13751,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// enum-specifier, each enumerator has the type of its
// enumeration.
ECD->setType(EnumType);
- continue;
+ goto flagbits;
} else {
NewTy = BestType;
NewWidth = BestWidth;
@@ -13384,8 +13778,32 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(EnumType);
else
ECD->setType(NewTy);
+
+flagbits:
+ // Check to see if we have a constant with exactly one bit set. Note that x
+ // & (x - 1) will be nonzero if and only if x has more than one bit set.
+ if (FEAttr) {
+ llvm::APInt ExtVal = InitVal.zextOrSelf(BestWidth);
+ if (ExtVal != 0 && !(ExtVal & (ExtVal - 1))) {
+ FEAttr->getFlagBits() |= ExtVal;
+ }
+ }
}
+ if (FEAttr) {
+ for (Decl *D : Elements) {
+ EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(D);
+ if (!ECD) continue; // Already issued a diagnostic.
+
+ llvm::APSInt InitVal = ECD->getInitVal();
+ if (InitVal != 0 && !IsValueInFlagEnum(Enum, InitVal, true))
+ Diag(ECD->getLocation(), diag::warn_flag_enum_constant_out_of_range)
+ << ECD << Enum;
+ }
+ }
+
+
+
Enum->completeDefinition(BestType, BestPromotionType,
NumPositiveBits, NumNegativeBits);
@@ -13455,6 +13873,9 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule)
Diag(ImportLoc, diag::err_module_self_import)
<< Mod->getFullModuleName() << getLangOpts().CurrentModule;
+ else if (Mod->getTopLevelModuleName() == getLangOpts().ImplementationOfModule)
+ Diag(ImportLoc, diag::err_module_import_in_implementation)
+ << Mod->getFullModuleName() << getLangOpts().ImplementationOfModule;
SmallVector<SourceLocation, 2> IdentifierLocs;
Module *ModCheck = Mod;
@@ -13575,5 +13996,6 @@ AvailabilityResult Sema::getCurContextAvailability() const {
dyn_cast<ObjCImplementationDecl>(D)) {
D = ID->getClassInterface();
}
- return D->getAvailability();
+ // Recover from user error.
+ return D ? D->getAvailability() : AR_Available;
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 61683cd87579..17a849ea7af0 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -29,6 +29,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MathExtras.h"
using namespace clang;
using namespace sema;
@@ -88,21 +89,39 @@ static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) {
return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType();
}
+static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getParamDecl(Idx)->getSourceRange();
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->parameters()[Idx]->getSourceRange();
+ if (const auto *BD = dyn_cast<BlockDecl>(D))
+ return BD->getParamDecl(Idx)->getSourceRange();
+ return SourceRange();
+}
+
static QualType getFunctionOrMethodResultType(const Decl *D) {
if (const FunctionType *FnTy = D->getFunctionType())
return cast<FunctionType>(FnTy)->getReturnType();
return cast<ObjCMethodDecl>(D)->getReturnType();
}
+static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getReturnTypeSourceRange();
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->getReturnTypeSourceRange();
+ return SourceRange();
+}
+
static bool isFunctionOrMethodVariadic(const Decl *D) {
if (const FunctionType *FnTy = D->getFunctionType()) {
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
return proto->isVariadic();
- } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
- return BD->isVariadic();
- else {
- return cast<ObjCMethodDecl>(D)->isVariadic();
}
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
+ return BD->isVariadic();
+
+ return cast<ObjCMethodDecl>(D)->isVariadic();
}
static bool isInstanceMethod(const Decl *D) {
@@ -148,30 +167,43 @@ static unsigned getNumAttributeArgs(const AttributeList &Attr) {
return Attr.getNumArgs() + Attr.hasParsedType();
}
-/// \brief Check if the attribute has exactly as many args as Num. May
-/// output an error.
-static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
- unsigned Num) {
- if (getNumAttributeArgs(Attr) != Num) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << Num;
+template <typename Compare>
+static bool checkAttributeNumArgsImpl(Sema &S, const AttributeList &Attr,
+ unsigned Num, unsigned Diag,
+ Compare Comp) {
+ if (Comp(getNumAttributeArgs(Attr), Num)) {
+ S.Diag(Attr.getLoc(), Diag) << Attr.getName() << Num;
return false;
}
return true;
}
+/// \brief Check if the attribute has exactly as many args as Num. May
+/// output an error.
+static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
+ unsigned Num) {
+ return checkAttributeNumArgsImpl(S, Attr, Num,
+ diag::err_attribute_wrong_number_arguments,
+ std::not_equal_to<unsigned>());
+}
+
/// \brief Check if the attribute has at least as many args as Num. May
/// output an error.
static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr,
unsigned Num) {
- if (getNumAttributeArgs(Attr) < Num) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments)
- << Attr.getName() << Num;
- return false;
- }
+ return checkAttributeNumArgsImpl(S, Attr, Num,
+ diag::err_attribute_too_few_arguments,
+ std::less<unsigned>());
+}
- return true;
+/// \brief Check if the attribute has at most as many args as Num. May
+/// output an error.
+static bool checkAttributeAtMostNumArgs(Sema &S, const AttributeList &Attr,
+ unsigned Num) {
+ return checkAttributeNumArgsImpl(S, Attr, Num,
+ diag::err_attribute_too_many_arguments,
+ std::greater<unsigned>());
}
/// \brief If Expr is a valid integer constant, get the value of the integer
@@ -192,6 +224,13 @@ static bool checkUInt32Argument(Sema &S, const AttributeList &Attr,
<< Expr->getSourceRange();
return false;
}
+
+ if (!I.isIntN(32)) {
+ S.Diag(Expr->getExprLoc(), diag::err_ice_too_large)
+ << I.toString(10, false) << 32 << /* Unsigned */ 1;
+ return false;
+ }
+
Val = (uint32_t)I.getZExtValue();
return true;
}
@@ -528,10 +567,6 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
// Attribute Implementations
//===----------------------------------------------------------------------===//
-// FIXME: All this manual attribute parsing code is gross. At the
-// least add some helper functions to check most argument patterns (#
-// and types of args).
-
static void handlePtGuardedVarAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (!threadSafetyCheckIsPointer(S, D, Attr))
@@ -706,11 +741,9 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
if (!checkTryLockFunAttrCommon(S, D, Attr, Args))
return;
- D->addAttr(::new (S.Context)
- ExclusiveTrylockFunctionAttr(Attr.getRange(), S.Context,
- Attr.getArgAsExpr(0),
- Args.data(), Args.size(),
- Attr.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(
+ Attr.getRange(), S.Context, Attr.getArgAsExpr(0), Args.data(),
+ Args.size(), Attr.getAttributeSpellingListIndex()));
}
static void handleLockReturnedAttr(Sema &S, Decl *D,
@@ -828,8 +861,14 @@ static void handleCallableWhenAttr(Sema &S, Decl *D,
StringRef StateString;
SourceLocation Loc;
- if (!S.checkStringLiteralArgumentAttr(Attr, ArgIndex, StateString, &Loc))
- return;
+ if (Attr.isArgIdent(ArgIndex)) {
+ IdentifierLoc *Ident = Attr.getArgAsIdent(ArgIndex);
+ StateString = Ident->Ident->getName();
+ Loc = Ident->Loc;
+ } else {
+ if (!S.checkStringLiteralArgumentAttr(Attr, ArgIndex, StateString, &Loc))
+ return;
+ }
if (!CallableWhenAttr::ConvertStrToConsumedState(StateString,
CallableState)) {
@@ -849,8 +888,6 @@ static void handleCallableWhenAttr(Sema &S, Decl *D,
static void handleParamTypestateAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 1)) return;
-
ParamTypestateAttr::ConsumedState ParamState;
if (Attr.isArgIdent(0)) {
@@ -889,8 +926,6 @@ static void handleParamTypestateAttr(Sema &S, Decl *D,
static void handleReturnTypestateAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 1)) return;
-
ReturnTypestateAttr::ConsumedState ReturnState;
if (Attr.isArgIdent(0)) {
@@ -939,9 +974,6 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D,
static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
return;
@@ -967,9 +999,6 @@ static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr)
static void handleTestTypestateAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
return;
@@ -1101,30 +1130,39 @@ static void handleIBOutletCollection(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-static void possibleTransparentUnionPointerType(QualType &T) {
- if (const RecordType *UT = T->getAsUnionType())
+bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) {
+ if (RefOkay) {
+ if (T->isReferenceType())
+ return true;
+ } else {
+ T = T.getNonReferenceType();
+ }
+
+ // The nonnull attribute, and other similar attributes, can be applied to a
+ // transparent union that contains a pointer type.
+ if (const RecordType *UT = T->getAsUnionType()) {
if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) {
RecordDecl *UD = UT->getDecl();
for (const auto *I : UD->fields()) {
QualType QT = I->getType();
- if (QT->isAnyPointerType() || QT->isBlockPointerType()) {
- T = QT;
- return;
- }
+ if (QT->isAnyPointerType() || QT->isBlockPointerType())
+ return true;
}
}
+ }
+
+ return T->isAnyPointerType() || T->isBlockPointerType();
}
static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr,
- SourceRange R, bool isReturnValue = false) {
- T = T.getNonReferenceType();
- possibleTransparentUnionPointerType(T);
-
- if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
- S.Diag(Attr.getLoc(),
- isReturnValue ? diag::warn_attribute_return_pointers_only
- : diag::warn_attribute_pointers_only)
- << Attr.getName() << R;
+ SourceRange AttrParmRange,
+ SourceRange TypeRange,
+ bool isReturnValue = false) {
+ if (!S.isValidPointerAttrType(T)) {
+ S.Diag(Attr.getLoc(), isReturnValue
+ ? diag::warn_attribute_return_pointers_only
+ : diag::warn_attribute_pointers_only)
+ << Attr.getName() << AttrParmRange << TypeRange;
return false;
}
return true;
@@ -1132,46 +1170,45 @@ static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr,
static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
SmallVector<unsigned, 8> NonNullArgs;
- for (unsigned i = 0; i < Attr.getNumArgs(); ++i) {
- Expr *Ex = Attr.getArgAsExpr(i);
+ for (unsigned I = 0; I < Attr.getNumArgs(); ++I) {
+ Expr *Ex = Attr.getArgAsExpr(I);
uint64_t Idx;
- if (!checkFunctionOrMethodParameterIndex(S, D, Attr, i + 1, Ex, Idx))
+ if (!checkFunctionOrMethodParameterIndex(S, D, Attr, I + 1, Ex, Idx))
return;
// Is the function argument a pointer type?
- // FIXME: Should also highlight argument in decl in the diagnostic.
- if (!attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr,
- Ex->getSourceRange()))
+ if (Idx < getFunctionOrMethodNumParams(D) &&
+ !attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr,
+ Ex->getSourceRange(),
+ getFunctionOrMethodParamRange(D, Idx)))
continue;
NonNullArgs.push_back(Idx);
}
// If no arguments were specified to __attribute__((nonnull)) then all pointer
- // arguments have a nonnull attribute.
- if (NonNullArgs.empty()) {
- for (unsigned i = 0, e = getFunctionOrMethodNumParams(D); i != e; ++i) {
- QualType T = getFunctionOrMethodParamType(D, i).getNonReferenceType();
- possibleTransparentUnionPointerType(T);
- if (T->isAnyPointerType() || T->isBlockPointerType())
- NonNullArgs.push_back(i);
+ // arguments have a nonnull attribute; warn if there aren't any. Skip this
+ // check if the attribute came from a macro expansion or a template
+ // instantiation.
+ if (NonNullArgs.empty() && Attr.getLoc().isFileID() &&
+ S.ActiveTemplateInstantiations.empty()) {
+ bool AnyPointers = isFunctionOrMethodVariadic(D);
+ for (unsigned I = 0, E = getFunctionOrMethodNumParams(D);
+ I != E && !AnyPointers; ++I) {
+ QualType T = getFunctionOrMethodParamType(D, I);
+ if (T->isDependentType() || S.isValidPointerAttrType(T))
+ AnyPointers = true;
}
- // No pointer arguments?
- if (NonNullArgs.empty()) {
- // Warn the trivial case only if attribute is not coming from a
- // macro instantiation.
- if (Attr.getLoc().isFileID())
- S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers);
- return;
- }
+ if (!AnyPointers)
+ S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers);
}
- unsigned *start = &NonNullArgs[0];
- unsigned size = NonNullArgs.size();
- llvm::array_pod_sort(start, start + size);
+ unsigned *Start = NonNullArgs.data();
+ unsigned Size = NonNullArgs.size();
+ llvm::array_pod_sort(Start, Start + Size);
D->addAttr(::new (S.Context)
- NonNullAttr(Attr.getRange(), S.Context, start, size,
+ NonNullAttr(Attr.getRange(), S.Context, Start, Size,
Attr.getAttributeSpellingListIndex()));
}
@@ -1188,7 +1225,8 @@ static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
}
// Is the argument a pointer type?
- if (!attrNonNullArgCheck(S, D->getType(), Attr, D->getSourceRange()))
+ if (!attrNonNullArgCheck(S, D->getType(), Attr, SourceRange(),
+ D->getSourceRange()))
return;
D->addAttr(::new (S.Context)
@@ -1199,7 +1237,8 @@ static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
static void handleReturnsNonNullAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
QualType ResultType = getFunctionOrMethodResultType(D);
- if (!attrNonNullArgCheck(S, ResultType, Attr, Attr.getRange(),
+ SourceRange SR = getFunctionOrMethodResultSourceRange(D);
+ if (!attrNonNullArgCheck(S, ResultType, Attr, SourceRange(), SR,
/* isReturnValue */ true))
return;
@@ -1208,6 +1247,65 @@ static void handleReturnsNonNullAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+static void handleAssumeAlignedAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ Expr *E = Attr.getArgAsExpr(0),
+ *OE = Attr.getNumArgs() > 1 ? Attr.getArgAsExpr(1) : nullptr;
+ S.AddAssumeAlignedAttr(Attr.getRange(), D, E, OE,
+ Attr.getAttributeSpellingListIndex());
+}
+
+void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
+ Expr *OE, unsigned SpellingListIndex) {
+ QualType ResultType = getFunctionOrMethodResultType(D);
+ SourceRange SR = getFunctionOrMethodResultSourceRange(D);
+
+ AssumeAlignedAttr TmpAttr(AttrRange, Context, E, OE, SpellingListIndex);
+ SourceLocation AttrLoc = AttrRange.getBegin();
+
+ if (!isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
+ Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
+ << &TmpAttr << AttrRange << SR;
+ return;
+ }
+
+ if (!E->isValueDependent()) {
+ llvm::APSInt I(64);
+ if (!E->isIntegerConstantExpr(I, Context)) {
+ if (OE)
+ Diag(AttrLoc, diag::err_attribute_argument_n_type)
+ << &TmpAttr << 1 << AANT_ArgumentIntegerConstant
+ << E->getSourceRange();
+ else
+ Diag(AttrLoc, diag::err_attribute_argument_type)
+ << &TmpAttr << AANT_ArgumentIntegerConstant
+ << E->getSourceRange();
+ return;
+ }
+
+ if (!I.isPowerOf2()) {
+ Diag(AttrLoc, diag::err_alignment_not_power_of_two)
+ << E->getSourceRange();
+ return;
+ }
+ }
+
+ if (OE) {
+ if (!OE->isValueDependent()) {
+ llvm::APSInt I(64);
+ if (!OE->isIntegerConstantExpr(I, Context)) {
+ Diag(AttrLoc, diag::err_attribute_argument_n_type)
+ << &TmpAttr << 2 << AANT_ArgumentIntegerConstant
+ << OE->getSourceRange();
+ return;
+ }
+ }
+ }
+
+ D->addAttr(::new (Context)
+ AssumeAlignedAttr(AttrRange, Context, E, OE, SpellingListIndex));
+}
+
static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
// This attribute must be applied to a function declaration. The first
// argument to the attribute must be an identifier, the name of the resource,
@@ -1286,13 +1384,26 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
// Check we don't have a conflict with another ownership attribute.
for (const auto *I : D->specific_attrs<OwnershipAttr>()) {
- // FIXME: A returns attribute should conflict with any returns attribute
- // with a different index too.
+ // Cannot have two ownership attributes of different kinds for the same
+ // index.
if (I->getOwnKind() != K && I->args_end() !=
std::find(I->args_begin(), I->args_end(), Idx)) {
S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
<< AL.getName() << I;
return;
+ } else if (K == OwnershipAttr::Returns &&
+ I->getOwnKind() == OwnershipAttr::Returns) {
+ // A returns attribute conflicts with any other returns attribute using
+ // a different index. Note, diagnostic reporting is 1-based, but stored
+ // argument indexes are 0-based.
+ if (std::find(I->args_begin(), I->args_end(), Idx) == I->args_end()) {
+ S.Diag(I->getLocation(), diag::err_ownership_returns_index_mismatch)
+ << *(I->args_begin()) + 1;
+ if (I->args_size())
+ S.Diag(AL.getLoc(), diag::note_ownership_returns_index_mismatch)
+ << (unsigned)Idx + 1 << Ex->getSourceRange();
+ return;
+ }
}
}
OwnershipArgs.push_back(Idx);
@@ -1586,15 +1697,8 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.getNumArgs() > 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
- << Attr.getName() << 1;
- return;
- }
-
uint32_t priority = ConstructorAttr::DefaultPriority;
- if (Attr.getNumArgs() > 0 &&
+ if (Attr.getNumArgs() &&
!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority))
return;
@@ -1604,15 +1708,8 @@ static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.getNumArgs() > 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
- << Attr.getName() << 1;
- return;
- }
-
uint32_t priority = DestructorAttr::DefaultPriority;
- if (Attr.getNumArgs() > 0 &&
+ if (Attr.getNumArgs() &&
!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority))
return;
@@ -1624,16 +1721,9 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
template <typename AttrTy>
static void handleAttrWithMessage(Sema &S, Decl *D,
const AttributeList &Attr) {
- unsigned NumArgs = Attr.getNumArgs();
- if (NumArgs > 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
- << Attr.getName() << 1;
- return;
- }
-
// Handle the case where the attribute has a text message.
StringRef Str;
- if (NumArgs == 1 && !S.checkStringLiteralArgumentAttr(Attr, 0, Str))
+ if (Attr.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(Attr, 0, Str))
return;
D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str,
@@ -2036,13 +2126,6 @@ static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.getNumArgs() > 2) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
- << Attr.getName() << 2;
- return;
- }
-
unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel;
if (Attr.getNumArgs() > 0) {
Expr *E = Attr.getArgAsExpr(0);
@@ -2349,10 +2432,9 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
!Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
- // FIXME: Should highlight the actual expression that has the wrong type.
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
- << (not_nsstring_type ? "a string type" : "an NSString")
- << IdxExpr->getSourceRange();
+ << (not_nsstring_type ? "a string type" : "an NSString")
+ << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0);
return;
}
Ty = getFunctionOrMethodResultType(D);
@@ -2360,10 +2442,9 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
!Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
- // FIXME: Should highlight the actual expression that has the wrong type.
S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not)
- << (not_nsstring_type ? "string type" : "NSString")
- << IdxExpr->getSourceRange();
+ << (not_nsstring_type ? "string type" : "NSString")
+ << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0);
return;
}
@@ -2534,23 +2615,24 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Kind == CFStringFormat) {
if (!isCFStringType(Ty, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
- << "a CFString" << IdxExpr->getSourceRange();
+ << "a CFString" << IdxExpr->getSourceRange()
+ << getFunctionOrMethodParamRange(D, ArgIdx);
return;
}
} else if (Kind == NSStringFormat) {
// FIXME: do we need to check if the type is NSString*? What are the
// semantics?
if (!isNSStringType(Ty, S.Context)) {
- // FIXME: Should highlight the actual expression that has the wrong type.
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
- << "an NSString" << IdxExpr->getSourceRange();
+ << "an NSString" << IdxExpr->getSourceRange()
+ << getFunctionOrMethodParamRange(D, ArgIdx);
return;
}
} else if (!Ty->isPointerType() ||
!Ty->getAs<PointerType>()->getPointeeType()->isCharType()) {
- // FIXME: Should highlight the actual expression that has the wrong type.
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
- << "a string type" << IdxExpr->getSourceRange();
+ << "a string type" << IdxExpr->getSourceRange()
+ << getFunctionOrMethodParamRange(D, ArgIdx);
return;
}
@@ -2679,6 +2761,58 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
+static void handleAlignValueAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ S.AddAlignValueAttr(Attr.getRange(), D, Attr.getArgAsExpr(0),
+ Attr.getAttributeSpellingListIndex());
+}
+
+void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
+ unsigned SpellingListIndex) {
+ AlignValueAttr TmpAttr(AttrRange, Context, E, SpellingListIndex);
+ SourceLocation AttrLoc = AttrRange.getBegin();
+
+ QualType T;
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
+ T = TD->getUnderlyingType();
+ else if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ T = VD->getType();
+ else
+ llvm_unreachable("Unknown decl type for align_value");
+
+ if (!T->isDependentType() && !T->isAnyPointerType() &&
+ !T->isReferenceType() && !T->isMemberPointerType()) {
+ Diag(AttrLoc, diag::warn_attribute_pointer_or_reference_only)
+ << &TmpAttr /*TmpAttr.getName()*/ << T << D->getSourceRange();
+ return;
+ }
+
+ if (!E->isValueDependent()) {
+ llvm::APSInt Alignment(32);
+ ExprResult ICE
+ = VerifyIntegerConstantExpression(E, &Alignment,
+ diag::err_align_value_attribute_argument_not_int,
+ /*AllowFold*/ false);
+ if (ICE.isInvalid())
+ return;
+
+ if (!Alignment.isPowerOf2()) {
+ Diag(AttrLoc, diag::err_alignment_not_power_of_two)
+ << E->getSourceRange();
+ return;
+ }
+
+ D->addAttr(::new (Context)
+ AlignValueAttr(AttrRange, Context, ICE.get(),
+ SpellingListIndex));
+ return;
+ }
+
+ // Save dependent expressions in the AST to be instantiated.
+ D->addAttr(::new (Context) AlignValueAttr(TmpAttr));
+ return;
+}
+
static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (Attr.getNumArgs() > 1) {
@@ -2773,7 +2907,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
// An alignment specification of zero has no effect.
if (!(TmpAttr.isAlignas() && !Alignment) &&
!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
- Diag(AttrLoc, diag::err_attribute_aligned_not_power_of_two)
+ Diag(AttrLoc, diag::err_alignment_not_power_of_two)
<< E->getSourceRange();
return;
}
@@ -3006,24 +3140,75 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
+AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Ident,
+ unsigned AttrSpellingListIndex) {
+ if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
+ Diag(Range.getBegin(), diag::warn_attribute_ignored) << Ident;
+ Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
+ return nullptr;
+ }
+
+ if (D->hasAttr<AlwaysInlineAttr>())
+ return nullptr;
+
+ return ::new (Context) AlwaysInlineAttr(Range, Context,
+ AttrSpellingListIndex);
+}
+
+MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex) {
+ if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
+ Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'minsize'";
+ Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
+ return nullptr;
+ }
+
+ if (D->hasAttr<MinSizeAttr>())
+ return nullptr;
+
+ return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex);
+}
+
+OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex) {
+ if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
+ Diag(Inline->getLocation(), diag::warn_attribute_ignored) << Inline;
+ Diag(Range.getBegin(), diag::note_conflicting_attribute);
+ D->dropAttr<AlwaysInlineAttr>();
+ }
+ if (MinSizeAttr *MinSize = D->getAttr<MinSizeAttr>()) {
+ Diag(MinSize->getLocation(), diag::warn_attribute_ignored) << MinSize;
+ Diag(Range.getBegin(), diag::note_conflicting_attribute);
+ D->dropAttr<MinSizeAttr>();
+ }
+
+ if (D->hasAttr<OptimizeNoneAttr>())
+ return nullptr;
+
+ return ::new (Context) OptimizeNoneAttr(Range, Context,
+ AttrSpellingListIndex);
+}
+
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (checkAttrMutualExclusion<OptimizeNoneAttr>(S, D, Attr))
- return;
+ if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr(
+ D, Attr.getRange(), Attr.getName(),
+ Attr.getAttributeSpellingListIndex()))
+ D->addAttr(Inline);
+}
- D->addAttr(::new (S.Context)
- AlwaysInlineAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (MinSizeAttr *MinSize = S.mergeMinSizeAttr(
+ D, Attr.getRange(), Attr.getAttributeSpellingListIndex()))
+ D->addAttr(MinSize);
}
static void handleOptimizeNoneAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr))
- return;
-
- D->addAttr(::new (S.Context)
- OptimizeNoneAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr(
+ D, Attr.getRange(), Attr.getAttributeSpellingListIndex()))
+ D->addAttr(Optnone);
}
static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3039,7 +3224,7 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
D->addAttr(::new (S.Context)
CUDAGlobalAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ Attr.getAttributeSpellingListIndex()));
}
static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3096,6 +3281,11 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
PascalAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
return;
+ case AttributeList::AT_VectorCall:
+ D->addAttr(::new (S.Context)
+ VectorCallAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+ return;
case AttributeList::AT_MSABI:
D->addAttr(::new (S.Context)
MSABIAttr(Attr.getRange(), S.Context,
@@ -3158,6 +3348,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
case AttributeList::AT_StdCall: CC = CC_X86StdCall; break;
case AttributeList::AT_ThisCall: CC = CC_X86ThisCall; break;
case AttributeList::AT_Pascal: CC = CC_X86Pascal; break;
+ case AttributeList::AT_VectorCall: CC = CC_X86VectorCall; break;
case AttributeList::AT_MSABI:
CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C :
CC_X86_64Win64;
@@ -3242,14 +3433,6 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
static void handleLaunchBoundsAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // check the attribute arguments.
- if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) {
- // FIXME: 0 is not okay.
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
- << Attr.getName() << 2;
- return;
- }
-
uint32_t MaxThreads, MinBlocks = 0;
if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), MaxThreads, 1))
return;
@@ -3440,29 +3623,24 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
default:
llvm_unreachable("invalid ownership attribute");
case AttributeList::AT_NSReturnsAutoreleased:
- D->addAttr(::new (S.Context)
- NSReturnsAutoreleasedAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_CFReturnsNotRetained:
- D->addAttr(::new (S.Context)
- CFReturnsNotRetainedAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_NSReturnsNotRetained:
- D->addAttr(::new (S.Context)
- NSReturnsNotRetainedAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_CFReturnsRetained:
- D->addAttr(::new (S.Context)
- CFReturnsRetainedAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CFReturnsRetainedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_NSReturnsRetained:
- D->addAttr(::new (S.Context)
- NSReturnsRetainedAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NSReturnsRetainedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
return;
};
}
@@ -3491,9 +3669,8 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context)
- ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context,
- attr.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(
+ attr.getRange(), S.Context, attr.getAttributeSpellingListIndex()));
}
static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
@@ -3587,7 +3764,8 @@ static void handleObjCBridgeRelatedAttr(Sema &S, Scope *Sc, Decl *D,
static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
const AttributeList &Attr) {
ObjCInterfaceDecl *IFace;
- if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext()))
+ if (ObjCCategoryDecl *CatDecl =
+ dyn_cast<ObjCCategoryDecl>(D->getDeclContext()))
IFace = CatDecl->getClassInterface();
else
IFace = cast<ObjCInterfaceDecl>(D->getDeclContext());
@@ -3812,6 +3990,32 @@ static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
handleARMInterruptAttr(S, D, Attr);
}
+static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ uint32_t NumRegs;
+ Expr *NumRegsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
+ if (!checkUInt32Argument(S, Attr, NumRegsExpr, NumRegs))
+ return;
+
+ D->addAttr(::new (S.Context)
+ AMDGPUNumVGPRAttr(Attr.getLoc(), S.Context,
+ NumRegs,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ uint32_t NumRegs;
+ Expr *NumRegsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
+ if (!checkUInt32Argument(S, Attr, NumRegsExpr, NumRegs))
+ return;
+
+ D->addAttr(::new (S.Context)
+ AMDGPUNumSGPRAttr(Attr.getLoc(), S.Context,
+ NumRegs,
+ Attr.getAttributeSpellingListIndex()));
+}
+
static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
const AttributeList& Attr) {
// If we try to apply it to a function pointer, don't warn, but don't
@@ -3871,6 +4075,16 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) {
return;
}
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isInlined() && A.getKind() == AttributeList::AT_DLLImport &&
+ !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ // MinGW doesn't allow dllimport on inline functions.
+ S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline)
+ << A.getName();
+ return;
+ }
+ }
+
unsigned Index = A.getAttributeSpellingListIndex();
Attr *NewAttr = A.getKind() == AttributeList::AT_DLLExport
? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index)
@@ -4001,6 +4215,19 @@ static void handleRequiresCapabilityAttr(Sema &S, Decl *D,
D->addAttr(RCA);
}
+static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (auto *NSD = dyn_cast<NamespaceDecl>(D)) {
+ if (NSD->isAnonymousNamespace()) {
+ S.Diag(Attr.getLoc(), diag::warn_deprecated_anonymous_namespace);
+ // Do not want to attach the attribute to the namespace because that will
+ // cause confusing diagnostic reports for uses of declarations within the
+ // namespace.
+ return;
+ }
+ }
+ handleAttrWithMessage<DeprecatedAttr>(S, D, Attr);
+}
+
/// Handles semantic checking for features that are common to all attributes,
/// such as checking whether a parameter was properly specified, or the correct
/// number of arguments were passed, etc.
@@ -4020,11 +4247,20 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
if (!Attr.diagnoseLangOpts(S))
return true;
- // If there are no optional arguments, then checking for the argument count
- // is trivial.
- if (Attr.getMinArgs() == Attr.getMaxArgs() &&
- !checkAttributeNumArgs(S, Attr, Attr.getMinArgs()))
- return true;
+ if (Attr.getMinArgs() == Attr.getMaxArgs()) {
+ // If there are no optional arguments, then checking for the argument count
+ // is trivial.
+ if (!checkAttributeNumArgs(S, Attr, Attr.getMinArgs()))
+ return true;
+ } else {
+ // There are optional arguments, so checking is slightly more involved.
+ if (Attr.getMinArgs() &&
+ !checkAttributeAtLeastNumArgs(S, Attr, Attr.getMinArgs()))
+ return true;
+ else if (!Attr.hasVariadicArg() && Attr.getMaxArgs() &&
+ !checkAttributeAtMostNumArgs(S, Attr, Attr.getMaxArgs()))
+ return true;
+ }
// Check whether the attribute appertains to the given subject.
if (!Attr.diagnoseAppertainsTo(S, D))
@@ -4087,6 +4323,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_NoMips16:
handleSimpleAttribute<NoMips16Attr>(S, D, Attr);
break;
+ case AttributeList::AT_AMDGPUNumVGPR:
+ handleAMDGPUNumVGPRAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_AMDGPUNumSGPR:
+ handleAMDGPUNumSGPRAttr(S, D, Attr);
+ break;
case AttributeList::AT_IBAction:
handleSimpleAttribute<IBActionAttr>(S, D, Attr);
break;
@@ -4102,6 +4344,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_Aligned:
handleAlignedAttr(S, D, Attr);
break;
+ case AttributeList::AT_AlignValue:
+ handleAlignValueAttr(S, D, Attr);
+ break;
case AttributeList::AT_AlwaysInline:
handleAlwaysInlineAttr(S, D, Attr);
break;
@@ -4133,7 +4378,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleSimpleAttribute<CXX11NoReturnAttr>(S, D, Attr);
break;
case AttributeList::AT_Deprecated:
- handleAttrWithMessage<DeprecatedAttr>(S, D, Attr);
+ handleDeprecatedAttr(S, D, Attr);
break;
case AttributeList::AT_Destructor:
handleDestructorAttr(S, D, Attr);
@@ -4145,11 +4390,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleExtVectorTypeAttr(S, scope, D, Attr);
break;
case AttributeList::AT_MinSize:
- handleSimpleAttribute<MinSizeAttr>(S, D, Attr);
+ handleMinSizeAttr(S, D, Attr);
break;
case AttributeList::AT_OptimizeNone:
handleOptimizeNoneAttr(S, D, Attr);
break;
+ case AttributeList::AT_FlagEnum:
+ handleSimpleAttribute<FlagEnumAttr>(S, D, Attr);
+ break;
case AttributeList::AT_Flatten:
handleSimpleAttribute<FlattenAttr>(S, D, Attr);
break;
@@ -4198,6 +4446,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ReturnsNonNull:
handleReturnsNonNullAttr(S, D, Attr);
break;
+ case AttributeList::AT_AssumeAligned:
+ handleAssumeAlignedAttr(S, D, Attr);
+ break;
case AttributeList::AT_Overloadable:
handleSimpleAttribute<OverloadableAttr>(S, D, Attr);
break;
@@ -4392,6 +4643,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_FastCall:
case AttributeList::AT_ThisCall:
case AttributeList::AT_Pascal:
+ case AttributeList::AT_VectorCall:
case AttributeList::AT_MSABI:
case AttributeList::AT_SysVABI:
case AttributeList::AT_Pcs:
@@ -4553,19 +4805,31 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
return;
}
+ // FIXME: We should be able to handle this in TableGen as well. It would be
+ // good to have a way to specify "these attributes must appear as a group",
+ // for these. Additionally, it would be good to have a way to specify "these
+ // attribute must never appear as a group" for attributes like cold and hot.
if (!D->hasAttr<OpenCLKernelAttr>()) {
// These attributes cannot be applied to a non-kernel function.
if (Attr *A = D->getAttr<ReqdWorkGroupSizeAttr>()) {
+ // FIXME: This emits a different error message than
+ // diag::err_attribute_wrong_decl_type + ExpectedKernelFunction.
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
D->setInvalidDecl();
- }
- if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) {
+ } else if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) {
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
D->setInvalidDecl();
- }
- if (Attr *A = D->getAttr<VecTypeHintAttr>()) {
+ } else if (Attr *A = D->getAttr<VecTypeHintAttr>()) {
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
D->setInvalidDecl();
+ } else if (Attr *A = D->getAttr<AMDGPUNumVGPRAttr>()) {
+ Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
+ << A << ExpectedKernelFunction;
+ D->setInvalidDecl();
+ } else if (Attr *A = D->getAttr<AMDGPUNumSGPRAttr>()) {
+ Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
+ << A << ExpectedKernelFunction;
+ D->setInvalidDecl();
}
}
}
@@ -4576,7 +4840,7 @@ bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
const AttributeList *AttrList) {
for (const AttributeList* l = AttrList; l; l = l->getNext()) {
if (l->getKind() == AttributeList::AT_Annotate) {
- handleAnnotateAttr(*this, ASDecl, *l);
+ ProcessDeclAttribute(*this, nullptr, ASDecl, *l, l->isCXX11Attribute());
} else {
Diag(l->getLoc(), diag::err_only_annotate_after_access_spec);
return true;
@@ -4774,61 +5038,6 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
diag.Triggered = true;
}
-void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
- assert(DelayedDiagnostics.getCurrentPool());
- DelayedDiagnosticPool &poppedPool = *DelayedDiagnostics.getCurrentPool();
- DelayedDiagnostics.popWithoutEmitting(state);
-
- // When delaying diagnostics to run in the context of a parsed
- // declaration, we only want to actually emit anything if parsing
- // succeeds.
- if (!decl) return;
-
- // We emit all the active diagnostics in this pool or any of its
- // parents. In general, we'll get one pool for the decl spec
- // and a child pool for each declarator; in a decl group like:
- // deprecated_typedef foo, *bar, baz();
- // only the declarator pops will be passed decls. This is correct;
- // we really do need to consider delayed diagnostics from the decl spec
- // for each of the different declarations.
- const DelayedDiagnosticPool *pool = &poppedPool;
- do {
- for (DelayedDiagnosticPool::pool_iterator
- i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) {
- // This const_cast is a bit lame. Really, Triggered should be mutable.
- DelayedDiagnostic &diag = const_cast<DelayedDiagnostic&>(*i);
- if (diag.Triggered)
- continue;
-
- switch (diag.Kind) {
- case DelayedDiagnostic::Deprecation:
- case DelayedDiagnostic::Unavailable:
- // Don't bother giving deprecation/unavailable diagnostics if
- // the decl is invalid.
- if (!decl->isInvalidDecl())
- HandleDelayedAvailabilityCheck(diag, decl);
- break;
-
- case DelayedDiagnostic::Access:
- HandleDelayedAccessCheck(diag, decl);
- break;
-
- case DelayedDiagnostic::ForbiddenType:
- handleDelayedForbiddenType(*this, diag, decl);
- break;
- }
- }
- } while ((pool = pool->getParent()));
-}
-
-/// Given a set of delayed diagnostics, re-emit them as if they had
-/// been delayed in the current context instead of in the given pool.
-/// Essentially, this just moves them to the current pool.
-void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
- DelayedDiagnosticPool *curPool = DelayedDiagnostics.getCurrentPool();
- assert(curPool && "re-emitting in undelayed context not supported");
- curPool->steal(pool);
-}
static bool isDeclDeprecated(Decl *D) {
do {
@@ -4852,17 +5061,12 @@ static bool isDeclUnavailable(Decl *D) {
return false;
}
-static void
-DoEmitAvailabilityWarning(Sema &S,
- DelayedDiagnostic::DDKind K,
- Decl *Ctx,
- const NamedDecl *D,
- StringRef Message,
- SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCProperty,
- bool ObjCPropertyAccess) {
-
+static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K,
+ Decl *Ctx, const NamedDecl *D,
+ StringRef Message, SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty,
+ bool ObjCPropertyAccess) {
// Diagnostics for deprecated or unavailable.
unsigned diag, diag_message, diag_fwdclass_message;
@@ -4874,65 +5078,116 @@ DoEmitAvailabilityWarning(Sema &S,
// Don't warn if our current context is deprecated or unavailable.
switch (K) {
- case DelayedDiagnostic::Deprecation:
- if (isDeclDeprecated(Ctx))
- return;
- diag = !ObjCPropertyAccess ? diag::warn_deprecated
- : diag::warn_property_method_deprecated;
- diag_message = diag::warn_deprecated_message;
- diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
- property_note_select = /* deprecated */ 0;
- available_here_select_kind = /* deprecated */ 2;
- break;
+ case DelayedDiagnostic::Deprecation:
+ if (isDeclDeprecated(Ctx))
+ return;
+ diag = !ObjCPropertyAccess ? diag::warn_deprecated
+ : diag::warn_property_method_deprecated;
+ diag_message = diag::warn_deprecated_message;
+ diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
+ property_note_select = /* deprecated */ 0;
+ available_here_select_kind = /* deprecated */ 2;
+ break;
- case DelayedDiagnostic::Unavailable:
- if (isDeclUnavailable(Ctx))
- return;
- diag = !ObjCPropertyAccess ? diag::err_unavailable
- : diag::err_property_method_unavailable;
- diag_message = diag::err_unavailable_message;
- diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
- property_note_select = /* unavailable */ 1;
- available_here_select_kind = /* unavailable */ 0;
- break;
+ case DelayedDiagnostic::Unavailable:
+ if (isDeclUnavailable(Ctx))
+ return;
+ diag = !ObjCPropertyAccess ? diag::err_unavailable
+ : diag::err_property_method_unavailable;
+ diag_message = diag::err_unavailable_message;
+ diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
+ property_note_select = /* unavailable */ 1;
+ available_here_select_kind = /* unavailable */ 0;
+ break;
- default:
- llvm_unreachable("Neither a deprecation or unavailable kind");
+ default:
+ llvm_unreachable("Neither a deprecation or unavailable kind");
}
- DeclarationName Name = D->getDeclName();
if (!Message.empty()) {
- S.Diag(Loc, diag_message) << Name << Message;
+ S.Diag(Loc, diag_message) << D << Message;
if (ObjCProperty)
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
- << ObjCProperty->getDeclName() << property_note_select;
+ << ObjCProperty->getDeclName() << property_note_select;
} else if (!UnknownObjCClass) {
- S.Diag(Loc, diag) << Name;
+ S.Diag(Loc, diag) << D;
if (ObjCProperty)
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
- << ObjCProperty->getDeclName() << property_note_select;
+ << ObjCProperty->getDeclName() << property_note_select;
} else {
- S.Diag(Loc, diag_fwdclass_message) << Name;
+ S.Diag(Loc, diag_fwdclass_message) << D;
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
}
S.Diag(D->getLocation(), diag::note_availability_specified_here)
- << D << available_here_select_kind;
+ << D << available_here_select_kind;
}
-void Sema::HandleDelayedAvailabilityCheck(DelayedDiagnostic &DD,
- Decl *Ctx) {
+static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
+ Decl *Ctx) {
DD.Triggered = true;
- DoEmitAvailabilityWarning(*this,
- (DelayedDiagnostic::DDKind) DD.Kind,
- Ctx,
- DD.getDeprecationDecl(),
- DD.getDeprecationMessage(),
- DD.Loc,
- DD.getUnknownObjCClass(),
+ DoEmitAvailabilityWarning(S, (DelayedDiagnostic::DDKind)DD.Kind, Ctx,
+ DD.getDeprecationDecl(), DD.getDeprecationMessage(),
+ DD.Loc, DD.getUnknownObjCClass(),
DD.getObjCProperty(), false);
}
+void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
+ assert(DelayedDiagnostics.getCurrentPool());
+ DelayedDiagnosticPool &poppedPool = *DelayedDiagnostics.getCurrentPool();
+ DelayedDiagnostics.popWithoutEmitting(state);
+
+ // When delaying diagnostics to run in the context of a parsed
+ // declaration, we only want to actually emit anything if parsing
+ // succeeds.
+ if (!decl) return;
+
+ // We emit all the active diagnostics in this pool or any of its
+ // parents. In general, we'll get one pool for the decl spec
+ // and a child pool for each declarator; in a decl group like:
+ // deprecated_typedef foo, *bar, baz();
+ // only the declarator pops will be passed decls. This is correct;
+ // we really do need to consider delayed diagnostics from the decl spec
+ // for each of the different declarations.
+ const DelayedDiagnosticPool *pool = &poppedPool;
+ do {
+ for (DelayedDiagnosticPool::pool_iterator
+ i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) {
+ // This const_cast is a bit lame. Really, Triggered should be mutable.
+ DelayedDiagnostic &diag = const_cast<DelayedDiagnostic&>(*i);
+ if (diag.Triggered)
+ continue;
+
+ switch (diag.Kind) {
+ case DelayedDiagnostic::Deprecation:
+ case DelayedDiagnostic::Unavailable:
+ // Don't bother giving deprecation/unavailable diagnostics if
+ // the decl is invalid.
+ if (!decl->isInvalidDecl())
+ handleDelayedAvailabilityCheck(*this, diag, decl);
+ break;
+
+ case DelayedDiagnostic::Access:
+ HandleDelayedAccessCheck(diag, decl);
+ break;
+
+ case DelayedDiagnostic::ForbiddenType:
+ handleDelayedForbiddenType(*this, diag, decl);
+ break;
+ }
+ }
+ } while ((pool = pool->getParent()));
+}
+
+/// Given a set of delayed diagnostics, re-emit them as if they had
+/// been delayed in the current context instead of in the given pool.
+/// Essentially, this just moves them to the current pool.
+void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
+ DelayedDiagnosticPool *curPool = DelayedDiagnostics.getCurrentPool();
+ assert(curPool && "re-emitting in undelayed context not supported");
+ curPool->steal(pool);
+}
+
void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD,
NamedDecl *D, StringRef Message,
SourceLocation Loc,
@@ -4941,11 +5196,9 @@ void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD,
bool ObjCPropertyAccess) {
// Delay if we're currently parsing a declaration.
if (DelayedDiagnostics.shouldDelayDiagnostics()) {
- DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(AD, Loc, D,
- UnknownObjCClass,
- ObjCProperty,
- Message,
- ObjCPropertyAccess));
+ DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(
+ AD, Loc, D, UnknownObjCClass, ObjCProperty, Message,
+ ObjCPropertyAccess));
return;
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index c5cd83da59d6..510738ea8168 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -36,6 +36,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include <map>
@@ -212,7 +213,7 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
ComputedEST = EST_Dynamic;
// Record the exceptions in this function's exception specification.
for (const auto &E : Proto->exceptions())
- if (ExceptionsSeen.insert(Self->Context.getCanonicalType(E)))
+ if (ExceptionsSeen.insert(Self->Context.getCanonicalType(E)).second)
Exceptions.push_back(E);
}
@@ -353,7 +354,9 @@ void Sema::ActOnParamDefaultArgumentError(Decl *param,
Param->setInvalidDecl();
UnparsedDefaultArgLocs.erase(Param);
Param->setDefaultArg(new(Context)
- OpaqueValueExpr(EqualLoc, Param->getType(), VK_RValue));
+ OpaqueValueExpr(EqualLoc,
+ Param->getType().getNonReferenceType(),
+ VK_RValue));
}
/// CheckExtraCXXDefaultArguments - Check for any extra default
@@ -385,9 +388,14 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
ParmVarDecl *Param = cast<ParmVarDecl>(chunk.Fun.Params[argIdx].Param);
if (Param->hasUnparsedDefaultArg()) {
CachedTokens *Toks = chunk.Fun.Params[argIdx].DefaultArgTokens;
+ SourceRange SR;
+ if (Toks->size() > 1)
+ SR = SourceRange((*Toks)[1].getLocation(),
+ Toks->back().getLocation());
+ else
+ SR = UnparsedDefaultArgLocs[Param];
Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
- << SourceRange((*Toks)[1].getLocation(),
- Toks->back().getLocation());
+ << SR;
delete Toks;
chunk.Fun.Params[argIdx].DefaultArgTokens = nullptr;
} else if (Param->getDefaultArg()) {
@@ -446,20 +454,24 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
bool OldParamHasDfl = OldParam->hasDefaultArg();
bool NewParamHasDfl = NewParam->hasDefaultArg();
- NamedDecl *ND = Old;
-
// The declaration context corresponding to the scope is the semantic
// parent, unless this is a local function declaration, in which case
// it is that surrounding function.
- DeclContext *ScopeDC = New->getLexicalDeclContext();
- if (!ScopeDC->isFunctionOrMethod())
- ScopeDC = New->getDeclContext();
- if (S && !isDeclInScope(ND, ScopeDC, S) &&
+ DeclContext *ScopeDC = New->isLocalExternDecl()
+ ? New->getLexicalDeclContext()
+ : New->getDeclContext();
+ if (S && !isDeclInScope(Old, ScopeDC, S) &&
!New->getDeclContext()->isRecord())
// Ignore default parameters of old decl if they are not in
// the same scope and this is not an out-of-line definition of
// a member function.
OldParamHasDfl = false;
+ if (New->isLocalExternDecl() != Old->isLocalExternDecl())
+ // If only one of these is a local function declaration, then they are
+ // declared in different scopes, even though isDeclInScope may think
+ // they're in the same scope. (If both are local, the scope check is
+ // sufficent, and if neither is local, then they are in the same scope.)
+ OldParamHasDfl = false;
if (OldParamHasDfl && NewParamHasDfl) {
@@ -855,7 +867,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
// C++1y allows types to be defined, not just declared.
if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition())
SemaRef.Diag(DS->getLocStart(),
- SemaRef.getLangOpts().CPlusPlus1y
+ SemaRef.getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_constexpr_type_definition
: diag::ext_constexpr_type_definition)
<< isa<CXXConstructorDecl>(Dcl);
@@ -896,7 +908,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
}
}
SemaRef.Diag(VD->getLocation(),
- SemaRef.getLangOpts().CPlusPlus1y
+ SemaRef.getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_constexpr_local_var
: diag::ext_constexpr_local_var)
<< isa<CXXConstructorDecl>(Dcl);
@@ -1041,7 +1053,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
case Stmt::ContinueStmtClass:
// C++1y allows all of these. We don't allow them as extensions in C++11,
// because they don't make sense without variable mutation.
- if (!SemaRef.getLangOpts().CPlusPlus1y)
+ if (!SemaRef.getLangOpts().CPlusPlus14)
break;
if (!Cxx1yLoc.isValid())
Cxx1yLoc = S->getLocStart();
@@ -1115,7 +1127,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
if (Cxx1yLoc.isValid())
Diag(Cxx1yLoc,
- getLangOpts().CPlusPlus1y
+ getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_constexpr_body_invalid_stmt
: diag::ext_constexpr_body_invalid_stmt)
<< isa<CXXConstructorDecl>(Dcl);
@@ -1180,7 +1192,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// statement. We still do, unless the return type might be void, because
// otherwise if there's no return statement, the function cannot
// be used in a core constant expression.
- bool OK = getLangOpts().CPlusPlus1y &&
+ bool OK = getLangOpts().CPlusPlus14 &&
(Dcl->getReturnType()->isVoidType() ||
Dcl->getReturnType()->isDependentType());
Diag(Dcl->getLocation(),
@@ -1190,7 +1202,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
}
if (ReturnStmts.size() > 1) {
Diag(ReturnStmts.back(),
- getLangOpts().CPlusPlus1y
+ getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_constexpr_body_multiple_return
: diag::ext_constexpr_body_multiple_return);
for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
@@ -1881,7 +1893,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) {
}
// C++11 [class.virtual]p5:
- // If a virtual function is marked with the virt-specifier override and
+ // If a function is marked with the virt-specifier override and
// does not override a member function of a base class, the program is
// ill-formed.
bool HasOverriddenMethods =
@@ -1891,6 +1903,30 @@ void Sema::CheckOverrideControl(NamedDecl *D) {
<< MD->getDeclName();
}
+void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) {
+ if (D->isInvalidDecl() || D->hasAttr<OverrideAttr>())
+ return;
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
+ if (!MD || MD->isImplicit() || MD->hasAttr<FinalAttr>() ||
+ isa<CXXDestructorDecl>(MD))
+ return;
+
+ SourceLocation Loc = MD->getLocation();
+ SourceLocation SpellingLoc = Loc;
+ if (getSourceManager().isMacroArgExpansion(Loc))
+ SpellingLoc = getSourceManager().getImmediateExpansionRange(Loc).first;
+ SpellingLoc = getSourceManager().getSpellingLoc(SpellingLoc);
+ if (SpellingLoc.isValid() && getSourceManager().isInSystemHeader(SpellingLoc))
+ return;
+
+ if (MD->size_overridden_methods() > 0) {
+ Diag(MD->getLocation(), diag::warn_function_marked_not_override_overriding)
+ << MD->getDeclName();
+ const CXXMethodDecl *OMD = *MD->begin_overridden_methods();
+ Diag(OMD->getLocation(), diag::note_overridden_virtual_function);
+ }
+}
+
/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member
/// function overrides a virtual member function marked 'final', according to
/// C++11 [class.virtual]p4.
@@ -2133,7 +2169,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (BitWidth) {
if (Member->isInvalidDecl()) {
// don't emit another diagnostic.
- } else if (isa<VarDecl>(Member)) {
+ } else if (isa<VarDecl>(Member) || isa<VarTemplateDecl>(Member)) {
// C++ 9.6p3: A bit-field shall not be a static member.
// "static member 'A' cannot be a bit-field"
Diag(Loc, diag::err_static_not_bitfield)
@@ -2205,18 +2241,73 @@ namespace {
Sema &S;
// List of Decls to generate a warning on. Also remove Decls that become
// initialized.
- llvm::SmallPtrSet<ValueDecl*, 4> &Decls;
+ llvm::SmallPtrSetImpl<ValueDecl*> &Decls;
+ // List of base classes of the record. Classes are removed after their
+ // initializers.
+ llvm::SmallPtrSetImpl<QualType> &BaseClasses;
+ // Vector of decls to be removed from the Decl set prior to visiting the
+ // nodes. These Decls may have been initialized in the prior initializer.
+ llvm::SmallVector<ValueDecl*, 4> DeclsToRemove;
// If non-null, add a note to the warning pointing back to the constructor.
const CXXConstructorDecl *Constructor;
+ // Variables to hold state when processing an initializer list. When
+ // InitList is true, special case initialization of FieldDecls matching
+ // InitListFieldDecl.
+ bool InitList;
+ FieldDecl *InitListFieldDecl;
+ llvm::SmallVector<unsigned, 4> InitFieldIndex;
+
public:
typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
UninitializedFieldVisitor(Sema &S,
- llvm::SmallPtrSet<ValueDecl*, 4> &Decls,
- const CXXConstructorDecl *Constructor)
- : Inherited(S.Context), S(S), Decls(Decls),
- Constructor(Constructor) { }
+ llvm::SmallPtrSetImpl<ValueDecl*> &Decls,
+ llvm::SmallPtrSetImpl<QualType> &BaseClasses)
+ : Inherited(S.Context), S(S), Decls(Decls), BaseClasses(BaseClasses),
+ Constructor(nullptr), InitList(false), InitListFieldDecl(nullptr) {}
+
+ // Returns true if the use of ME is not an uninitialized use.
+ bool IsInitListMemberExprInitialized(MemberExpr *ME,
+ bool CheckReferenceOnly) {
+ llvm::SmallVector<FieldDecl*, 4> Fields;
+ bool ReferenceField = false;
+ while (ME) {
+ FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (!FD)
+ return false;
+ Fields.push_back(FD);
+ if (FD->getType()->isReferenceType())
+ ReferenceField = true;
+ ME = dyn_cast<MemberExpr>(ME->getBase()->IgnoreParenImpCasts());
+ }
+
+ // Binding a reference to an unintialized field is not an
+ // uninitialized use.
+ if (CheckReferenceOnly && !ReferenceField)
+ return true;
- void HandleMemberExpr(MemberExpr *ME, bool CheckReferenceOnly) {
+ llvm::SmallVector<unsigned, 4> UsedFieldIndex;
+ // Discard the first field since it is the field decl that is being
+ // initialized.
+ for (auto I = Fields.rbegin() + 1, E = Fields.rend(); I != E; ++I) {
+ UsedFieldIndex.push_back((*I)->getFieldIndex());
+ }
+
+ for (auto UsedIter = UsedFieldIndex.begin(),
+ UsedEnd = UsedFieldIndex.end(),
+ OrigIter = InitFieldIndex.begin(),
+ OrigEnd = InitFieldIndex.end();
+ UsedIter != UsedEnd && OrigIter != OrigEnd; ++UsedIter, ++OrigIter) {
+ if (*UsedIter < *OrigIter)
+ return true;
+ if (*UsedIter > *OrigIter)
+ break;
+ }
+
+ return false;
+ }
+
+ void HandleMemberExpr(MemberExpr *ME, bool CheckReferenceOnly,
+ bool AddressOf) {
if (isa<EnumConstantDecl>(ME->getMemberDecl()))
return;
@@ -2224,33 +2315,63 @@ namespace {
// or union.
MemberExpr *FieldME = ME;
+ bool AllPODFields = FieldME->getType().isPODType(S.Context);
+
Expr *Base = ME;
- while (isa<MemberExpr>(Base)) {
- ME = cast<MemberExpr>(Base);
+ while (MemberExpr *SubME =
+ dyn_cast<MemberExpr>(Base->IgnoreParenImpCasts())) {
- if (isa<VarDecl>(ME->getMemberDecl()))
+ if (isa<VarDecl>(SubME->getMemberDecl()))
return;
- if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(SubME->getMemberDecl()))
if (!FD->isAnonymousStructOrUnion())
- FieldME = ME;
+ FieldME = SubME;
+
+ if (!FieldME->getType().isPODType(S.Context))
+ AllPODFields = false;
- Base = ME->getBase();
+ Base = SubME->getBase();
}
- if (!isa<CXXThisExpr>(Base))
+ if (!isa<CXXThisExpr>(Base->IgnoreParenImpCasts()))
+ return;
+
+ if (AddressOf && AllPODFields)
return;
ValueDecl* FoundVD = FieldME->getMemberDecl();
+ if (ImplicitCastExpr *BaseCast = dyn_cast<ImplicitCastExpr>(Base)) {
+ while (isa<ImplicitCastExpr>(BaseCast->getSubExpr())) {
+ BaseCast = cast<ImplicitCastExpr>(BaseCast->getSubExpr());
+ }
+
+ if (BaseCast->getCastKind() == CK_UncheckedDerivedToBase) {
+ QualType T = BaseCast->getType();
+ if (T->isPointerType() &&
+ BaseClasses.count(T->getPointeeType())) {
+ S.Diag(FieldME->getExprLoc(), diag::warn_base_class_is_uninit)
+ << T->getPointeeType() << FoundVD;
+ }
+ }
+ }
+
if (!Decls.count(FoundVD))
return;
const bool IsReference = FoundVD->getType()->isReferenceType();
- // Prevent double warnings on use of unbounded references.
- if (IsReference != CheckReferenceOnly)
- return;
+ if (InitList && !AddressOf && FoundVD == InitListFieldDecl) {
+ // Special checking for initializer lists.
+ if (IsInitListMemberExprInitialized(ME, CheckReferenceOnly)) {
+ return;
+ }
+ } else {
+ // Prevent double warnings on use of unbounded references.
+ if (CheckReferenceOnly && !IsReference)
+ return;
+ }
unsigned diag = IsReference
? diag::warn_reference_field_is_uninit
@@ -2263,74 +2384,160 @@ namespace {
}
- void HandleValue(Expr *E) {
+ void HandleValue(Expr *E, bool AddressOf) {
E = E->IgnoreParens();
if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- HandleMemberExpr(ME, false /*CheckReferenceOnly*/);
+ HandleMemberExpr(ME, false /*CheckReferenceOnly*/,
+ AddressOf /*AddressOf*/);
return;
}
if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
- HandleValue(CO->getTrueExpr());
- HandleValue(CO->getFalseExpr());
+ Visit(CO->getCond());
+ HandleValue(CO->getTrueExpr(), AddressOf);
+ HandleValue(CO->getFalseExpr(), AddressOf);
return;
}
if (BinaryConditionalOperator *BCO =
dyn_cast<BinaryConditionalOperator>(E)) {
- HandleValue(BCO->getCommon());
- HandleValue(BCO->getFalseExpr());
+ Visit(BCO->getCond());
+ HandleValue(BCO->getFalseExpr(), AddressOf);
+ return;
+ }
+
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) {
+ HandleValue(OVE->getSourceExpr(), AddressOf);
return;
}
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
default:
- return;
+ break;
case(BO_PtrMemD):
case(BO_PtrMemI):
- HandleValue(BO->getLHS());
+ HandleValue(BO->getLHS(), AddressOf);
+ Visit(BO->getRHS());
return;
case(BO_Comma):
- HandleValue(BO->getRHS());
+ Visit(BO->getLHS());
+ HandleValue(BO->getRHS(), AddressOf);
return;
}
}
+
+ Visit(E);
+ }
+
+ void CheckInitListExpr(InitListExpr *ILE) {
+ InitFieldIndex.push_back(0);
+ for (auto Child : ILE->children()) {
+ if (InitListExpr *SubList = dyn_cast<InitListExpr>(Child)) {
+ CheckInitListExpr(SubList);
+ } else {
+ Visit(Child);
+ }
+ ++InitFieldIndex.back();
+ }
+ InitFieldIndex.pop_back();
+ }
+
+ void CheckInitializer(Expr *E, const CXXConstructorDecl *FieldConstructor,
+ FieldDecl *Field, const Type *BaseClass) {
+ // Remove Decls that may have been initialized in the previous
+ // initializer.
+ for (ValueDecl* VD : DeclsToRemove)
+ Decls.erase(VD);
+ DeclsToRemove.clear();
+
+ Constructor = FieldConstructor;
+ InitListExpr *ILE = dyn_cast<InitListExpr>(E);
+
+ if (ILE && Field) {
+ InitList = true;
+ InitListFieldDecl = Field;
+ InitFieldIndex.clear();
+ CheckInitListExpr(ILE);
+ } else {
+ InitList = false;
+ Visit(E);
+ }
+
+ if (Field)
+ Decls.erase(Field);
+ if (BaseClass)
+ BaseClasses.erase(BaseClass->getCanonicalTypeInternal());
}
void VisitMemberExpr(MemberExpr *ME) {
// All uses of unbounded reference fields will warn.
- HandleMemberExpr(ME, true /*CheckReferenceOnly*/);
-
- Inherited::VisitMemberExpr(ME);
+ HandleMemberExpr(ME, true /*CheckReferenceOnly*/, false /*AddressOf*/);
}
void VisitImplicitCastExpr(ImplicitCastExpr *E) {
- if (E->getCastKind() == CK_LValueToRValue)
- HandleValue(E->getSubExpr());
+ if (E->getCastKind() == CK_LValueToRValue) {
+ HandleValue(E->getSubExpr(), false /*AddressOf*/);
+ return;
+ }
Inherited::VisitImplicitCastExpr(E);
}
void VisitCXXConstructExpr(CXXConstructExpr *E) {
- if (E->getConstructor()->isCopyConstructor())
- if (ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(E->getArg(0)))
+ if (E->getConstructor()->isCopyConstructor()) {
+ Expr *ArgExpr = E->getArg(0);
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(ArgExpr))
+ if (ILE->getNumInits() == 1)
+ ArgExpr = ILE->getInit(0);
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgExpr))
if (ICE->getCastKind() == CK_NoOp)
- if (MemberExpr *ME = dyn_cast<MemberExpr>(ICE->getSubExpr()))
- HandleMemberExpr(ME, false /*CheckReferenceOnly*/);
-
+ ArgExpr = ICE->getSubExpr();
+ HandleValue(ArgExpr, false /*AddressOf*/);
+ return;
+ }
Inherited::VisitCXXConstructExpr(E);
}
void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
Expr *Callee = E->getCallee();
- if (isa<MemberExpr>(Callee))
- HandleValue(Callee);
+ if (isa<MemberExpr>(Callee)) {
+ HandleValue(Callee, false /*AddressOf*/);
+ for (auto Arg : E->arguments())
+ Visit(Arg);
+ return;
+ }
Inherited::VisitCXXMemberCallExpr(E);
}
+ void VisitCallExpr(CallExpr *E) {
+ // Treat std::move as a use.
+ if (E->getNumArgs() == 1) {
+ if (FunctionDecl *FD = E->getDirectCallee()) {
+ if (FD->isInStdNamespace() && FD->getIdentifier() &&
+ FD->getIdentifier()->isStr("move")) {
+ HandleValue(E->getArg(0), false /*AddressOf*/);
+ return;
+ }
+ }
+ }
+
+ Inherited::VisitCallExpr(E);
+ }
+
+ void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ Expr *Callee = E->getCallee();
+
+ if (isa<UnresolvedLookupExpr>(Callee))
+ return Inherited::VisitCXXOperatorCallExpr(E);
+
+ Visit(Callee);
+ for (auto Arg : E->arguments())
+ HandleValue(Arg->IgnoreParenImpCasts(), false /*AddressOf*/);
+ }
+
void VisitBinaryOperator(BinaryOperator *E) {
// If a field assignment is detected, remove the field from the
// uninitiailized field set.
@@ -2338,30 +2545,32 @@ namespace {
if (MemberExpr *ME = dyn_cast<MemberExpr>(E->getLHS()))
if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
if (!FD->getType()->isReferenceType())
- Decls.erase(FD);
+ DeclsToRemove.push_back(FD);
+
+ if (E->isCompoundAssignmentOp()) {
+ HandleValue(E->getLHS(), false /*AddressOf*/);
+ Visit(E->getRHS());
+ return;
+ }
Inherited::VisitBinaryOperator(E);
}
- };
- static void CheckInitExprContainsUninitializedFields(
- Sema &S, Expr *E, llvm::SmallPtrSet<ValueDecl*, 4> &Decls,
- const CXXConstructorDecl *Constructor) {
- if (Decls.size() == 0)
- return;
-
- if (!E)
- return;
- if (CXXDefaultInitExpr *Default = dyn_cast<CXXDefaultInitExpr>(E)) {
- E = Default->getExpr();
- if (!E)
+ void VisitUnaryOperator(UnaryOperator *E) {
+ if (E->isIncrementDecrementOp()) {
+ HandleValue(E->getSubExpr(), false /*AddressOf*/);
return;
- // In class initializers will point to the constructor.
- UninitializedFieldVisitor(S, Decls, Constructor).Visit(E);
- } else {
- UninitializedFieldVisitor(S, Decls, nullptr).Visit(E);
+ }
+ if (E->getOpcode() == UO_AddrOf) {
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E->getSubExpr())) {
+ HandleValue(ME->getBase(), true /*AddressOf*/);
+ return;
+ }
+ }
+
+ Inherited::VisitUnaryOperator(E);
}
- }
+ };
// Diagnose value-uses of fields to initialize themselves, e.g.
// foo(foo)
@@ -2382,6 +2591,9 @@ namespace {
const CXXRecordDecl *RD = Constructor->getParent();
+ if (RD->getDescribedClassTemplate())
+ return;
+
// Holds fields that are uninitialized.
llvm::SmallPtrSet<ValueDecl*, 4> UninitializedFields;
@@ -2394,14 +2606,39 @@ namespace {
}
}
+ llvm::SmallPtrSet<QualType, 4> UninitializedBaseClasses;
+ for (auto I : RD->bases())
+ UninitializedBaseClasses.insert(I.getType().getCanonicalType());
+
+ if (UninitializedFields.empty() && UninitializedBaseClasses.empty())
+ return;
+
+ UninitializedFieldVisitor UninitializedChecker(SemaRef,
+ UninitializedFields,
+ UninitializedBaseClasses);
+
for (const auto *FieldInit : Constructor->inits()) {
- Expr *InitExpr = FieldInit->getInit();
+ if (UninitializedFields.empty() && UninitializedBaseClasses.empty())
+ break;
- CheckInitExprContainsUninitializedFields(
- SemaRef, InitExpr, UninitializedFields, Constructor);
+ Expr *InitExpr = FieldInit->getInit();
+ if (!InitExpr)
+ continue;
- if (FieldDecl *Field = FieldInit->getAnyMember())
- UninitializedFields.erase(Field);
+ if (CXXDefaultInitExpr *Default =
+ dyn_cast<CXXDefaultInitExpr>(InitExpr)) {
+ InitExpr = Default->getExpr();
+ if (!InitExpr)
+ continue;
+ // In class initializers will point to the constructor.
+ UninitializedChecker.CheckInitializer(InitExpr, Constructor,
+ FieldInit->getAnyMember(),
+ FieldInit->getBaseClass());
+ } else {
+ UninitializedChecker.CheckInitializer(InitExpr, nullptr,
+ FieldInit->getAnyMember(),
+ FieldInit->getBaseClass());
+ }
}
}
} // namespace
@@ -2424,13 +2661,14 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
// Pop the notional constructor scope we created earlier.
PopFunctionScopeInfo(nullptr, D);
- FieldDecl *FD = cast<FieldDecl>(D);
- assert(FD->getInClassInitStyle() != ICIS_NoInit &&
+ FieldDecl *FD = dyn_cast<FieldDecl>(D);
+ assert((isa<MSPropertyDecl>(D) || FD->getInClassInitStyle() != ICIS_NoInit) &&
"must set init style when field is created");
if (!InitExpr) {
- FD->setInvalidDecl();
- FD->removeInClassInitializer();
+ D->setInvalidDecl();
+ if (FD)
+ FD->removeInClassInitializer();
return;
}
@@ -2581,6 +2819,11 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
SourceLocation IdLoc,
Expr *Init,
SourceLocation EllipsisLoc) {
+ ExprResult Res = CorrectDelayedTyposInExpr(Init);
+ if (!Res.isUsable())
+ return true;
+ Init = Res.get();
+
if (!ConstructorD)
return true;
@@ -2610,8 +2853,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
// using a qualified name. ]
if (!SS.getScopeRep() && !TemplateTypeTy) {
// Look for a member, first.
- DeclContext::lookup_result Result
- = ClassDecl->lookup(MemberOrBase);
+ DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase);
if (!Result.empty()) {
ValueDecl *Member;
if ((Member = dyn_cast<FieldDecl>(Result.front())) ||
@@ -2666,10 +2908,11 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
// If no results were found, try to correct typos.
TypoCorrection Corr;
- MemInitializerValidatorCCC Validator(ClassDecl);
if (R.empty() && BaseType.isNull() &&
- (Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
- Validator, CTK_ErrorRecovery, ClassDecl))) {
+ (Corr = CorrectTypo(
+ R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
+ llvm::make_unique<MemInitializerValidatorCCC>(ClassDecl),
+ CTK_ErrorRecovery, ClassDecl))) {
if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
// We have found a non-static data member with a similar
// name to what was typed; complain and initialize that
@@ -2713,6 +2956,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (BaseType.isNull()) {
BaseType = Context.getTypeDeclType(TyD);
+ MarkAnyDeclReferenced(TyD->getLocation(), TyD, /*OdrUse=*/false);
if (SS.isSet())
// FIXME: preserve source range information
BaseType = Context.getElaboratedType(ETK_None, SS.getScopeRep(),
@@ -3528,19 +3772,19 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
return false;
if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) {
- Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context,
- Info.Ctor->getLocation(), Field);
+ ExprResult DIE =
+ SemaRef.BuildCXXDefaultInitExpr(Info.Ctor->getLocation(), Field);
+ if (DIE.isInvalid())
+ return true;
CXXCtorInitializer *Init;
if (Indirect)
- Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect,
- SourceLocation(),
- SourceLocation(), DIE,
- SourceLocation());
+ Init = new (SemaRef.Context)
+ CXXCtorInitializer(SemaRef.Context, Indirect, SourceLocation(),
+ SourceLocation(), DIE.get(), SourceLocation());
else
- Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
- SourceLocation(),
- SourceLocation(), DIE,
- SourceLocation());
+ Init = new (SemaRef.Context)
+ CXXCtorInitializer(SemaRef.Context, Field, SourceLocation(),
+ SourceLocation(), DIE.get(), SourceLocation());
return Info.addFieldInitializer(Init);
}
@@ -3582,6 +3826,8 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
DelegatingCtorDecls.push_back(Constructor);
+ DiagnoseUninitializedFields(*this, Constructor);
+
return false;
}
@@ -4234,7 +4480,7 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) {
if (!SO->second.front().Method->isPure())
continue;
- if (!SeenPureMethods.insert(SO->second.front().Method))
+ if (!SeenPureMethods.insert(SO->second.front().Method).second)
continue;
Diag(SO->second.front().Method->getLocation(),
@@ -4415,10 +4661,53 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info,
/// \brief Check class-level dllimport/dllexport attribute.
static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) {
Attr *ClassAttr = getDLLAttr(Class);
+
+ // MSVC inherits DLL attributes to partial class template specializations.
+ if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && !ClassAttr) {
+ if (auto *Spec = dyn_cast<ClassTemplatePartialSpecializationDecl>(Class)) {
+ if (Attr *TemplateAttr =
+ getDLLAttr(Spec->getSpecializedTemplate()->getTemplatedDecl())) {
+ auto *A = cast<InheritableAttr>(TemplateAttr->clone(S.getASTContext()));
+ A->setInherited(true);
+ ClassAttr = A;
+ }
+ }
+ }
+
if (!ClassAttr)
return;
- bool ClassExported = ClassAttr->getKind() == attr::DLLExport;
+ if (!Class->isExternallyVisible()) {
+ S.Diag(Class->getLocation(), diag::err_attribute_dll_not_extern)
+ << Class << ClassAttr;
+ return;
+ }
+
+ if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ !ClassAttr->isInherited()) {
+ // Diagnose dll attributes on members of class with dll attribute.
+ for (Decl *Member : Class->decls()) {
+ if (!isa<VarDecl>(Member) && !isa<CXXMethodDecl>(Member))
+ continue;
+ InheritableAttr *MemberAttr = getDLLAttr(Member);
+ if (!MemberAttr || MemberAttr->isInherited() || Member->isInvalidDecl())
+ continue;
+
+ S.Diag(MemberAttr->getLocation(),
+ diag::err_attribute_dll_member_of_dll_class)
+ << MemberAttr << ClassAttr;
+ S.Diag(ClassAttr->getLocation(), diag::note_previous_attribute);
+ Member->setInvalidDecl();
+ }
+ }
+
+ if (Class->getDescribedClassTemplate())
+ // Don't inherit dll attribute until the template is instantiated.
+ return;
+
+ // The class is either imported or exported.
+ const bool ClassExported = ClassAttr->getKind() == attr::DLLExport;
+ const bool ClassImported = !ClassExported;
// Force declaration of implicit members so they can inherit the attribute.
S.ForceDeclarationOfImplicitMembers(Class);
@@ -4426,6 +4715,9 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) {
// FIXME: MSVC's docs say all bases must be exportable, but this doesn't
// seem to be true in practice?
+ TemplateSpecializationKind TSK =
+ Class->getTemplateSpecializationKind();
+
for (Decl *Member : Class->decls()) {
VarDecl *VD = dyn_cast<VarDecl>(Member);
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member);
@@ -4434,50 +4726,57 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) {
if (!VD && !MD)
continue;
- // Don't process deleted methods.
- if (MD && MD->isDeleted())
- continue;
+ if (MD) {
+ // Don't process deleted methods.
+ if (MD->isDeleted())
+ continue;
- if (MD && MD->isMoveAssignmentOperator() && !ClassExported &&
- MD->isInlined()) {
- // Current MSVC versions don't export the move assignment operators, so
- // don't attempt to import them if we have a definition.
- continue;
- }
+ if (MD->isMoveAssignmentOperator() && ClassImported && MD->isInlined()) {
+ // Current MSVC versions don't export the move assignment operators, so
+ // don't attempt to import them if we have a definition.
+ continue;
+ }
- if (InheritableAttr *MemberAttr = getDLLAttr(Member)) {
- if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() &&
- !MemberAttr->isInherited() && !ClassAttr->isInherited()) {
- S.Diag(MemberAttr->getLocation(),
- diag::err_attribute_dll_member_of_dll_class)
- << MemberAttr << ClassAttr;
- S.Diag(ClassAttr->getLocation(), diag::note_previous_attribute);
- Member->setInvalidDecl();
+ if (MD->isInlined() && ClassImported &&
+ !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ // MinGW does not import inline functions.
continue;
}
- } else {
+ }
+
+ if (!getDLLAttr(Member)) {
auto *NewAttr =
cast<InheritableAttr>(ClassAttr->clone(S.getASTContext()));
NewAttr->setInherited(true);
Member->addAttr(NewAttr);
}
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
- if (ClassExported) {
- if (MD->isUserProvided()) {
- // Instantiate non-default methods.
- S.MarkFunctionReferenced(Class->getLocation(), MD);
- } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() ||
- MD->isCopyAssignmentOperator() ||
- MD->isMoveAssignmentOperator()) {
- // Instantiate non-trivial or explicitly defaulted methods, and the
- // copy assignment / move assignment operators.
- S.MarkFunctionReferenced(Class->getLocation(), MD);
- // Resolve its exception specification; CodeGen needs it.
- auto *FPT = MD->getType()->getAs<FunctionProtoType>();
- S.ResolveExceptionSpec(Class->getLocation(), FPT);
- S.ActOnFinishInlineMethodDef(MD);
- }
+ if (MD && ClassExported) {
+ if (MD->isUserProvided()) {
+ // Instantiate non-default class member functions ...
+
+ // .. except for certain kinds of template specializations.
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
+ continue;
+ if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited())
+ continue;
+
+ S.MarkFunctionReferenced(Class->getLocation(), MD);
+
+ // The function will be passed to the consumer when its definition is
+ // encountered.
+ } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() ||
+ MD->isCopyAssignmentOperator() ||
+ MD->isMoveAssignmentOperator()) {
+ // Synthesize and instantiate non-trivial implicit methods, explicitly
+ // defaulted methods, and the copy and move assignment operators. The
+ // latter are exported even if they are trivial, because the address of
+ // an operator can be taken and should compare equal accross libraries.
+ S.MarkFunctionReferenced(Class->getLocation(), MD);
+
+ // There is no later point when we will see the definition of this
+ // function, so pass it to the consumer now.
+ S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD));
}
}
}
@@ -4563,13 +4862,18 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
+ bool HasMethodWithOverrideControl = false,
+ HasOverridingMethodWithoutOverrideControl = false;
if (!Record->isDependentType()) {
for (auto *M : Record->methods()) {
// See if a method overloads virtual methods in a base
// class without overriding any.
if (!M->isStatic())
DiagnoseHiddenVirtualMethods(M);
-
+ if (M->hasAttr<OverrideAttr>())
+ HasMethodWithOverrideControl = true;
+ else if (M->size_overridden_methods() > 0)
+ HasOverridingMethodWithoutOverrideControl = true;
// Check whether the explicitly-defaulted special members are valid.
if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
CheckExplicitlyDefaultedSpecialMember(M);
@@ -4588,41 +4892,12 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
- // C++11 [dcl.constexpr]p8: A constexpr specifier for a non-static member
- // function that is not a constructor declares that member function to be
- // const. [...] The class of which that function is a member shall be
- // a literal type.
- //
- // If the class has virtual bases, any constexpr members will already have
- // been diagnosed by the checks performed on the member declaration, so
- // suppress this (less useful) diagnostic.
- //
- // We delay this until we know whether an explicitly-defaulted (or deleted)
- // destructor for the class is trivial.
- if (LangOpts.CPlusPlus11 && !Record->isDependentType() &&
- !Record->isLiteral() && !Record->getNumVBases()) {
- for (const auto *M : Record->methods()) {
- if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(M)) {
- switch (Record->getTemplateSpecializationKind()) {
- case TSK_ImplicitInstantiation:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- // If a template instantiates to a non-literal type, but its members
- // instantiate to constexpr functions, the template is technically
- // ill-formed, but we allow it for sanity.
- continue;
-
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- RequireLiteralType(M->getLocation(), Context.getRecordType(Record),
- diag::err_constexpr_method_non_literal);
- break;
- }
-
- // Only produce one error per class.
- break;
- }
- }
+ if (HasMethodWithOverrideControl &&
+ HasOverridingMethodWithoutOverrideControl) {
+ // At least one method has the 'override' control declared.
+ // Diagnose all other overridden methods which do not have 'override' specified on them.
+ for (auto *M : Record->methods())
+ DiagnoseAbsenceOfOverrideControl(M);
}
// ms_struct is a request to use the same ABI rules as MSVC. Check
@@ -4723,7 +4998,7 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
case Sema::CXXCopyAssignment:
case Sema::CXXMoveAssignment:
- if (!S.getLangOpts().CPlusPlus1y)
+ if (!S.getLangOpts().CPlusPlus14)
return false;
// In C++1y, we need to perform overload resolution.
Ctor = false;
@@ -4818,8 +5093,8 @@ static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
FunctionProtoType::ExtProtoInfo EPI;
// Build an exception specification pointing back at this member.
- EPI.ExceptionSpecType = EST_Unevaluated;
- EPI.ExceptionSpecDecl = MD;
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = MD;
// Set the calling convention to the default for C++ instance methods.
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(
@@ -4834,14 +5109,10 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD)
return;
// Evaluate the exception specification.
- ImplicitExceptionSpecification ExceptSpec =
- computeImplicitExceptionSpec(*this, Loc, MD);
-
- FunctionProtoType::ExtProtoInfo EPI;
- ExceptSpec.getEPI(EPI);
+ auto ESI = computeImplicitExceptionSpec(*this, Loc, MD).getExceptionSpec();
// Update the type of the special member to use it.
- UpdateExceptionSpec(MD, EPI);
+ UpdateExceptionSpec(MD, ESI);
// A user-provided destructor can be defined outside the class. When that
// happens, be sure to update the exception specification on both
@@ -4849,7 +5120,7 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD)
const FunctionProtoType *CanonicalFPT =
MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>();
if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated)
- UpdateExceptionSpec(MD->getCanonicalDecl(), EPI);
+ UpdateExceptionSpec(MD->getCanonicalDecl(), ESI);
}
void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
@@ -4911,7 +5182,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// A defaulted special member cannot have cv-qualifiers.
if (Type->getTypeQuals()) {
Diag(MD->getLocation(), diag::err_defaulted_special_member_quals)
- << (CSM == CXXMoveAssignment) << getLangOpts().CPlusPlus1y;
+ << (CSM == CXXMoveAssignment) << getLangOpts().CPlusPlus14;
HadError = true;
}
}
@@ -4960,7 +5231,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// destructors in C++1y), this is checked elsewhere.
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
HasConstParam);
- if ((getLangOpts().CPlusPlus1y ? !isa<CXXDestructorDecl>(MD)
+ if ((getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
: isa<CXXConstructorDecl>(MD)) &&
MD->isConstexpr() && !Constexpr &&
MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
@@ -4995,10 +5266,10 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// -- it is implicitly considered to have the same exception-specification
// as if it had been implicitly declared,
FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
- EPI.ExceptionSpecType = EST_Unevaluated;
- EPI.ExceptionSpecDecl = MD;
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = MD;
MD->setType(Context.getFunctionType(ReturnType,
- ArrayRef<QualType>(&ArgType,
+ llvm::makeArrayRef(&ArgType,
ExpectedParams),
EPI));
}
@@ -5026,11 +5297,18 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
/// C++11 [dcl.fct.def.default]p2.
void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) {
+ // If the exception specification was explicitly specified but hadn't been
+ // parsed when the method was defaulted, grab it now.
+ if (SpecifiedType->getExceptionSpecType() == EST_Unparsed)
+ SpecifiedType =
+ MD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();
+
// Compute the implicit exception specification.
CallingConv CC = Context.getDefaultCallingConvention(/*IsVariadic=*/false,
/*IsCXXMethod=*/true);
FunctionProtoType::ExtProtoInfo EPI(CC);
- computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
+ EPI.ExceptionSpec = computeImplicitExceptionSpec(*this, MD->getLocation(), MD)
+ .getExceptionSpec();
const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(
Context.getFunctionType(Context.VoidTy, None, EPI));
@@ -5043,27 +5321,21 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
}
void Sema::CheckDelayedMemberExceptionSpecs() {
- SmallVector<std::pair<const CXXDestructorDecl *, const CXXDestructorDecl *>,
- 2> Checks;
- SmallVector<std::pair<CXXMethodDecl *, const FunctionProtoType *>, 2> Specs;
+ decltype(DelayedExceptionSpecChecks) Checks;
+ decltype(DelayedDefaultedMemberExceptionSpecs) Specs;
- std::swap(Checks, DelayedDestructorExceptionSpecChecks);
+ std::swap(Checks, DelayedExceptionSpecChecks);
std::swap(Specs, DelayedDefaultedMemberExceptionSpecs);
// Perform any deferred checking of exception specifications for virtual
// destructors.
- for (unsigned i = 0, e = Checks.size(); i != e; ++i) {
- const CXXDestructorDecl *Dtor = Checks[i].first;
- assert(!Dtor->getParent()->isDependentType() &&
- "Should not ever add destructors of templates into the list.");
- CheckOverridingFunctionExceptionSpec(Dtor, Checks[i].second);
- }
+ for (auto &Check : Checks)
+ CheckOverridingFunctionExceptionSpec(Check.first, Check.second);
// Check that any explicitly-defaulted methods have exception specifications
// compatible with their implicit exception specifications.
- for (unsigned I = 0, N = Specs.size(); I != N; ++I)
- CheckExplicitlyDefaultedMemberExceptionSpec(Specs[I].first,
- Specs[I].second);
+ for (auto &Spec : Specs)
+ CheckExplicitlyDefaultedMemberExceptionSpec(Spec.first, Spec.second);
}
namespace {
@@ -5491,6 +5763,13 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
if (SMI.shouldDeleteForAllConstMembers())
return true;
+ if (getLangOpts().CUDA) {
+ // We should delete the special member in CUDA mode if target inference
+ // failed.
+ return inferCUDATargetForImplicitSpecialMember(RD, CSM, MD, SMI.ConstArg,
+ Diagnose);
+ }
+
return false;
}
@@ -5907,7 +6186,7 @@ namespace {
/// \brief Check whether any most overriden method from MD in Methods
static bool CheckMostOverridenMethods(const CXXMethodDecl *MD,
- const llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) {
+ const llvm::SmallPtrSetImpl<const CXXMethodDecl *>& Methods) {
if (MD->size_overridden_methods() == 0)
return Methods.count(MD->getCanonicalDecl());
for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
@@ -5945,7 +6224,14 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
if (!MD->isVirtual())
continue;
// If the method we are checking overrides a method from its base
- // don't warn about the other overloaded methods.
+ // don't warn about the other overloaded methods. Clang deviates from GCC
+ // by only diagnosing overloads of inherited virtual functions that do not
+ // override any other virtual functions in the base. GCC's
+ // -Woverloaded-virtual diagnoses any derived function hiding a virtual
+ // function from a base class. These cases may be better served by a
+ // warning (not specific to virtual functions) on call sites when the call
+ // would select a different function from the base class, were it visible.
+ // See FIXME in test/SemaCXX/warn-overload-virtual.cpp for an example.
if (!Data.S->IsOverload(Data.Method, MD, false))
return true;
// Collect the overload only if its hidden.
@@ -5962,7 +6248,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
/// \brief Add the most overriden methods from MD to Methods
static void AddMostOverridenMethods(const CXXMethodDecl *MD,
- llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) {
+ llvm::SmallPtrSetImpl<const CXXMethodDecl *>& Methods) {
if (MD->size_overridden_methods() == 0)
Methods.insert(MD->getCanonicalDecl());
for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
@@ -6515,6 +6801,22 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
return Context.getFunctionType(Context.VoidTy, None, EPI);
}
+static void extendLeft(SourceRange &R, const SourceRange &Before) {
+ if (Before.isInvalid())
+ return;
+ R.setBegin(Before.getBegin());
+ if (R.getEnd().isInvalid())
+ R.setEnd(Before.getEnd());
+}
+
+static void extendRight(SourceRange &R, const SourceRange &After) {
+ if (After.isInvalid())
+ return;
+ if (R.getBegin().isInvalid())
+ R.setBegin(After.getBegin());
+ R.setEnd(After.getEnd());
+}
+
/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
/// well-formednes of the conversion function declarator @p D with
/// type @p R. If there are any errors in the declarator, this routine
@@ -6536,7 +6838,9 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
SC = SC_None;
}
- QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId);
+ TypeSourceInfo *ConvTSI = nullptr;
+ QualType ConvType =
+ GetTypeFromParser(D.getName().ConversionFunctionId, &ConvTSI);
if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) {
// Conversion functions don't have return types, but the parser will
@@ -6570,9 +6874,75 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// Diagnose "&operator bool()" and other such nonsense. This
// is actually a gcc extension which we don't support.
if (Proto->getReturnType() != ConvType) {
- Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl)
- << Proto->getReturnType();
- D.setInvalidType();
+ bool NeedsTypedef = false;
+ SourceRange Before, After;
+
+ // Walk the chunks and extract information on them for our diagnostic.
+ bool PastFunctionChunk = false;
+ for (auto &Chunk : D.type_objects()) {
+ switch (Chunk.Kind) {
+ case DeclaratorChunk::Function:
+ if (!PastFunctionChunk) {
+ if (Chunk.Fun.HasTrailingReturnType) {
+ TypeSourceInfo *TRT = nullptr;
+ GetTypeFromParser(Chunk.Fun.getTrailingReturnType(), &TRT);
+ if (TRT) extendRight(After, TRT->getTypeLoc().getSourceRange());
+ }
+ PastFunctionChunk = true;
+ break;
+ }
+ // Fall through.
+ case DeclaratorChunk::Array:
+ NeedsTypedef = true;
+ extendRight(After, Chunk.getSourceRange());
+ break;
+
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::MemberPointer:
+ extendLeft(Before, Chunk.getSourceRange());
+ break;
+
+ case DeclaratorChunk::Paren:
+ extendLeft(Before, Chunk.Loc);
+ extendRight(After, Chunk.EndLoc);
+ break;
+ }
+ }
+
+ SourceLocation Loc = Before.isValid() ? Before.getBegin() :
+ After.isValid() ? After.getBegin() :
+ D.getIdentifierLoc();
+ auto &&DB = Diag(Loc, diag::err_conv_function_with_complex_decl);
+ DB << Before << After;
+
+ if (!NeedsTypedef) {
+ DB << /*don't need a typedef*/0;
+
+ // If we can provide a correct fix-it hint, do so.
+ if (After.isInvalid() && ConvTSI) {
+ SourceLocation InsertLoc =
+ PP.getLocForEndOfToken(ConvTSI->getTypeLoc().getLocEnd());
+ DB << FixItHint::CreateInsertion(InsertLoc, " ")
+ << FixItHint::CreateInsertionFromRange(
+ InsertLoc, CharSourceRange::getTokenRange(Before))
+ << FixItHint::CreateRemoval(Before);
+ }
+ } else if (!Proto->getReturnType()->isDependentType()) {
+ DB << /*typedef*/1 << Proto->getReturnType();
+ } else if (getLangOpts().CPlusPlus11) {
+ DB << /*alias template*/2 << Proto->getReturnType();
+ } else {
+ DB << /*might not be fixable*/3;
+ }
+
+ // Recover by incorporating the other type chunks into the result type.
+ // Note, this does *not* change the name of the function. This is compatible
+ // with the GCC extension:
+ // struct S { &operator int(); } s;
+ // int &r = s.operator int(); // ok in GCC
+ // S::operator int&() {} // error in GCC, function name is 'operator int'.
ConvType = Proto->getReturnType();
}
@@ -6893,7 +7263,7 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() {
/*PrevDecl=*/nullptr);
getStdNamespace()->setImplicit(true);
}
-
+
return getStdNamespace();
}
@@ -7054,12 +7424,11 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident) {
- NamespaceValidatorCCC Validator;
R.clear();
- if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), Sc, &SS,
- Validator,
- Sema::CTK_ErrorRecovery)) {
+ if (TypoCorrection Corrected =
+ S.CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), Sc, &SS,
+ llvm::make_unique<NamespaceValidatorCCC>(),
+ Sema::CTK_ErrorRecovery)) {
if (DeclContext *DC = S.computeDeclContext(SS, false)) {
std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
@@ -7124,6 +7493,10 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
NamedDecl *Named = R.getFoundDecl();
assert((isa<NamespaceDecl>(Named) || isa<NamespaceAliasDecl>(Named))
&& "expected namespace decl");
+
+ // The use of a nested name specifier may trigger deprecation warnings.
+ DiagnoseUseOfDecl(Named, IdentLoc);
+
// C++ [namespace.udir]p1:
// A using-directive specifies that the names in the nominated
// namespace can be used in the scope in which the
@@ -7685,11 +8058,12 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// Try to correct typos if possible.
if (R.empty()) {
- UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation, SS.getScopeRep(),
- dyn_cast<CXXRecordDecl>(CurContext));
- if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), S, &SS, CCC,
- CTK_ErrorRecovery)){
+ if (TypoCorrection Corrected = CorrectTypo(
+ R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
+ llvm::make_unique<UsingValidatorCCC>(
+ HasTypenameKeyword, IsInstantiation, SS.getScopeRep(),
+ dyn_cast<CXXRecordDecl>(CurContext)),
+ CTK_ErrorRecovery)) {
// We reject any correction for which ND would be NULL.
NamedDecl *ND = Corrected.getCorrectionDecl();
@@ -7874,7 +8248,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
// If we weren't able to compute a valid scope, it must be a
// dependent class scope.
if (!NamedContext || NamedContext->isRecord()) {
- auto *RD = dyn_cast<CXXRecordDecl>(NamedContext);
+ auto *RD = dyn_cast_or_null<CXXRecordDecl>(NamedContext);
if (RD && RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), RD))
RD = nullptr;
@@ -8164,6 +8538,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc,
Name.Identifier, TemplateParams,
NewTD);
+ NewTD->setDescribedAliasTemplate(NewDecl);
NewDecl->setAccess(AS);
@@ -8185,57 +8560,65 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
return NewND;
}
-Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
- SourceLocation NamespaceLoc,
- SourceLocation AliasLoc,
- IdentifierInfo *Alias,
- CXXScopeSpec &SS,
- SourceLocation IdentLoc,
- IdentifierInfo *Ident) {
+Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
+ SourceLocation AliasLoc,
+ IdentifierInfo *Alias, CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *Ident) {
// Lookup the namespace name.
LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName);
LookupParsedName(R, S, &SS);
+ if (R.isAmbiguous())
+ return nullptr;
+
+ if (R.empty()) {
+ if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
+ Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
+ return nullptr;
+ }
+ }
+ assert(!R.isAmbiguous() && !R.empty());
+
// Check if we have a previous declaration with the same name.
- NamedDecl *PrevDecl
- = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName,
- ForRedeclaration);
+ NamedDecl *PrevDecl = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName,
+ ForRedeclaration);
if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
PrevDecl = nullptr;
+ NamedDecl *ND = R.getFoundDecl();
+
if (PrevDecl) {
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
// We already have an alias with the same name that points to the same
- // namespace, so don't create a new one.
- // FIXME: At some point, we'll want to create the (redundant)
- // declaration to maintain better source information.
- if (!R.isAmbiguous() && !R.empty() &&
- AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl())))
+ // namespace; check that it matches.
+ if (!AD->getNamespace()->Equals(getNamespaceDecl(ND))) {
+ Diag(AliasLoc, diag::err_redefinition_different_namespace_alias)
+ << Alias;
+ Diag(PrevDecl->getLocation(), diag::note_previous_namespace_alias)
+ << AD->getNamespace();
return nullptr;
- }
-
- unsigned DiagID = isa<NamespaceDecl>(PrevDecl) ? diag::err_redefinition :
- diag::err_redefinition_different_kind;
- Diag(AliasLoc, DiagID) << Alias;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- return nullptr;
- }
-
- if (R.isAmbiguous())
- return nullptr;
-
- if (R.empty()) {
- if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
- Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
+ }
+ } else {
+ unsigned DiagID = isa<NamespaceDecl>(PrevDecl)
+ ? diag::err_redefinition
+ : diag::err_redefinition_different_kind;
+ Diag(AliasLoc, DiagID) << Alias;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
return nullptr;
}
}
+ // The use of a nested name specifier may trigger deprecation warnings.
+ DiagnoseUseOfDecl(ND, IdentLoc);
+
NamespaceAliasDecl *AliasDecl =
NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc,
Alias, SS.getWithLocInContext(Context),
- IdentLoc, R.getFoundDecl());
+ IdentLoc, ND);
+ if (PrevDecl)
+ AliasDecl->setPreviousDecl(cast<NamespaceAliasDecl>(PrevDecl));
PushOnScopeChains(AliasDecl, S);
return AliasDecl;
@@ -8285,22 +8668,6 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
if (F->hasInClassInitializer()) {
if (Expr *E = F->getInClassInitializer())
ExceptSpec.CalledExpr(E);
- else if (!F->isInvalidDecl())
- // DR1351:
- // If the brace-or-equal-initializer of a non-static data member
- // invokes a defaulted default constructor of its class or of an
- // enclosing class in a potentially evaluated subexpression, the
- // program is ill-formed.
- //
- // This resolution is unworkable: the exception specification of the
- // default constructor can be needed in an unevaluated context, in
- // particular, in the operand of a noexcept-expression, and we can be
- // unable to compute an exception specification for an enclosed class.
- //
- // We do not allow an in-class initializer to require the evaluation
- // of the exception specification for any in-class initializer whose
- // definition is not lexically complete.
- Diag(Loc, diag::err_in_class_initializer_references_def_ctor) << MD;
} else if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
@@ -8368,9 +8735,6 @@ Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) {
if (F->hasInClassInitializer()) {
if (Expr *E = F->getInClassInitializer())
ExceptSpec.CalledExpr(E);
- else if (!F->isInvalidDecl())
- Diag(CD->getLocation(),
- diag::err_in_class_initializer_references_def_ctor) << CD;
} else if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
@@ -8392,7 +8756,7 @@ struct DeclaringSpecialMember {
DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM)
: S(S), D(RD, CSM) {
- WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D);
+ WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D).second;
if (WasAlreadyBeingDeclared)
// This almost never happens, but if it does, ensure that our cache
// doesn't contain a stale result.
@@ -8421,7 +8785,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
// 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->needsImplicitDefaultConstructor() &&
+ assert(ClassDecl->needsImplicitDefaultConstructor() &&
"Should not build implicit default constructor!");
DeclaringSpecialMember DSM(*this, ClassDecl, CXXDefaultConstructor);
@@ -8445,7 +8809,13 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
/*isImplicitlyDeclared=*/true, Constexpr);
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
- DefaultCon->setImplicit();
+
+ if (getLangOpts().CUDA) {
+ inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDefaultConstructor,
+ DefaultCon,
+ /* ConstRHS */ false,
+ /* Diagnose */ false);
+ }
// Build an exception specification pointing back at this constructor.
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, DefaultCon);
@@ -8488,6 +8858,11 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
return;
}
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ Constructor->getType()->castAs<FunctionProtoType>());
+
SourceLocation Loc = Constructor->getLocEnd().isValid()
? Constructor->getLocEnd()
: Constructor->getLocation();
@@ -8597,7 +8972,7 @@ private:
void inherit(const CXXConstructorDecl *Ctor) {
const FunctionProtoType *CtorType =
Ctor->getType()->castAs<FunctionProtoType>();
- ArrayRef<QualType> ArgTypes(CtorType->getParamTypes());
+ ArrayRef<QualType> ArgTypes = CtorType->getParamTypes();
FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo();
SourceLocation UsingLoc = getUsingLoc(Ctor->getParent());
@@ -8737,8 +9112,8 @@ private:
// Build an unevaluated exception specification for this constructor.
const FunctionProtoType *FPT = DerivedType->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- EPI.ExceptionSpecType = EST_Unevaluated;
- EPI.ExceptionSpecDecl = DerivedCtor;
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = DerivedCtor;
DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(),
FPT->getParamTypes(), EPI));
@@ -8900,7 +9275,13 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
- Destructor->setImplicit();
+
+ if (getLangOpts().CUDA) {
+ inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDestructor,
+ Destructor,
+ /* ConstRHS */ false,
+ /* Diagnose */ false);
+ }
// Build an exception specification pointing back at this destructor.
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor);
@@ -8952,6 +9333,11 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
return;
}
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ Destructor->getType()->castAs<FunctionProtoType>());
+
SourceLocation Loc = Destructor->getLocEnd().isValid()
? Destructor->getLocEnd()
: Destructor->getLocation();
@@ -8971,7 +9357,7 @@ void Sema::ActOnFinishCXXMemberDecls() {
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(CurContext)) {
if (Record->isInvalidDecl()) {
DelayedDefaultedMemberExceptionSpecs.clear();
- DelayedDestructorExceptionSpecChecks.clear();
+ DelayedExceptionSpecChecks.clear();
return;
}
}
@@ -8995,8 +9381,8 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
// the only thing of interest in the destructor type is its extended info.
// The return and arguments are fixed.
FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();
- EPI.ExceptionSpecType = EST_Unevaluated;
- EPI.ExceptionSpecDecl = Destructor;
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = Destructor;
Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
// FIXME: If the destructor has a body that could throw, and the newly created
@@ -9032,7 +9418,7 @@ class RefBuilder: public ExprBuilder {
QualType VarType;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const override {
+ Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(S.BuildDeclRefExpr(Var, VarType, VK_LValue, Loc).get());
}
@@ -9042,7 +9428,7 @@ public:
class ThisBuilder: public ExprBuilder {
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const override {
+ Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(S.ActOnCXXThis(Loc).getAs<Expr>());
}
};
@@ -9054,7 +9440,7 @@ class CastBuilder: public ExprBuilder {
const CXXCastPath &Path;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const override {
+ Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(S.ImpCastExprToType(Builder.build(S, Loc), Type,
CK_UncheckedDerivedToBase, Kind,
&Path).get());
@@ -9069,7 +9455,7 @@ class DerefBuilder: public ExprBuilder {
const ExprBuilder &Builder;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const override {
+ Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(
S.CreateBuiltinUnaryOp(Loc, UO_Deref, Builder.build(S, Loc)).get());
}
@@ -9085,7 +9471,7 @@ class MemberBuilder: public ExprBuilder {
LookupResult &MemberLookup;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const override {
+ Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(S.BuildMemberReferenceExpr(
Builder.build(S, Loc), Type, Loc, IsArrow, SS, SourceLocation(),
nullptr, MemberLookup, nullptr).get());
@@ -9101,7 +9487,7 @@ class MoveCastBuilder: public ExprBuilder {
const ExprBuilder &Builder;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const override {
+ Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(CastForMoving(S, Builder.build(S, Loc)));
}
@@ -9112,7 +9498,7 @@ class LvalueConvBuilder: public ExprBuilder {
const ExprBuilder &Builder;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const override {
+ Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(
S.DefaultLvalueConversion(Builder.build(S, Loc)).get());
}
@@ -9125,7 +9511,7 @@ class SubscriptBuilder: public ExprBuilder {
const ExprBuilder &Index;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const override {
+ Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(S.CreateBuiltinArraySubscriptExpr(
Base.build(S, Loc), Loc, Index.build(S, Loc), Loc).get());
}
@@ -9521,6 +9907,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
+ if (getLangOpts().CUDA) {
+ inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXCopyAssignment,
+ CopyAssignment,
+ /* ConstRHS */ Const,
+ /* Diagnose */ false);
+ }
+
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI =
getImplicitMethodEPI(*this, CopyAssignment);
@@ -9795,6 +10188,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
}
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ CopyAssignOperator->getType()->castAs<FunctionProtoType>());
+
if (Invalid) {
CopyAssignOperator->setInvalidDecl();
return;
@@ -9898,6 +10296,13 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
MoveAssignment->setDefaulted();
MoveAssignment->setImplicit();
+ if (getLangOpts().CUDA) {
+ inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXMoveAssignment,
+ MoveAssignment,
+ /* ConstRHS */ false,
+ /* Diagnose */ false);
+ }
+
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI =
getImplicitMethodEPI(*this, MoveAssignment);
@@ -10217,6 +10622,11 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
}
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ MoveAssignOperator->getType()->castAs<FunctionProtoType>());
+
if (Invalid) {
MoveAssignOperator->setInvalidDecl();
return;
@@ -10319,6 +10729,13 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
+ if (getLangOpts().CUDA) {
+ inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXCopyConstructor,
+ CopyConstructor,
+ /* ConstRHS */ Const,
+ /* Diagnose */ false);
+ }
+
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI =
getImplicitMethodEPI(*this, CopyConstructor);
@@ -10386,6 +10803,11 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>());
}
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ CopyConstructor->getType()->castAs<FunctionProtoType>());
+
CopyConstructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -10484,6 +10906,13 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();
+ if (getLangOpts().CUDA) {
+ inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXMoveConstructor,
+ MoveConstructor,
+ /* ConstRHS */ false,
+ /* Diagnose */ false);
+ }
+
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI =
getImplicitMethodEPI(*this, MoveConstructor);
@@ -10546,6 +10975,11 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>());
}
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ MoveConstructor->getType()->castAs<FunctionProtoType>());
+
MoveConstructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -10765,6 +11199,56 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
ParenRange);
}
+ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
+ assert(Field->hasInClassInitializer());
+
+ // If we already have the in-class initializer nothing needs to be done.
+ if (Field->getInClassInitializer())
+ return CXXDefaultInitExpr::Create(Context, Loc, Field);
+
+ // Maybe we haven't instantiated the in-class initializer. Go check the
+ // pattern FieldDecl to see if it has one.
+ CXXRecordDecl *ParentRD = cast<CXXRecordDecl>(Field->getParent());
+
+ if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) {
+ CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern();
+ DeclContext::lookup_result Lookup =
+ ClassPattern->lookup(Field->getDeclName());
+ assert(Lookup.size() == 1);
+ FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]);
+ if (InstantiateInClassInitializer(Loc, Field, Pattern,
+ getTemplateInstantiationArgs(Field)))
+ return ExprError();
+ return CXXDefaultInitExpr::Create(Context, Loc, Field);
+ }
+
+ // DR1351:
+ // If the brace-or-equal-initializer of a non-static data member
+ // invokes a defaulted default constructor of its class or of an
+ // enclosing class in a potentially evaluated subexpression, the
+ // program is ill-formed.
+ //
+ // This resolution is unworkable: the exception specification of the
+ // default constructor can be needed in an unevaluated context, in
+ // particular, in the operand of a noexcept-expression, and we can be
+ // unable to compute an exception specification for an enclosed class.
+ //
+ // Any attempt to resolve the exception specification of a defaulted default
+ // constructor before the initializer is lexically complete will ultimately
+ // come here at which point we can diagnose it.
+ RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext();
+ if (OutermostClass == ParentRD) {
+ Diag(Field->getLocEnd(), diag::err_in_class_initializer_not_yet_parsed)
+ << ParentRD << Field;
+ } else {
+ Diag(Field->getLocEnd(),
+ diag::err_in_class_initializer_not_yet_parsed_outer_class)
+ << ParentRD << OutermostClass << Field;
+ }
+
+ return ExprError();
+}
+
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
if (VD->isInvalidDecl()) return;
@@ -10834,8 +11318,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
DiagnoseSentinelCalls(Constructor, Loc, AllArgs);
CheckConstructorCall(Constructor,
- llvm::makeArrayRef<const Expr *>(AllArgs.data(),
- AllArgs.size()),
+ llvm::makeArrayRef(AllArgs.data(), AllArgs.size()),
Proto, Loc);
return Invalid;
@@ -12118,8 +12601,12 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
}
// Mark templated-scope function declarations as unsupported.
- if (FD->getNumTemplateParameterLists())
+ if (FD->getNumTemplateParameterLists() && SS.isValid()) {
+ Diag(FD->getLocation(), diag::warn_template_qualified_friend_unsupported)
+ << SS.getScopeRep() << SS.getRange()
+ << cast<CXXRecordDecl>(CurContext);
FrD->setUnsupportedFriend(true);
+ }
}
return ND;
@@ -12220,11 +12707,6 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
CheckExplicitlyDefaultedSpecialMember(MD);
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(DefaultLoc,
- MD->getType()->castAs<FunctionProtoType>());
-
if (MD->isInvalidDecl())
return;
@@ -12538,7 +13020,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired));
if (!Pos.second) {
// If we already had an entry, check to see if we are promoting this vtable
- // to required a definition. If so, we need to reappend to the VTableUses
+ // to require a definition. If so, we need to reappend to the VTableUses
// list, since we may have already processed the first entry.
if (DefinitionRequired && !Pos.first->second) {
Pos.first->second = true;
@@ -12739,10 +13221,10 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
AllToInit.push_back(Member);
// Be sure that the destructor is accessible and is marked as referenced.
- if (const RecordType *RecordTy
- = Context.getBaseElementType(Field->getType())
- ->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (const RecordType *RecordTy =
+ Context.getBaseElementType(Field->getType())
+ ->getAs<RecordType>()) {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
MarkFunctionReferenced(Field->getLocation(), Destructor);
CheckDestructorAccess(Field->getLocation(), Destructor,
@@ -12780,7 +13262,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
// Avoid dereferencing a null pointer here.
*TCanonical = Target? Target->getCanonicalDecl() : nullptr;
- if (!Current.insert(Canonical))
+ if (!Current.insert(Canonical).second)
return;
// We know that beyond here, we aren't chaining into a cycle.
@@ -12898,6 +13380,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
FindCXXThisExpr Finder(*this);
switch (Proto->getExceptionSpecType()) {
+ case EST_Unparsed:
case EST_Uninstantiated:
case EST_Unevaluated:
case EST_BasicNoexcept:
@@ -12934,27 +13417,27 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
else if (const auto *G = dyn_cast<PtGuardedByAttr>(A))
Arg = G->getArg();
else if (const auto *AA = dyn_cast<AcquiredAfterAttr>(A))
- Args = ArrayRef<Expr *>(AA->args_begin(), AA->args_size());
+ Args = llvm::makeArrayRef(AA->args_begin(), AA->args_size());
else if (const auto *AB = dyn_cast<AcquiredBeforeAttr>(A))
- Args = ArrayRef<Expr *>(AB->args_begin(), AB->args_size());
+ Args = llvm::makeArrayRef(AB->args_begin(), AB->args_size());
else if (const auto *ETLF = dyn_cast<ExclusiveTrylockFunctionAttr>(A)) {
Arg = ETLF->getSuccessValue();
- Args = ArrayRef<Expr *>(ETLF->args_begin(), ETLF->args_size());
+ Args = llvm::makeArrayRef(ETLF->args_begin(), ETLF->args_size());
} else if (const auto *STLF = dyn_cast<SharedTrylockFunctionAttr>(A)) {
Arg = STLF->getSuccessValue();
- Args = ArrayRef<Expr *>(STLF->args_begin(), STLF->args_size());
+ Args = llvm::makeArrayRef(STLF->args_begin(), STLF->args_size());
} else if (const auto *LR = dyn_cast<LockReturnedAttr>(A))
Arg = LR->getArg();
else if (const auto *LE = dyn_cast<LocksExcludedAttr>(A))
- Args = ArrayRef<Expr *>(LE->args_begin(), LE->args_size());
+ Args = llvm::makeArrayRef(LE->args_begin(), LE->args_size());
else if (const auto *RC = dyn_cast<RequiresCapabilityAttr>(A))
- Args = ArrayRef<Expr *>(RC->args_begin(), RC->args_size());
+ Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size());
else if (const auto *AC = dyn_cast<AcquireCapabilityAttr>(A))
- Args = ArrayRef<Expr *>(AC->args_begin(), AC->args_size());
+ Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size());
else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A))
- Args = ArrayRef<Expr *>(AC->args_begin(), AC->args_size());
+ Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size());
else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A))
- Args = ArrayRef<Expr *>(RC->args_begin(), RC->args_size());
+ Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size());
if (Arg && !Finder.TraverseStmt(Arg))
return true;
@@ -12968,28 +13451,29 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
return false;
}
-void
-Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
- ArrayRef<ParsedType> DynamicExceptions,
- ArrayRef<SourceRange> DynamicExceptionRanges,
- Expr *NoexceptExpr,
- SmallVectorImpl<QualType> &Exceptions,
- FunctionProtoType::ExtProtoInfo &EPI) {
+void Sema::checkExceptionSpecification(
+ bool IsTopLevel, ExceptionSpecificationType EST,
+ ArrayRef<ParsedType> DynamicExceptions,
+ ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr,
+ SmallVectorImpl<QualType> &Exceptions,
+ FunctionProtoType::ExceptionSpecInfo &ESI) {
Exceptions.clear();
- EPI.ExceptionSpecType = EST;
+ ESI.Type = EST;
if (EST == EST_Dynamic) {
Exceptions.reserve(DynamicExceptions.size());
for (unsigned ei = 0, ee = DynamicExceptions.size(); ei != ee; ++ei) {
// FIXME: Preserve type source info.
QualType ET = GetTypeFromParser(DynamicExceptions[ei]);
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- collectUnexpandedParameterPacks(ET, Unexpanded);
- if (!Unexpanded.empty()) {
- DiagnoseUnexpandedParameterPacks(DynamicExceptionRanges[ei].getBegin(),
- UPPC_ExceptionType,
- Unexpanded);
- continue;
+ if (IsTopLevel) {
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ collectUnexpandedParameterPacks(ET, Unexpanded);
+ if (!Unexpanded.empty()) {
+ DiagnoseUnexpandedParameterPacks(
+ DynamicExceptionRanges[ei].getBegin(), UPPC_ExceptionType,
+ Unexpanded);
+ continue;
+ }
}
// Check that the type is valid for an exception spec, and
@@ -12997,11 +13481,10 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
if (!CheckSpecifiedExceptionType(ET, DynamicExceptionRanges[ei]))
Exceptions.push_back(ET);
}
- EPI.NumExceptions = Exceptions.size();
- EPI.Exceptions = Exceptions.data();
+ ESI.Exceptions = Exceptions;
return;
}
-
+
if (EST == EST_ComputedNoexcept) {
// If an error occurred, there's no expression here.
if (NoexceptExpr) {
@@ -13009,59 +13492,59 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
Context.BoolTy) &&
"Parser should have made sure that the expression is boolean");
- if (NoexceptExpr && DiagnoseUnexpandedParameterPack(NoexceptExpr)) {
- EPI.ExceptionSpecType = EST_BasicNoexcept;
+ if (IsTopLevel && NoexceptExpr &&
+ DiagnoseUnexpandedParameterPack(NoexceptExpr)) {
+ ESI.Type = EST_BasicNoexcept;
return;
}
-
+
if (!NoexceptExpr->isValueDependent())
NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, nullptr,
diag::err_noexcept_needs_constant_expression,
/*AllowFold*/ false).get();
- EPI.NoexceptExpr = NoexceptExpr;
+ ESI.NoexceptExpr = NoexceptExpr;
}
return;
}
}
-/// IdentifyCUDATarget - Determine the CUDA compilation target for this function
-Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
- // Implicitly declared functions (e.g. copy constructors) are
- // __host__ __device__
- if (D->isImplicit())
- return CFT_HostDevice;
-
- if (D->hasAttr<CUDAGlobalAttr>())
- return CFT_Global;
+void Sema::actOnDelayedExceptionSpecification(Decl *MethodD,
+ ExceptionSpecificationType EST,
+ SourceRange SpecificationRange,
+ ArrayRef<ParsedType> DynamicExceptions,
+ ArrayRef<SourceRange> DynamicExceptionRanges,
+ Expr *NoexceptExpr) {
+ if (!MethodD)
+ return;
- if (D->hasAttr<CUDADeviceAttr>()) {
- if (D->hasAttr<CUDAHostAttr>())
- return CFT_HostDevice;
- return CFT_Device;
- }
+ // Dig out the method we're referring to.
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(MethodD))
+ MethodD = FunTmpl->getTemplatedDecl();
- return CFT_Host;
-}
+ CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(MethodD);
+ if (!Method)
+ return;
-bool Sema::CheckCUDATarget(CUDAFunctionTarget CallerTarget,
- CUDAFunctionTarget CalleeTarget) {
- // CUDA B.1.1 "The __device__ qualifier declares a function that is...
- // Callable from the device only."
- if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device)
- return true;
+ // Check the exception specification.
+ llvm::SmallVector<QualType, 4> Exceptions;
+ FunctionProtoType::ExceptionSpecInfo ESI;
+ checkExceptionSpecification(/*IsTopLevel*/true, EST, DynamicExceptions,
+ DynamicExceptionRanges, NoexceptExpr, Exceptions,
+ ESI);
- // CUDA B.1.2 "The __global__ qualifier declares a function that is...
- // Callable from the host only."
- // CUDA B.1.3 "The __host__ qualifier declares a function that is...
- // Callable from the host only."
- if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) &&
- (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global))
- return true;
+ // Update the exception specification on the function type.
+ Context.adjustExceptionSpec(Method, ESI, /*AsWritten*/true);
- if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice)
- return true;
+ if (Method->isStatic())
+ checkThisInStaticMemberFunctionExceptionSpec(Method);
- return false;
+ if (Method->isVirtual()) {
+ // Check overrides, which we previously had to delay.
+ for (CXXMethodDecl::method_iterator O = Method->begin_overridden_methods(),
+ OEnd = Method->end_overridden_methods();
+ O != OEnd; ++O)
+ CheckOverridingFunctionExceptionSpec(Method, *O);
+ }
}
/// HandleMSProperty - Analyze a __delcspec(property) field of a C++ class.
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index b5205b3e6238..7e3da941b339 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -118,10 +118,7 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
// a suitable return type, but the new (overriding) method does not have
// a suitable return type.
QualType ResultType = NewMethod->getReturnType();
- SourceRange ResultTypeRange;
- if (const TypeSourceInfo *ResultTypeInfo =
- NewMethod->getReturnTypeSourceInfo())
- ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+ SourceRange ResultTypeRange = NewMethod->getReturnTypeSourceRange();
// Figure out which class this method is part of, if any.
ObjCInterfaceDecl *CurrentClass
@@ -204,15 +201,13 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
case OMF_autorelease:
case OMF_retainCount:
case OMF_self:
+ case OMF_initialize:
case OMF_performSelector:
return false;
case OMF_dealloc:
if (!Context.hasSameType(method->getReturnType(), Context.VoidTy)) {
- SourceRange ResultTypeRange;
- if (const TypeSourceInfo *ResultTypeInfo =
- method->getReturnTypeSourceInfo())
- ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+ SourceRange ResultTypeRange = method->getReturnTypeSourceRange();
if (ResultTypeRange.isInvalid())
Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
<< method->getReturnType()
@@ -359,6 +354,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
case OMF_copy:
case OMF_new:
case OMF_self:
+ case OMF_initialize:
case OMF_performSelector:
break;
}
@@ -520,10 +516,11 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (!PrevDecl) {
// Try to correct for a typo in the superclass name without correcting
// to the class we're defining.
- ObjCInterfaceValidatorCCC Validator(IDecl);
- if (TypoCorrection Corrected = CorrectTypo(
- DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
- nullptr, Validator, CTK_ErrorRecovery)) {
+ if (TypoCorrection Corrected =
+ CorrectTypo(DeclarationNameInfo(SuperName, SuperLoc),
+ LookupOrdinaryName, TUScope, nullptr,
+ llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl),
+ CTK_ErrorRecovery)) {
diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest)
<< SuperName << ClassName);
PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
@@ -790,10 +787,10 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
ProtocolId[i].second);
if (!PDecl) {
- DeclFilterCCC<ObjCProtocolDecl> Validator;
TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
- LookupObjCProtocolName, TUScope, nullptr, Validator,
+ LookupObjCProtocolName, TUScope, nullptr,
+ llvm::make_unique<DeclFilterCCC<ObjCProtocolDecl>>(),
CTK_ErrorRecovery);
if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>()))
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_protocol_suggest)
@@ -1031,11 +1028,9 @@ Decl *Sema::ActOnStartClassImplementation(
} else {
// We did not find anything with the name ClassName; try to correct for
// typos in the class name.
- ObjCInterfaceValidatorCCC Validator;
- TypoCorrection Corrected =
- CorrectTypo(DeclarationNameInfo(ClassName, ClassLoc),
- LookupOrdinaryName, TUScope, nullptr, Validator,
- CTK_NonError);
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope,
+ nullptr, llvm::make_unique<ObjCInterfaceValidatorCCC>(), CTK_NonError);
if (Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
// Suggest the (potentially) correct interface name. Don't provide a
// code-modification hint or use the typo name for recovery, because
@@ -1362,9 +1357,9 @@ static bool CheckMethodOverrideReturn(Sema &S,
? diag::warn_conflicting_overriding_ret_type_modifiers
: diag::warn_conflicting_ret_type_modifiers))
<< MethodImpl->getDeclName()
- << getTypeRange(MethodImpl->getReturnTypeSourceInfo());
+ << MethodImpl->getReturnTypeSourceRange();
S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration)
- << getTypeRange(MethodDecl->getReturnTypeSourceInfo());
+ << MethodDecl->getReturnTypeSourceRange();
}
else
return false;
@@ -1402,11 +1397,11 @@ static bool CheckMethodOverrideReturn(Sema &S,
S.Diag(MethodImpl->getLocation(), DiagID)
<< MethodImpl->getDeclName() << MethodDecl->getReturnType()
<< MethodImpl->getReturnType()
- << getTypeRange(MethodImpl->getReturnTypeSourceInfo());
+ << MethodImpl->getReturnTypeSourceRange();
S.Diag(MethodDecl->getLocation(), IsOverridingMode
? diag::note_previous_declaration
: diag::note_previous_definition)
- << getTypeRange(MethodDecl->getReturnTypeSourceInfo());
+ << MethodDecl->getReturnTypeSourceRange();
return false;
}
@@ -1521,6 +1516,7 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
case OMF_finalize:
case OMF_retainCount:
case OMF_self:
+ case OMF_initialize:
case OMF_performSelector:
// Mismatches for these methods don't change ownership
// conventions, so we don't care.
@@ -1819,7 +1815,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
// Check and see if instance methods in class interface have been
// implemented in the implementation class. If so, their types match.
for (auto *I : CDecl->instance_methods()) {
- if (!InsMapSeen.insert(I->getSelector()))
+ if (!InsMapSeen.insert(I->getSelector()).second)
continue;
if (!I->isPropertyAccessor() &&
!InsMap.count(I->getSelector())) {
@@ -1846,7 +1842,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
// Check and see if class methods in class interface have been
// implemented in the implementation class. If so, their types match.
for (auto *I : CDecl->class_methods()) {
- if (!ClsMapSeen.insert(I->getSelector()))
+ if (!ClsMapSeen.insert(I->getSelector()).second)
continue;
if (!ClsMap.count(I->getSelector())) {
if (ImmediateClass)
@@ -2008,13 +2004,12 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
IncompleteImpl, InsMap, ClsMap, CDecl,
ExplicitImplProtocols);
DiagnoseUnimplementedProperties(S, IMPDecl, CDecl,
- /* SynthesizeProperties */ false);
+ /*SynthesizeProperties=*/false);
}
} else
llvm_unreachable("invalid ObjCContainerDecl type.");
}
-/// ActOnForwardClassDeclaration -
Sema::DeclGroupPtrTy
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
IdentifierInfo **IdentList,
@@ -2041,10 +2036,11 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
} else {
// a forward class declaration matching a typedef name of a class refers
// to the underlying class. Just ignore the forward class with a warning
- // as this will force the intended behavior which is to lookup the typedef
- // name.
+ // as this will force the intended behavior which is to lookup the
+ // typedef name.
if (isa<ObjCObjectType>(TDD->getUnderlyingType())) {
- Diag(AtClassLoc, diag::warn_forward_class_redefinition) << IdentList[i];
+ Diag(AtClassLoc, diag::warn_forward_class_redefinition)
+ << IdentList[i];
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
continue;
}
@@ -2107,7 +2103,12 @@ static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy,
// validate the basic, low-level compatibility of the two types.
// As a minimum, require the sizes and alignments to match.
- if (Context.getTypeInfo(left) != Context.getTypeInfo(right))
+ TypeInfo LeftTI = Context.getTypeInfo(left);
+ TypeInfo RightTI = Context.getTypeInfo(right);
+ if (LeftTI.Width != RightTI.Width)
+ return false;
+
+ if (LeftTI.Align != RightTI.Align)
return false;
// Consider all the kinds of non-dependent canonical types:
@@ -2159,7 +2160,13 @@ static bool tryMatchRecordTypes(ASTContext &Context,
return false;
// Require size and alignment to match.
- if (Context.getTypeInfo(lt) != Context.getTypeInfo(rt)) return false;
+ TypeInfo LeftTI = Context.getTypeInfo(lt);
+ TypeInfo RightTI = Context.getTypeInfo(rt);
+ if (LeftTI.Width != RightTI.Width)
+ return false;
+
+ if (LeftTI.Align != RightTI.Align)
+ return false;
// Require fields to match.
RecordDecl::field_iterator li = left->field_begin(), le = left->field_end();
@@ -2210,21 +2217,22 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
return true;
}
-void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) {
+void Sema::addMethodToGlobalList(ObjCMethodList *List,
+ ObjCMethodDecl *Method) {
// Record at the head of the list whether there were 0, 1, or >= 2 methods
// inside categories.
- if (ObjCCategoryDecl *
- CD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext()))
+ if (ObjCCategoryDecl *CD =
+ dyn_cast<ObjCCategoryDecl>(Method->getDeclContext()))
if (!CD->IsClassExtension() && List->getBits() < 2)
- List->setBits(List->getBits()+1);
+ List->setBits(List->getBits() + 1);
// If the list is empty, make it a singleton list.
- if (List->Method == nullptr) {
- List->Method = Method;
+ if (List->getMethod() == nullptr) {
+ List->setMethod(Method);
List->setNext(nullptr);
return;
}
-
+
// We've seen a method with this name, see if we have already seen this type
// signature.
ObjCMethodList *Previous = List;
@@ -2233,35 +2241,42 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) {
if (getLangOpts().Modules && !getLangOpts().CurrentModule.empty())
continue;
- if (!MatchTwoMethodDeclarations(Method, List->Method))
+ if (!MatchTwoMethodDeclarations(Method, List->getMethod()))
continue;
-
- ObjCMethodDecl *PrevObjCMethod = List->Method;
+
+ ObjCMethodDecl *PrevObjCMethod = List->getMethod();
// Propagate the 'defined' bit.
if (Method->isDefined())
PrevObjCMethod->setDefined(true);
-
+ else {
+ // Objective-C doesn't allow an @interface for a class after its
+ // @implementation. So if Method is not defined and there already is
+ // an entry for this type signature, Method has to be for a different
+ // class than PrevObjCMethod.
+ List->setHasMoreThanOneDecl(true);
+ }
+
// If a method is deprecated, push it in the global pool.
// This is used for better diagnostics.
if (Method->isDeprecated()) {
if (!PrevObjCMethod->isDeprecated())
- List->Method = Method;
+ List->setMethod(Method);
}
- // If new method is unavailable, push it into global pool
+ // If the new method is unavailable, push it into global pool
// unless previous one is deprecated.
if (Method->isUnavailable()) {
if (PrevObjCMethod->getAvailability() < AR_Deprecated)
- List->Method = Method;
+ List->setMethod(Method);
}
-
+
return;
}
-
+
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
- Previous->setNext(new (Mem) ObjCMethodList(Method, nullptr));
+ Previous->setNext(new (Mem) ObjCMethodList(Method));
}
/// \brief Read the contents of the method pool for a given selector from
@@ -2284,7 +2299,7 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
if (Pos == MethodPool.end())
Pos = MethodPool.insert(std::make_pair(Method->getSelector(),
GlobalMethods())).first;
-
+
Method->setDefined(impl);
ObjCMethodList &Entry = instance ? Pos->second.first : Pos->second.second;
@@ -2310,6 +2325,32 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
return (chosen->getReturnType()->isIntegerType());
}
+bool Sema::CollectMultipleMethodsInGlobalPool(
+ Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods, bool instance) {
+ if (ExternalSource)
+ ReadMethodPool(Sel);
+
+ GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
+ if (Pos == MethodPool.end())
+ return false;
+ // Gather the non-hidden methods.
+ ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
+ for (ObjCMethodList *M = &MethList; M; M = M->getNext())
+ if (M->getMethod() && !M->getMethod()->isHidden())
+ Methods.push_back(M->getMethod());
+ return Methods.size() > 1;
+}
+
+bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, bool instance) {
+ GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
+ // Test for no method in the pool which should not trigger any warning by
+ // caller.
+ if (Pos == MethodPool.end())
+ return true;
+ ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
+ return MethList.hasMoreThanOneDecl();
+}
+
ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
bool receiverIdOrClass,
bool warn, bool instance) {
@@ -2324,12 +2365,12 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
SmallVector<ObjCMethodDecl *, 4> Methods;
for (ObjCMethodList *M = &MethList; M; M = M->getNext()) {
- if (M->Method && !M->Method->isHidden()) {
+ if (M->getMethod() && !M->getMethod()->isHidden()) {
// If we're not supposed to warn about mismatches, we're done.
if (!warn)
- return M->Method;
+ return M->getMethod();
- Methods.push_back(M->Method);
+ Methods.push_back(M->getMethod());
}
}
@@ -2401,13 +2442,13 @@ ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
GlobalMethods &Methods = Pos->second;
for (const ObjCMethodList *Method = &Methods.first; Method;
Method = Method->getNext())
- if (Method->Method && Method->Method->isDefined())
- return Method->Method;
+ if (Method->getMethod() && Method->getMethod()->isDefined())
+ return Method->getMethod();
for (const ObjCMethodList *Method = &Methods.second; Method;
Method = Method->getNext())
- if (Method->Method && Method->Method->isDefined())
- return Method->Method;
+ if (Method->getMethod() && Method->getMethod()->isDefined())
+ return Method->getMethod();
return nullptr;
}
@@ -2470,25 +2511,27 @@ Sema::SelectorsForTypoCorrection(Selector Sel,
e = MethodPool.end(); b != e; b++) {
// instance methods
for (ObjCMethodList *M = &b->second.first; M; M=M->getNext())
- if (M->Method &&
- (M->Method->getSelector().getNumArgs() == NumArgs) &&
- (M->Method->getSelector() != Sel)) {
+ if (M->getMethod() &&
+ (M->getMethod()->getSelector().getNumArgs() == NumArgs) &&
+ (M->getMethod()->getSelector() != Sel)) {
if (ObjectIsId)
- Methods.push_back(M->Method);
+ Methods.push_back(M->getMethod());
else if (!ObjectIsClass &&
- HelperIsMethodInObjCType(*this, M->Method->getSelector(), ObjectType))
- Methods.push_back(M->Method);
+ HelperIsMethodInObjCType(*this, M->getMethod()->getSelector(),
+ ObjectType))
+ Methods.push_back(M->getMethod());
}
// class methods
for (ObjCMethodList *M = &b->second.second; M; M=M->getNext())
- if (M->Method &&
- (M->Method->getSelector().getNumArgs() == NumArgs) &&
- (M->Method->getSelector() != Sel)) {
+ if (M->getMethod() &&
+ (M->getMethod()->getSelector().getNumArgs() == NumArgs) &&
+ (M->getMethod()->getSelector() != Sel)) {
if (ObjectIsClass)
- Methods.push_back(M->Method);
+ Methods.push_back(M->getMethod());
else if (!ObjectIsId &&
- HelperIsMethodInObjCType(*this, M->Method->getSelector(), ObjectType))
- Methods.push_back(M->Method);
+ HelperIsMethodInObjCType(*this, M->getMethod()->getSelector(),
+ ObjectType))
+ Methods.push_back(M->getMethod());
}
}
@@ -2818,7 +2861,7 @@ public:
}
ObjCMethodList &list =
method->isInstanceMethod() ? it->second.first : it->second.second;
- if (!list.Method) return;
+ if (!list.getMethod()) return;
ObjCContainerDecl *container
= cast<ObjCContainerDecl>(method->getDeclContext());
@@ -3237,6 +3280,7 @@ Decl *Sema::ActOnMethodDeclaration(
case OMF_mutableCopy:
case OMF_release:
case OMF_retainCount:
+ case OMF_initialize:
case OMF_performSelector:
break;
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index b92fcbd2a0d9..2387325be435 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -35,6 +35,33 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType T)
return T->getAs<FunctionProtoType>();
}
+/// HACK: libstdc++ has a bug where it shadows std::swap with a member
+/// swap function then tries to call std::swap unqualified from the exception
+/// specification of that function. This function detects whether we're in
+/// such a case and turns off delay-parsing of exception specifications.
+bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
+ auto *RD = dyn_cast<CXXRecordDecl>(CurContext);
+
+ // All the problem cases are member functions named "swap" within class
+ // templates declared directly within namespace std.
+ if (!RD || RD->getEnclosingNamespaceContext() != getStdNamespace() ||
+ !RD->getIdentifier() || !RD->getDescribedClassTemplate() ||
+ !D.getIdentifier() || !D.getIdentifier()->isStr("swap"))
+ return false;
+
+ // Only apply this hack within a system header.
+ if (!Context.getSourceManager().isInSystemHeader(D.getLocStart()))
+ return false;
+
+ return llvm::StringSwitch<bool>(RD->getIdentifier()->getName())
+ .Case("array", true)
+ .Case("pair", true)
+ .Case("priority_queue", true)
+ .Case("stack", true)
+ .Case("queue", true)
+ .Default(false);
+}
+
/// CheckSpecifiedExceptionType - Check if the given type is valid in an
/// exception specification. Incomplete types, or pointers to incomplete types
/// other than void are not allowed.
@@ -112,6 +139,11 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
const FunctionProtoType *
Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
+ if (FPT->getExceptionSpecType() == EST_Unparsed) {
+ Diag(Loc, diag::err_exception_spec_not_parsed);
+ return nullptr;
+ }
+
if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
return FPT;
@@ -132,21 +164,14 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
return SourceDecl->getType()->castAs<FunctionProtoType>();
}
-void Sema::UpdateExceptionSpec(FunctionDecl *FD,
- const FunctionProtoType::ExtProtoInfo &EPI) {
- const FunctionProtoType *Proto = FD->getType()->castAs<FunctionProtoType>();
-
- // Overwrite the exception spec and rebuild the function type.
- FunctionProtoType::ExtProtoInfo NewEPI = Proto->getExtProtoInfo();
- NewEPI.ExceptionSpecType = EPI.ExceptionSpecType;
- NewEPI.NumExceptions = EPI.NumExceptions;
- NewEPI.Exceptions = EPI.Exceptions;
- NewEPI.NoexceptExpr = EPI.NoexceptExpr;
- FD->setType(Context.getFunctionType(Proto->getReturnType(),
- Proto->getParamTypes(), NewEPI));
+void
+Sema::UpdateExceptionSpec(FunctionDecl *FD,
+ const FunctionProtoType::ExceptionSpecInfo &ESI) {
+ for (auto *Redecl : FD->redecls())
+ Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
// If we've fully resolved the exception specification, notify listeners.
- if (!isUnresolvedExceptionSpec(EPI.ExceptionSpecType))
+ if (!isUnresolvedExceptionSpec(ESI.Type))
if (auto *Listener = getASTMutationListener())
Listener->ResolvedExceptionSpec(FD);
}
@@ -227,32 +252,28 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
(Old->getLocation().isInvalid() ||
Context.getSourceManager().isInSystemHeader(Old->getLocation())) &&
Old->isExternC()) {
- FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
- EPI.ExceptionSpecType = EST_DynamicNone;
- QualType NewType = Context.getFunctionType(NewProto->getReturnType(),
- NewProto->getParamTypes(), EPI);
- New->setType(NewType);
+ New->setType(Context.getFunctionType(
+ NewProto->getReturnType(), NewProto->getParamTypes(),
+ NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone)));
return false;
}
const FunctionProtoType *OldProto =
Old->getType()->castAs<FunctionProtoType>();
- FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
- EPI.ExceptionSpecType = OldProto->getExceptionSpecType();
- if (EPI.ExceptionSpecType == EST_Dynamic) {
- EPI.NumExceptions = OldProto->getNumExceptions();
- EPI.Exceptions = OldProto->exception_begin();
- } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+ FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType();
+ if (ESI.Type == EST_Dynamic) {
+ ESI.Exceptions = OldProto->exceptions();
+ } else if (ESI.Type == EST_ComputedNoexcept) {
// FIXME: We can't just take the expression from the old prototype. It
// likely contains references to the old prototype's parameters.
}
// Update the type of the function with the appropriate exception
// specification.
- QualType NewType = Context.getFunctionType(NewProto->getReturnType(),
- NewProto->getParamTypes(), EPI);
- New->setType(NewType);
+ New->setType(Context.getFunctionType(
+ NewProto->getReturnType(), NewProto->getParamTypes(),
+ NewProto->getExtProtoInfo().withExceptionSpec(ESI)));
// Warn about the lack of exception specification.
SmallString<128> ExceptionSpecString;
@@ -723,10 +744,11 @@ static bool CheckSpecForTypesEquivalent(Sema &S,
/// assignment and override compatibility check. We do not check the parameters
/// of parameter function pointers recursively, as no sane programmer would
/// even be able to write such a function type.
-bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
- const FunctionProtoType *Target, SourceLocation TargetLoc,
- const FunctionProtoType *Source, SourceLocation SourceLoc)
-{
+bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID,
+ const FunctionProtoType *Target,
+ SourceLocation TargetLoc,
+ const FunctionProtoType *Source,
+ SourceLocation SourceLoc) {
if (CheckSpecForTypesEquivalent(
*this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(),
Target->getReturnType(), TargetLoc, Source->getReturnType(),
@@ -747,23 +769,30 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
return false;
}
-bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
-{
+bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
// First we check for applicability.
// Target type must be a function, function pointer or function reference.
const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
- if (!ToFunc)
+ if (!ToFunc || ToFunc->hasDependentExceptionSpec())
return false;
// SourceType must be a function or function pointer.
const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
- if (!FromFunc)
+ if (!FromFunc || FromFunc->hasDependentExceptionSpec())
return false;
// Now we've got the correct types on both sides, check their compatibility.
// This means that the source of the conversion can only throw a subset of
// the exceptions of the target, and any exception specs on arguments or
// return types must be equivalent.
+ //
+ // FIXME: If there is a nested dependent exception specification, we should
+ // not be checking it here. This is fine:
+ // template<typename T> void f() {
+ // void (*p)(void (*) throw(T));
+ // void (*q)(void (*) throw(int)) = p;
+ // }
+ // ... because it might be instantiated with T=int.
return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs),
PDiag(), ToFunc,
From->getSourceRange().getBegin(),
@@ -772,6 +801,11 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
+ // If the new exception specification hasn't been parsed yet, skip the check.
+ // We'll get called again once it's been parsed.
+ if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
+ EST_Unparsed)
+ return false;
if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) {
// Don't check uninstantiated template destructors at all. We can only
// synthesize correct specs after the template is instantiated.
@@ -780,11 +814,18 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
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)));
+ DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
return false;
}
}
+ // If the old exception specification hasn't been parsed yet, remember that
+ // we need to perform this check when we get to the end of the outermost
+ // lexically-surrounding class.
+ if (Old->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
+ EST_Unparsed) {
+ DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
+ return false;
+ }
unsigned DiagID = diag::err_override_exception_spec;
if (getLangOpts().MicrosoftExt)
DiagID = diag::ext_override_exception_spec;
@@ -1051,6 +1092,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CXXDependentScopeMemberExprClass:
case Expr::CXXUnresolvedConstructExprClass:
case Expr::DependentScopeDeclRefExprClass:
+ case Expr::CXXFoldExprClass:
return CT_Dependent;
case Expr::AsTypeExprClass:
@@ -1071,6 +1113,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::UnaryExprOrTypeTraitExprClass:
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
+ case Expr::TypoExprClass:
// FIXME: Can any of the above throw? If so, when?
return CT_Cannot;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 35dad82523c9..fba7a2d23ffd 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -42,6 +42,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/Template.h"
+#include "llvm/Support/ConvertUTF.h"
using namespace clang;
using namespace sema;
@@ -59,7 +60,7 @@ bool Sema::CanUseDecl(NamedDecl *D) {
// If the function has a deduced return type, and we can't deduce it,
// then we can't use it either.
- if (getLangOpts().CPlusPlus1y && FD->getReturnType()->isUndeducedType() &&
+ if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() &&
DeduceReturnType(FD, SourceLocation(), /*Diagnose*/ false))
return false;
}
@@ -302,7 +303,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
// If the function has a deduced return type, and we can't deduce it,
// then we can't use it either.
- if (getLangOpts().CPlusPlus1y && FD->getReturnType()->isUndeducedType() &&
+ if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() &&
DeduceReturnType(FD, Loc))
return true;
}
@@ -397,8 +398,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
if (sentinelExpr->isValueDependent()) return;
if (Context.isSentinelNullExpr(sentinelExpr)) return;
- // Pick a reasonable string to insert. Optimistically use 'nil' or
- // 'NULL' if those are actually defined in the context. Only use
+ // Pick a reasonable string to insert. Optimistically use 'nil', 'nullptr',
+ // or 'NULL' if those are actually defined in the context. Only use
// 'nil' for ObjC methods, where it's much more likely that the
// variadic arguments form a list of object pointers.
SourceLocation MissingNilLoc
@@ -407,6 +408,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
if (calleeType == CT_Method &&
PP.getIdentifierInfo("nil")->hasMacroDefinition())
NullValue = "nil";
+ else if (getLangOpts().CPlusPlus11)
+ NullValue = "nullptr";
else if (PP.getIdentifierInfo("NULL")->hasMacroDefinition())
NullValue = "NULL";
else
@@ -800,6 +803,9 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
if (Ty->isObjCObjectType())
return VAK_Invalid;
+ if (getLangOpts().MSVCCompat)
+ return VAK_MSVCUndefined;
+
// FIXME: In C++11, these cases are conditionally-supported, meaning we're
// permitted to reject them. We should consider doing so.
return VAK_Undefined;
@@ -829,6 +835,7 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) {
break;
case VAK_Undefined:
+ case VAK_MSVCUndefined:
DiagRuntimeBehavior(
E->getLocStart(), nullptr,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
@@ -933,68 +940,6 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
return false;
}
-/// \brief Takes two complex float types and converts them to the same type.
-/// Helper function of UsualArithmeticConversions()
-static QualType
-handleComplexFloatToComplexFloatConverstion(Sema &S, ExprResult &LHS,
- ExprResult &RHS, QualType LHSType,
- QualType RHSType,
- bool IsCompAssign) {
- int order = S.Context.getFloatingTypeOrder(LHSType, RHSType);
-
- if (order < 0) {
- // _Complex float -> _Complex double
- if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FloatingComplexCast);
- return RHSType;
- }
- if (order > 0)
- // _Complex float -> _Complex double
- RHS = S.ImpCastExprToType(RHS.get(), LHSType, CK_FloatingComplexCast);
- return LHSType;
-}
-
-/// \brief Converts otherExpr to complex float and promotes complexExpr if
-/// necessary. Helper function of UsualArithmeticConversions()
-static QualType handleOtherComplexFloatConversion(Sema &S,
- ExprResult &ComplexExpr,
- ExprResult &OtherExpr,
- QualType ComplexTy,
- QualType OtherTy,
- bool ConvertComplexExpr,
- bool ConvertOtherExpr) {
- int order = S.Context.getFloatingTypeOrder(ComplexTy, OtherTy);
-
- // If just the complexExpr is complex, the otherExpr needs to be converted,
- // and the complexExpr might need to be promoted.
- if (order > 0) { // complexExpr is wider
- // float -> _Complex double
- if (ConvertOtherExpr) {
- QualType fp = cast<ComplexType>(ComplexTy)->getElementType();
- OtherExpr = S.ImpCastExprToType(OtherExpr.get(), fp, CK_FloatingCast);
- OtherExpr = S.ImpCastExprToType(OtherExpr.get(), ComplexTy,
- CK_FloatingRealToComplex);
- }
- return ComplexTy;
- }
-
- // otherTy is at least as wide. Find its corresponding complex type.
- QualType result = (order == 0 ? ComplexTy :
- S.Context.getComplexType(OtherTy));
-
- // double -> _Complex double
- if (ConvertOtherExpr)
- OtherExpr = S.ImpCastExprToType(OtherExpr.get(), result,
- CK_FloatingRealToComplex);
-
- // _Complex float -> _Complex double
- if (ConvertComplexExpr && order < 0)
- ComplexExpr = S.ImpCastExprToType(ComplexExpr.get(), result,
- CK_FloatingComplexCast);
-
- return result;
-}
-
/// \brief Handle arithmetic conversion with complex types. Helper function of
/// UsualArithmeticConversions()
static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
@@ -1020,26 +965,35 @@ static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
// when combining a "long double" with a "double _Complex", the
// "double _Complex" is promoted to "long double _Complex".
- bool LHSComplexFloat = LHSType->isComplexType();
- bool RHSComplexFloat = RHSType->isComplexType();
-
- // If both are complex, just cast to the more precise type.
- if (LHSComplexFloat && RHSComplexFloat)
- return handleComplexFloatToComplexFloatConverstion(S, LHS, RHS,
- LHSType, RHSType,
- IsCompAssign);
-
- // If only one operand is complex, promote it if necessary and convert the
- // other operand to complex.
- if (LHSComplexFloat)
- return handleOtherComplexFloatConversion(
- S, LHS, RHS, LHSType, RHSType, /*convertComplexExpr*/!IsCompAssign,
- /*convertOtherExpr*/ true);
-
- assert(RHSComplexFloat);
- return handleOtherComplexFloatConversion(
- S, RHS, LHS, RHSType, LHSType, /*convertComplexExpr*/true,
- /*convertOtherExpr*/ !IsCompAssign);
+ // Compute the rank of the two types, regardless of whether they are complex.
+ int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType);
+
+ auto *LHSComplexType = dyn_cast<ComplexType>(LHSType);
+ auto *RHSComplexType = dyn_cast<ComplexType>(RHSType);
+ QualType LHSElementType =
+ LHSComplexType ? LHSComplexType->getElementType() : LHSType;
+ QualType RHSElementType =
+ RHSComplexType ? RHSComplexType->getElementType() : RHSType;
+
+ QualType ResultType = S.Context.getComplexType(LHSElementType);
+ if (Order < 0) {
+ // Promote the precision of the LHS if not an assignment.
+ ResultType = S.Context.getComplexType(RHSElementType);
+ if (!IsCompAssign) {
+ if (LHSComplexType)
+ LHS =
+ S.ImpCastExprToType(LHS.get(), ResultType, CK_FloatingComplexCast);
+ else
+ LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, CK_FloatingCast);
+ }
+ } else if (Order > 0) {
+ // Promote the precision of the RHS.
+ if (RHSComplexType)
+ RHS = S.ImpCastExprToType(RHS.get(), ResultType, CK_FloatingComplexCast);
+ else
+ RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast);
+ }
+ return ResultType;
}
/// \brief Hande arithmetic conversion from integer to float. Helper function
@@ -1336,6 +1290,13 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
ControllingExpr = result.get();
}
+ // The controlling expression is an unevaluated operand, so side effects are
+ // likely unintended.
+ if (ActiveTemplateInstantiations.empty() &&
+ ControllingExpr->HasSideEffects(Context, false))
+ Diag(ControllingExpr->getExprLoc(),
+ diag::warn_side_effects_unevaluated_context);
+
bool TypeErrorFound = false,
IsResultDependent = ControllingExpr->isTypeDependent(),
ContainsUnexpandedParameterPack
@@ -1636,40 +1597,37 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
if (getLangOpts().CUDA)
if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) {
- CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller),
- CalleeTarget = IdentifyCUDATarget(Callee);
- if (CheckCUDATarget(CallerTarget, CalleeTarget)) {
+ if (CheckCUDATarget(Caller, Callee)) {
Diag(NameInfo.getLoc(), diag::err_ref_bad_target)
- << CalleeTarget << D->getIdentifier() << CallerTarget;
+ << IdentifyCUDATarget(Callee) << D->getIdentifier()
+ << IdentifyCUDATarget(Caller);
Diag(D->getLocation(), diag::note_previous_decl)
<< D->getIdentifier();
return ExprError();
}
}
- bool refersToEnclosingScope =
- (CurContext != D->getDeclContext() &&
- D->getDeclContext()->isFunctionOrMethod()) ||
- (isa<VarDecl>(D) &&
- cast<VarDecl>(D)->isInitCapture());
+ bool RefersToCapturedVariable =
+ isa<VarDecl>(D) &&
+ NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc());
DeclRefExpr *E;
if (isa<VarTemplateSpecializationDecl>(D)) {
VarTemplateSpecializationDecl *VarSpec =
cast<VarTemplateSpecializationDecl>(D);
- E = DeclRefExpr::Create(
- Context,
- SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(),
- VarSpec->getTemplateKeywordLoc(), D, refersToEnclosingScope,
- NameInfo.getLoc(), Ty, VK, FoundD, TemplateArgs);
+ E = DeclRefExpr::Create(Context, SS ? SS->getWithLocInContext(Context)
+ : NestedNameSpecifierLoc(),
+ VarSpec->getTemplateKeywordLoc(), D,
+ RefersToCapturedVariable, NameInfo.getLoc(), Ty, VK,
+ FoundD, TemplateArgs);
} else {
assert(!TemplateArgs && "No template arguments for non-variable"
" template specialization references");
- E = DeclRefExpr::Create(
- Context,
- SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(),
- SourceLocation(), D, refersToEnclosingScope, NameInfo, Ty, VK, FoundD);
+ E = DeclRefExpr::Create(Context, SS ? SS->getWithLocInContext(Context)
+ : NestedNameSpecifierLoc(),
+ SourceLocation(), D, RefersToCapturedVariable,
+ NameInfo, Ty, VK, FoundD);
}
MarkDeclRefReferenced(E);
@@ -1719,13 +1677,48 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
}
}
+static void emitEmptyLookupTypoDiagnostic(
+ const TypoCorrection &TC, Sema &SemaRef, const CXXScopeSpec &SS,
+ DeclarationName Typo, SourceLocation TypoLoc, ArrayRef<Expr *> Args,
+ unsigned DiagnosticID, unsigned DiagnosticSuggestID) {
+ DeclContext *Ctx =
+ SS.isEmpty() ? nullptr : SemaRef.computeDeclContext(SS, false);
+ if (!TC) {
+ // Emit a special diagnostic for failed member lookups.
+ // FIXME: computing the declaration context might fail here (?)
+ if (Ctx)
+ SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx
+ << SS.getRange();
+ else
+ SemaRef.Diag(TypoLoc, DiagnosticID) << Typo;
+ return;
+ }
+
+ std::string CorrectedStr = TC.getAsString(SemaRef.getLangOpts());
+ bool DroppedSpecifier =
+ TC.WillReplaceSpecifier() && Typo.getAsString() == CorrectedStr;
+ unsigned NoteID =
+ (TC.getCorrectionDecl() && isa<ImplicitParamDecl>(TC.getCorrectionDecl()))
+ ? diag::note_implicit_param_decl
+ : diag::note_previous_decl;
+ if (!Ctx)
+ SemaRef.diagnoseTypo(TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo,
+ SemaRef.PDiag(NoteID));
+ else
+ SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest)
+ << Typo << Ctx << DroppedSpecifier
+ << SS.getRange(),
+ SemaRef.PDiag(NoteID));
+}
+
/// Diagnose an empty lookup.
///
/// \return false if new lookup candidates were found
-bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- CorrectionCandidateCallback &CCC,
- TemplateArgumentListInfo *ExplicitTemplateArgs,
- ArrayRef<Expr *> Args) {
+bool
+Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
+ std::unique_ptr<CorrectionCandidateCallback> CCC,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
+ ArrayRef<Expr *> Args, TypoExpr **Out) {
DeclarationName Name = R.getLookupName();
unsigned diagnostic = diag::err_undeclared_var_use;
@@ -1842,8 +1835,22 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// We didn't find anything, so try to correct for a typo.
TypoCorrection Corrected;
- if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
- S, &SS, CCC, CTK_ErrorRecovery))) {
+ if (S && Out) {
+ SourceLocation TypoLoc = R.getNameLoc();
+ assert(!ExplicitTemplateArgs &&
+ "Diagnosing an empty lookup with explicit template args!");
+ *Out = CorrectTypoDelayed(
+ R.getLookupNameInfo(), R.getLookupKind(), S, &SS, std::move(CCC),
+ [=](const TypoCorrection &TC) {
+ emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args,
+ diagnostic, diagnostic_suggest);
+ },
+ nullptr, CTK_ErrorRecovery);
+ if (*Out)
+ return true;
+ } else if (S && (Corrected =
+ CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S,
+ &SS, std::move(CCC), CTK_ErrorRecovery))) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
@@ -1990,14 +1997,12 @@ recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context,
TemplateArgs);
}
-ExprResult Sema::ActOnIdExpression(Scope *S,
- CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
- UnqualifiedId &Id,
- bool HasTrailingLParen,
- bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC,
- bool IsInlineAsmIdentifier) {
+ExprResult
+Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc, UnqualifiedId &Id,
+ bool HasTrailingLParen, bool IsAddressOfOperand,
+ std::unique_ptr<CorrectionCandidateCallback> CCC,
+ bool IsInlineAsmIdentifier, Token *KeywordReplacement) {
assert(!(IsAddressOfOperand && HasTrailingLParen) &&
"cannot be direct & operand and have a trailing lparen");
if (SS.isInvalid())
@@ -2109,12 +2114,43 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// If this name wasn't predeclared and if this is not a function
// call, diagnose the problem.
- CorrectionCandidateCallback DefaultValidator;
- DefaultValidator.IsAddressOfOperand = IsAddressOfOperand;
+ TypoExpr *TE = nullptr;
+ auto DefaultValidator = llvm::make_unique<CorrectionCandidateCallback>(
+ II, SS.isValid() ? SS.getScopeRep() : nullptr);
+ DefaultValidator->IsAddressOfOperand = IsAddressOfOperand;
assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) &&
"Typo correction callback misconfigured");
- if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator))
- return ExprError();
+ if (CCC) {
+ // Make sure the callback knows what the typo being diagnosed is.
+ CCC->setTypoName(II);
+ if (SS.isValid())
+ CCC->setTypoNNS(SS.getScopeRep());
+ }
+ if (DiagnoseEmptyLookup(S, SS, R,
+ CCC ? std::move(CCC) : std::move(DefaultValidator),
+ nullptr, None, &TE)) {
+ if (TE && KeywordReplacement) {
+ auto &State = getTypoExprState(TE);
+ auto BestTC = State.Consumer->getNextCorrection();
+ if (BestTC.isKeyword()) {
+ auto *II = BestTC.getCorrectionAsIdentifierInfo();
+ if (State.DiagHandler)
+ State.DiagHandler(BestTC);
+ KeywordReplacement->startToken();
+ KeywordReplacement->setKind(II->getTokenID());
+ KeywordReplacement->setIdentifierInfo(II);
+ KeywordReplacement->setLocation(BestTC.getCorrectionRange().getBegin());
+ // Clean up the state associated with the TypoExpr, since it has
+ // now been diagnosed (without a call to CorrectDelayedTyposInExpr).
+ clearDelayedTypo(TE);
+ // Signal that a correction to a keyword was performed by returning a
+ // valid-but-null ExprResult.
+ return (Expr*)nullptr;
+ }
+ State.Consumer->resetCorrectionStream();
+ }
+ return TE ? TE : ExprError();
+ }
assert(!R.empty() &&
"DiagnoseEmptyLookup returned false but added no results");
@@ -2364,10 +2400,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
!IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
- ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- Loc, IV->getLocation(),
- SelfExpr.get(),
- true, true);
+ ObjCIvarRefExpr *Result = new (Context)
+ ObjCIvarRefExpr(IV, IV->getType(), Loc, IV->getLocation(),
+ SelfExpr.get(), true, true);
if (getLangOpts().ObjCAutoRefCount) {
if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
@@ -2660,15 +2695,15 @@ static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) {
return false;
}
-ExprResult
-Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- bool NeedsADL) {
+ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
+ LookupResult &R, bool NeedsADL,
+ bool AcceptInvalidDecl) {
// If this is a single, fully-resolved result and we don't need ADL,
// just build an ordinary singleton decl ref.
if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>())
return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
- R.getRepresentativeDecl());
+ R.getRepresentativeDecl(), nullptr,
+ AcceptInvalidDecl);
// We only need to check the declaration if there's exactly one
// result, because in the overloaded case the results can only be
@@ -2695,7 +2730,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
/// \brief Complete semantic analysis for a reference to the given declaration.
ExprResult Sema::BuildDeclarationNameExpr(
const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
- NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) {
+ NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs,
+ bool AcceptInvalidDecl) {
assert(D && "Cannot refer to a NULL declaration");
assert(!isa<FunctionTemplateDecl>(D) &&
"Cannot refer unambiguously to a function template");
@@ -2730,7 +2766,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
return ExprError();
// Only create DeclRefExpr's for valid Decl's.
- if (VD->isInvalidDecl())
+ if (VD->isInvalidDecl() && !AcceptInvalidDecl)
return ExprError();
// Handle members of anonymous structs and unions. If we got here,
@@ -2902,6 +2938,17 @@ ExprResult Sema::BuildDeclarationNameExpr(
}
}
+static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
+ SmallString<32> &Target) {
+ Target.resize(CharByteWidth * (Source.size() + 1));
+ char *ResultPtr = &Target[0];
+ const UTF8 *ErrorPtr;
+ bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr);
+ (void)success;
+ assert(success);
+ Target.resize(ResultPtr - &Target[0]);
+}
+
ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
PredefinedExpr::IdentType IT) {
// Pick the current block, lambda, captured statement or function.
@@ -2921,22 +2968,35 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
}
QualType ResTy;
+ StringLiteral *SL = nullptr;
if (cast<DeclContext>(currentDecl)->isDependentContext())
ResTy = Context.DependentTy;
else {
// Pre-defined identifiers are of type char[x], where x is the length of
// the string.
- unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
+ auto Str = PredefinedExpr::ComputeName(IT, currentDecl);
+ unsigned Length = Str.length();
llvm::APInt LengthI(32, Length + 1);
- if (IT == PredefinedExpr::LFunction)
+ if (IT == PredefinedExpr::LFunction) {
ResTy = Context.WideCharTy.withConst();
- else
+ SmallString<32> RawChars;
+ ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(),
+ Str, RawChars);
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
+ /*IndexTypeQuals*/ 0);
+ SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide,
+ /*Pascal*/ false, ResTy, Loc);
+ } else {
ResTy = Context.CharTy.withConst();
- ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
+ /*IndexTypeQuals*/ 0);
+ SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii,
+ /*Pascal*/ false, ResTy, Loc);
+ }
}
- return new (Context) PredefinedExpr(Loc, ResTy, IT);
+ return new (Context) PredefinedExpr(Loc, ResTy, IT, SL);
}
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
@@ -3046,6 +3106,34 @@ static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc);
}
+bool Sema::CheckLoopHintExpr(Expr *E, SourceLocation Loc) {
+ assert(E && "Invalid expression");
+
+ if (E->isValueDependent())
+ return false;
+
+ QualType QT = E->getType();
+ if (!QT->isIntegerType() || QT->isBooleanType() || QT->isCharType()) {
+ Diag(E->getExprLoc(), diag::err_pragma_loop_invalid_argument_type) << QT;
+ return true;
+ }
+
+ llvm::APSInt ValueAPS;
+ ExprResult R = VerifyIntegerConstantExpression(E, &ValueAPS);
+
+ if (R.isInvalid())
+ return true;
+
+ bool ValueIsPositive = ValueAPS.isStrictlyPositive();
+ if (!ValueIsPositive || ValueAPS.getActiveBits() > 31) {
+ Diag(E->getExprLoc(), diag::err_pragma_loop_invalid_argument_value)
+ << ValueAPS.toString(10) << ValueIsPositive;
+ return true;
+ }
+
+ return false;
+}
+
ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// Fast path for a single digit (which is quite common). A single digit
// cannot have a trigraph, escaped newline, radix prefix, or suffix.
@@ -3117,7 +3205,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
} else {
llvm::APInt ResultVal(Context.getTargetInfo().getLongLongWidth(), 0);
if (Literal.GetIntegerValue(ResultVal))
- Diag(Tok.getLocation(), diag::err_integer_too_large);
+ Diag(Tok.getLocation(), diag::err_integer_literal_too_large)
+ << /* Unsigned */ 1;
Lit = IntegerLiteral::Create(Context, ResultVal, CookedTy,
Tok.getLocation());
}
@@ -3210,7 +3299,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
if (Literal.GetIntegerValue(ResultVal)) {
// If this value didn't fit into uintmax_t, error and force to ull.
- Diag(Tok.getLocation(), diag::err_integer_too_large);
+ Diag(Tok.getLocation(), diag::err_integer_literal_too_large)
+ << /* Unsigned */ 1;
Ty = Context.UnsignedLongLongTy;
assert(Context.getTypeSize(Ty) == ResultVal.getBitWidth() &&
"long long is not intmax_t?");
@@ -3290,7 +3380,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// If we still couldn't decide a type, we probably have something that
// does not fit in a signed long long, but has no U suffix.
if (Ty.isNull()) {
- Diag(Tok.getLocation(), diag::ext_integer_too_large_for_signed);
+ Diag(Tok.getLocation(), diag::ext_integer_literal_too_large_for_signed);
Ty = Context.UnsignedLongLongTy;
Width = Context.getTargetInfo().getLongLongWidth();
}
@@ -3442,6 +3532,12 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
return true;
}
+ // The operand for sizeof and alignof is in an unevaluated expression context,
+ // so side effects could result in unintended consequences.
+ if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf) &&
+ ActiveTemplateInstantiations.empty() && E->HasSideEffects(Context, false))
+ Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
+
if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(),
E->getSourceRange(), ExprKind))
return true;
@@ -4083,11 +4179,12 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn,
MemberExpr *ME = dyn_cast<MemberExpr>(Fn);
DeclarationName FuncName = FDecl->getDeclName();
SourceLocation NameLoc = ME ? ME->getMemberLoc() : Fn->getLocStart();
- FunctionCallCCC CCC(S, FuncName.getAsIdentifierInfo(), Args.size(), ME);
if (TypoCorrection Corrected = S.CorrectTypo(
DeclarationNameInfo(FuncName, NameLoc), Sema::LookupOrdinaryName,
- S.getScopeForContext(S.CurContext), nullptr, CCC,
+ S.getScopeForContext(S.CurContext), nullptr,
+ llvm::make_unique<FunctionCallCCC>(S, FuncName.getAsIdentifierInfo(),
+ Args.size(), ME),
Sema::CTK_ErrorRecovery)) {
if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
if (Corrected.isOverloaded()) {
@@ -4454,6 +4551,8 @@ static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) {
ExprResult result = S.CheckPlaceholderExpr(args[i]);
if (result.isInvalid()) hasInvalid = true;
else args[i] = result.get();
+ } else if (hasInvalid) {
+ (void)S.CorrectDelayedTyposInExpr(args[i]);
}
}
return hasInvalid;
@@ -4587,23 +4686,6 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
ExecConfig, IsExecConfig);
}
-ExprResult
-Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
- MultiExprArg ExecConfig, SourceLocation GGGLoc) {
- FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl();
- if (!ConfigDecl)
- return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use)
- << "cudaConfigureCall");
- QualType ConfigQTy = ConfigDecl->getType();
-
- DeclRefExpr *ConfigDR = new (Context) DeclRefExpr(
- ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc);
- MarkFunctionReferenced(LLLLoc, ConfigDecl);
-
- return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr,
- /*IsExecConfig=*/true);
-}
-
/// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments.
///
/// __builtin_astype( value, dst type )
@@ -4680,8 +4762,12 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
VK_RValue, RParenLoc);
// Bail out early if calling a builtin with custom typechecking.
- if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID))
- return CheckBuiltinFunctionCall(BuiltinID, TheCall);
+ if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) {
+ ExprResult Res = CorrectDelayedTyposInExpr(TheCall);
+ if (!Res.isUsable() || !isa<CallExpr>(Res.get()))
+ return Res;
+ return CheckBuiltinFunctionCall(FDecl, BuiltinID, cast<CallExpr>(Res.get()));
+ }
retry:
const FunctionType *FuncT;
@@ -4809,7 +4895,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
return ExprError();
if (BuiltinID)
- return CheckBuiltinFunctionCall(BuiltinID, TheCall);
+ return CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall);
} else if (NDecl) {
if (CheckPointerCall(NDecl, TheCall, Proto))
return ExprError();
@@ -5227,6 +5313,12 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
if (getLangOpts().CPlusPlus) {
// Check that there are no default arguments (C++ only).
CheckExtraCXXDefaultArguments(D);
+ } else {
+ // Make sure any TypoExprs have been dealt with.
+ ExprResult Res = CorrectDelayedTyposInExpr(CastExpr);
+ if (!Res.isUsable())
+ return ExprError();
+ CastExpr = Res.get();
}
checkUnusedDeclAttributes(D);
@@ -5693,6 +5785,15 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprObjectKind &OK,
SourceLocation QuestionLoc) {
+ if (!getLangOpts().CPlusPlus) {
+ // C cannot handle TypoExpr nodes on either side of a binop because it
+ // doesn't handle dependent types properly, so make sure any TypoExprs have
+ // been dealt with before checking the operands.
+ ExprResult CondResult = CorrectDelayedTyposInExpr(Cond);
+ if (!CondResult.isUsable()) return QualType();
+ Cond = CondResult;
+ }
+
ExprResult LHSResult = CheckPlaceholderExpr(LHS.get());
if (!LHSResult.isUsable()) return QualType();
LHS = LHSResult;
@@ -5720,7 +5821,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
RHS.get()->getType()->isVectorType())
return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
- UsualArithmeticConversions(LHS, RHS);
+ QualType ResTy = UsualArithmeticConversions(LHS, RHS);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -5737,8 +5838,12 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
- if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType())
- return LHS.get()->getType();
+ if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) {
+ LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy));
+ RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy));
+
+ return ResTy;
+ }
// If both operands are the same structure or union type, the result is that
// type.
@@ -6161,7 +6266,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
if (!lhq.compatiblyIncludes(rhq)) {
// Treat address-space mismatches as fatal. TODO: address subspaces
- if (lhq.getAddressSpace() != rhq.getAddressSpace())
+ if (!lhq.isAddressSpaceSupersetOf(rhq))
ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
// It's okay to add or remove GC or lifetime qualifiers when converting to
@@ -6446,7 +6551,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) {
// U* -> T*
if (isa<PointerType>(RHSType)) {
- Kind = CK_BitCast;
+ unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace();
+ unsigned AddrSpaceR = RHSType->getPointeeType().getAddressSpace();
+ Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
return checkPointerTypesForAssignment(*this, LHSType, RHSType);
}
@@ -6754,6 +6861,15 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
return Incompatible;
}
+ Expr *PRE = RHS.get()->IgnoreParenCasts();
+ if (ObjCProtocolExpr *OPE = dyn_cast<ObjCProtocolExpr>(PRE)) {
+ ObjCProtocolDecl *PDecl = OPE->getProtocol();
+ if (PDecl && !PDecl->hasDefinition()) {
+ Diag(PRE->getExprLoc(), diag::warn_atprotocol_protocol) << PDecl->getName();
+ Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl;
+ }
+ }
+
CastKind Kind = CK_Invalid;
Sema::AssignConvertType result =
CheckAssignmentConstraints(LHSType, RHS, Kind);
@@ -7120,6 +7236,19 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
if (isLHSPointer) LHSPointeeTy = LHSExpr->getType()->getPointeeType();
if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType();
+ // if both are pointers check if operation is valid wrt address spaces
+ if (isLHSPointer && isRHSPointer) {
+ const PointerType *lhsPtr = LHSExpr->getType()->getAs<PointerType>();
+ const PointerType *rhsPtr = RHSExpr->getType()->getAs<PointerType>();
+ if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) {
+ S.Diag(Loc,
+ diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
+ << LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/
+ << LHSExpr->getSourceRange() << RHSExpr->getSourceRange();
+ return false;
+ }
+ }
+
// Check for arithmetic on pointers to incomplete types.
bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType();
bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType();
@@ -7163,7 +7292,7 @@ static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc,
bool IsStringPlusInt = StrExpr &&
IndexExpr->getType()->isIntegralOrUnscopedEnumerationType();
- if (!IsStringPlusInt)
+ if (!IsStringPlusInt || IndexExpr->isValueDependent())
return;
llvm::APSInt index;
@@ -7193,13 +7322,13 @@ static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc,
/// \brief Emit a warning when adding a char literal to a string.
static void diagnoseStringPlusChar(Sema &Self, SourceLocation OpLoc,
Expr *LHSExpr, Expr *RHSExpr) {
- const DeclRefExpr *StringRefExpr =
- dyn_cast<DeclRefExpr>(LHSExpr->IgnoreImpCasts());
+ const Expr *StringRefExpr = LHSExpr;
const CharacterLiteral *CharExpr =
dyn_cast<CharacterLiteral>(RHSExpr->IgnoreImpCasts());
- if (!StringRefExpr) {
- StringRefExpr = dyn_cast<DeclRefExpr>(RHSExpr->IgnoreImpCasts());
+
+ if (!CharExpr) {
CharExpr = dyn_cast<CharacterLiteral>(LHSExpr->IgnoreImpCasts());
+ StringRefExpr = RHSExpr;
}
if (!CharExpr || !StringRefExpr)
@@ -7417,7 +7546,7 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
}
static bool isScopedEnumerationType(QualType T) {
- if (const EnumType *ET = dyn_cast<EnumType>(T))
+ if (const EnumType *ET = T->getAs<EnumType>())
return ET->getDecl()->isScoped();
return false;
}
@@ -8048,6 +8177,13 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false);
}
if (LCanPointeeTy != RCanPointeeTy) {
+ const PointerType *lhsPtr = LHSType->getAs<PointerType>();
+ if (!lhsPtr->isAddressSpaceOverlapping(*RHSType->getAs<PointerType>())) {
+ Diag(Loc,
+ diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
+ << LHSType << RHSType << 0 /* comparison */
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ }
unsigned AddrSpaceL = LCanPointeeTy.getAddressSpace();
unsigned AddrSpaceR = RCanPointeeTy.getAddressSpace();
CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion
@@ -8462,7 +8598,7 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
// Must be a reference to a declaration from an enclosing scope.
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
if (!DRE) return NCCK_None;
- if (!DRE->refersToEnclosingLocal()) return NCCK_None;
+ if (!DRE->refersToEnclosingVariableOrCapture()) return NCCK_None;
// The declaration must be a variable which is not declared 'const'.
VarDecl *var = dyn_cast<VarDecl>(DRE->getDecl());
@@ -8494,19 +8630,19 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
if (IsLV == Expr::MLV_Valid)
return false;
- unsigned Diag = 0;
+ unsigned DiagID = 0;
bool NeedType = false;
switch (IsLV) { // C99 6.5.16p2
case Expr::MLV_ConstQualified:
- Diag = diag::err_typecheck_assign_const;
+ DiagID = diag::err_typecheck_assign_const;
// Use a specialized diagnostic when we're assigning to an object
// from an enclosing function or block.
if (NonConstCaptureKind NCCK = isReferenceToNonConstCapture(S, E)) {
if (NCCK == NCCK_Block)
- Diag = diag::err_block_decl_ref_not_modifiable_lvalue;
+ DiagID = diag::err_block_decl_ref_not_modifiable_lvalue;
else
- Diag = diag::err_lambda_decl_ref_not_modifiable_lvalue;
+ DiagID = diag::err_lambda_decl_ref_not_modifiable_lvalue;
break;
}
@@ -8526,18 +8662,18 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
// - self
ObjCMethodDecl *method = S.getCurMethodDecl();
if (method && var == method->getSelfDecl())
- Diag = method->isClassMethod()
+ DiagID = method->isClassMethod()
? diag::err_typecheck_arc_assign_self_class_method
: diag::err_typecheck_arc_assign_self;
// - fast enumeration variables
else
- Diag = diag::err_typecheck_arr_assign_enumeration;
+ DiagID = diag::err_typecheck_arr_assign_enumeration;
SourceRange Assign;
if (Loc != OrigLoc)
Assign = SourceRange(OrigLoc, OrigLoc);
- S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
+ S.Diag(Loc, DiagID) << E->getSourceRange() << Assign;
// We need to preserve the AST regardless, so migration tool
// can do its job.
return false;
@@ -8548,37 +8684,37 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
break;
case Expr::MLV_ArrayType:
case Expr::MLV_ArrayTemporary:
- Diag = diag::err_typecheck_array_not_modifiable_lvalue;
+ DiagID = diag::err_typecheck_array_not_modifiable_lvalue;
NeedType = true;
break;
case Expr::MLV_NotObjectType:
- Diag = diag::err_typecheck_non_object_not_modifiable_lvalue;
+ DiagID = diag::err_typecheck_non_object_not_modifiable_lvalue;
NeedType = true;
break;
case Expr::MLV_LValueCast:
- Diag = diag::err_typecheck_lvalue_casts_not_supported;
+ DiagID = diag::err_typecheck_lvalue_casts_not_supported;
break;
case Expr::MLV_Valid:
llvm_unreachable("did not take early return for MLV_Valid");
case Expr::MLV_InvalidExpression:
case Expr::MLV_MemberFunction:
case Expr::MLV_ClassTemporary:
- Diag = diag::err_typecheck_expression_not_modifiable_lvalue;
+ DiagID = diag::err_typecheck_expression_not_modifiable_lvalue;
break;
case Expr::MLV_IncompleteType:
case Expr::MLV_IncompleteVoidType:
return S.RequireCompleteType(Loc, E->getType(),
diag::err_typecheck_incomplete_type_not_modifiable_lvalue, E);
case Expr::MLV_DuplicateVectorComponents:
- Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
+ DiagID = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
break;
case Expr::MLV_NoSetterProperty:
llvm_unreachable("readonly properties should be processed differently");
case Expr::MLV_InvalidMessageExpression:
- Diag = diag::error_readonly_message_assignment;
+ DiagID = diag::error_readonly_message_assignment;
break;
case Expr::MLV_SubObjCPropertySetting:
- Diag = diag::error_no_subobject_property_setting;
+ DiagID = diag::error_no_subobject_property_setting;
break;
}
@@ -8586,9 +8722,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
if (Loc != OrigLoc)
Assign = SourceRange(OrigLoc, OrigLoc);
if (NeedType)
- S.Diag(Loc, Diag) << E->getType() << E->getSourceRange() << Assign;
+ S.Diag(Loc, DiagID) << E->getType() << E->getSourceRange() << Assign;
else
- S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
+ S.Diag(Loc, DiagID) << E->getSourceRange() << Assign;
return true;
}
@@ -8754,6 +8890,7 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
/// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions.
static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
ExprValueKind &VK,
+ ExprObjectKind &OK,
SourceLocation OpLoc,
bool IsInc, bool IsPrefix) {
if (Op->isTypeDependent())
@@ -8799,7 +8936,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
} else if (ResType->isPlaceholderType()) {
ExprResult PR = S.CheckPlaceholderExpr(Op);
if (PR.isInvalid()) return QualType();
- return CheckIncrementDecrementOperand(S, PR.get(), VK, OpLoc,
+ return CheckIncrementDecrementOperand(S, PR.get(), VK, OK, OpLoc,
IsInc, IsPrefix);
} else if (S.getLangOpts().AltiVec && ResType->isVectorType()) {
// OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 )
@@ -8820,6 +8957,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
// operand.
if (IsPrefix && S.getLangOpts().CPlusPlus) {
VK = VK_LValue;
+ OK = Op->getObjectKind();
return ResType;
} else {
VK = VK_RValue;
@@ -9104,6 +9242,24 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
return Context.getPointerType(op->getType());
}
+static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) {
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp);
+ if (!DRE)
+ return;
+ const Decl *D = DRE->getDecl();
+ if (!D)
+ return;
+ const ParmVarDecl *Param = dyn_cast<ParmVarDecl>(D);
+ if (!Param)
+ return;
+ if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(Param->getDeclContext()))
+ if (!FD->hasAttr<NonNullAttr>() && !Param->hasAttr<NonNullAttr>())
+ return;
+ if (FunctionScopeInfo *FD = S.getCurFunction())
+ if (!FD->ModifiedNonNullParams.count(Param))
+ FD->ModifiedNonNullParams.insert(Param);
+}
+
/// CheckIndirectionOperand - Type check unary indirection (prefix '*').
static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
SourceLocation OpLoc) {
@@ -9164,8 +9320,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
return Result;
}
-static inline BinaryOperatorKind ConvertTokenKindToBinaryOpcode(
- tok::TokenKind Kind) {
+BinaryOperatorKind Sema::ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind) {
BinaryOperatorKind Opc;
switch (Kind) {
default: llvm_unreachable("Unknown binop!");
@@ -9334,6 +9489,16 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
+ if (!getLangOpts().CPlusPlus) {
+ // C cannot handle TypoExpr nodes on either side of a binop because it
+ // doesn't handle dependent types properly, so make sure any TypoExprs have
+ // been dealt with before checking the operands.
+ LHS = CorrectDelayedTyposInExpr(LHSExpr);
+ RHS = CorrectDelayedTyposInExpr(RHSExpr);
+ if (!LHS.isUsable() || !RHS.isUsable())
+ return ExprError();
+ }
+
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
@@ -9342,8 +9507,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
VK = LHS.get()->getValueKind();
OK = LHS.get()->getObjectKind();
}
- if (!ResultTy.isNull())
+ if (!ResultTy.isNull()) {
DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
+ DiagnoseSelfMove(LHS.get(), RHS.get(), OpLoc);
+ }
+ RecordModifiableNonNullParam(*this, LHS.get());
break;
case BO_PtrMemD:
case BO_PtrMemI:
@@ -9503,7 +9671,7 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
StringRef OpStr = isLeftComp ? LHSBO->getOpcodeStr() : RHSBO->getOpcodeStr();
SourceRange ParensRange = isLeftComp ?
SourceRange(LHSBO->getRHS()->getLocStart(), RHSExpr->getLocEnd())
- : SourceRange(LHSExpr->getLocStart(), RHSBO->getLHS()->getLocStart());
+ : SourceRange(LHSExpr->getLocStart(), RHSBO->getLHS()->getLocEnd());
Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
<< DiagRange << BinaryOperator::getOpcodeStr(Opc) << OpStr;
@@ -9709,7 +9877,7 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
UnresolvedSet<16> Functions;
OverloadedOperatorKind OverOp
= BinaryOperator::getOverloadedOperator(Opc);
- if (Sc && OverOp != OO_None)
+ if (Sc && OverOp != OO_None && OverOp != OO_Equal)
S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(),
RHS->getType(), Functions);
@@ -9808,7 +9976,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_PreDec:
case UO_PostInc:
case UO_PostDec:
- resultType = CheckIncrementDecrementOperand(*this, Input.get(), VK, OpLoc,
+ resultType = CheckIncrementDecrementOperand(*this, Input.get(), VK, OK,
+ OpLoc,
Opc == UO_PreInc ||
Opc == UO_PostInc,
Opc == UO_PreInc ||
@@ -9816,6 +9985,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
break;
case UO_AddrOf:
resultType = CheckAddressOfOperand(Input, OpLoc);
+ RecordModifiableNonNullParam(*this, InputExpr);
break;
case UO_Deref: {
Input = DefaultFunctionArrayLvalueConversion(Input.get());
@@ -10107,11 +10277,6 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
assert(!ExprNeedsCleanups && "cleanups within StmtExpr not correctly bound!");
PopExpressionEvaluationContext();
- bool isFileScope
- = (getCurFunctionOrMethodDecl() == nullptr) && (getCurBlock() == nullptr);
- if (isFileScope)
- return ExprError(Diag(LPLoc, diag::err_stmtexpr_file_scope));
-
// FIXME: there are a variety of strange constraints to enforce here, for
// example, it is not possible to goto into a stmt expression apparently.
// More semantic analysis is needed.
@@ -10998,7 +11163,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
PartialDiagnostic FDiag = PDiag(DiagKind);
if (Action == AA_Passing_CFAudited)
- FDiag << FirstType << SecondType << SrcExpr->getSourceRange();
+ FDiag << FirstType << SecondType << AA_Passing << SrcExpr->getSourceRange();
else
FDiag << FirstType << SecondType << Action << SrcExpr->getSourceRange();
@@ -11285,6 +11450,7 @@ Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
void Sema::PopExpressionEvaluationContext() {
ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
+ unsigned NumTypos = Rec.NumTypos;
if (!Rec.Lambdas.empty()) {
if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) {
@@ -11301,19 +11467,14 @@ void Sema::PopExpressionEvaluationContext() {
// evaluate [...] a lambda-expression.
D = diag::err_lambda_in_constant_expression;
}
- for (unsigned I = 0, N = Rec.Lambdas.size(); I != N; ++I)
- Diag(Rec.Lambdas[I]->getLocStart(), D);
+ for (const auto *L : Rec.Lambdas)
+ Diag(L->getLocStart(), D);
} else {
// Mark the capture expressions odr-used. This was deferred
// during lambda expression creation.
- for (unsigned I = 0, N = Rec.Lambdas.size(); I != N; ++I) {
- LambdaExpr *Lambda = Rec.Lambdas[I];
- for (LambdaExpr::capture_init_iterator
- C = Lambda->capture_init_begin(),
- CEnd = Lambda->capture_init_end();
- C != CEnd; ++C) {
- MarkDeclarationsReferencedInExpr(*C);
- }
+ for (auto *Lambda : Rec.Lambdas) {
+ for (auto *C : Lambda->capture_inits())
+ MarkDeclarationsReferencedInExpr(C);
}
}
}
@@ -11337,6 +11498,12 @@ void Sema::PopExpressionEvaluationContext() {
// Pop the current expression evaluation context off the stack.
ExprEvalContexts.pop_back();
+
+ if (!ExprEvalContexts.empty())
+ ExprEvalContexts.back().NumTypos += NumTypos;
+ else
+ assert(NumTypos == 0 && "There are outstanding typos after popping the "
+ "last ExpressionEvaluationContextRecord");
}
void Sema::DiscardCleanupsInEvaluationContext() {
@@ -11385,7 +11552,8 @@ static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
/// \brief Mark a function referenced, and check whether it is odr-used
/// (C++ [basic.def.odr]p2, C99 6.9p3)
-void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
+void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
+ bool OdrUse) {
assert(Func && "No function?");
Func->setReferenced();
@@ -11484,6 +11652,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
ResolveExceptionSpec(Loc, FPT);
+ if (!OdrUse) return;
+
// Implicit instantiation of function templates and member functions of
// class templates.
if (Func->isImplicitlyInstantiable()) {
@@ -11636,7 +11806,7 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *
const bool Diagnose, Sema &S) {
if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC))
return getLambdaAwareParentOfDeclContext(DC);
- else {
+ else if (Var->hasLocalStorage()) {
if (Diagnose)
diagnoseUncapturableValueReference(S, Loc, Var, DC);
}
@@ -11665,13 +11835,10 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
return false;
}
- // Prohibit variably-modified types; they're difficult to deal with.
- if (Var->getType()->isVariablyModifiedType() && (IsBlock || IsLambda)) {
+ // Prohibit variably-modified types in blocks; they're difficult to deal with.
+ if (Var->getType()->isVariablyModifiedType() && IsBlock) {
if (Diagnose) {
- if (IsBlock)
- S.Diag(Loc, diag::err_ref_vm_type);
- else
- S.Diag(Loc, diag::err_lambda_capture_vm_type) << Var->getDeclName();
+ S.Diag(Loc, diag::err_ref_vm_type);
S.Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
}
@@ -11807,7 +11974,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
const bool BuildAndDiagnose,
QualType &CaptureType,
QualType &DeclRefType,
- const bool RefersToEnclosingLocal,
+ const bool RefersToCapturedVariable,
Sema &S) {
// By default, capture variables by reference.
@@ -11829,7 +11996,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
Field->setAccess(AS_private);
RD->addDecl(Field);
- CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal,
+ CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable,
DeclRefType, VK_LValue, Loc);
Var->setReferenced(true);
Var->markUsed(S.Context);
@@ -11837,7 +12004,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
// Actually capture the variable.
if (BuildAndDiagnose)
- RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToEnclosingLocal, Loc,
+ RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToCapturedVariable, Loc,
SourceLocation(), CaptureType, CopyExpr);
@@ -11851,7 +12018,7 @@ static ExprResult addAsFieldToClosureType(Sema &S,
VarDecl *Var, QualType FieldType,
QualType DeclRefType,
SourceLocation Loc,
- bool RefersToEnclosingLocal) {
+ bool RefersToCapturedVariable) {
CXXRecordDecl *Lambda = LSI->Lambda;
// Build the non-static data member.
@@ -11880,7 +12047,7 @@ static ExprResult addAsFieldToClosureType(Sema &S,
// C++ [expr.prim.labda]p12:
// An entity captured by a lambda-expression is odr-used (3.2) in
// the scope containing the lambda-expression.
- Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal,
+ Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable,
DeclRefType, VK_LValue, Loc);
Var->setReferenced(true);
Var->markUsed(S.Context);
@@ -11974,7 +12141,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
const bool BuildAndDiagnose,
QualType &CaptureType,
QualType &DeclRefType,
- const bool RefersToEnclosingLocal,
+ const bool RefersToCapturedVariable,
const Sema::TryCaptureKind Kind,
SourceLocation EllipsisLoc,
const bool IsTopScope,
@@ -12048,7 +12215,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
if (BuildAndDiagnose) {
ExprResult Result = addAsFieldToClosureType(S, LSI, Var,
CaptureType, DeclRefType, Loc,
- RefersToEnclosingLocal);
+ RefersToCapturedVariable);
if (!Result.isInvalid())
CopyExpr = Result.get();
}
@@ -12069,20 +12236,19 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
// Add the capture.
if (BuildAndDiagnose)
- LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToEnclosingLocal,
+ LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable,
Loc, EllipsisLoc, CaptureType, CopyExpr);
return true;
}
-
bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc,
TryCaptureKind Kind, SourceLocation EllipsisLoc,
bool BuildAndDiagnose,
QualType &CaptureType,
QualType &DeclRefType,
const unsigned *const FunctionScopeIndexToStopAt) {
- bool Nested = false;
+ bool Nested = Var->isInitCapture();
DeclContext *DC = CurContext;
const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt
@@ -12100,8 +12266,13 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc,
// If the variable is declared in the current context (and is not an
// init-capture), there is no need to capture it.
- if (!Var->isInitCapture() && Var->getDeclContext() == DC) return true;
- if (!Var->hasLocalStorage()) return true;
+ if (!Nested && Var->getDeclContext() == DC) return true;
+
+ // Capture global variables if it is required to use private copy of this
+ // variable.
+ bool IsGlobal = !Var->hasLocalStorage();
+ if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedVar(Var)))
+ return true;
// Walk up the stack to determine whether we can capture the variable,
// performing the "simple" checks that don't depend on type. We stop when
@@ -12122,8 +12293,17 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc,
ExprLoc,
BuildAndDiagnose,
*this);
- if (!ParentDC) return true;
-
+ // We need to check for the parent *first* because, if we *have*
+ // private-captured a global variable, we need to recursively capture it in
+ // intermediate blocks, lambdas, etc.
+ if (!ParentDC) {
+ if (IsGlobal) {
+ FunctionScopesIndex = MaxFunctionScopesIndex - 1;
+ break;
+ }
+ return true;
+ }
+
FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex];
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FSI);
@@ -12212,14 +12392,37 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc,
break;
case Type::VariableArray: {
// Losing element qualification here is fine.
- const VariableArrayType *Vat = cast<VariableArrayType>(Ty);
+ const VariableArrayType *VAT = cast<VariableArrayType>(Ty);
// Unknown size indication requires no size computation.
// Otherwise, evaluate and record it.
- if (Expr *Size = Vat->getSizeExpr()) {
- MarkDeclarationsReferencedInExpr(Size);
+ if (auto Size = VAT->getSizeExpr()) {
+ if (!CSI->isVLATypeCaptured(VAT)) {
+ RecordDecl *CapRecord = nullptr;
+ if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
+ CapRecord = LSI->Lambda;
+ } else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
+ CapRecord = CRSI->TheRecordDecl;
+ }
+ if (CapRecord) {
+ auto ExprLoc = Size->getExprLoc();
+ auto SizeType = Context.getSizeType();
+ // Build the non-static data member.
+ auto Field = FieldDecl::Create(
+ Context, CapRecord, ExprLoc, ExprLoc,
+ /*Id*/ nullptr, SizeType, /*TInfo*/ nullptr,
+ /*BW*/ nullptr, /*Mutable*/ false,
+ /*InitStyle*/ ICIS_NoInit);
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ Field->setCapturedVLAType(VAT);
+ CapRecord->addDecl(Field);
+
+ CSI->addVLATypeCapture(ExprLoc, SizeType);
+ }
+ }
}
- QTy = Vat->getElementType();
+ QTy = VAT->getElementType();
break;
}
case Type::FunctionProto:
@@ -12326,6 +12529,14 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
DeclRefType, nullptr);
}
+bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) {
+ QualType CaptureType;
+ QualType DeclRefType;
+ return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),
+ /*BuildAndDiagnose=*/false, CaptureType,
+ DeclRefType, nullptr);
+}
+
QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
QualType CaptureType;
QualType DeclRefType;
@@ -12388,6 +12599,8 @@ void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
}
ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
+ Res = CorrectDelayedTyposInExpr(Res);
+
if (!Res.isUsable())
return Res;
@@ -12412,7 +12625,7 @@ void Sema::CleanupVarDeclMarking() {
Var = cast<VarDecl>(ME->getMemberDecl());
Loc = ME->getMemberLoc();
} else {
- llvm_unreachable("Unexpcted expression");
+ llvm_unreachable("Unexpected expression");
}
MarkVarDeclODRUsed(Var, Loc, *this,
@@ -12429,6 +12642,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
"Invalid Expr argument to DoMarkVarDeclReferenced");
Var->setReferenced();
+ TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+ bool MarkODRUsed = true;
+
// If the context is not potentially evaluated, this is not an odr-use and
// does not trigger instantiation.
if (!IsPotentiallyEvaluatedContext(SemaRef)) {
@@ -12443,25 +12659,29 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// arguments, where local variables can't be used.
const bool RefersToEnclosingScope =
(SemaRef.CurContext != Var->getDeclContext() &&
- Var->getDeclContext()->isFunctionOrMethod() &&
- Var->hasLocalStorage());
- if (!RefersToEnclosingScope)
- return;
-
- if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) {
- // If a variable could potentially be odr-used, defer marking it so
- // until we finish analyzing the full expression for any lvalue-to-rvalue
- // or discarded value conversions that would obviate odr-use.
- // Add it to the list of potential captures that will be analyzed
- // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
- // unless the variable is a reference that was initialized by a constant
- // expression (this will never need to be captured or odr-used).
- assert(E && "Capture variable should be used in an expression.");
- if (!Var->getType()->isReferenceType() ||
- !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context))
- LSI->addPotentialCapture(E->IgnoreParens());
+ Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage());
+ if (RefersToEnclosingScope) {
+ if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) {
+ // If a variable could potentially be odr-used, defer marking it so
+ // until we finish analyzing the full expression for any
+ // lvalue-to-rvalue
+ // or discarded value conversions that would obviate odr-use.
+ // Add it to the list of potential captures that will be analyzed
+ // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
+ // unless the variable is a reference that was initialized by a constant
+ // expression (this will never need to be captured or odr-used).
+ assert(E && "Capture variable should be used in an expression.");
+ if (!Var->getType()->isReferenceType() ||
+ !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context))
+ LSI->addPotentialCapture(E->IgnoreParens());
+ }
}
- return;
+
+ if (!isTemplateInstantiation(TSK))
+ return;
+
+ // Instantiate, but do not mark as odr-used, variable templates.
+ MarkODRUsed = false;
}
VarTemplateSpecializationDecl *VarSpec =
@@ -12473,7 +12693,6 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// templates of class templates, and variable template specializations. Delay
// instantiations of variable templates, except for those that could be used
// in a constant expression.
- TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
if (isTemplateInstantiation(TSK)) {
bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
@@ -12513,6 +12732,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
}
}
+ if(!MarkODRUsed) return;
+
// Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies
// the requirements for appearing in a constant expression (5.19) and, if
// it is an object, the lvalue-to-rvalue conversion (4.1)
@@ -12555,6 +12776,10 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ME->getMemberDecl());
if (!MD)
return;
+ // Only attempt to devirtualize if this is truly a virtual call.
+ bool IsVirtualCall = MD->isVirtual() && !ME->hasQualifier();
+ if (!IsVirtualCall)
+ return;
const Expr *Base = ME->getBase();
const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType();
if (!MostDerivedClassDecl)
@@ -12602,14 +12827,14 @@ void Sema::MarkMemberReferenced(MemberExpr *E) {
/// normal expression which refers to a variable.
void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse) {
if (OdrUse) {
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (auto *VD = dyn_cast<VarDecl>(D)) {
MarkVariableReferenced(Loc, VD);
return;
}
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- MarkFunctionReferenced(Loc, FD);
- return;
- }
+ }
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ MarkFunctionReferenced(Loc, FD, OdrUse);
+ return;
}
D->setReferenced();
}
@@ -12935,6 +13160,7 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) {
<< T << E->getSourceRange();
return ExprError();
}
+ CheckBoolLikeConversion(E, Loc);
}
return E;
@@ -13306,6 +13532,39 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
<< VD << E->getSourceRange();
return ExprError();
}
+ if (const FunctionProtoType *FT = Type->getAs<FunctionProtoType>()) {
+ // We must match the FunctionDecl's type to the hack introduced in
+ // RebuildUnknownAnyExpr::VisitCallExpr to vararg functions of unknown
+ // type. See the lengthy commentary in that routine.
+ QualType FDT = FD->getType();
+ const FunctionType *FnType = FDT->castAs<FunctionType>();
+ const FunctionProtoType *Proto = dyn_cast_or_null<FunctionProtoType>(FnType);
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
+ if (DRE && Proto && Proto->getParamTypes().empty() && Proto->isVariadic()) {
+ SourceLocation Loc = FD->getLocation();
+ FunctionDecl *NewFD = FunctionDecl::Create(FD->getASTContext(),
+ FD->getDeclContext(),
+ Loc, Loc, FD->getNameInfo().getName(),
+ DestType, FD->getTypeSourceInfo(),
+ SC_None, false/*isInlineSpecified*/,
+ FD->hasPrototype(),
+ false/*isConstexprSpecified*/);
+
+ if (FD->getQualifier())
+ NewFD->setQualifierInfo(FD->getQualifierLoc());
+
+ SmallVector<ParmVarDecl*, 16> Params;
+ for (const auto &AI : FT->param_types()) {
+ ParmVarDecl *Param =
+ S.BuildParmVarDeclForTypedef(FD, Loc, AI);
+ Param->setScopeInfo(0, Params.size());
+ Params.push_back(Param);
+ }
+ NewFD->setParams(Params);
+ DRE->setDecl(NewFD);
+ VD = DRE->getDecl();
+ }
+ }
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (MD->isInstance()) {
@@ -13431,6 +13690,15 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
/// Check for operands with placeholder types and complain if found.
/// Returns true if there was an error and no recovery was possible.
ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
+ if (!getLangOpts().CPlusPlus) {
+ // C cannot handle TypoExpr nodes on either side of a binop because it
+ // doesn't handle dependent types properly, so make sure any TypoExprs have
+ // been dealt with before checking the operands.
+ ExprResult Result = CorrectDelayedTyposInExpr(E);
+ if (!Result.isUsable()) return ExprError();
+ E = Result.get();
+ }
+
const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType();
if (!placeholderType) return E;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 0dabdca29553..422398ebeb1e 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "TreeTransform.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
@@ -67,6 +68,7 @@ ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS,
break;
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
llvm_unreachable("Nested name specifier is not a type for inheriting ctor");
@@ -198,6 +200,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) {
QualType T = Context.getTypeDeclType(Type);
+ MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
if (SearchType.isNull() || SearchType->isDependentType() ||
Context.hasSameUnqualifiedType(T, SearchType)) {
@@ -354,6 +357,7 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
return true;
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
return false;
@@ -380,6 +384,9 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid))
return ExprError();
+ if (T->isVariablyModifiedType())
+ return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T);
+
return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand,
SourceRange(TypeidLoc, RParenLoc));
}
@@ -389,6 +396,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
SourceLocation TypeidLoc,
Expr *E,
SourceLocation RParenLoc) {
+ bool WasEvaluated = false;
if (E && !E->isTypeDependent()) {
if (E->getType()->isPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
@@ -418,6 +426,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
// We require a vtable to query the type at run time.
MarkVTableUsed(TypeidLoc, RecordD);
+ WasEvaluated = true;
}
}
@@ -434,6 +443,18 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
}
}
+ if (E->getType()->isVariablyModifiedType())
+ return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid)
+ << E->getType());
+ else if (ActiveTemplateInstantiations.empty() &&
+ E->HasSideEffects(Context, WasEvaluated)) {
+ // The expression operand for typeid is in an unevaluated expression
+ // context, so side effects could result in unintended consequences.
+ Diag(E->getExprLoc(), WasEvaluated
+ ? diag::warn_side_effects_typeid
+ : diag::warn_side_effects_unevaluated_context);
+ }
+
return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), E,
SourceRange(TypeidLoc, RParenLoc));
}
@@ -580,15 +601,15 @@ Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) {
bool IsThrownVarInScope = false;
if (Ex) {
// C++0x [class.copymove]p31:
- // When certain criteria are met, an implementation is allowed to omit the
+ // When certain criteria are met, an implementation is allowed to omit the
// copy/move construction of a class object [...]
//
- // - in a throw-expression, when the operand is the name of a
+ // - in a throw-expression, when the operand is the name of a
// non-volatile automatic object (other than a function or catch-
- // clause parameter) whose scope does not extend beyond the end of the
- // innermost enclosing try-block (if there is one), the copy/move
- // operation from the operand to the exception object (15.1) can be
- // omitted by constructing the automatic object directly into the
+ // clause parameter) whose scope does not extend beyond the end of the
+ // innermost enclosing try-block (if there is one), the copy/move
+ // operation from the operand to the exception object (15.1) can be
+ // omitted by constructing the automatic object directly into the
// exception object
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex->IgnoreParens()))
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
@@ -1083,7 +1104,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr;
if (Expr *NumElts = (Expr *)Array.NumElts) {
if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) {
- if (getLangOpts().CPlusPlus1y) {
+ if (getLangOpts().CPlusPlus14) {
// C++1y [expr.new]p6: Every constant-expression in a noptr-new-declarator
// shall be a converted constant expression (5.19) of type std::size_t
// and shall evaluate to a strictly positive value.
@@ -1257,7 +1278,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// std::size_t.
if (ArraySize && !ArraySize->isTypeDependent()) {
ExprResult ConvertedSize;
- if (getLangOpts().CPlusPlus1y) {
+ if (getLangOpts().CPlusPlus14) {
assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?");
ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(),
@@ -2072,19 +2093,18 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
if (!getLangOpts().CPlusPlus11) {
BadAllocType = Context.getTypeDeclType(getStdBadAlloc());
assert(StdBadAlloc && "Must have std::bad_alloc declared");
- EPI.ExceptionSpecType = EST_Dynamic;
- EPI.NumExceptions = 1;
- EPI.Exceptions = &BadAllocType;
+ EPI.ExceptionSpec.Type = EST_Dynamic;
+ EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType);
}
} else {
- EPI.ExceptionSpecType = getLangOpts().CPlusPlus11 ?
- EST_BasicNoexcept : EST_DynamicNone;
+ EPI.ExceptionSpec =
+ getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone;
}
QualType Params[] = { Param1, Param2 };
QualType FnType = Context.getFunctionType(
- Return, ArrayRef<QualType>(Params, NumParams), EPI);
+ Return, llvm::makeArrayRef(Params, NumParams), EPI);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(),
SourceLocation(), Name,
@@ -2102,7 +2122,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
SC_None, nullptr);
ParamDecls[I]->setImplicit();
}
- Alloc->setParams(ArrayRef<ParmVarDecl*>(ParamDecls, NumParams));
+ Alloc->setParams(llvm::makeArrayRef(ParamDecls, NumParams));
Context.getTranslationUnitDecl()->addDecl(Alloc);
IdResolver.tryAddTopLevelDecl(Alloc, Name);
@@ -2622,8 +2642,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// Do no conversion if dealing with ... for the first conversion.
if (!ICS.UserDefined.EllipsisConversion) {
// If the user-defined conversion is specified by a constructor, the
- // initial standard conversion sequence converts the source type to the
- // type required by the argument of the constructor
+ // initial standard conversion sequence converts the source type to
+ // the type required by the argument of the constructor
BeforeToType = Ctor->getParamDecl(0)->getType().getNonReferenceType();
}
}
@@ -2739,15 +2759,19 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// Perform the first implicit conversion.
switch (SCS.First) {
case ICK_Identity:
- // Nothing to do.
+ if (const AtomicType *FromAtomic = FromType->getAs<AtomicType>()) {
+ FromType = FromAtomic->getValueType().getUnqualifiedType();
+ From = ImplicitCastExpr::Create(Context, FromType, CK_AtomicToNonAtomic,
+ From, /*BasePath=*/nullptr, VK_RValue);
+ }
break;
case ICK_Lvalue_To_Rvalue: {
assert(From->getObjectKind() != OK_ObjCProperty);
- FromType = FromType.getUnqualifiedType();
ExprResult FromRes = DefaultLvalueConversion(From);
assert(!FromRes.isInvalid() && "Can't perform deduced conversion?!");
From = FromRes.get();
+ FromType = From->getType();
break;
}
@@ -2770,10 +2794,29 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// Perform the second implicit conversion
switch (SCS.Second) {
case ICK_Identity:
- // If both sides are functions (or pointers/references to them), there could
- // be incompatible exception declarations.
- if (CheckExceptionSpecCompatibility(From, ToType))
- return ExprError();
+ // C++ [except.spec]p5:
+ // [For] assignment to and initialization of pointers to functions,
+ // pointers to member functions, and references to functions: the
+ // target entity shall allow at least the exceptions allowed by the
+ // source value in the assignment or initialization.
+ switch (Action) {
+ case AA_Assigning:
+ case AA_Initializing:
+ // Note, function argument passing and returning are initialization.
+ case AA_Passing:
+ case AA_Returning:
+ case AA_Sending:
+ case AA_Passing_CFAudited:
+ if (CheckExceptionSpecCompatibility(From, ToType))
+ return ExprError();
+ break;
+
+ case AA_Casting:
+ case AA_Converting:
+ // Casts and implicit conversions are not initialization, so are not
+ // checked for exception specification mismatches.
+ break;
+ }
// Nothing else to do.
break;
@@ -2899,6 +2942,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
if (CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
+
+ // We may not have been able to figure out what this member pointer resolved
+ // to up until this exact point. Attempt to lock-in it's inheritance model.
+ QualType FromType = From->getType();
+ if (FromType->isMemberPointerType())
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft())
+ RequireCompleteType(From->getExprLoc(), FromType, 0);
+
From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
.get();
break;
@@ -3642,12 +3693,13 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
if (T->isObjectType() || T->isFunctionType())
T = S.Context.getRValueReferenceType(T);
OpaqueArgExprs.push_back(
- OpaqueValueExpr(Args[I]->getTypeLoc().getLocStart(),
+ OpaqueValueExpr(Args[I]->getTypeLoc().getLocStart(),
T.getNonLValueExprType(S.Context),
Expr::getValueKindForType(T)));
- ArgExprs.push_back(&OpaqueArgExprs.back());
}
-
+ for (Expr &E : OpaqueArgExprs)
+ ArgExprs.push_back(&E);
+
// Perform the initialization in an unevaluated context within a SFINAE
// trap at translation unit scope.
EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
@@ -4549,10 +4601,14 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// the usual arithmetic conversions are performed to bring them to a
// common type, and the result is of that type.
if (LTy->isArithmeticType() && RTy->isArithmeticType()) {
- UsualArithmeticConversions(LHS, RHS);
+ QualType ResTy = UsualArithmeticConversions(LHS, RHS);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
- return LHS.get()->getType();
+
+ LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy));
+ RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy));
+
+ return ResTy;
}
// -- The second and third operands have pointer type, or one has pointer
@@ -4993,9 +5049,8 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
if (!ExprNeedsCleanups)
return SubExpr;
- ArrayRef<ExprWithCleanups::CleanupObject> Cleanups
- = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup,
- ExprCleanupObjects.size() - FirstCleanup);
+ auto Cleanups = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup,
+ ExprCleanupObjects.size() - FirstCleanup);
Expr *E = ExprWithCleanups::Create(Context, SubExpr, Cleanups);
DiscardCleanupsInEvaluationContext();
@@ -5231,7 +5286,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
OperatorArrows.push_back(OpCall->getDirectCallee());
BaseType = Base->getType();
CanQualType CBaseType = Context.getCanonicalType(BaseType);
- if (!CTypes.insert(CBaseType)) {
+ if (!CTypes.insert(CBaseType).second) {
Diag(OpLoc, diag::err_operator_arrow_circular) << StartingType;
noteOperatorArrows(*this, OperatorArrows);
return ExprError();
@@ -5581,7 +5636,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
return ExprError();
- QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+ QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(),
+ false);
TypeLocBuilder TLB;
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
@@ -5649,6 +5705,13 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand,
SourceLocation RParen) {
+ if (ActiveTemplateInstantiations.empty() &&
+ Operand->HasSideEffects(Context, false)) {
+ // The expression operand for noexcept is in an unevaluated expression
+ // context, so side effects could result in unintended consequences.
+ Diag(Operand->getExprLoc(), diag::warn_side_effects_unevaluated_context);
+ }
+
CanThrowResult CanThrow = canThrow(Operand);
return new (Context)
CXXNoexceptExpr(Context.BoolTy, Operand, CanThrow, KeyLoc, RParen);
@@ -5905,6 +5968,284 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
CurrentLSI->clearPotentialCaptures();
}
+static ExprResult attemptRecovery(Sema &SemaRef,
+ const TypoCorrectionConsumer &Consumer,
+ TypoCorrection TC) {
+ LookupResult R(SemaRef, Consumer.getLookupResult().getLookupNameInfo(),
+ Consumer.getLookupResult().getLookupKind());
+ const CXXScopeSpec *SS = Consumer.getSS();
+ CXXScopeSpec NewSS;
+
+ // Use an approprate CXXScopeSpec for building the expr.
+ if (auto *NNS = TC.getCorrectionSpecifier())
+ NewSS.MakeTrivial(SemaRef.Context, NNS, TC.getCorrectionRange());
+ else if (SS && !TC.WillReplaceSpecifier())
+ NewSS = *SS;
+
+ if (auto *ND = TC.getCorrectionDecl()) {
+ R.setLookupName(ND->getDeclName());
+ R.addDecl(ND);
+ if (ND->isCXXClassMember()) {
+ // Figure out the correct naming class to add to the LookupResult.
+ CXXRecordDecl *Record = nullptr;
+ if (auto *NNS = TC.getCorrectionSpecifier())
+ Record = NNS->getAsType()->getAsCXXRecordDecl();
+ if (!Record)
+ Record =
+ dyn_cast<CXXRecordDecl>(ND->getDeclContext()->getRedeclContext());
+ if (Record)
+ R.setNamingClass(Record);
+
+ // Detect and handle the case where the decl might be an implicit
+ // member.
+ bool MightBeImplicitMember;
+ if (!Consumer.isAddressOfOperand())
+ MightBeImplicitMember = true;
+ else if (!NewSS.isEmpty())
+ MightBeImplicitMember = false;
+ else if (R.isOverloadedResult())
+ MightBeImplicitMember = false;
+ else if (R.isUnresolvableResult())
+ MightBeImplicitMember = true;
+ else
+ MightBeImplicitMember = isa<FieldDecl>(ND) ||
+ isa<IndirectFieldDecl>(ND) ||
+ isa<MSPropertyDecl>(ND);
+
+ if (MightBeImplicitMember)
+ return SemaRef.BuildPossibleImplicitMemberExpr(
+ NewSS, /*TemplateKWLoc*/ SourceLocation(), R,
+ /*TemplateArgs*/ nullptr);
+ } else if (auto *Ivar = dyn_cast<ObjCIvarDecl>(ND)) {
+ return SemaRef.LookupInObjCMethod(R, Consumer.getScope(),
+ Ivar->getIdentifier());
+ }
+ }
+
+ return SemaRef.BuildDeclarationNameExpr(NewSS, R, /*NeedsADL*/ false,
+ /*AcceptInvalidDecl*/ true);
+}
+
+namespace {
+class FindTypoExprs : public RecursiveASTVisitor<FindTypoExprs> {
+ llvm::SmallSetVector<TypoExpr *, 2> &TypoExprs;
+
+public:
+ explicit FindTypoExprs(llvm::SmallSetVector<TypoExpr *, 2> &TypoExprs)
+ : TypoExprs(TypoExprs) {}
+ bool VisitTypoExpr(TypoExpr *TE) {
+ TypoExprs.insert(TE);
+ return true;
+ }
+};
+
+class TransformTypos : public TreeTransform<TransformTypos> {
+ typedef TreeTransform<TransformTypos> BaseTransform;
+
+ llvm::function_ref<ExprResult(Expr *)> ExprFilter;
+ llvm::SmallSetVector<TypoExpr *, 2> TypoExprs, AmbiguousTypoExprs;
+ llvm::SmallDenseMap<TypoExpr *, ExprResult, 2> TransformCache;
+ llvm::SmallDenseMap<OverloadExpr *, Expr *, 4> OverloadResolution;
+
+ /// \brief Emit diagnostics for all of the TypoExprs encountered.
+ /// If the TypoExprs were successfully corrected, then the diagnostics should
+ /// suggest the corrections. Otherwise the diagnostics will not suggest
+ /// anything (having been passed an empty TypoCorrection).
+ void EmitAllDiagnostics() {
+ for (auto E : TypoExprs) {
+ TypoExpr *TE = cast<TypoExpr>(E);
+ auto &State = SemaRef.getTypoExprState(TE);
+ if (State.DiagHandler) {
+ TypoCorrection TC = State.Consumer->getCurrentCorrection();
+ ExprResult Replacement = TransformCache[TE];
+
+ // Extract the NamedDecl from the transformed TypoExpr and add it to the
+ // TypoCorrection, replacing the existing decls. This ensures the right
+ // NamedDecl is used in diagnostics e.g. in the case where overload
+ // resolution was used to select one from several possible decls that
+ // had been stored in the TypoCorrection.
+ if (auto *ND = getDeclFromExpr(
+ Replacement.isInvalid() ? nullptr : Replacement.get()))
+ TC.setCorrectionDecl(ND);
+
+ State.DiagHandler(TC);
+ }
+ SemaRef.clearDelayedTypo(TE);
+ }
+ }
+
+ /// \brief If corrections for the first TypoExpr have been exhausted for a
+ /// given combination of the other TypoExprs, retry those corrections against
+ /// the next combination of substitutions for the other TypoExprs by advancing
+ /// to the next potential correction of the second TypoExpr. For the second
+ /// and subsequent TypoExprs, if its stream of corrections has been exhausted,
+ /// the stream is reset and the next TypoExpr's stream is advanced by one (a
+ /// TypoExpr's correction stream is advanced by removing the TypoExpr from the
+ /// TransformCache). Returns true if there is still any untried combinations
+ /// of corrections.
+ bool CheckAndAdvanceTypoExprCorrectionStreams() {
+ for (auto TE : TypoExprs) {
+ auto &State = SemaRef.getTypoExprState(TE);
+ TransformCache.erase(TE);
+ if (!State.Consumer->finished())
+ return true;
+ State.Consumer->resetCorrectionStream();
+ }
+ return false;
+ }
+
+ NamedDecl *getDeclFromExpr(Expr *E) {
+ if (auto *OE = dyn_cast_or_null<OverloadExpr>(E))
+ E = OverloadResolution[OE];
+
+ if (!E)
+ return nullptr;
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+ return DRE->getDecl();
+ if (auto *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ // FIXME: Add any other expr types that could be be seen by the delayed typo
+ // correction TreeTransform for which the corresponding TypoCorrection could
+ // contain multiple decls.
+ return nullptr;
+ }
+
+ ExprResult TryTransform(Expr *E) {
+ Sema::SFINAETrap Trap(SemaRef);
+ ExprResult Res = TransformExpr(E);
+ if (Trap.hasErrorOccurred() || Res.isInvalid())
+ return ExprError();
+
+ return ExprFilter(Res.get());
+ }
+
+public:
+ TransformTypos(Sema &SemaRef, llvm::function_ref<ExprResult(Expr *)> Filter)
+ : BaseTransform(SemaRef), ExprFilter(Filter) {}
+
+ ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation RParenLoc,
+ Expr *ExecConfig = nullptr) {
+ auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args,
+ RParenLoc, ExecConfig);
+ if (auto *OE = dyn_cast<OverloadExpr>(Callee)) {
+ if (Result.isUsable()) {
+ Expr *ResultCall = Result.get();
+ if (auto *BE = dyn_cast<CXXBindTemporaryExpr>(ResultCall))
+ ResultCall = BE->getSubExpr();
+ if (auto *CE = dyn_cast<CallExpr>(ResultCall))
+ OverloadResolution[OE] = CE->getCallee();
+ }
+ }
+ return Result;
+ }
+
+ ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); }
+
+ ExprResult TransformOpaqueValueExpr(OpaqueValueExpr *E) {
+ if (Expr *SE = E->getSourceExpr())
+ return TransformExpr(SE);
+ return BaseTransform::TransformOpaqueValueExpr(E);
+ }
+
+ ExprResult Transform(Expr *E) {
+ ExprResult Res;
+ while (true) {
+ Res = TryTransform(E);
+
+ // Exit if either the transform was valid or if there were no TypoExprs
+ // to transform that still have any untried correction candidates..
+ if (!Res.isInvalid() ||
+ !CheckAndAdvanceTypoExprCorrectionStreams())
+ break;
+ }
+
+ // Ensure none of the TypoExprs have multiple typo correction candidates
+ // with the same edit length that pass all the checks and filters.
+ // TODO: Properly handle various permutations of possible corrections when
+ // there is more than one potentially ambiguous typo correction.
+ while (!AmbiguousTypoExprs.empty()) {
+ auto TE = AmbiguousTypoExprs.back();
+ auto Cached = TransformCache[TE];
+ AmbiguousTypoExprs.pop_back();
+ TransformCache.erase(TE);
+ if (!TryTransform(E).isInvalid()) {
+ SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream();
+ TransformCache.erase(TE);
+ Res = ExprError();
+ break;
+ } else
+ TransformCache[TE] = Cached;
+ }
+
+ // Ensure that all of the TypoExprs within the current Expr have been found.
+ if (!Res.isUsable())
+ FindTypoExprs(TypoExprs).TraverseStmt(E);
+
+ EmitAllDiagnostics();
+
+ return Res;
+ }
+
+ ExprResult TransformTypoExpr(TypoExpr *E) {
+ // If the TypoExpr hasn't been seen before, record it. Otherwise, return the
+ // cached transformation result if there is one and the TypoExpr isn't the
+ // first one that was encountered.
+ auto &CacheEntry = TransformCache[E];
+ if (!TypoExprs.insert(E) && !CacheEntry.isUnset()) {
+ return CacheEntry;
+ }
+
+ auto &State = SemaRef.getTypoExprState(E);
+ assert(State.Consumer && "Cannot transform a cleared TypoExpr");
+
+ // For the first TypoExpr and an uncached TypoExpr, find the next likely
+ // typo correction and return it.
+ while (TypoCorrection TC = State.Consumer->getNextCorrection()) {
+ ExprResult NE = State.RecoveryHandler ?
+ State.RecoveryHandler(SemaRef, E, TC) :
+ attemptRecovery(SemaRef, *State.Consumer, TC);
+ if (!NE.isInvalid()) {
+ // Check whether there may be a second viable correction with the same
+ // edit distance; if so, remember this TypoExpr may have an ambiguous
+ // correction so it can be more thoroughly vetted later.
+ TypoCorrection Next;
+ if ((Next = State.Consumer->peekNextCorrection()) &&
+ Next.getEditDistance(false) == TC.getEditDistance(false)) {
+ AmbiguousTypoExprs.insert(E);
+ } else {
+ AmbiguousTypoExprs.remove(E);
+ }
+ assert(!NE.isUnset() &&
+ "Typo was transformed into a valid-but-null ExprResult");
+ return CacheEntry = NE;
+ }
+ }
+ return CacheEntry = ExprError();
+ }
+};
+}
+
+ExprResult Sema::CorrectDelayedTyposInExpr(
+ Expr *E, llvm::function_ref<ExprResult(Expr *)> Filter) {
+ // If the current evaluation context indicates there are uncorrected typos
+ // and the current expression isn't guaranteed to not have typos, try to
+ // resolve any TypoExpr nodes that might be in the expression.
+ if (E && !ExprEvalContexts.empty() && ExprEvalContexts.back().NumTypos &&
+ (E->isTypeDependent() || E->isValueDependent() ||
+ E->isInstantiationDependent())) {
+ auto TyposResolved = DelayedTypos.size();
+ auto Result = TransformTypos(*this, Filter).Transform(E);
+ TyposResolved -= DelayedTypos.size();
+ if (Result.isInvalid() || Result.get() != E) {
+ ExprEvalContexts.back().NumTypos -= TyposResolved;
+ return Result;
+ }
+ assert(TyposResolved == 0 && "Corrected typo but got same Expr back?");
+ }
+ return E;
+}
ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
bool DiscardedValue,
@@ -5952,6 +6293,10 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
return ExprError();
}
+ FullExpr = CorrectDelayedTyposInExpr(FullExpr.get());
+ if (FullExpr.isInvalid())
+ return ExprError();
+
CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr);
// At the end of this full expression (which could be a deeply nested
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index ef7898208cae..af1cf9046113 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -10,7 +10,7 @@
// This file implements semantic analysis member access expressions.
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Overload.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -21,6 +21,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
using namespace clang;
using namespace sema;
@@ -89,7 +90,6 @@ 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());
@@ -204,6 +204,9 @@ static void diagnoseInstanceReference(Sema &SemaRef,
SourceRange Range(Loc);
if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
+ // Look through using shadow decls and aliases.
+ Rep = Rep->getUnderlyingDecl();
+
DeclContext *FunctionLevelDC = SemaRef.getFunctionLevelDeclContext();
CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FunctionLevelDC);
CXXRecordDecl *ContextClass = Method ? Method->getParent() : nullptr;
@@ -236,7 +239,7 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
- switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
+ switch (ClassifyImplicitMemberAccess(*this, R)) {
case IMA_Instance:
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true);
@@ -536,9 +539,17 @@ namespace {
// FunctionTemplateDecl and are declared in the current record or, for a C++
// classes, one of its base classes.
class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
- public:
+public:
explicit RecordMemberExprValidatorCCC(const RecordType *RTy)
- : Record(RTy->getDecl()) {}
+ : Record(RTy->getDecl()) {
+ // Don't add bare keywords to the consumer since they will always fail
+ // validation by virtue of not being associated with any decls.
+ WantTypeSpecifiers = false;
+ WantExpressionKeywords = false;
+ WantCXXNamedCasts = false;
+ WantFunctionLikeCasts = false;
+ WantRemainingKeywords = false;
+ }
bool ValidateCandidate(const TypoCorrection &candidate) override {
NamedDecl *ND = candidate.getCorrectionDecl();
@@ -554,8 +565,8 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record)) {
// Accept candidates that occur in any of the current class' base classes.
for (const auto &BS : RD->bases()) {
- if (const RecordType *BSTy = dyn_cast_or_null<RecordType>(
- BS.getType().getTypePtrOrNull())) {
+ if (const RecordType *BSTy =
+ dyn_cast_or_null<RecordType>(BS.getType().getTypePtrOrNull())) {
if (BSTy->getDecl()->containsDecl(ND))
return true;
}
@@ -565,17 +576,19 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
return false;
}
- private:
+private:
const RecordDecl *const Record;
};
}
-static bool
-LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
- SourceRange BaseRange, const RecordType *RTy,
- SourceLocation OpLoc, CXXScopeSpec &SS,
- bool HasTemplateArgs) {
+static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
+ Expr *BaseExpr,
+ const RecordType *RTy,
+ SourceLocation OpLoc, bool IsArrow,
+ CXXScopeSpec &SS, bool HasTemplateArgs,
+ TypoExpr *&TE) {
+ SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
RecordDecl *RDecl = RTy->getDecl();
if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) &&
SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
@@ -600,7 +613,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
- << SS.getRange() << DC;
+ << SS.getRange() << DC;
return true;
}
@@ -608,47 +621,48 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
if (!isa<TypeDecl>(DC)) {
SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
- << DC << SS.getRange();
+ << DC << SS.getRange();
return true;
}
}
// The record definition is complete, now look up the member.
- SemaRef.LookupQualifiedName(R, DC);
+ SemaRef.LookupQualifiedName(R, DC, SS);
if (!R.empty())
return false;
- // We didn't find anything with the given name, so try to correct
- // for typos.
- DeclarationName Name = R.getLookupName();
- RecordMemberExprValidatorCCC Validator(RTy);
- TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), nullptr,
- &SS, Validator,
- Sema::CTK_ErrorRecovery, DC);
- R.clear();
- if (Corrected.isResolved() && !Corrected.isKeyword()) {
- R.setLookupName(Corrected.getCorrection());
- for (TypoCorrection::decl_iterator DI = Corrected.begin(),
- DIEnd = Corrected.end();
- DI != DIEnd; ++DI) {
- R.addDecl(*DI);
- }
- R.resolveKind();
-
- // If we're typo-correcting to an overloaded name, we don't yet have enough
- // information to do overload resolution, so we don't know which previous
- // declaration to point to.
- if (Corrected.isOverloaded())
- Corrected.setCorrectionDecl(nullptr);
- bool DroppedSpecifier =
- Corrected.WillReplaceSpecifier() &&
- Name.getAsString() == Corrected.getAsString(SemaRef.getLangOpts());
- SemaRef.diagnoseTypo(Corrected,
- SemaRef.PDiag(diag::err_no_member_suggest)
- << Name << DC << DroppedSpecifier << SS.getRange());
- }
+ DeclarationName Typo = R.getLookupName();
+ SourceLocation TypoLoc = R.getNameLoc();
+ TE = SemaRef.CorrectTypoDelayed(
+ R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS,
+ llvm::make_unique<RecordMemberExprValidatorCCC>(RTy),
+ [=, &SemaRef](const TypoCorrection &TC) {
+ if (TC) {
+ assert(!TC.isKeyword() &&
+ "Got a keyword as a correction for a member!");
+ bool DroppedSpecifier =
+ TC.WillReplaceSpecifier() &&
+ Typo.getAsString() == TC.getAsString(SemaRef.getLangOpts());
+ SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest)
+ << Typo << DC << DroppedSpecifier
+ << SS.getRange());
+ } else {
+ SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << DC << BaseRange;
+ }
+ },
+ [=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable {
+ R.clear(); // Ensure there's no decls lingering in the shared state.
+ R.suppressDiagnostics();
+ R.setLookupName(TC.getCorrection());
+ for (NamedDecl *ND : TC)
+ R.addDecl(ND);
+ R.resolveKind();
+ return SemaRef.BuildMemberReferenceExpr(
+ BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(),
+ nullptr, R, nullptr);
+ },
+ Sema::CTK_ErrorRecovery, DC);
return false;
}
@@ -678,12 +692,15 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
// Implicit member accesses.
if (!Base) {
+ TypoExpr *TE = nullptr;
QualType RecordTy = BaseType;
if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
- if (LookupMemberExprInRecord(*this, R, SourceRange(),
- RecordTy->getAs<RecordType>(),
- OpLoc, SS, TemplateArgs != nullptr))
+ if (LookupMemberExprInRecord(*this, R, nullptr,
+ RecordTy->getAs<RecordType>(), OpLoc, IsArrow,
+ SS, TemplateArgs != nullptr, TE))
return ExprError();
+ if (TE)
+ return TE;
// Explicit member accesses.
} else {
@@ -1211,13 +1228,16 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
// Handle field access to simple records.
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
- if (LookupMemberExprInRecord(S, R, BaseExpr.get()->getSourceRange(),
- RTy, OpLoc, SS, HasTemplateArgs))
+ TypoExpr *TE = nullptr;
+ if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy,
+ OpLoc, IsArrow, SS, HasTemplateArgs, TE))
return ExprError();
// Returning valid-but-null is how we indicate to the caller that
- // the lookup result was filled in.
- return ExprResult((Expr *)nullptr);
+ // the lookup result was filled in. If typo correction was attempted and
+ // failed, the lookup result will have been cleared--that combined with the
+ // valid-but-null ExprResult will trigger the appropriate diagnostics.
+ return ExprResult(TE);
}
// Handle ivar access to Objective-C objects.
@@ -1262,11 +1282,11 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
if (!IV) {
// Attempt to correct for typos in ivar names.
- DeclFilterCCC<ObjCIvarDecl> Validator;
- Validator.IsObjCIvarLookup = IsArrow;
+ auto Validator = llvm::make_unique<DeclFilterCCC<ObjCIvarDecl>>();
+ Validator->IsObjCIvarLookup = IsArrow;
if (TypoCorrection Corrected = S.CorrectTypo(
R.getLookupNameInfo(), Sema::LookupMemberName, nullptr, nullptr,
- Validator, Sema::CTK_ErrorRecovery, IDecl)) {
+ std::move(Validator), Sema::CTK_ErrorRecovery, IDecl)) {
IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
S.diagnoseTypo(
Corrected,
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 500233203c79..9c3b51c623d3 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -944,7 +944,11 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
return ExprError();
std::string Str;
- Context.getObjCEncodingForType(EncodedType, Str);
+ QualType NotEncodedT;
+ Context.getObjCEncodingForType(EncodedType, Str, nullptr, &NotEncodedT);
+ if (!NotEncodedT.isNull())
+ Diag(AtLoc, diag::warn_incomplete_encoded_type)
+ << EncodedType << NotEncodedT;
// The type of @encode is the same as the type of the corresponding string,
// which is an array type.
@@ -983,7 +987,7 @@ static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
ObjCMethodList *M = &MethList;
bool Warned = false;
for (M = M->getNext(); M; M=M->getNext()) {
- ObjCMethodDecl *MatchingMethodDecl = M->Method;
+ ObjCMethodDecl *MatchingMethodDecl = M->getMethod();
if (MatchingMethodDecl == Method ||
isa<ObjCImplDecl>(MatchingMethodDecl->getDeclContext()) ||
MatchingMethodDecl->getSelector() != Method->getSelector())
@@ -1086,6 +1090,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
case OMF_mutableCopy:
case OMF_new:
case OMF_self:
+ case OMF_initialize:
case OMF_performSelector:
break;
}
@@ -1105,6 +1110,8 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId;
return true;
}
+ if (PDecl->hasDefinition())
+ PDecl = PDecl->getDefinition();
QualType Ty = Context.getObjCProtoType();
if (Ty.isNull())
@@ -1222,12 +1229,8 @@ void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) {
// 'instancetype'.
if (const ObjCMethodDecl *overridden =
findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) {
- SourceLocation loc;
- SourceRange range;
- if (TypeSourceInfo *TSI = overridden->getReturnTypeSourceInfo()) {
- range = TSI->getTypeLoc().getSourceRange();
- loc = range.getBegin();
- }
+ SourceRange range = overridden->getReturnTypeSourceRange();
+ SourceLocation loc = range.getBegin();
if (loc.isInvalid())
loc = overridden->getLocation();
Diag(loc, diag::note_related_result_type_explicit)
@@ -1276,6 +1279,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
ObjCMethodDecl *Method,
bool isClassMessage, bool isSuperMessage,
SourceLocation lbrac, SourceLocation rbrac,
+ SourceRange RecRange,
QualType &ReturnType, ExprValueKind &VK) {
SourceLocation SelLoc;
if (!SelectorLocs.empty() && SelectorLocs.front().isValid())
@@ -1317,9 +1321,12 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
: diag::warn_instance_method_not_found_with_typo;
Selector MatchedSel = OMD->getSelector();
SourceRange SelectorRange(SelectorLocs.front(), SelectorLocs.back());
- Diag(SelLoc, DiagID)
- << Sel<< isClassMessage << MatchedSel
- << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
+ if (MatchedSel.isUnarySelector())
+ Diag(SelLoc, DiagID)
+ << Sel<< isClassMessage << MatchedSel
+ << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
+ else
+ Diag(SelLoc, DiagID) << Sel<< isClassMessage << MatchedSel;
}
else
Diag(SelLoc, DiagID)
@@ -1327,9 +1334,15 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
SelectorLocs.back());
// Find the class to which we are sending this message.
if (ReceiverType->isObjCObjectPointerType()) {
- if (ObjCInterfaceDecl *Class =
- ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl())
- Diag(Class->getLocation(), diag::note_receiver_class_declared);
+ if (ObjCInterfaceDecl *ThisClass =
+ ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) {
+ Diag(ThisClass->getLocation(), diag::note_receiver_class_declared);
+ if (!RecRange.isInvalid())
+ if (ThisClass->lookupClassMethod(Sel))
+ Diag(RecRange.getBegin(),diag::note_receiver_expr_here)
+ << FixItHint::CreateReplacement(RecRange,
+ ThisClass->getNameAsString());
+ }
}
}
@@ -1400,7 +1413,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
param);
- ExprResult ArgE = PerformCopyInitialization(Entity, SelLoc, argExpr);
+ ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr);
if (ArgE.isInvalid())
IsError = true;
else
@@ -1434,7 +1447,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
// Do additional checkings on method.
IsError |= CheckObjCMethodCall(
- Method, SelLoc, makeArrayRef<const Expr *>(Args.data(), Args.size()));
+ Method, SelLoc, makeArrayRef(Args.data(), Args.size()));
return IsError;
}
@@ -1651,6 +1664,22 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
+ // Special warning if member name used in a property-dot for a setter accessor
+ // does not use a property with same name; e.g. obj.X = ... for a property with
+ // name 'x'.
+ if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor()
+ && !IFace->FindPropertyDeclaration(Member)) {
+ if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) {
+ // Do not warn if user is using property-dot syntax to make call to
+ // user named setter.
+ if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter))
+ Diag(MemberLoc,
+ diag::warn_property_access_suggest)
+ << MemberName << QualType(OPT, 0) << PDecl->getName()
+ << FixItHint::CreateReplacement(MemberLoc, PDecl->getName());
+ }
+ }
+
if (Getter || Setter) {
if (Super)
return new (Context)
@@ -1664,10 +1693,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
}
// Attempt to correct for typos in property names.
- DeclFilterCCC<ObjCPropertyDecl> Validator;
- if (TypoCorrection Corrected = CorrectTypo(
- DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName,
- nullptr, nullptr, Validator, CTK_ErrorRecovery, IFace, false, OPT)) {
+ if (TypoCorrection Corrected =
+ CorrectTypo(DeclarationNameInfo(MemberName, MemberLoc),
+ LookupOrdinaryName, nullptr, nullptr,
+ llvm::make_unique<DeclFilterCCC<ObjCPropertyDecl>>(),
+ CTK_ErrorRecovery, IFace, false, OPT)) {
diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
<< MemberName << QualType(OPT, 0));
DeclarationName TypoResult = Corrected.getCorrection();
@@ -1892,11 +1922,10 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
}
}
- ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl());
- if (TypoCorrection Corrected =
- CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S,
- nullptr, Validator, CTK_ErrorRecovery, nullptr, false,
- nullptr, false)) {
+ if (TypoCorrection Corrected = CorrectTypo(
+ Result.getLookupNameInfo(), Result.getLookupKind(), S, nullptr,
+ llvm::make_unique<ObjCInterfaceOrSuperCCC>(getCurMethodDecl()),
+ CTK_ErrorRecovery, nullptr, false, nullptr, false)) {
if (Corrected.isKeyword()) {
// If we've found the keyword "super" (the only keyword that would be
// returned by CorrectTypo), this is a send to super.
@@ -2034,6 +2063,45 @@ static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) {
edit::rewriteObjCRedundantCallWithLiteral);
}
+/// \brief Diagnose use of %s directive in an NSString which is being passed
+/// as formatting string to formatting method.
+static void
+DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S,
+ ObjCMethodDecl *Method,
+ Selector Sel,
+ Expr **Args, unsigned NumArgs) {
+ unsigned Idx = 0;
+ bool Format = false;
+ ObjCStringFormatFamily SFFamily = Sel.getStringFormatFamily();
+ if (SFFamily == ObjCStringFormatFamily::SFF_NSString) {
+ Idx = 0;
+ Format = true;
+ }
+ else if (Method) {
+ for (const auto *I : Method->specific_attrs<FormatAttr>()) {
+ if (S.GetFormatNSStringIdx(I, Idx)) {
+ Format = true;
+ break;
+ }
+ }
+ }
+ if (!Format || NumArgs <= Idx)
+ return;
+
+ Expr *FormatExpr = Args[Idx];
+ if (ObjCStringLiteral *OSL =
+ dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) {
+ StringLiteral *FormatString = OSL->getString();
+ if (S.FormatStringHasSArg(FormatString)) {
+ S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
+ << "%s" << 0 << 0;
+ if (Method)
+ S.Diag(Method->getLocation(), diag::note_method_declared_at)
+ << Method->getDeclName();
+ }
+ }
+}
+
/// \brief Build an Objective-C class message expression.
///
/// This routine takes care of both normal class messages and
@@ -2146,7 +2214,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs),
Sel, SelectorLocs,
Method, true,
- SuperLoc.isValid(), LBracLoc, RBracLoc,
+ SuperLoc.isValid(), LBracLoc, RBracLoc,
+ SourceRange(),
ReturnType, VK))
return ExprError();
@@ -2154,7 +2223,32 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
RequireCompleteType(LBracLoc, Method->getReturnType(),
diag::err_illegal_message_expr_incomplete_type))
return ExprError();
-
+
+ // Warn about explicit call of +initialize on its own class. But not on 'super'.
+ if (Method && Method->getMethodFamily() == OMF_initialize) {
+ if (!SuperLoc.isValid()) {
+ const ObjCInterfaceDecl *ID =
+ dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext());
+ if (ID == Class) {
+ Diag(Loc, diag::warn_direct_initialize_call);
+ Diag(Method->getLocation(), diag::note_method_declared_at)
+ << Method->getDeclName();
+ }
+ }
+ else if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
+ // [super initialize] is allowed only within an +initialize implementation
+ if (CurMeth->getMethodFamily() != OMF_initialize) {
+ Diag(Loc, diag::warn_direct_super_initialize_call);
+ Diag(Method->getLocation(), diag::note_method_declared_at)
+ << Method->getDeclName();
+ Diag(CurMeth->getLocation(), diag::note_method_declared_at)
+ << CurMeth->getDeclName();
+ }
+ }
+ }
+
+ DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs);
+
// Construct the appropriate ObjCMessageExpr.
ObjCMessageExpr *Result;
if (SuperLoc.isValid())
@@ -2354,11 +2448,19 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LBracLoc,RBracLoc),
receiverIsId);
+ if (Method) {
+ if (ObjCMethodDecl *BestMethod =
+ SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
+ Method = BestMethod;
+ if (!AreMultipleMethodsInGlobalPool(Sel, Method->isInstanceMethod()))
+ DiagnoseUseOfDecl(Method, SelLoc);
+ }
} else if (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType()) {
// Handle messages to Class.
- // We allow sending a message to a qualified Class ("Class<foo>"), which
- // is ok as long as one of the protocols implements the selector (if not, warn).
+ // We allow sending a message to a qualified Class ("Class<foo>"), which
+ // is ok as long as one of the protocols implements the selector (if not,
+ // warn).
if (const ObjCObjectPointerType *QClassTy
= ReceiverType->getAsObjCQualifiedClassType()) {
// Search protocols for class methods.
@@ -2405,6 +2507,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
<< Sel << SourceRange(LBracLoc, RBracLoc);
}
}
+ if (Method)
+ if (ObjCMethodDecl *BestMethod =
+ SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
+ Method = BestMethod;
}
}
}
@@ -2543,7 +2649,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs),
Sel, SelectorLocs, Method,
ClassMessage, SuperLoc.isValid(),
- LBracLoc, RBracLoc, ReturnType, VK))
+ LBracLoc, RBracLoc, RecRange, ReturnType, VK))
return ExprError();
if (Method && !Method->getReturnType()->isVoidType() &&
@@ -2568,6 +2674,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
case OMF_mutableCopy:
case OMF_new:
case OMF_self:
+ case OMF_initialize:
break;
case OMF_dealloc:
@@ -2630,6 +2737,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
}
+ DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs);
+
// Construct the appropriate ObjCMessageExpr instance.
ObjCMessageExpr *Result;
if (SuperLoc.isValid())
@@ -3296,6 +3405,9 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr,
if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
HadTheAttribute = true;
+ if (Parm->isStr("id"))
+ return true;
+
NamedDecl *Target = nullptr;
// Check for an existing type with this name.
LookupResult R(S, DeclarationName(Parm), SourceLocation(),
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 06ca9aed6a87..569ef307474f 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -466,11 +466,15 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
// members in the aggregate, then each member not explicitly initialized
// shall be initialized from its brace-or-equal-initializer [...]
if (Field->hasInClassInitializer()) {
- Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, Loc, Field);
+ ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
+ if (DIE.isInvalid()) {
+ hadError = true;
+ return;
+ }
if (Init < NumInits)
- ILE->setInit(Init, DIE);
+ ILE->setInit(Init, DIE.get());
else {
- ILE->updateInit(SemaRef.Context, Init, DIE);
+ ILE->updateInit(SemaRef.Context, Init, DIE.get());
RequiresSecondPass = true;
}
return;
@@ -1555,10 +1559,11 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
}
}
- // Value-initialize the first named member of the union.
+ // Value-initialize the first member of the union that isn't an unnamed
+ // bitfield.
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
- if (Field->getDeclName()) {
+ if (!Field->isUnnamedBitfield()) {
if (VerifyOnly)
CheckEmptyInitializable(
InitializedEntity::InitializeMember(*Field, &Entity),
@@ -1734,24 +1739,6 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
&Replacements[0] + Replacements.size());
}
-/// \brief Given an implicit anonymous field, search the IndirectField that
-/// corresponds to FieldName.
-static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField,
- IdentifierInfo *FieldName) {
- if (!FieldName)
- return nullptr;
-
- assert(AnonField->isAnonymousStructOrUnion());
- Decl *NextDecl = AnonField->getNextDeclInContext();
- while (IndirectFieldDecl *IF =
- dyn_cast_or_null<IndirectFieldDecl>(NextDecl)) {
- if (FieldName == IF->getAnonField()->getIdentifier())
- return IF;
- NextDecl = NextDecl->getNextDeclInContext();
- }
- return nullptr;
-}
-
static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef,
DesignatedInitExpr *DIE) {
unsigned NumIndexExprs = DIE->getNumSubExprs() - 1;
@@ -1892,103 +1879,76 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
return true;
}
- // Note: we perform a linear search of the fields here, despite
- // the fact that we have a faster lookup method, because we always
- // need to compute the field's index.
FieldDecl *KnownField = D->getField();
- IdentifierInfo *FieldName = D->getFieldName();
- unsigned FieldIndex = 0;
- RecordDecl::field_iterator
- Field = RT->getDecl()->field_begin(),
- FieldEnd = RT->getDecl()->field_end();
- for (; Field != FieldEnd; ++Field) {
- if (Field->isUnnamedBitfield())
- continue;
-
- // If we find a field representing an anonymous field, look in the
- // IndirectFieldDecl that follow for the designated initializer.
- if (!KnownField && Field->isAnonymousStructOrUnion()) {
- if (IndirectFieldDecl *IF =
- FindIndirectFieldDesignator(*Field, FieldName)) {
+ if (!KnownField) {
+ IdentifierInfo *FieldName = D->getFieldName();
+ DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
+ for (NamedDecl *ND : Lookup) {
+ if (auto *FD = dyn_cast<FieldDecl>(ND)) {
+ KnownField = FD;
+ break;
+ }
+ if (auto *IFD = dyn_cast<IndirectFieldDecl>(ND)) {
// In verify mode, don't modify the original.
if (VerifyOnly)
DIE = CloneDesignatedInitExpr(SemaRef, DIE);
- ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IF);
+ ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IFD);
D = DIE->getDesignator(DesigIdx);
+ KnownField = cast<FieldDecl>(*IFD->chain_begin());
break;
}
}
- if (KnownField && KnownField == *Field)
- break;
- if (FieldName && FieldName == Field->getIdentifier())
- break;
-
- ++FieldIndex;
- }
+ if (!KnownField) {
+ if (VerifyOnly) {
+ ++Index;
+ return true; // No typo correction when just trying this out.
+ }
- if (Field == FieldEnd) {
- if (VerifyOnly) {
- ++Index;
- return true; // No typo correction when just trying this out.
- }
+ // Name lookup found something, but it wasn't a field.
+ if (!Lookup.empty()) {
+ SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
+ << FieldName;
+ SemaRef.Diag(Lookup.front()->getLocation(),
+ diag::note_field_designator_found);
+ ++Index;
+ return true;
+ }
- // There was no normal field in the struct with the designated
- // name. Perform another lookup for this name, which may find
- // something that we can't designate (e.g., a member function),
- // may find nothing, or may find a member of an anonymous
- // struct/union.
- DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
- FieldDecl *ReplacementField = nullptr;
- if (Lookup.empty()) {
- // Name lookup didn't find anything. Determine whether this
- // was a typo for another field name.
- FieldInitializerValidatorCCC Validator(RT->getDecl());
+ // Name lookup didn't find anything.
+ // Determine whether this was a typo for another field name.
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(FieldName, D->getFieldLoc()),
- Sema::LookupMemberName, /*Scope=*/ nullptr, /*SS=*/ nullptr,
- Validator, Sema::CTK_ErrorRecovery, RT->getDecl())) {
+ Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr,
+ llvm::make_unique<FieldInitializerValidatorCCC>(RT->getDecl()),
+ Sema::CTK_ErrorRecovery, RT->getDecl())) {
SemaRef.diagnoseTypo(
Corrected,
SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
- << FieldName << CurrentObjectType);
- ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>();
+ << FieldName << CurrentObjectType);
+ KnownField = Corrected.getCorrectionDeclAs<FieldDecl>();
hadError = true;
} else {
+ // Typo correction didn't find anything.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
++Index;
return true;
}
}
+ }
- if (!ReplacementField) {
- // Name lookup found something, but it wasn't a field.
- SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
- << FieldName;
- SemaRef.Diag(Lookup.front()->getLocation(),
- diag::note_field_designator_found);
- ++Index;
- return true;
- }
-
- if (!KnownField) {
- // The replacement field comes from typo correction; find it
- // in the list of fields.
- FieldIndex = 0;
- Field = RT->getDecl()->field_begin();
- for (; Field != FieldEnd; ++Field) {
- if (Field->isUnnamedBitfield())
- continue;
-
- if (ReplacementField == *Field ||
- Field->getIdentifier() == ReplacementField->getIdentifier())
- break;
-
- ++FieldIndex;
- }
- }
+ unsigned FieldIndex = 0;
+ for (auto *FI : RT->getDecl()->fields()) {
+ if (FI->isUnnamedBitfield())
+ continue;
+ if (KnownField == FI)
+ break;
+ ++FieldIndex;
}
+ RecordDecl::field_iterator Field =
+ RecordDecl::field_iterator(DeclContext::decl_iterator(KnownField));
+
// All of the fields of a union are located at the same place in
// the initializer list.
if (RT->getDecl()->isUnion()) {
@@ -5537,18 +5497,18 @@ static void performLifetimeExtension(Expr *Init,
static bool
performReferenceExtension(Expr *Init,
const InitializedEntity *ExtendingEntity) {
- if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
- if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
- // This is just redundant braces around an initializer. Step over it.
- Init = ILE->getInit(0);
- }
- }
-
// Walk past any constructs which we can lifetime-extend across.
Expr *Old;
do {
Old = Init;
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+ if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
+ // This is just redundant braces around an initializer. Step over it.
+ Init = ILE->getInit(0);
+ }
+ }
+
// Step over any subobject adjustments; we may have a materialized
// temporary inside them.
SmallVector<const Expr *, 2> CommaLHSs;
@@ -6476,12 +6436,45 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
return diagnoseListInit(S, HiddenArray, InitList);
}
+ if (DestType->isReferenceType()) {
+ // A list-initialization failure for a reference means that we tried to
+ // create a temporary of the inner type (per [dcl.init.list]p3.6) and the
+ // inner initialization failed.
+ QualType T = DestType->getAs<ReferenceType>()->getPointeeType();
+ diagnoseListInit(S, InitializedEntity::InitializeTemporary(T), InitList);
+ SourceLocation Loc = InitList->getLocStart();
+ if (auto *D = Entity.getDecl())
+ Loc = D->getLocation();
+ S.Diag(Loc, diag::note_in_reference_temporary_list_initializer) << T;
+ return;
+ }
+
InitListChecker DiagnoseInitList(S, Entity, InitList, DestType,
/*VerifyOnly=*/false);
assert(DiagnoseInitList.HadError() &&
"Inconsistent init list check result.");
}
+/// Prints a fixit for adding a null initializer for |Entity|. Call this only
+/// right after emitting a diagnostic.
+static void maybeEmitZeroInitializationFixit(Sema &S,
+ InitializationSequence &Sequence,
+ const InitializedEntity &Entity) {
+ if (Entity.getKind() != InitializedEntity::EK_Variable)
+ return;
+
+ VarDecl *VD = cast<VarDecl>(Entity.getDecl());
+ if (VD->getInit() || VD->getLocEnd().isMacroID())
+ return;
+
+ QualType VariableTy = VD->getType().getCanonicalType();
+ SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd());
+ std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
+
+ S.Diag(Loc, diag::note_add_initializer)
+ << VD << FixItHint::CreateInsertion(Loc, Init);
+}
+
bool InitializationSequence::Diagnose(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -6812,7 +6805,8 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Entity.getName();
} else {
S.Diag(Kind.getLocation(), diag::err_default_init_const)
- << DestType << (bool)DestType->getAs<RecordType>();
+ << DestType << (bool)DestType->getAs<RecordType>();
+ maybeEmitZeroInitializationFixit(S, *this, Entity);
}
break;
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 0cf4ed7c6081..90a81f4ec452 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -617,7 +617,7 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
// If it was ever a placeholder, it had to been deduced to DependentTy.
assert(CSI.ReturnType.isNull() || !CSI.ReturnType->isUndeducedType());
- // C++ Core Issue #975, proposed resolution:
+ // C++ core issue 975:
// If a lambda-expression does not include a trailing-return-type,
// it is as if the trailing-return-type denotes the following type:
// - if there are no return statements in the compound-statement,
@@ -631,6 +631,10 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
// same, that common type;
// - otherwise, the program is ill-formed.
//
+ // C++ core issue 1048 additionally removes top-level cv-qualifiers
+ // from the types of returned expressions to match the C++14 auto
+ // deduction rules.
+ //
// In addition, in blocks in non-C++ modes, if all of the return
// statements are enumerator-like expressions of some type T, where
// T has a name for linkage, then we infer the return type of the
@@ -679,7 +683,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
const ReturnStmt *RS = *I;
const Expr *RetE = RS->getRetValue();
- QualType ReturnType = (RetE ? RetE->getType() : Context.VoidTy);
+ QualType ReturnType =
+ (RetE ? RetE->getType() : Context.VoidTy).getUnqualifiedType();
if (Context.hasSameType(ReturnType, CSI.ReturnType))
continue;
@@ -873,7 +878,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// We don't do this before C++1y, because we don't support deduced return
// types there.
QualType DefaultTypeForNoTrailingReturn =
- getLangOpts().CPlusPlus1y ? Context.getAutoDeductType()
+ getLangOpts().CPlusPlus14 ? Context.getAutoDeductType()
: Context.DependentTy;
QualType MethodTy =
Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI);
@@ -999,7 +1004,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
VarDecl *Var = nullptr;
if (C->Init.isUsable()) {
- Diag(C->Loc, getLangOpts().CPlusPlus1y
+ Diag(C->Loc, getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_init_capture
: diag::ext_init_capture);
@@ -1049,8 +1054,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (R.empty()) {
// FIXME: Disable corrections that would add qualification?
CXXScopeSpec ScopeSpec;
- DeclFilterCCC<VarDecl> Validator;
- if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator))
+ if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R,
+ llvm::make_unique<DeclFilterCCC<VarDecl>>()))
continue;
}
@@ -1062,7 +1067,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// C++11 [expr.prim.lambda]p8:
// An identifier or this shall not appear more than once in a
// lambda-capture.
- if (!CaptureNames.insert(C->Id)) {
+ if (!CaptureNames.insert(C->Id).second) {
if (Var && LSI->isCaptured(Var)) {
Diag(C->Loc, diag::err_capture_more_than_once)
<< C->Id << SourceRange(LSI->getCapture(Var).getLocation())
@@ -1414,6 +1419,12 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
/*isImplicit=*/true));
continue;
}
+ if (From.isVLATypeCapture()) {
+ Captures.push_back(
+ LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType));
+ CaptureInits.push_back(nullptr);
+ continue;
+ }
VarDecl *Var = From.getVariable();
LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
@@ -1451,7 +1462,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
// different machinery.
// FIXME: Refactor and Merge the return type deduction machinery.
// FIXME: Assumes current resolution to core issue 975.
- if (LSI->HasImplicitReturnType && !getLangOpts().CPlusPlus1y) {
+ if (LSI->HasImplicitReturnType && !getLangOpts().CPlusPlus14) {
deduceClosureReturnType(*LSI);
// - if there are no return statements in the
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index fe2c8161b871..3445264461f7 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -128,7 +128,7 @@ namespace {
// that contexts be visited from the inside out in order to get
// the effective DCs right.
void visit(DeclContext *DC, DeclContext *EffectiveDC) {
- if (!visited.insert(DC))
+ if (!visited.insert(DC).second)
return;
addUsingDirectives(DC, EffectiveDC);
@@ -139,7 +139,7 @@ namespace {
// were declared in the effective DC.
void visit(UsingDirectiveDecl *UD, DeclContext *EffectiveDC) {
DeclContext *NS = UD->getNominatedNamespace();
- if (!visited.insert(NS))
+ if (!visited.insert(NS).second)
return;
addUsingDirective(UD, EffectiveDC);
@@ -154,7 +154,7 @@ namespace {
while (true) {
for (auto UD : DC->using_directives()) {
DeclContext *NS = UD->getNominatedNamespace();
- if (visited.insert(NS)) {
+ if (visited.insert(NS).second) {
addUsingDirective(UD, EffectiveDC);
queue.push_back(NS);
}
@@ -285,7 +285,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
}
void LookupResult::configure() {
- IDNS = getIDNS(LookupKind, SemaRef.getLangOpts().CPlusPlus,
+ IDNS = getIDNS(LookupKind, getSema().getLangOpts().CPlusPlus,
isForRedeclaration());
// If we're looking for one of the allocation or deallocation
@@ -296,7 +296,7 @@ void LookupResult::configure() {
case OO_Delete:
case OO_Array_New:
case OO_Array_Delete:
- SemaRef.DeclareGlobalNewDelete();
+ getSema().DeclareGlobalNewDelete();
break;
default:
@@ -307,7 +307,7 @@ void LookupResult::configure() {
// up being declared.
if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) {
if (unsigned BuiltinID = Id->getBuiltinID()) {
- if (!SemaRef.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ if (!getSema().Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
AllowHidden = true;
}
}
@@ -400,8 +400,8 @@ void LookupResult::resolveKind() {
// canonical type.
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
if (!TD->getDeclContext()->isRecord()) {
- QualType T = SemaRef.Context.getTypeDeclType(TD);
- if (!UniqueTypes.insert(SemaRef.Context.getCanonicalType(T))) {
+ QualType T = getSema().Context.getTypeDeclType(TD);
+ if (!UniqueTypes.insert(getSema().Context.getCanonicalType(T)).second) {
// The type is not unique; pull something off the back and continue
// at this index.
Decls[I] = Decls[--N];
@@ -410,7 +410,7 @@ void LookupResult::resolveKind() {
}
}
- if (!Unique.insert(D)) {
+ if (!Unique.insert(D).second) {
// If it's not unique, pull something off the back (and
// continue at this index).
Decls[I] = Decls[--N];
@@ -735,8 +735,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// FIXME: Calling convention!
FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo();
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C);
- EPI.ExceptionSpecType = EST_None;
- EPI.NumExceptions = 0;
+ EPI.ExceptionSpec = EST_None;
QualType ExpectedType
= R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
None, EPI);
@@ -1176,21 +1175,8 @@ static Module *getDefiningModule(Decl *Entity) {
if (FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
Entity = Pattern;
} else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Entity)) {
- // If it's a class template specialization, find the template or partial
- // specialization from which it was instantiated.
- if (ClassTemplateSpecializationDecl *SpecRD =
- dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
- llvm::PointerUnion<ClassTemplateDecl*,
- ClassTemplatePartialSpecializationDecl*> From =
- SpecRD->getInstantiatedFrom();
- if (ClassTemplateDecl *FromTemplate = From.dyn_cast<ClassTemplateDecl*>())
- Entity = FromTemplate->getTemplatedDecl();
- else if (From)
- Entity = From.get<ClassTemplatePartialSpecializationDecl*>();
- // Otherwise, it's an explicit specialization.
- } else if (MemberSpecializationInfo *MSInfo =
- RD->getMemberSpecializationInfo())
- Entity = getInstantiatedFrom(RD, MSInfo);
+ if (CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern())
+ Entity = Pattern;
} else if (EnumDecl *ED = dyn_cast<EnumDecl>(Entity)) {
if (MemberSpecializationInfo *MSInfo = ED->getMemberSpecializationInfo())
Entity = getInstantiatedFrom(ED, MSInfo);
@@ -1279,7 +1265,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
}
NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
- return findAcceptableDecl(SemaRef, D);
+ return findAcceptableDecl(getSema(), D);
}
/// @brief Perform unqualified name lookup starting from a given
@@ -1466,7 +1452,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
// with its using-children.
for (auto *I : UsingDirectives) {
NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace();
- if (Visited.insert(ND))
+ if (Visited.insert(ND).second)
Queue.push_back(ND);
}
@@ -1514,7 +1500,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
for (auto I : ND->using_directives()) {
NamespaceDecl *Nom = I->getNominatedNamespace();
- if (Visited.insert(Nom))
+ if (Visited.insert(Nom).second)
Queue.push_back(Nom);
}
}
@@ -1776,6 +1762,31 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
return true;
}
+/// \brief Performs qualified name lookup or special type of lookup for
+/// "__super::" scope specifier.
+///
+/// This routine is a convenience overload meant to be called from contexts
+/// that need to perform a qualified name lookup with an optional C++ scope
+/// specifier that might require special kind of lookup.
+///
+/// \param R captures both the lookup criteria and any lookup results found.
+///
+/// \param LookupCtx The context in which qualified name lookup will
+/// search.
+///
+/// \param SS An optional C++ scope-specifier.
+///
+/// \returns true if lookup succeeded, false if it failed.
+bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+ CXXScopeSpec &SS) {
+ auto *NNS = SS.getScopeRep();
+ if (NNS && NNS->getKind() == NestedNameSpecifier::Super)
+ return LookupInSuper(R, NNS->getAsRecordDecl());
+ else
+
+ return LookupQualifiedName(R, LookupCtx);
+}
+
/// @brief Performs name lookup for a name that was parsed in the
/// source code, and may contain a C++ scope specifier.
///
@@ -1783,7 +1794,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
/// contexts that receive a name and an optional C++ scope specifier
/// (e.g., "N::M::x"). It will then perform either qualified or
/// unqualified name lookup (with LookupQualifiedName or LookupName,
-/// respectively) on the given name and return those results.
+/// respectively) on the given name and return those results. It will
+/// perform a special type of lookup for "__super::" scope specifier.
///
/// @param S The scope from which unqualified name lookup will
/// begin.
@@ -1803,6 +1815,10 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
}
if (SS && SS->isSet()) {
+ NestedNameSpecifier *NNS = SS->getScopeRep();
+ if (NNS->getKind() == NestedNameSpecifier::Super)
+ return LookupInSuper(R, NNS->getAsRecordDecl());
+
if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) {
// We have resolved the scope specifier to a particular declaration
// contex, and will perform name lookup in that context.
@@ -1825,6 +1841,30 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
return LookupName(R, S, AllowBuiltinCreation);
}
+/// \brief Perform qualified name lookup into all base classes of the given
+/// class.
+///
+/// \param R captures both the lookup criteria and any lookup results found.
+///
+/// \param Class The context in which qualified name lookup will
+/// search. Name lookup will search in all base classes merging the results.
+///
+/// @returns True if any decls were found (but possibly ambiguous)
+bool Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) {
+ for (const auto &BaseSpec : Class->bases()) {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(
+ BaseSpec.getType()->castAs<RecordType>()->getDecl());
+ LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind());
+ Result.setBaseObjectType(Context.getRecordType(Class));
+ LookupQualifiedName(Result, RD);
+ for (auto *Decl : Result)
+ R.addDecl(Decl);
+ }
+
+ R.resolveKind();
+
+ return !R.empty();
+}
/// \brief Produce a diagnostic describing the ambiguity that resulted
/// from name lookup.
@@ -2024,7 +2064,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
// FIXME: That's not correct, we may have added this class only because it
// was the enclosing class of another class, and in that case we won't have
// added its base classes yet.
- if (!Result.Classes.insert(Class))
+ if (!Result.Classes.insert(Class).second)
return;
// -- If T is a template-id, its associated namespaces and classes are
@@ -2073,7 +2113,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
if (!BaseType)
continue;
CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (Result.Classes.insert(BaseDecl)) {
+ if (Result.Classes.insert(BaseDecl).second) {
// Find the associated namespace for this base class.
DeclContext *BaseCtx = BaseDecl->getDeclContext();
CollectEnclosingNamespace(Result.Namespaces, BaseCtx);
@@ -2875,7 +2915,7 @@ public:
/// \brief Determine whether we have already visited this context
/// (and, if not, note that we are going to visit that context now).
bool visitedContext(DeclContext *Ctx) {
- return !VisitedContexts.insert(Ctx);
+ return !VisitedContexts.insert(Ctx).second;
}
bool alreadyVisitedContext(DeclContext *Ctx) {
@@ -3263,6 +3303,49 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
bool isObjCIvarLookup,
bool FindHidden);
+/// \brief Check whether the declarations found for a typo correction are
+/// visible, and if none of them are, convert the correction to an 'import
+/// a module' correction.
+static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) {
+ if (TC.begin() == TC.end())
+ return;
+
+ TypoCorrection::decl_iterator DI = TC.begin(), DE = TC.end();
+
+ for (/**/; DI != DE; ++DI)
+ if (!LookupResult::isVisible(SemaRef, *DI))
+ break;
+ // Nothing to do if all decls are visible.
+ if (DI == DE)
+ return;
+
+ llvm::SmallVector<NamedDecl*, 4> NewDecls(TC.begin(), DI);
+ bool AnyVisibleDecls = !NewDecls.empty();
+
+ for (/**/; DI != DE; ++DI) {
+ NamedDecl *VisibleDecl = *DI;
+ if (!LookupResult::isVisible(SemaRef, *DI))
+ VisibleDecl = findAcceptableDecl(SemaRef, *DI);
+
+ if (VisibleDecl) {
+ if (!AnyVisibleDecls) {
+ // Found a visible decl, discard all hidden ones.
+ AnyVisibleDecls = true;
+ NewDecls.clear();
+ }
+ NewDecls.push_back(VisibleDecl);
+ } else if (!AnyVisibleDecls && !(*DI)->isModulePrivate())
+ NewDecls.push_back(*DI);
+ }
+
+ if (NewDecls.empty())
+ TC = TypoCorrection();
+ else {
+ TC.setCorrectionDecls(NewDecls);
+ TC.setRequiresImport(!AnyVisibleDecls);
+ }
+}
+
// Fill the supplied vector with the IdentifierInfo pointers for each piece of
// the given NestedNameSpecifier (i.e. given a NestedNameSpecifier "foo::bar::",
// fill the vector with the IdentifierInfo pointers for "foo" and "bar").
@@ -3297,6 +3380,7 @@ static void getNestedNameSpecifierIdentifiers(
break;
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
return;
}
@@ -3304,157 +3388,6 @@ static void getNestedNameSpecifierIdentifiers(
Identifiers.push_back(II);
}
-namespace {
-
-static const unsigned MaxTypoDistanceResultSets = 5;
-
-class TypoCorrectionConsumer : public VisibleDeclConsumer {
- typedef SmallVector<TypoCorrection, 1> TypoResultList;
- typedef llvm::StringMap<TypoResultList> TypoResultsMap;
- typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
-
-public:
- explicit TypoCorrectionConsumer(Sema &SemaRef,
- const DeclarationNameInfo &TypoName,
- Sema::LookupNameKind LookupKind,
- Scope *S, CXXScopeSpec *SS,
- CorrectionCandidateCallback &CCC,
- DeclContext *MemberContext,
- bool EnteringContext)
- : Typo(TypoName.getName().getAsIdentifierInfo()), SemaRef(SemaRef), S(S),
- SS(SS), CorrectionValidator(CCC), MemberContext(MemberContext),
- Result(SemaRef, TypoName, LookupKind),
- Namespaces(SemaRef.Context, SemaRef.CurContext, SS),
- EnteringContext(EnteringContext), SearchNamespaces(false) {
- Result.suppressDiagnostics();
- }
-
- bool includeHiddenDecls() const override { return true; }
-
- // Methods for adding potential corrections to the consumer.
- void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
- bool InBaseClass) override;
- void FoundName(StringRef Name);
- void addKeywordResult(StringRef Keyword);
- void addCorrection(TypoCorrection Correction);
-
- bool empty() const { return CorrectionResults.empty(); }
-
- /// \brief Return the list of TypoCorrections for the given identifier from
- /// the set of corrections that have the closest edit distance, if any.
- TypoResultList &operator[](StringRef Name) {
- return CorrectionResults.begin()->second[Name];
- }
-
- /// \brief Return the edit distance of the corrections that have the
- /// closest/best edit distance from the original typop.
- unsigned getBestEditDistance(bool Normalized) {
- if (CorrectionResults.empty())
- return (std::numeric_limits<unsigned>::max)();
-
- unsigned BestED = CorrectionResults.begin()->first;
- return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED;
- }
-
- /// \brief Set-up method to add to the consumer the set of namespaces to use
- /// in performing corrections to nested name specifiers. This method also
- /// implicitly adds all of the known classes in the current AST context to the
- /// to the consumer for correcting nested name specifiers.
- void
- addNamespaces(const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces);
-
- /// \brief Return the next typo correction that passes all internal filters
- /// and is deemed valid by the consumer's CorrectionCandidateCallback,
- /// starting with the corrections that have the closest edit distance. An
- /// empty TypoCorrection is returned once no more viable corrections remain
- /// in the consumer.
- TypoCorrection getNextCorrection();
-
-private:
- class NamespaceSpecifierSet {
- struct SpecifierInfo {
- DeclContext* DeclCtx;
- NestedNameSpecifier* NameSpecifier;
- unsigned EditDistance;
- };
-
- typedef SmallVector<DeclContext*, 4> DeclContextList;
- typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList;
-
- ASTContext &Context;
- DeclContextList CurContextChain;
- std::string CurNameSpecifier;
- SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers;
- SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers;
- bool isSorted;
-
- SpecifierInfoList Specifiers;
- llvm::SmallSetVector<unsigned, 4> Distances;
- llvm::DenseMap<unsigned, SpecifierInfoList> DistanceMap;
-
- /// \brief Helper for building the list of DeclContexts between the current
- /// context and the top of the translation unit
- static DeclContextList buildContextChain(DeclContext *Start);
-
- void sortNamespaces();
-
- unsigned buildNestedNameSpecifier(DeclContextList &DeclChain,
- NestedNameSpecifier *&NNS);
-
- public:
- NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext,
- CXXScopeSpec *CurScopeSpec);
-
- /// \brief Add the DeclContext (a namespace or record) to the set, computing
- /// the corresponding NestedNameSpecifier and its distance in the process.
- void addNameSpecifier(DeclContext *Ctx);
-
- typedef SpecifierInfoList::iterator iterator;
- iterator begin() {
- if (!isSorted) sortNamespaces();
- return Specifiers.begin();
- }
- iterator end() { return Specifiers.end(); }
- };
-
- void addName(StringRef Name, NamedDecl *ND,
- NestedNameSpecifier *NNS = nullptr, bool isKeyword = false);
-
- /// \brief Find any visible decls for the given typo correction candidate.
- /// If none are found, it to the set of candidates for which qualified lookups
- /// will be performed to find possible nested name specifier changes.
- bool resolveCorrection(TypoCorrection &Candidate);
-
- /// \brief Perform qualified lookups on the queued set of typo correction
- /// candidates and add the nested name specifier changes to each candidate if
- /// a lookup succeeds (at which point the candidate will be returned to the
- /// main pool of potential corrections).
- void performQualifiedLookups();
-
- /// \brief The name written that is a typo in the source.
- IdentifierInfo *Typo;
-
- /// \brief The results found that have the smallest edit distance
- /// found (so far) with the typo name.
- ///
- /// The pointer value being set to the current DeclContext indicates
- /// whether there is a keyword with this name.
- TypoEditDistanceMap CorrectionResults;
-
- Sema &SemaRef;
- Scope *S;
- CXXScopeSpec *SS;
- CorrectionCandidateCallback &CorrectionValidator;
- DeclContext *MemberContext;
- LookupResult Result;
- NamespaceSpecifierSet Namespaces;
- SmallVector<TypoCorrection, 2> QualifiedResults;
- bool EnteringContext;
- bool SearchNamespaces;
-};
-
-}
-
void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
DeclContext *Ctx, bool InBaseClass) {
// Don't consider hidden names for typo correction.
@@ -3506,9 +3439,12 @@ void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND,
TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, ED);
if (isKeyword) TC.makeKeyword();
+ TC.setCorrectionRange(nullptr, Result.getLookupNameInfo());
addCorrection(TC);
}
+static const unsigned MaxTypoDistanceResultSets = 5;
+
void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
StringRef TypoStr = Typo->getName();
StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName();
@@ -3521,9 +3457,11 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
return;
// If the correction is resolved but is not viable, ignore it.
- if (Correction.isResolved() &&
- !isCandidateViable(CorrectionValidator, Correction))
- return;
+ if (Correction.isResolved()) {
+ checkCorrectionVisibility(SemaRef, Correction);
+ if (!Correction || !isCandidateViable(*CorrectionValidator, Correction))
+ return;
+ }
TypoResultList &CList =
CorrectionResults[Correction.getEditDistance(false)][Name];
@@ -3577,7 +3515,11 @@ void TypoCorrectionConsumer::addNamespaces(
}
}
-TypoCorrection TypoCorrectionConsumer::getNextCorrection() {
+const TypoCorrection &TypoCorrectionConsumer::getNextCorrection() {
+ if (++CurrentTCIndex < ValidatedCorrections.size())
+ return ValidatedCorrections[CurrentTCIndex];
+
+ CurrentTCIndex = ValidatedCorrections.size();
while (!CorrectionResults.empty()) {
auto DI = CorrectionResults.begin();
if (DI->second.empty()) {
@@ -3593,20 +3535,22 @@ TypoCorrection TypoCorrectionConsumer::getNextCorrection() {
}
TypoCorrection TC = RI->second.pop_back_val();
- if (TC.isResolved() || resolveCorrection(TC))
- return TC;
+ if (TC.isResolved() || TC.requiresImport() || resolveCorrection(TC)) {
+ ValidatedCorrections.push_back(TC);
+ return ValidatedCorrections[CurrentTCIndex];
+ }
}
- return TypoCorrection();
+ return ValidatedCorrections[0]; // The empty correction.
}
bool TypoCorrectionConsumer::resolveCorrection(TypoCorrection &Candidate) {
IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo();
DeclContext *TempMemberContext = MemberContext;
- CXXScopeSpec *TempSS = SS;
+ CXXScopeSpec *TempSS = SS.get();
retry_lookup:
LookupPotentialTypoResult(SemaRef, Result, Name, S, TempSS, TempMemberContext,
EnteringContext,
- CorrectionValidator.IsObjCIvarLookup,
+ CorrectionValidator->IsObjCIvarLookup,
Name == Typo && !Candidate.WillReplaceSpecifier());
switch (Result.getResultKind()) {
case LookupResult::NotFound:
@@ -3620,7 +3564,7 @@ retry_lookup:
}
if (TempMemberContext) {
if (SS && !TempSS)
- TempSS = SS;
+ TempSS = SS.get();
TempMemberContext = nullptr;
goto retry_lookup;
}
@@ -3637,11 +3581,13 @@ retry_lookup:
// Store all of the Decls for overloaded symbols
for (auto *TRD : Result)
Candidate.addCorrectionDecl(TRD);
- if (!isCandidateViable(CorrectionValidator, Candidate)) {
+ checkCorrectionVisibility(SemaRef, Candidate);
+ if (!isCandidateViable(*CorrectionValidator, Candidate)) {
if (SearchNamespaces)
QualifiedResults.push_back(Candidate);
break;
}
+ Candidate.setCorrectionRange(TempSS, Result.getLookupNameInfo());
return true;
}
return false;
@@ -3707,8 +3653,10 @@ void TypoCorrectionConsumer::performQualifiedLookups() {
TRD.getPair()) == Sema::AR_accessible)
TC.addCorrectionDecl(*TRD);
}
- if (TC.isResolved())
+ if (TC.isResolved()) {
+ TC.setCorrectionRange(SS.get(), Result.getLookupNameInfo());
addCorrection(TC);
+ }
break;
}
case LookupResult::NotFound:
@@ -3856,8 +3804,8 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier(
SmallVector<const IdentifierInfo*, 4> NewNameSpecifierIdentifiers;
getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers);
NumSpecifiers = llvm::ComputeEditDistance(
- ArrayRef<const IdentifierInfo *>(CurNameSpecifierIdentifiers),
- ArrayRef<const IdentifierInfo *>(NewNameSpecifierIdentifiers));
+ llvm::makeArrayRef(CurNameSpecifierIdentifiers),
+ llvm::makeArrayRef(NewNameSpecifierIdentifiers));
}
isSorted = false;
@@ -3972,6 +3920,13 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
if (SemaRef.getLangOpts().GNUMode)
Consumer.addKeywordResult("typeof");
+ } else if (CCC.WantFunctionLikeCasts) {
+ static const char *const CastableTypeSpecs[] = {
+ "char", "double", "float", "int", "long", "short",
+ "signed", "unsigned", "void"
+ };
+ for (auto *kw : CastableTypeSpecs)
+ Consumer.addKeywordResult(kw);
}
if (CCC.WantCXXNamedCasts && SemaRef.getLangOpts().CPlusPlus) {
@@ -4063,212 +4018,96 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
}
}
-/// \brief Check whether the declarations found for a typo correction are
-/// visible, and if none of them are, convert the correction to an 'import
-/// a module' correction.
-static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) {
- if (TC.begin() == TC.end())
- return;
-
- TypoCorrection::decl_iterator DI = TC.begin(), DE = TC.end();
-
- for (/**/; DI != DE; ++DI)
- if (!LookupResult::isVisible(SemaRef, *DI))
- break;
- // Nothing to do if all decls are visible.
- if (DI == DE)
- return;
-
- llvm::SmallVector<NamedDecl*, 4> NewDecls(TC.begin(), DI);
- bool AnyVisibleDecls = !NewDecls.empty();
-
- for (/**/; DI != DE; ++DI) {
- NamedDecl *VisibleDecl = *DI;
- if (!LookupResult::isVisible(SemaRef, *DI))
- VisibleDecl = findAcceptableDecl(SemaRef, *DI);
-
- if (VisibleDecl) {
- if (!AnyVisibleDecls) {
- // Found a visible decl, discard all hidden ones.
- AnyVisibleDecls = true;
- NewDecls.clear();
- }
- NewDecls.push_back(VisibleDecl);
- } else if (!AnyVisibleDecls && !(*DI)->isModulePrivate())
- NewDecls.push_back(*DI);
- }
-
- if (NewDecls.empty())
- TC = TypoCorrection();
- else {
- TC.setCorrectionDecls(NewDecls);
- TC.setRequiresImport(!AnyVisibleDecls);
- }
-}
-
-/// \brief Try to "correct" a typo in the source code by finding
-/// visible declarations whose names are similar to the name that was
-/// present in the source code.
-///
-/// \param TypoName the \c DeclarationNameInfo structure that contains
-/// the name that was present in the source code along with its location.
-///
-/// \param LookupKind the name-lookup criteria used to search for the name.
-///
-/// \param S the scope in which name lookup occurs.
-///
-/// \param SS the nested-name-specifier that precedes the name we're
-/// looking for, if present.
-///
-/// \param CCC A CorrectionCandidateCallback object that provides further
-/// validation of typo correction candidates. It also provides flags for
-/// determining the set of keywords permitted.
-///
-/// \param MemberContext if non-NULL, the context in which to look for
-/// a member access expression.
-///
-/// \param EnteringContext whether we're entering the context described by
-/// the nested-name-specifier SS.
-///
-/// \param OPT when non-NULL, the search for visible declarations will
-/// also walk the protocols in the qualified interfaces of \p OPT.
-///
-/// \returns a \c TypoCorrection containing the corrected name if the typo
-/// along with information such as the \c NamedDecl where the corrected name
-/// was declared, and any additional \c NestedNameSpecifier needed to access
-/// it (C++ only). The \c TypoCorrection is empty if there is no correction.
-TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
- Sema::LookupNameKind LookupKind,
- Scope *S, CXXScopeSpec *SS,
- CorrectionCandidateCallback &CCC,
- CorrectTypoKind Mode,
- DeclContext *MemberContext,
- bool EnteringContext,
- const ObjCObjectPointerType *OPT,
- bool RecordFailure) {
- // Always let the ExternalSource have the first chance at correction, even
- // if we would otherwise have given up.
- if (ExternalSource) {
- if (TypoCorrection Correction = ExternalSource->CorrectTypo(
- TypoName, LookupKind, S, SS, CCC, MemberContext, EnteringContext, OPT))
- return Correction;
- }
+std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer(
+ const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind,
+ Scope *S, CXXScopeSpec *SS,
+ std::unique_ptr<CorrectionCandidateCallback> CCC,
+ DeclContext *MemberContext, bool EnteringContext,
+ const ObjCObjectPointerType *OPT, bool ErrorRecovery) {
if (Diags.hasFatalErrorOccurred() || !getLangOpts().SpellChecking ||
DisableTypoCorrection)
- return TypoCorrection();
+ return nullptr;
// In Microsoft mode, don't perform typo correction in a template member
// function dependent context because it interferes with the "lookup into
// dependent bases of class templates" feature.
if (getLangOpts().MSVCCompat && CurContext->isDependentContext() &&
isa<CXXMethodDecl>(CurContext))
- return TypoCorrection();
+ return nullptr;
// We only attempt to correct typos for identifiers.
IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
if (!Typo)
- return TypoCorrection();
+ return nullptr;
// If the scope specifier itself was invalid, don't try to correct
// typos.
if (SS && SS->isInvalid())
- return TypoCorrection();
+ return nullptr;
// Never try to correct typos during template deduction or
// instantiation.
if (!ActiveTemplateInstantiations.empty())
- return TypoCorrection();
+ return nullptr;
// Don't try to correct 'super'.
if (S && S->isInObjcMethodScope() && Typo == getSuperIdentifier())
- return TypoCorrection();
+ return nullptr;
// Abort if typo correction already failed for this specific typo.
IdentifierSourceLocations::iterator locs = TypoCorrectionFailures.find(Typo);
if (locs != TypoCorrectionFailures.end() &&
locs->second.count(TypoName.getLoc()))
- return TypoCorrection();
+ return nullptr;
// Don't try to correct the identifier "vector" when in AltiVec mode.
// TODO: Figure out why typo correction misbehaves in this case, fix it, and
// remove this workaround.
if (getLangOpts().AltiVec && Typo->isStr("vector"))
- return TypoCorrection();
+ return nullptr;
+
+ // Provide a stop gap for files that are just seriously broken. Trying
+ // to correct all typos can turn into a HUGE performance penalty, causing
+ // some files to take minutes to get rejected by the parser.
+ unsigned Limit = getDiagnostics().getDiagnosticOptions().SpellCheckingLimit;
+ if (Limit && TyposCorrected >= Limit)
+ return nullptr;
+ ++TyposCorrected;
// If we're handling a missing symbol error, using modules, and the
// special search all modules option is used, look for a missing import.
- if ((Mode == CTK_ErrorRecovery) && getLangOpts().Modules &&
+ if (ErrorRecovery && getLangOpts().Modules &&
getLangOpts().ModulesSearchAll) {
// The following has the side effect of loading the missing module.
getModuleLoader().lookupMissingImports(Typo->getName(),
TypoName.getLocStart());
}
- TypoCorrectionConsumer Consumer(*this, TypoName, LookupKind, S, SS, CCC,
- MemberContext, EnteringContext);
-
- // If a callback object considers an empty typo correction candidate to be
- // viable, assume it does not do any actual validation of the candidates.
- TypoCorrection EmptyCorrection;
- bool ValidatingCallback = !isCandidateViable(CCC, EmptyCorrection);
+ CorrectionCandidateCallback &CCCRef = *CCC;
+ auto Consumer = llvm::make_unique<TypoCorrectionConsumer>(
+ *this, TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
+ EnteringContext);
// Perform name lookup to find visible, similarly-named entities.
bool IsUnqualifiedLookup = false;
DeclContext *QualifiedDC = MemberContext;
if (MemberContext) {
- LookupVisibleDecls(MemberContext, LookupKind, Consumer);
+ LookupVisibleDecls(MemberContext, LookupKind, *Consumer);
// Look in qualified interfaces.
if (OPT) {
for (auto *I : OPT->quals())
- LookupVisibleDecls(I, LookupKind, Consumer);
+ LookupVisibleDecls(I, LookupKind, *Consumer);
}
} else if (SS && SS->isSet()) {
QualifiedDC = computeDeclContext(*SS, EnteringContext);
if (!QualifiedDC)
- return TypoCorrection();
+ return nullptr;
- // Provide a stop gap for files that are just seriously broken. Trying
- // to correct all typos can turn into a HUGE performance penalty, causing
- // some files to take minutes to get rejected by the parser.
- if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
- return TypoCorrection();
- ++TyposCorrected;
-
- LookupVisibleDecls(QualifiedDC, LookupKind, Consumer);
+ LookupVisibleDecls(QualifiedDC, LookupKind, *Consumer);
} else {
IsUnqualifiedLookup = true;
- UnqualifiedTyposCorrectedMap::iterator Cached
- = UnqualifiedTyposCorrected.find(Typo);
- if (Cached != UnqualifiedTyposCorrected.end()) {
- // Add the cached value, unless it's a keyword or fails validation. In the
- // keyword case, we'll end up adding the keyword below.
- if (Cached->second) {
- if (!Cached->second.isKeyword() &&
- isCandidateViable(CCC, Cached->second)) {
- // Do not use correction that is unaccessible in the given scope.
- NamedDecl *CorrectionDecl = Cached->second.getCorrectionDecl();
- DeclarationNameInfo NameInfo(CorrectionDecl->getDeclName(),
- CorrectionDecl->getLocation());
- LookupResult R(*this, NameInfo, LookupOrdinaryName);
- if (LookupName(R, S))
- Consumer.addCorrection(Cached->second);
- }
- } else {
- // Only honor no-correction cache hits when a callback that will validate
- // correction candidates is not being used.
- if (!ValidatingCallback)
- return TypoCorrection();
- }
- }
- if (Cached == UnqualifiedTyposCorrected.end()) {
- // Provide a stop gap for files that are just seriously broken. Trying
- // to correct all typos can turn into a HUGE performance penalty, causing
- // some files to take minutes to get rejected by the parser.
- if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
- return TypoCorrection();
- }
}
// Determine whether we are going to search in the various namespaces for
@@ -4276,17 +4115,13 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
bool SearchNamespaces
= getLangOpts().CPlusPlus &&
(IsUnqualifiedLookup || (SS && SS->isSet()));
- // In a few cases we *only* want to search for corrections based on just
- // adding or changing the nested name specifier.
- unsigned TypoLen = Typo->getName().size();
- bool AllowOnlyNNSChanges = TypoLen < 3;
if (IsUnqualifiedLookup || SearchNamespaces) {
// For unqualified lookup, look through all of the names that we have
// seen in this translation unit.
// FIXME: Re-add the ability to skip very unlikely potential corrections.
for (const auto &I : Context.Idents)
- Consumer.FoundName(I.getKey());
+ Consumer->FoundName(I.getKey());
// Walk through identifiers in external identifier sources.
// FIXME: Re-add the ability to skip very unlikely potential corrections.
@@ -4298,24 +4133,12 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (Name.empty())
break;
- Consumer.FoundName(Name);
+ Consumer->FoundName(Name);
} while (true);
}
}
- AddKeywordsToConsumer(*this, Consumer, S, CCC, SS && SS->isNotEmpty());
-
- // If we haven't found anything, we're done.
- if (Consumer.empty())
- return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
- IsUnqualifiedLookup);
-
- // Make sure the best edit distance (prior to adding any namespace qualifiers)
- // is not more that about a third of the length of the typo's identifier.
- unsigned ED = Consumer.getBestEditDistance(true);
- if (ED > 0 && TypoLen / ED < 3)
- return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
- IsUnqualifiedLookup);
+ AddKeywordsToConsumer(*this, *Consumer, S, CCCRef, SS && SS->isNotEmpty());
// Build the NestedNameSpecifiers for the KnownNamespaces, if we're going
// to search those namespaces.
@@ -4329,22 +4152,99 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
KnownNamespaces[N] = true;
}
- Consumer.addNamespaces(KnownNamespaces);
+ Consumer->addNamespaces(KnownNamespaces);
}
- TypoCorrection BestTC = Consumer.getNextCorrection();
- TypoCorrection SecondBestTC = Consumer.getNextCorrection();
+ return Consumer;
+}
+
+/// \brief Try to "correct" a typo in the source code by finding
+/// visible declarations whose names are similar to the name that was
+/// present in the source code.
+///
+/// \param TypoName the \c DeclarationNameInfo structure that contains
+/// the name that was present in the source code along with its location.
+///
+/// \param LookupKind the name-lookup criteria used to search for the name.
+///
+/// \param S the scope in which name lookup occurs.
+///
+/// \param SS the nested-name-specifier that precedes the name we're
+/// looking for, if present.
+///
+/// \param CCC A CorrectionCandidateCallback object that provides further
+/// validation of typo correction candidates. It also provides flags for
+/// determining the set of keywords permitted.
+///
+/// \param MemberContext if non-NULL, the context in which to look for
+/// a member access expression.
+///
+/// \param EnteringContext whether we're entering the context described by
+/// the nested-name-specifier SS.
+///
+/// \param OPT when non-NULL, the search for visible declarations will
+/// also walk the protocols in the qualified interfaces of \p OPT.
+///
+/// \returns a \c TypoCorrection containing the corrected name if the typo
+/// along with information such as the \c NamedDecl where the corrected name
+/// was declared, and any additional \c NestedNameSpecifier needed to access
+/// it (C++ only). The \c TypoCorrection is empty if there is no correction.
+TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
+ Sema::LookupNameKind LookupKind,
+ Scope *S, CXXScopeSpec *SS,
+ std::unique_ptr<CorrectionCandidateCallback> CCC,
+ CorrectTypoKind Mode,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ const ObjCObjectPointerType *OPT,
+ bool RecordFailure) {
+ assert(CCC && "CorrectTypo requires a CorrectionCandidateCallback");
+
+ // Always let the ExternalSource have the first chance at correction, even
+ // if we would otherwise have given up.
+ if (ExternalSource) {
+ if (TypoCorrection Correction = ExternalSource->CorrectTypo(
+ TypoName, LookupKind, S, SS, *CCC, MemberContext, EnteringContext, OPT))
+ return Correction;
+ }
+
+ // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver;
+ // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for
+ // some instances of CTC_Unknown, while WantRemainingKeywords is true
+ // for CTC_Unknown but not for CTC_ObjCMessageReceiver.
+ bool ObjCMessageReceiver = CCC->WantObjCSuper && !CCC->WantRemainingKeywords;
+
+ IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
+ auto Consumer = makeTypoCorrectionConsumer(
+ TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
+ EnteringContext, OPT, Mode == CTK_ErrorRecovery);
+
+ if (!Consumer)
+ return TypoCorrection();
+
+ // If we haven't found anything, we're done.
+ if (Consumer->empty())
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
+
+ // Make sure the best edit distance (prior to adding any namespace qualifiers)
+ // is not more that about a third of the length of the typo's identifier.
+ unsigned ED = Consumer->getBestEditDistance(true);
+ unsigned TypoLen = Typo->getName().size();
+ if (ED > 0 && TypoLen / ED < 3)
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
+
+ TypoCorrection BestTC = Consumer->getNextCorrection();
+ TypoCorrection SecondBestTC = Consumer->getNextCorrection();
if (!BestTC)
return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
ED = BestTC.getEditDistance();
- if (!AllowOnlyNNSChanges && ED > 0 && TypoLen / ED < 3) {
+ if (TypoLen >= 3 && ED > 0 && TypoLen / ED < 3) {
// If this was an unqualified lookup and we believe the callback
// object wouldn't have filtered out possible corrections, note
// that no correction was found.
- return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
- IsUnqualifiedLookup && !ValidatingCallback);
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
}
// If only a single name remains, return that result.
@@ -4357,28 +4257,19 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (ED == 0 && Result.isKeyword())
return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
- // Record the correction for unqualified lookup.
- if (IsUnqualifiedLookup)
- UnqualifiedTyposCorrected[Typo] = Result;
-
TypoCorrection TC = Result;
TC.setCorrectionRange(SS, TypoName);
checkCorrectionVisibility(*this, TC);
return TC;
- }
- // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver;
- // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for
- // some instances of CTC_Unknown, while WantRemainingKeywords is true
- // for CTC_Unknown but not for CTC_ObjCMessageReceiver.
- else if (SecondBestTC && CCC.WantObjCSuper && !CCC.WantRemainingKeywords) {
+ } else if (SecondBestTC && ObjCMessageReceiver) {
// Prefer 'super' when we're completing in a message-receiver
// context.
if (BestTC.getCorrection().getAsString() != "super") {
if (SecondBestTC.getCorrection().getAsString() == "super")
BestTC = SecondBestTC;
- else if (Consumer["super"].front().isKeyword())
- BestTC = Consumer["super"].front();
+ else if ((*Consumer)["super"].front().isKeyword())
+ BestTC = (*Consumer)["super"].front();
}
// Don't correct to a keyword that's the same as the typo; the keyword
// wasn't actually in scope.
@@ -4386,10 +4277,6 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
BestTC.getCorrection().getAsString() != "super")
return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
- // Record the correction for unqualified lookup.
- if (IsUnqualifiedLookup)
- UnqualifiedTyposCorrected[Typo] = BestTC;
-
BestTC.setCorrectionRange(SS, TypoName);
return BestTC;
}
@@ -4397,8 +4284,75 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Record the failure's location if needed and return an empty correction. If
// this was an unqualified lookup and we believe the callback object did not
// filter out possible corrections, also cache the failure for the typo.
- return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
- IsUnqualifiedLookup && !ValidatingCallback);
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
+}
+
+/// \brief Try to "correct" a typo in the source code by finding
+/// visible declarations whose names are similar to the name that was
+/// present in the source code.
+///
+/// \param TypoName the \c DeclarationNameInfo structure that contains
+/// the name that was present in the source code along with its location.
+///
+/// \param LookupKind the name-lookup criteria used to search for the name.
+///
+/// \param S the scope in which name lookup occurs.
+///
+/// \param SS the nested-name-specifier that precedes the name we're
+/// looking for, if present.
+///
+/// \param CCC A CorrectionCandidateCallback object that provides further
+/// validation of typo correction candidates. It also provides flags for
+/// determining the set of keywords permitted.
+///
+/// \param TDG A TypoDiagnosticGenerator functor that will be used to print
+/// diagnostics when the actual typo correction is attempted.
+///
+/// \param TRC A TypoRecoveryCallback functor that will be used to build an
+/// Expr from a typo correction candidate.
+///
+/// \param MemberContext if non-NULL, the context in which to look for
+/// a member access expression.
+///
+/// \param EnteringContext whether we're entering the context described by
+/// the nested-name-specifier SS.
+///
+/// \param OPT when non-NULL, the search for visible declarations will
+/// also walk the protocols in the qualified interfaces of \p OPT.
+///
+/// \returns a new \c TypoExpr that will later be replaced in the AST with an
+/// Expr representing the result of performing typo correction, or nullptr if
+/// typo correction is not possible. If nullptr is returned, no diagnostics will
+/// be emitted and it is the responsibility of the caller to emit any that are
+/// needed.
+TypoExpr *Sema::CorrectTypoDelayed(
+ const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind,
+ Scope *S, CXXScopeSpec *SS,
+ std::unique_ptr<CorrectionCandidateCallback> CCC,
+ TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode,
+ DeclContext *MemberContext, bool EnteringContext,
+ const ObjCObjectPointerType *OPT) {
+ assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback");
+
+ TypoCorrection Empty;
+ auto Consumer = makeTypoCorrectionConsumer(
+ TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
+ EnteringContext, OPT,
+ /*SearchModules=*/(Mode == CTK_ErrorRecovery) && getLangOpts().Modules &&
+ getLangOpts().ModulesSearchAll);
+
+ if (!Consumer || Consumer->empty())
+ return nullptr;
+
+ // Make sure the best edit distance (prior to adding any namespace qualifiers)
+ // is not more that about a third of the length of the typo's identifier.
+ unsigned ED = Consumer->getBestEditDistance(true);
+ IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
+ if (ED > 0 && Typo->getName().size() / ED < 3)
+ return nullptr;
+
+ ExprEvalContexts.back().NumTypos++;
+ return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC));
}
void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) {
@@ -4425,7 +4379,8 @@ std::string TypoCorrection::getAsString(const LangOptions &LO) const {
return CorrectionName.getAsString();
}
-bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candidate) {
+bool CorrectionCandidateCallback::ValidateCandidate(
+ const TypoCorrection &candidate) {
if (!candidate.isResolved())
return true;
@@ -4461,7 +4416,8 @@ FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
MemberExpr *ME)
: NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs),
CurContext(SemaRef.CurContext), MemberFn(ME) {
- WantTypeSpecifiers = SemaRef.getLangOpts().CPlusPlus;
+ WantTypeSpecifiers = false;
+ WantFunctionLikeCasts = SemaRef.getLangOpts().CPlusPlus && NumArgs == 1;
WantRemainingKeywords = false;
}
@@ -4596,3 +4552,26 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction,
Diag(ChosenDecl->getLocation(), PrevNote)
<< CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo);
}
+
+TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC,
+ TypoDiagnosticGenerator TDG,
+ TypoRecoveryCallback TRC) {
+ assert(TCC && "createDelayedTypo requires a valid TypoCorrectionConsumer");
+ auto TE = new (Context) TypoExpr(Context.DependentTy);
+ auto &State = DelayedTypos[TE];
+ State.Consumer = std::move(TCC);
+ State.DiagHandler = std::move(TDG);
+ State.RecoveryHandler = std::move(TRC);
+ return TE;
+}
+
+const Sema::TypoExprState &Sema::getTypoExprState(TypoExpr *TE) const {
+ auto Entry = DelayedTypos.find(TE);
+ assert(Entry != DelayedTypos.end() &&
+ "Failed to get the state for a TypoExpr!");
+ return Entry->second;
+}
+
+void Sema::clearDelayedTypo(TypoExpr *TE) {
+ DelayedTypos.erase(TE);
+}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 8eb806ba301a..72b6020351fa 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -116,9 +116,9 @@ static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) {
static void
CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
ObjCProtocolDecl *Proto,
- llvm::SmallPtrSet<ObjCProtocolDecl *, 16> &Known) {
+ llvm::SmallPtrSetImpl<ObjCProtocolDecl *> &Known) {
// Have we seen this protocol before?
- if (!Known.insert(Proto))
+ if (!Known.insert(Proto).second)
return;
// Look for a property with the same name.
@@ -1547,36 +1547,22 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
if (IMPDecl->getInstanceMethod(Prop->getSetterName()))
continue;
}
- // If property to be implemented in the super class, ignore.
- if (SuperPropMap[Prop->getIdentifier()]) {
- ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()];
- if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) &&
- (PropInSuperClass->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_readonly) &&
- !IMPDecl->getInstanceMethod(Prop->getSetterName()) &&
- !IDecl->HasUserDeclaredSetterMethod(Prop)) {
- Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)
- << Prop->getIdentifier();
- Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
- }
- continue;
- }
if (ObjCPropertyImplDecl *PID =
IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {
- if (PID->getPropertyDecl() != Prop) {
- Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)
- << Prop->getIdentifier();
- if (!PID->getLocation().isInvalid())
- Diag(PID->getLocation(), diag::note_property_synthesize);
- }
+ Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)
+ << Prop->getIdentifier();
+ if (!PID->getLocation().isInvalid())
+ Diag(PID->getLocation(), diag::note_property_synthesize);
continue;
}
+ ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()];
if (ObjCProtocolDecl *Proto =
dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) {
// We won't auto-synthesize properties declared in protocols.
// Suppress the warning if class's superclass implements property's
// getter and implements property's setter (if readwrite property).
- if (!SuperClassImplementsProperty(IDecl, Prop)) {
+ // Or, if property is going to be implemented in its super class.
+ if (!SuperClassImplementsProperty(IDecl, Prop) && !PropInSuperClass) {
Diag(IMPDecl->getLocation(),
diag::warn_auto_synthesizing_protocol_property)
<< Prop << Proto;
@@ -1584,7 +1570,25 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
}
continue;
}
-
+ // If property to be implemented in the super class, ignore.
+ if (PropInSuperClass) {
+ if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) &&
+ (PropInSuperClass->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_readonly) &&
+ !IMPDecl->getInstanceMethod(Prop->getSetterName()) &&
+ !IDecl->HasUserDeclaredSetterMethod(Prop)) {
+ Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)
+ << Prop->getIdentifier();
+ Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
+ }
+ else {
+ Diag(Prop->getLocation(), diag::warn_autosynthesis_property_in_superclass)
+ << Prop->getIdentifier();
+ Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
+ Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
+ }
+ continue;
+ }
// We use invalid SourceLocations for the synthesized ivars since they
// aren't really synthesized at a particular location; they just exist.
// Saying that they are located at the @implementation isn't really going
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 7f2af68e55d5..d72942a2ffec 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclOpenMP.h"
@@ -91,15 +92,17 @@ private:
DeclarationNameInfo DirectiveName;
Scope *CurScope;
SourceLocation ConstructLoc;
+ bool OrderedRegion;
+ SourceLocation InnerTeamsRegionLoc;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified),
Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope),
- ConstructLoc(Loc) {}
+ ConstructLoc(Loc), OrderedRegion(false), InnerTeamsRegionLoc() {}
SharingMapTy()
: SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified),
Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr),
- ConstructLoc() {}
+ ConstructLoc(), OrderedRegion(false), InnerTeamsRegionLoc() {}
};
typedef SmallVector<SharingMapTy, 64> StackTy;
@@ -194,13 +197,42 @@ public:
return isOpenMPThreadPrivate(DVar.CKind);
}
+ /// \brief Marks current region as ordered (it has an 'ordered' clause).
+ void setOrderedRegion(bool IsOrdered = true) {
+ Stack.back().OrderedRegion = IsOrdered;
+ }
+ /// \brief Returns true, if parent region is ordered (has associated
+ /// 'ordered' clause), false - otherwise.
+ bool isParentOrderedRegion() const {
+ if (Stack.size() > 2)
+ return Stack[Stack.size() - 2].OrderedRegion;
+ return false;
+ }
+
+ /// \brief Marks current target region as one with closely nested teams
+ /// region.
+ void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) {
+ if (Stack.size() > 2)
+ Stack[Stack.size() - 2].InnerTeamsRegionLoc = TeamsRegionLoc;
+ }
+ /// \brief Returns true, if current region has closely nested teams region.
+ bool hasInnerTeamsRegion() const {
+ return getInnerTeamsRegionLoc().isValid();
+ }
+ /// \brief Returns location of the nested teams region (if any).
+ SourceLocation getInnerTeamsRegionLoc() const {
+ if (Stack.size() > 1)
+ return Stack.back().InnerTeamsRegionLoc;
+ return SourceLocation();
+ }
+
Scope *getCurScope() const { return Stack.back().CurScope; }
Scope *getCurScope() { return Stack.back().CurScope; }
SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; }
};
bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) {
return isOpenMPParallelDirective(DKind) || DKind == OMPD_task ||
- DKind == OMPD_unknown;
+ isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown;
}
} // namespace
@@ -213,7 +245,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// File-scope or namespace-scope variables referenced in called routines
// in the region are shared unless they appear in a threadprivate
// directive.
- if (!D->isFunctionOrMethodVarDecl())
+ if (!D->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(D))
DVar.CKind = OMPC_shared;
// OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced
@@ -263,7 +295,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// In a parallel construct, if no default clause is present, these
// variables are shared.
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
- if (isOpenMPParallelDirective(DVar.DKind)) {
+ if (isOpenMPParallelDirective(DVar.DKind) ||
+ isOpenMPTeamsDirective(DVar.DKind)) {
DVar.CKind = OMPC_shared;
return DVar;
}
@@ -358,7 +391,8 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.1]
// Variables appearing in threadprivate directives are threadprivate.
- if (D->getTLSKind() != VarDecl::TLS_None) {
+ if (D->getTLSKind() != VarDecl::TLS_None ||
+ D->getStorageClass() == SC_Register) {
DVar.CKind = OMPC_threadprivate;
return DVar;
}
@@ -380,8 +414,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) {
StartI = std::next(StartI);
}
if (!isParallelOrTaskRegion(Kind)) {
- if (isOpenMPLocal(D, StartI) && D->isLocalVarDecl() &&
- (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) {
+ if (isOpenMPLocal(D, StartI) &&
+ ((D->isLocalVarDecl() && (D->getStorageClass() == SC_Auto ||
+ D->getStorageClass() == SC_None)) ||
+ isa<ParmVarDecl>(D))) {
DVar.CKind = OMPC_private;
return DVar;
}
@@ -516,6 +552,19 @@ void Sema::InitDataSharingAttributesStack() {
#define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack)
+bool Sema::IsOpenMPCapturedVar(VarDecl *VD) {
+ assert(LangOpts.OpenMP && "OpenMP is not allowed");
+ if (DSAStack->getCurrentDirective() != OMPD_unknown) {
+ auto DVarPrivate = DSAStack->getTopDSA(VD, /*FromParent=*/false);
+ if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
+ return true;
+ DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(),
+ /*FromParent=*/false);
+ return DVarPrivate.CKind != OMPC_unknown;
+ }
+ return false;
+}
+
void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
@@ -612,10 +661,9 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
VarDecl *VD;
if (!Lookup.isSingleResult()) {
- VarDeclFilterCCC Validator(*this);
- if (TypoCorrection Corrected =
- CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, Validator,
- CTK_ErrorRecovery)) {
+ if (TypoCorrection Corrected = CorrectTypo(
+ Id, LookupOrdinaryName, CurScope, nullptr,
+ llvm::make_unique<VarDeclFilterCCC>(*this), CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(Lookup.empty()
? diag::err_undeclared_var_use_suggest
@@ -794,8 +842,10 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
}
// Check if this is a TLS variable.
- if (VD->getTLSKind()) {
- Diag(ILoc, diag::err_omp_var_thread_local) << VD;
+ if (VD->getTLSKind() != VarDecl::TLS_None ||
+ VD->getStorageClass() == SC_Register) {
+ Diag(ILoc, diag::err_omp_var_thread_local)
+ << VD << ((VD->getTLSKind() != VarDecl::TLS_None) ? 0 : 1);
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -814,6 +864,10 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
Vars.push_back(RefExpr);
DSAStack->addDSA(VD, DE, OMPC_threadprivate);
+ VD->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
+ Context, SourceRange(Loc, Loc)));
+ if (auto *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPThreadPrivate(VD);
}
OMPThreadPrivateDecl *D = nullptr;
if (!Vars.empty()) {
@@ -918,7 +972,8 @@ public:
DVar = Stack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction),
[](OpenMPDirectiveKind K) -> bool {
return isOpenMPParallelDirective(K) ||
- isOpenMPWorksharingDirective(K);
+ isOpenMPWorksharingDirective(K) ||
+ isOpenMPTeamsDirective(K);
},
false);
if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) {
@@ -993,6 +1048,14 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Params);
break;
}
+ case OMPD_for_simd: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
case OMPD_sections: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
@@ -1045,6 +1108,18 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Params);
break;
}
+ case OMPD_parallel_for_simd: {
+ QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
+ QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty);
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
case OMPD_parallel_sections: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
@@ -1061,7 +1136,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Params);
break;
}
- case OMPD_taskyield: {
+ case OMPD_ordered: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
@@ -1069,7 +1144,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Params);
break;
}
- case OMPD_barrier: {
+ case OMPD_atomic: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
@@ -1077,7 +1152,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Params);
break;
}
- case OMPD_taskwait: {
+ case OMPD_target: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
@@ -1085,8 +1160,12 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Params);
break;
}
- case OMPD_flush: {
+ case OMPD_teams: {
+ QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
+ QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty);
Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
@@ -1094,6 +1173,10 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
break;
}
case OMPD_threadprivate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_flush:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -1110,6 +1193,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// +------------------+-----------------+------------------------------------+
// | parallel | parallel | * |
// | parallel | for | * |
+ // | parallel | for simd | * |
// | parallel | master | * |
// | parallel | critical | * |
// | parallel | simd | * |
@@ -1117,15 +1201,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | parallel | section | + |
// | parallel | single | * |
// | parallel | parallel for | * |
+ // | parallel |parallel for simd| * |
// | parallel |parallel sections| * |
// | parallel | task | * |
// | parallel | taskyield | * |
// | parallel | barrier | * |
// | parallel | taskwait | * |
// | parallel | flush | * |
+ // | parallel | ordered | + |
+ // | parallel | atomic | * |
+ // | parallel | target | * |
+ // | parallel | teams | + |
// +------------------+-----------------+------------------------------------+
// | for | parallel | * |
// | for | for | + |
+ // | for | for simd | + |
// | for | master | + |
// | for | critical | * |
// | for | simd | * |
@@ -1133,15 +1223,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | for | section | + |
// | for | single | + |
// | for | parallel for | * |
+ // | for |parallel for simd| * |
// | for |parallel sections| * |
// | for | task | * |
// | for | taskyield | * |
// | for | barrier | + |
// | for | taskwait | * |
// | for | flush | * |
+ // | for | ordered | * (if construct is ordered) |
+ // | for | atomic | * |
+ // | for | target | * |
+ // | for | teams | + |
// +------------------+-----------------+------------------------------------+
// | master | parallel | * |
// | master | for | + |
+ // | master | for simd | + |
// | master | master | * |
// | master | critical | * |
// | master | simd | * |
@@ -1149,30 +1245,42 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | master | section | + |
// | master | single | + |
// | master | parallel for | * |
+ // | master |parallel for simd| * |
// | master |parallel sections| * |
// | master | task | * |
// | master | taskyield | * |
// | master | barrier | + |
// | master | taskwait | * |
// | master | flush | * |
+ // | master | ordered | + |
+ // | master | atomic | * |
+ // | master | target | * |
+ // | master | teams | + |
// +------------------+-----------------+------------------------------------+
// | critical | parallel | * |
// | critical | for | + |
+ // | critical | for simd | + |
// | critical | master | * |
- // | critical | critical | * (should have dirrerent names) |
+ // | critical | critical | * (should have different names) |
// | critical | simd | * |
// | critical | sections | + |
// | critical | section | + |
// | critical | single | + |
// | critical | parallel for | * |
+ // | critical |parallel for simd| * |
// | critical |parallel sections| * |
// | critical | task | * |
// | critical | taskyield | * |
// | critical | barrier | + |
// | critical | taskwait | * |
+ // | critical | ordered | + |
+ // | critical | atomic | * |
+ // | critical | target | * |
+ // | critical | teams | + |
// +------------------+-----------------+------------------------------------+
// | simd | parallel | |
// | simd | for | |
+ // | simd | for simd | |
// | simd | master | |
// | simd | critical | |
// | simd | simd | |
@@ -1180,15 +1288,65 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | simd | section | |
// | simd | single | |
// | simd | parallel for | |
+ // | simd |parallel for simd| |
// | simd |parallel sections| |
// | simd | task | |
// | simd | taskyield | |
// | simd | barrier | |
// | simd | taskwait | |
// | simd | flush | |
+ // | simd | ordered | |
+ // | simd | atomic | |
+ // | simd | target | |
+ // | simd | teams | |
+ // +------------------+-----------------+------------------------------------+
+ // | for simd | parallel | |
+ // | for simd | for | |
+ // | for simd | for simd | |
+ // | for simd | master | |
+ // | for simd | critical | |
+ // | for simd | simd | |
+ // | for simd | sections | |
+ // | for simd | section | |
+ // | for simd | single | |
+ // | for simd | parallel for | |
+ // | for simd |parallel for simd| |
+ // | for simd |parallel sections| |
+ // | for simd | task | |
+ // | for simd | taskyield | |
+ // | for simd | barrier | |
+ // | for simd | taskwait | |
+ // | for simd | flush | |
+ // | for simd | ordered | |
+ // | for simd | atomic | |
+ // | for simd | target | |
+ // | for simd | teams | |
+ // +------------------+-----------------+------------------------------------+
+ // | parallel for simd| parallel | |
+ // | parallel for simd| for | |
+ // | parallel for simd| for simd | |
+ // | parallel for simd| master | |
+ // | parallel for simd| critical | |
+ // | parallel for simd| simd | |
+ // | parallel for simd| sections | |
+ // | parallel for simd| section | |
+ // | parallel for simd| single | |
+ // | parallel for simd| parallel for | |
+ // | parallel for simd|parallel for simd| |
+ // | parallel for simd|parallel sections| |
+ // | parallel for simd| task | |
+ // | parallel for simd| taskyield | |
+ // | parallel for simd| barrier | |
+ // | parallel for simd| taskwait | |
+ // | parallel for simd| flush | |
+ // | parallel for simd| ordered | |
+ // | parallel for simd| atomic | |
+ // | parallel for simd| target | |
+ // | parallel for simd| teams | |
// +------------------+-----------------+------------------------------------+
// | sections | parallel | * |
// | sections | for | + |
+ // | sections | for simd | + |
// | sections | master | + |
// | sections | critical | * |
// | sections | simd | * |
@@ -1196,15 +1354,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | sections | section | * |
// | sections | single | + |
// | sections | parallel for | * |
+ // | sections |parallel for simd| * |
// | sections |parallel sections| * |
// | sections | task | * |
// | sections | taskyield | * |
// | sections | barrier | + |
// | sections | taskwait | * |
// | sections | flush | * |
+ // | sections | ordered | + |
+ // | sections | atomic | * |
+ // | sections | target | * |
+ // | sections | teams | + |
// +------------------+-----------------+------------------------------------+
// | section | parallel | * |
// | section | for | + |
+ // | section | for simd | + |
// | section | master | + |
// | section | critical | * |
// | section | simd | * |
@@ -1212,15 +1376,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | section | section | + |
// | section | single | + |
// | section | parallel for | * |
+ // | section |parallel for simd| * |
// | section |parallel sections| * |
// | section | task | * |
// | section | taskyield | * |
// | section | barrier | + |
// | section | taskwait | * |
// | section | flush | * |
+ // | section | ordered | + |
+ // | section | atomic | * |
+ // | section | target | * |
+ // | section | teams | + |
// +------------------+-----------------+------------------------------------+
// | single | parallel | * |
// | single | for | + |
+ // | single | for simd | + |
// | single | master | + |
// | single | critical | * |
// | single | simd | * |
@@ -1228,15 +1398,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | single | section | + |
// | single | single | + |
// | single | parallel for | * |
+ // | single |parallel for simd| * |
// | single |parallel sections| * |
// | single | task | * |
// | single | taskyield | * |
// | single | barrier | + |
// | single | taskwait | * |
// | single | flush | * |
+ // | single | ordered | + |
+ // | single | atomic | * |
+ // | single | target | * |
+ // | single | teams | + |
// +------------------+-----------------+------------------------------------+
// | parallel for | parallel | * |
// | parallel for | for | + |
+ // | parallel for | for simd | + |
// | parallel for | master | + |
// | parallel for | critical | * |
// | parallel for | simd | * |
@@ -1244,15 +1420,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | parallel for | section | + |
// | parallel for | single | + |
// | parallel for | parallel for | * |
+ // | parallel for |parallel for simd| * |
// | parallel for |parallel sections| * |
// | parallel for | task | * |
// | parallel for | taskyield | * |
// | parallel for | barrier | + |
// | parallel for | taskwait | * |
// | parallel for | flush | * |
+ // | parallel for | ordered | * (if construct is ordered) |
+ // | parallel for | atomic | * |
+ // | parallel for | target | * |
+ // | parallel for | teams | + |
// +------------------+-----------------+------------------------------------+
// | parallel sections| parallel | * |
// | parallel sections| for | + |
+ // | parallel sections| for simd | + |
// | parallel sections| master | + |
// | parallel sections| critical | + |
// | parallel sections| simd | * |
@@ -1260,15 +1442,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | parallel sections| section | * |
// | parallel sections| single | + |
// | parallel sections| parallel for | * |
+ // | parallel sections|parallel for simd| * |
// | parallel sections|parallel sections| * |
// | parallel sections| task | * |
// | parallel sections| taskyield | * |
// | parallel sections| barrier | + |
// | parallel sections| taskwait | * |
// | parallel sections| flush | * |
+ // | parallel sections| ordered | + |
+ // | parallel sections| atomic | * |
+ // | parallel sections| target | * |
+ // | parallel sections| teams | + |
// +------------------+-----------------+------------------------------------+
// | task | parallel | * |
// | task | for | + |
+ // | task | for simd | + |
// | task | master | + |
// | task | critical | * |
// | task | simd | * |
@@ -1276,24 +1464,128 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | task | section | + |
// | task | single | + |
// | task | parallel for | * |
+ // | task |parallel for simd| * |
// | task |parallel sections| * |
// | task | task | * |
// | task | taskyield | * |
// | task | barrier | + |
// | task | taskwait | * |
// | task | flush | * |
+ // | task | ordered | + |
+ // | task | atomic | * |
+ // | task | target | * |
+ // | task | teams | + |
+ // +------------------+-----------------+------------------------------------+
+ // | ordered | parallel | * |
+ // | ordered | for | + |
+ // | ordered | for simd | + |
+ // | ordered | master | * |
+ // | ordered | critical | * |
+ // | ordered | simd | * |
+ // | ordered | sections | + |
+ // | ordered | section | + |
+ // | ordered | single | + |
+ // | ordered | parallel for | * |
+ // | ordered |parallel for simd| * |
+ // | ordered |parallel sections| * |
+ // | ordered | task | * |
+ // | ordered | taskyield | * |
+ // | ordered | barrier | + |
+ // | ordered | taskwait | * |
+ // | ordered | flush | * |
+ // | ordered | ordered | + |
+ // | ordered | atomic | * |
+ // | ordered | target | * |
+ // | ordered | teams | + |
+ // +------------------+-----------------+------------------------------------+
+ // | atomic | parallel | |
+ // | atomic | for | |
+ // | atomic | for simd | |
+ // | atomic | master | |
+ // | atomic | critical | |
+ // | atomic | simd | |
+ // | atomic | sections | |
+ // | atomic | section | |
+ // | atomic | single | |
+ // | atomic | parallel for | |
+ // | atomic |parallel for simd| |
+ // | atomic |parallel sections| |
+ // | atomic | task | |
+ // | atomic | taskyield | |
+ // | atomic | barrier | |
+ // | atomic | taskwait | |
+ // | atomic | flush | |
+ // | atomic | ordered | |
+ // | atomic | atomic | |
+ // | atomic | target | |
+ // | atomic | teams | |
+ // +------------------+-----------------+------------------------------------+
+ // | target | parallel | * |
+ // | target | for | * |
+ // | target | for simd | * |
+ // | target | master | * |
+ // | target | critical | * |
+ // | target | simd | * |
+ // | target | sections | * |
+ // | target | section | * |
+ // | target | single | * |
+ // | target | parallel for | * |
+ // | target |parallel for simd| * |
+ // | target |parallel sections| * |
+ // | target | task | * |
+ // | target | taskyield | * |
+ // | target | barrier | * |
+ // | target | taskwait | * |
+ // | target | flush | * |
+ // | target | ordered | * |
+ // | target | atomic | * |
+ // | target | target | * |
+ // | target | teams | * |
+ // +------------------+-----------------+------------------------------------+
+ // | teams | parallel | * |
+ // | teams | for | + |
+ // | teams | for simd | + |
+ // | teams | master | + |
+ // | teams | critical | + |
+ // | teams | simd | + |
+ // | teams | sections | + |
+ // | teams | section | + |
+ // | teams | single | + |
+ // | teams | parallel for | * |
+ // | teams |parallel for simd| * |
+ // | teams |parallel sections| * |
+ // | teams | task | + |
+ // | teams | taskyield | + |
+ // | teams | barrier | + |
+ // | teams | taskwait | + |
+ // | teams | flush | + |
+ // | teams | ordered | + |
+ // | teams | atomic | + |
+ // | teams | target | + |
+ // | teams | teams | + |
// +------------------+-----------------+------------------------------------+
if (Stack->getCurScope()) {
auto ParentRegion = Stack->getParentDirective();
bool NestingProhibited = false;
bool CloseNesting = true;
- bool ShouldBeInParallelRegion = false;
+ enum {
+ NoRecommend,
+ ShouldBeInParallelRegion,
+ ShouldBeInOrderedRegion,
+ ShouldBeInTargetRegion
+ } Recommend = NoRecommend;
if (isOpenMPSimdDirective(ParentRegion)) {
// OpenMP [2.16, Nesting of Regions]
// OpenMP constructs may not be nested inside a simd region.
SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_simd);
return true;
}
+ if (ParentRegion == OMPD_atomic) {
+ // OpenMP [2.16, Nesting of Regions]
+ // OpenMP constructs may not be nested inside an atomic region.
+ SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_atomic);
+ return true;
+ }
if (CurrentRegion == OMPD_section) {
// OpenMP [2.7.2, sections Construct, Restrictions]
// Orphaned section directives are prohibited. That is, the section
@@ -1308,10 +1600,14 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
}
return false;
}
+ // Allow some constructs to be orphaned (they could be used in functions,
+ // called from OpenMP regions with the required preconditions).
+ if (ParentRegion == OMPD_unknown)
+ return false;
if (CurrentRegion == OMPD_master) {
// OpenMP [2.16, Nesting of Regions]
// A master region may not be closely nested inside a worksharing,
- // atomic (TODO), or explicit task region.
+ // atomic, or explicit task region.
NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
ParentRegion == OMPD_task;
} else if (CurrentRegion == OMPD_critical && CurrentName.getName()) {
@@ -1346,30 +1642,52 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
} else if (CurrentRegion == OMPD_barrier) {
// OpenMP [2.16, Nesting of Regions]
// A barrier region may not be closely nested inside a worksharing,
- // explicit task, critical, ordered(TODO), atomic(TODO), or master
- // region.
- NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
- ParentRegion == OMPD_task ||
- ParentRegion == OMPD_master ||
- ParentRegion == OMPD_critical;
+ // explicit task, critical, ordered, atomic, or master region.
+ NestingProhibited =
+ isOpenMPWorksharingDirective(ParentRegion) ||
+ ParentRegion == OMPD_task || ParentRegion == OMPD_master ||
+ ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered;
} else if (isOpenMPWorksharingDirective(CurrentRegion) &&
- !isOpenMPParallelDirective(CurrentRegion) &&
- !isOpenMPSimdDirective(CurrentRegion)) {
+ !isOpenMPParallelDirective(CurrentRegion)) {
// OpenMP [2.16, Nesting of Regions]
// A worksharing region may not be closely nested inside a worksharing,
// explicit task, critical, ordered, atomic, or master region.
- // TODO
- NestingProhibited = (isOpenMPWorksharingDirective(ParentRegion) &&
- !isOpenMPSimdDirective(ParentRegion)) ||
+ NestingProhibited =
+ isOpenMPWorksharingDirective(ParentRegion) ||
+ ParentRegion == OMPD_task || ParentRegion == OMPD_master ||
+ ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered;
+ Recommend = ShouldBeInParallelRegion;
+ } else if (CurrentRegion == OMPD_ordered) {
+ // OpenMP [2.16, Nesting of Regions]
+ // An ordered region may not be closely nested inside a critical,
+ // atomic, or explicit task region.
+ // An ordered region must be closely nested inside a loop region (or
+ // parallel loop region) with an ordered clause.
+ NestingProhibited = ParentRegion == OMPD_critical ||
ParentRegion == OMPD_task ||
- ParentRegion == OMPD_master ||
- ParentRegion == OMPD_critical;
- ShouldBeInParallelRegion = true;
+ !Stack->isParentOrderedRegion();
+ Recommend = ShouldBeInOrderedRegion;
+ } else if (isOpenMPTeamsDirective(CurrentRegion)) {
+ // OpenMP [2.16, Nesting of Regions]
+ // If specified, a teams construct must be contained within a target
+ // construct.
+ NestingProhibited = ParentRegion != OMPD_target;
+ Recommend = ShouldBeInTargetRegion;
+ Stack->setParentTeamsRegionLoc(Stack->getConstructLoc());
+ }
+ if (!NestingProhibited && isOpenMPTeamsDirective(ParentRegion)) {
+ // OpenMP [2.16, Nesting of Regions]
+ // distribute, parallel, parallel sections, parallel workshare, and the
+ // parallel loop and parallel loop SIMD constructs are the only OpenMP
+ // constructs that can be closely nested in the teams region.
+ // TODO: add distribute directive.
+ NestingProhibited = !isOpenMPParallelDirective(CurrentRegion);
+ Recommend = ShouldBeInParallelRegion;
}
if (NestingProhibited) {
SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region)
- << CloseNesting << getOpenMPDirectiveName(ParentRegion)
- << ShouldBeInParallelRegion << getOpenMPDirectiveName(CurrentRegion);
+ << CloseNesting << getOpenMPDirectiveName(ParentRegion) << Recommend
+ << getOpenMPDirectiveName(CurrentRegion);
return true;
}
}
@@ -1426,6 +1744,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc,
VarsWithInheritedDSA);
break;
+ case OMPD_for_simd:
+ Res = ActOnOpenMPForSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc, VarsWithInheritedDSA);
+ break;
case OMPD_sections:
Res = ActOnOpenMPSectionsDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
@@ -1453,6 +1775,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
Res = ActOnOpenMPParallelForDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
break;
+ case OMPD_parallel_for_simd:
+ Res = ActOnOpenMPParallelForSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ break;
case OMPD_parallel_sections:
Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt,
StartLoc, EndLoc);
@@ -1487,6 +1813,23 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
"No associated statement allowed for 'omp flush' directive");
Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc);
break;
+ case OMPD_ordered:
+ assert(ClausesWithImplicit.empty() &&
+ "No clauses are allowed for 'omp ordered' directive");
+ Res = ActOnOpenMPOrderedDirective(AStmt, StartLoc, EndLoc);
+ break;
+ case OMPD_atomic:
+ Res = ActOnOpenMPAtomicDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc);
+ break;
+ case OMPD_teams:
+ Res =
+ ActOnOpenMPTeamsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc);
+ break;
+ case OMPD_target:
+ Res = ActOnOpenMPTargetDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc);
+ break;
case OMPD_threadprivate:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
@@ -1535,10 +1878,16 @@ class OpenMPIterationSpaceChecker {
SourceLocation DefaultLoc;
/// \brief A location for diagnostics (when increment is not compatible).
SourceLocation ConditionLoc;
+ /// \brief A source location for referring to loop init later.
+ SourceRange InitSrcRange;
/// \brief A source location for referring to condition later.
SourceRange ConditionSrcRange;
+ /// \brief A source location for referring to increment later.
+ SourceRange IncrementSrcRange;
/// \brief Loop variable.
VarDecl *Var;
+ /// \brief Reference to loop variable.
+ DeclRefExpr *VarRef;
/// \brief Lower bound (initializer for the var).
Expr *LB;
/// \brief Upper bound.
@@ -1559,9 +1908,10 @@ class OpenMPIterationSpaceChecker {
public:
OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc)
: SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc),
- ConditionSrcRange(SourceRange()), Var(nullptr), LB(nullptr),
- UB(nullptr), Step(nullptr), TestIsLessOp(false), TestIsStrictOp(false),
- SubtractStep(false) {}
+ InitSrcRange(SourceRange()), ConditionSrcRange(SourceRange()),
+ IncrementSrcRange(SourceRange()), Var(nullptr), VarRef(nullptr),
+ LB(nullptr), UB(nullptr), Step(nullptr), TestIsLessOp(false),
+ TestIsStrictOp(false), SubtractStep(false) {}
/// \brief Check init-expr for canonical loop form and save loop counter
/// variable - #Var and its initialization value - #LB.
bool CheckInit(Stmt *S);
@@ -1573,6 +1923,24 @@ public:
bool CheckInc(Expr *S);
/// \brief Return the loop counter variable.
VarDecl *GetLoopVar() const { return Var; }
+ /// \brief Return the reference expression to loop counter variable.
+ DeclRefExpr *GetLoopVarRefExpr() const { return VarRef; }
+ /// \brief Source range of the loop init.
+ SourceRange GetInitSrcRange() const { return InitSrcRange; }
+ /// \brief Source range of the loop condition.
+ SourceRange GetConditionSrcRange() const { return ConditionSrcRange; }
+ /// \brief Source range of the loop increment.
+ SourceRange GetIncrementSrcRange() const { return IncrementSrcRange; }
+ /// \brief True if the step should be subtracted.
+ bool ShouldSubtractStep() const { return SubtractStep; }
+ /// \brief Build the expression to calculate the number of iterations.
+ Expr *BuildNumIterations(Scope *S, const bool LimitedType) const;
+ /// \brief Build reference expression to the counter be used for codegen.
+ Expr *BuildCounterVar() const;
+ /// \brief Build initization of the counter be used for codegen.
+ Expr *BuildCounterInit() const;
+ /// \brief Build step of the counter be used for codegen.
+ Expr *BuildCounterStep() const;
/// \brief Return true if any expression is dependent.
bool Dependent() const;
@@ -1581,7 +1949,7 @@ private:
/// expression.
bool CheckIncRHS(Expr *RHS);
/// \brief Helper to set loop counter variable and its initializer.
- bool SetVarAndLB(VarDecl *NewVar, Expr *NewLB);
+ bool SetVarAndLB(VarDecl *NewVar, DeclRefExpr *NewVarRefExpr, Expr *NewLB);
/// \brief Helper to set upper bound.
bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, const SourceRange &SR,
const SourceLocation &SL);
@@ -1598,13 +1966,16 @@ bool OpenMPIterationSpaceChecker::Dependent() const {
(UB && UB->isValueDependent()) || (Step && Step->isValueDependent());
}
-bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, Expr *NewLB) {
+bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar,
+ DeclRefExpr *NewVarRefExpr,
+ Expr *NewLB) {
// State consistency checking to ensure correct usage.
- assert(Var == nullptr && LB == nullptr && UB == nullptr && Step == nullptr &&
- !TestIsLessOp && !TestIsStrictOp);
+ assert(Var == nullptr && LB == nullptr && VarRef == nullptr &&
+ UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
if (!NewVar || !NewLB)
return true;
Var = NewVar;
+ VarRef = NewVarRefExpr;
LB = NewLB;
return false;
}
@@ -1655,10 +2026,12 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) {
bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation();
bool IsConstNeg =
IsConstant && Result.isSigned() && (Subtract != Result.isNegative());
+ bool IsConstPos =
+ IsConstant && Result.isSigned() && (Subtract == Result.isNegative());
bool IsConstZero = IsConstant && !Result.getBoolValue();
if (UB && (IsConstZero ||
(TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract))
- : (!IsConstNeg || (IsUnsigned && !Subtract))))) {
+ : (IsConstPos || (IsUnsigned && !Subtract))))) {
SemaRef.Diag(NewStep->getExprLoc(),
diag::err_omp_loop_incr_not_compatible)
<< Var << TestIsLessOp << NewStep->getSourceRange();
@@ -1667,6 +2040,11 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) {
<< TestIsLessOp << ConditionSrcRange;
return true;
}
+ if (TestIsLessOp == Subtract) {
+ NewStep = SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus,
+ NewStep).get();
+ Subtract = !Subtract;
+ }
}
Step = NewStep;
@@ -1687,12 +2065,14 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) {
SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init);
return true;
}
+ InitSrcRange = S->getSourceRange();
if (Expr *E = dyn_cast<Expr>(S))
S = E->IgnoreParens();
if (auto BO = dyn_cast<BinaryOperator>(S)) {
if (BO->getOpcode() == BO_Assign)
if (auto DRE = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens()))
- return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), BO->getLHS());
+ return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE,
+ BO->getRHS());
} else if (auto DS = dyn_cast<DeclStmt>(S)) {
if (DS->isSingleDecl()) {
if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) {
@@ -1702,14 +2082,15 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) {
SemaRef.Diag(S->getLocStart(),
diag::ext_omp_loop_not_canonical_init)
<< S->getSourceRange();
- return SetVarAndLB(Var, Var->getInit());
+ return SetVarAndLB(Var, nullptr, Var->getInit());
}
}
}
} else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S))
if (CE->getOperator() == OO_Equal)
if (auto DRE = dyn_cast<DeclRefExpr>(CE->getArg(0)))
- return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), CE->getArg(1));
+ return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE,
+ CE->getArg(1));
SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init)
<< S->getSourceRange();
@@ -1833,6 +2214,7 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) {
SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var;
return true;
}
+ IncrementSrcRange = S->getSourceRange();
S = S->IgnoreParens();
if (auto UO = dyn_cast<UnaryOperator>(S)) {
if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var)
@@ -1882,6 +2264,115 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) {
<< S->getSourceRange() << Var;
return true;
}
+
+/// \brief Build the expression to calculate the number of iterations.
+Expr *
+OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S,
+ const bool LimitedType) const {
+ ExprResult Diff;
+ if (Var->getType()->isIntegerType() || Var->getType()->isPointerType() ||
+ SemaRef.getLangOpts().CPlusPlus) {
+ // Upper - Lower
+ Expr *Upper = TestIsLessOp ? UB : LB;
+ Expr *Lower = TestIsLessOp ? LB : UB;
+
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
+
+ if (!Diff.isUsable() && Var->getType()->getAsCXXRecordDecl()) {
+ // BuildBinOp already emitted error, this one is to point user to upper
+ // and lower bound, and to tell what is passed to 'operator-'.
+ SemaRef.Diag(Upper->getLocStart(), diag::err_omp_loop_diff_cxx)
+ << Upper->getSourceRange() << Lower->getSourceRange();
+ return nullptr;
+ }
+ }
+
+ if (!Diff.isUsable())
+ return nullptr;
+
+ // Upper - Lower [- 1]
+ if (TestIsStrictOp)
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Sub, Diff.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ if (!Diff.isUsable())
+ return nullptr;
+
+ // Upper - Lower [- 1] + Step
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(),
+ Step->IgnoreImplicit());
+ if (!Diff.isUsable())
+ return nullptr;
+
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
+ return nullptr;
+
+ // (Upper - Lower [- 1] + Step) / Step
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(),
+ Step->IgnoreImplicit());
+ if (!Diff.isUsable())
+ return nullptr;
+
+ // OpenMP runtime requires 32-bit or 64-bit loop variables.
+ if (LimitedType) {
+ auto &C = SemaRef.Context;
+ QualType Type = Diff.get()->getType();
+ unsigned NewSize = (C.getTypeSize(Type) > 32) ? 64 : 32;
+ if (NewSize != C.getTypeSize(Type)) {
+ if (NewSize < C.getTypeSize(Type)) {
+ assert(NewSize == 64 && "incorrect loop var size");
+ SemaRef.Diag(DefaultLoc, diag::warn_omp_loop_64_bit_var)
+ << InitSrcRange << ConditionSrcRange;
+ }
+ QualType NewType = C.getIntTypeForBitwidth(
+ NewSize, Type->hasSignedIntegerRepresentation());
+ Diff = SemaRef.PerformImplicitConversion(Diff.get(), NewType,
+ Sema::AA_Converting, true);
+ if (!Diff.isUsable())
+ return nullptr;
+ }
+ }
+
+ return Diff.get();
+}
+
+/// \brief Build reference expression to the counter be used for codegen.
+Expr *OpenMPIterationSpaceChecker::BuildCounterVar() const {
+ return DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
+ GetIncrementSrcRange().getBegin(), Var, false,
+ DefaultLoc, Var->getType(), VK_LValue);
+}
+
+/// \brief Build initization of the counter be used for codegen.
+Expr *OpenMPIterationSpaceChecker::BuildCounterInit() const { return LB; }
+
+/// \brief Build step of the counter be used for codegen.
+Expr *OpenMPIterationSpaceChecker::BuildCounterStep() const { return Step; }
+
+/// \brief Iteration space of a single for loop.
+struct LoopIterationSpace {
+ /// \brief This expression calculates the number of iterations in the loop.
+ /// It is always possible to calculate it before starting the loop.
+ Expr *NumIterations;
+ /// \brief The loop counter variable.
+ Expr *CounterVar;
+ /// \brief This is initializer for the initial value of #CounterVar.
+ Expr *CounterInit;
+ /// \brief This is step for the #CounterVar used to generate its update:
+ /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration.
+ Expr *CounterStep;
+ /// \brief Should step be subtracted?
+ bool Subtract;
+ /// \brief Source range of the loop init.
+ SourceRange InitSrcRange;
+ /// \brief Source range of the loop condition.
+ SourceRange CondSrcRange;
+ /// \brief Source range of the loop increment.
+ SourceRange IncSrcRange;
+};
+
} // namespace
/// \brief Called on a for stmt to check and extract its iteration space
@@ -1890,7 +2381,8 @@ static bool CheckOpenMPIterationSpace(
OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA,
unsigned CurrentNestedLoopCount, unsigned NestedLoopCount,
Expr *NestedLoopCountExpr,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA,
+ LoopIterationSpace &ResultIterSpace) {
// OpenMP [2.6, Canonical Loop Form]
// for (init-expr; test-expr; incr-expr) structured-block
auto For = dyn_cast_or_null<ForStmt>(S);
@@ -1943,8 +2435,7 @@ static bool CheckOpenMPIterationSpace(
// that is the increment of the associated for-loop.
// Exclude loop var from the list of variables with implicitly defined data
// sharing attributes.
- while (VarsWithImplicitDSA.count(Var) > 0)
- VarsWithImplicitDSA.erase(Var);
+ VarsWithImplicitDSA.erase(Var);
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in
// a Construct, C/C++].
@@ -1954,25 +2445,40 @@ static bool CheckOpenMPIterationSpace(
// The loop iteration variable(s) in the associated for-loop(s) of a for or
// parallel for construct may be listed in a private or lastprivate clause.
DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var, false);
+ auto LoopVarRefExpr = ISC.GetLoopVarRefExpr();
+ // If LoopVarRefExpr is nullptr it means the corresponding loop variable is
+ // declared in the loop and it is predetermined as a private.
auto PredeterminedCKind =
isOpenMPSimdDirective(DKind)
? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
: OMPC_private;
if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
DVar.CKind != PredeterminedCKind) ||
- (isOpenMPWorksharingDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
+ (isOpenMPWorksharingDirective(DKind) && !isOpenMPSimdDirective(DKind) &&
+ DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private &&
+ DVar.CKind != OMPC_lastprivate)) &&
(DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa)
<< getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(PredeterminedCKind);
ReportOriginalDSA(SemaRef, &DSA, Var, DVar, true);
HasErrors = true;
- } else {
+ } else if (LoopVarRefExpr != nullptr) {
// Make the loop iteration variable private (for worksharing constructs),
// linear (for simd directives with the only one associated loop) or
// lastprivate (for simd directives with several collapsed loops).
- DSA.addDSA(Var, nullptr, PredeterminedCKind);
+ // FIXME: the next check and error message must be removed once the
+ // capturing of global variables in loops is fixed.
+ if (DVar.CKind == OMPC_unknown)
+ DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(),
+ /*FromParent=*/false);
+ if (!Var->hasLocalStorage() && DVar.CKind == OMPC_unknown) {
+ SemaRef.Diag(Init->getLocStart(), diag::err_omp_global_loop_var_dsa)
+ << getOpenMPClauseName(PredeterminedCKind)
+ << getOpenMPDirectiveName(DKind);
+ HasErrors = true;
+ } else
+ DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind);
}
assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
@@ -1983,35 +2489,97 @@ static bool CheckOpenMPIterationSpace(
// Check incr-expr.
HasErrors |= ISC.CheckInc(For->getInc());
- if (ISC.Dependent())
+ if (ISC.Dependent() || SemaRef.CurContext->isDependentContext() || HasErrors)
return HasErrors;
- // FIXME: Build loop's iteration space representation.
+ // Build the loop's iteration space representation.
+ ResultIterSpace.NumIterations = ISC.BuildNumIterations(
+ DSA.getCurScope(), /* LimitedType */ isOpenMPWorksharingDirective(DKind));
+ ResultIterSpace.CounterVar = ISC.BuildCounterVar();
+ ResultIterSpace.CounterInit = ISC.BuildCounterInit();
+ ResultIterSpace.CounterStep = ISC.BuildCounterStep();
+ ResultIterSpace.InitSrcRange = ISC.GetInitSrcRange();
+ ResultIterSpace.CondSrcRange = ISC.GetConditionSrcRange();
+ ResultIterSpace.IncSrcRange = ISC.GetIncrementSrcRange();
+ ResultIterSpace.Subtract = ISC.ShouldSubtractStep();
+
+ HasErrors |= (ResultIterSpace.NumIterations == nullptr ||
+ ResultIterSpace.CounterVar == nullptr ||
+ ResultIterSpace.CounterInit == nullptr ||
+ ResultIterSpace.CounterStep == nullptr);
+
return HasErrors;
}
-/// \brief A helper routine to skip no-op (attributed, compound) stmts get the
-/// next nested for loop. If \a IgnoreCaptured is true, it skips captured stmt
-/// to get the first for loop.
-static Stmt *IgnoreContainerStmts(Stmt *S, bool IgnoreCaptured) {
- if (IgnoreCaptured)
- if (auto CapS = dyn_cast_or_null<CapturedStmt>(S))
- S = CapS->getCapturedStmt();
- // OpenMP [2.8.1, simd construct, Restrictions]
- // All loops associated with the construct must be perfectly nested; that is,
- // there must be no intervening code nor any OpenMP directive between any two
- // loops.
- while (true) {
- if (auto AS = dyn_cast_or_null<AttributedStmt>(S))
- S = AS->getSubStmt();
- else if (auto CS = dyn_cast_or_null<CompoundStmt>(S)) {
- if (CS->size() != 1)
- break;
- S = CS->body_back();
- } else
- break;
- }
- return S;
+/// \brief Build a variable declaration for OpenMP loop iteration variable.
+static VarDecl *BuildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type,
+ StringRef Name) {
+ DeclContext *DC = SemaRef.CurContext;
+ IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
+ TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc);
+ VarDecl *Decl =
+ VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, TInfo, SC_None);
+ Decl->setImplicit();
+ return Decl;
+}
+
+/// \brief Build 'VarRef = Start + Iter * Step'.
+static ExprResult BuildCounterUpdate(Sema &SemaRef, Scope *S,
+ SourceLocation Loc, ExprResult VarRef,
+ ExprResult Start, ExprResult Iter,
+ ExprResult Step, bool Subtract) {
+ // Add parentheses (for debugging purposes only).
+ Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get());
+ if (!VarRef.isUsable() || !Start.isUsable() || !Iter.isUsable() ||
+ !Step.isUsable())
+ return ExprError();
+
+ ExprResult Update = SemaRef.BuildBinOp(S, Loc, BO_Mul, Iter.get(),
+ Step.get()->IgnoreImplicit());
+ if (!Update.isUsable())
+ return ExprError();
+
+ // Build 'VarRef = Start + Iter * Step'.
+ Update = SemaRef.BuildBinOp(S, Loc, (Subtract ? BO_Sub : BO_Add),
+ Start.get()->IgnoreImplicit(), Update.get());
+ if (!Update.isUsable())
+ return ExprError();
+
+ Update = SemaRef.PerformImplicitConversion(
+ Update.get(), VarRef.get()->getType(), Sema::AA_Converting, true);
+ if (!Update.isUsable())
+ return ExprError();
+
+ Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get());
+ return Update;
+}
+
+/// \brief Convert integer expression \a E to make it have at least \a Bits
+/// bits.
+static ExprResult WidenIterationCount(unsigned Bits, Expr *E,
+ Sema &SemaRef) {
+ if (E == nullptr)
+ return ExprError();
+ auto &C = SemaRef.Context;
+ QualType OldType = E->getType();
+ unsigned HasBits = C.getTypeSize(OldType);
+ if (HasBits >= Bits)
+ return ExprResult(E);
+ // OK to convert to signed, because new type has more bits than old.
+ QualType NewType = C.getIntTypeForBitwidth(Bits, /* Signed */ true);
+ return SemaRef.PerformImplicitConversion(E, NewType, Sema::AA_Converting,
+ true);
+}
+
+/// \brief Check if the given expression \a E is a constant integer that fits
+/// into \a Bits bits.
+static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) {
+ if (E == nullptr)
+ return false;
+ llvm::APSInt Result;
+ if (E->isIntegerConstantExpr(Result, SemaRef.Context))
+ return Signed ? Result.isSignedIntN(Bits) : Result.isIntN(Bits);
+ return false;
}
/// \brief Called on a for stmt to check itself and nested loops (if any).
@@ -2020,7 +2588,8 @@ static Stmt *IgnoreContainerStmts(Stmt *S, bool IgnoreCaptured) {
static unsigned
CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,
Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA,
+ OMPLoopDirective::HelperExprs &Built) {
unsigned NestedLoopCount = 1;
if (NestedLoopCountExpr) {
// Found 'collapse' clause - calculate collapse number.
@@ -2030,18 +2599,336 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,
}
// This is helper routine for loop directives (e.g., 'for', 'simd',
// 'for simd', etc.).
- Stmt *CurStmt = IgnoreContainerStmts(AStmt, true);
+ SmallVector<LoopIterationSpace, 4> IterSpaces;
+ IterSpaces.resize(NestedLoopCount);
+ Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true);
for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt,
NestedLoopCount, NestedLoopCountExpr,
- VarsWithImplicitDSA))
+ VarsWithImplicitDSA, IterSpaces[Cnt]))
return 0;
// Move on to the next nested for loop, or to the loop body.
- CurStmt = IgnoreContainerStmts(cast<ForStmt>(CurStmt)->getBody(), false);
+ // OpenMP [2.8.1, simd construct, Restrictions]
+ // All loops associated with the construct must be perfectly nested; that
+ // is, there must be no intervening code nor any OpenMP directive between
+ // any two loops.
+ CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
+ }
+
+ Built.clear(/* size */ NestedLoopCount);
+
+ if (SemaRef.CurContext->isDependentContext())
+ return NestedLoopCount;
+
+ // An example of what is generated for the following code:
+ //
+ // #pragma omp simd collapse(2)
+ // for (i = 0; i < NI; ++i)
+ // for (j = J0; j < NJ; j+=2) {
+ // <loop body>
+ // }
+ //
+ // We generate the code below.
+ // Note: the loop body may be outlined in CodeGen.
+ // Note: some counters may be C++ classes, operator- is used to find number of
+ // iterations and operator+= to calculate counter value.
+ // Note: decltype(NumIterations) must be integer type (in 'omp for', only i32
+ // or i64 is currently supported).
+ //
+ // #define NumIterations (NI * ((NJ - J0 - 1 + 2) / 2))
+ // for (int[32|64]_t IV = 0; IV < NumIterations; ++IV ) {
+ // .local.i = IV / ((NJ - J0 - 1 + 2) / 2);
+ // .local.j = J0 + (IV % ((NJ - J0 - 1 + 2) / 2)) * 2;
+ // // similar updates for vars in clauses (e.g. 'linear')
+ // <loop body (using local i and j)>
+ // }
+ // i = NI; // assign final values of counters
+ // j = NJ;
+ //
+
+ // Last iteration number is (I1 * I2 * ... In) - 1, where I1, I2 ... In are
+ // the iteration counts of the collapsed for loops.
+ auto N0 = IterSpaces[0].NumIterations;
+ ExprResult LastIteration32 = WidenIterationCount(32 /* Bits */, N0, SemaRef);
+ ExprResult LastIteration64 = WidenIterationCount(64 /* Bits */, N0, SemaRef);
+
+ if (!LastIteration32.isUsable() || !LastIteration64.isUsable())
+ return NestedLoopCount;
+
+ auto &C = SemaRef.Context;
+ bool AllCountsNeedLessThan32Bits = C.getTypeSize(N0->getType()) < 32;
+
+ Scope *CurScope = DSA.getCurScope();
+ for (unsigned Cnt = 1; Cnt < NestedLoopCount; ++Cnt) {
+ auto N = IterSpaces[Cnt].NumIterations;
+ AllCountsNeedLessThan32Bits &= C.getTypeSize(N->getType()) < 32;
+ if (LastIteration32.isUsable())
+ LastIteration32 = SemaRef.BuildBinOp(CurScope, SourceLocation(), BO_Mul,
+ LastIteration32.get(), N);
+ if (LastIteration64.isUsable())
+ LastIteration64 = SemaRef.BuildBinOp(CurScope, SourceLocation(), BO_Mul,
+ LastIteration64.get(), N);
+ }
+
+ // Choose either the 32-bit or 64-bit version.
+ ExprResult LastIteration = LastIteration64;
+ if (LastIteration32.isUsable() &&
+ C.getTypeSize(LastIteration32.get()->getType()) == 32 &&
+ (AllCountsNeedLessThan32Bits || NestedLoopCount == 1 ||
+ FitsInto(
+ 32 /* Bits */,
+ LastIteration32.get()->getType()->hasSignedIntegerRepresentation(),
+ LastIteration64.get(), SemaRef)))
+ LastIteration = LastIteration32;
+
+ if (!LastIteration.isUsable())
+ return 0;
+
+ // Save the number of iterations.
+ ExprResult NumIterations = LastIteration;
+ {
+ LastIteration = SemaRef.BuildBinOp(
+ CurScope, SourceLocation(), BO_Sub, LastIteration.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ if (!LastIteration.isUsable())
+ return 0;
+ }
+
+ // Calculate the last iteration number beforehand instead of doing this on
+ // each iteration. Do not do this if the number of iterations may be kfold-ed.
+ llvm::APSInt Result;
+ bool IsConstant =
+ LastIteration.get()->isIntegerConstantExpr(Result, SemaRef.Context);
+ ExprResult CalcLastIteration;
+ if (!IsConstant) {
+ SourceLocation SaveLoc;
+ VarDecl *SaveVar =
+ BuildVarDecl(SemaRef, SaveLoc, LastIteration.get()->getType(),
+ ".omp.last.iteration");
+ ExprResult SaveRef = SemaRef.BuildDeclRefExpr(
+ SaveVar, LastIteration.get()->getType(), VK_LValue, SaveLoc);
+ CalcLastIteration = SemaRef.BuildBinOp(CurScope, SaveLoc, BO_Assign,
+ SaveRef.get(), LastIteration.get());
+ LastIteration = SaveRef;
+
+ // Prepare SaveRef + 1.
+ NumIterations = SemaRef.BuildBinOp(
+ CurScope, SaveLoc, BO_Add, SaveRef.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ if (!NumIterations.isUsable())
+ return 0;
+ }
+
+ SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin();
+
+ // Precondition tests if there is at least one iteration (LastIteration > 0).
+ ExprResult PreCond = SemaRef.BuildBinOp(
+ CurScope, InitLoc, BO_GT, LastIteration.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get());
+
+ QualType VType = LastIteration.get()->getType();
+ // Build variables passed into runtime, nesessary for worksharing directives.
+ ExprResult LB, UB, IL, ST, EUB;
+ if (isOpenMPWorksharingDirective(DKind)) {
+ // Lower bound variable, initialized with zero.
+ VarDecl *LBDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.lb");
+ LB = SemaRef.BuildDeclRefExpr(LBDecl, VType, VK_LValue, InitLoc);
+ SemaRef.AddInitializerToDecl(
+ LBDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(),
+ /*DirectInit*/ false, /*TypeMayContainAuto*/ false);
+
+ // Upper bound variable, initialized with last iteration number.
+ VarDecl *UBDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.ub");
+ UB = SemaRef.BuildDeclRefExpr(UBDecl, VType, VK_LValue, InitLoc);
+ SemaRef.AddInitializerToDecl(UBDecl, LastIteration.get(),
+ /*DirectInit*/ false,
+ /*TypeMayContainAuto*/ false);
+
+ // A 32-bit variable-flag where runtime returns 1 for the last iteration.
+ // This will be used to implement clause 'lastprivate'.
+ QualType Int32Ty = SemaRef.Context.getIntTypeForBitwidth(32, true);
+ VarDecl *ILDecl = BuildVarDecl(SemaRef, InitLoc, Int32Ty, ".omp.is_last");
+ IL = SemaRef.BuildDeclRefExpr(ILDecl, Int32Ty, VK_LValue, InitLoc);
+ SemaRef.AddInitializerToDecl(
+ ILDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(),
+ /*DirectInit*/ false, /*TypeMayContainAuto*/ false);
+
+ // Stride variable returned by runtime (we initialize it to 1 by default).
+ VarDecl *STDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.stride");
+ ST = SemaRef.BuildDeclRefExpr(STDecl, VType, VK_LValue, InitLoc);
+ SemaRef.AddInitializerToDecl(
+ STDecl, SemaRef.ActOnIntegerConstant(InitLoc, 1).get(),
+ /*DirectInit*/ false, /*TypeMayContainAuto*/ false);
+
+ // Build expression: UB = min(UB, LastIteration)
+ // It is nesessary for CodeGen of directives with static scheduling.
+ ExprResult IsUBGreater = SemaRef.BuildBinOp(CurScope, InitLoc, BO_GT,
+ UB.get(), LastIteration.get());
+ ExprResult CondOp = SemaRef.ActOnConditionalOp(
+ InitLoc, InitLoc, IsUBGreater.get(), LastIteration.get(), UB.get());
+ EUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, UB.get(),
+ CondOp.get());
+ EUB = SemaRef.ActOnFinishFullExpr(EUB.get());
+ }
+
+ // Build the iteration variable and its initialization before loop.
+ ExprResult IV;
+ ExprResult Init;
+ {
+ VarDecl *IVDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.iv");
+ IV = SemaRef.BuildDeclRefExpr(IVDecl, VType, VK_LValue, InitLoc);
+ Expr *RHS = isOpenMPWorksharingDirective(DKind)
+ ? LB.get()
+ : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get();
+ Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS);
+ Init = SemaRef.ActOnFinishFullExpr(Init.get());
}
- // FIXME: Build resulting iteration space for IR generation (collapsing
- // iteration spaces when loop count > 1 ('collapse' clause)).
+ // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops.
+ SourceLocation CondLoc;
+ ExprResult Cond =
+ isOpenMPWorksharingDirective(DKind)
+ ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get())
+ : SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(),
+ NumIterations.get());
+ // Loop condition with 1 iteration separated (IV < LastIteration)
+ ExprResult SeparatedCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT,
+ IV.get(), LastIteration.get());
+
+ // Loop increment (IV = IV + 1)
+ SourceLocation IncLoc;
+ ExprResult Inc =
+ SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, IV.get(),
+ SemaRef.ActOnIntegerConstant(IncLoc, 1).get());
+ if (!Inc.isUsable())
+ return 0;
+ Inc = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, IV.get(), Inc.get());
+ Inc = SemaRef.ActOnFinishFullExpr(Inc.get());
+ if (!Inc.isUsable())
+ return 0;
+
+ // Increments for worksharing loops (LB = LB + ST; UB = UB + ST).
+ // Used for directives with static scheduling.
+ ExprResult NextLB, NextUB;
+ if (isOpenMPWorksharingDirective(DKind)) {
+ // LB + ST
+ NextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, LB.get(), ST.get());
+ if (!NextLB.isUsable())
+ return 0;
+ // LB = LB + ST
+ NextLB =
+ SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, LB.get(), NextLB.get());
+ NextLB = SemaRef.ActOnFinishFullExpr(NextLB.get());
+ if (!NextLB.isUsable())
+ return 0;
+ // UB + ST
+ NextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, UB.get(), ST.get());
+ if (!NextUB.isUsable())
+ return 0;
+ // UB = UB + ST
+ NextUB =
+ SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, UB.get(), NextUB.get());
+ NextUB = SemaRef.ActOnFinishFullExpr(NextUB.get());
+ if (!NextUB.isUsable())
+ return 0;
+ }
+
+ // Build updates and final values of the loop counters.
+ bool HasErrors = false;
+ Built.Counters.resize(NestedLoopCount);
+ Built.Updates.resize(NestedLoopCount);
+ Built.Finals.resize(NestedLoopCount);
+ {
+ ExprResult Div;
+ // Go from inner nested loop to outer.
+ for (int Cnt = NestedLoopCount - 1; Cnt >= 0; --Cnt) {
+ LoopIterationSpace &IS = IterSpaces[Cnt];
+ SourceLocation UpdLoc = IS.IncSrcRange.getBegin();
+ // Build: Iter = (IV / Div) % IS.NumIters
+ // where Div is product of previous iterations' IS.NumIters.
+ ExprResult Iter;
+ if (Div.isUsable()) {
+ Iter =
+ SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Div, IV.get(), Div.get());
+ } else {
+ Iter = IV;
+ assert((Cnt == (int)NestedLoopCount - 1) &&
+ "unusable div expected on first iteration only");
+ }
+
+ if (Cnt != 0 && Iter.isUsable())
+ Iter = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Rem, Iter.get(),
+ IS.NumIterations);
+ if (!Iter.isUsable()) {
+ HasErrors = true;
+ break;
+ }
+
+ // Build update: IS.CounterVar = IS.Start + Iter * IS.Step
+ ExprResult Update =
+ BuildCounterUpdate(SemaRef, CurScope, UpdLoc, IS.CounterVar,
+ IS.CounterInit, Iter, IS.CounterStep, IS.Subtract);
+ if (!Update.isUsable()) {
+ HasErrors = true;
+ break;
+ }
+
+ // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step
+ ExprResult Final = BuildCounterUpdate(
+ SemaRef, CurScope, UpdLoc, IS.CounterVar, IS.CounterInit,
+ IS.NumIterations, IS.CounterStep, IS.Subtract);
+ if (!Final.isUsable()) {
+ HasErrors = true;
+ break;
+ }
+
+ // Build Div for the next iteration: Div <- Div * IS.NumIters
+ if (Cnt != 0) {
+ if (Div.isUnset())
+ Div = IS.NumIterations;
+ else
+ Div = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Mul, Div.get(),
+ IS.NumIterations);
+
+ // Add parentheses (for debugging purposes only).
+ if (Div.isUsable())
+ Div = SemaRef.ActOnParenExpr(UpdLoc, UpdLoc, Div.get());
+ if (!Div.isUsable()) {
+ HasErrors = true;
+ break;
+ }
+ }
+ if (!Update.isUsable() || !Final.isUsable()) {
+ HasErrors = true;
+ break;
+ }
+ // Save results
+ Built.Counters[Cnt] = IS.CounterVar;
+ Built.Updates[Cnt] = Update.get();
+ Built.Finals[Cnt] = Final.get();
+ }
+ }
+
+ if (HasErrors)
+ return 0;
+
+ // Save results
+ Built.IterationVarRef = IV.get();
+ Built.LastIteration = LastIteration.get();
+ Built.CalcLastIteration = CalcLastIteration.get();
+ Built.PreCond = PreCond.get();
+ Built.Cond = Cond.get();
+ Built.SeparatedCond = SeparatedCond.get();
+ Built.Init = Init.get();
+ Built.Inc = Inc.get();
+ Built.LB = LB.get();
+ Built.UB = UB.get();
+ Built.IL = IL.get();
+ Built.ST = ST.get();
+ Built.EUB = EUB.get();
+ Built.NLB = NextLB.get();
+ Built.NUB = NextUB.get();
+
return NestedLoopCount;
}
@@ -2060,32 +2947,60 @@ StmtResult Sema::ActOnOpenMPSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_simd, GetCollapseNumberExpr(Clauses), AStmt, *this,
- *DSAStack, VarsWithImplicitDSA);
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp simd loop exprs were not built");
+
getCurFunction()->setHasBranchProtectedScope();
return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
- Clauses, AStmt);
+ Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPForDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_for, GetCollapseNumberExpr(Clauses), AStmt, *this,
- *DSAStack, VarsWithImplicitDSA);
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
getCurFunction()->setHasBranchProtectedScope();
return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
- Clauses, AStmt);
+ Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPForSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse', it will define the nested loops number.
+ unsigned NestedLoopCount =
+ CheckOpenMPLoop(OMPD_for_simd, GetCollapseNumberExpr(Clauses), AStmt,
+ *this, *DSAStack, VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for simd loop exprs were not built");
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPForSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
+ Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses,
@@ -2178,16 +3093,46 @@ StmtResult Sema::ActOnOpenMPParallelForDirective(
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_parallel_for, GetCollapseNumberExpr(Clauses), AStmt,
- *this, *DSAStack, VarsWithImplicitDSA);
+ *this, *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp parallel for loop exprs were not built");
+
getCurFunction()->setHasBranchProtectedScope();
return OMPParallelForDirective::Create(Context, StartLoc, EndLoc,
- NestedLoopCount, Clauses, AStmt);
+ NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPParallelForSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse', it will define the nested loops number.
+ unsigned NestedLoopCount =
+ CheckOpenMPLoop(OMPD_parallel_for_simd, GetCollapseNumberExpr(Clauses),
+ AStmt, *this, *DSAStack, VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPParallelForSimdDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
StmtResult
@@ -2264,6 +3209,271 @@ StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses);
}
+StmtResult Sema::ActOnOpenMPOrderedDirective(Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ // TODO further analysis of associated statements and clauses.
+ OpenMPClauseKind AtomicKind = OMPC_unknown;
+ SourceLocation AtomicKindLoc;
+ for (auto *C : Clauses) {
+ if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write ||
+ C->getClauseKind() == OMPC_update ||
+ C->getClauseKind() == OMPC_capture) {
+ if (AtomicKind != OMPC_unknown) {
+ Diag(C->getLocStart(), diag::err_omp_atomic_several_clauses)
+ << SourceRange(C->getLocStart(), C->getLocEnd());
+ Diag(AtomicKindLoc, diag::note_omp_atomic_previous_clause)
+ << getOpenMPClauseName(AtomicKind);
+ } else {
+ AtomicKind = C->getClauseKind();
+ AtomicKindLoc = C->getLocStart();
+ }
+ }
+ }
+
+ auto Body = CS->getCapturedStmt();
+ Expr *X = nullptr;
+ Expr *V = nullptr;
+ Expr *E = nullptr;
+ // OpenMP [2.12.6, atomic Construct]
+ // In the next expressions:
+ // * x and v (as applicable) are both l-value expressions with scalar type.
+ // * During the execution of an atomic region, multiple syntactic
+ // occurrences of x must designate the same storage location.
+ // * Neither of v and expr (as applicable) may access the storage location
+ // designated by x.
+ // * Neither of x and expr (as applicable) may access the storage location
+ // designated by v.
+ // * expr is an expression with scalar type.
+ // * binop is one of +, *, -, /, &, ^, |, <<, or >>.
+ // * binop, binop=, ++, and -- are not overloaded operators.
+ // * The expression x binop expr must be numerically equivalent to x binop
+ // (expr). This requirement is satisfied if the operators in expr have
+ // precedence greater than binop, or by using parentheses around expr or
+ // subexpressions of expr.
+ // * The expression expr binop x must be numerically equivalent to (expr)
+ // binop x. This requirement is satisfied if the operators in expr have
+ // precedence equal to or greater than binop, or by using parentheses around
+ // expr or subexpressions of expr.
+ // * For forms that allow multiple occurrences of x, the number of times
+ // that x is evaluated is unspecified.
+ enum {
+ NotAnExpression,
+ NotAnAssignmentOp,
+ NotAScalarType,
+ NotAnLValue,
+ NoError
+ } ErrorFound = NoError;
+ if (AtomicKind == OMPC_read) {
+ SourceLocation ErrorLoc, NoteLoc;
+ SourceRange ErrorRange, NoteRange;
+ // If clause is read:
+ // v = x;
+ if (auto AtomicBody = dyn_cast<Expr>(Body)) {
+ auto AtomicBinOp =
+ dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts());
+ if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
+ X = AtomicBinOp->getRHS()->IgnoreParenImpCasts();
+ V = AtomicBinOp->getLHS()->IgnoreParenImpCasts();
+ if ((X->isInstantiationDependent() || X->getType()->isScalarType()) &&
+ (V->isInstantiationDependent() || V->getType()->isScalarType())) {
+ if (!X->isLValue() || !V->isLValue()) {
+ auto NotLValueExpr = X->isLValue() ? V : X;
+ ErrorFound = NotAnLValue;
+ ErrorLoc = AtomicBinOp->getExprLoc();
+ ErrorRange = AtomicBinOp->getSourceRange();
+ NoteLoc = NotLValueExpr->getExprLoc();
+ NoteRange = NotLValueExpr->getSourceRange();
+ }
+ } else if (!X->isInstantiationDependent() ||
+ !V->isInstantiationDependent()) {
+ auto NotScalarExpr =
+ (X->isInstantiationDependent() || X->getType()->isScalarType())
+ ? V
+ : X;
+ ErrorFound = NotAScalarType;
+ ErrorLoc = AtomicBinOp->getExprLoc();
+ ErrorRange = AtomicBinOp->getSourceRange();
+ NoteLoc = NotScalarExpr->getExprLoc();
+ NoteRange = NotScalarExpr->getSourceRange();
+ }
+ } else {
+ ErrorFound = NotAnAssignmentOp;
+ ErrorLoc = AtomicBody->getExprLoc();
+ ErrorRange = AtomicBody->getSourceRange();
+ NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc()
+ : AtomicBody->getExprLoc();
+ NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange()
+ : AtomicBody->getSourceRange();
+ }
+ } else {
+ ErrorFound = NotAnExpression;
+ NoteLoc = ErrorLoc = Body->getLocStart();
+ NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
+ }
+ if (ErrorFound != NoError) {
+ Diag(ErrorLoc, diag::err_omp_atomic_read_not_expression_statement)
+ << ErrorRange;
+ Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound
+ << NoteRange;
+ return StmtError();
+ } else if (CurContext->isDependentContext())
+ V = X = nullptr;
+ } else if (AtomicKind == OMPC_write) {
+ SourceLocation ErrorLoc, NoteLoc;
+ SourceRange ErrorRange, NoteRange;
+ // If clause is write:
+ // x = expr;
+ if (auto AtomicBody = dyn_cast<Expr>(Body)) {
+ auto AtomicBinOp =
+ dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts());
+ if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
+ X = AtomicBinOp->getLHS()->IgnoreParenImpCasts();
+ E = AtomicBinOp->getRHS()->IgnoreParenImpCasts();
+ if ((X->isInstantiationDependent() || X->getType()->isScalarType()) &&
+ (E->isInstantiationDependent() || E->getType()->isScalarType())) {
+ if (!X->isLValue()) {
+ ErrorFound = NotAnLValue;
+ ErrorLoc = AtomicBinOp->getExprLoc();
+ ErrorRange = AtomicBinOp->getSourceRange();
+ NoteLoc = X->getExprLoc();
+ NoteRange = X->getSourceRange();
+ }
+ } else if (!X->isInstantiationDependent() ||
+ !E->isInstantiationDependent()) {
+ auto NotScalarExpr =
+ (X->isInstantiationDependent() || X->getType()->isScalarType())
+ ? E
+ : X;
+ ErrorFound = NotAScalarType;
+ ErrorLoc = AtomicBinOp->getExprLoc();
+ ErrorRange = AtomicBinOp->getSourceRange();
+ NoteLoc = NotScalarExpr->getExprLoc();
+ NoteRange = NotScalarExpr->getSourceRange();
+ }
+ } else {
+ ErrorFound = NotAnAssignmentOp;
+ ErrorLoc = AtomicBody->getExprLoc();
+ ErrorRange = AtomicBody->getSourceRange();
+ NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc()
+ : AtomicBody->getExprLoc();
+ NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange()
+ : AtomicBody->getSourceRange();
+ }
+ } else {
+ ErrorFound = NotAnExpression;
+ NoteLoc = ErrorLoc = Body->getLocStart();
+ NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
+ }
+ if (ErrorFound != NoError) {
+ Diag(ErrorLoc, diag::err_omp_atomic_write_not_expression_statement)
+ << ErrorRange;
+ Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound
+ << NoteRange;
+ return StmtError();
+ } else if (CurContext->isDependentContext())
+ E = X = nullptr;
+ } else if (AtomicKind == OMPC_update || AtomicKind == OMPC_unknown) {
+ if (!isa<Expr>(Body)) {
+ Diag(Body->getLocStart(),
+ diag::err_omp_atomic_update_not_expression_statement)
+ << (AtomicKind == OMPC_update);
+ return StmtError();
+ }
+ } else if (AtomicKind == OMPC_capture) {
+ if (isa<Expr>(Body) && !isa<BinaryOperator>(Body)) {
+ Diag(Body->getLocStart(),
+ diag::err_omp_atomic_capture_not_expression_statement);
+ return StmtError();
+ } else if (!isa<Expr>(Body) && !isa<CompoundStmt>(Body)) {
+ Diag(Body->getLocStart(),
+ diag::err_omp_atomic_capture_not_compound_statement);
+ return StmtError();
+ }
+ }
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
+ X, V, E);
+}
+
+StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+
+ // OpenMP [2.16, Nesting of Regions]
+ // If specified, a teams construct must be contained within a target
+ // construct. That target construct must contain no statements or directives
+ // outside of the teams construct.
+ if (DSAStack->hasInnerTeamsRegion()) {
+ auto S = AStmt->IgnoreContainers(/*IgnoreCaptured*/ true);
+ bool OMPTeamsFound = true;
+ if (auto *CS = dyn_cast<CompoundStmt>(S)) {
+ auto I = CS->body_begin();
+ while (I != CS->body_end()) {
+ auto OED = dyn_cast<OMPExecutableDirective>(*I);
+ if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind())) {
+ OMPTeamsFound = false;
+ break;
+ }
+ ++I;
+ }
+ assert(I != CS->body_end() && "Not found statement");
+ S = *I;
+ }
+ if (!OMPTeamsFound) {
+ Diag(StartLoc, diag::err_omp_target_contains_not_only_teams);
+ Diag(DSAStack->getInnerTeamsRegionLoc(),
+ diag::note_omp_nested_teams_construct_here);
+ Diag(S->getLocStart(), diag::note_omp_nested_statement_here)
+ << isa<OMPExecutableDirective>(S);
+ return StmtError();
+ }
+ }
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPTargetDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
+}
+
OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -2303,6 +3513,11 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_flush:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
@@ -2345,7 +3560,6 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc);
}
-
ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
Expr *Op) {
if (!Op)
@@ -2396,7 +3610,6 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
SourceLocation EndLoc) {
Expr *ValExpr = NumThreads;
if (!NumThreads->isValueDependent() && !NumThreads->isTypeDependent() &&
- !NumThreads->isInstantiationDependent() &&
!NumThreads->containsUnexpandedParameterPack()) {
SourceLocation NumThreadsLoc = NumThreads->getLocStart();
ExprResult Val =
@@ -2437,6 +3650,11 @@ ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E,
<< getOpenMPClauseName(CKind) << E->getSourceRange();
return ExprError();
}
+ if (CKind == OMPC_aligned && !Result.isPowerOf2()) {
+ Diag(E->getExprLoc(), diag::warn_omp_alignment_not_power_of_two)
+ << E->getSourceRange();
+ return ExprError();
+ }
return ICE;
}
@@ -2506,6 +3724,11 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_flush:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
@@ -2621,6 +3844,11 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_flush:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
@@ -2700,6 +3928,21 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_mergeable:
Res = ActOnOpenMPMergeableClause(StartLoc, EndLoc);
break;
+ case OMPC_read:
+ Res = ActOnOpenMPReadClause(StartLoc, EndLoc);
+ break;
+ case OMPC_write:
+ Res = ActOnOpenMPWriteClause(StartLoc, EndLoc);
+ break;
+ case OMPC_update:
+ Res = ActOnOpenMPUpdateClause(StartLoc, EndLoc);
+ break;
+ case OMPC_capture:
+ Res = ActOnOpenMPCaptureClause(StartLoc, EndLoc);
+ break;
+ case OMPC_seq_cst:
+ Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@@ -2727,6 +3970,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
+ DSAStack->setOrderedRegion();
return new (Context) OMPOrderedClause(StartLoc, EndLoc);
}
@@ -2745,6 +3989,31 @@ OMPClause *Sema::ActOnOpenMPMergeableClause(SourceLocation StartLoc,
return new (Context) OMPMergeableClause(StartLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPReadClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPReadClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPWriteClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPWriteClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPUpdateClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPUpdateClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPCaptureClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPCaptureClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPSeqCstClause(StartLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
@@ -2798,6 +4067,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
@@ -2809,11 +4083,13 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
+ SmallVector<Expr *, 8> PrivateCopies;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP private clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ PrivateCopies.push_back(nullptr);
continue;
}
@@ -2835,6 +4111,7 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
+ PrivateCopies.push_back(nullptr);
continue;
}
@@ -2860,54 +4137,8 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
// A variable of class type (or array thereof) that appears in a private
// clause requires an accessible, unambiguous default constructor for the
// class type.
- while (Type.getNonReferenceType()->isArrayType()) {
- Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr())
- ->getElementType();
- }
- CXXRecordDecl *RD = getLangOpts().CPlusPlus
- ? Type.getNonReferenceType()->getAsCXXRecordDecl()
- : nullptr;
- // FIXME This code must be replaced by actual constructing/destructing of
- // the private variable.
- if (RD) {
- CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
- PartialDiagnostic PD =
- PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
- if (!CD ||
- CheckConstructorAccess(ELoc, CD,
- InitializedEntity::InitializeTemporary(Type),
- CD->getAccess(), PD) == AR_inaccessible ||
- CD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_private) << 0;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, CD);
- DiagnoseUseOfDecl(CD, ELoc);
-
- CXXDestructorDecl *DD = RD->getDestructor();
- if (DD) {
- if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
- DD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_private) << 4;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, DD);
- DiagnoseUseOfDecl(DD, ELoc);
- }
+ while (Type->isArrayType()) {
+ Type = cast<ArrayType>(Type.getTypePtr())->getElementType();
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -2925,14 +4156,59 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
continue;
}
+ // Generate helper private variable and initialize it with the default
+ // value. The address of the original variable is replaced by the address of
+ // the new private variable in CodeGen. This new variable is not added to
+ // IdResolver, so the code in the OpenMP region uses original variable for
+ // proper diagnostics.
+ auto VDPrivate =
+ VarDecl::Create(Context, CurContext, DE->getLocStart(),
+ DE->getExprLoc(), VD->getIdentifier(), VD->getType(),
+ VD->getTypeSourceInfo(), /*S*/ SC_Auto);
+ ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto*/ false);
+ if (VDPrivate->isInvalidDecl())
+ continue;
+ CurContext->addDecl(VDPrivate);
+ auto VDPrivateRefExpr =
+ DeclRefExpr::Create(Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+ /*TemplateKWLoc*/ SourceLocation(), VDPrivate,
+ /*RefersToEnclosingVariableOrCapture*/ false,
+ /*NameLoc*/ SourceLocation(), DE->getType(),
+ /*VK*/ VK_LValue);
+
DSAStack->addDSA(VD, DE, OMPC_private);
Vars.push_back(DE);
+ PrivateCopies.push_back(VDPrivateRefExpr);
}
if (Vars.empty())
return nullptr;
- return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+ return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars,
+ PrivateCopies);
+}
+
+namespace {
+class DiagsUninitializedSeveretyRAII {
+private:
+ DiagnosticsEngine &Diags;
+ SourceLocation SavedLoc;
+ bool IsIgnored;
+
+public:
+ DiagsUninitializedSeveretyRAII(DiagnosticsEngine &Diags, SourceLocation Loc,
+ bool IsIgnored)
+ : Diags(Diags), SavedLoc(Loc), IsIgnored(IsIgnored) {
+ if (!IsIgnored) {
+ Diags.setSeverity(/*Diag*/ diag::warn_uninit_self_reference_in_init,
+ /*Map*/ diag::Severity::Ignored, Loc);
+ }
+ }
+ ~DiagsUninitializedSeveretyRAII() {
+ if (!IsIgnored)
+ Diags.popMappings(SavedLoc);
+ }
+};
}
OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
@@ -2940,6 +4216,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
+ SmallVector<Expr *, 8> PrivateCopies;
+ SmallVector<Expr *, 8> Inits;
bool IsImplicitClause =
StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
auto ImplicitClauseLoc = DSAStack->getConstructLoc();
@@ -2949,11 +4227,13 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ PrivateCopies.push_back(nullptr);
+ Inits.push_back(nullptr);
continue;
}
- SourceLocation ELoc = IsImplicitClause ? ImplicitClauseLoc
- : RefExpr->getExprLoc();
+ SourceLocation ELoc =
+ IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc();
// OpenMP [2.1, C/C++]
// A list item is a variable name.
// OpenMP [2.9.3.3, Restrictions, p.1]
@@ -2971,6 +4251,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
+ PrivateCopies.push_back(nullptr);
+ Inits.push_back(nullptr);
continue;
}
@@ -3004,65 +4286,6 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// clause requires an accessible, unambiguous copy constructor for the
// class type.
Type = Context.getBaseElementType(Type);
- CXXRecordDecl *RD = getLangOpts().CPlusPlus
- ? Type.getNonReferenceType()->getAsCXXRecordDecl()
- : nullptr;
- // FIXME This code must be replaced by actual constructing/destructing of
- // the firstprivate variable.
- if (RD) {
- CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0);
- PartialDiagnostic PD =
- PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
- if (!CD ||
- CheckConstructorAccess(ELoc, CD,
- InitializedEntity::InitializeTemporary(Type),
- CD->getAccess(), PD) == AR_inaccessible ||
- CD->isDeleted()) {
- if (IsImplicitClause) {
- Diag(ImplicitClauseLoc,
- diag::err_omp_task_predetermined_firstprivate_required_method)
- << 0;
- Diag(RefExpr->getExprLoc(), diag::note_used_here);
- } else {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_firstprivate) << 1;
- }
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, CD);
- DiagnoseUseOfDecl(CD, ELoc);
-
- CXXDestructorDecl *DD = RD->getDestructor();
- if (DD) {
- if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
- DD->isDeleted()) {
- if (IsImplicitClause) {
- Diag(ImplicitClauseLoc,
- diag::err_omp_task_predetermined_firstprivate_required_method)
- << 1;
- Diag(RefExpr->getExprLoc(), diag::note_used_here);
- } else {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_firstprivate) << 4;
- }
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, DD);
- DiagnoseUseOfDecl(DD, ELoc);
- }
- }
// If an implicit firstprivate variable found it was checked already.
if (!IsImplicitClause) {
@@ -3152,15 +4375,75 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
}
}
+ Type = Type.getUnqualifiedType();
+ auto VDPrivate = VarDecl::Create(Context, CurContext, DE->getLocStart(),
+ ELoc, VD->getIdentifier(), VD->getType(),
+ VD->getTypeSourceInfo(), /*S*/ SC_Auto);
+ // Generate helper private variable and initialize it with the value of the
+ // original variable. The address of the original variable is replaced by
+ // the address of the new private variable in the CodeGen. This new variable
+ // is not added to IdResolver, so the code in the OpenMP region uses
+ // original variable for proper diagnostics and variable capturing.
+ Expr *VDInitRefExpr = nullptr;
+ // For arrays generate initializer for single element and replace it by the
+ // original array element in CodeGen.
+ if (DE->getType()->isArrayType()) {
+ auto VDInit = VarDecl::Create(Context, CurContext, DE->getLocStart(),
+ ELoc, VD->getIdentifier(), Type,
+ VD->getTypeSourceInfo(), /*S*/ SC_Auto);
+ CurContext->addHiddenDecl(VDInit);
+ VDInitRefExpr = DeclRefExpr::Create(
+ Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+ /*TemplateKWLoc*/ SourceLocation(), VDInit,
+ /*RefersToEnclosingVariableOrCapture*/ true, ELoc, Type,
+ /*VK*/ VK_LValue);
+ VDInit->setIsUsed();
+ auto Init = DefaultLvalueConversion(VDInitRefExpr).get();
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInit);
+ InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc);
+
+ InitializationSequence InitSeq(*this, Entity, Kind, Init);
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Init);
+ if (Result.isInvalid())
+ VDPrivate->setInvalidDecl();
+ else
+ VDPrivate->setInit(Result.getAs<Expr>());
+ } else {
+ AddInitializerToDecl(
+ VDPrivate,
+ DefaultLvalueConversion(
+ DeclRefExpr::Create(Context, NestedNameSpecifierLoc(),
+ SourceLocation(), DE->getDecl(),
+ /*RefersToEnclosingVariableOrCapture=*/true,
+ DE->getExprLoc(), DE->getType(),
+ /*VK=*/VK_LValue)).get(),
+ /*DirectInit=*/false, /*TypeMayContainAuto=*/false);
+ }
+ if (VDPrivate->isInvalidDecl()) {
+ if (IsImplicitClause) {
+ Diag(DE->getExprLoc(),
+ diag::note_omp_task_predetermined_firstprivate_here);
+ }
+ continue;
+ }
+ CurContext->addDecl(VDPrivate);
+ auto VDPrivateRefExpr =
+ DeclRefExpr::Create(Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+ /*TemplateKWLoc*/ SourceLocation(), VDPrivate,
+ /*RefersToEnclosingVariableOrCapture*/ false,
+ DE->getLocStart(), DE->getType(),
+ /*VK*/ VK_LValue);
DSAStack->addDSA(VD, DE, OMPC_firstprivate);
Vars.push_back(DE);
+ PrivateCopies.push_back(VDPrivateRefExpr);
+ Inits.push_back(VDInitRefExpr);
}
if (Vars.empty())
return nullptr;
return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- Vars);
+ Vars, PrivateCopies, Inits);
}
OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
@@ -4099,4 +5382,3 @@ OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList,
return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList);
}
-#undef DSAStack
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 03001d89f07e..9195ee59075d 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -35,7 +35,7 @@
#include <algorithm>
#include <cstdlib>
-namespace clang {
+using namespace clang;
using namespace sema;
/// A convenience routine for creating a decayed reference to a function.
@@ -102,43 +102,9 @@ CompareDerivedToBaseConversions(Sema &S,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
-
-
-/// GetConversionCategory - Retrieve the implicit conversion
-/// category corresponding to the given implicit conversion kind.
-ImplicitConversionCategory
-GetConversionCategory(ImplicitConversionKind Kind) {
- static const ImplicitConversionCategory
- Category[(int)ICK_Num_Conversion_Kinds] = {
- ICC_Identity,
- ICC_Lvalue_Transformation,
- ICC_Lvalue_Transformation,
- ICC_Lvalue_Transformation,
- ICC_Identity,
- ICC_Qualification_Adjustment,
- ICC_Promotion,
- ICC_Promotion,
- ICC_Promotion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion,
- ICC_Conversion
- };
- return Category[(int)Kind];
-}
-
/// GetConversionRank - Retrieve the implicit conversion rank
/// corresponding to the given implicit conversion kind.
-ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
+ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
static const ImplicitConversionRank
Rank[(int)ICK_Num_Conversion_Kinds] = {
ICR_Exact_Match,
@@ -171,7 +137,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
/// GetImplicitConversionName - Return the name of this kind of
/// implicit conversion.
-const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
+static const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
static const char* const Name[(int)ICK_Num_Conversion_Kinds] = {
"No conversion",
"Lvalue-to-rvalue",
@@ -195,7 +161,7 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
"Vector splat",
"Complex-real conversion",
"Block Pointer conversion",
- "Transparent Union Conversion"
+ "Transparent Union Conversion",
"Writeback conversion"
};
return Name[Kind];
@@ -568,9 +534,10 @@ namespace {
/// \brief Convert from Sema's representation of template deduction information
/// to the form used in overload-candidate information.
-DeductionFailureInfo MakeDeductionFailureInfo(ASTContext &Context,
- Sema::TemplateDeductionResult TDK,
- TemplateDeductionInfo &Info) {
+DeductionFailureInfo
+clang::MakeDeductionFailureInfo(ASTContext &Context,
+ Sema::TemplateDeductionResult TDK,
+ TemplateDeductionInfo &Info) {
DeductionFailureInfo Result;
Result.Result = static_cast<unsigned>(TDK);
Result.HasDiagnostic = false;
@@ -1067,7 +1034,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
// is a redeclaration of OldMethod.
unsigned OldQuals = OldMethod->getTypeQualifiers();
unsigned NewQuals = NewMethod->getTypeQualifiers();
- if (!getLangOpts().CPlusPlus1y && NewMethod->isConstexpr() &&
+ if (!getLangOpts().CPlusPlus14 && NewMethod->isConstexpr() &&
!isa<CXXConstructorDecl>(NewMethod))
NewQuals |= Qualifiers::Const;
@@ -1268,11 +1235,11 @@ Sema::TryImplicitConversion(Expr *From, QualType ToType,
bool InOverloadResolution,
bool CStyle,
bool AllowObjCWritebackConversion) {
- return clang::TryImplicitConversion(*this, From, ToType,
- SuppressUserConversions, AllowExplicit,
- InOverloadResolution, CStyle,
- AllowObjCWritebackConversion,
- /*AllowObjCConversionOnExplicit=*/false);
+ return ::TryImplicitConversion(*this, From, ToType,
+ SuppressUserConversions, AllowExplicit,
+ InOverloadResolution, CStyle,
+ AllowObjCWritebackConversion,
+ /*AllowObjCConversionOnExplicit=*/false);
}
/// PerformImplicitConversion - Perform an implicit conversion of the
@@ -1301,13 +1268,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (getLangOpts().ObjC1)
CheckObjCBridgeRelatedConversions(From->getLocStart(),
ToType, From->getType(), From);
- ICS = clang::TryImplicitConversion(*this, From, ToType,
- /*SuppressUserConversions=*/false,
- AllowExplicit,
- /*InOverloadResolution=*/false,
- /*CStyle=*/false,
- AllowObjCWritebackConversion,
- /*AllowObjCConversionOnExplicit=*/false);
+ ICS = ::TryImplicitConversion(*this, From, ToType,
+ /*SuppressUserConversions=*/false,
+ AllowExplicit,
+ /*InOverloadResolution=*/false,
+ /*CStyle=*/false,
+ AllowObjCWritebackConversion,
+ /*AllowObjCConversionOnExplicit=*/false);
return PerformImplicitConversion(From, ToType, ICS, Action);
}
@@ -1451,6 +1418,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// We were able to resolve the address of the overloaded function,
// so we can convert to the type of that function.
FromType = Fn->getType();
+ SCS.setFromType(FromType);
// we can sometimes resolve &foo<int> regardless of ToType, so check
// if the type matches (identity) or we are converting to bool
@@ -3656,7 +3624,7 @@ CompareStandardConversionSequences(Sema &S,
/// CompareQualificationConversions - Compares two standard conversion
/// sequences to determine whether they can be ranked based on their
/// qualification conversions (C++ 13.3.3.2p3 bullet 3).
-ImplicitConversionSequence::CompareKind
+static ImplicitConversionSequence::CompareKind
CompareQualificationConversions(Sema &S,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
@@ -3769,7 +3737,7 @@ CompareQualificationConversions(Sema &S,
/// various kinds of derived-to-base conversions (C++
/// [over.ics.rank]p4b3). As part of these checks, we also look at
/// conversions between Objective-C interface types.
-ImplicitConversionSequence::CompareKind
+static ImplicitConversionSequence::CompareKind
CompareDerivedToBaseConversions(Sema &S,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
@@ -4849,9 +4817,8 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
// Note that we always use the true parent context when performing
// the actual argument initialization.
- ImplicitConversionSequence ICS
- = TryObjectArgumentInitialization(*this, From->getType(), FromClassification,
- Method, Method->getParent());
+ ImplicitConversionSequence ICS = TryObjectArgumentInitialization(
+ *this, From->getType(), FromClassification, Method, Method->getParent());
if (ICS.isBad()) {
if (ICS.Bad.Kind == BadConversionSequence::bad_qualifiers) {
Qualifiers FromQs = FromRecordType.getQualifiers();
@@ -4927,41 +4894,51 @@ static bool CheckConvertedConstantConversions(Sema &S,
// conversions are fine.
switch (SCS.Second) {
case ICK_Identity:
+ case ICK_NoReturn_Adjustment:
case ICK_Integral_Promotion:
- case ICK_Integral_Conversion:
- case ICK_Zero_Event_Conversion:
+ case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere.
return true;
case ICK_Boolean_Conversion:
// Conversion from an integral or unscoped enumeration type to bool is
- // classified as ICK_Boolean_Conversion, but it's also an integral
- // conversion, so it's permitted in a converted constant expression.
+ // classified as ICK_Boolean_Conversion, but it's also arguably an integral
+ // conversion, so we allow it in a converted constant expression.
+ //
+ // FIXME: Per core issue 1407, we should not allow this, but that breaks
+ // a lot of popular code. We should at least add a warning for this
+ // (non-conforming) extension.
return SCS.getFromType()->isIntegralOrUnscopedEnumerationType() &&
SCS.getToType(2)->isBooleanType();
+ case ICK_Pointer_Conversion:
+ case ICK_Pointer_Member:
+ // C++1z: null pointer conversions and null member pointer conversions are
+ // only permitted if the source type is std::nullptr_t.
+ return SCS.getFromType()->isNullPtrType();
+
+ case ICK_Floating_Promotion:
+ case ICK_Complex_Promotion:
+ case ICK_Floating_Conversion:
+ case ICK_Complex_Conversion:
case ICK_Floating_Integral:
+ case ICK_Compatible_Conversion:
+ case ICK_Derived_To_Base:
+ case ICK_Vector_Conversion:
+ case ICK_Vector_Splat:
case ICK_Complex_Real:
+ case ICK_Block_Pointer_Conversion:
+ case ICK_TransparentUnionConversion:
+ case ICK_Writeback_Conversion:
+ case ICK_Zero_Event_Conversion:
return false;
case ICK_Lvalue_To_Rvalue:
case ICK_Array_To_Pointer:
case ICK_Function_To_Pointer:
- case ICK_NoReturn_Adjustment:
+ llvm_unreachable("found a first conversion kind in Second");
+
case ICK_Qualification:
- case ICK_Compatible_Conversion:
- case ICK_Vector_Conversion:
- case ICK_Vector_Splat:
- case ICK_Derived_To_Base:
- case ICK_Pointer_Conversion:
- case ICK_Pointer_Member:
- case ICK_Block_Pointer_Conversion:
- case ICK_Writeback_Conversion:
- case ICK_Floating_Promotion:
- case ICK_Complex_Promotion:
- case ICK_Complex_Conversion:
- case ICK_Floating_Conversion:
- case ICK_TransparentUnionConversion:
- llvm_unreachable("unexpected second conversion kind");
+ llvm_unreachable("found a third conversion kind in Second");
case ICK_Num_Conversion_Kinds:
break;
@@ -4973,67 +4950,71 @@ static bool CheckConvertedConstantConversions(Sema &S,
/// CheckConvertedConstantExpression - Check that the expression From is a
/// converted constant expression of type T, perform the conversion and produce
/// the converted expression, per C++11 [expr.const]p3.
-ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
- llvm::APSInt &Value,
- CCEKind CCE) {
- assert(LangOpts.CPlusPlus11 && "converted constant expression outside C++11");
- assert(T->isIntegralOrEnumerationType() && "unexpected converted const type");
-
- if (checkPlaceholderForOverload(*this, From))
+static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
+ QualType T, APValue &Value,
+ Sema::CCEKind CCE,
+ bool RequireInt) {
+ assert(S.getLangOpts().CPlusPlus11 &&
+ "converted constant expression outside C++11");
+
+ if (checkPlaceholderForOverload(S, From))
return ExprError();
- // C++11 [expr.const]p3 with proposed wording fixes:
- // A converted constant expression of type T is a core constant expression,
- // implicitly converted to a prvalue of type T, where the converted
- // expression is a literal constant expression and the implicit conversion
- // sequence contains only user-defined conversions, lvalue-to-rvalue
- // conversions, integral promotions, and integral conversions other than
- // narrowing conversions.
+ // C++1z [expr.const]p3:
+ // A converted constant expression of type T is an expression,
+ // implicitly converted to type T, where the converted
+ // expression is a constant expression and the implicit conversion
+ // sequence contains only [... list of conversions ...].
ImplicitConversionSequence ICS =
- TryImplicitConversion(From, T,
+ TryCopyInitialization(S, From, T,
/*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
/*InOverloadResolution=*/false,
- /*CStyle=*/false,
- /*AllowObjcWritebackConversion=*/false);
+ /*AllowObjcWritebackConversion=*/false,
+ /*AllowExplicit=*/false);
StandardConversionSequence *SCS = nullptr;
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
- if (!CheckConvertedConstantConversions(*this, ICS.Standard))
- return Diag(From->getLocStart(),
- diag::err_typecheck_converted_constant_expression_disallowed)
- << From->getType() << From->getSourceRange() << T;
SCS = &ICS.Standard;
break;
case ImplicitConversionSequence::UserDefinedConversion:
- // We are converting from class type to an integral or enumeration type, so
- // the Before sequence must be trivial.
- if (!CheckConvertedConstantConversions(*this, ICS.UserDefined.After))
- return Diag(From->getLocStart(),
- diag::err_typecheck_converted_constant_expression_disallowed)
- << From->getType() << From->getSourceRange() << T;
+ // We are converting to a non-class type, so the Before sequence
+ // must be trivial.
SCS = &ICS.UserDefined.After;
break;
case ImplicitConversionSequence::AmbiguousConversion:
case ImplicitConversionSequence::BadConversion:
- if (!DiagnoseMultipleUserDefinedConversion(From, T))
- return Diag(From->getLocStart(),
- diag::err_typecheck_converted_constant_expression)
- << From->getType() << From->getSourceRange() << T;
+ if (!S.DiagnoseMultipleUserDefinedConversion(From, T))
+ return S.Diag(From->getLocStart(),
+ diag::err_typecheck_converted_constant_expression)
+ << From->getType() << From->getSourceRange() << T;
return ExprError();
case ImplicitConversionSequence::EllipsisConversion:
llvm_unreachable("ellipsis conversion in converted constant expression");
}
- ExprResult Result = PerformImplicitConversion(From, T, ICS, AA_Converting);
+ // Check that we would only use permitted conversions.
+ if (!CheckConvertedConstantConversions(S, *SCS)) {
+ return S.Diag(From->getLocStart(),
+ diag::err_typecheck_converted_constant_expression_disallowed)
+ << From->getType() << From->getSourceRange() << T;
+ }
+ // [...] and where the reference binding (if any) binds directly.
+ if (SCS->ReferenceBinding && !SCS->DirectBinding) {
+ return S.Diag(From->getLocStart(),
+ diag::err_typecheck_converted_constant_expression_indirect)
+ << From->getType() << From->getSourceRange() << T;
+ }
+
+ ExprResult Result =
+ S.PerformImplicitConversion(From, T, ICS, Sema::AA_Converting);
if (Result.isInvalid())
return Result;
// Check for a narrowing implicit conversion.
APValue PreNarrowingValue;
QualType PreNarrowingType;
- switch (SCS->getNarrowingKind(Context, Result.get(), PreNarrowingValue,
+ switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
PreNarrowingType)) {
case NK_Variable_Narrowing:
// Implicit conversion to a narrower type, and the value is not a constant
@@ -5042,13 +5023,13 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
break;
case NK_Constant_Narrowing:
- Diag(From->getLocStart(), diag::ext_cce_narrowing)
+ S.Diag(From->getLocStart(), diag::ext_cce_narrowing)
<< CCE << /*Constant*/1
- << PreNarrowingValue.getAsString(Context, PreNarrowingType) << T;
+ << PreNarrowingValue.getAsString(S.Context, PreNarrowingType) << T;
break;
case NK_Type_Narrowing:
- Diag(From->getLocStart(), diag::ext_cce_narrowing)
+ S.Diag(From->getLocStart(), diag::ext_cce_narrowing)
<< CCE << /*Constant*/0 << From->getType() << T;
break;
}
@@ -5058,12 +5039,15 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
Expr::EvalResult Eval;
Eval.Diag = &Notes;
- if (!Result.get()->EvaluateAsRValue(Eval, Context) || !Eval.Val.isInt()) {
+ if ((T->isReferenceType()
+ ? !Result.get()->EvaluateAsLValue(Eval, S.Context)
+ : !Result.get()->EvaluateAsRValue(Eval, S.Context)) ||
+ (RequireInt && !Eval.Val.isInt())) {
// The expression can't be folded, so we can't keep it at this position in
// the AST.
Result = ExprError();
} else {
- Value = Eval.Val.getInt();
+ Value = Eval.Val;
if (Notes.empty()) {
// It's a constant expression.
@@ -5074,16 +5058,34 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
// It's not a constant expression. Produce an appropriate diagnostic.
if (Notes.size() == 1 &&
Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr)
- Diag(Notes[0].first, diag::err_expr_not_cce) << CCE;
+ S.Diag(Notes[0].first, diag::err_expr_not_cce) << CCE;
else {
- Diag(From->getLocStart(), diag::err_expr_not_cce)
+ S.Diag(From->getLocStart(), diag::err_expr_not_cce)
<< CCE << From->getSourceRange();
for (unsigned I = 0; I < Notes.size(); ++I)
- Diag(Notes[I].first, Notes[I].second);
+ S.Diag(Notes[I].first, Notes[I].second);
}
- return Result;
+ return ExprError();
+}
+
+ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
+ APValue &Value, CCEKind CCE) {
+ return ::CheckConvertedConstantExpression(*this, From, T, Value, CCE, false);
}
+ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
+ llvm::APSInt &Value,
+ CCEKind CCE) {
+ assert(T->isIntegralOrEnumerationType() && "unexpected converted const type");
+
+ APValue V;
+ auto R = ::CheckConvertedConstantExpression(*this, From, T, V, CCE, true);
+ if (!R.isInvalid())
+ Value = V.getInt();
+ return R;
+}
+
+
/// dropPointerConversions - If the given standard conversion sequence
/// involves any pointer conversions, remove them. This may change
/// the result type of the conversion sequence.
@@ -5364,14 +5366,14 @@ ExprResult Sema::PerformContextualImplicitConversion(
CXXConversionDecl *Conversion;
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
if (ConvTemplate) {
- if (getLangOpts().CPlusPlus1y)
+ if (getLangOpts().CPlusPlus14)
Conversion = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
continue; // C++11 does not consider conversion operator templates(?).
} else
Conversion = cast<CXXConversionDecl>(D);
- assert((!ConvTemplate || getLangOpts().CPlusPlus1y) &&
+ assert((!ConvTemplate || getLangOpts().CPlusPlus14) &&
"Conversion operator templates are considered potentially "
"viable in C++1y");
@@ -5384,7 +5386,7 @@ ExprResult Sema::PerformContextualImplicitConversion(
if (!ConvTemplate)
ExplicitConversions.addDecl(I.getDecl(), I.getAccess());
} else {
- if (!ConvTemplate && getLangOpts().CPlusPlus1y) {
+ if (!ConvTemplate && getLangOpts().CPlusPlus14) {
if (ToType.isNull())
ToType = CurToType.getUnqualifiedType();
else if (HasUniqueTargetType &&
@@ -5396,7 +5398,7 @@ ExprResult Sema::PerformContextualImplicitConversion(
}
}
- if (getLangOpts().CPlusPlus1y) {
+ if (getLangOpts().CPlusPlus14) {
// C++1y [conv]p6:
// ... An expression e of class type E appearing in such a context
// is said to be contextually implicitly converted to a specified
@@ -5584,6 +5586,15 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ // Add this candidate
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = Function;
+ Candidate.Viable = true;
+ Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
+ Candidate.ExplicitCallArguments = Args.size();
+
if (Constructor) {
// C++ [class.copy]p3:
// A member function template is never instantiated to perform the copy
@@ -5592,19 +5603,13 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if (Args.size() == 1 &&
Constructor->isSpecializationCopyingObject() &&
(Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) ||
- IsDerivedFrom(Args[0]->getType(), ClassType)))
+ IsDerivedFrom(Args[0]->getType(), ClassType))) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_illegal_constructor;
return;
+ }
}
- // Add this candidate
- OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
- Candidate.FoundDecl = FoundDecl;
- Candidate.Function = Function;
- Candidate.Viable = true;
- Candidate.IsSurrogate = false;
- Candidate.IgnoreObjectArgument = false;
- Candidate.ExplicitCallArguments = Args.size();
-
unsigned NumParams = Proto->getNumParams();
// (C++ 13.3.2p2): A candidate function having fewer than m
@@ -5633,7 +5638,11 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// (CUDA B.1): Check for invalid calls between targets.
if (getLangOpts().CUDA)
if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
- if (CheckCUDATarget(Caller, Function)) {
+ // Skip the check for callers that are implicit members, because in this
+ // case we may not yet know what the member's target is; the target is
+ // inferred for the member automatically, based on the bases and fields of
+ // the class.
+ if (!Caller->isImplicit() && CheckCUDATarget(Caller, Function)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_target;
return;
@@ -5676,6 +5685,93 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
}
}
+ObjCMethodDecl *Sema::SelectBestMethod(Selector Sel, MultiExprArg Args,
+ bool IsInstance) {
+ SmallVector<ObjCMethodDecl*, 4> Methods;
+ if (!CollectMultipleMethodsInGlobalPool(Sel, Methods, IsInstance))
+ return nullptr;
+
+ for (unsigned b = 0, e = Methods.size(); b < e; b++) {
+ bool Match = true;
+ ObjCMethodDecl *Method = Methods[b];
+ unsigned NumNamedArgs = Sel.getNumArgs();
+ // Method might have more arguments than selector indicates. This is due
+ // to addition of c-style arguments in method.
+ if (Method->param_size() > NumNamedArgs)
+ NumNamedArgs = Method->param_size();
+ if (Args.size() < NumNamedArgs)
+ continue;
+
+ for (unsigned i = 0; i < NumNamedArgs; i++) {
+ // We can't do any type-checking on a type-dependent argument.
+ if (Args[i]->isTypeDependent()) {
+ Match = false;
+ break;
+ }
+
+ ParmVarDecl *param = Method->parameters()[i];
+ Expr *argExpr = Args[i];
+ assert(argExpr && "SelectBestMethod(): missing expression");
+
+ // Strip the unbridged-cast placeholder expression off unless it's
+ // a consumed argument.
+ if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) &&
+ !param->hasAttr<CFConsumedAttr>())
+ argExpr = stripARCUnbridgedCast(argExpr);
+
+ // If the parameter is __unknown_anytype, move on to the next method.
+ if (param->getType() == Context.UnknownAnyTy) {
+ Match = false;
+ break;
+ }
+
+ ImplicitConversionSequence ConversionState
+ = TryCopyInitialization(*this, argExpr, param->getType(),
+ /*SuppressUserConversions*/false,
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ getLangOpts().ObjCAutoRefCount,
+ /*AllowExplicit*/false);
+ if (ConversionState.isBad()) {
+ Match = false;
+ break;
+ }
+ }
+ // Promote additional arguments to variadic methods.
+ if (Match && Method->isVariadic()) {
+ for (unsigned i = NumNamedArgs, e = Args.size(); i < e; ++i) {
+ if (Args[i]->isTypeDependent()) {
+ Match = false;
+ break;
+ }
+ ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
+ nullptr);
+ if (Arg.isInvalid()) {
+ Match = false;
+ break;
+ }
+ }
+ } else {
+ // Check for extra arguments to non-variadic methods.
+ if (Args.size() != NumNamedArgs)
+ Match = false;
+ else if (Match && NumNamedArgs == 0 && Methods.size() > 1) {
+ // Special case when selectors have no argument. In this case, select
+ // one with the most general result type of 'id'.
+ for (unsigned b = 0, e = Methods.size(); b < e; b++) {
+ QualType ReturnT = Methods[b]->getReturnType();
+ if (ReturnT->isObjCIdType())
+ return Methods[b];
+ }
+ }
+ }
+
+ if (Match)
+ return Method;
+ }
+ return nullptr;
+}
+
static bool IsNotEnableIfAttr(Attr *A) { return !isa<EnableIfAttr>(A); }
EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
@@ -5696,6 +5792,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
// Convert the arguments.
SmallVector<Expr *, 16> ConvertedArgs;
bool InitializationFailed = false;
+ bool ContainsValueDependentExpr = false;
for (unsigned i = 0, e = Args.size(); i != e; ++i) {
if (i == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) &&
!cast<CXXMethodDecl>(Function)->isStatic() &&
@@ -5708,6 +5805,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
InitializationFailed = true;
break;
}
+ ContainsValueDependentExpr |= R.get()->isValueDependent();
ConvertedArgs.push_back(R.get());
} else {
ExprResult R =
@@ -5720,6 +5818,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
InitializationFailed = true;
break;
}
+ ContainsValueDependentExpr |= R.get()->isValueDependent();
ConvertedArgs.push_back(R.get());
}
}
@@ -5730,11 +5829,16 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
for (AttrVec::iterator I = Attrs.begin(); I != E; ++I) {
APValue Result;
EnableIfAttr *EIA = cast<EnableIfAttr>(*I);
+ if (EIA->getCond()->isValueDependent()) {
+ // Don't even try now, we'll examine it after instantiation.
+ continue;
+ }
+
if (!EIA->getCond()->EvaluateWithSubstitution(
- Result, Context, Function,
- ArrayRef<const Expr*>(ConvertedArgs.data(),
- ConvertedArgs.size())) ||
- !Result.isInt() || !Result.getInt().getBoolValue()) {
+ Result, Context, Function, llvm::makeArrayRef(ConvertedArgs))) {
+ if (!ContainsValueDependentExpr)
+ return EIA;
+ } else if (!Result.isInt() || !Result.getInt().getBoolValue()) {
return EIA;
}
}
@@ -5891,6 +5995,15 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
}
}
+ // (CUDA B.1): Check for invalid calls between targets.
+ if (getLangOpts().CUDA)
+ if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
+ if (CheckCUDATarget(Caller, Method)) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_target;
+ return;
+ }
+
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
@@ -6087,7 +6200,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// If the conversion function has an undeduced return type, trigger its
// deduction now.
- if (getLangOpts().CPlusPlus1y && ConvType->isUndeducedType()) {
+ if (getLangOpts().CPlusPlus14 && ConvType->isUndeducedType()) {
if (DeduceReturnType(Conversion, From->getExprLoc()))
return;
ConvType = Conversion->getConversionType().getNonReferenceType();
@@ -6226,7 +6339,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
"Can only end up with a standard conversion sequence or failure");
}
- if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, ArrayRef<Expr*>())) {
+ if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
@@ -6379,7 +6492,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
}
}
- if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, ArrayRef<Expr*>())) {
+ if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
@@ -6610,7 +6723,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
const Qualifiers &VisibleQuals) {
// Insert this type.
- if (!PointerTypes.insert(Ty))
+ if (!PointerTypes.insert(Ty).second)
return false;
QualType PointeeTy;
@@ -6678,7 +6791,7 @@ bool
BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants(
QualType Ty) {
// Insert this type.
- if (!MemberPointerTypes.insert(Ty))
+ if (!MemberPointerTypes.insert(Ty).second)
return false;
const MemberPointerType *PointerTy = Ty->getAs<MemberPointerType>();
@@ -7248,7 +7361,7 @@ public:
MemPtr != MemPtrEnd;
++MemPtr) {
// Don't add the same builtin candidate twice.
- if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)).second)
continue;
QualType ParamTypes[2] = { *MemPtr, *MemPtr };
@@ -7323,7 +7436,7 @@ public:
PtrEnd = CandidateTypes[ArgIdx].pointer_end();
Ptr != PtrEnd; ++Ptr) {
// Don't add the same builtin candidate twice.
- if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)).second)
continue;
QualType ParamTypes[2] = { *Ptr, *Ptr };
@@ -7337,7 +7450,7 @@ public:
// Don't add the same builtin candidate twice, or if a user defined
// candidate exists.
- if (!AddedTypes.insert(CanonType) ||
+ if (!AddedTypes.insert(CanonType).second ||
UserDefinedBinaryOperators.count(std::make_pair(CanonType,
CanonType)))
continue;
@@ -7348,7 +7461,7 @@ public:
if (CandidateTypes[ArgIdx].hasNullPtrType()) {
CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy);
- if (AddedTypes.insert(NullPtrTy) &&
+ if (AddedTypes.insert(NullPtrTy).second &&
!UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy,
NullPtrTy))) {
QualType ParamTypes[2] = { NullPtrTy, NullPtrTy };
@@ -7401,7 +7514,7 @@ public:
}
if (Op == OO_Minus) {
// ptrdiff_t operator-(T, T);
- if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)).second)
continue;
QualType ParamTypes[2] = { *Ptr, *Ptr };
@@ -7530,7 +7643,7 @@ public:
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
EnumEnd = CandidateTypes[ArgIdx].enumeration_end();
Enum != EnumEnd; ++Enum) {
- if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)).second)
continue;
AddBuiltinAssignmentOperatorCandidates(S, *Enum, Args, CandidateSet);
@@ -7540,7 +7653,7 @@ public:
MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(),
MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end();
MemPtr != MemPtrEnd; ++MemPtr) {
- if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)).second)
continue;
AddBuiltinAssignmentOperatorCandidates(S, *MemPtr, Args, CandidateSet);
@@ -7623,7 +7736,7 @@ public:
PtrEnd = CandidateTypes[1].pointer_end();
Ptr != PtrEnd; ++Ptr) {
// Make sure we don't add the same candidate twice.
- if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)).second)
continue;
QualType ParamTypes[2] = {
@@ -7904,7 +8017,7 @@ public:
Ptr = CandidateTypes[ArgIdx].pointer_begin(),
PtrEnd = CandidateTypes[ArgIdx].pointer_end();
Ptr != PtrEnd; ++Ptr) {
- if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)).second)
continue;
QualType ParamTypes[2] = { *Ptr, *Ptr };
@@ -7915,7 +8028,7 @@ public:
MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(),
MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end();
MemPtr != MemPtrEnd; ++MemPtr) {
- if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)).second)
continue;
QualType ParamTypes[2] = { *MemPtr, *MemPtr };
@@ -7930,7 +8043,7 @@ public:
if (!(*Enum)->getAs<EnumType>()->getDecl()->isScoped())
continue;
- if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)).second)
continue;
QualType ParamTypes[2] = { *Enum, *Enum };
@@ -8184,12 +8297,10 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
/// isBetterOverloadCandidate - Determines whether the first overload
/// candidate is a better candidate than the second (C++ 13.3.3p1).
-bool
-isBetterOverloadCandidate(Sema &S,
- const OverloadCandidate &Cand1,
- const OverloadCandidate &Cand2,
- SourceLocation Loc,
- bool UserDefinedConversion) {
+bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
+ const OverloadCandidate &Cand2,
+ SourceLocation Loc,
+ bool UserDefinedConversion) {
// Define viable functions to be better candidates than non-viable
// functions.
if (!Cand2.Viable)
@@ -8521,9 +8632,8 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion(
S.Diag(SourceLocation(), diag::note_ovl_too_many_candidates) << int(E - I);
}
-namespace {
-
-void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
+static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
+ unsigned I) {
const ImplicitConversionSequence &Conv = Cand->Conversions[I];
assert(Conv.isBad());
assert(Cand->Function && "for now, candidate must be a function");
@@ -8741,8 +8851,8 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
/// Additional arity mismatch diagnosis specific to a function overload
/// candidates. This is not covered by the more general DiagnoseArityMismatch()
/// over a candidate in any candidate set.
-bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,
- unsigned NumArgs) {
+static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,
+ unsigned NumArgs) {
FunctionDecl *Fn = Cand->Function;
unsigned MinParams = Fn->getMinRequiredArguments();
@@ -8769,7 +8879,7 @@ bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,
}
/// General arity mismatch diagnosis over a candidate in a candidate set.
-void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) {
+static void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) {
assert(isa<FunctionDecl>(D) &&
"The templated declaration should at least be a function"
" when diagnosing bad template argument deduction due to too many"
@@ -8813,13 +8923,13 @@ void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) {
}
/// Arity mismatch diagnosis specific to a function overload candidate.
-void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
- unsigned NumFormalArgs) {
+static void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
+ unsigned NumFormalArgs) {
if (!CheckArityMismatch(S, Cand, NumFormalArgs))
DiagnoseArityMismatch(S, Cand->Function, NumFormalArgs);
}
-TemplateDecl *getDescribedTemplate(Decl *Templated) {
+static TemplateDecl *getDescribedTemplate(Decl *Templated) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Templated))
return FD->getDescribedFunctionTemplate();
else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Templated))
@@ -8830,9 +8940,9 @@ TemplateDecl *getDescribedTemplate(Decl *Templated) {
}
/// Diagnose a failed template-argument deduction.
-void DiagnoseBadDeduction(Sema &S, Decl *Templated,
- DeductionFailureInfo &DeductionFailure,
- unsigned NumArgs) {
+static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
+ DeductionFailureInfo &DeductionFailure,
+ unsigned NumArgs) {
TemplateParameter Param = DeductionFailure.getTemplateParameter();
NamedDecl *ParamD;
(ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
@@ -9019,7 +9129,8 @@ void DiagnoseBadDeduction(Sema &S, Decl *Templated,
}
/// Diagnose a failed template-argument deduction, for function calls.
-void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, unsigned NumArgs) {
+static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
+ unsigned NumArgs) {
unsigned TDK = Cand->DeductionFailure.Result;
if (TDK == Sema::TDK_TooFewArguments || TDK == Sema::TDK_TooManyArguments) {
if (CheckArityMismatch(S, Cand, NumArgs))
@@ -9030,7 +9141,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, unsigned NumArgs) {
}
/// CUDA: diagnose an invalid call across targets.
-void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
+static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
FunctionDecl *Caller = cast<FunctionDecl>(S.CurContext);
FunctionDecl *Callee = Cand->Function;
@@ -9041,10 +9152,50 @@ void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Callee, FnDesc);
S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target)
- << (unsigned) FnKind << CalleeTarget << CallerTarget;
+ << (unsigned)FnKind << CalleeTarget << CallerTarget;
+
+ // This could be an implicit constructor for which we could not infer the
+ // target due to a collsion. Diagnose that case.
+ CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Callee);
+ if (Meth != nullptr && Meth->isImplicit()) {
+ CXXRecordDecl *ParentClass = Meth->getParent();
+ Sema::CXXSpecialMember CSM;
+
+ switch (FnKind) {
+ default:
+ return;
+ case oc_implicit_default_constructor:
+ CSM = Sema::CXXDefaultConstructor;
+ break;
+ case oc_implicit_copy_constructor:
+ CSM = Sema::CXXCopyConstructor;
+ break;
+ case oc_implicit_move_constructor:
+ CSM = Sema::CXXMoveConstructor;
+ break;
+ case oc_implicit_copy_assignment:
+ CSM = Sema::CXXCopyAssignment;
+ break;
+ case oc_implicit_move_assignment:
+ CSM = Sema::CXXMoveAssignment;
+ break;
+ };
+
+ bool ConstRHS = false;
+ if (Meth->getNumParams()) {
+ if (const ReferenceType *RT =
+ Meth->getParamDecl(0)->getType()->getAs<ReferenceType>()) {
+ ConstRHS = RT->getPointeeType().isConstQualified();
+ }
+ }
+
+ S.inferCUDATargetForImplicitSpecialMember(ParentClass, CSM, Meth,
+ /* ConstRHS */ ConstRHS,
+ /* Diagnose */ true);
+ }
}
-void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
+static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
FunctionDecl *Callee = Cand->Function;
EnableIfAttr *Attr = static_cast<EnableIfAttr*>(Cand->DeductionFailure.Data);
@@ -9066,8 +9217,8 @@ void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
/// It would be great to be able to express per-candidate problems
/// more richly for those diagnostic clients that cared, but we'd
/// still have to be just as careful with the default diagnostics.
-void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
- unsigned NumArgs) {
+static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
+ unsigned NumArgs) {
FunctionDecl *Fn = Cand->Function;
// Note deleted candidates, but only if they're viable.
@@ -9097,6 +9248,13 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_bad_deduction:
return DiagnoseBadDeduction(S, Cand, NumArgs);
+ case ovl_fail_illegal_constructor: {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_illegal_constructor)
+ << (Fn->getPrimaryTemplate() ? 1 : 0);
+ MaybeEmitInheritedConstructorNote(S, Fn);
+ return;
+ }
+
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
case ovl_fail_final_conversion_not_exact:
@@ -9122,7 +9280,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
}
}
-void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
+static void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
// Desugar the type of the surrogate down to a function type,
// retaining as many typedefs as possible while still showing
// the function type (and, therefore, its parameter types).
@@ -9155,10 +9313,9 @@ void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
MaybeEmitInheritedConstructorNote(S, Cand->Surrogate);
}
-void NoteBuiltinOperatorCandidate(Sema &S,
- StringRef Opc,
- SourceLocation OpLoc,
- OverloadCandidate *Cand) {
+static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
+ SourceLocation OpLoc,
+ OverloadCandidate *Cand) {
assert(Cand->NumConversions <= 2 && "builtin operator is not binary");
std::string TypeStr("operator");
TypeStr += Opc;
@@ -9175,8 +9332,8 @@ void NoteBuiltinOperatorCandidate(Sema &S,
}
}
-void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
- OverloadCandidate *Cand) {
+static void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
+ OverloadCandidate *Cand) {
unsigned NoOperands = Cand->NumConversions;
for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
@@ -9228,6 +9385,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
llvm_unreachable("Unhandled deduction result");
}
+namespace {
struct CompareOverloadCandidatesForDisplay {
Sema &S;
size_t NumArgs;
@@ -9351,11 +9509,12 @@ struct CompareOverloadCandidatesForDisplay {
return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc);
}
};
+}
/// CompleteNonViableCandidate - Normally, overload resolution only
/// computes up to the first. Produces the FixIt set if possible.
-void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
- ArrayRef<Expr *> Args) {
+static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
+ ArrayRef<Expr *> Args) {
assert(!Cand->Viable);
// Don't do anything on failures other than bad conversion.
@@ -9435,8 +9594,6 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
}
}
-} // end anonymous namespace
-
/// PrintOverloadCandidates - When overload resolution fails, prints
/// diagnostic messages containing the candidates in the candidate
/// set.
@@ -9513,6 +9670,7 @@ GetLocationForCandidate(const TemplateSpecCandidate *Cand) {
: SourceLocation();
}
+namespace {
struct CompareTemplateSpecCandidatesForDisplay {
Sema &S;
CompareTemplateSpecCandidatesForDisplay(Sema &S) : S(S) {}
@@ -9543,6 +9701,7 @@ struct CompareTemplateSpecCandidatesForDisplay {
return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc);
}
};
+}
/// Diagnose a template argument deduction failure.
/// We are treating these failures as overload failures due to bad
@@ -9631,10 +9790,10 @@ QualType Sema::ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType) {
return Ret;
}
+namespace {
// A helper class to help with address of function resolution
// - allows us to avoid passing around all those ugly parameters
-class AddressOfFunctionResolver
-{
+class AddressOfFunctionResolver {
Sema& S;
Expr* SourceExpr;
const QualType& TargetType;
@@ -9782,12 +9941,12 @@ private:
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) {
if (S.getLangOpts().CUDA)
if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext))
- if (S.CheckCUDATarget(Caller, FunDecl))
+ if (!Caller->isImplicit() && S.CheckCUDATarget(Caller, FunDecl))
return false;
// If any candidate has a placeholder return type, trigger its deduction
// now.
- if (S.getLangOpts().CPlusPlus1y &&
+ if (S.getLangOpts().CPlusPlus14 &&
FunDecl->getReturnType()->isUndeducedType() &&
S.DeduceReturnType(FunDecl, SourceExpr->getLocStart(), Complain))
return false;
@@ -9960,7 +10119,8 @@ public:
return &Matches[0].first;
}
};
-
+}
+
/// ResolveAddressOfOverloadedFunction - Try to resolve the address of
/// an overloaded function (C++ [over.over]), where @p From is an
/// expression with overloaded function type and @p ToType is the type
@@ -10092,7 +10252,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
if (FoundResult) *FoundResult = I.getPair();
}
- if (Matched && getLangOpts().CPlusPlus1y &&
+ if (Matched && getLangOpts().CPlusPlus14 &&
Matched->getReturnType()->isUndeducedType() &&
DeduceReturnType(Matched, ovl->getExprLoc(), Complain))
return nullptr;
@@ -10422,6 +10582,15 @@ public:
}
+static std::unique_ptr<CorrectionCandidateCallback>
+MakeValidator(Sema &SemaRef, MemberExpr *ME, size_t NumArgs,
+ bool HasTemplateArgs, bool AllowTypoCorrection) {
+ if (!AllowTypoCorrection)
+ return llvm::make_unique<NoTypoCorrectionCCC>();
+ return llvm::make_unique<FunctionCallFilterCCC>(SemaRef, NumArgs,
+ HasTemplateArgs, ME);
+}
+
/// Attempts to recover from a call where no functions were found.
///
/// Returns true if new candidates were found.
@@ -10455,19 +10624,15 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
- FunctionCallFilterCCC Validator(SemaRef, Args.size(),
- ExplicitTemplateArgs != nullptr,
- dyn_cast<MemberExpr>(Fn));
- NoTypoCorrectionCCC RejectAll;
- CorrectionCandidateCallback *CCC = AllowTypoCorrection ?
- (CorrectionCandidateCallback*)&Validator :
- (CorrectionCandidateCallback*)&RejectAll;
if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
OverloadCandidateSet::CSK_Normal,
ExplicitTemplateArgs, Args) &&
(!EmptyLookup ||
- SemaRef.DiagnoseEmptyLookup(S, SS, R, *CCC,
- ExplicitTemplateArgs, Args)))
+ SemaRef.DiagnoseEmptyLookup(
+ S, SS, R,
+ MakeValidator(SemaRef, dyn_cast<MemberExpr>(Fn), Args.size(),
+ ExplicitTemplateArgs != nullptr, AllowTypoCorrection),
+ ExplicitTemplateArgs, Args)))
return ExprError();
assert(!R.empty() && "lookup results empty despite recovery");
@@ -10945,10 +11110,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
- // Add candidates from ADL.
- AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
- /*ExplicitTemplateArgs*/ nullptr,
- CandidateSet);
+ // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
+ // performed for an assignment operator (nor for operator[] nor operator->,
+ // which don't get here).
+ if (Opc != BO_Assign)
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
+ /*ExplicitTemplateArgs*/ nullptr,
+ CandidateSet);
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);
@@ -11031,7 +11199,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Cut off the implicit 'this'.
if (isa<CXXMethodDecl>(FnDecl))
ArgsArray = ArgsArray.slice(1);
- checkCall(FnDecl, ArgsArray, 0, isa<CXXMethodDecl>(FnDecl), OpLoc,
+
+ // Check for a self move.
+ if (Op == OO_Equal)
+ DiagnoseSelfMove(Args[0], Args[1], OpLoc);
+
+ checkCall(FnDecl, ArgsArray, 0, isa<CXXMethodDecl>(FnDecl), OpLoc,
TheCall->getSourceRange(), VariadicDoesNotApply);
return MaybeBindToTemporary(TheCall);
@@ -11352,6 +11525,10 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
<< (qualsString.find(' ') == std::string::npos ? 1 : 2);
}
+ if (resultType->isMemberPointerType())
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft())
+ RequireCompleteType(LParenLoc, resultType, 0);
+
CXXMemberCallExpr *call
= new (Context) CXXMemberCallExpr(Context, MemExprE, Args,
resultType, valueKind, RParenLoc);
@@ -11505,6 +11682,18 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
new (Context) CXXMemberCallExpr(Context, MemExprE, Args,
ResultType, VK, RParenLoc);
+ // (CUDA B.1): Check for invalid calls between targets.
+ if (getLangOpts().CUDA) {
+ if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) {
+ if (CheckCUDATarget(Caller, Method)) {
+ Diag(MemExpr->getMemberLoc(), diag::err_ref_bad_target)
+ << IdentifyCUDATarget(Method) << Method->getIdentifier()
+ << IdentifyCUDATarget(Caller);
+ return ExprError();
+ }
+ }
+ }
+
// Check for a valid return type.
if (CheckCallReturnType(Method->getReturnType(), MemExpr->getMemberLoc(),
TheCall, Method))
@@ -11568,7 +11757,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts))
return ExprError();
- assert(Object.get()->getType()->isRecordType() && "Requires object type argument");
+ assert(Object.get()->getType()->isRecordType() &&
+ "Requires object type argument");
const RecordType *Record = Object.get()->getType()->getAs<RecordType>();
// C++ [over.call.object]p1:
@@ -12272,5 +12462,3 @@ ExprResult Sema::FixOverloadedFunctionReference(ExprResult E,
FunctionDecl *Fn) {
return FixOverloadedFunctionReference(E.get(), Found, Fn);
}
-
-} // end namespace clang
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index aa3e89ed67a9..5e92d5d07c51 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -406,6 +406,10 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
BinaryOperatorKind opcode,
Expr *LHS, Expr *RHS) {
assert(BinaryOperator::isAssignmentOp(opcode));
+
+ // Recover from user error
+ if (isa<UnresolvedLookupExpr>(RHS))
+ return ExprError();
Expr *syntacticLHS = rebuildAndCaptureObject(LHS);
OpaqueValueExpr *capturedRHS = capture(RHS);
@@ -615,7 +619,7 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) {
if (setter->isPropertyAccessor() && warn)
if (const ObjCInterfaceDecl *IFace =
dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) {
- const StringRef thisPropertyName(prop->getName());
+ StringRef thisPropertyName = prop->getName();
// Try flipping the case of the first character.
char front = thisPropertyName.front();
front = isLowercase(front) ? toUppercase(front) : toLowercase(front);
@@ -1022,7 +1026,8 @@ Sema::ObjCSubscriptKind
// If we don't have a class type in C++, there's no way we can get an
// expression of integral or enumeration type.
const RecordType *RecordTy = T->getAs<RecordType>();
- if (!RecordTy && T->isObjCObjectPointerType())
+ if (!RecordTy &&
+ (T->isObjCObjectPointerType() || T->isVoidPointerType()))
// All other scalar cases are assumed to be dictionary indexing which
// caller handles, with diagnostics if needed.
return OS_Dictionary;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 278e6d66828b..22ed93082065 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/TypeLoc.h"
@@ -184,6 +185,12 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
const Expr *E = dyn_cast_or_null<Expr>(S);
if (!E)
return;
+
+ // If we are in an unevaluated expression context, then there can be no unused
+ // results because the results aren't expected to be used in the first place.
+ if (isUnevaluatedContext())
+ return;
+
SourceLocation ExprLoc = E->IgnoreParens()->getExprLoc();
// In most cases, we don't want to warn if the expression is written in a
// macro body, or if the macro comes from a system header. If the offending
@@ -364,6 +371,23 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
return StmtError();
}
+ ExprResult LHS =
+ CorrectDelayedTyposInExpr(LHSVal, [this](class Expr *E) {
+ if (!getLangOpts().CPlusPlus11)
+ return VerifyIntegerConstantExpression(E);
+ if (Expr *CondExpr =
+ getCurFunction()->SwitchStack.back()->getCond()) {
+ QualType CondType = CondExpr->getType();
+ llvm::APSInt TempVal;
+ return CheckConvertedConstantExpression(E, CondType, TempVal,
+ CCEK_CaseValue);
+ }
+ return ExprError();
+ });
+ if (LHS.isInvalid())
+ return StmtError();
+ LHSVal = LHS.get();
+
if (!getLangOpts().CPlusPlus11) {
// C99 6.8.4.2p3: The expression shall be an integer constant.
// However, GCC allows any evaluatable integer expression.
@@ -381,14 +405,19 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
}
}
- LHSVal = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false,
- getLangOpts().CPlusPlus11).get();
- if (RHSVal)
- RHSVal = ActOnFinishFullExpr(RHSVal, RHSVal->getExprLoc(), false,
- getLangOpts().CPlusPlus11).get();
+ LHS = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false,
+ getLangOpts().CPlusPlus11);
+ if (LHS.isInvalid())
+ return StmtError();
+
+ auto RHS = RHSVal ? ActOnFinishFullExpr(RHSVal, RHSVal->getExprLoc(), false,
+ getLangOpts().CPlusPlus11)
+ : ExprResult();
+ if (RHS.isInvalid())
+ return StmtError();
- CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
- ColonLoc);
+ CaseStmt *CS = new (Context)
+ CaseStmt(LHS.get(), RHS.get(), CaseLoc, DotDotDotLoc, ColonLoc);
getCurFunction()->SwitchStack.back()->addSwitchCase(CS);
return CS;
}
@@ -431,7 +460,11 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
TheDecl->setStmt(LS);
if (!TheDecl->isGnuLocal()) {
TheDecl->setLocStart(IdentLoc);
- TheDecl->setLocation(IdentLoc);
+ if (!TheDecl->isMSAsmLabel()) {
+ // Don't update the location of MS ASM labels. These will result in
+ // a diagnostic, and changing the location here will mess that up.
+ TheDecl->setLocation(IdentLoc);
+ }
}
return LS;
}
@@ -481,47 +514,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar,
thenStmt, ElseLoc, elseStmt);
}
-/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
-/// the specified width and sign. If an overflow occurs, detect it and emit
-/// the specified diagnostic.
-void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
- unsigned NewWidth, bool NewSign,
- SourceLocation Loc,
- unsigned DiagID) {
- // Perform a conversion to the promoted condition type if needed.
- if (NewWidth > Val.getBitWidth()) {
- // If this is an extension, just do it.
- Val = Val.extend(NewWidth);
- Val.setIsSigned(NewSign);
-
- // If the input was signed and negative and the output is
- // unsigned, don't bother to warn: this is implementation-defined
- // behavior.
- // FIXME: Introduce a second, default-ignored warning for this case?
- } else if (NewWidth < Val.getBitWidth()) {
- // If this is a truncation, check for overflow.
- llvm::APSInt ConvVal(Val);
- ConvVal = ConvVal.trunc(NewWidth);
- ConvVal.setIsSigned(NewSign);
- ConvVal = ConvVal.extend(Val.getBitWidth());
- ConvVal.setIsSigned(Val.isSigned());
- if (ConvVal != Val)
- Diag(Loc, DiagID) << Val.toString(10) << ConvVal.toString(10);
-
- // Regardless of whether a diagnostic was emitted, really do the
- // truncation.
- Val = Val.trunc(NewWidth);
- Val.setIsSigned(NewSign);
- } else if (NewSign != Val.isSigned()) {
- // Convert the sign to match the sign of the condition. This can cause
- // overflow as well: unsigned(INTMIN)
- // We don't diagnose this overflow, because it is implementation-defined
- // behavior.
- // FIXME: Introduce a second, default-ignored warning for this case?
- Val.setIsSigned(NewSign);
- }
-}
-
namespace {
struct CaseCompareFunctor {
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
@@ -671,33 +663,63 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
}
static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) {
- if (Val.getBitWidth() < BitWidth)
- Val = Val.extend(BitWidth);
- else if (Val.getBitWidth() > BitWidth)
- Val = Val.trunc(BitWidth);
+ Val = Val.extOrTrunc(BitWidth);
Val.setIsSigned(IsSigned);
}
+/// Check the specified case value is in range for the given unpromoted switch
+/// type.
+static void checkCaseValue(Sema &S, SourceLocation Loc, const llvm::APSInt &Val,
+ unsigned UnpromotedWidth, bool UnpromotedSign) {
+ // If the case value was signed and negative and the switch expression is
+ // unsigned, don't bother to warn: this is implementation-defined behavior.
+ // FIXME: Introduce a second, default-ignored warning for this case?
+ if (UnpromotedWidth < Val.getBitWidth()) {
+ llvm::APSInt ConvVal(Val);
+ AdjustAPSInt(ConvVal, UnpromotedWidth, UnpromotedSign);
+ AdjustAPSInt(ConvVal, Val.getBitWidth(), Val.isSigned());
+ // FIXME: Use different diagnostics for overflow in conversion to promoted
+ // type versus "switch expression cannot have this value". Use proper
+ // IntRange checking rather than just looking at the unpromoted type here.
+ if (ConvVal != Val)
+ S.Diag(Loc, diag::warn_case_value_overflow) << Val.toString(10)
+ << ConvVal.toString(10);
+ }
+}
+
+typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
+
/// Returns true if we should emit a diagnostic about this case expression not
/// being a part of the enum used in the switch controlling expression.
-static bool ShouldDiagnoseSwitchCaseNotInEnum(const ASTContext &Ctx,
+static bool ShouldDiagnoseSwitchCaseNotInEnum(const Sema &S,
const EnumDecl *ED,
- const Expr *CaseExpr) {
- // Don't warn if the 'case' expression refers to a static const variable of
- // the enum type.
- CaseExpr = CaseExpr->IgnoreParenImpCasts();
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CaseExpr)) {
+ const Expr *CaseExpr,
+ EnumValsTy::iterator &EI,
+ EnumValsTy::iterator &EIEnd,
+ const llvm::APSInt &Val) {
+ bool FlagType = ED->hasAttr<FlagEnumAttr>();
+
+ if (const DeclRefExpr *DRE =
+ dyn_cast<DeclRefExpr>(CaseExpr->IgnoreParenImpCasts())) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (!VD->hasGlobalStorage())
- return true;
QualType VarType = VD->getType();
- if (!VarType.isConstQualified())
- return true;
- QualType EnumType = Ctx.getTypeDeclType(ED);
- if (Ctx.hasSameUnqualifiedType(EnumType, VarType))
+ QualType EnumType = S.Context.getTypeDeclType(ED);
+ if (VD->hasGlobalStorage() && VarType.isConstQualified() &&
+ S.Context.hasSameUnqualifiedType(EnumType, VarType))
return false;
}
}
+
+ if (FlagType) {
+ return !S.IsValueInFlagEnum(ED, Val, false);
+ } else {
+ while (EI != EIEnd && EI->first < Val)
+ EI++;
+
+ if (EI != EIEnd && EI->first == Val)
+ return false;
+ }
+
return true;
}
@@ -708,9 +730,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
assert(SS == getCurFunction()->SwitchStack.back() &&
"switch stack missing push/pop!");
+ getCurFunction()->SwitchStack.pop_back();
+
if (!BodyStmt) return StmtError();
SS->setBody(BodyStmt, SwitchLoc);
- getCurFunction()->SwitchStack.pop_back();
Expr *CondExpr = SS->getCond();
if (!CondExpr) return StmtError();
@@ -744,13 +767,20 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
}
}
- // Get the bitwidth of the switched-on value before promotions. We must
+ // Get the bitwidth of the switched-on value after promotions. We must
// convert the integer case values to this width before comparison.
bool HasDependentValue
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
- unsigned CondWidth
+ unsigned CondWidth = HasDependentValue ? 0 : Context.getIntWidth(CondType);
+ bool CondIsSigned = CondType->isSignedIntegerOrEnumerationType();
+
+ // Get the width and signedness that the condition might actually have, for
+ // warning purposes.
+ // FIXME: Grab an IntRange for the condition rather than using the unpromoted
+ // type.
+ unsigned CondWidthBeforePromotion
= HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion);
- bool CondIsSigned
+ bool CondIsSignedBeforePromotion
= CondTypeBeforePromotion->isSignedIntegerOrEnumerationType();
// Accumulate all of the case values in a vector so that we can sort them
@@ -816,15 +846,13 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).get();
}
- // Convert the value to the same width/sign as the condition had prior to
- // integral promotions.
- //
- // FIXME: This causes us to reject valid code:
- // switch ((char)c) { case 256: case 0: return 0; }
- // Here we claim there is a duplicated condition value, but there is not.
- ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
- Lo->getLocStart(),
- diag::warn_case_value_overflow);
+ // Check the unconverted value is within the range of possible values of
+ // the switch expression.
+ checkCaseValue(*this, Lo->getLocStart(), LoVal,
+ CondWidthBeforePromotion, CondIsSignedBeforePromotion);
+
+ // Convert the value to the same width/sign as the condition.
+ AdjustAPSInt(LoVal, CondWidth, CondIsSigned);
CS->setLHS(Lo);
@@ -847,9 +875,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
llvm::APSInt ConstantCondValue;
bool HasConstantCond = false;
if (!HasDependentValue && !TheDefaultStmt) {
- HasConstantCond
- = CondExprBeforePromotion->EvaluateAsInt(ConstantCondValue, Context,
- Expr::SE_AllowSideEffects);
+ HasConstantCond = CondExpr->EvaluateAsInt(ConstantCondValue, Context,
+ Expr::SE_AllowSideEffects);
assert(!HasConstantCond ||
(ConstantCondValue.getBitWidth() == CondWidth &&
ConstantCondValue.isSigned() == CondIsSigned));
@@ -935,10 +962,13 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).get();
}
+ // Check the unconverted value is within the range of possible values of
+ // the switch expression.
+ checkCaseValue(*this, Hi->getLocStart(), HiVal,
+ CondWidthBeforePromotion, CondIsSignedBeforePromotion);
+
// Convert the value to the same width/sign as the condition.
- ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
- Hi->getLocStart(),
- diag::warn_case_value_overflow);
+ AdjustAPSInt(HiVal, CondWidth, CondIsSigned);
CR->setRHS(Hi);
@@ -1029,8 +1059,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// If switch has default case, then ignore it.
if (!CaseListIsErroneous && !HasConstantCond && ET) {
const EnumDecl *ED = ET->getDecl();
- typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64>
- EnumValsTy;
EnumValsTy EnumVals;
// Gather all enum values, set their type and sort them,
@@ -1041,57 +1069,48 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
EnumVals.push_back(std::make_pair(Val, EDI));
}
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
- EnumValsTy::iterator EIend =
+ auto EI = EnumVals.begin(), EIEnd =
std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
// See which case values aren't in enum.
- EnumValsTy::const_iterator EI = EnumVals.begin();
for (CaseValsTy::const_iterator CI = CaseVals.begin();
- CI != CaseVals.end(); CI++) {
- while (EI != EIend && EI->first < CI->first)
- EI++;
- if (EI == EIend || EI->first > CI->first) {
- Expr *CaseExpr = CI->second->getLHS();
- if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr))
- Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
- << CondTypeBeforePromotion;
- }
+ CI != CaseVals.end(); CI++) {
+ Expr *CaseExpr = CI->second->getLHS();
+ if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd,
+ CI->first))
+ Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
}
+
// See which of case ranges aren't in enum
EI = EnumVals.begin();
for (CaseRangesTy::const_iterator RI = CaseRanges.begin();
- RI != CaseRanges.end() && EI != EIend; RI++) {
- while (EI != EIend && EI->first < RI->first)
- EI++;
-
- if (EI == EIend || EI->first != RI->first) {
- Expr *CaseExpr = RI->second->getLHS();
- if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr))
- Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
- << CondTypeBeforePromotion;
- }
+ RI != CaseRanges.end(); RI++) {
+ Expr *CaseExpr = RI->second->getLHS();
+ if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd,
+ RI->first))
+ Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
llvm::APSInt Hi =
RI->second->getRHS()->EvaluateKnownConstInt(Context);
AdjustAPSInt(Hi, CondWidth, CondIsSigned);
- while (EI != EIend && EI->first < Hi)
- EI++;
- if (EI == EIend || EI->first != Hi) {
- Expr *CaseExpr = RI->second->getRHS();
- if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr))
- Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
- << CondTypeBeforePromotion;
- }
+
+ CaseExpr = RI->second->getRHS();
+ if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd,
+ Hi))
+ Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
}
// Check which enum vals aren't in switch
- CaseValsTy::const_iterator CI = CaseVals.begin();
- CaseRangesTy::const_iterator RI = CaseRanges.begin();
+ auto CI = CaseVals.begin();
+ auto RI = CaseRanges.begin();
bool hasCasesNotInSwitch = false;
SmallVector<DeclarationName,8> UnhandledNames;
- for (EI = EnumVals.begin(); EI != EIend; EI++){
+ for (EI = EnumVals.begin(); EI != EIEnd; EI++){
// Drop unneeded case values
while (CI != CaseVals.end() && CI->first < EI->first)
CI++;
@@ -1178,30 +1197,37 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context);
AdjustAPSInt(RhsVal, DstWidth, DstIsSigned);
const EnumDecl *ED = ET->getDecl();
- typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64>
- EnumValsTy;
- EnumValsTy EnumVals;
-
- // Gather all enum values, set their type and sort them,
- // allowing easier comparison with rhs constant.
- for (auto *EDI : ED->enumerators()) {
- llvm::APSInt Val = EDI->getInitVal();
- AdjustAPSInt(Val, DstWidth, DstIsSigned);
- EnumVals.push_back(std::make_pair(Val, EDI));
- }
- if (EnumVals.empty())
- return;
- std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
- EnumValsTy::iterator EIend =
- std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
-
- // See which values aren't in the enum.
- EnumValsTy::const_iterator EI = EnumVals.begin();
- while (EI != EIend && EI->first < RhsVal)
- EI++;
- if (EI == EIend || EI->first != RhsVal) {
- Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
+
+ if (ED->hasAttr<FlagEnumAttr>()) {
+ if (!IsValueInFlagEnum(ED, RhsVal, true))
+ Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
<< DstType.getUnqualifiedType();
+ } else {
+ typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64>
+ EnumValsTy;
+ EnumValsTy EnumVals;
+
+ // Gather all enum values, set their type and sort them,
+ // allowing easier comparison with rhs constant.
+ for (auto *EDI : ED->enumerators()) {
+ llvm::APSInt Val = EDI->getInitVal();
+ AdjustAPSInt(Val, DstWidth, DstIsSigned);
+ EnumVals.push_back(std::make_pair(Val, EDI));
+ }
+ if (EnumVals.empty())
+ return;
+ std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
+ EnumValsTy::iterator EIend =
+ std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
+
+ // See which values aren't in the enum.
+ EnumValsTy::const_iterator EI = EnumVals.begin();
+ while (EI != EIend && EI->first < RhsVal)
+ EI++;
+ if (EI == EIend || EI->first != RhsVal) {
+ Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
+ << DstType.getUnqualifiedType();
+ }
}
}
}
@@ -1260,13 +1286,13 @@ namespace {
// the evaluated decls into a vector. Simple is set to true if none
// of the excluded constructs are used.
class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> {
- llvm::SmallPtrSet<VarDecl*, 8> &Decls;
+ llvm::SmallPtrSetImpl<VarDecl*> &Decls;
SmallVectorImpl<SourceRange> &Ranges;
bool Simple;
public:
typedef EvaluatedExprVisitor<DeclExtractor> Inherited;
- DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls,
+ DeclExtractor(Sema &S, llvm::SmallPtrSetImpl<VarDecl*> &Decls,
SmallVectorImpl<SourceRange> &Ranges) :
Inherited(S.Context),
Decls(Decls),
@@ -1338,13 +1364,13 @@ namespace {
// DeclMatcher checks to see if the decls are used in a non-evauluated
// context.
class DeclMatcher : public EvaluatedExprVisitor<DeclMatcher> {
- llvm::SmallPtrSet<VarDecl*, 8> &Decls;
+ llvm::SmallPtrSetImpl<VarDecl*> &Decls;
bool FoundDecl;
public:
typedef EvaluatedExprVisitor<DeclMatcher> Inherited;
- DeclMatcher(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls,
+ DeclMatcher(Sema &S, llvm::SmallPtrSetImpl<VarDecl*> &Decls,
Stmt *Statement) :
Inherited(S.Context), Decls(Decls), FoundDecl(false) {
if (!Statement) return;
@@ -1427,8 +1453,8 @@ namespace {
if (Decls.size() == 0) return;
// Don't warn on volatile, static, or global variables.
- for (llvm::SmallPtrSet<VarDecl*, 8>::iterator I = Decls.begin(),
- E = Decls.end();
+ for (llvm::SmallPtrSetImpl<VarDecl*>::iterator I = Decls.begin(),
+ E = Decls.end();
I != E; ++I)
if ((*I)->getType().isVolatileQualified() ||
(*I)->hasGlobalStorage()) return;
@@ -1443,8 +1469,8 @@ namespace {
PDiag << 0;
else {
PDiag << Decls.size();
- for (llvm::SmallPtrSet<VarDecl*, 8>::iterator I = Decls.begin(),
- E = Decls.end();
+ for (llvm::SmallPtrSetImpl<VarDecl*>::iterator I = Decls.begin(),
+ E = Decls.end();
I != E; ++I)
PDiag << (*I)->getDeclName();
}
@@ -1660,11 +1686,16 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
if (!collection)
return ExprError();
+ ExprResult result = CorrectDelayedTyposInExpr(collection);
+ if (!result.isUsable())
+ return ExprError();
+ collection = result.get();
+
// Bail out early if we've got a type-dependent expression.
if (collection->isTypeDependent()) return collection;
// Perform normal l-value conversion.
- ExprResult result = DefaultFunctionArrayLvalueConversion(collection);
+ result = DefaultFunctionArrayLvalueConversion(collection);
if (result.isInvalid())
return ExprError();
collection = result.get();
@@ -2453,7 +2484,7 @@ VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType,
// - in a return statement in a function [where] ...
// ... the expression is the name of a non-volatile automatic object ...
DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens());
- if (!DR || DR->refersToEnclosingLocal())
+ if (!DR || DR->refersToEnclosingVariableOrCapture())
return nullptr;
VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
if (!VD)
@@ -2621,8 +2652,12 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
return StmtError();
RetValExp = Result.get();
+ // DR1048: even prior to C++14, we should use the 'auto' deduction rules
+ // when deducing a return type for a lambda-expression (or by extension
+ // for a block). These rules differ from the stated C++11 rules only in
+ // that they remove top-level cv-qualifiers.
if (!CurContext->isDependentContext())
- FnRetType = RetValExp->getType();
+ FnRetType = RetValExp->getType().getUnqualifiedType();
else
FnRetType = CurCap->ReturnType = Context.DependentTy;
} else {
@@ -2727,14 +2762,54 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
return Result;
}
+namespace {
+/// \brief Marks all typedefs in all local classes in a type referenced.
+///
+/// In a function like
+/// auto f() {
+/// struct S { typedef int a; };
+/// return S();
+/// }
+///
+/// the local type escapes and could be referenced in some TUs but not in
+/// others. Pretend that all local typedefs are always referenced, to not warn
+/// on this. This isn't necessary if f has internal linkage, or the typedef
+/// is private.
+class LocalTypedefNameReferencer
+ : public RecursiveASTVisitor<LocalTypedefNameReferencer> {
+public:
+ LocalTypedefNameReferencer(Sema &S) : S(S) {}
+ bool VisitRecordType(const RecordType *RT);
+private:
+ Sema &S;
+};
+bool LocalTypedefNameReferencer::VisitRecordType(const RecordType *RT) {
+ auto *R = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!R || !R->isLocalClass() || !R->isLocalClass()->isExternallyVisible() ||
+ R->isDependentType())
+ return true;
+ for (auto *TmpD : R->decls())
+ if (auto *T = dyn_cast<TypedefNameDecl>(TmpD))
+ if (T->getAccess() != AS_private || R->hasFriends())
+ S.MarkAnyDeclReferenced(T->getLocation(), T, /*OdrUse=*/false);
+ return true;
+}
+}
+
+TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const {
+ TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
+ while (auto ATL = TL.getAs<AttributedTypeLoc>())
+ TL = ATL.getModifiedLoc().IgnoreParens();
+ return TL.castAs<FunctionProtoTypeLoc>().getReturnLoc();
+}
+
/// Deduce the return type for a function from a returned expression, per
/// C++1y [dcl.spec.auto]p6.
bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
SourceLocation ReturnLoc,
Expr *&RetExpr,
AutoType *AT) {
- TypeLoc OrigResultType = FD->getTypeSourceInfo()->getTypeLoc().
- IgnoreParens().castAs<FunctionProtoTypeLoc>().getReturnLoc();
+ TypeLoc OrigResultType = getReturnTypeLoc(FD);
QualType Deduced;
if (RetExpr && isa<InitListExpr>(RetExpr)) {
@@ -2772,6 +2847,11 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
if (DAR != DAR_Succeeded)
return true;
+
+ // If a local type is part of the returned type, mark its fields as
+ // referenced.
+ LocalTypedefNameReferencer Referencer(*this);
+ Referencer.TraverseType(RetExpr->getType());
} else {
// In the case of a return with no operand, the initializer is considered
// to be void().
@@ -2872,7 +2952,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// FIXME: Add a flag to the ScopeInfo to indicate whether we're performing
// deduction.
- if (getLangOpts().CPlusPlus1y) {
+ if (getLangOpts().CPlusPlus14) {
if (AutoType *AT = FnRetType->getContainedAutoType()) {
FunctionDecl *FD = cast<FunctionDecl>(CurContext);
if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
@@ -2964,14 +3044,26 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr);
} else if (!RetValExp && !HasDependentReturnType) {
- unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4
- // C99 6.8.6.4p1 (ext_ since GCC warns)
- if (getLangOpts().C99) DiagID = diag::ext_return_missing_expr;
+ FunctionDecl *FD = getCurFunctionDecl();
- if (FunctionDecl *FD = getCurFunctionDecl())
+ unsigned DiagID;
+ if (getLangOpts().CPlusPlus11 && FD && FD->isConstexpr()) {
+ // C++11 [stmt.return]p2
+ DiagID = diag::err_constexpr_return_missing_expr;
+ FD->setInvalidDecl();
+ } else if (getLangOpts().C99) {
+ // C99 6.8.6.4p1 (ext_ since GCC warns)
+ DiagID = diag::ext_return_missing_expr;
+ } else {
+ // C90 6.6.6.4p4
+ DiagID = diag::warn_return_missing_expr;
+ }
+
+ if (FD)
Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
else
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
+
Result = new (Context) ReturnStmt(ReturnLoc);
} else {
assert(RetValExp || HasDependentReturnType);
@@ -3119,9 +3211,24 @@ Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) {
if (!type->isDependentType() &&
!type->isObjCObjectPointerType()) {
const PointerType *pointerType = type->getAs<PointerType>();
- if (!pointerType || !pointerType->getPointeeType()->isVoidType())
- return Diag(atLoc, diag::error_objc_synchronized_expects_object)
- << type << operand->getSourceRange();
+ if (!pointerType || !pointerType->getPointeeType()->isVoidType()) {
+ if (getLangOpts().CPlusPlus) {
+ if (RequireCompleteType(atLoc, type,
+ diag::err_incomplete_receiver_type))
+ return Diag(atLoc, diag::error_objc_synchronized_expects_object)
+ << type << operand->getSourceRange();
+
+ ExprResult result = PerformContextuallyConvertToObjCPointer(operand);
+ if (!result.isUsable())
+ return Diag(atLoc, diag::error_objc_synchronized_expects_object)
+ << type << operand->getSourceRange();
+
+ operand = result.get();
+ } else {
+ return Diag(atLoc, diag::error_objc_synchronized_expects_object)
+ << type << operand->getSourceRange();
+ }
+ }
}
// The operand to @synchronized is a full-expression.
@@ -3249,15 +3356,16 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
return CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers);
}
-StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
- Stmt *TryBlock, Stmt *Handler,
- int HandlerIndex, int HandlerParentIndex) {
+StmtResult
+Sema::ActOnSEHTryBlock(bool IsCXXTry,
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler) {
assert(TryBlock && Handler);
getCurFunction()->setHasBranchProtectedScope();
- return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler,
- HandlerIndex, HandlerParentIndex);
+ return SEHTryStmt::Create(Context,IsCXXTry,TryLoc,TryBlock,Handler);
}
StmtResult
@@ -3330,6 +3438,7 @@ Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc,
else
RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/nullptr);
+ RD->setCapturedRecord();
DC->addDecl(RD);
RD->setImplicit();
RD->startDefinition();
@@ -3353,6 +3462,11 @@ static void buildCapturedStmtCaptureList(
CapturedStmt::VCK_This));
CaptureInits.push_back(Cap->getInitExpr());
continue;
+ } else if (Cap->isVLATypeCapture()) {
+ Captures.push_back(
+ CapturedStmt::Capture(Cap->getLocation(), CapturedStmt::VCK_VLAType));
+ CaptureInits.push_back(nullptr);
+ continue;
}
assert(Cap->isReferenceCapture() &&
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 5d076cac940f..286c7619ed40 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
@@ -74,6 +75,32 @@ static bool isOperandMentioned(unsigned OpNo,
return false;
}
+static bool CheckNakedParmReference(Expr *E, Sema &S) {
+ FunctionDecl *Func = dyn_cast<FunctionDecl>(S.CurContext);
+ if (!Func)
+ return false;
+ if (!Func->hasAttr<NakedAttr>())
+ return false;
+
+ SmallVector<Expr*, 4> WorkList;
+ WorkList.push_back(E);
+ while (WorkList.size()) {
+ Expr *E = WorkList.pop_back_val();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (isa<ParmVarDecl>(DRE->getDecl())) {
+ S.Diag(DRE->getLocStart(), diag::err_asm_naked_parm_ref);
+ S.Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute);
+ return true;
+ }
+ }
+ for (Stmt *Child : E->children()) {
+ if (Expr *E = dyn_cast_or_null<Expr>(Child))
+ WorkList.push_back(E);
+ }
+ }
+ return false;
+}
+
StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
bool IsVolatile, unsigned NumOutputs,
unsigned NumInputs, IdentifierInfo **Names,
@@ -89,15 +116,11 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
// The parser verifies that there is a string literal here.
- if (!AsmString->isAscii())
- return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
- << AsmString->getSourceRange());
+ assert(AsmString->isAscii());
for (unsigned i = 0; i != NumOutputs; i++) {
StringLiteral *Literal = Constraints[i];
- if (!Literal->isAscii())
- return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
- << Literal->getSourceRange());
+ assert(Literal->isAscii());
StringRef OutputName;
if (Names[i])
@@ -109,27 +132,69 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
diag::err_asm_invalid_output_constraint)
<< Info.getConstraintStr());
+ ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
+ if (ER.isInvalid())
+ return StmtError();
+ Exprs[i] = ER.get();
+
// Check that the output exprs are valid lvalues.
Expr *OutputExpr = Exprs[i];
- if (CheckAsmLValue(OutputExpr, *this))
- return StmtError(Diag(OutputExpr->getLocStart(),
- diag::err_asm_invalid_lvalue_in_output)
- << OutputExpr->getSourceRange());
- if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(),
- diag::err_dereference_incomplete_type))
+ // Referring to parameters is not allowed in naked functions.
+ if (CheckNakedParmReference(OutputExpr, *this))
return StmtError();
OutputConstraintInfos.push_back(Info);
+
+ // If this is dependent, just continue.
+ if (OutputExpr->isTypeDependent())
+ continue;
+
+ Expr::isModifiableLvalueResult IsLV =
+ OutputExpr->isModifiableLvalue(Context, /*Loc=*/nullptr);
+ switch (IsLV) {
+ case Expr::MLV_Valid:
+ // Cool, this is an lvalue.
+ break;
+ case Expr::MLV_ArrayType:
+ // This is OK too.
+ break;
+ case Expr::MLV_LValueCast: {
+ const Expr *LVal = OutputExpr->IgnoreParenNoopCasts(Context);
+ if (!getLangOpts().HeinousExtensions) {
+ Diag(LVal->getLocStart(), diag::err_invalid_asm_cast_lvalue)
+ << OutputExpr->getSourceRange();
+ } else {
+ Diag(LVal->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
+ << OutputExpr->getSourceRange();
+ }
+ // Accept, even if we emitted an error diagnostic.
+ break;
+ }
+ case Expr::MLV_IncompleteType:
+ case Expr::MLV_IncompleteVoidType:
+ if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(),
+ diag::err_dereference_incomplete_type))
+ return StmtError();
+ default:
+ return StmtError(Diag(OutputExpr->getLocStart(),
+ diag::err_asm_invalid_lvalue_in_output)
+ << OutputExpr->getSourceRange());
+ }
+
+ unsigned Size = Context.getTypeSize(OutputExpr->getType());
+ if (!Context.getTargetInfo().validateOutputSize(Literal->getString(),
+ Size))
+ return StmtError(Diag(OutputExpr->getLocStart(),
+ diag::err_asm_invalid_output_size)
+ << Info.getConstraintStr());
}
SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
StringLiteral *Literal = Constraints[i];
- if (!Literal->isAscii())
- return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
- << Literal->getSourceRange());
+ assert(Literal->isAscii());
StringRef InputName;
if (Names[i])
@@ -143,8 +208,17 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
<< Info.getConstraintStr());
}
+ ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
+ if (ER.isInvalid())
+ return StmtError();
+ Exprs[i] = ER.get();
+
Expr *InputExpr = Exprs[i];
+ // Referring to parameters is not allowed in naked functions.
+ if (CheckNakedParmReference(InputExpr, *this))
+ return StmtError();
+
// Only allow void types for memory constraints.
if (Info.allowsMemory() && !Info.allowsRegister()) {
if (CheckAsmLValue(InputExpr, *this))
@@ -152,6 +226,20 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
diag::err_asm_invalid_lvalue_in_input)
<< Info.getConstraintStr()
<< InputExpr->getSourceRange());
+ } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) {
+ llvm::APSInt Result;
+ if (!InputExpr->EvaluateAsInt(Result, Context))
+ return StmtError(
+ Diag(InputExpr->getLocStart(), diag::err_asm_invalid_type_in_input)
+ << InputExpr->getType() << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
+ if (Result.slt(Info.getImmConstantMin()) ||
+ Result.sgt(Info.getImmConstantMax()))
+ return StmtError(Diag(InputExpr->getLocStart(),
+ diag::err_invalid_asm_value_for_constraint)
+ << Result.toString(10) << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
+
} else {
ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
if (Result.isInvalid())
@@ -191,9 +279,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Check that the clobbers are valid.
for (unsigned i = 0; i != NumClobbers; i++) {
StringLiteral *Literal = Clobbers[i];
- if (!Literal->isAscii())
- return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
- << Literal->getSourceRange());
+ assert(Literal->isAscii());
StringRef Clobber = Literal->getString();
@@ -257,16 +343,47 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
continue;
unsigned Size = Context.getTypeSize(Ty);
- if (!Context.getTargetInfo()
- .validateConstraintModifier(Literal->getString(), Piece.getModifier(),
- Size))
+ std::string SuggestedModifier;
+ if (!Context.getTargetInfo().validateConstraintModifier(
+ Literal->getString(), Piece.getModifier(), Size,
+ SuggestedModifier)) {
Diag(Exprs[ConstraintIdx]->getLocStart(),
diag::warn_asm_mismatched_size_modifier);
+
+ if (!SuggestedModifier.empty()) {
+ auto B = Diag(Piece.getRange().getBegin(),
+ diag::note_asm_missing_constraint_modifier)
+ << SuggestedModifier;
+ SuggestedModifier = "%" + SuggestedModifier + Piece.getString();
+ B.AddFixItHint(FixItHint::CreateReplacement(Piece.getRange(),
+ SuggestedModifier));
+ }
+ }
}
// Validate tied input operands for type mismatches.
+ unsigned NumAlternatives = ~0U;
+ for (unsigned i = 0, e = OutputConstraintInfos.size(); i != e; ++i) {
+ TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
+ StringRef ConstraintStr = Info.getConstraintStr();
+ unsigned AltCount = ConstraintStr.count(',') + 1;
+ if (NumAlternatives == ~0U)
+ NumAlternatives = AltCount;
+ else if (NumAlternatives != AltCount)
+ return StmtError(Diag(NS->getOutputExpr(i)->getLocStart(),
+ diag::err_asm_unexpected_constraint_alternatives)
+ << NumAlternatives << AltCount);
+ }
for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
+ StringRef ConstraintStr = Info.getConstraintStr();
+ unsigned AltCount = ConstraintStr.count(',') + 1;
+ if (NumAlternatives == ~0U)
+ NumAlternatives = AltCount;
+ else if (NumAlternatives != AltCount)
+ return StmtError(Diag(NS->getInputExpr(i)->getLocStart(),
+ diag::err_asm_unexpected_constraint_alternatives)
+ << NumAlternatives << AltCount);
// If this is a tied constraint, verify that the output and input have
// either exactly the same type, or that they are int/ptr operands with the
@@ -394,6 +511,10 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
Result = CheckPlaceholderExpr(Result.get());
if (!Result.isUsable()) return Result;
+ // Referring to parameters is not allowed in naked functions.
+ if (CheckNakedParmReference(Result.get(), *this))
+ return ExprError();
+
QualType T = Result.get()->getType();
// For now, reject dependent types.
@@ -443,9 +564,10 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
NamedDecl *FoundDecl = BaseResult.getFoundDecl();
if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
RT = VD->getType()->getAs<RecordType>();
- else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl))
+ else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) {
+ MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
RT = TD->getUnderlyingType()->getAs<RecordType>();
- else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl))
+ } else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl))
RT = TD->getTypeForDecl()->getAs<RecordType>();
if (!RT)
return true;
@@ -481,6 +603,7 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
ArrayRef<Expr*> Exprs,
SourceLocation EndLoc) {
bool IsSimple = (NumOutputs != 0 || NumInputs != 0);
+ getCurFunction()->setHasBranchProtectedScope();
MSAsmStmt *NS =
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
/*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs,
@@ -488,3 +611,34 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
Clobbers, EndLoc);
return NS;
}
+
+LabelDecl *Sema::GetOrCreateMSAsmLabel(StringRef ExternalLabelName,
+ SourceLocation Location,
+ bool AlwaysCreate) {
+ LabelDecl* Label = LookupOrCreateLabel(PP.getIdentifierInfo(ExternalLabelName),
+ Location);
+
+ if (Label->isMSAsmLabel()) {
+ // If we have previously created this label implicitly, mark it as used.
+ Label->markUsed(Context);
+ } else {
+ // Otherwise, insert it, but only resolve it if we have seen the label itself.
+ std::string InternalName;
+ llvm::raw_string_ostream OS(InternalName);
+ // Create an internal name for the label. The name should not be a valid mangled
+ // name, and should be unique. We use a dot to make the name an invalid mangled
+ // name.
+ OS << "__MSASMLABEL_." << MSAsmLabelNameCounter++ << "__" << ExternalLabelName;
+ Label->setMSAsmLabel(OS.str());
+ }
+ if (AlwaysCreate) {
+ // The label might have been created implicitly from a previously encountered
+ // goto statement. So, for both newly created and looked up labels, we mark
+ // them as resolved.
+ Label->setMSAsmLabelResolved();
+ }
+ // Adjust their location for being able to generate accurate diagnostics.
+ Label->setLocation(Location);
+
+ return Label;
+}
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index a32e0fbcb622..19e2c8ed652f 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -47,30 +47,36 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
SourceRange) {
IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
- IdentifierInfo *OptionInfo = OptionLoc->Ident;
- IdentifierLoc *ValueLoc = A.getArgAsIdent(2);
- IdentifierInfo *ValueInfo = ValueLoc ? ValueLoc->Ident : nullptr;
+ IdentifierLoc *StateLoc = A.getArgAsIdent(2);
Expr *ValueExpr = A.getArgAsExpr(3);
- assert(OptionInfo && "Attribute must have valid option info.");
-
+ bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll";
+ bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll";
if (St->getStmtClass() != Stmt::DoStmtClass &&
St->getStmtClass() != Stmt::ForStmtClass &&
St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
St->getStmtClass() != Stmt::WhileStmtClass) {
- const char *Pragma = PragmaNameLoc->Ident->getName() == "unroll"
- ? "#pragma unroll"
- : "#pragma clang loop";
+ const char *Pragma =
+ llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName())
+ .Case("unroll", "#pragma unroll")
+ .Case("nounroll", "#pragma nounroll")
+ .Default("#pragma clang loop");
S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
return nullptr;
}
LoopHintAttr::OptionType Option;
LoopHintAttr::Spelling Spelling;
- if (PragmaNameLoc->Ident->getName() == "unroll") {
- Option = ValueLoc ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll;
+ if (PragmaUnroll) {
+ Option = ValueExpr ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll;
Spelling = LoopHintAttr::Pragma_unroll;
+ } else if (PragmaNoUnroll) {
+ Option = LoopHintAttr::Unroll;
+ Spelling = LoopHintAttr::Pragma_nounroll;
} else {
+ assert(OptionLoc && OptionLoc->Ident &&
+ "Attribute must have valid option info.");
+ IdentifierInfo *OptionInfo = OptionLoc->Ident;
Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
.Case("vectorize", LoopHintAttr::Vectorize)
.Case("vectorize_width", LoopHintAttr::VectorizeWidth)
@@ -82,53 +88,45 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
Spelling = LoopHintAttr::Pragma_clang_loop;
}
- int ValueInt;
- if (Option == LoopHintAttr::Unroll &&
- Spelling == LoopHintAttr::Pragma_unroll) {
- ValueInt = 1;
- } else if (Option == LoopHintAttr::Vectorize ||
- Option == LoopHintAttr::Interleave ||
- Option == LoopHintAttr::Unroll) {
- if (!ValueInfo) {
- S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
- return nullptr;
- }
- if (ValueInfo->isStr("disable"))
- ValueInt = 0;
- else if (ValueInfo->isStr("enable"))
- ValueInt = 1;
- else {
- S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
- return nullptr;
- }
+ LoopHintAttr::LoopHintState State = LoopHintAttr::Default;
+ if (PragmaNoUnroll) {
+ State = LoopHintAttr::Disable;
} else if (Option == LoopHintAttr::VectorizeWidth ||
Option == LoopHintAttr::InterleaveCount ||
Option == LoopHintAttr::UnrollCount) {
- // FIXME: We should support template parameters for the loop hint value.
- // See bug report #19610.
- llvm::APSInt ValueAPS;
- if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context) ||
- (ValueInt = ValueAPS.getSExtValue()) < 1) {
- S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value);
+ assert(ValueExpr && "Attribute must have a valid value expression.");
+ if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart()))
return nullptr;
+ } else if (Option == LoopHintAttr::Vectorize ||
+ Option == LoopHintAttr::Interleave ||
+ Option == LoopHintAttr::Unroll) {
+ // Default state is assumed if StateLoc is not specified, such as with
+ // '#pragma unroll'.
+ if (StateLoc && StateLoc->Ident) {
+ if (StateLoc->Ident->isStr("disable"))
+ State = LoopHintAttr::Disable;
+ else
+ State = LoopHintAttr::Enable;
}
- } else
- llvm_unreachable("Unknown loop hint option");
+ }
- return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, ValueInt,
- A.getRange());
+ return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
+ ValueExpr, A.getRange());
}
-static void CheckForIncompatibleAttributes(
- Sema &S, const SmallVectorImpl<const Attr *> &Attrs) {
- // There are 3 categories of loop hints: vectorize, interleave, and
- // unroll. Each comes in two variants: an enable/disable form and a
- // form which takes a numeric argument. For example:
- // unroll(enable|disable) and unroll_count(N). The following array
- // accumulate the hints encountered while iterating through the
- // attributes to check for compatibility.
+static void
+CheckForIncompatibleAttributes(Sema &S,
+ const SmallVectorImpl<const Attr *> &Attrs) {
+ // There are 3 categories of loop hints attributes: vectorize, interleave,
+ // and unroll. Each comes in two variants: a state form and a numeric form.
+ // The state form selectively defaults/enables/disables the transformation
+ // for the loop (for unroll, default indicates full unrolling rather than
+ // enabling the transformation). The numeric form form provides an integer
+ // hint (for example, unroll count) to the transformer. The following array
+ // accumulates the hints encountered while iterating through the attributes
+ // to check for compatibility.
struct {
- const LoopHintAttr *EnableAttr;
+ const LoopHintAttr *StateAttr;
const LoopHintAttr *NumericAttr;
} HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}};
@@ -141,49 +139,53 @@ static void CheckForIncompatibleAttributes(
int Option = LH->getOption();
int Category;
+ enum { Vectorize, Interleave, Unroll };
switch (Option) {
case LoopHintAttr::Vectorize:
case LoopHintAttr::VectorizeWidth:
- Category = 0;
+ Category = Vectorize;
break;
case LoopHintAttr::Interleave:
case LoopHintAttr::InterleaveCount:
- Category = 1;
+ Category = Interleave;
break;
case LoopHintAttr::Unroll:
case LoopHintAttr::UnrollCount:
- Category = 2;
+ Category = Unroll;
break;
};
auto &CategoryState = HintAttrs[Category];
- SourceLocation OptionLoc = LH->getRange().getBegin();
const LoopHintAttr *PrevAttr;
if (Option == LoopHintAttr::Vectorize ||
Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) {
// Enable|disable hint. For example, vectorize(enable).
- PrevAttr = CategoryState.EnableAttr;
- CategoryState.EnableAttr = LH;
+ PrevAttr = CategoryState.StateAttr;
+ CategoryState.StateAttr = LH;
} else {
// Numeric hint. For example, vectorize_width(8).
PrevAttr = CategoryState.NumericAttr;
CategoryState.NumericAttr = LH;
}
+ PrintingPolicy Policy(S.Context.getLangOpts());
+ SourceLocation OptionLoc = LH->getRange().getBegin();
if (PrevAttr)
// Cannot specify same type of attribute twice.
S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
- << /*Duplicate=*/true << PrevAttr->getDiagnosticName()
- << LH->getDiagnosticName();
-
- if (CategoryState.EnableAttr && !CategoryState.EnableAttr->getValue() &&
- CategoryState.NumericAttr) {
- // Disable hints are not compatible with numeric hints of the
- // same category.
+ << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy)
+ << LH->getDiagnosticName(Policy);
+
+ if (CategoryState.StateAttr && CategoryState.NumericAttr &&
+ (Category == Unroll ||
+ CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) {
+ // Disable hints are not compatible with numeric hints of the same
+ // category. As a special case, numeric unroll hints are also not
+ // compatible with "enable" form of the unroll pragma, unroll(full).
S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
<< /*Duplicate=*/false
- << CategoryState.EnableAttr->getDiagnosticName()
- << CategoryState.NumericAttr->getDiagnosticName();
+ << CategoryState.StateAttr->getDiagnosticName(Policy)
+ << CategoryState.NumericAttr->getDiagnosticName(Policy);
}
}
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 7e8f0b721dfe..67c36a5fb5e9 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -107,7 +107,7 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R,
// template itself and not a specialization thereof, and is not
// ambiguous.
if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl))
- if (!ClassTemplates.insert(ClassTmpl)) {
+ if (!ClassTemplates.insert(ClassTmpl).second) {
filter.erase();
continue;
}
@@ -318,15 +318,14 @@ void Sema::LookupTemplateName(LookupResult &Found,
DeclarationName Name = Found.getLookupName();
Found.clear();
// Simple filter callback that, for keywords, only accepts the C++ *_cast
- CorrectionCandidateCallback FilterCCC;
- FilterCCC.WantTypeSpecifiers = false;
- FilterCCC.WantExpressionKeywords = false;
- FilterCCC.WantRemainingKeywords = false;
- FilterCCC.WantCXXNamedCasts = true;
- if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(),
- Found.getLookupKind(), S, &SS,
- FilterCCC, CTK_ErrorRecovery,
- LookupCtx)) {
+ auto FilterCCC = llvm::make_unique<CorrectionCandidateCallback>();
+ FilterCCC->WantTypeSpecifiers = false;
+ FilterCCC->WantExpressionKeywords = false;
+ FilterCCC->WantRemainingKeywords = false;
+ FilterCCC->WantCXXNamedCasts = true;
+ if (TypoCorrection Corrected = CorrectTypo(
+ Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS,
+ std::move(FilterCCC), CTK_ErrorRecovery, LookupCtx)) {
Found.setLookupName(Corrected.getCorrection());
if (Corrected.getCorrectionDecl())
Found.addDecl(Corrected.getCorrectionDecl());
@@ -652,12 +651,8 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
// A non-type template-parameter of type "array of T" or
// "function returning T" is adjusted to be of type "pointer to
// T" or "pointer to function returning T", respectively.
- else if (T->isArrayType())
- // FIXME: Keep the type prior to promotion?
- return Context.getArrayDecayedType(T);
- else if (T->isFunctionType())
- // FIXME: Keep the type prior to promotion?
- return Context.getPointerType(T);
+ else if (T->isArrayType() || T->isFunctionType())
+ return Context.getDecayedType(T);
Diag(Loc, diag::err_template_nontype_parm_bad_type)
<< T;
@@ -720,7 +715,8 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
return Param;
TemplateArgument Converted;
- ExprResult DefaultRes = CheckTemplateArgument(Param, Param->getType(), Default, Converted);
+ ExprResult DefaultRes =
+ CheckTemplateArgument(Param, Param->getType(), Default, Converted);
if (DefaultRes.isInvalid()) {
Param->setInvalidDecl();
return Param;
@@ -1105,9 +1101,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
AddPushedVisibilityAttribute(NewClass);
- if (TUK != TUK_Friend)
- PushOnScopeChains(NewTemplate, S);
- else {
+ if (TUK != TUK_Friend) {
+ // Per C++ [basic.scope.temp]p2, skip the template parameter scopes.
+ Scope *Outer = S;
+ while ((Outer->getFlags() & Scope::TemplateParamScope) != 0)
+ Outer = Outer->getParent();
+ PushOnScopeChains(NewTemplate, Outer);
+ } else {
if (PrevClassTemplate && PrevClassTemplate->getAccess() != AS_none) {
NewTemplate->setAccess(PrevClassTemplate->getAccess());
NewClass->setAccess(PrevClassTemplate->getAccess());
@@ -2396,7 +2396,7 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc,
- TemplateParameterList *TemplateParams, VarDecl::StorageClass SC,
+ TemplateParameterList *TemplateParams, StorageClass SC,
bool IsPartialSpecialization) {
// D must be variable template id.
assert(D.getName().getKind() == UnqualifiedId::IK_TemplateId &&
@@ -4106,6 +4106,7 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier(
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
return false;
case NestedNameSpecifier::TypeSpec:
@@ -4595,8 +4596,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
// Create the template argument.
- Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
- ParamType->isReferenceType());
+ Converted =
+ TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()), ParamType);
S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity, false);
return false;
}
@@ -4691,7 +4692,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
Converted = TemplateArgument(Arg);
} else {
VD = cast<ValueDecl>(VD->getCanonicalDecl());
- Converted = TemplateArgument(VD, /*isReferenceParam*/false);
+ Converted = TemplateArgument(VD, ParamType);
}
return Invalid;
}
@@ -4720,7 +4721,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
Converted = TemplateArgument(Arg);
} else {
ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
- Converted = TemplateArgument(D, /*isReferenceParam*/false);
+ Converted = TemplateArgument(D, ParamType);
}
return Invalid;
}
@@ -4738,30 +4739,152 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
///
/// This routine implements the semantics of C++ [temp.arg.nontype].
/// If an error occurred, it returns ExprError(); otherwise, it
-/// returns the converted template argument. \p
-/// InstantiatedParamType is the type of the non-type template
-/// parameter after it has been instantiated.
+/// returns the converted template argument. \p ParamType is the
+/// type of the non-type template parameter after it has been instantiated.
ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
- QualType InstantiatedParamType, Expr *Arg,
+ QualType ParamType, Expr *Arg,
TemplateArgument &Converted,
CheckTemplateArgumentKind CTAK) {
SourceLocation StartLoc = Arg->getLocStart();
// If either the parameter has a dependent type or the argument is
// type-dependent, there's nothing we can check now.
- if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) {
+ if (ParamType->isDependentType() || Arg->isTypeDependent()) {
// FIXME: Produce a cloned, canonical expression?
Converted = TemplateArgument(Arg);
return Arg;
}
+ // We should have already dropped all cv-qualifiers by now.
+ assert(!ParamType.hasQualifiers() &&
+ "non-type template parameter type cannot be qualified");
+
+ if (CTAK == CTAK_Deduced &&
+ !Context.hasSameUnqualifiedType(ParamType, Arg->getType())) {
+ // C++ [temp.deduct.type]p17:
+ // If, in the declaration of a function template with a non-type
+ // template-parameter, the non-type template-parameter is used
+ // in an expression in the function parameter-list and, if the
+ // corresponding template-argument is deduced, the
+ // template-argument type shall match the type of the
+ // template-parameter exactly, except that a template-argument
+ // deduced from an array bound may be of any integral type.
+ Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
+ << Arg->getType().getUnqualifiedType()
+ << ParamType.getUnqualifiedType();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return ExprError();
+ }
+
+ if (getLangOpts().CPlusPlus1z) {
+ // FIXME: We can do some limited checking for a value-dependent but not
+ // type-dependent argument.
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ return Arg;
+ }
+
+ // C++1z [temp.arg.nontype]p1:
+ // A template-argument for a non-type template parameter shall be
+ // a converted constant expression of the type of the template-parameter.
+ APValue Value;
+ ExprResult ArgResult = CheckConvertedConstantExpression(
+ Arg, ParamType, Value, CCEK_TemplateArg);
+ if (ArgResult.isInvalid())
+ return ExprError();
+
+ QualType CanonParamType = Context.getCanonicalType(ParamType);
+
+ // Convert the APValue to a TemplateArgument.
+ switch (Value.getKind()) {
+ case APValue::Uninitialized:
+ assert(ParamType->isNullPtrType());
+ Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true);
+ break;
+ case APValue::Int:
+ assert(ParamType->isIntegralOrEnumerationType());
+ Converted = TemplateArgument(Context, Value.getInt(), CanonParamType);
+ break;
+ case APValue::MemberPointer: {
+ assert(ParamType->isMemberPointerType());
+
+ // FIXME: We need TemplateArgument representation and mangling for these.
+ if (!Value.getMemberPointerPath().empty()) {
+ Diag(Arg->getLocStart(),
+ diag::err_template_arg_member_ptr_base_derived_not_supported)
+ << Value.getMemberPointerDecl() << ParamType
+ << Arg->getSourceRange();
+ return ExprError();
+ }
+
+ auto *VD = const_cast<ValueDecl*>(Value.getMemberPointerDecl());
+ Converted = VD ? TemplateArgument(VD, CanonParamType)
+ : TemplateArgument(CanonParamType, /*isNullPtr*/true);
+ break;
+ }
+ case APValue::LValue: {
+ // For a non-type template-parameter of pointer or reference type,
+ // the value of the constant expression shall not refer to
+ assert(ParamType->isPointerType() || ParamType->isReferenceType() ||
+ ParamType->isNullPtrType());
+ // -- a temporary object
+ // -- a string literal
+ // -- the result of a typeid expression, or
+ // -- a predefind __func__ variable
+ if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) {
+ if (isa<CXXUuidofExpr>(E)) {
+ Converted = TemplateArgument(const_cast<Expr*>(E));
+ break;
+ }
+ Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
+ << Arg->getSourceRange();
+ return ExprError();
+ }
+ auto *VD = const_cast<ValueDecl *>(
+ Value.getLValueBase().dyn_cast<const ValueDecl *>());
+ // -- a subobject
+ if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
+ VD && VD->getType()->isArrayType() &&
+ Value.getLValuePath()[0].ArrayIndex == 0 &&
+ !Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) {
+ // Per defect report (no number yet):
+ // ... other than a pointer to the first element of a complete array
+ // object.
+ } else if (!Value.hasLValuePath() || Value.getLValuePath().size() ||
+ Value.isLValueOnePastTheEnd()) {
+ Diag(StartLoc, diag::err_non_type_template_arg_subobject)
+ << Value.getAsString(Context, ParamType);
+ return ExprError();
+ }
+ assert((VD || !ParamType->isReferenceType()) &&
+ "null reference should not be a constant expression");
+ assert((!VD || !ParamType->isNullPtrType()) &&
+ "non-null value of type nullptr_t?");
+ Converted = VD ? TemplateArgument(VD, CanonParamType)
+ : TemplateArgument(CanonParamType, /*isNullPtr*/true);
+ break;
+ }
+ case APValue::AddrLabelDiff:
+ return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff);
+ case APValue::Float:
+ case APValue::ComplexInt:
+ case APValue::ComplexFloat:
+ case APValue::Vector:
+ case APValue::Array:
+ case APValue::Struct:
+ case APValue::Union:
+ llvm_unreachable("invalid kind for template argument");
+ }
+
+ return ArgResult.get();
+ }
+
// C++ [temp.arg.nontype]p5:
// The following conversions are performed on each expression used
// as a non-type template-argument. If a non-type
// template-argument cannot be converted to the type of the
// corresponding template-parameter then the program is
// ill-formed.
- QualType ParamType = InstantiatedParamType;
if (ParamType->isIntegralOrEnumerationType()) {
// C++11:
// -- for a non-type template-parameter of integral or
@@ -4773,23 +4896,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// enumeration type, integral promotions (4.5) and integral
// conversions (4.7) are applied.
- if (CTAK == CTAK_Deduced &&
- !Context.hasSameUnqualifiedType(ParamType, Arg->getType())) {
- // C++ [temp.deduct.type]p17:
- // If, in the declaration of a function template with a non-type
- // template-parameter, the non-type template-parameter is used
- // in an expression in the function parameter-list and, if the
- // corresponding template-argument is deduced, the
- // template-argument type shall match the type of the
- // template-parameter exactly, except that a template-argument
- // deduced from an array bound may be of any integral type.
- Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
- << Arg->getType().getUnqualifiedType()
- << ParamType.getUnqualifiedType();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return ExprError();
- }
-
if (getLangOpts().CPlusPlus11) {
// We can't check arbitrary value-dependent arguments.
// FIXME: If there's no viable conversion to the template parameter type,
@@ -4867,9 +4973,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
}
- // From here on out, all we care about are the unqualified forms
- // of the parameter and argument types.
- ParamType = ParamType.getUnqualifiedType();
+ // From here on out, all we care about is the unqualified form
+ // of the argument type.
ArgType = ArgType.getUnqualifiedType();
// Try to convert the argument to the parameter's type.
@@ -4886,7 +4991,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// We can't perform this conversion.
Diag(Arg->getLocStart(),
diag::err_template_arg_not_convertible)
- << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
+ << Arg->getType() << ParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
return ExprError();
}
@@ -6329,14 +6434,11 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
- D->dropAttrs();
+ D->dropAttr<DLLImportAttr>();
+ D->dropAttr<DLLExportAttr>();
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
FD->setInlineSpecified(false);
-
- for (auto I : FD->params())
- I->dropAttrs();
- }
}
/// \brief Compute the diagnostic location for an explicit instantiation
@@ -7606,6 +7708,29 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// Ignore access control bits, we don't need them for redeclaration checking.
FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
+ // C++11 [except.spec]p4
+ // In an explicit instantiation an exception-specification may be specified,
+ // but is not required.
+ // If an exception-specification is specified in an explicit instantiation
+ // directive, it shall be compatible with the exception-specifications of
+ // other declarations of that function.
+ if (auto *FPT = R->getAs<FunctionProtoType>())
+ if (FPT->hasExceptionSpec()) {
+ unsigned DiagID =
+ diag::err_mismatched_exception_spec_explicit_instantiation;
+ if (getLangOpts().MicrosoftExt)
+ DiagID = diag::ext_mismatched_exception_spec_explicit_instantiation;
+ bool Result = CheckEquivalentExceptionSpec(
+ PDiag(DiagID) << Specialization->getType(),
+ PDiag(diag::note_explicit_instantiation_here),
+ Specialization->getType()->getAs<FunctionProtoType>(),
+ Specialization->getLocation(), FPT, D.getLocStart());
+ // In Microsoft mode, mismatching exception specifications just cause a
+ // warning.
+ if (!getLangOpts().MicrosoftExt && Result)
+ return true;
+ }
+
if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) {
Diag(D.getIdentifierLoc(),
diag::err_explicit_instantiation_member_function_not_instantiated)
@@ -7879,7 +8004,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
DeclarationName Name(&II);
LookupResult Result(*this, Name, IILoc, LookupOrdinaryName);
- LookupQualifiedName(Result, Ctx);
+ LookupQualifiedName(Result, Ctx, SS);
unsigned DiagID = 0;
Decl *Referenced = nullptr;
switch (Result.getResultKind()) {
@@ -7924,6 +8049,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
// We found a type. Build an ElaboratedType, since the
// typename-specifier was just sugar.
+ MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
return Context.getElaboratedType(ETK_Typename,
QualifierLoc.getNestedNameSpecifier(),
Context.getTypeDeclType(Type));
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 53a75d227c7b..dd2a4d26979e 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -262,8 +262,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
// If we deduced two declarations, make sure they they refer to the
// same declaration.
if (Y.getKind() == TemplateArgument::Declaration &&
- isSameDeclaration(X.getAsDecl(), Y.getAsDecl()) &&
- X.isDeclForReferenceParam() == Y.isDeclForReferenceParam())
+ isSameDeclaration(X.getAsDecl(), Y.getAsDecl()))
return X;
// All other combinations are incompatible.
@@ -384,7 +383,7 @@ DeduceNonTypeTemplateArgument(Sema &S,
"Cannot deduce non-type template argument with depth > 0");
D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
- TemplateArgument New(D, NTTP->getType()->isReferenceType());
+ TemplateArgument New(D, NTTP->getType());
DeducedTemplateArgument NewDeduced(New);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[NTTP->getIndex()],
@@ -1302,7 +1301,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// T &
case Type::LValueReference: {
- const LValueReferenceType *ReferenceArg = Arg->getAs<LValueReferenceType>();
+ const LValueReferenceType *ReferenceArg =
+ Arg->getAs<LValueReferenceType>();
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
@@ -1313,7 +1313,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// T && [C++0x]
case Type::RValueReference: {
- const RValueReferenceType *ReferenceArg = Arg->getAs<RValueReferenceType>();
+ const RValueReferenceType *ReferenceArg =
+ Arg->getAs<RValueReferenceType>();
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
@@ -1492,7 +1493,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
const RecordType *NextT = ToVisit.pop_back_val();
// If we have already seen this type, skip it.
- if (!Visited.insert(NextT))
+ if (!Visited.insert(NextT).second)
continue;
// If this is a base class, try to perform template argument
@@ -1726,8 +1727,7 @@ DeduceTemplateArguments(Sema &S,
case TemplateArgument::Declaration:
if (Arg.getKind() == TemplateArgument::Declaration &&
- isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()) &&
- Param.isDeclForReferenceParam() == Arg.isDeclForReferenceParam())
+ isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()))
return Sema::TDK_Success;
Info.FirstArg = Param;
@@ -1962,8 +1962,7 @@ static bool isSameTemplateArg(ASTContext &Context,
Context.getCanonicalType(Y.getAsType());
case TemplateArgument::Declaration:
- return isSameDeclaration(X.getAsDecl(), Y.getAsDecl()) &&
- X.isDeclForReferenceParam() == Y.isDeclForReferenceParam();
+ return isSameDeclaration(X.getAsDecl(), Y.getAsDecl());
case TemplateArgument::NullPtr:
return Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType());
@@ -2056,7 +2055,8 @@ getTrivialTemplateArgumentLoc(Sema &S,
TemplateName Template = Arg.getAsTemplate();
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
Builder.MakeTrivial(S.Context, DTN->getQualifier(), Loc);
- else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ else if (QualifiedTemplateName *QTN =
+ Template.getAsQualifiedTemplateName())
Builder.MakeTrivial(S.Context, QTN->getQualifier(), Loc);
if (Arg.getKind() == TemplateArgument::Template)
@@ -2588,6 +2588,9 @@ Sema::SubstituteExplicitTemplateArguments(
= Function->getType()->getAs<FunctionProtoType>();
assert(Proto && "Function template does not have a prototype?");
+ // Isolate our substituted parameters from our caller.
+ LocalInstantiationScope InstScope(*this, /*MergeWithOuterScope*/true);
+
// Instantiate the types of each of the function parameters given the
// explicitly-specified template arguments. If the function has a trailing
// return type, substitute it after the arguments to ensure we substitute
@@ -3000,7 +3003,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R,
FunctionDecl *Fn) {
// We may need to deduce the return type of the function now.
- if (S.getLangOpts().CPlusPlus1y && Fn->getReturnType()->isUndeducedType() &&
+ if (S.getLangOpts().CPlusPlus14 && Fn->getReturnType()->isUndeducedType() &&
S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/ false))
return QualType();
@@ -3229,9 +3232,9 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
return false;
}
-static bool hasDeducibleTemplateParameters(Sema &S,
- FunctionTemplateDecl *FunctionTemplate,
- QualType T);
+static bool
+hasDeducibleTemplateParameters(Sema &S, FunctionTemplateDecl *FunctionTemplate,
+ QualType T);
/// \brief Perform template argument deduction by matching a parameter type
/// against a single expression, where the expression is an element of
@@ -3488,8 +3491,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
}
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
- NumExplicitlySpecified,
- Specialization, Info, &OriginalCallArgs);
+ NumExplicitlySpecified, Specialization,
+ Info, &OriginalCallArgs);
}
QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
@@ -3579,7 +3582,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// If the function has a deduced return type, substitute it for a dependent
// type so that we treat it as a non-deduced context in what follows.
bool HasDeducedReturnType = false;
- if (getLangOpts().CPlusPlus1y && InOverloadResolution &&
+ if (getLangOpts().CPlusPlus14 && InOverloadResolution &&
Function->getReturnType()->getContainedAutoType()) {
FunctionType = SubstAutoType(FunctionType, Context.DependentTy);
HasDeducedReturnType = true;
@@ -3788,7 +3791,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
// C++0x [temp.deduct.conv]p4:
// If A is a cv-qualified type, the top level cv-qualifiers of A's
- // type are ignored for type deduction. If A is a reference type, the type
+ // type are ignored for type deduction. If A is a reference type, the type
// referred to by A is used for type deduction.
A = A.getUnqualifiedType();
}
@@ -3842,8 +3845,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized);
// If the conversion operator is being invoked on a lambda closure to convert
- // to a ptr-to-function, use the deduced arguments from the conversion function
- // to specialize the corresponding call operator.
+ // to a ptr-to-function, use the deduced arguments from the conversion
+ // function to specialize the corresponding call operator.
// e.g., int (*fp)(int) = [](auto a) { return a; };
if (Result == TDK_Success && isLambdaConversionOperator(ConversionGeneric)) {
@@ -3907,9 +3910,10 @@ namespace {
public TreeTransform<SubstituteAutoTransform> {
QualType Replacement;
public:
- SubstituteAutoTransform(Sema &SemaRef, QualType Replacement) :
- TreeTransform<SubstituteAutoTransform>(SemaRef), Replacement(Replacement) {
- }
+ SubstituteAutoTransform(Sema &SemaRef, QualType Replacement)
+ : TreeTransform<SubstituteAutoTransform>(SemaRef),
+ Replacement(Replacement) {}
+
QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) {
// If we're building the type pattern to deduce against, don't wrap the
// substituted type in an AutoType. Certain template deduction rules
@@ -3988,7 +3992,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
return DAR_FailedAlreadyDiagnosed;
}
- QualType Deduced = BuildDecltypeType(Init, Init->getLocStart());
+ QualType Deduced = BuildDecltypeType(Init, Init->getLocStart(), false);
// FIXME: Support a non-canonical deduced type for 'auto'.
Deduced = Context.getCanonicalType(Deduced);
Result = SubstituteAutoTransform(*this, Deduced).Apply(Type);
@@ -4885,8 +4889,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
Depth, Used);
// C++0x [temp.deduct.type]p9:
- // If the template argument list of P contains a pack expansion that is not
- // the last template argument, the entire template argument list is a
+ // If the template argument list of P contains a pack expansion that is
+ // not the last template argument, the entire template argument list is a
// non-deduced context.
if (OnlyDeduced &&
hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs()))
@@ -5069,10 +5073,9 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
/// \brief Marks all of the template parameters that will be deduced by a
/// call to the given function template.
-void
-Sema::MarkDeducedTemplateParameters(ASTContext &Ctx,
- const FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallBitVector &Deduced) {
+void Sema::MarkDeducedTemplateParameters(
+ ASTContext &Ctx, const FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallBitVector &Deduced) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
Deduced.clear();
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 14c64050168a..6ac7175cf30f 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -448,6 +448,10 @@ void Sema::PrintInstantiationStack() {
diag::note_template_enum_def_here)
<< ED
<< Active->InstantiationRange;
+ } else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_template_nsdmi_here)
+ << FD << Active->InstantiationRange;
} else {
Diags.Report(Active->PointOfInstantiation,
diag::note_template_type_alias_instantiation_here)
@@ -767,6 +771,8 @@ namespace {
QualType ObjectType = QualType(),
NamedDecl *FirstQualifierInScope = nullptr);
+ const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
+
ExprResult TransformPredefinedExpr(PredefinedExpr *E);
ExprResult TransformDeclRefExpr(DeclRefExpr *E);
ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
@@ -789,11 +795,17 @@ namespace {
ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E);
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
- FunctionProtoTypeLoc TL);
+ FunctionProtoTypeLoc TL) {
+ // Call the base version; it will forward to our overridden version below.
+ return inherited::TransformFunctionProtoType(TLB, TL);
+ }
+
+ template<typename Fn>
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL,
CXXRecordDecl *ThisContext,
- unsigned ThisTypeQuals);
+ unsigned ThisTypeQuals,
+ Fn TransformExceptionSpec);
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
@@ -1023,7 +1035,7 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc,
TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
TemplateName Name,
- SourceLocation NameLoc,
+ SourceLocation NameLoc,
QualType ObjectType,
NamedDecl *FirstQualifierInScope) {
if (TemplateTemplateParmDecl *TTP
@@ -1127,6 +1139,24 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg);
}
+const LoopHintAttr *
+TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
+ Expr *TransformedExpr = getDerived().TransformExpr(LH->getValue()).get();
+
+ if (TransformedExpr == LH->getValue())
+ return LH;
+
+ // Generate error if there is a problem with the value.
+ if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation()))
+ return LH;
+
+ // Create new LoopHintValueAttr with integral expression in place of the
+ // non-type template parameter.
+ return LoopHintAttr::CreateImplicit(
+ getSema().Context, LH->getSemanticSpelling(), LH->getOption(),
+ LH->getState(), TransformedExpr, LH->getRange());
+}
+
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
NonTypeTemplateParmDecl *parm,
SourceLocation loc,
@@ -1255,8 +1285,8 @@ TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
Decl *TransformedDecl;
if (DeclArgumentPack *Pack = Found->dyn_cast<DeclArgumentPack *>()) {
- // If this is a reference to a function parameter pack which we can substitute
- // but can't yet expand, build a FunctionParmPackExpr for it.
+ // If this is a reference to a function parameter pack which we can
+ // substitute but can't yet expand, build a FunctionParmPackExpr for it.
if (getSema().ArgumentPackSubstitutionIndex == -1) {
QualType T = TransformType(E->getType());
if (T.isNull())
@@ -1307,21 +1337,16 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
E->getParam());
}
-QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
- FunctionProtoTypeLoc TL) {
- // We need a local instantiation scope for this function prototype.
- LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- return inherited::TransformFunctionProtoType(TLB, TL);
-}
-
+template<typename Fn>
QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL,
CXXRecordDecl *ThisContext,
- unsigned ThisTypeQuals) {
+ unsigned ThisTypeQuals,
+ Fn TransformExceptionSpec) {
// We need a local instantiation scope for this function prototype.
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- return inherited::TransformFunctionProtoType(TLB, TL, ThisContext,
- ThisTypeQuals);
+ return inherited::TransformFunctionProtoType(
+ TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec);
}
ParmVarDecl *
@@ -1556,7 +1581,8 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
/// A form of SubstType intended specifically for instantiating the
/// type of a FunctionDecl. Its purpose is solely to force the
-/// instantiation of default-argument expressions.
+/// instantiation of default-argument expressions and to avoid
+/// instantiating an exception-specification.
TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &Args,
SourceLocation Loc,
@@ -1579,9 +1605,17 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
QualType Result;
- if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) {
- Result = Instantiator.TransformFunctionProtoType(TLB, Proto, ThisContext,
- ThisTypeQuals);
+ if (FunctionProtoTypeLoc Proto =
+ TL.IgnoreParens().getAs<FunctionProtoTypeLoc>()) {
+ // Instantiate the type, other than its exception specification. The
+ // exception specification is instantiated in InitFunctionInstantiation
+ // once we've built the FunctionDecl.
+ // FIXME: Set the exception specification to EST_Uninstantiated here,
+ // instead of rebuilding the function type again later.
+ Result = Instantiator.TransformFunctionProtoType(
+ TLB, Proto, ThisContext, ThisTypeQuals,
+ [](FunctionProtoType::ExceptionSpecInfo &ESI,
+ bool &Changed) { return false; });
} else {
Result = Instantiator.TransformType(TLB, TL);
}
@@ -1591,6 +1625,26 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
return TLB.getTypeSourceInfo(Context, Result);
}
+void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
+ const MultiLevelTemplateArgumentList &Args) {
+ FunctionProtoType::ExceptionSpecInfo ESI =
+ Proto->getExtProtoInfo().ExceptionSpec;
+ assert(ESI.Type != EST_Uninstantiated);
+
+ TemplateInstantiator Instantiator(*this, Args, New->getLocation(),
+ New->getDeclName());
+
+ SmallVector<QualType, 4> ExceptionStorage;
+ bool Changed = false;
+ if (Instantiator.TransformExceptionSpec(
+ New->getTypeSourceInfo()->getTypeLoc().getLocEnd(), ESI,
+ ExceptionStorage, Changed))
+ // On error, recover by dropping the exception specification.
+ ESI.Type = EST_None;
+
+ UpdateExceptionSpec(New, ESI);
+}
+
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
@@ -1947,8 +2001,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
SmallVector<Decl*, 4> Fields;
- SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4>
- FieldsWithMemberInitializers;
// Delay instantiation of late parsed attributes.
LateInstantiatedAttrVec LateAttrs;
Instantiator.enableLateAttributeInstantiation(&LateAttrs);
@@ -1975,10 +2027,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
if (NewMember) {
if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) {
Fields.push_back(Field);
- FieldDecl *OldField = cast<FieldDecl>(Member);
- if (OldField->getInClassInitializer())
- FieldsWithMemberInitializers.push_back(std::make_pair(OldField,
- Field));
} else if (EnumDecl *Enum = dyn_cast<EnumDecl>(NewMember)) {
// C++11 [temp.inst]p1: The implicit instantiation of a class template
// specialization causes the implicit instantiation of the definitions
@@ -2015,31 +2063,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
SourceLocation(), SourceLocation(), nullptr);
CheckCompletedCXXClass(Instantiation);
- // Attach any in-class member initializers now the class is complete.
- // FIXME: We are supposed to defer instantiating these until they are needed.
- if (!FieldsWithMemberInitializers.empty()) {
- // C++11 [expr.prim.general]p4:
- // Otherwise, if a member-declarator declares a non-static data member
- // (9.2) of a class X, the expression this is a prvalue of type "pointer
- // to X" within the optional brace-or-equal-initializer. It shall not
- // appear elsewhere in the member-declarator.
- CXXThisScopeRAII ThisScope(*this, Instantiation, (unsigned)0);
-
- for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) {
- FieldDecl *OldField = FieldsWithMemberInitializers[I].first;
- FieldDecl *NewField = FieldsWithMemberInitializers[I].second;
- Expr *OldInit = OldField->getInClassInitializer();
-
- ActOnStartCXXInClassMemberInitializer();
- ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs,
- /*CXXDirectInit=*/false);
- Expr *Init = NewInit.get();
- assert((!Init || !isa<ParenListExpr>(Init)) &&
- "call-style init in class");
- ActOnFinishCXXInClassMemberInitializer(NewField,
- Init ? Init->getLocStart() : SourceLocation(), Init);
- }
- }
// Instantiate late parsed attributes, and attach them to their decls.
// See Sema::InstantiateAttrs
for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(),
@@ -2180,6 +2203,80 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
return Instantiation->isInvalidDecl();
}
+
+/// \brief Instantiate the definition of a field from the given pattern.
+///
+/// \param PointOfInstantiation The point of instantiation within the
+/// source code.
+/// \param Instantiation is the declaration whose definition is being
+/// instantiated. This will be a class of a class temploid
+/// specialization, or a local enumeration within a function temploid
+/// specialization.
+/// \param Pattern The templated declaration from which the instantiation
+/// occurs.
+/// \param TemplateArgs The template arguments to be substituted into
+/// the pattern.
+///
+/// \return \c true if an error occurred, \c false otherwise.
+bool Sema::InstantiateInClassInitializer(
+ SourceLocation PointOfInstantiation, FieldDecl *Instantiation,
+ FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs) {
+ // If there is no initializer, we don't need to do anything.
+ if (!Pattern->hasInClassInitializer())
+ return false;
+
+ assert(Instantiation->getInClassInitStyle() ==
+ Pattern->getInClassInitStyle() &&
+ "pattern and instantiation disagree about init style");
+
+ // Error out if we haven't parsed the initializer of the pattern yet because
+ // we are waiting for the closing brace of the outer class.
+ Expr *OldInit = Pattern->getInClassInitializer();
+ if (!OldInit) {
+ RecordDecl *PatternRD = Pattern->getParent();
+ RecordDecl *OutermostClass = PatternRD->getOuterLexicalRecordContext();
+ if (OutermostClass == PatternRD) {
+ Diag(Pattern->getLocEnd(), diag::err_in_class_initializer_not_yet_parsed)
+ << PatternRD << Pattern;
+ } else {
+ Diag(Pattern->getLocEnd(),
+ diag::err_in_class_initializer_not_yet_parsed_outer_class)
+ << PatternRD << OutermostClass << Pattern;
+ }
+ Instantiation->setInvalidDecl();
+ return true;
+ }
+
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
+ if (Inst.isInvalid())
+ return true;
+
+ // Enter the scope of this instantiation. We don't use PushDeclContext because
+ // we don't have a scope.
+ ContextRAII SavedContext(*this, Instantiation->getParent());
+ EnterExpressionEvaluationContext EvalContext(*this,
+ Sema::PotentiallyEvaluated);
+
+ LocalInstantiationScope Scope(*this);
+
+ // Instantiate the initializer.
+ ActOnStartCXXInClassMemberInitializer();
+ CXXThisScopeRAII ThisScope(*this, Instantiation->getParent(), /*TypeQuals=*/0);
+
+ ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs,
+ /*CXXDirectInit=*/false);
+ Expr *Init = NewInit.get();
+ assert((!Init || !isa<ParenListExpr>(Init)) && "call-style init in class");
+ ActOnFinishCXXInClassMemberInitializer(
+ Instantiation, Init ? Init->getLocStart() : SourceLocation(), Init);
+
+ // Exit the scope of this instantiation.
+ SavedContext.pop();
+
+ // Return true if the in-class initializer is still missing.
+ return !Instantiation->getInClassInitializer();
+}
+
namespace {
/// \brief A partial specialization whose template arguments have matched
/// a given template-id.
@@ -2458,7 +2555,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
// Always skip the injected-class-name, along with any
// redeclarations of nested classes, since both would cause us
// to try to instantiate the members of a class twice.
- if (Record->isInjectedClassName() || Record->getPreviousDecl())
+ // Skip closure types; they'll get instantiated when we instantiate
+ // the corresponding lambda-expression.
+ if (Record->isInjectedClassName() || Record->getPreviousDecl() ||
+ Record->isLambda())
continue;
MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo();
@@ -2541,6 +2641,19 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
MSInfo->setTemplateSpecializationKind(TSK);
MSInfo->setPointOfInstantiation(PointOfInstantiation);
}
+ } else if (auto *Field = dyn_cast<FieldDecl>(D)) {
+ // No need to instantiate in-class initializers during explicit
+ // instantiation.
+ if (Field->hasInClassInitializer() && TSK == TSK_ImplicitInstantiation) {
+ CXXRecordDecl *ClassPattern =
+ Instantiation->getTemplateInstantiationPattern();
+ DeclContext::lookup_result Lookup =
+ ClassPattern->lookup(Field->getDeclName());
+ assert(Lookup.size() == 1);
+ FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]);
+ InstantiateInClassInitializer(PointOfInstantiation, Field, Pattern,
+ TemplateArgs);
+ }
}
}
}
@@ -2649,8 +2762,7 @@ bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs,
return Instantiator.TransformTemplateArguments(Args, NumArgs, Result);
}
-
-static const Decl* getCanonicalParmVarDecl(const Decl *D) {
+static const Decl *getCanonicalParmVarDecl(const Decl *D) {
// When storing ParmVarDecls in the local instantiation scope, we always
// want to use the ParmVarDecl from the canonical function declaration,
// since the map is then valid for any redeclaration or definition of that
@@ -2658,7 +2770,10 @@ static const Decl* getCanonicalParmVarDecl(const Decl *D) {
if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(D)) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
unsigned i = PV->getFunctionScopeIndex();
- return FD->getCanonicalDecl()->getParamDecl(i);
+ // This parameter might be from a freestanding function type within the
+ // function and isn't necessarily referring to one of FD's parameters.
+ if (FD->getParamDecl(i) == PV)
+ return FD->getCanonicalDecl()->getParamDecl(i);
}
}
return D;
@@ -2707,12 +2822,22 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
D = getCanonicalParmVarDecl(D);
llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
- if (Stored.isNull())
+ if (Stored.isNull()) {
+#ifndef NDEBUG
+ // It should not be present in any surrounding scope either.
+ LocalInstantiationScope *Current = this;
+ while (Current->CombineWithOuterScope && Current->Outer) {
+ Current = Current->Outer;
+ assert(Current->LocalDecls.find(D) == Current->LocalDecls.end() &&
+ "Instantiated local in inner and outer scopes");
+ }
+#endif
Stored = Inst;
- else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>())
+ } else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) {
Pack->push_back(Inst);
- else
+ } else {
assert(Stored.get<Decl *>() == Inst && "Already instantiated this local");
+ }
}
void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D,
@@ -2723,9 +2848,16 @@ void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D,
}
void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) {
+#ifndef NDEBUG
+ // This should be the first time we've been told about this decl.
+ for (LocalInstantiationScope *Current = this;
+ Current && Current->CombineWithOuterScope; Current = Current->Outer)
+ assert(Current->LocalDecls.find(D) == Current->LocalDecls.end() &&
+ "Creating local pack after instantiation of local");
+#endif
+
D = getCanonicalParmVarDecl(D);
llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
- assert(Stored.isNull() && "Already instantiated this local");
DeclArgumentPack *Pack = new DeclArgumentPack;
Stored = Pack;
ArgumentPacks.push_back(Pack);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index accec95bf708..40e86175b2cd 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -36,14 +36,24 @@ static bool isDeclWithinFunction(const Decl *D) {
return false;
}
-bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
- DeclaratorDecl *NewDecl) {
+template<typename DeclT>
+static bool SubstQualifier(Sema &SemaRef, const DeclT *OldDecl, DeclT *NewDecl,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
if (!OldDecl->getQualifierLoc())
return false;
+ assert((NewDecl->getFriendObjectKind() ||
+ !OldDecl->getLexicalDeclContext()->isDependentContext()) &&
+ "non-friend with qualified name defined in dependent context");
+ Sema::ContextRAII SavedContext(
+ SemaRef,
+ const_cast<DeclContext *>(NewDecl->getFriendObjectKind()
+ ? NewDecl->getLexicalDeclContext()
+ : OldDecl->getLexicalDeclContext()));
+
NestedNameSpecifierLoc NewQualifierLoc
- = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
- TemplateArgs);
+ = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
+ TemplateArgs);
if (!NewQualifierLoc)
return true;
@@ -52,20 +62,14 @@ bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
return false;
}
+bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
+ DeclaratorDecl *NewDecl) {
+ return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
+}
+
bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl) {
- if (!OldDecl->getQualifierLoc())
- return false;
-
- NestedNameSpecifierLoc NewQualifierLoc
- = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
- TemplateArgs);
-
- if (!NewQualifierLoc)
- return true;
-
- NewDecl->setQualifierInfo(NewQualifierLoc);
- return false;
+ return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
}
// Include attribute instantiation code.
@@ -129,6 +133,40 @@ static void instantiateDependentAlignedAttr(
}
}
+static void instantiateDependentAssumeAlignedAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const AssumeAlignedAttr *Aligned, Decl *New) {
+ // The alignment expression is a constant expression.
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
+
+ Expr *E, *OE = nullptr;
+ ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs);
+ if (Result.isInvalid())
+ return;
+ E = Result.getAs<Expr>();
+
+ if (Aligned->getOffset()) {
+ Result = S.SubstExpr(Aligned->getOffset(), TemplateArgs);
+ if (Result.isInvalid())
+ return;
+ OE = Result.getAs<Expr>();
+ }
+
+ S.AddAssumeAlignedAttr(Aligned->getLocation(), New, E, OE,
+ Aligned->getSpellingListIndex());
+}
+
+static void instantiateDependentAlignValueAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const AlignValueAttr *Aligned, Decl *New) {
+ // The alignment expression is a constant expression.
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
+ ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs);
+ if (!Result.isInvalid())
+ S.AddAlignValueAttr(Aligned->getLocation(), New, Result.getAs<Expr>(),
+ Aligned->getSpellingListIndex());
+}
+
static void instantiateDependentEnableIfAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const EnableIfAttr *A, const Decl *Tmpl, Decl *New) {
@@ -176,6 +214,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
+ const AssumeAlignedAttr *AssumeAligned = dyn_cast<AssumeAlignedAttr>(TmplAttr);
+ if (AssumeAligned) {
+ instantiateDependentAssumeAlignedAttr(*this, TemplateArgs, AssumeAligned, New);
+ continue;
+ }
+
+ const AlignValueAttr *AlignValue = dyn_cast<AlignValueAttr>(TmplAttr);
+ if (AlignValue) {
+ instantiateDependentAlignValueAttr(*this, TemplateArgs, AlignValue, New);
+ continue;
+ }
+
const EnableIfAttr *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr);
if (EnableIf && EnableIf->getCond()->isValueDependent()) {
instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,
@@ -183,6 +233,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
+ // Existing DLL attribute on the instantiation takes precedence.
+ if (TmplAttr->getKind() == attr::DLLExport ||
+ TmplAttr->getKind() == attr::DLLImport) {
+ if (New->hasAttr<DLLExportAttr>() || New->hasAttr<DLLImportAttr>()) {
+ continue;
+ }
+ }
+
assert(!TmplAttr->isPackExpansion());
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
@@ -207,6 +265,24 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}
}
+/// Get the previous declaration of a declaration for the purposes of template
+/// instantiation. If this finds a previous declaration, then the previous
+/// declaration of the instantiation of D should be an instantiation of the
+/// result of this function.
+template<typename DeclT>
+static DeclT *getPreviousDeclForInstantiation(DeclT *D) {
+ DeclT *Result = D->getPreviousDecl();
+
+ // If the declaration is within a class, and the previous declaration was
+ // merged from a different definition of that class, then we don't have a
+ // previous declaration for the purpose of template instantiation.
+ if (Result && isa<CXXRecordDecl>(D->getDeclContext()) &&
+ D->getLexicalDeclContext() != Result->getLexicalDeclContext())
+ return nullptr;
+
+ return Result;
+}
+
Decl *
TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
llvm_unreachable("Translation units cannot be instantiated");
@@ -293,7 +369,7 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
}
}
- if (TypedefNameDecl *Prev = D->getPreviousDecl()) {
+ if (TypedefNameDecl *Prev = getPreviousDeclForInstantiation(D)) {
NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev,
TemplateArgs);
if (!InstPrev)
@@ -316,13 +392,15 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false);
- Owner->addDecl(Typedef);
+ if (Typedef)
+ Owner->addDecl(Typedef);
return Typedef;
}
Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) {
Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true);
- Owner->addDecl(Typedef);
+ if (Typedef)
+ Owner->addDecl(Typedef);
return Typedef;
}
@@ -340,7 +418,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
TypeAliasDecl *Pattern = D->getTemplatedDecl();
TypeAliasTemplateDecl *PrevAliasTemplate = nullptr;
- if (Pattern->getPreviousDecl()) {
+ if (getPreviousDeclForInstantiation<TypedefNameDecl>(Pattern)) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (!Found.empty()) {
PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Found.front());
@@ -355,6 +433,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
TypeAliasTemplateDecl *Inst
= TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getDeclName(), InstParams, AliasInst);
+ AliasInst->setDescribedAliasTemplate(Inst);
if (PrevAliasTemplate)
Inst->setPreviousDecl(PrevAliasTemplate);
@@ -578,11 +657,12 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
}
QualType T = cast<FieldDecl>(NamedChain[i-1])->getType();
- IndirectFieldDecl* IndirectField
- = IndirectFieldDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getIdentifier(), T,
- NamedChain, D->getChainingSize());
+ IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create(
+ SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), T,
+ NamedChain, D->getChainingSize());
+ for (const auto *Attr : D->attrs())
+ IndirectField->addAttr(Attr->clone(SemaRef.Context));
IndirectField->setImplicit(D->isImplicit());
IndirectField->setAccess(D->getAccess());
@@ -659,9 +739,9 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
EnumDecl *PrevDecl = nullptr;
- if (D->getPreviousDecl()) {
+ if (EnumDecl *PatternPrev = getPreviousDeclForInstantiation(D)) {
NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
- D->getPreviousDecl(),
+ PatternPrev,
TemplateArgs);
if (!Prev) return nullptr;
PrevDecl = cast<EnumDecl>(Prev);
@@ -823,7 +903,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
CXXRecordDecl *PrevDecl = nullptr;
ClassTemplateDecl *PrevClassTemplate = nullptr;
- if (!isFriend && Pattern->getPreviousDecl()) {
+ if (!isFriend && getPreviousDeclForInstantiation(Pattern)) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (!Found.empty()) {
PrevClassTemplate = dyn_cast<ClassTemplateDecl>(Found.front());
@@ -1017,7 +1097,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) {
VarDecl *Pattern = D->getTemplatedDecl();
VarTemplateDecl *PrevVarTemplate = nullptr;
- if (Pattern->getPreviousDecl()) {
+ if (getPreviousDeclForInstantiation(Pattern)) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (!Found.empty())
PrevVarTemplate = dyn_cast<VarTemplateDecl>(Found.front());
@@ -1127,7 +1207,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (!isFriend) {
Owner->addDecl(InstTemplate);
} else if (InstTemplate->getDeclContext()->isRecord() &&
- !D->getPreviousDecl()) {
+ !getPreviousDeclForInstantiation(D)) {
SemaRef.CheckFriendAccess(InstTemplate);
}
@@ -1138,9 +1218,9 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
CXXRecordDecl *PrevDecl = nullptr;
if (D->isInjectedClassName())
PrevDecl = cast<CXXRecordDecl>(Owner);
- else if (D->getPreviousDecl()) {
+ else if (CXXRecordDecl *PatternPrev = getPreviousDeclForInstantiation(D)) {
NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
- D->getPreviousDecl(),
+ PatternPrev,
TemplateArgs);
if (!Prev) return nullptr;
PrevDecl = cast<CXXRecordDecl>(Prev);
@@ -1191,6 +1271,9 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
TSK_ImplicitInstantiation);
}
+
+ SemaRef.DiagnoseUnusedNestedTypedefs(Record);
+
return Record;
}
@@ -2201,7 +2284,8 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
if (CheckRedeclaration) {
if (SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev, PrevDecl))
continue;
- } else if (UsingShadowDecl *OldPrev = Shadow->getPreviousDecl()) {
+ } else if (UsingShadowDecl *OldPrev =
+ getPreviousDeclForInstantiation(Shadow)) {
PrevDecl = cast_or_null<UsingShadowDecl>(SemaRef.FindInstantiatedDecl(
Shadow->getLocation(), OldPrev, TemplateArgs));
}
@@ -2276,8 +2360,10 @@ Decl * TemplateDeclInstantiator
Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *Decl) {
CXXMethodDecl *OldFD = Decl->getSpecialization();
- CXXMethodDecl *NewFD = cast<CXXMethodDecl>(VisitCXXMethodDecl(OldFD,
- nullptr, true));
+ CXXMethodDecl *NewFD =
+ cast_or_null<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, nullptr, true));
+ if (!NewFD)
+ return nullptr;
LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName,
Sema::ForRedeclaration);
@@ -2976,7 +3062,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
/// Introduce the instantiated function parameters into the local
/// instantiation scope, and set the parameter names to those used
/// in the template.
-static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
+static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
const FunctionDecl *PatternDecl,
LocalInstantiationScope &Scope,
const MultiLevelTemplateArgumentList &TemplateArgs) {
@@ -2987,15 +3073,22 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
// Simple case: not a parameter pack.
assert(FParamIdx < Function->getNumParams());
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
+ FunctionParam->setDeclName(PatternParam->getDeclName());
// If the parameter's type is not dependent, update it to match the type
// in the pattern. They can differ in top-level cv-qualifiers, and we want
// the pattern's type here. If the type is dependent, they can't differ,
- // per core issue 1668.
+ // per core issue 1668. Substitute into the type from the pattern, in case
+ // it's instantiation-dependent.
// FIXME: Updating the type to work around this is at best fragile.
- if (!PatternDecl->getType()->isDependentType())
- FunctionParam->setType(PatternParam->getType());
+ if (!PatternDecl->getType()->isDependentType()) {
+ QualType T = S.SubstType(PatternParam->getType(), TemplateArgs,
+ FunctionParam->getLocation(),
+ FunctionParam->getDeclName());
+ if (T.isNull())
+ return true;
+ FunctionParam->setType(T);
+ }
- FunctionParam->setDeclName(PatternParam->getDeclName());
Scope.InstantiatedLocal(PatternParam, FunctionParam);
++FParamIdx;
continue;
@@ -3007,137 +3100,27 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
= S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
assert(NumArgumentsInExpansion &&
"should only be called when all template arguments are known");
+ QualType PatternType =
+ PatternParam->getType()->castAs<PackExpansionType>()->getPattern();
for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
- if (!PatternDecl->getType()->isDependentType())
- FunctionParam->setType(PatternParam->getType());
-
FunctionParam->setDeclName(PatternParam->getDeclName());
- Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
- ++FParamIdx;
- }
- }
-}
-
-static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
- const FunctionProtoType *Proto,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
- assert(Proto->getExceptionSpecType() != EST_Uninstantiated);
-
- // C++11 [expr.prim.general]p3:
- // If a declaration declares a member function or member function
- // template of a class X, the expression this is a prvalue of type
- // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
- // and the end of the function-definition, member-declarator, or
- // declarator.
- CXXRecordDecl *ThisContext = nullptr;
- unsigned ThisTypeQuals = 0;
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {
- ThisContext = Method->getParent();
- ThisTypeQuals = Method->getTypeQualifiers();
- }
- Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,
- SemaRef.getLangOpts().CPlusPlus11);
-
- // The function has an exception specification or a "noreturn"
- // attribute. Substitute into each of the exception types.
- SmallVector<QualType, 4> Exceptions;
- for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {
- // FIXME: Poor location information!
- if (const PackExpansionType *PackExpansion
- = Proto->getExceptionType(I)->getAs<PackExpansionType>()) {
- // We have a pack expansion. Instantiate it.
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
- Unexpanded);
- assert(!Unexpanded.empty() &&
- "Pack expansion without parameter packs?");
-
- bool Expand = false;
- bool RetainExpansion = false;
- Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
- if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
- SourceRange(),
- Unexpanded,
- TemplateArgs,
- Expand,
- RetainExpansion,
- NumExpansions))
- break;
-
- if (!Expand) {
- // We can't expand this pack expansion into separate arguments yet;
- // just substitute into the pattern and create a new pack expansion
- // type.
- Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
- QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
- TemplateArgs,
- New->getLocation(), New->getDeclName());
+ if (!PatternDecl->getType()->isDependentType()) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg);
+ QualType T = S.SubstType(PatternType, TemplateArgs,
+ FunctionParam->getLocation(),
+ FunctionParam->getDeclName());
if (T.isNull())
- break;
-
- T = SemaRef.Context.getPackExpansionType(T, NumExpansions);
- Exceptions.push_back(T);
- continue;
- }
-
- // Substitute into the pack expansion pattern for each template
- bool Invalid = false;
- for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
- Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx);
-
- QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
- TemplateArgs,
- New->getLocation(), New->getDeclName());
- if (T.isNull()) {
- Invalid = true;
- break;
- }
-
- Exceptions.push_back(T);
+ return true;
+ FunctionParam->setType(T);
}
- if (Invalid)
- break;
-
- continue;
- }
-
- QualType T
- = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,
- New->getLocation(), New->getDeclName());
- if (T.isNull() ||
- SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))
- continue;
-
- Exceptions.push_back(T);
- }
- Expr *NoexceptExpr = nullptr;
- if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::ConstantEvaluated);
- ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
- if (E.isUsable())
- E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart());
-
- if (E.isUsable()) {
- NoexceptExpr = E.get();
- if (!NoexceptExpr->isTypeDependent() &&
- !NoexceptExpr->isValueDependent())
- NoexceptExpr
- = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
- nullptr, diag::err_noexcept_needs_constant_expression,
- /*AllowFold*/ false).get();
+ Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
+ ++FParamIdx;
}
}
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = Proto->getExceptionSpecType();
- EPI.NumExceptions = Exceptions.size();
- EPI.Exceptions = Exceptions.data();
- EPI.NoexceptExpr = NoexceptExpr;
-
- SemaRef.UpdateExceptionSpec(New, EPI);
+ return false;
}
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
@@ -3151,9 +3134,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
if (Inst.isInvalid()) {
// We hit the instantiation depth limit. Clear the exception specification
// so that our callers don't have to cope with EST_Uninstantiated.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = EST_None;
- UpdateExceptionSpec(Decl, EPI);
+ UpdateExceptionSpec(Decl, EST_None);
return;
}
@@ -3166,11 +3147,14 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
- addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs);
+ if (addInstantiatedParametersToScope(*this, Decl, Template, Scope,
+ TemplateArgs)) {
+ UpdateExceptionSpec(Decl, EST_None);
+ return;
+ }
- ::InstantiateExceptionSpec(*this, Decl,
- Template->getType()->castAs<FunctionProtoType>(),
- TemplateArgs);
+ SubstExceptionSpec(Decl, Template->getType()->castAs<FunctionProtoType>(),
+ TemplateArgs);
}
/// \brief Initializes the common fields of an instantiation function
@@ -3218,14 +3202,14 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
// DR1330: In C++11, defer instantiation of a non-trivial
// exception specification.
if (SemaRef.getLangOpts().CPlusPlus11 &&
- EPI.ExceptionSpecType != EST_None &&
- EPI.ExceptionSpecType != EST_DynamicNone &&
- EPI.ExceptionSpecType != EST_BasicNoexcept) {
+ EPI.ExceptionSpec.Type != EST_None &&
+ EPI.ExceptionSpec.Type != EST_DynamicNone &&
+ EPI.ExceptionSpec.Type != EST_BasicNoexcept) {
FunctionDecl *ExceptionSpecTemplate = Tmpl;
- if (EPI.ExceptionSpecType == EST_Uninstantiated)
- ExceptionSpecTemplate = EPI.ExceptionSpecTemplate;
+ if (EPI.ExceptionSpec.Type == EST_Uninstantiated)
+ ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate;
ExceptionSpecificationType NewEST = EST_Uninstantiated;
- if (EPI.ExceptionSpecType == EST_Unevaluated)
+ if (EPI.ExceptionSpec.Type == EST_Unevaluated)
NewEST = EST_Unevaluated;
// Mark the function has having an uninstantiated exception specification.
@@ -3233,13 +3217,13 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
= New->getType()->getAs<FunctionProtoType>();
assert(NewProto && "Template instantiation without function prototype?");
EPI = NewProto->getExtProtoInfo();
- EPI.ExceptionSpecType = NewEST;
- EPI.ExceptionSpecDecl = New;
- EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;
+ EPI.ExceptionSpec.Type = NewEST;
+ EPI.ExceptionSpec.SourceDecl = New;
+ EPI.ExceptionSpec.SourceTemplate = ExceptionSpecTemplate;
New->setType(SemaRef.Context.getFunctionType(
NewProto->getReturnType(), NewProto->getParamTypes(), EPI));
} else {
- ::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
+ SemaRef.SubstExceptionSpec(New, Proto, TemplateArgs);
}
}
@@ -3322,6 +3306,20 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
return;
}
+ // 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.
+ // This has to happen before LateTemplateParser below is called, so that
+ // it marks vtables used in late parsed templates as used.
+ SavePendingLocalImplicitInstantiationsRAII
+ SavedPendingLocalImplicitInstantiations(*this);
+ std::unique_ptr<SavePendingInstantiationsAndVTableUsesRAII>
+ SavePendingInstantiationsAndVTableUses;
+ if (Recursive) {
+ SavePendingInstantiationsAndVTableUses.reset(
+ new SavePendingInstantiationsAndVTableUsesRAII(*this));
+ }
+
// Call the LateTemplateParser callback if there is a need to late parse
// a templated function definition.
if (!Pattern && PatternDecl->isLateTemplateParsed() &&
@@ -3353,6 +3351,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
Function->setInvalidDecl();
} else if (Function->getTemplateSpecializationKind()
== TSK_ExplicitInstantiationDefinition) {
+ assert(!Recursive);
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
}
@@ -3389,18 +3388,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Copy the inner loc start from the pattern.
Function->setInnerLocStart(PatternDecl->getInnerLocStart());
- // 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.
- SmallVector<VTableUse, 16> SavedVTableUses;
- std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
- SavePendingLocalImplicitInstantiationsRAII
- SavedPendingLocalImplicitInstantiations(*this);
- if (Recursive) {
- VTableUses.swap(SavedVTableUses);
- PendingInstantiations.swap(SavedPendingInstantiations);
- }
-
EnterExpressionEvaluationContext EvalContext(*this,
Sema::PotentiallyEvaluated);
@@ -3417,17 +3404,24 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (PatternDecl->isDefaulted())
SetDeclDefaulted(Function, PatternDecl->getLocation());
else {
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl);
+
+ // Substitute into the qualifier; we can get a substitution failure here
+ // through evil use of alias templates.
+ // FIXME: Is CurContext correct for this? Should we go to the (instantiation
+ // of the) lexical context of the pattern?
+ SubstQualifier(*this, PatternDecl, Function, TemplateArgs);
+
ActOnStartOfFunctionDef(nullptr, Function);
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
Sema::ContextRAII savedContext(*this, Function);
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl);
-
- addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
- TemplateArgs);
+ if (addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
+ TemplateArgs))
+ return;
// If this is a constructor, instantiate the member initializers.
if (const CXXConstructorDecl *Ctor =
@@ -3469,15 +3463,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// instantiation of this template.
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);
+ // Restore PendingInstantiations and VTableUses.
+ SavePendingInstantiationsAndVTableUses.reset();
}
}
@@ -3651,7 +3638,7 @@ void Sema::BuildVariableInstantiation(
// Diagnose unused local variables with dependent types, where the diagnostic
// will have been deferred.
if (!NewVar->isInvalidDecl() &&
- NewVar->getDeclContext()->isFunctionOrMethod() && !NewVar->isUsed() &&
+ NewVar->getDeclContext()->isFunctionOrMethod() &&
OldVar->getType()->isDependentType())
DiagnoseUnusedDecl(NewVar);
}
@@ -3793,11 +3780,11 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// 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.
- SmallVector<VTableUse, 16> SavedVTableUses;
- std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
+ std::unique_ptr<SavePendingInstantiationsAndVTableUsesRAII>
+ SavePendingInstantiationsAndVTableUses;
if (Recursive) {
- VTableUses.swap(SavedVTableUses);
- PendingInstantiations.swap(SavedPendingInstantiations);
+ SavePendingInstantiationsAndVTableUses.reset(
+ new SavePendingInstantiationsAndVTableUsesRAII(*this));
}
LocalInstantiationScope Local(*this);
@@ -3825,15 +3812,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// instantiation of this template.
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);
+ // Restore PendingInstantiations and VTableUses.
+ SavePendingInstantiationsAndVTableUses.reset();
}
}
@@ -3917,13 +3897,13 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// 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.
- SmallVector<VTableUse, 16> SavedVTableUses;
- std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
SavePendingLocalImplicitInstantiationsRAII
SavedPendingLocalImplicitInstantiations(*this);
+ std::unique_ptr<SavePendingInstantiationsAndVTableUsesRAII>
+ SavePendingInstantiationsAndVTableUses;
if (Recursive) {
- VTableUses.swap(SavedVTableUses);
- PendingInstantiations.swap(SavedPendingInstantiations);
+ SavePendingInstantiationsAndVTableUses.reset(
+ new SavePendingInstantiationsAndVTableUsesRAII(*this));
}
// Enter the scope of this instantiation. We don't use
@@ -3990,15 +3970,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// instantiation of this template.
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);
+ // Restore PendingInstantiations and VTableUses.
+ SavePendingInstantiationsAndVTableUses.reset();
}
}
@@ -4235,25 +4208,26 @@ static bool isInstantiationOf(EnumDecl *Pattern,
static bool isInstantiationOf(UsingShadowDecl *Pattern,
UsingShadowDecl *Instance,
ASTContext &C) {
- return C.getInstantiatedFromUsingShadowDecl(Instance) == Pattern;
+ return declaresSameEntity(C.getInstantiatedFromUsingShadowDecl(Instance),
+ Pattern);
}
static bool isInstantiationOf(UsingDecl *Pattern,
UsingDecl *Instance,
ASTContext &C) {
- return C.getInstantiatedFromUsingDecl(Instance) == Pattern;
+ return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern);
}
static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern,
UsingDecl *Instance,
ASTContext &C) {
- return C.getInstantiatedFromUsingDecl(Instance) == Pattern;
+ return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern);
}
static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern,
UsingDecl *Instance,
ASTContext &C) {
- return C.getInstantiatedFromUsingDecl(Instance) == Pattern;
+ return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern);
}
static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
@@ -4319,8 +4293,8 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) {
if (!Field->getDeclName()) {
// This is an unnamed field.
- return Ctx.getInstantiatedFromUnnamedFieldDecl(Field) ==
- cast<FieldDecl>(D);
+ return declaresSameEntity(Ctx.getInstantiatedFromUnnamedFieldDecl(Field),
+ cast<FieldDecl>(D));
}
}
@@ -4412,17 +4386,17 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
(isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) {
// D is a local of some kind. Look into the map of local
// declarations to their instantiations.
- typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
- llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found
- = CurrentInstantiationScope->findInstantiationOf(D);
-
- if (Found) {
- if (Decl *FD = Found->dyn_cast<Decl *>())
- return cast<NamedDecl>(FD);
-
- int PackIdx = ArgumentPackSubstitutionIndex;
- assert(PackIdx != -1 && "found declaration pack but not pack expanding");
- return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]);
+ if (CurrentInstantiationScope) {
+ if (auto Found = CurrentInstantiationScope->findInstantiationOf(D)) {
+ if (Decl *FD = Found->dyn_cast<Decl *>())
+ return cast<NamedDecl>(FD);
+
+ int PackIdx = ArgumentPackSubstitutionIndex;
+ assert(PackIdx != -1 &&
+ "found declaration pack but not pack expanding");
+ typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
+ return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]);
+ }
}
// If we're performing a partial substitution during template argument
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 8e4ce0d9da6f..e4fab71d995b 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -197,6 +197,20 @@ namespace {
};
}
+/// \brief Determine whether it's possible for an unexpanded parameter pack to
+/// be valid in this location. This only happens when we're in a declaration
+/// that is nested within an expression that could be expanded, such as a
+/// lambda-expression within a function call.
+///
+/// This is conservatively correct, but may claim that some unexpanded packs are
+/// permitted when they are not.
+bool Sema::isUnexpandedParameterPackPermitted() {
+ for (auto *SI : FunctionScopes)
+ if (isa<sema::LambdaScopeInfo>(SI))
+ return true;
+ return false;
+}
+
/// \brief Diagnose all of the unexpanded parameter packs in the given
/// vector.
bool
@@ -230,7 +244,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
else
Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier();
- if (Name && NamesKnown.insert(Name))
+ if (Name && NamesKnown.insert(Name).second)
Names.push_back(Name);
if (Unexpanded[I].second.isValid())
@@ -733,24 +747,48 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_error:
break;
}
-
+
for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) {
const DeclaratorChunk &Chunk = D.getTypeObject(I);
switch (Chunk.Kind) {
case DeclaratorChunk::Pointer:
case DeclaratorChunk::Reference:
case DeclaratorChunk::Paren:
+ case DeclaratorChunk::BlockPointer:
// These declarator chunks cannot contain any parameter packs.
break;
case DeclaratorChunk::Array:
+ if (Chunk.Arr.NumElts &&
+ Chunk.Arr.NumElts->containsUnexpandedParameterPack())
+ return true;
+ break;
case DeclaratorChunk::Function:
- case DeclaratorChunk::BlockPointer:
- // Syntactically, these kinds of declarator chunks all come after the
- // declarator-id (conceptually), so the parser should not invoke this
- // routine at this time.
- llvm_unreachable("Could not have seen this kind of declarator chunk");
-
+ for (unsigned i = 0, e = Chunk.Fun.NumParams; i != e; ++i) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(Chunk.Fun.Params[i].Param);
+ QualType ParamTy = Param->getType();
+ assert(!ParamTy.isNull() && "Couldn't parse type?");
+ if (ParamTy->containsUnexpandedParameterPack()) return true;
+ }
+
+ if (Chunk.Fun.getExceptionSpecType() == EST_Dynamic) {
+ for (unsigned i = 0; i != Chunk.Fun.NumExceptions; ++i) {
+ if (Chunk.Fun.Exceptions[i]
+ .Ty.get()
+ ->containsUnexpandedParameterPack())
+ return true;
+ }
+ } else if (Chunk.Fun.getExceptionSpecType() == EST_ComputedNoexcept &&
+ Chunk.Fun.NoexceptExpr->containsUnexpandedParameterPack())
+ return true;
+
+ if (Chunk.Fun.hasTrailingReturnType()) {
+ QualType T = Chunk.Fun.getTrailingReturnType().get();
+ if (!T.isNull() && T->containsUnexpandedParameterPack())
+ return true;
+ }
+ break;
+
case DeclaratorChunk::MemberPointer:
if (Chunk.Mem.Scope().getScopeRep() &&
Chunk.Mem.Scope().getScopeRep()->containsUnexpandedParameterPack())
@@ -800,7 +838,6 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
LookupName(R, S);
NamedDecl *ParameterPack = nullptr;
- ParameterPackValidatorCCC Validator;
switch (R.getResultKind()) {
case LookupResult::Found:
ParameterPack = R.getFoundDecl();
@@ -808,9 +845,10 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
- if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), S, nullptr,
- Validator, CTK_ErrorRecovery)) {
+ if (TypoCorrection Corrected =
+ CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, nullptr,
+ llvm::make_unique<ParameterPackValidatorCCC>(),
+ CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(diag::err_sizeof_pack_no_pack_name_suggest) << &Name,
PDiag(diag::note_parameter_pack_here));
@@ -897,3 +935,108 @@ Sema::getTemplateArgumentPackExpansionPattern(
llvm_unreachable("Invalid TemplateArgument Kind!");
}
+
+static void CheckFoldOperand(Sema &S, Expr *E) {
+ if (!E)
+ return;
+
+ E = E->IgnoreImpCasts();
+ if (isa<BinaryOperator>(E) || isa<AbstractConditionalOperator>(E)) {
+ S.Diag(E->getExprLoc(), diag::err_fold_expression_bad_operand)
+ << E->getSourceRange()
+ << FixItHint::CreateInsertion(E->getLocStart(), "(")
+ << FixItHint::CreateInsertion(E->getLocEnd(), ")");
+ }
+}
+
+ExprResult Sema::ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
+ tok::TokenKind Operator,
+ SourceLocation EllipsisLoc, Expr *RHS,
+ SourceLocation RParenLoc) {
+ // LHS and RHS must be cast-expressions. We allow an arbitrary expression
+ // in the parser and reduce down to just cast-expressions here.
+ CheckFoldOperand(*this, LHS);
+ CheckFoldOperand(*this, RHS);
+
+ // [expr.prim.fold]p3:
+ // In a binary fold, op1 and op2 shall be the same fold-operator, and
+ // either e1 shall contain an unexpanded parameter pack or e2 shall contain
+ // an unexpanded parameter pack, but not both.
+ if (LHS && RHS &&
+ LHS->containsUnexpandedParameterPack() ==
+ RHS->containsUnexpandedParameterPack()) {
+ return Diag(EllipsisLoc,
+ LHS->containsUnexpandedParameterPack()
+ ? diag::err_fold_expression_packs_both_sides
+ : diag::err_pack_expansion_without_parameter_packs)
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ }
+
+ // [expr.prim.fold]p2:
+ // In a unary fold, the cast-expression shall contain an unexpanded
+ // parameter pack.
+ if (!LHS || !RHS) {
+ Expr *Pack = LHS ? LHS : RHS;
+ assert(Pack && "fold expression with neither LHS nor RHS");
+ if (!Pack->containsUnexpandedParameterPack())
+ return Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
+ << Pack->getSourceRange();
+ }
+
+ BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Operator);
+ return BuildCXXFoldExpr(LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc);
+}
+
+ExprResult Sema::BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
+ BinaryOperatorKind Operator,
+ SourceLocation EllipsisLoc, Expr *RHS,
+ SourceLocation RParenLoc) {
+ return new (Context) CXXFoldExpr(Context.DependentTy, LParenLoc, LHS,
+ Operator, EllipsisLoc, RHS, RParenLoc);
+}
+
+ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
+ BinaryOperatorKind Operator) {
+ // [temp.variadic]p9:
+ // If N is zero for a unary fold-expression, the value of the expression is
+ // * -> 1
+ // + -> int()
+ // & -> -1
+ // | -> int()
+ // && -> true
+ // || -> false
+ // , -> void()
+ // if the operator is not listed [above], the instantiation is ill-formed.
+ //
+ // Note that we need to use something like int() here, not merely 0, to
+ // prevent the result from being a null pointer constant.
+ QualType ScalarType;
+ switch (Operator) {
+ case BO_Add:
+ ScalarType = Context.IntTy;
+ break;
+ case BO_Mul:
+ return ActOnIntegerConstant(EllipsisLoc, 1);
+ case BO_Or:
+ ScalarType = Context.IntTy;
+ break;
+ case BO_And:
+ return CreateBuiltinUnaryOp(EllipsisLoc, UO_Minus,
+ ActOnIntegerConstant(EllipsisLoc, 1).get());
+ case BO_LOr:
+ return ActOnCXXBoolLiteral(EllipsisLoc, tok::kw_false);
+ case BO_LAnd:
+ return ActOnCXXBoolLiteral(EllipsisLoc, tok::kw_true);
+ case BO_Comma:
+ ScalarType = Context.VoidTy;
+ break;
+
+ default:
+ return Diag(EllipsisLoc, diag::err_fold_expression_empty)
+ << BinaryOperator::getOpcodeStr(Operator);
+ }
+
+ return new (Context) CXXScalarValueInitExpr(
+ ScalarType, Context.getTrivialTypeSourceInfo(ScalarType, EllipsisLoc),
+ EllipsisLoc);
+}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index be1191c1e8e0..0f96a1cbce35 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -107,6 +107,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
case AttributeList::AT_StdCall: \
case AttributeList::AT_ThisCall: \
case AttributeList::AT_Pascal: \
+ case AttributeList::AT_VectorCall: \
case AttributeList::AT_MSABI: \
case AttributeList::AT_SysVABI: \
case AttributeList::AT_Regparm: \
@@ -660,26 +661,27 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
// ...and *prepend* it to the declarator.
SourceLocation NoLoc;
declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction(
- /*HasProto=*/true,
- /*IsAmbiguous=*/false,
- /*LParenLoc=*/NoLoc,
- /*ArgInfo=*/nullptr,
- /*NumArgs=*/0,
- /*EllipsisLoc=*/NoLoc,
- /*RParenLoc=*/NoLoc,
- /*TypeQuals=*/0,
- /*RefQualifierIsLvalueRef=*/true,
- /*RefQualifierLoc=*/NoLoc,
- /*ConstQualifierLoc=*/NoLoc,
- /*VolatileQualifierLoc=*/NoLoc,
- /*MutableLoc=*/NoLoc,
- EST_None,
- /*ESpecLoc=*/NoLoc,
- /*Exceptions=*/nullptr,
- /*ExceptionRanges=*/nullptr,
- /*NumExceptions=*/0,
- /*NoexceptExpr=*/nullptr,
- loc, loc, declarator));
+ /*HasProto=*/true,
+ /*IsAmbiguous=*/false,
+ /*LParenLoc=*/NoLoc,
+ /*ArgInfo=*/nullptr,
+ /*NumArgs=*/0,
+ /*EllipsisLoc=*/NoLoc,
+ /*RParenLoc=*/NoLoc,
+ /*TypeQuals=*/0,
+ /*RefQualifierIsLvalueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
+ /*RestrictQualifierLoc=*/NoLoc,
+ /*MutableLoc=*/NoLoc, EST_None,
+ /*ESpecLoc=*/NoLoc,
+ /*Exceptions=*/nullptr,
+ /*ExceptionRanges=*/nullptr,
+ /*NumExceptions=*/0,
+ /*NoexceptExpr=*/nullptr,
+ /*ExceptionSpecTokens=*/nullptr,
+ loc, loc, declarator));
// For consistency, make sure the state still has us as processing
// the decl spec.
@@ -763,7 +765,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// is inferred from the return statements inside the block.
// The declspec is always missing in a lambda expr context; it is either
// specified with a trailing return type or inferred.
- if (S.getLangOpts().CPlusPlus1y &&
+ if (S.getLangOpts().CPlusPlus14 &&
declarator.getContext() == Declarator::LambdaExprContext) {
// In C++1y, a lambda's implicit return type is 'auto'.
Result = Context.getAutoDeductType();
@@ -1005,16 +1007,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
const bool IsParameterPack = declarator.hasEllipsis();
-
- // Create a name for the invented template parameter type.
- std::string InventedTemplateParamName = "$auto-";
- llvm::raw_string_ostream ss(InventedTemplateParamName);
- ss << TemplateParameterDepth;
- ss << "-" << AutoParameterPosition;
- ss.flush();
-
- IdentifierInfo& TemplateParamII = Context.Idents.get(
- InventedTemplateParamName.c_str());
+
// Turns out we must create the TemplateTypeParmDecl here to
// retrieve the corresponding template parameter type.
TemplateTypeParmDecl *CorrespondingTemplateParam =
@@ -1029,11 +1022,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
/*NameLoc*/ declarator.getLocStart(),
TemplateParameterDepth,
AutoParameterPosition, // our template param index
- /* Identifier*/ &TemplateParamII, false, IsParameterPack);
+ /* Identifier*/ nullptr, false, IsParameterPack);
LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
// Replace the 'auto' in the function parameter with this invented
// template type parameter.
- Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);
+ Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);
} else {
Result = Context.getAutoType(QualType(), /*decltype(auto)*/false, false);
}
@@ -1107,8 +1100,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
S.Diag(DS.getConstSpecLoc(), diag::warn_typecheck_function_qualifiers)
<< Result << DS.getSourceRange();
else if (TypeQuals & DeclSpec::TQ_volatile)
- S.Diag(DS.getVolatileSpecLoc(), diag::warn_typecheck_function_qualifiers)
- << Result << DS.getSourceRange();
+ S.Diag(DS.getVolatileSpecLoc(),
+ diag::warn_typecheck_function_qualifiers)
+ << Result << DS.getSourceRange();
else {
assert((TypeQuals & (DeclSpec::TQ_restrict | DeclSpec::TQ_atomic)) &&
"Has CVRA quals but not C, V, R, or A?");
@@ -1174,6 +1168,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Qualified;
}
+ assert(!Result.isNull() && "This function should not return a null type");
return Result;
}
@@ -1186,6 +1181,9 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) {
QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
Qualifiers Qs, const DeclSpec *DS) {
+ if (T.isNull())
+ return QualType();
+
// Enforce C99 6.7.3p2: "Types other than pointer types derived from
// object or incomplete types shall not be restrict-qualified."
if (Qs.hasRestrict()) {
@@ -1224,6 +1222,9 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
unsigned CVRA, const DeclSpec *DS) {
+ if (T.isNull())
+ return QualType();
+
// Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic.
unsigned CVR = CVRA & ~DeclSpec::TQ_atomic;
@@ -1746,7 +1747,7 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
}
// Functions cannot return half FP.
- if (T->isHalfType()) {
+ if (T->isHalfType() && !getLangOpts().HalfArgsAndReturns) {
Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 <<
FixItHint::CreateInsertion(Loc, "*");
return true;
@@ -1776,7 +1777,7 @@ QualType Sema::BuildFunctionType(QualType T,
if (ParamType->isVoidType()) {
Diag(Loc, diag::err_param_with_void_type);
Invalid = true;
- } else if (ParamType->isHalfType()) {
+ } else if (ParamType->isHalfType() && !getLangOpts().HalfArgsAndReturns) {
// Disallow half FP arguments.
Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 <<
FixItHint::CreateInsertion(Loc, "*");
@@ -2175,7 +2176,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
Error = 0;
break;
case Declarator::LambdaExprParameterContext:
- if (!(SemaRef.getLangOpts().CPlusPlus1y
+ if (!(SemaRef.getLangOpts().CPlusPlus14
&& D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto))
Error = 14;
break;
@@ -2208,11 +2209,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
Error = 10; // Type alias
break;
case Declarator::TrailingReturnContext:
- if (!SemaRef.getLangOpts().CPlusPlus1y)
+ if (!SemaRef.getLangOpts().CPlusPlus14)
Error = 11; // Function return type
break;
case Declarator::ConversionIdContext:
- if (!SemaRef.getLangOpts().CPlusPlus1y)
+ if (!SemaRef.getLangOpts().CPlusPlus14)
Error = 12; // conversion-type-id
break;
case Declarator::TypeNameContext:
@@ -2332,6 +2333,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
}
}
+ assert(!T.isNull() && "This function should not return a null type");
return T;
}
@@ -2481,7 +2483,8 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D,
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
-
+ // The TypeSourceInfo that this function returns will not be a null type.
+ // If there is an error, this function will fill in a dummy type as fallback.
QualType T = declSpecType;
Declarator &D = state.getDeclarator();
Sema &S = state.getSema();
@@ -2697,7 +2700,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// and not, for instance, a pointer to a function.
if (D.getDeclSpec().containsPlaceholderType() &&
!FTI.hasTrailingReturnType() && chunkIndex == 0 &&
- !S.getLangOpts().CPlusPlus1y) {
+ !S.getLangOpts().CPlusPlus14) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto
? diag::err_auto_missing_trailing_return
@@ -2751,7 +2754,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
S.Diag(D.getIdentifierLoc(), diag::err_opencl_half_return) << T;
D.setInvalidType(true);
}
- } else {
+ } else if (!S.getLangOpts().HalfArgsAndReturns) {
S.Diag(D.getIdentifierLoc(),
diag::err_parameters_retval_cannot_have_fp16_type) << 1;
D.setInvalidType(true);
@@ -2941,7 +2944,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
D.setInvalidType();
Param->setInvalidDecl();
}
- } else {
+ } else if (!S.getLangOpts().HalfArgsAndReturns) {
S.Diag(Param->getLocation(),
diag::err_parameters_retval_cannot_have_fp16_type) << 0;
D.setInvalidType();
@@ -2989,12 +2992,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
NoexceptExpr = FTI.NoexceptExpr;
}
- S.checkExceptionSpecification(FTI.getExceptionSpecType(),
+ S.checkExceptionSpecification(D.isFunctionDeclarationContext(),
+ FTI.getExceptionSpecType(),
DynamicExceptions,
DynamicExceptionRanges,
NoexceptExpr,
Exceptions,
- EPI);
+ EPI.ExceptionSpec);
T = Context.getFunctionType(T, ParamTys, EPI);
}
@@ -3021,6 +3025,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
llvm_unreachable("Nested-name-specifier must name a type");
case NestedNameSpecifier::TypeSpec:
@@ -3044,7 +3049,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
if (!ClsType.isNull())
- T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier());
+ T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc,
+ D.getIdentifier());
if (T.isNull()) {
T = Context.IntTy;
D.setInvalidType(true);
@@ -3064,6 +3070,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
processTypeAttrs(state, T, TAL_DeclChunk, attrs);
}
+ assert(!T.isNull() && "T must not be null after this point");
+
if (LangOpts.CPlusPlus && T->isFunctionType()) {
const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>();
assert(FnTy && "Why oh why is there not a FunctionProtoType here?");
@@ -3120,9 +3128,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
RemovalLocs.push_back(Chunk.Fun.getConstQualifierLoc());
if (Chunk.Fun.TypeQuals & Qualifiers::Volatile)
RemovalLocs.push_back(Chunk.Fun.getVolatileQualifierLoc());
- // FIXME: We do not track the location of the __restrict qualifier.
- //if (Chunk.Fun.TypeQuals & Qualifiers::Restrict)
- // RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc());
+ if (Chunk.Fun.TypeQuals & Qualifiers::Restrict)
+ RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc());
if (!RemovalLocs.empty()) {
std::sort(RemovalLocs.begin(), RemovalLocs.end(),
BeforeThanCompare<SourceLocation>(S.getSourceManager()));
@@ -3153,12 +3160,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
// Apply any undistributed attributes from the declarator.
- if (!T.isNull())
- if (AttributeList *attrs = D.getAttributes())
- processTypeAttrs(state, T, TAL_DeclName, attrs);
+ if (AttributeList *attrs = D.getAttributes())
+ processTypeAttrs(state, T, TAL_DeclName, attrs);
// Diagnose any ignored type attributes.
- if (!T.isNull()) state.diagnoseIgnoredTypeAttrs(T);
+ state.diagnoseIgnoredTypeAttrs(T);
// C++0x [dcl.constexpr]p9:
// A constexpr specifier used in an object declaration declares the object
@@ -3169,7 +3175,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If there was an ellipsis in the declarator, the declaration declares a
// parameter pack whose type may be a pack expansion type.
- if (D.hasEllipsis() && !T.isNull()) {
+ if (D.hasEllipsis()) {
// C++0x [dcl.fct]p13:
// A declarator-id or abstract-declarator containing an ellipsis shall
// only be used in a parameter-declaration. Such a parameter-declaration
@@ -3234,15 +3240,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case Declarator::TemplateTypeArgContext:
// FIXME: We may want to allow parameter packs in block-literal contexts
// in the future.
- S.Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter);
+ S.Diag(D.getEllipsisLoc(),
+ diag::err_ellipsis_in_declarator_not_parameter);
D.setEllipsisLoc(SourceLocation());
break;
}
}
- if (T.isNull())
- return Context.getNullTypeSourceInfo();
- else if (D.isInvalidType())
+ assert(!T.isNull() && "T must not be null at the end of this function");
+ if (D.isInvalidType())
return Context.getTrivialTypeSourceInfo(T);
return S.GetTypeSourceInfoForDeclarator(D, T, TInfo);
@@ -3261,8 +3267,6 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
TypeSourceInfo *ReturnTypeInfo = nullptr;
QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
- if (T.isNull())
- return Context.getNullTypeSourceInfo();
if (D.isPrototypeContext() && getLangOpts().ObjCAutoRefCount)
inferARCWriteback(state, T);
@@ -3376,8 +3380,6 @@ TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) {
TypeSourceInfo *ReturnTypeInfo = nullptr;
QualType declSpecTy = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
- if (declSpecTy.isNull())
- return Context.getNullTypeSourceInfo();
if (getLangOpts().ObjCAutoRefCount) {
Qualifiers::ObjCLifetime ownership = Context.getInnerObjCOwnership(FromTy);
@@ -3417,6 +3419,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_ThisCall;
case AttributedType::attr_pascal:
return AttributeList::AT_Pascal;
+ case AttributedType::attr_vectorcall:
+ return AttributeList::AT_VectorCall;
case AttributedType::attr_pcs:
case AttributedType::attr_pcs_vfp:
return AttributeList::AT_Pcs;
@@ -3717,6 +3721,7 @@ namespace {
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
llvm_unreachable("Nested-name-specifier must name a type");
}
@@ -3975,6 +3980,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
ASIdx = LangAS::opencl_local; break;
case AttributeList::AT_OpenCLConstantAddressSpace:
ASIdx = LangAS::opencl_constant; break;
+ case AttributeList::AT_OpenCLGenericAddressSpace:
+ ASIdx = LangAS::opencl_generic; break;
default:
assert(Attr.getKind() == AttributeList::AT_OpenCLPrivateAddressSpace);
ASIdx = 0; break;
@@ -4432,6 +4439,8 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) {
return AttributedType::attr_thiscall;
case AttributeList::AT_Pascal:
return AttributedType::attr_pascal;
+ case AttributeList::AT_VectorCall:
+ return AttributedType::attr_vectorcall;
case AttributeList::AT_Pcs: {
// The attribute may have had a fixit applied where we treated an
// identifier as a string literal. The contents of the string are valid,
@@ -4549,7 +4558,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
}
// Diagnose use of callee-cleanup calling convention on variadic functions.
- if (isCalleeCleanup(CC)) {
+ if (!supportsVariadicCall(CC)) {
const FunctionProtoType *FnP = dyn_cast<FunctionProtoType>(fn);
if (FnP && FnP->isVariadic()) {
unsigned DiagID = diag::err_cconv_varargs;
@@ -4564,23 +4573,12 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
}
}
- // Diagnose the use of X86 fastcall on unprototyped functions.
- if (CC == CC_X86FastCall) {
- if (isa<FunctionNoProtoType>(fn)) {
- S.Diag(attr.getLoc(), diag::err_cconv_knr)
- << FunctionType::getNameForCallConv(CC);
- attr.setInvalid();
- return true;
- }
-
- // Also diagnose fastcall with regparm.
- if (fn->getHasRegParm()) {
- S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "regparm"
- << FunctionType::getNameForCallConv(CC);
- attr.setInvalid();
- return true;
- }
+ // Also diagnose fastcall with regparm.
+ if (CC == CC_X86FastCall && fn->getHasRegParm()) {
+ S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall);
+ attr.setInvalid();
+ return true;
}
// Modify the CC from the wrapped function type, wrap it all back, and then
@@ -4739,9 +4737,7 @@ static bool isPermittedNeonBaseType(QualType &Ty,
// Signed poly is mathematically wrong, but has been baked into some ABIs by
// now.
bool IsPolyUnsigned = Triple.getArch() == llvm::Triple::aarch64 ||
- Triple.getArch() == llvm::Triple::aarch64_be ||
- Triple.getArch() == llvm::Triple::arm64 ||
- Triple.getArch() == llvm::Triple::arm64_be;
+ Triple.getArch() == llvm::Triple::aarch64_be;
if (VecKind == VectorType::NeonPolyVector) {
if (IsPolyUnsigned) {
// AArch64 polynomial vectors are unsigned and support poly64.
@@ -4759,9 +4755,7 @@ static bool isPermittedNeonBaseType(QualType &Ty,
// Non-polynomial vector types: the usual suspects are allowed, as well as
// float64_t on AArch64.
bool Is64Bit = Triple.getArch() == llvm::Triple::aarch64 ||
- Triple.getArch() == llvm::Triple::aarch64_be ||
- Triple.getArch() == llvm::Triple::arm64 ||
- Triple.getArch() == llvm::Triple::arm64_be;
+ Triple.getArch() == llvm::Triple::aarch64_be;
if (Is64Bit && BTy->getKind() == BuiltinType::Double)
return true;
@@ -4899,6 +4893,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case AttributeList::AT_OpenCLGlobalAddressSpace:
case AttributeList::AT_OpenCLLocalAddressSpace:
case AttributeList::AT_OpenCLConstantAddressSpace:
+ case AttributeList::AT_OpenCLGenericAddressSpace:
case AttributeList::AT_AddressSpace:
HandleAddressSpaceTypeAttribute(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
@@ -5098,31 +5093,9 @@ static bool hasVisibleDefinition(Sema &S, NamedDecl *D, NamedDecl **Suggested) {
// If this definition was instantiated from a template, map back to the
// pattern from which it was instantiated.
- //
- // FIXME: There must be a better place for this to live.
if (auto *RD = dyn_cast<CXXRecordDecl>(D)) {
- if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
- auto From = TD->getInstantiatedFrom();
- if (auto *CTD = From.dyn_cast<ClassTemplateDecl*>()) {
- while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
- if (NewCTD->isMemberSpecialization())
- break;
- CTD = NewCTD;
- }
- RD = CTD->getTemplatedDecl();
- } else if (auto *CTPSD = From.dyn_cast<
- ClassTemplatePartialSpecializationDecl *>()) {
- while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
- if (NewCTPSD->isMemberSpecialization())
- break;
- CTPSD = NewCTPSD;
- }
- RD = CTPSD;
- }
- } else if (isTemplateInstantiation(RD->getTemplateSpecializationKind())) {
- while (auto *NewRD = RD->getInstantiatedFromMemberClass())
- RD = NewRD;
- }
+ if (auto *Pattern = RD->getTemplateInstantiationPattern())
+ RD = Pattern;
D = RD->getDefinition();
} else if (auto *ED = dyn_cast<EnumDecl>(D)) {
while (auto *NewED = ED->getInstantiatedFromMemberEnum())
@@ -5178,14 +5151,6 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
? S.ImplicitMSInheritanceAttrLoc
: RD->getSourceRange()));
}
-
- if (RD->hasDefinition()) {
- // Assign inheritance models to all of the base classes, because now we can
- // form pointers to members of base classes without calling
- // RequireCompleteType on the pointer to member of the base class type.
- for (const CXXBaseSpecifier &BS : RD->bases())
- assignInheritanceModel(S, BS.getType()->getAsCXXRecordDecl());
- }
}
/// \brief The implementation of RequireCompleteType
@@ -5510,6 +5475,8 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
} else if (const ObjCPropertyRefExpr *PR = dyn_cast<ObjCPropertyRefExpr>(E)) {
if (PR->isExplicitProperty())
return PR->getExplicitProperty()->getType();
+ } else if (auto *PE = dyn_cast<PredefinedExpr>(E)) {
+ return PE->getType();
}
// C++11 [expr.lambda.prim]p18:
@@ -5550,11 +5517,19 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
return T;
}
-QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) {
+QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc,
+ bool AsUnevaluated) {
ExprResult ER = CheckPlaceholderExpr(E);
if (ER.isInvalid()) return QualType();
E = ER.get();
+ if (AsUnevaluated && ActiveTemplateInstantiations.empty() &&
+ E->HasSideEffects(Context, false)) {
+ // The expression operand for decltype is in an unevaluated expression
+ // context, so side effects could result in unintended consequences.
+ Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
+ }
+
return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 312811d2c008..36abbb624af7 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H
-#define LLVM_CLANG_SEMA_TREETRANSFORM_H
+#ifndef LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H
+#define LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H
#include "TypeLocBuilder.h"
#include "clang/AST/Decl.h"
@@ -327,6 +327,27 @@ public:
/// \returns the transformed OpenMP clause.
OMPClause *TransformOMPClause(OMPClause *S);
+ /// \brief Transform the given attribute.
+ ///
+ /// By default, this routine transforms a statement by delegating to the
+ /// appropriate TransformXXXAttr function to transform a specific kind
+ /// of attribute. Subclasses may override this function to transform
+ /// attributed statements using some other mechanism.
+ ///
+ /// \returns the transformed attribute
+ const Attr *TransformAttr(const Attr *S);
+
+/// \brief Transform the specified attribute.
+///
+/// Subclasses should override the transformation of attributes with a pragma
+/// spelling to transform expressions stored within the attribute.
+///
+/// \returns the transformed attribute.
+#define ATTR(X)
+#define PRAGMA_SPELLING_ATTR(X) \
+ const X##Attr *Transform##X##Attr(const X##Attr *R) { return R; }
+#include "clang/Basic/AttrList.inc"
+
/// \brief Transform the given expression.
///
/// By default, this routine transforms an expression by delegating to the
@@ -542,10 +563,17 @@ public:
QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
#include "clang/AST/TypeLocNodes.def"
+ template<typename Fn>
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL,
CXXRecordDecl *ThisContext,
- unsigned ThisTypeQuals);
+ unsigned ThisTypeQuals,
+ Fn TransformExceptionSpec);
+
+ bool TransformExceptionSpec(SourceLocation Loc,
+ FunctionProtoType::ExceptionSpecInfo &ESI,
+ SmallVectorImpl<QualType> &Exceptions,
+ bool &Changed);
StmtResult TransformSEHHandler(Stmt *Handler);
@@ -560,10 +588,9 @@ public:
TemplateName Template,
CXXScopeSpec &SS);
- QualType
- TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
- DependentTemplateSpecializationTypeLoc TL,
- NestedNameSpecifierLoc QualifierLoc);
+ QualType TransformDependentTemplateSpecializationType(
+ TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL,
+ NestedNameSpecifierLoc QualifierLoc);
/// \brief Transforms the parameters of a function type into the
/// given vectors.
@@ -1665,10 +1692,8 @@ public:
}
StmtResult RebuildSEHTryStmt(bool IsCXXTry, SourceLocation TryLoc,
- Stmt *TryBlock, Stmt *Handler, int HandlerIndex,
- int HandlerParentIndex) {
- return getSema().ActOnSEHTryBlock(IsCXXTry, TryLoc, TryBlock, Handler,
- HandlerIndex, HandlerParentIndex);
+ Stmt *TryBlock, Stmt *Handler) {
+ return getSema().ActOnSEHTryBlock(IsCXXTry, TryLoc, TryBlock, Handler);
}
StmtResult RebuildSEHExceptStmt(SourceLocation Loc, Expr *FilterExpr,
@@ -1680,6 +1705,15 @@ public:
return getSema().ActOnSEHFinallyBlock(Loc, Block);
}
+ /// \brief Build a new predefined expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildPredefinedExpr(SourceLocation Loc,
+ PredefinedExpr::IdentType IT) {
+ return getSema().BuildPredefinedExpr(Loc, IT);
+ }
+
/// \brief Build a new expression that references a declaration.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2757,6 +2791,27 @@ public:
return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions);
}
+ /// \brief Build a new C++1z fold-expression.
+ ///
+ /// By default, performs semantic analysis in order to build a new fold
+ /// expression.
+ ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
+ BinaryOperatorKind Operator,
+ SourceLocation EllipsisLoc, Expr *RHS,
+ SourceLocation RParenLoc) {
+ return getSema().BuildCXXFoldExpr(LParenLoc, LHS, Operator, EllipsisLoc,
+ RHS, RParenLoc);
+ }
+
+ /// \brief Build an empty C++1z fold-expression with the given operator.
+ ///
+ /// By default, produces the fallback value for the fold-expression, or
+ /// produce an error if there is no fallback value.
+ ExprResult RebuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
+ BinaryOperatorKind Operator) {
+ return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator);
+ }
+
/// \brief Build a new atomic operation expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -3103,6 +3158,14 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
SS.MakeGlobal(SemaRef.Context, Q.getBeginLoc());
break;
+ case NestedNameSpecifier::Super: {
+ CXXRecordDecl *RD =
+ cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
+ SourceLocation(), QNNS->getAsRecordDecl()));
+ SS.MakeSuper(SemaRef.Context, RD, Q.getBeginLoc(), Q.getEndLoc());
+ break;
+ }
+
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec: {
TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType,
@@ -4515,15 +4578,20 @@ template<typename Derived>
QualType
TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL) {
- return getDerived().TransformFunctionProtoType(TLB, TL, nullptr, 0);
-}
-
-template<typename Derived>
-QualType
-TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
- FunctionProtoTypeLoc TL,
- CXXRecordDecl *ThisContext,
- unsigned ThisTypeQuals) {
+ SmallVector<QualType, 4> ExceptionStorage;
+ TreeTransform *This = this; // Work around gcc.gnu.org/PR56135.
+ return getDerived().TransformFunctionProtoType(
+ TLB, TL, nullptr, 0,
+ [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) {
+ return This->TransformExceptionSpec(TL.getBeginLoc(), ESI,
+ ExceptionStorage, Changed);
+ });
+}
+
+template<typename Derived> template<typename Fn>
+QualType TreeTransform<Derived>::TransformFunctionProtoType(
+ TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext,
+ unsigned ThisTypeQuals, Fn TransformExceptionSpec) {
// Transform the parameters and return type.
//
// We are required to instantiate the params and return type in source order.
@@ -4568,15 +4636,21 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
return QualType();
}
- // FIXME: Need to transform the exception-specification too.
+ FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo();
+
+ bool EPIChanged = false;
+ if (TransformExceptionSpec(EPI.ExceptionSpec, EPIChanged))
+ return QualType();
+
+ // FIXME: Need to transform ConsumedParameters for variadic template
+ // expansion.
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() ||
T->getNumParams() != ParamTypes.size() ||
!std::equal(T->param_type_begin(), T->param_type_end(),
- ParamTypes.begin())) {
- Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes,
- T->getExtProtoInfo());
+ ParamTypes.begin()) || EPIChanged) {
+ Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, EPI);
if (Result.isNull())
return QualType();
}
@@ -4593,6 +4667,107 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
}
template<typename Derived>
+bool TreeTransform<Derived>::TransformExceptionSpec(
+ SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI,
+ SmallVectorImpl<QualType> &Exceptions, bool &Changed) {
+ assert(ESI.Type != EST_Uninstantiated && ESI.Type != EST_Unevaluated);
+
+ // Instantiate a dynamic noexcept expression, if any.
+ if (ESI.Type == EST_ComputedNoexcept) {
+ EnterExpressionEvaluationContext Unevaluated(getSema(),
+ Sema::ConstantEvaluated);
+ ExprResult NoexceptExpr = getDerived().TransformExpr(ESI.NoexceptExpr);
+ if (NoexceptExpr.isInvalid())
+ return true;
+
+ NoexceptExpr = getSema().CheckBooleanCondition(
+ NoexceptExpr.get(), NoexceptExpr.get()->getLocStart());
+ if (NoexceptExpr.isInvalid())
+ return true;
+
+ if (!NoexceptExpr.get()->isValueDependent()) {
+ NoexceptExpr = getSema().VerifyIntegerConstantExpression(
+ NoexceptExpr.get(), nullptr,
+ diag::err_noexcept_needs_constant_expression,
+ /*AllowFold*/false);
+ if (NoexceptExpr.isInvalid())
+ return true;
+ }
+
+ if (ESI.NoexceptExpr != NoexceptExpr.get())
+ Changed = true;
+ ESI.NoexceptExpr = NoexceptExpr.get();
+ }
+
+ if (ESI.Type != EST_Dynamic)
+ return false;
+
+ // Instantiate a dynamic exception specification's type.
+ for (QualType T : ESI.Exceptions) {
+ if (const PackExpansionType *PackExpansion =
+ T->getAs<PackExpansionType>()) {
+ Changed = true;
+
+ // We have a pack expansion. Instantiate it.
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
+ Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+ // Determine whether the set of unexpanded parameter packs can and
+ // should
+ // be expanded.
+ bool Expand = false;
+ bool RetainExpansion = false;
+ Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
+ // FIXME: Track the location of the ellipsis (and track source location
+ // information for the types in the exception specification in general).
+ if (getDerived().TryExpandParameterPacks(
+ Loc, SourceRange(), Unexpanded, Expand,
+ RetainExpansion, NumExpansions))
+ return true;
+
+ if (!Expand) {
+ // We can't expand this pack expansion into separate arguments yet;
+ // just substitute into the pattern and create a new pack expansion
+ // type.
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+ QualType U = getDerived().TransformType(PackExpansion->getPattern());
+ if (U.isNull())
+ return true;
+
+ U = SemaRef.Context.getPackExpansionType(U, NumExpansions);
+ Exceptions.push_back(U);
+ continue;
+ }
+
+ // Substitute into the pack expansion pattern for each slice of the
+ // pack.
+ for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx);
+
+ QualType U = getDerived().TransformType(PackExpansion->getPattern());
+ if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc))
+ return true;
+
+ Exceptions.push_back(U);
+ }
+ } else {
+ QualType U = getDerived().TransformType(T);
+ if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc))
+ return true;
+ if (T != U)
+ Changed = true;
+
+ Exceptions.push_back(U);
+ }
+ }
+
+ ESI.Exceptions = Exceptions;
+ return false;
+}
+
+template<typename Derived>
QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
TypeLocBuilder &TLB,
FunctionNoProtoTypeLoc TL) {
@@ -5147,8 +5322,8 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
if (const TemplateSpecializationType *TST =
NamedT->getAs<TemplateSpecializationType>()) {
TemplateName Template = TST->getTemplateName();
- if (TypeAliasTemplateDecl *TAT =
- dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) {
+ 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);
@@ -5529,19 +5704,43 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) {
SubStmt.get());
}
-template<typename Derived>
-StmtResult
-TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) {
+template <typename Derived>
+const Attr *TreeTransform<Derived>::TransformAttr(const Attr *R) {
+ if (!R)
+ return R;
+
+ switch (R->getKind()) {
+// Transform attributes with a pragma spelling by calling TransformXXXAttr.
+#define ATTR(X)
+#define PRAGMA_SPELLING_ATTR(X) \
+ case attr::X: \
+ return getDerived().Transform##X##Attr(cast<X##Attr>(R));
+#include "clang/Basic/AttrList.inc"
+ default:
+ return R;
+ }
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) {
+ bool AttrsChanged = false;
+ SmallVector<const Attr *, 1> Attrs;
+
+ // Visit attributes and keep track if any are transformed.
+ for (const auto *I : S->getAttrs()) {
+ const Attr *R = getDerived().TransformAttr(I);
+ AttrsChanged |= (I != R);
+ Attrs.push_back(R);
+ }
+
StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
if (SubStmt.isInvalid())
return StmtError();
- // TODO: transform attributes
- if (SubStmt.get() == S->getSubStmt() /* && attrs are the same */)
+ if (SubStmt.get() == S->getSubStmt() && !AttrsChanged)
return S;
- return getDerived().RebuildAttributedStmt(S->getAttrLoc(),
- S->getAttrs(),
+ return getDerived().RebuildAttributedStmt(S->getAttrLoc(), Attrs,
SubStmt.get());
}
@@ -5824,7 +6023,8 @@ TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformReturnStmt(ReturnStmt *S) {
- ExprResult Result = getDerived().TransformExpr(S->getRetValue());
+ ExprResult Result = getDerived().TransformInitializer(S->getRetValue(),
+ /*NotCopyInit*/false);
if (Result.isInvalid())
return StmtError();
@@ -6380,9 +6580,8 @@ StmtResult TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
Handler.get() == S->getHandler())
return S;
- return getDerived().RebuildSEHTryStmt(
- S->getIsCXXTry(), S->getTryLoc(), TryBlock.get(), Handler.get(),
- S->getHandlerIndex(), S->getHandlerParentIndex());
+ return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(), S->getTryLoc(),
+ TryBlock.get(), Handler.get());
}
template <typename Derived>
@@ -6504,6 +6703,17 @@ TreeTransform<Derived>::TransformOMPForDirective(OMPForDirective *D) {
template <typename Derived>
StmtResult
+TreeTransform<Derived>::TransformOMPForSimdDirective(OMPForSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_for_simd, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
TreeTransform<Derived>::TransformOMPSectionsDirective(OMPSectionsDirective *D) {
DeclarationNameInfo DirName;
getDerived().getSema().StartOpenMPDSABlock(OMPD_sections, DirName, nullptr,
@@ -6568,6 +6778,17 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelForDirective(
}
template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPParallelForSimdDirective(
+ OMPParallelForSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_for_simd, DirName,
+ nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPParallelSectionsDirective(
OMPParallelSectionsDirective *D) {
DeclarationNameInfo DirName;
@@ -6633,6 +6854,50 @@ TreeTransform<Derived>::TransformOMPFlushDirective(OMPFlushDirective *D) {
return Res;
}
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPOrderedDirective(OMPOrderedDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_ordered, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPAtomicDirective(OMPAtomicDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_atomic, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPTargetDirective(OMPTargetDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_target, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPTeamsDirective(OMPTeamsDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_teams, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clause transformation
//===----------------------------------------------------------------------===//
@@ -6740,6 +7005,39 @@ TreeTransform<Derived>::TransformOMPMergeableClause(OMPMergeableClause *C) {
}
template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPReadClause(OMPReadClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPWriteClause(OMPWriteClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPUpdateClause(OMPUpdateClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPCaptureClause(OMPCaptureClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPSeqCstClause(OMPSeqCstClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
@@ -6912,7 +7210,11 @@ OMPClause *TreeTransform<Derived>::TransformOMPFlushClause(OMPFlushClause *C) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) {
- return E;
+ if (!E->isTypeDependent())
+ return E;
+
+ return getDerived().RebuildPredefinedExpr(E->getLocation(),
+ E->getIdentType());
}
template<typename Derived>
@@ -7161,6 +7463,12 @@ TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformTypoExpr(TypoExpr *E) {
+ return E;
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) {
// Rebuild the syntactic form. The original syntactic form has
// opaque-value expressions in it, so strip those away and rebuild
@@ -7873,15 +8181,11 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
Type == E->getTypeInfoAsWritten() &&
SubExpr.get() == E->getSubExpr())
return E;
- return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
- E->getStmtClass(),
- E->getAngleBrackets().getBegin(),
- Type,
- E->getAngleBrackets().getEnd(),
- // FIXME. this should be '(' location
- E->getAngleBrackets().getEnd(),
- SubExpr.get(),
- E->getRParenLoc());
+ return getDerived().RebuildCXXNamedCastExpr(
+ E->getOperatorLoc(), E->getStmtClass(), E->getAngleBrackets().getBegin(),
+ Type, E->getAngleBrackets().getEnd(),
+ // FIXME. this should be '(' location
+ E->getAngleBrackets().getEnd(), SubExpr.get(), E->getRParenLoc());
}
template<typename Derived>
@@ -8786,113 +9090,68 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
-
- // Transform any init-capture expressions before entering the scope of the
+ // Transform any init-capture expressions before entering the scope of the
// lambda body, because they are not semantically within that scope.
SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes;
InitCaptureExprsAndTypes.resize(E->explicit_capture_end() -
E->explicit_capture_begin());
-
for (LambdaExpr::capture_iterator C = E->capture_begin(),
- CEnd = E->capture_end();
- C != CEnd; ++C) {
+ CEnd = E->capture_end();
+ C != CEnd; ++C) {
if (!C->isInitCapture())
continue;
- EnterExpressionEvaluationContext EEEC(getSema(),
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext EEEC(getSema(),
+ Sema::PotentiallyEvaluated);
ExprResult NewExprInitResult = getDerived().TransformInitializer(
C->getCapturedVar()->getInit(),
C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
-
+
if (NewExprInitResult.isInvalid())
return ExprError();
Expr *NewExprInit = NewExprInitResult.get();
-
+
VarDecl *OldVD = C->getCapturedVar();
- QualType NewInitCaptureType =
- getSema().performLambdaInitCaptureInitialization(C->getLocation(),
- OldVD->getType()->isReferenceType(), OldVD->getIdentifier(),
+ QualType NewInitCaptureType =
+ getSema().performLambdaInitCaptureInitialization(C->getLocation(),
+ OldVD->getType()->isReferenceType(), OldVD->getIdentifier(),
NewExprInit);
NewExprInitResult = NewExprInit;
InitCaptureExprsAndTypes[C - E->capture_begin()] =
std::make_pair(NewExprInitResult, NewInitCaptureType);
-
}
LambdaScopeInfo *LSI = getSema().PushLambdaScope();
+ Sema::FunctionScopeRAII FuncScopeCleanup(getSema());
+
// Transform the template parameters, and add them to the current
// instantiation scope. The null case is handled correctly.
LSI->GLTemplateParameterList = getDerived().TransformTemplateParameterList(
E->getTemplateParameterList());
- // Check to see if the TypeSourceInfo of the call operator needs to
- // be transformed, and if so do the transformation in the
- // CurrentInstantiationScope.
-
- TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
- FunctionProtoTypeLoc OldCallOpFPTL =
- OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+ // Transform the type of the original lambda's call operator.
+ // The transformation MUST be done in the CurrentInstantiationScope since
+ // it introduces a mapping of the original to the newly created
+ // transformed parameters.
TypeSourceInfo *NewCallOpTSI = nullptr;
-
- const bool CallOpWasAlreadyTransformed =
- getDerived().AlreadyTransformed(OldCallOpTSI->getType());
-
- // Use the Old Call Operator's TypeSourceInfo if it is already transformed.
- if (CallOpWasAlreadyTransformed)
- NewCallOpTSI = OldCallOpTSI;
- else {
- // Transform the TypeSourceInfo of the Original Lambda's Call Operator.
- // The transformation MUST be done in the CurrentInstantiationScope since
- // it introduces a mapping of the original to the newly created
- // transformed parameters.
+ {
+ TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
+ FunctionProtoTypeLoc OldCallOpFPTL =
+ OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
TypeLocBuilder NewCallOpTLBuilder;
- QualType NewCallOpType = TransformFunctionProtoType(NewCallOpTLBuilder,
- OldCallOpFPTL,
- nullptr, 0);
+ SmallVector<QualType, 4> ExceptionStorage;
+ TreeTransform *This = this; // Work around gcc.gnu.org/PR56135.
+ QualType NewCallOpType = TransformFunctionProtoType(
+ NewCallOpTLBuilder, OldCallOpFPTL, nullptr, 0,
+ [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) {
+ return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI,
+ ExceptionStorage, Changed);
+ });
+ if (NewCallOpType.isNull())
+ return ExprError();
NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context,
NewCallOpType);
}
- // Extract the ParmVarDecls from the NewCallOpTSI and add them to
- // the vector below - this will be used to synthesize the
- // NewCallOperator. Additionally, add the parameters of the untransformed
- // lambda call operator to the CurrentInstantiationScope.
- SmallVector<ParmVarDecl *, 4> Params;
- {
- FunctionProtoTypeLoc NewCallOpFPTL =
- NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
- ParmVarDecl **NewParamDeclArray = NewCallOpFPTL.getParmArray();
- const unsigned NewNumArgs = NewCallOpFPTL.getNumParams();
-
- for (unsigned I = 0; I < NewNumArgs; ++I) {
- // If this call operator's type does not require transformation,
- // the parameters do not get added to the current instantiation scope,
- // - so ADD them! This allows the following to compile when the enclosing
- // template is specialized and the entire lambda expression has to be
- // transformed.
- // template<class T> void foo(T t) {
- // auto L = [](auto a) {
- // auto M = [](char b) { <-- note: non-generic lambda
- // auto N = [](auto c) {
- // int x = sizeof(a);
- // x = sizeof(b); <-- specifically this line
- // x = sizeof(c);
- // };
- // };
- // };
- // }
- // foo('a')
- if (CallOpWasAlreadyTransformed)
- getDerived().transformedLocalDecl(NewParamDeclArray[I],
- NewParamDeclArray[I]);
- // Add to Params array, so these parameters can be used to create
- // the newly transformed call operator.
- Params.push_back(NewParamDeclArray[I]);
- }
- }
-
- if (!NewCallOpTSI)
- return ExprError();
// Create the local class that will describe the lambda.
CXXRecordDecl *Class
@@ -8900,19 +9159,21 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewCallOpTSI,
/*KnownDependent=*/false,
E->getCaptureDefault());
-
getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
// Build the call operator.
- CXXMethodDecl *NewCallOperator
- = getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
- NewCallOpTSI,
- E->getCallOperator()->getLocEnd(),
- Params);
+ CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
+ Class, E->getIntroducerRange(), NewCallOpTSI,
+ E->getCallOperator()->getLocEnd(),
+ NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams());
LSI->CallOperator = NewCallOperator;
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
+ // TransformLambdaScope will manage the function scope, so we can disable the
+ // cleanup.
+ FuncScopeCleanup.disable();
+
return getDerived().TransformLambdaScope(E, NewCallOperator,
InitCaptureExprsAndTypes);
}
@@ -8954,6 +9215,10 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit());
continue;
}
+ // Captured expression will be recaptured during captured variables
+ // rebuilding.
+ if (C->capturesVLAType())
+ continue;
// Rebuild init-captures, including the implied field declaration.
if (C->isInitCapture()) {
@@ -9033,7 +9298,7 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
VarDecl *CapturedVar
= cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
C->getCapturedVar()));
- if (!CapturedVar) {
+ if (!CapturedVar || CapturedVar->isInvalidDecl()) {
Invalid = true;
continue;
}
@@ -9398,6 +9663,128 @@ TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
+ Expr *Pattern = E->getPattern();
+
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+ // Determine whether the set of unexpanded parameter packs can and should
+ // be expanded.
+ bool Expand = true;
+ bool RetainExpansion = false;
+ Optional<unsigned> NumExpansions;
+ if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(),
+ Pattern->getSourceRange(),
+ Unexpanded,
+ Expand, RetainExpansion,
+ NumExpansions))
+ return true;
+
+ if (!Expand) {
+ // Do not expand any packs here, just transform and rebuild a fold
+ // expression.
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+
+ ExprResult LHS =
+ E->getLHS() ? getDerived().TransformExpr(E->getLHS()) : ExprResult();
+ if (LHS.isInvalid())
+ return true;
+
+ ExprResult RHS =
+ E->getRHS() ? getDerived().TransformExpr(E->getRHS()) : ExprResult();
+ if (RHS.isInvalid())
+ return true;
+
+ if (!getDerived().AlwaysRebuild() &&
+ LHS.get() == E->getLHS() && RHS.get() == E->getRHS())
+ return E;
+
+ return getDerived().RebuildCXXFoldExpr(
+ E->getLocStart(), LHS.get(), E->getOperator(), E->getEllipsisLoc(),
+ RHS.get(), E->getLocEnd());
+ }
+
+ // The transform has determined that we should perform an elementwise
+ // expansion of the pattern. Do so.
+ ExprResult Result = getDerived().TransformExpr(E->getInit());
+ if (Result.isInvalid())
+ return true;
+ bool LeftFold = E->isLeftFold();
+
+ // If we're retaining an expansion for a right fold, it is the innermost
+ // component and takes the init (if any).
+ if (!LeftFold && RetainExpansion) {
+ ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+
+ ExprResult Out = getDerived().TransformExpr(Pattern);
+ if (Out.isInvalid())
+ return true;
+
+ Result = getDerived().RebuildCXXFoldExpr(
+ E->getLocStart(), Out.get(), E->getOperator(), E->getEllipsisLoc(),
+ Result.get(), E->getLocEnd());
+ if (Result.isInvalid())
+ return true;
+ }
+
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(
+ getSema(), LeftFold ? I : *NumExpansions - I - 1);
+ ExprResult Out = getDerived().TransformExpr(Pattern);
+ if (Out.isInvalid())
+ return true;
+
+ if (Out.get()->containsUnexpandedParameterPack()) {
+ // We still have a pack; retain a pack expansion for this slice.
+ Result = getDerived().RebuildCXXFoldExpr(
+ E->getLocStart(),
+ LeftFold ? Result.get() : Out.get(),
+ E->getOperator(), E->getEllipsisLoc(),
+ LeftFold ? Out.get() : Result.get(),
+ E->getLocEnd());
+ } else if (Result.isUsable()) {
+ // We've got down to a single element; build a binary operator.
+ Result = getDerived().RebuildBinaryOperator(
+ E->getEllipsisLoc(), E->getOperator(),
+ LeftFold ? Result.get() : Out.get(),
+ LeftFold ? Out.get() : Result.get());
+ } else
+ Result = Out;
+
+ if (Result.isInvalid())
+ return true;
+ }
+
+ // If we're retaining an expansion for a left fold, it is the outermost
+ // component and takes the complete expansion so far as its init (if any).
+ if (LeftFold && RetainExpansion) {
+ ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+
+ ExprResult Out = getDerived().TransformExpr(Pattern);
+ if (Out.isInvalid())
+ return true;
+
+ Result = getDerived().RebuildCXXFoldExpr(
+ E->getLocStart(), Result.get(),
+ E->getOperator(), E->getEllipsisLoc(),
+ Out.get(), E->getLocEnd());
+ if (Result.isInvalid())
+ return true;
+ }
+
+ // If we had no init and an empty pack, and we're not retaining an expansion,
+ // then produce a fallback value or error.
+ if (Result.isUnset())
+ return getDerived().RebuildEmptyCXXFoldExpr(E->getEllipsisLoc(),
+ E->getOperator());
+
+ return Result;
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformCXXStdInitializerListExpr(
CXXStdInitializerListExpr *E) {
return getDerived().TransformExpr(E->getSubExpr());
@@ -10292,7 +10679,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
SourceLocation RBrace;
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) {
- DeclarationNameLoc &NameLoc = DRE->getNameInfo().getInfo();
+ DeclarationNameLoc NameLoc = DRE->getNameInfo().getInfo();
LBrace = SourceLocation::getFromRawEncoding(
NameLoc.CXXOperatorName.BeginOpNameLoc);
RBrace = SourceLocation::getFromRawEncoding(
@@ -10348,9 +10735,16 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
// The scope type is now known to be a valid nested name specifier
// component. Tack it on to the end of the nested name specifier.
- if (ScopeType)
- SS.Extend(SemaRef.Context, SourceLocation(),
- ScopeType->getTypeLoc(), CCLoc);
+ if (ScopeType) {
+ if (!ScopeType->getType()->getAs<TagType>()) {
+ getSema().Diag(ScopeType->getTypeLoc().getBeginLoc(),
+ diag::err_expected_class_or_namespace)
+ << ScopeType->getType() << getSema().getLangOpts().CPlusPlus;
+ return ExprError();
+ }
+ SS.Extend(SemaRef.Context, SourceLocation(), ScopeType->getTypeLoc(),
+ CCLoc);
+ }
SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
return getSema().BuildMemberReferenceExpr(Base, BaseType,
@@ -10397,4 +10791,4 @@ TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) {
} // end namespace clang
-#endif // LLVM_CLANG_SEMA_TREETRANSFORM_H
+#endif
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index c3f874e1a854..82844b391467 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SEMA_TYPELOCBUILDER_H
-#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
+#ifndef LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H
+#define LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H
#include "clang/AST/ASTContext.h"
#include "clang/AST/TypeLoc.h"
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index ad046ffa277a..13393225b60e 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "ASTCommon.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Serialization/ASTDeserializationListener.h"
@@ -150,7 +151,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
switch (static_cast<Decl::Kind>(Kind)) {
case Decl::TranslationUnit: // Special case of a "merged" declaration.
case Decl::Namespace:
- case Decl::NamespaceAlias: // FIXME: Not yet redeclarable, but will be.
+ case Decl::NamespaceAlias:
case Decl::Typedef:
case Decl::TypeAlias:
case Decl::Enum:
@@ -188,8 +189,6 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::MSProperty:
case Decl::ObjCIvar:
case Decl::ObjCAtDefsField:
- case Decl::ImplicitParam:
- case Decl::ParmVar:
case Decl::NonTypeTemplateParm:
case Decl::TemplateTemplateParm:
case Decl::Using:
@@ -212,7 +211,20 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::Import:
case Decl::OMPThreadPrivate:
return false;
+
+ // These indirectly derive from Redeclarable<T> but are not actually
+ // redeclarable.
+ case Decl::ImplicitParam:
+ case Decl::ParmVar:
+ return false;
}
llvm_unreachable("Unhandled declaration kind");
}
+
+bool serialization::needsAnonymousDeclarationNumber(const NamedDecl *D) {
+ if (D->getDeclName() || !isa<CXXRecordDecl>(D->getLexicalDeclContext()))
+ return false;
+ return isa<TagDecl>(D) || isa<FieldDecl>(D);
+}
+
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index c7669749260b..38a0ff5fbd4e 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SERIALIZATION_LIB_AST_COMMON_H
-#define LLVM_CLANG_SERIALIZATION_LIB_AST_COMMON_H
+#ifndef LLVM_CLANG_LIB_SERIALIZATION_ASTCOMMON_H
+#define LLVM_CLANG_LIB_SERIALIZATION_ASTCOMMON_H
#include "clang/AST/ASTContext.h"
#include "clang/Serialization/ASTBitCodes.h"
@@ -25,14 +25,15 @@ enum DeclUpdateKind {
UPD_CXX_ADDED_IMPLICIT_MEMBER,
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
+ UPD_CXX_ADDED_FUNCTION_DEFINITION,
UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
- UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION,
UPD_CXX_INSTANTIATED_CLASS_DEFINITION,
UPD_CXX_RESOLVED_EXCEPTION_SPEC,
UPD_CXX_DEDUCED_RETURN_TYPE,
UPD_DECL_MARKED_USED,
UPD_MANGLING_NUMBER,
- UPD_STATIC_LOCAL_NUMBER
+ UPD_STATIC_LOCAL_NUMBER,
+ UPD_DECL_MARKED_OPENMP_THREADPRIVATE
};
TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);
@@ -80,6 +81,10 @@ const DeclContext *getDefinitiveDeclContext(const DeclContext *DC);
/// \brief Determine whether the given declaration kind is redeclarable.
bool isRedeclarableDeclKind(unsigned Kind);
+/// \brief Determine whether the given declaration needs an anonymous
+/// declaration number.
+bool needsAnonymousDeclarationNumber(const NamedDecl *D);
+
} // namespace serialization
} // namespace clang
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index ae41654904c6..416164ebb7d2 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -80,10 +80,14 @@ void ChainedASTReaderListener::ReadModuleMapFile(StringRef ModuleMapPath) {
First->ReadModuleMapFile(ModuleMapPath);
Second->ReadModuleMapFile(ModuleMapPath);
}
-bool ChainedASTReaderListener::ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) {
- return First->ReadLanguageOptions(LangOpts, Complain) ||
- Second->ReadLanguageOptions(LangOpts, Complain);
+bool
+ChainedASTReaderListener::ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain,
+ bool AllowCompatibleDifferences) {
+ return First->ReadLanguageOptions(LangOpts, Complain,
+ AllowCompatibleDifferences) ||
+ Second->ReadLanguageOptions(LangOpts, Complain,
+ AllowCompatibleDifferences);
}
bool
ChainedASTReaderListener::ReadTargetOptions(const TargetOptions &TargetOpts,
@@ -155,11 +159,14 @@ ASTReaderListener::~ASTReaderListener() {}
/// language options.
///
/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+/// \param AllowCompatibleDifferences If true, differences between compatible
+/// language options will be permitted.
///
/// \returns true if the languagae options mis-match, false otherwise.
static bool checkLanguageOptions(const LangOptions &LangOpts,
const LangOptions &ExistingLangOpts,
- DiagnosticsEngine *Diags) {
+ DiagnosticsEngine *Diags,
+ bool AllowCompatibleDifferences = true) {
#define LANGOPT(Name, Bits, Default, Description) \
if (ExistingLangOpts.Name != LangOpts.Name) { \
if (Diags) \
@@ -184,6 +191,14 @@ static bool checkLanguageOptions(const LangOptions &LangOpts,
return true; \
}
+#define COMPATIBLE_LANGOPT(Name, Bits, Default, Description) \
+ if (!AllowCompatibleDifferences) \
+ LANGOPT(Name, Bits, Default, Description)
+
+#define COMPATIBLE_ENUM_LANGOPT(Name, Bits, Default, Description) \
+ if (!AllowCompatibleDifferences) \
+ ENUM_LANGOPT(Name, Bits, Default, Description)
+
#define BENIGN_LANGOPT(Name, Bits, Default, Description)
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
@@ -278,10 +293,12 @@ static bool checkTargetOptions(const TargetOptions &TargetOpts,
bool
PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) {
+ bool Complain,
+ bool AllowCompatibleDifferences) {
const LangOptions &ExistingLangOpts = PP.getLangOpts();
return checkLanguageOptions(LangOpts, ExistingLangOpts,
- Complain? &Reader.Diags : nullptr);
+ Complain ? &Reader.Diags : nullptr,
+ AllowCompatibleDifferences);
}
bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
@@ -389,14 +406,14 @@ bool PCHValidator::ReadDiagnosticOptions(
// If the original import came from a file explicitly generated by the user,
// don't check the diagnostic mappings.
// FIXME: currently this is approximated by checking whether this is not a
- // module import.
+ // module import of an implicitly-loaded module file.
// Note: ModuleMgr.rbegin() may not be the current module, but it must be in
// the transitive closure of its imports, since unrelated modules cannot be
// imported until after this module finishes validation.
ModuleFile *TopImport = *ModuleMgr.rbegin();
while (!TopImport->ImportedBy.empty())
TopImport = TopImport->ImportedBy[0];
- if (TopImport->Kind != MK_Module)
+ if (TopImport->Kind != MK_ImplicitModule)
return false;
StringRef ModuleName = TopImport->ModuleName;
@@ -543,8 +560,7 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
continue;
SuggestedPredefines += "#include \"";
- SuggestedPredefines +=
- HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
+ SuggestedPredefines += File;
SuggestedPredefines += "\"\n";
}
@@ -556,8 +572,7 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
continue;
SuggestedPredefines += "#__include_macros \"";
- SuggestedPredefines +=
- HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
+ SuggestedPredefines += File;
SuggestedPredefines += "\"\n##\n";
}
@@ -635,14 +650,14 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
Result.ID = Reader.getGlobalSelectorID(
F, endian::readNext<uint32_t, little, unaligned>(d));
- unsigned NumInstanceMethodsAndBits =
- endian::readNext<uint16_t, little, unaligned>(d);
- unsigned NumFactoryMethodsAndBits =
- endian::readNext<uint16_t, little, unaligned>(d);
- Result.InstanceBits = NumInstanceMethodsAndBits & 0x3;
- Result.FactoryBits = NumFactoryMethodsAndBits & 0x3;
- unsigned NumInstanceMethods = NumInstanceMethodsAndBits >> 2;
- unsigned NumFactoryMethods = NumFactoryMethodsAndBits >> 2;
+ unsigned FullInstanceBits = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned FullFactoryBits = endian::readNext<uint16_t, little, unaligned>(d);
+ Result.InstanceBits = FullInstanceBits & 0x3;
+ Result.InstanceHasMoreThanOneDecl = (FullInstanceBits >> 2) & 0x1;
+ Result.FactoryBits = FullFactoryBits & 0x3;
+ Result.FactoryHasMoreThanOneDecl = (FullFactoryBits >> 2) & 0x1;
+ unsigned NumInstanceMethods = FullInstanceBits >> 3;
+ unsigned NumFactoryMethods = FullFactoryBits >> 3;
// Load instance methods
for (unsigned I = 0; I != NumInstanceMethods; ++I) {
@@ -774,15 +789,16 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
DataLen -= 4;
SmallVector<uint32_t, 8> LocalMacroIDs;
if (hasSubmoduleMacros) {
- while (uint32_t LocalMacroID =
- endian::readNext<uint32_t, little, unaligned>(d)) {
+ while (true) {
+ uint32_t LocalMacroID =
+ endian::readNext<uint32_t, little, unaligned>(d);
DataLen -= 4;
+ if (LocalMacroID == 0xdeadbeef) break;
LocalMacroIDs.push_back(LocalMacroID);
}
- DataLen -= 4;
}
- if (F.Kind == MK_Module) {
+ if (F.Kind == MK_ImplicitModule || F.Kind == MK_ExplicitModule) {
// Macro definitions are stored from newest to oldest, so reverse them
// before registering them.
llvm::SmallVector<unsigned, 8> MacroSizes;
@@ -1013,7 +1029,7 @@ void ASTReader::Error(unsigned DiagID,
/// \brief Read the line table in the source manager block.
/// \returns true if there was an error.
bool ASTReader::ParseLineTable(ModuleFile &F,
- SmallVectorImpl<uint64_t> &Record) {
+ const RecordData &Record) {
unsigned Idx = 0;
LineTableInfo &LineTable = SourceMgr.getLineTable();
@@ -1021,10 +1037,7 @@ bool ASTReader::ParseLineTable(ModuleFile &F,
std::map<int, int> FileIDs;
for (int I = 0, N = Record[Idx++]; I != N; ++I) {
// Extract the file name
- unsigned FilenameLen = Record[Idx++];
- std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
- Idx += FilenameLen;
- MaybeAddSystemRootToFilename(F, Filename);
+ auto Filename = ReadPath(F, Record, Idx);
FileIDs[I] = LineTable.getLineTableFilenameID(Filename);
}
@@ -1225,9 +1238,9 @@ bool ASTReader::ReadSLocEntry(int ID) {
return true;
}
- llvm::MemoryBuffer *Buffer
+ std::unique_ptr<llvm::MemoryBuffer> Buffer
= llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), File->getName());
- SourceMgr.overrideFileContents(File, Buffer);
+ SourceMgr.overrideFileContents(File, std::move(Buffer));
}
break;
@@ -1239,7 +1252,8 @@ bool ASTReader::ReadSLocEntry(int ID) {
SrcMgr::CharacteristicKind
FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
- if (IncludeLoc.isInvalid() && F->Kind == MK_Module) {
+ if (IncludeLoc.isInvalid() &&
+ (F->Kind == MK_ImplicitModule || F->Kind == MK_ExplicitModule)) {
IncludeLoc = getImportLocation(F);
}
unsigned Code = SLocEntryCursor.ReadCode();
@@ -1252,10 +1266,10 @@ bool ASTReader::ReadSLocEntry(int ID) {
return true;
}
- llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name);
- SourceMgr.createFileID(Buffer, FileCharacter, ID, BaseOffset + Offset,
- IncludeLoc);
+ std::unique_ptr<llvm::MemoryBuffer> Buffer =
+ llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name);
+ SourceMgr.createFileID(std::move(Buffer), FileCharacter, ID,
+ BaseOffset + Offset, IncludeLoc);
break;
}
@@ -1285,7 +1299,7 @@ std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) {
// Find which module file this entry lands in.
ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second;
- if (M->Kind != MK_Module)
+ if (M->Kind != MK_ImplicitModule && M->Kind != MK_ExplicitModule)
return std::make_pair(SourceLocation(), "");
// FIXME: Can we map this down to a particular submodule? That would be
@@ -1466,11 +1480,11 @@ ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const
unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
return llvm::hash_combine(ikey.Size, ikey.ModTime);
}
-
+
HeaderFileInfoTrait::internal_key_type
HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) {
internal_key_type ikey = { FE->getSize(), FE->getModificationTime(),
- FE->getName() };
+ FE->getName(), /*Imported*/false };
return ikey;
}
@@ -1478,14 +1492,24 @@ bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
if (a.Size != b.Size || a.ModTime != b.ModTime)
return false;
- if (strcmp(a.Filename, b.Filename) == 0)
+ if (llvm::sys::path::is_absolute(a.Filename) &&
+ strcmp(a.Filename, b.Filename) == 0)
return true;
// Determine whether the actual files are equivalent.
FileManager &FileMgr = Reader.getFileManager();
- const FileEntry *FEA = FileMgr.getFile(a.Filename);
- const FileEntry *FEB = FileMgr.getFile(b.Filename);
- return (FEA && FEA == FEB);
+ auto GetFile = [&](const internal_key_type &Key) -> const FileEntry* {
+ if (!Key.Imported)
+ return FileMgr.getFile(Key.Filename);
+
+ std::string Resolved = Key.Filename;
+ Reader.ResolveImportedPath(M, Resolved);
+ return FileMgr.getFile(Resolved);
+ };
+
+ const FileEntry *FEA = GetFile(a);
+ const FileEntry *FEB = GetFile(b);
+ return FEA && FEA == FEB;
}
std::pair<unsigned, unsigned>
@@ -1503,6 +1527,7 @@ HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
ikey.Size = off_t(endian::readNext<uint64_t, little, unaligned>(d));
ikey.ModTime = time_t(endian::readNext<uint64_t, little, unaligned>(d));
ikey.Filename = (const char *)d;
+ ikey.Imported = true;
return ikey;
}
@@ -1542,7 +1567,14 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
FileManager &FileMgr = Reader.getFileManager();
ModuleMap &ModMap =
Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();
- ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), HFI.getHeaderRole());
+ // FIXME: This information should be propagated through the
+ // SUBMODULE_HEADER etc records rather than from here.
+ // FIXME: We don't ever mark excluded headers.
+ std::string Filename = key.Filename;
+ if (key.Imported)
+ Reader.ResolveImportedPath(M, Filename);
+ Module::Header H = { key.Filename, FileMgr.getFile(Filename) };
+ ModMap.addHeader(Mod, H, HFI.getHeaderRole());
}
}
@@ -1732,10 +1764,12 @@ struct ASTReader::ModuleMacroInfo {
return llvm::makeArrayRef(Overrides + 1, *Overrides);
}
- DefMacroDirective *import(Preprocessor &PP, SourceLocation ImportLoc) const {
+ MacroDirective *import(Preprocessor &PP, SourceLocation ImportLoc) const {
if (!MI)
- return nullptr;
- return PP.AllocateDefMacroDirective(MI, ImportLoc, /*isImported=*/true);
+ return PP.AllocateUndefMacroDirective(ImportLoc, SubModID,
+ getOverriddenSubmodules());
+ return PP.AllocateDefMacroDirective(MI, ImportLoc, SubModID,
+ getOverriddenSubmodules());
}
};
@@ -1772,7 +1806,8 @@ void ASTReader::resolvePendingMacro(IdentifierInfo *II,
const PendingMacroInfo &PMInfo) {
assert(II);
- if (PMInfo.M->Kind != MK_Module) {
+ if (PMInfo.M->Kind != MK_ImplicitModule &&
+ PMInfo.M->Kind != MK_ExplicitModule) {
installPCHMacroDirectives(II, *PMInfo.M,
PMInfo.PCHMacroData.MacroDirectivesOffset);
return;
@@ -1790,13 +1825,13 @@ void ASTReader::resolvePendingMacro(IdentifierInfo *II,
// install if we make this module visible.
HiddenNamesMap[Owner].HiddenMacros.insert(std::make_pair(II, MMI));
} else {
- installImportedMacro(II, MMI, Owner, /*FromFinalization*/false);
+ installImportedMacro(II, MMI, Owner);
}
}
void ASTReader::installPCHMacroDirectives(IdentifierInfo *II,
ModuleFile &M, uint64_t Offset) {
- assert(M.Kind != MK_Module);
+ assert(M.Kind != MK_ImplicitModule && M.Kind != MK_ExplicitModule);
BitstreamCursor &Cursor = M.MacroCursor;
SavedStreamPosition SavedPosition(Cursor);
@@ -1828,23 +1863,36 @@ void ASTReader::installPCHMacroDirectives(IdentifierInfo *II,
case MacroDirective::MD_Define: {
GlobalMacroID GMacID = getGlobalMacroID(M, Record[Idx++]);
MacroInfo *MI = getMacro(GMacID);
- bool isImported = Record[Idx++];
- bool isAmbiguous = Record[Idx++];
+ SubmoduleID ImportedFrom = Record[Idx++];
+ bool IsAmbiguous = Record[Idx++];
+ llvm::SmallVector<unsigned, 4> Overrides;
+ if (ImportedFrom) {
+ Overrides.insert(Overrides.end(),
+ &Record[Idx] + 1, &Record[Idx] + 1 + Record[Idx]);
+ Idx += Overrides.size() + 1;
+ }
DefMacroDirective *DefMD =
- PP.AllocateDefMacroDirective(MI, Loc, isImported);
- DefMD->setAmbiguous(isAmbiguous);
+ PP.AllocateDefMacroDirective(MI, Loc, ImportedFrom, Overrides);
+ DefMD->setAmbiguous(IsAmbiguous);
MD = DefMD;
break;
}
- case MacroDirective::MD_Undefine:
- MD = PP.AllocateUndefMacroDirective(Loc);
+ case MacroDirective::MD_Undefine: {
+ SubmoduleID ImportedFrom = Record[Idx++];
+ llvm::SmallVector<unsigned, 4> Overrides;
+ if (ImportedFrom) {
+ Overrides.insert(Overrides.end(),
+ &Record[Idx] + 1, &Record[Idx] + 1 + Record[Idx]);
+ Idx += Overrides.size() + 1;
+ }
+ MD = PP.AllocateUndefMacroDirective(Loc, ImportedFrom, Overrides);
break;
- case MacroDirective::MD_Visibility: {
+ }
+ case MacroDirective::MD_Visibility:
bool isPublic = Record[Idx++];
MD = PP.AllocateVisibilityMacroDirective(Loc, isPublic);
break;
}
- }
if (!Latest)
Latest = MD;
@@ -1877,19 +1925,27 @@ static bool areDefinedInSystemModules(MacroInfo *PrevMI, MacroInfo *NewMI,
}
void ASTReader::removeOverriddenMacros(IdentifierInfo *II,
+ SourceLocation ImportLoc,
AmbiguousMacros &Ambig,
ArrayRef<SubmoduleID> Overrides) {
for (unsigned OI = 0, ON = Overrides.size(); OI != ON; ++OI) {
SubmoduleID OwnerID = Overrides[OI];
// If this macro is not yet visible, remove it from the hidden names list.
+ // It won't be there if we're in the middle of making the owner visible.
Module *Owner = getSubmodule(OwnerID);
- HiddenNames &Hidden = HiddenNamesMap[Owner];
- HiddenMacrosMap::iterator HI = Hidden.HiddenMacros.find(II);
- if (HI != Hidden.HiddenMacros.end()) {
- auto SubOverrides = HI->second->getOverriddenSubmodules();
- Hidden.HiddenMacros.erase(HI);
- removeOverriddenMacros(II, Ambig, SubOverrides);
+ auto HiddenIt = HiddenNamesMap.find(Owner);
+ if (HiddenIt != HiddenNamesMap.end()) {
+ HiddenNames &Hidden = HiddenIt->second;
+ HiddenMacrosMap::iterator HI = Hidden.HiddenMacros.find(II);
+ if (HI != Hidden.HiddenMacros.end()) {
+ // Register the macro now so we don't lose it when we re-export.
+ PP.appendMacroDirective(II, HI->second->import(PP, ImportLoc));
+
+ auto SubOverrides = HI->second->getOverriddenSubmodules();
+ Hidden.HiddenMacros.erase(HI);
+ removeOverriddenMacros(II, ImportLoc, Ambig, SubOverrides);
+ }
}
// If this macro is already in our list of conflicts, remove it from there.
@@ -1903,6 +1959,7 @@ void ASTReader::removeOverriddenMacros(IdentifierInfo *II,
ASTReader::AmbiguousMacros *
ASTReader::removeOverriddenMacros(IdentifierInfo *II,
+ SourceLocation ImportLoc,
ArrayRef<SubmoduleID> Overrides) {
MacroDirective *Prev = PP.getMacroDirective(II);
if (!Prev && Overrides.empty())
@@ -1915,7 +1972,7 @@ ASTReader::removeOverriddenMacros(IdentifierInfo *II,
AmbiguousMacros &Ambig = AmbiguousMacroDefs[II];
Ambig.push_back(PrevDef);
- removeOverriddenMacros(II, Ambig, Overrides);
+ removeOverriddenMacros(II, ImportLoc, Ambig, Overrides);
if (!Ambig.empty())
return &Ambig;
@@ -1927,7 +1984,7 @@ ASTReader::removeOverriddenMacros(IdentifierInfo *II,
if (PrevDef)
Ambig.push_back(PrevDef);
- removeOverriddenMacros(II, Ambig, Overrides);
+ removeOverriddenMacros(II, ImportLoc, Ambig, Overrides);
if (!Ambig.empty()) {
AmbiguousMacros &Result = AmbiguousMacroDefs[II];
@@ -1941,11 +1998,11 @@ ASTReader::removeOverriddenMacros(IdentifierInfo *II,
}
void ASTReader::installImportedMacro(IdentifierInfo *II, ModuleMacroInfo *MMI,
- Module *Owner, bool FromFinalization) {
+ Module *Owner) {
assert(II && Owner);
SourceLocation ImportLoc = Owner->MacroVisibilityLoc;
- if (ImportLoc.isInvalid() && !FromFinalization) {
+ if (ImportLoc.isInvalid()) {
// FIXME: If we made macros from this module visible but didn't provide a
// source location for the import, we don't have a location for the macro.
// Use the location at which the containing module file was first imported
@@ -1955,18 +2012,16 @@ void ASTReader::installImportedMacro(IdentifierInfo *II, ModuleMacroInfo *MMI,
}
AmbiguousMacros *Prev =
- removeOverriddenMacros(II, MMI->getOverriddenSubmodules());
+ removeOverriddenMacros(II, ImportLoc, MMI->getOverriddenSubmodules());
// Create a synthetic macro definition corresponding to the import (or null
// if this was an undefinition of the macro).
- DefMacroDirective *MD = MMI->import(PP, ImportLoc);
+ MacroDirective *Imported = MMI->import(PP, ImportLoc);
+ DefMacroDirective *MD = dyn_cast<DefMacroDirective>(Imported);
// If there's no ambiguity, just install the macro.
if (!Prev) {
- if (MD)
- PP.appendMacroDirective(II, MD);
- else
- PP.appendMacroDirective(II, PP.AllocateUndefMacroDirective(ImportLoc));
+ PP.appendMacroDirective(II, Imported);
return;
}
assert(!Prev->empty());
@@ -1974,10 +2029,14 @@ void ASTReader::installImportedMacro(IdentifierInfo *II, ModuleMacroInfo *MMI,
if (!MD) {
// We imported a #undef that didn't remove all prior definitions. The most
// recent prior definition remains, and we install it in the place of the
- // imported directive.
+ // imported directive, as if by a local #pragma pop_macro.
MacroInfo *NewMI = Prev->back()->getInfo();
Prev->pop_back();
- MD = PP.AllocateDefMacroDirective(NewMI, ImportLoc, /*Imported*/true);
+ MD = PP.AllocateDefMacroDirective(NewMI, ImportLoc);
+
+ // Install our #undef first so that we don't lose track of it. We'll replace
+ // this with whichever macro definition ends up winning.
+ PP.appendMacroDirective(II, Imported);
}
// We're introducing a macro definition that creates or adds to an ambiguity.
@@ -2035,14 +2094,14 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
off_t StoredSize;
time_t StoredTime;
bool Overridden;
-
+
assert(Record[0] == ID && "Bogus stored ID or offset");
StoredSize = static_cast<off_t>(Record[1]);
StoredTime = static_cast<time_t>(Record[2]);
Overridden = static_cast<bool>(Record[3]);
Filename = Blob;
- MaybeAddSystemRootToFilename(F, Filename);
-
+ ResolveImportedPath(F, Filename);
+
InputFileInfo R = { std::move(Filename), StoredSize, StoredTime, Overridden };
return R;
}
@@ -2128,12 +2187,23 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
bool IsOutOfDate = false;
// For an overridden file, there is nothing to validate.
- if (!Overridden && (StoredSize != File->getSize()
-#if !defined(LLVM_ON_WIN32)
+ if (!Overridden && //
+ (StoredSize != File->getSize() ||
+#if defined(LLVM_ON_WIN32)
+ false
+#else
// In our regression testing, the Windows file system seems to
// have inconsistent modification times that sometimes
// erroneously trigger this error-handling path.
- || StoredTime != File->getModificationTime()
+ //
+ // This also happens in networked file systems, so disable this
+ // check if validation is disabled or if we have an explicitly
+ // built PCM file.
+ //
+ // FIXME: Should we also do this for PCH files? They could also
+ // reasonably get shared across a network during a distributed build.
+ (StoredTime != File->getModificationTime() && !DisableValidation &&
+ F.Kind != MK_ExplicitModule)
#endif
)) {
if (Complain) {
@@ -2169,46 +2239,22 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
return IF;
}
-const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
- ModuleFile &M = ModuleMgr.getPrimaryModule();
- std::string Filename = filenameStrRef;
- MaybeAddSystemRootToFilename(M, Filename);
- const FileEntry *File = FileMgr.getFile(Filename);
- if (File == nullptr && !M.OriginalDir.empty() && !CurrentDir.empty() &&
- M.OriginalDir != CurrentDir) {
- std::string resolved = resolveFileRelativeToOriginalDir(Filename,
- M.OriginalDir,
- CurrentDir);
- if (!resolved.empty())
- File = FileMgr.getFile(resolved);
- }
-
- return File;
+/// \brief If we are loading a relocatable PCH or module file, and the filename
+/// is not an absolute path, add the system or module root to the beginning of
+/// the file name.
+void ASTReader::ResolveImportedPath(ModuleFile &M, std::string &Filename) {
+ // Resolve relative to the base directory, if we have one.
+ if (!M.BaseDirectory.empty())
+ return ResolveImportedPath(Filename, M.BaseDirectory);
}
-/// \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.
-void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
- std::string &Filename) {
- // If this is not a relocatable PCH file, there's nothing to do.
- if (!M.RelocatablePCH)
- return;
-
+void ASTReader::ResolveImportedPath(std::string &Filename, StringRef Prefix) {
if (Filename.empty() || llvm::sys::path::is_absolute(Filename))
return;
- if (isysroot.empty()) {
- // If no system root was given, default to '/'
- Filename.insert(Filename.begin(), '/');
- return;
- }
-
- unsigned Length = isysroot.size();
- if (isysroot[Length - 1] != '/')
- Filename.insert(Filename.begin(), '/');
-
- Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end());
+ SmallString<128> Buffer;
+ llvm::sys::path::append(Buffer, Prefix, Filename);
+ Filename.assign(Buffer.begin(), Buffer.end());
}
ASTReader::ASTReadResult
@@ -2223,8 +2269,16 @@ ASTReader::ReadControlBlock(ModuleFile &F,
return Failure;
}
+ // Should we allow the configuration of the module file to differ from the
+ // configuration of the current translation unit in a compatible way?
+ //
+ // FIXME: Allow this for files explicitly specified with -include-pch too.
+ bool AllowCompatibleConfigurationMismatch = F.Kind == MK_ExplicitModule;
+
// Read all of the records and blocks in the control block.
RecordData Record;
+ unsigned NumInputs = 0;
+ unsigned NumUserInputs = 0;
while (1) {
llvm::BitstreamEntry Entry = Stream.advance();
@@ -2237,15 +2291,9 @@ ASTReader::ReadControlBlock(ModuleFile &F,
const HeaderSearchOptions &HSOpts =
PP.getHeaderSearchInfo().getHeaderSearchOpts();
- // All user input files reside at the index range [0, Record[1]), and
- // system input files reside at [Record[1], Record[0]).
- // Record is the one from INPUT_FILE_OFFSETS.
- unsigned NumInputs = Record[0];
- unsigned NumUserInputs = Record[1];
-
- if (!DisableValidation &&
- (ValidateSystemInputs || !HSOpts.ModulesValidateOncePerBuildSession ||
- F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp)) {
+ // All user input files reside at the index range [0, NumUserInputs), and
+ // system input files reside at [NumUserInputs, NumInputs).
+ if (!DisableValidation) {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
// If we are reading a module, we will create a verification timestamp,
@@ -2254,7 +2302,9 @@ ASTReader::ReadControlBlock(ModuleFile &F,
unsigned N = NumUserInputs;
if (ValidateSystemInputs ||
- (HSOpts.ModulesValidateOncePerBuildSession && F.Kind == MK_Module))
+ (HSOpts.ModulesValidateOncePerBuildSession &&
+ F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp &&
+ F.Kind == MK_ImplicitModule))
N = NumInputs;
for (unsigned I = 0; I < N; ++I) {
@@ -2324,6 +2374,9 @@ ASTReader::ReadControlBlock(ModuleFile &F,
}
F.RelocatablePCH = Record[4];
+ // Relative paths in a relocatable PCH are relative to our sysroot.
+ if (F.RelocatablePCH)
+ F.BaseDirectory = isysroot.empty() ? "/" : isysroot;
const std::string &CurBranch = getClangFullRepositoryVersion();
StringRef ASTBranch = Blob;
@@ -2335,6 +2388,11 @@ ASTReader::ReadControlBlock(ModuleFile &F,
break;
}
+ case SIGNATURE:
+ assert((!F.Signature || F.Signature == Record[0]) && "signature changed");
+ F.Signature = Record[0];
+ break;
+
case IMPORTS: {
// Load each of the imported PCH files.
unsigned Idx = 0, N = Record.size();
@@ -2348,14 +2406,12 @@ ASTReader::ReadControlBlock(ModuleFile &F,
SourceLocation::getFromRawEncoding(Record[Idx++]);
off_t StoredSize = (off_t)Record[Idx++];
time_t StoredModTime = (time_t)Record[Idx++];
- unsigned Length = Record[Idx++];
- SmallString<128> ImportedFile(Record.begin() + Idx,
- Record.begin() + Idx + Length);
- Idx += Length;
+ ASTFileSignature StoredSignature = Record[Idx++];
+ auto ImportedFile = ReadPath(F, Record, Idx);
// Load the AST file.
switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
- StoredSize, StoredModTime,
+ StoredSize, StoredModTime, StoredSignature,
ClientLoadCapabilities)) {
case Failure: return Failure;
// If we have to ignore the dependency, we'll have to ignore this too.
@@ -2372,8 +2428,10 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case LANGUAGE_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ // FIXME: The &F == *ModuleMgr.begin() check is wrong for modules.
if (Listener && &F == *ModuleMgr.begin() &&
- ParseLanguageOptions(Record, Complain, *Listener) &&
+ ParseLanguageOptions(Record, Complain, *Listener,
+ AllowCompatibleConfigurationMismatch) &&
!DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
@@ -2391,6 +2449,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case DIAGNOSTIC_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate)==0;
if (Listener && &F == *ModuleMgr.begin() &&
+ !AllowCompatibleConfigurationMismatch &&
ParseDiagnosticOptions(Record, Complain, *Listener) &&
!DisableValidation)
return OutOfDate;
@@ -2400,6 +2459,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case FILE_SYSTEM_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
+ !AllowCompatibleConfigurationMismatch &&
ParseFileSystemOptions(Record, Complain, *Listener) &&
!DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
@@ -2409,6 +2469,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case HEADER_SEARCH_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
+ !AllowCompatibleConfigurationMismatch &&
ParseHeaderSearchOptions(Record, Complain, *Listener) &&
!DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
@@ -2418,6 +2479,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case PREPROCESSOR_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
+ !AllowCompatibleConfigurationMismatch &&
ParsePreprocessorOptions(Record, Complain, *Listener,
SuggestedPredefines) &&
!DisableValidation && !AllowConfigurationMismatch)
@@ -2429,7 +2491,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.OriginalSourceFileID = FileID::get(Record[0]);
F.ActualOriginalSourceFileName = Blob;
F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
- MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName);
+ ResolveImportedPath(F, F.OriginalSourceFileName);
break;
case ORIGINAL_FILE_ID:
@@ -2446,46 +2508,43 @@ ASTReader::ReadControlBlock(ModuleFile &F,
Listener->ReadModuleName(F.ModuleName);
break;
- case MODULE_MAP_FILE:
- F.ModuleMapPath = Blob;
-
- // Try to resolve ModuleName in the current header search context and
- // verify that it is found in the same module map file as we saved. If the
- // top-level AST file is a main file, skip this check because there is no
- // usable header search context.
+ case MODULE_DIRECTORY: {
assert(!F.ModuleName.empty() &&
- "MODULE_NAME should come before MOUDLE_MAP_FILE");
- if (F.Kind == MK_Module &&
- (*ModuleMgr.begin())->Kind != MK_MainFile) {
- Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName);
- if (!M) {
- assert(ImportedBy && "top-level import should be verified");
- if ((ClientLoadCapabilities & ARR_Missing) == 0)
- Diag(diag::err_imported_module_not_found)
- << F.ModuleName << ImportedBy->FileName;
- return Missing;
- }
-
- const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath);
- if (StoredModMap == nullptr || StoredModMap != M->ModuleMap) {
- assert(M->ModuleMap && "found module is missing module map file");
- assert(M->Name == F.ModuleName && "found module with different name");
- assert(ImportedBy && "top-level import should be verified");
- if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
- Diag(diag::err_imported_module_modmap_changed)
- << F.ModuleName << ImportedBy->FileName
- << M->ModuleMap->getName() << F.ModuleMapPath;
- return OutOfDate;
+ "MODULE_DIRECTORY found before MODULE_NAME");
+ // If we've already loaded a module map file covering this module, we may
+ // have a better path for it (relative to the current build).
+ Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName);
+ if (M && M->Directory) {
+ // If we're implicitly loading a module, the base directory can't
+ // change between the build and use.
+ if (F.Kind != MK_ExplicitModule) {
+ const DirectoryEntry *BuildDir =
+ PP.getFileManager().getDirectory(Blob);
+ if (!BuildDir || BuildDir != M->Directory) {
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_imported_module_relocated)
+ << F.ModuleName << Blob << M->Directory->getName();
+ return OutOfDate;
+ }
}
+ F.BaseDirectory = M->Directory->getName();
+ } else {
+ F.BaseDirectory = Blob;
}
+ break;
+ }
- if (Listener)
- Listener->ReadModuleMapFile(F.ModuleMapPath);
+ case MODULE_MAP_FILE:
+ if (ASTReadResult Result =
+ ReadModuleMapFileBlock(Record, F, ImportedBy, ClientLoadCapabilities))
+ return Result;
break;
case INPUT_FILE_OFFSETS:
+ NumInputs = Record[0];
+ NumUserInputs = Record[1];
F.InputFileOffsets = (const uint32_t *)Blob.data();
- F.InputFilesLoaded.resize(Record[0]);
+ F.InputFilesLoaded.resize(NumInputs);
break;
}
}
@@ -2628,7 +2687,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
F.TypeRemap.insertOrReplace(
std::make_pair(LocalBaseTypeIndex,
F.BaseTypeIndex - LocalBaseTypeIndex));
-
+
TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes);
}
break;
@@ -2658,7 +2717,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// Introduce the global -> local mapping for declarations within this
// module.
F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID;
-
+
DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls);
}
break;
@@ -2687,7 +2746,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
auto *DC = cast<DeclContext>(D);
DC->getPrimaryContext()->setHasExternalVisibleStorage(true);
auto *&LookupTable = F.DeclContextInfos[DC].NameLookupTableData;
- // FIXME: There should never be an existing lookup table.
delete LookupTable;
LookupTable = Table;
} else
@@ -2729,8 +2787,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
F.IdentifierRemap.insertOrReplace(
std::make_pair(LocalBaseIdentifierID,
F.BaseIdentifierID - LocalBaseIdentifierID));
-
- IdentifiersLoaded.resize(IdentifiersLoaded.size()
+
+ IdentifiersLoaded.resize(IdentifiersLoaded.size()
+ F.LocalNumIdentifiers);
}
break;
@@ -2823,7 +2881,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
std::make_pair(LocalBaseSelectorID,
F.BaseSelectorID - LocalBaseSelectorID));
- SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors);
+ SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors);
}
break;
}
@@ -2904,19 +2962,16 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
// Continuous range maps we may be updating in our module.
- ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
- IdentifierRemap(F.IdentifierRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
- MacroRemap(F.MacroRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
- PreprocessedEntityRemap(F.PreprocessedEntityRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
- SubmoduleRemap(F.SubmoduleRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
- SelectorRemap(F.SelectorRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder DeclRemap(F.DeclRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap);
+ typedef ContinuousRangeMap<uint32_t, int, 2>::Builder
+ RemapBuilder;
+ RemapBuilder SLocRemap(F.SLocRemap);
+ RemapBuilder IdentifierRemap(F.IdentifierRemap);
+ RemapBuilder MacroRemap(F.MacroRemap);
+ RemapBuilder PreprocessedEntityRemap(F.PreprocessedEntityRemap);
+ RemapBuilder SubmoduleRemap(F.SubmoduleRemap);
+ RemapBuilder SelectorRemap(F.SelectorRemap);
+ RemapBuilder DeclRemap(F.DeclRemap);
+ RemapBuilder TypeRemap(F.TypeRemap);
while(Data < DataEnd) {
using namespace llvm::support;
@@ -2946,26 +3001,23 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
uint32_t TypeIndexOffset =
endian::readNext<uint32_t, little, unaligned>(Data);
- // Source location offset is mapped to OM->SLocEntryBaseOffset.
- SLocRemap.insert(std::make_pair(SLocOffset,
- static_cast<int>(OM->SLocEntryBaseOffset - SLocOffset)));
- IdentifierRemap.insert(
- std::make_pair(IdentifierIDOffset,
- OM->BaseIdentifierID - IdentifierIDOffset));
- MacroRemap.insert(std::make_pair(MacroIDOffset,
- OM->BaseMacroID - MacroIDOffset));
- PreprocessedEntityRemap.insert(
- std::make_pair(PreprocessedEntityIDOffset,
- OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset));
- SubmoduleRemap.insert(std::make_pair(SubmoduleIDOffset,
- OM->BaseSubmoduleID - SubmoduleIDOffset));
- SelectorRemap.insert(std::make_pair(SelectorIDOffset,
- OM->BaseSelectorID - SelectorIDOffset));
- DeclRemap.insert(std::make_pair(DeclIDOffset,
- OM->BaseDeclID - DeclIDOffset));
-
- TypeRemap.insert(std::make_pair(TypeIndexOffset,
- OM->BaseTypeIndex - TypeIndexOffset));
+ uint32_t None = std::numeric_limits<uint32_t>::max();
+
+ auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset,
+ RemapBuilder &Remap) {
+ if (Offset != None)
+ Remap.insert(std::make_pair(Offset,
+ static_cast<int>(BaseOffset - Offset)));
+ };
+ mapOffset(SLocOffset, OM->SLocEntryBaseOffset, SLocRemap);
+ mapOffset(IdentifierIDOffset, OM->BaseIdentifierID, IdentifierRemap);
+ mapOffset(MacroIDOffset, OM->BaseMacroID, MacroRemap);
+ mapOffset(PreprocessedEntityIDOffset, OM->BasePreprocessedEntityID,
+ PreprocessedEntityRemap);
+ mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap);
+ mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap);
+ mapOffset(DeclIDOffset, OM->BaseDeclID, DeclRemap);
+ mapOffset(TypeIndexOffset, OM->BaseTypeIndex, TypeRemap);
// Global -> local mappings.
F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
@@ -3206,7 +3258,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
case IMPORTED_MODULES: {
- if (F.Kind != MK_Module) {
+ if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule) {
// If we aren't loading a module (which has its own exports), make
// all of the imported modules visible.
// FIXME: Deal with macros-only imports.
@@ -3287,10 +3339,110 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
OptimizeOffPragmaLocation = ReadSourceLocation(F, Record[0]);
break;
+
+ case UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ UnusedLocalTypedefNameCandidates.push_back(
+ getGlobalDeclID(F, Record[I]));
+ break;
}
}
}
+ASTReader::ASTReadResult
+ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
+ const ModuleFile *ImportedBy,
+ unsigned ClientLoadCapabilities) {
+ unsigned Idx = 0;
+ F.ModuleMapPath = ReadPath(F, Record, Idx);
+
+ if (F.Kind == MK_ExplicitModule) {
+ // For an explicitly-loaded module, we don't care whether the original
+ // module map file exists or matches.
+ return Success;
+ }
+
+ // Try to resolve ModuleName in the current header search context and
+ // verify that it is found in the same module map file as we saved. If the
+ // top-level AST file is a main file, skip this check because there is no
+ // usable header search context.
+ assert(!F.ModuleName.empty() &&
+ "MODULE_NAME should come before MODULE_MAP_FILE");
+ if (F.Kind == MK_ImplicitModule &&
+ (*ModuleMgr.begin())->Kind != MK_MainFile) {
+ // An implicitly-loaded module file should have its module listed in some
+ // module map file that we've already loaded.
+ Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName);
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr;
+ if (!ModMap) {
+ assert(ImportedBy && "top-level import should be verified");
+ if ((ClientLoadCapabilities & ARR_Missing) == 0)
+ Diag(diag::err_imported_module_not_found) << F.ModuleName << F.FileName
+ << ImportedBy->FileName
+ << F.ModuleMapPath;
+ return Missing;
+ }
+
+ assert(M->Name == F.ModuleName && "found module with different name");
+
+ // Check the primary module map file.
+ const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath);
+ if (StoredModMap == nullptr || StoredModMap != ModMap) {
+ assert(ModMap && "found module is missing module map file");
+ assert(ImportedBy && "top-level import should be verified");
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_imported_module_modmap_changed)
+ << F.ModuleName << ImportedBy->FileName
+ << ModMap->getName() << F.ModuleMapPath;
+ return OutOfDate;
+ }
+
+ llvm::SmallPtrSet<const FileEntry *, 1> AdditionalStoredMaps;
+ for (unsigned I = 0, N = Record[Idx++]; I < N; ++I) {
+ // FIXME: we should use input files rather than storing names.
+ std::string Filename = ReadPath(F, Record, Idx);
+ const FileEntry *F =
+ FileMgr.getFile(Filename, false, false);
+ if (F == nullptr) {
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Error("could not find file '" + Filename +"' referenced by AST file");
+ return OutOfDate;
+ }
+ AdditionalStoredMaps.insert(F);
+ }
+
+ // Check any additional module map files (e.g. module.private.modulemap)
+ // that are not in the pcm.
+ if (auto *AdditionalModuleMaps = Map.getAdditionalModuleMapFiles(M)) {
+ for (const FileEntry *ModMap : *AdditionalModuleMaps) {
+ // Remove files that match
+ // Note: SmallPtrSet::erase is really remove
+ if (!AdditionalStoredMaps.erase(ModMap)) {
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_module_different_modmap)
+ << F.ModuleName << /*new*/0 << ModMap->getName();
+ return OutOfDate;
+ }
+ }
+ }
+
+ // Check any additional module map files that are in the pcm, but not
+ // found in header search. Cases that match are already removed.
+ for (const FileEntry *ModMap : AdditionalStoredMaps) {
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_module_different_modmap)
+ << F.ModuleName << /*not new*/1 << ModMap->getName();
+ return OutOfDate;
+ }
+ }
+
+ if (Listener)
+ Listener->ReadModuleMapFile(F.ModuleMapPath);
+ return Success;
+}
+
+
/// \brief Move the given method to the back of the global list of methods.
static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
// Find the entry for this selector in the method pool.
@@ -3305,7 +3457,7 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
bool Found = false;
for (ObjCMethodList *List = &Start; List; List = List->getNext()) {
if (!Found) {
- if (List->Method == Method) {
+ if (List->getMethod() == Method) {
Found = true;
} else {
// Keep searching.
@@ -3314,9 +3466,9 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
}
if (List->getNext())
- List->Method = List->getNext()->Method;
+ List->setMethod(List->getNext()->getMethod());
else
- List->Method = Method;
+ List->setMethod(Method);
}
}
@@ -3336,8 +3488,13 @@ void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner,
assert((FromFinalization || Owner->NameVisibility >= Module::MacrosVisible) &&
"nothing to make visible?");
- for (const auto &Macro : Names.HiddenMacros)
- installImportedMacro(Macro.first, Macro.second, Owner, FromFinalization);
+ for (const auto &Macro : Names.HiddenMacros) {
+ if (FromFinalization)
+ PP.appendMacroDirective(Macro.first,
+ Macro.second->import(PP, SourceLocation()));
+ else
+ installImportedMacro(Macro.first, Macro.second, Owner);
+ }
}
void ASTReader::makeModuleVisible(Module *Mod,
@@ -3385,7 +3542,7 @@ void ASTReader::makeModuleVisible(Module *Mod,
for (SmallVectorImpl<Module *>::iterator
I = Exports.begin(), E = Exports.end(); I != E; ++I) {
Module *Exported = *I;
- if (Visited.insert(Exported))
+ if (Visited.insert(Exported).second)
Stack.push_back(Exported);
}
@@ -3435,10 +3592,9 @@ bool ASTReader::isGlobalIndexUnavailable() const {
static void updateModuleTimestamp(ModuleFile &MF) {
// Overwrite the timestamp file contents so that file's mtime changes.
std::string TimestampFilename = MF.getTimestampFilename();
- std::string ErrorInfo;
- llvm::raw_fd_ostream OS(TimestampFilename.c_str(), ErrorInfo,
- llvm::sys::fs::F_Text);
- if (!ErrorInfo.empty())
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(TimestampFilename, EC, llvm::sys::fs::F_Text);
+ if (EC)
return;
OS << "Timestamp file\n";
}
@@ -3460,7 +3616,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
SmallVector<ImportedModule, 4> Loaded;
switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
/*ImportedBy=*/nullptr, Loaded,
- 0, 0,
+ 0, 0, 0,
ClientLoadCapabilities)) {
case Failure:
case Missing:
@@ -3618,7 +3774,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
// in the filesystem).
for (unsigned I = 0, N = Loaded.size(); I != N; ++I) {
ImportedModule &M = Loaded[I];
- if (M.Mod->Kind == MK_Module) {
+ if (M.Mod->Kind == MK_ImplicitModule) {
updateModuleTimestamp(*M.Mod);
}
}
@@ -3627,6 +3783,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
return Success;
}
+static ASTFileSignature readASTFileSignature(llvm::BitstreamReader &StreamFile);
+
ASTReader::ASTReadResult
ASTReader::ReadASTCore(StringRef FileName,
ModuleKind Type,
@@ -3634,12 +3792,14 @@ ASTReader::ReadASTCore(StringRef FileName,
ModuleFile *ImportedBy,
SmallVectorImpl<ImportedModule> &Loaded,
off_t ExpectedSize, time_t ExpectedModTime,
+ ASTFileSignature ExpectedSignature,
unsigned ClientLoadCapabilities) {
ModuleFile *M;
std::string ErrorStr;
ModuleManager::AddModuleResult AddResult
= ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy,
getGeneration(), ExpectedSize, ExpectedModTime,
+ ExpectedSignature, readASTFileSignature,
M, ErrorStr);
switch (AddResult) {
@@ -3651,7 +3811,7 @@ ASTReader::ReadASTCore(StringRef FileName,
break;
case ModuleManager::Missing:
- // The module file was missing; if the client handle handle, that, return
+ // The module file was missing; if the client can handle that, return
// it.
if (ClientLoadCapabilities & ARR_Missing)
return Missing;
@@ -3690,7 +3850,7 @@ ASTReader::ReadASTCore(StringRef FileName,
ModuleFile &F = *M;
BitstreamCursor &Stream = F.Stream;
- Stream.init(F.StreamFile);
+ Stream.init(&F.StreamFile);
F.SizeInBits = F.Buffer->getBufferSize() * 8;
// Sniff for the signature.
@@ -3937,6 +4097,34 @@ static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) {
}
}
+static ASTFileSignature readASTFileSignature(llvm::BitstreamReader &StreamFile){
+ BitstreamCursor Stream(StreamFile);
+ if (Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'P' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'H') {
+ return 0;
+ }
+
+ // Scan for the CONTROL_BLOCK_ID block.
+ if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID))
+ return 0;
+
+ // Scan for SIGNATURE inside the control block.
+ ASTReader::RecordData Record;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+ if (Entry.Kind == llvm::BitstreamEntry::EndBlock ||
+ Entry.Kind != llvm::BitstreamEntry::Record)
+ return 0;
+
+ Record.clear();
+ StringRef Blob;
+ if (SIGNATURE == Stream.readRecord(Entry.ID, Record, &Blob))
+ return Record[0];
+ }
+}
+
/// \brief Retrieve the name of the original source file name
/// directly from the AST file, without actually loading the AST
/// file.
@@ -3944,20 +4132,18 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
FileManager &FileMgr,
DiagnosticsEngine &Diags) {
// Open the AST file.
- std::string ErrStr;
- std::unique_ptr<llvm::MemoryBuffer> Buffer;
- Buffer.reset(FileMgr.getBufferForFile(ASTFileName, &ErrStr));
+ auto Buffer = FileMgr.getBufferForFile(ASTFileName);
if (!Buffer) {
- Diags.Report(diag::err_fe_unable_to_read_pch_file) << ASTFileName << ErrStr;
+ Diags.Report(diag::err_fe_unable_to_read_pch_file)
+ << ASTFileName << Buffer.getError().message();
return std::string();
}
// Initialize the stream
llvm::BitstreamReader StreamFile;
- BitstreamCursor Stream;
- StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
- (const unsigned char *)Buffer->getBufferEnd());
- Stream.init(StreamFile);
+ StreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(),
+ (const unsigned char *)(*Buffer)->getBufferEnd());
+ BitstreamCursor Stream(StreamFile);
// Sniff for the signature.
if (Stream.Read(8) != 'C' ||
@@ -4012,9 +4198,10 @@ namespace {
{
}
- bool ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) override {
- return checkLanguageOptions(ExistingLangOpts, LangOpts, nullptr);
+ bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
+ bool AllowCompatibleDifferences) override {
+ return checkLanguageOptions(ExistingLangOpts, LangOpts, nullptr,
+ AllowCompatibleDifferences);
}
bool ReadTargetOptions(const TargetOptions &TargetOpts,
bool Complain) override {
@@ -4033,19 +4220,16 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
FileManager &FileMgr,
ASTReaderListener &Listener) {
// Open the AST file.
- std::string ErrStr;
- std::unique_ptr<llvm::MemoryBuffer> Buffer;
- Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr));
+ auto Buffer = FileMgr.getBufferForFile(Filename);
if (!Buffer) {
return true;
}
// Initialize the stream
llvm::BitstreamReader StreamFile;
- BitstreamCursor Stream;
- StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
- (const unsigned char *)Buffer->getBufferEnd());
- Stream.init(StreamFile);
+ StreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(),
+ (const unsigned char *)(*Buffer)->getBufferEnd());
+ BitstreamCursor Stream(StreamFile);
// Sniff for the signature.
if (Stream.Read(8) != 'C' ||
@@ -4061,6 +4245,7 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
bool NeedsInputFiles = Listener.needsInputFileVisitation();
bool NeedsSystemInputFiles = Listener.needsSystemInputFileVisitation();
+ bool NeedsImports = Listener.needsImportVisitation();
BitstreamCursor InputFilesCursor;
if (NeedsInputFiles) {
InputFilesCursor = Stream;
@@ -4083,6 +4268,7 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
// Scan for ORIGINAL_FILE inside the control block.
RecordData Record;
+ std::string ModuleDir;
while (1) {
llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
@@ -4107,11 +4293,19 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
case MODULE_NAME:
Listener.ReadModuleName(Blob);
break;
- case MODULE_MAP_FILE:
- Listener.ReadModuleMapFile(Blob);
+ case MODULE_DIRECTORY:
+ ModuleDir = Blob;
break;
+ case MODULE_MAP_FILE: {
+ unsigned Idx = 0;
+ auto Path = ReadString(Record, Idx);
+ ResolveImportedPath(Path, ModuleDir);
+ Listener.ReadModuleMapFile(Path);
+ break;
+ }
case LANGUAGE_OPTIONS:
- if (ParseLanguageOptions(Record, false, Listener))
+ if (ParseLanguageOptions(Record, false, Listener,
+ /*AllowCompatibleConfigurationMismatch*/false))
return true;
break;
@@ -4168,7 +4362,10 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) {
case INPUT_FILE:
bool Overridden = static_cast<bool>(Record[3]);
- shouldContinue = Listener.visitInputFile(Blob, isSystemFile, Overridden);
+ std::string Filename = Blob;
+ ResolveImportedPath(Filename, ModuleDir);
+ shouldContinue =
+ Listener.visitInputFile(Filename, isSystemFile, Overridden);
break;
}
if (!shouldContinue)
@@ -4177,6 +4374,21 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
break;
}
+ case IMPORTS: {
+ if (!NeedsImports)
+ break;
+
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ // Read information about the AST file.
+ Idx += 5; // ImportLoc, Size, ModTime, Signature
+ std::string Filename = ReadString(Record, Idx);
+ ResolveImportedPath(Filename, ModuleDir);
+ Listener.visitImport(Filename);
+ }
+ break;
+ }
+
default:
// No other validation to perform.
break;
@@ -4224,21 +4436,30 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// Read a record.
StringRef Blob;
Record.clear();
- switch (F.Stream.readRecord(Entry.ID, Record, &Blob)) {
+ auto Kind = F.Stream.readRecord(Entry.ID, Record, &Blob);
+
+ if ((Kind == SUBMODULE_METADATA) != First) {
+ Error("submodule metadata record should be at beginning of block");
+ return Failure;
+ }
+ First = false;
+
+ // Submodule information is only valid if we have a current module.
+ // FIXME: Should we error on these cases?
+ if (!CurrentModule && Kind != SUBMODULE_METADATA &&
+ Kind != SUBMODULE_DEFINITION)
+ continue;
+
+ switch (Kind) {
default: // Default behavior: ignore.
break;
-
- case SUBMODULE_DEFINITION: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
+ case SUBMODULE_DEFINITION: {
if (Record.size() < 8) {
Error("malformed module definition");
return Failure;
}
-
+
StringRef Name = Blob;
unsigned Idx = 0;
SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[Idx++]);
@@ -4253,20 +4474,17 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
bool ConfigMacrosExhaustive = Record[Idx++];
Module *ParentModule = nullptr;
- const FileEntry *ModuleMap = nullptr;
- if (Parent) {
+ if (Parent)
ParentModule = getSubmodule(Parent);
- ModuleMap = ParentModule->ModuleMap;
- }
-
- if (!F.ModuleMapPath.empty())
- ModuleMap = FileMgr.getFile(F.ModuleMapPath);
// Retrieve this (sub)module from the module map, creating it if
// necessary.
- CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, ModuleMap,
- IsFramework,
+ CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, IsFramework,
IsExplicit).first;
+
+ // FIXME: set the definition loc for CurrentModule, or call
+ // ModMap.setInferredModuleAllowedBy()
+
SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
if (GlobalIndex >= SubmodulesLoaded.size() ||
SubmodulesLoaded[GlobalIndex]) {
@@ -4311,14 +4529,6 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
case SUBMODULE_UMBRELLA_HEADER: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
if (const FileEntry *Umbrella = PP.getFileManager().getFile(Blob)) {
if (!CurrentModule->getUmbrellaHeader())
ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
@@ -4331,73 +4541,26 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
}
- case SUBMODULE_HEADER: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
- // We lazily associate headers with their modules via the HeaderInfoTable.
- // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
- // of complete filenames or remove it entirely.
- break;
- }
-
- case SUBMODULE_EXCLUDED_HEADER: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
- // We lazily associate headers with their modules via the HeaderInfoTable.
+ case SUBMODULE_HEADER:
+ case SUBMODULE_EXCLUDED_HEADER:
+ case SUBMODULE_PRIVATE_HEADER:
+ // We lazily associate headers with their modules via the HeaderInfo table.
// FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
// of complete filenames or remove it entirely.
- break;
- }
-
- case SUBMODULE_PRIVATE_HEADER: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
+ break;
- if (!CurrentModule)
- break;
-
- // We lazily associate headers with their modules via the HeaderInfoTable.
- // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
- // of complete filenames or remove it entirely.
- break;
- }
+ case SUBMODULE_TEXTUAL_HEADER:
+ case SUBMODULE_PRIVATE_TEXTUAL_HEADER:
+ // FIXME: Textual headers are not marked in the HeaderInfo table. Load
+ // them here.
+ break;
case SUBMODULE_TOPHEADER: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
CurrentModule->addTopHeaderFilename(Blob);
break;
}
case SUBMODULE_UMBRELLA_DIR: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
if (const DirectoryEntry *Umbrella
= PP.getFileManager().getDirectory(Blob)) {
if (!CurrentModule->getUmbrellaDir())
@@ -4412,12 +4575,6 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
case SUBMODULE_METADATA: {
- if (!First) {
- Error("submodule metadata record not at beginning of block");
- return Failure;
- }
- First = false;
-
F.BaseSubmoduleID = getTotalNumSubmodules();
F.LocalNumSubmodules = Record[0];
unsigned LocalBaseSubmoduleID = Record[1];
@@ -4431,21 +4588,13 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
F.SubmoduleRemap.insertOrReplace(
std::make_pair(LocalBaseSubmoduleID,
F.BaseSubmoduleID - LocalBaseSubmoduleID));
-
+
SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules);
- }
+ }
break;
}
case SUBMODULE_IMPORTS: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
UnresolvedModuleRef Unresolved;
Unresolved.File = &F;
@@ -4459,14 +4608,6 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
case SUBMODULE_EXPORTS: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
UnresolvedModuleRef Unresolved;
Unresolved.File = &F;
@@ -4483,53 +4624,21 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
}
case SUBMODULE_REQUIRES: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
CurrentModule->addRequirement(Blob, Record[0], Context.getLangOpts(),
Context.getTargetInfo());
break;
}
case SUBMODULE_LINK_LIBRARY:
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
CurrentModule->LinkLibraries.push_back(
Module::LinkLibrary(Blob, Record[0]));
break;
case SUBMODULE_CONFIG_MACRO:
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
CurrentModule->ConfigMacros.push_back(Blob.str());
break;
case SUBMODULE_CONFLICT: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return Failure;
- }
-
- if (!CurrentModule)
- break;
-
UnresolvedModuleRef Unresolved;
Unresolved.File = &F;
Unresolved.Mod = CurrentModule;
@@ -4553,7 +4662,8 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
/// \returns true if the listener deems the file unacceptable, false otherwise.
bool ASTReader::ParseLanguageOptions(const RecordData &Record,
bool Complain,
- ASTReaderListener &Listener) {
+ ASTReaderListener &Listener,
+ bool AllowCompatibleDifferences) {
LangOptions LangOpts;
unsigned Idx = 0;
#define LANGOPT(Name, Bits, Default, Description) \
@@ -4561,7 +4671,8 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record,
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
#include "clang/Basic/LangOptions.def"
-#define SANITIZER(NAME, ID) LangOpts.Sanitize.ID = Record[Idx++];
+#define SANITIZER(NAME, ID) \
+ LangOpts.Sanitize.set(SanitizerKind::ID, Record[Idx++]);
#include "clang/Basic/Sanitizers.def"
ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
@@ -4581,7 +4692,8 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record,
}
LangOpts.CommentOpts.ParseAllComments = Record[Idx++];
- return Listener.ReadLanguageOptions(LangOpts, Complain);
+ return Listener.ReadLanguageOptions(LangOpts, Complain,
+ AllowCompatibleDifferences);
}
bool ASTReader::ParseTargetOptions(const RecordData &Record,
@@ -5235,17 +5347,19 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
/*produces*/ Record[5]);
unsigned Idx = 6;
- unsigned NumParams = Record[Idx++];
- SmallVector<QualType, 16> ParamTypes;
- for (unsigned I = 0; I != NumParams; ++I)
- ParamTypes.push_back(readType(*Loc.F, Record, Idx));
EPI.Variadic = Record[Idx++];
EPI.HasTrailingReturn = Record[Idx++];
EPI.TypeQuals = Record[Idx++];
EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
SmallVector<QualType, 8> ExceptionStorage;
- readExceptionSpec(*Loc.F, ExceptionStorage, EPI, Record, Idx);
+ readExceptionSpec(*Loc.F, ExceptionStorage, EPI.ExceptionSpec, Record, Idx);
+
+ unsigned NumParams = Record[Idx++];
+ SmallVector<QualType, 16> ParamTypes;
+ for (unsigned I = 0; I != NumParams; ++I)
+ ParamTypes.push_back(readType(*Loc.F, Record, Idx));
+
return Context.getFunctionType(ResultType, ParamTypes, EPI);
}
@@ -5414,13 +5528,18 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
QualType TST = readType(*Loc.F, Record, Idx); // probably derivable
// FIXME: ASTContext::getInjectedClassNameType is not currently suitable
// for AST reading, too much interdependencies.
- const Type *T;
- if (const Type *Existing = D->getTypeForDecl())
- T = Existing;
- else if (auto *Prev = D->getPreviousDecl())
- T = Prev->getTypeForDecl();
- else
+ const Type *T = nullptr;
+ for (auto *DI = D; DI; DI = DI->getPreviousDecl()) {
+ if (const Type *Existing = DI->getTypeForDecl()) {
+ T = Existing;
+ break;
+ }
+ }
+ if (!T) {
T = new (Context, TypeAlignment) InjectedClassNameType(D, TST);
+ for (auto *DI = D; DI; DI = DI->getPreviousDecl())
+ DI->setTypeForDecl(T);
+ }
return QualType(T, 0);
}
@@ -5508,24 +5627,22 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
void ASTReader::readExceptionSpec(ModuleFile &ModuleFile,
SmallVectorImpl<QualType> &Exceptions,
- FunctionProtoType::ExtProtoInfo &EPI,
+ FunctionProtoType::ExceptionSpecInfo &ESI,
const RecordData &Record, unsigned &Idx) {
ExceptionSpecificationType EST =
static_cast<ExceptionSpecificationType>(Record[Idx++]);
- EPI.ExceptionSpecType = EST;
+ ESI.Type = EST;
if (EST == EST_Dynamic) {
- EPI.NumExceptions = Record[Idx++];
- for (unsigned I = 0; I != EPI.NumExceptions; ++I)
+ for (unsigned I = 0, N = Record[Idx++]; I != N; ++I)
Exceptions.push_back(readType(ModuleFile, Record, Idx));
- EPI.Exceptions = Exceptions.data();
+ ESI.Exceptions = Exceptions;
} else if (EST == EST_ComputedNoexcept) {
- EPI.NoexceptExpr = ReadExpr(ModuleFile);
+ ESI.NoexceptExpr = ReadExpr(ModuleFile);
} else if (EST == EST_Uninstantiated) {
- EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
- EPI.ExceptionSpecTemplate =
- ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ ESI.SourceDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ ESI.SourceTemplate = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
} else if (EST == EST_Unevaluated) {
- EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ ESI.SourceDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
}
}
@@ -5976,18 +6093,10 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
const DeclContext *DC = D->getDeclContext()->getRedeclContext();
- // Recursively ensure that the decl context itself is complete
- // (in particular, this matters if the decl context is a namespace).
- //
- // FIXME: This should be performed by lookup instead of here.
- cast<Decl>(DC)->getMostRecentDecl();
-
// If this is a named declaration, complete it by looking it up
// within its context.
//
- // FIXME: We don't currently handle the cases where we can't do this;
- // merging a class definition that contains unnamed entities should merge
- // those entities. Likewise, merging a function definition should merge
+ // FIXME: Merging a function definition should merge
// all mergeable entities within it.
if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC) ||
isa<CXXRecordDecl>(DC) || isa<EnumDecl>(DC)) {
@@ -6000,6 +6109,9 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
updateOutOfDateIdentifier(*II);
} else
DC->lookup(Name);
+ } else if (needsAnonymousDeclarationNumber(cast<NamedDecl>(D))) {
+ // FIXME: It'd be nice to do something a bit more targeted here.
+ D->getDeclContext()->decls_begin();
}
}
}
@@ -6345,13 +6457,13 @@ namespace {
/// declaration context.
class DeclContextNameLookupVisitor {
ASTReader &Reader;
- SmallVectorImpl<const DeclContext *> &Contexts;
+ ArrayRef<const DeclContext *> Contexts;
DeclarationName Name;
SmallVectorImpl<NamedDecl *> &Decls;
public:
- DeclContextNameLookupVisitor(ASTReader &Reader,
- SmallVectorImpl<const DeclContext *> &Contexts,
+ DeclContextNameLookupVisitor(ASTReader &Reader,
+ ArrayRef<const DeclContext *> Contexts,
DeclarationName Name,
SmallVectorImpl<NamedDecl *> &Decls)
: Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { }
@@ -6364,9 +6476,9 @@ namespace {
// this context in this module.
ModuleFile::DeclContextInfosMap::iterator Info;
bool FoundInfo = false;
- for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
- Info = M.DeclContextInfos.find(This->Contexts[I]);
- if (Info != M.DeclContextInfos.end() &&
+ for (auto *DC : This->Contexts) {
+ Info = M.DeclContextInfos.find(DC);
+ if (Info != M.DeclContextInfos.end() &&
Info->second.NameLookupTableData) {
FoundInfo = true;
break;
@@ -6375,7 +6487,7 @@ namespace {
if (!FoundInfo)
return false;
-
+
// Look for this name within this module.
ASTDeclContextNameLookupTable *LookupTable =
Info->second.NameLookupTableData;
@@ -6396,9 +6508,11 @@ namespace {
// currently read before reading its name. The lookup is triggered by
// building that decl (likely indirectly), and so it is later in the
// sense of "already existing" and can be ignored here.
+ // FIXME: This should not happen; deserializing declarations should
+ // not perform lookups since that can lead to deserialization cycles.
continue;
}
-
+
// Record this declaration.
FoundAnything = true;
This->Decls.push_back(ND);
@@ -6438,15 +6552,17 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
if (!Name)
return false;
+ Deserializing LookupResults(this);
+
SmallVector<NamedDecl *, 64> Decls;
-
+
// Compute the declaration contexts we need to look into. Multiple such
// declaration contexts occur when two declaration contexts from disjoint
// modules get merged, e.g., when two namespaces with the same name are
// independently defined in separate modules.
SmallVector<const DeclContext *, 2> Contexts;
Contexts.push_back(DC);
-
+
if (DC->isNamespace()) {
auto Merged = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
if (Merged != MergedDecls.end()) {
@@ -6454,24 +6570,45 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
}
}
- if (isa<CXXRecordDecl>(DC)) {
- auto Merged = MergedLookups.find(DC);
- if (Merged != MergedLookups.end())
- Contexts.insert(Contexts.end(), Merged->second.begin(),
- Merged->second.end());
- }
- DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
+ auto LookUpInContexts = [&](ArrayRef<const DeclContext*> Contexts) {
+ DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
- // If we can definitively determine which module file to look into,
- // only look there. Otherwise, look in all module files.
- ModuleFile *Definitive;
- if (Contexts.size() == 1 &&
- (Definitive = getDefinitiveModuleFileFor(DC, *this))) {
- DeclContextNameLookupVisitor::visit(*Definitive, &Visitor);
- } else {
- ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
+ // If we can definitively determine which module file to look into,
+ // only look there. Otherwise, look in all module files.
+ ModuleFile *Definitive;
+ if (Contexts.size() == 1 &&
+ (Definitive = getDefinitiveModuleFileFor(Contexts[0], *this))) {
+ DeclContextNameLookupVisitor::visit(*Definitive, &Visitor);
+ } else {
+ ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
+ }
+ };
+
+ LookUpInContexts(Contexts);
+
+ // If this might be an implicit special member function, then also search
+ // all merged definitions of the surrounding class. We need to search them
+ // individually, because finding an entity in one of them doesn't imply that
+ // we can't find a different entity in another one.
+ if (isa<CXXRecordDecl>(DC)) {
+ auto Kind = Name.getNameKind();
+ if (Kind == DeclarationName::CXXConstructorName ||
+ Kind == DeclarationName::CXXDestructorName ||
+ (Kind == DeclarationName::CXXOperatorName &&
+ Name.getCXXOverloadedOperator() == OO_Equal)) {
+ auto Merged = MergedLookups.find(DC);
+ if (Merged != MergedLookups.end()) {
+ for (unsigned I = 0; I != Merged->second.size(); ++I) {
+ LookUpInContexts(Merged->second[I]);
+ // We might have just added some more merged lookups. If so, our
+ // iterator is now invalid, so grab a fresh one before continuing.
+ Merged = MergedLookups.find(DC);
+ }
+ }
+ }
}
+
++NumVisibleDeclContextsRead;
SetExternalVisibleDeclsForName(DC, Name, Decls);
return !Decls.empty();
@@ -6786,11 +6923,11 @@ void ASTReader::InitializeSema(Sema &S) {
// Makes sure any declarations that were deserialized "too early"
// still get added to the identifier's declaration chains.
- for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
- pushExternalDeclIntoScope(PreloadedDecls[I],
- PreloadedDecls[I]->getDeclName());
+ for (uint64_t ID : PreloadedDeclIDs) {
+ NamedDecl *D = cast<NamedDecl>(GetDecl(ID));
+ pushExternalDeclIntoScope(D, D->getDeclName());
}
- PreloadedDecls.clear();
+ PreloadedDeclIDs.clear();
// FIXME: What happens if these are changed by a module import?
if (!FPPragmaOptions.empty()) {
@@ -6924,15 +7061,18 @@ namespace clang { namespace serialization {
unsigned PriorGeneration;
unsigned InstanceBits;
unsigned FactoryBits;
+ bool InstanceHasMoreThanOneDecl;
+ bool FactoryHasMoreThanOneDecl;
SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
public:
- ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel,
+ ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel,
unsigned PriorGeneration)
- : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration),
- InstanceBits(0), FactoryBits(0) { }
-
+ : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration),
+ InstanceBits(0), FactoryBits(0), InstanceHasMoreThanOneDecl(false),
+ FactoryHasMoreThanOneDecl(false) {}
+
static bool visit(ModuleFile &M, void *UserData) {
ReadMethodPoolVisitor *This
= static_cast<ReadMethodPoolVisitor *>(UserData);
@@ -6966,6 +7106,8 @@ namespace clang { namespace serialization {
This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end());
This->InstanceBits = Data.InstanceBits;
This->FactoryBits = Data.FactoryBits;
+ This->InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl;
+ This->FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl;
return true;
}
@@ -6981,6 +7123,10 @@ namespace clang { namespace serialization {
unsigned getInstanceBits() const { return InstanceBits; }
unsigned getFactoryBits() const { return FactoryBits; }
+ bool instanceHasMoreThanOneDecl() const {
+ return InstanceHasMoreThanOneDecl;
+ }
+ bool factoryHasMoreThanOneDecl() const { return FactoryHasMoreThanOneDecl; }
};
} } // end namespace clang::serialization
@@ -7015,11 +7161,17 @@ void ASTReader::ReadMethodPool(Selector Sel) {
Sema &S = *getSema();
Sema::GlobalMethodPool::iterator Pos
= S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first;
-
- addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first);
- addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second);
+
Pos->second.first.setBits(Visitor.getInstanceBits());
+ Pos->second.first.setHasMoreThanOneDecl(Visitor.instanceHasMoreThanOneDecl());
Pos->second.second.setBits(Visitor.getFactoryBits());
+ Pos->second.second.setHasMoreThanOneDecl(Visitor.factoryHasMoreThanOneDecl());
+
+ // Add methods to the global pool *after* setting hasMoreThanOneDecl, since
+ // when building a module we keep every method individually and may need to
+ // update hasMoreThanOneDecl as we add the methods.
+ addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first);
+ addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second);
}
void ASTReader::ReadKnownNamespaces(
@@ -7095,6 +7247,18 @@ void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {
DynamicClasses.clear();
}
+void ASTReader::ReadUnusedLocalTypedefNameCandidates(
+ llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {
+ for (unsigned I = 0, N = UnusedLocalTypedefNameCandidates.size(); I != N;
+ ++I) {
+ TypedefNameDecl *D = dyn_cast_or_null<TypedefNameDecl>(
+ GetDecl(UnusedLocalTypedefNameCandidates[I]));
+ if (D)
+ Decls.insert(D);
+ }
+ UnusedLocalTypedefNameCandidates.clear();
+}
+
void
ASTReader::ReadLocallyScopedExternCDecls(SmallVectorImpl<NamedDecl *> &Decls) {
for (unsigned I = 0, N = LocallyScopedExternCDecls.size(); I != N; ++I) {
@@ -7230,24 +7394,26 @@ ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
}
for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
- NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
- if (SemaObj) {
- // If we're simply supposed to record the declarations, do so now.
- if (Decls) {
- Decls->push_back(D);
- continue;
- }
-
- // Introduce this declaration into the translation-unit scope
- // and add it to the declaration chain for this identifier, so
- // that (unqualified) name lookup will find it.
- pushExternalDeclIntoScope(D, II);
- } else {
+ if (!SemaObj) {
// Queue this declaration so that it will be added to the
// translation unit scope and identifier's declaration chain
// once a Sema object is known.
- PreloadedDecls.push_back(D);
+ PreloadedDeclIDs.push_back(DeclIDs[I]);
+ continue;
}
+
+ NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
+
+ // If we're simply supposed to record the declarations, do so now.
+ if (Decls) {
+ Decls->push_back(D);
+ continue;
+ }
+
+ // Introduce this declaration into the translation-unit scope
+ // and add it to the declaration chain for this identifier, so
+ // that (unqualified) name lookup will find it.
+ pushExternalDeclIntoScope(D, II);
}
}
@@ -7584,8 +7750,7 @@ ASTReader::ReadTemplateArgument(ModuleFile &F,
return TemplateArgument(readType(F, Record, Idx));
case TemplateArgument::Declaration: {
ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx);
- bool ForReferenceParam = Record[Idx++];
- return TemplateArgument(D, ForReferenceParam);
+ return TemplateArgument(D, readType(F, Record, Idx));
}
case TemplateArgument::NullPtr:
return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true);
@@ -7806,6 +7971,12 @@ ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
// No associated value, and there can't be a prefix.
break;
}
+
+ case NestedNameSpecifier::Super: {
+ CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx);
+ NNS = NestedNameSpecifier::SuperSpecifier(Context, RD);
+ break;
+ }
}
Prev = NNS;
}
@@ -7862,9 +8033,16 @@ ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record,
Builder.MakeGlobal(Context, ColonColonLoc);
break;
}
+
+ case NestedNameSpecifier::Super: {
+ CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ Builder.MakeSuper(Context, RD, Range.getBegin(), Range.getEnd());
+ break;
+ }
}
}
-
+
return Builder.getWithLocInContext(Context);
}
@@ -7906,6 +8084,13 @@ std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) {
return Result;
}
+std::string ASTReader::ReadPath(ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ std::string Filename = ReadString(Record, Idx);
+ ResolveImportedPath(F, Filename);
+ return Filename;
+}
+
VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
unsigned &Idx) {
unsigned Major = Record[Idx++];
@@ -8008,6 +8193,14 @@ void ASTReader::ReadComments() {
}
}
+void ASTReader::getInputFiles(ModuleFile &F,
+ SmallVectorImpl<serialization::InputFile> &Files) {
+ for (unsigned I = 0, E = F.InputFilesLoaded.size(); I != E; ++I) {
+ unsigned ID = I+1;
+ Files.push_back(getInputFile(F, ID));
+ }
+}
+
std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
// If we know the owning module, use it.
if (Module *M = D->getOwningModule())
@@ -8025,7 +8218,7 @@ void ASTReader::finishPendingActions() {
while (!PendingIdentifierInfos.empty() ||
!PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() ||
!PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
- !PendingUpdateRecords.empty() || !PendingOdrMergeChecks.empty()) {
+ !PendingUpdateRecords.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
typedef llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> >
@@ -8073,14 +8266,16 @@ void ASTReader::finishPendingActions() {
for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
++IDIdx) {
const PendingMacroInfo &Info = GlobalIDs[IDIdx];
- if (Info.M->Kind != MK_Module)
+ if (Info.M->Kind != MK_ImplicitModule &&
+ Info.M->Kind != MK_ExplicitModule)
resolvePendingMacro(II, Info);
}
// Handle module imports.
for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
++IDIdx) {
const PendingMacroInfo &Info = GlobalIDs[IDIdx];
- if (Info.M->Kind == MK_Module)
+ if (Info.M->Kind == MK_ImplicitModule ||
+ Info.M->Kind == MK_ExplicitModule)
resolvePendingMacro(II, Info);
}
}
@@ -8097,110 +8292,36 @@ void ASTReader::finishPendingActions() {
}
// Perform any pending declaration updates.
- //
- // Don't do this if we have known-incomplete redecl chains: it relies on
- // being able to walk redeclaration chains.
- while (PendingDeclChains.empty() && !PendingUpdateRecords.empty()) {
+ while (!PendingUpdateRecords.empty()) {
auto Update = PendingUpdateRecords.pop_back_val();
ReadingKindTracker ReadingKind(Read_Decl, *this);
loadDeclUpdateRecords(Update.first, Update.second);
}
-
- // Trigger the import of the full definition of each class that had any
- // odr-merging problems, so we can produce better diagnostics for them.
- for (auto &Merge : PendingOdrMergeFailures) {
- Merge.first->buildLookup();
- Merge.first->decls_begin();
- Merge.first->bases_begin();
- Merge.first->vbases_begin();
- for (auto *RD : Merge.second) {
- RD->decls_begin();
- RD->bases_begin();
- RD->vbases_begin();
- }
- }
-
- // For each declaration from a merged context, check that the canonical
- // definition of that context also contains a declaration of the same
- // entity.
- while (!PendingOdrMergeChecks.empty()) {
- NamedDecl *D = PendingOdrMergeChecks.pop_back_val();
-
- // FIXME: Skip over implicit declarations for now. This matters for things
- // like implicitly-declared special member functions. This isn't entirely
- // correct; we can end up with multiple unmerged declarations of the same
- // implicit entity.
- if (D->isImplicit())
- continue;
-
- DeclContext *CanonDef = D->getDeclContext();
- DeclContext::lookup_result R = CanonDef->lookup(D->getDeclName());
-
- bool Found = false;
- const Decl *DCanon = D->getCanonicalDecl();
-
- llvm::SmallVector<const NamedDecl*, 4> Candidates;
- for (DeclContext::lookup_iterator I = R.begin(), E = R.end();
- !Found && I != E; ++I) {
- for (auto RI : (*I)->redecls()) {
- if (RI->getLexicalDeclContext() == CanonDef) {
- // This declaration is present in the canonical definition. If it's
- // in the same redecl chain, it's the one we're looking for.
- if (RI->getCanonicalDecl() == DCanon)
- Found = true;
- else
- Candidates.push_back(cast<NamedDecl>(RI));
- break;
- }
- }
- }
-
- if (!Found) {
- D->setInvalidDecl();
-
- std::string CanonDefModule =
- getOwningModuleNameForDiagnostic(cast<Decl>(CanonDef));
- Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl)
- << D << getOwningModuleNameForDiagnostic(D)
- << CanonDef << CanonDefModule.empty() << CanonDefModule;
-
- if (Candidates.empty())
- Diag(cast<Decl>(CanonDef)->getLocation(),
- diag::note_module_odr_violation_no_possible_decls) << D;
- else {
- for (unsigned I = 0, N = Candidates.size(); I != N; ++I)
- Diag(Candidates[I]->getLocation(),
- diag::note_module_odr_violation_possible_decl)
- << Candidates[I];
- }
-
- DiagnosedOdrMergeFailures.insert(CanonDef);
- }
- }
}
// If we deserialized any C++ or Objective-C class definitions, any
// Objective-C protocol definitions, or any redeclarable templates, make sure
// that all redeclarations point to the definitions. Note that this can only
// happen now, after the redeclaration chains have been fully wired.
- for (llvm::SmallPtrSet<Decl *, 4>::iterator D = PendingDefinitions.begin(),
- DEnd = PendingDefinitions.end();
- D != DEnd; ++D) {
- if (TagDecl *TD = dyn_cast<TagDecl>(*D)) {
+ for (Decl *D : PendingDefinitions) {
+ if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
if (const TagType *TagT = dyn_cast<TagType>(TD->getTypeForDecl())) {
// Make sure that the TagType points at the definition.
const_cast<TagType*>(TagT)->decl = TD;
}
- if (auto RD = dyn_cast<CXXRecordDecl>(*D)) {
- for (auto R : RD->redecls())
+ if (auto RD = dyn_cast<CXXRecordDecl>(D)) {
+ for (auto R : RD->redecls()) {
+ assert((R == D) == R->isThisDeclarationADefinition() &&
+ "declaration thinks it's the definition but it isn't");
cast<CXXRecordDecl>(R)->DefinitionData = RD->DefinitionData;
+ }
}
continue;
}
- if (auto ID = dyn_cast<ObjCInterfaceDecl>(*D)) {
+ if (auto ID = dyn_cast<ObjCInterfaceDecl>(D)) {
// Make sure that the ObjCInterfaceType points at the definition.
const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl))
->Decl = ID;
@@ -8211,14 +8332,14 @@ void ASTReader::finishPendingActions() {
continue;
}
- if (auto PD = dyn_cast<ObjCProtocolDecl>(*D)) {
+ if (auto PD = dyn_cast<ObjCProtocolDecl>(D)) {
for (auto R : PD->redecls())
R->Data = PD->Data;
continue;
}
- auto RTD = cast<RedeclarableTemplateDecl>(*D)->getCanonicalDecl();
+ auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
for (auto R : RTD->redecls())
R->Common = RTD->Common;
}
@@ -8243,10 +8364,108 @@ void ASTReader::finishPendingActions() {
MD->setLazyBody(PB->second);
}
PendingBodies.clear();
+}
+
+void ASTReader::diagnoseOdrViolations() {
+ if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty())
+ return;
+
+ // Trigger the import of the full definition of each class that had any
+ // odr-merging problems, so we can produce better diagnostics for them.
+ // These updates may in turn find and diagnose some ODR failures, so take
+ // ownership of the set first.
+ auto OdrMergeFailures = std::move(PendingOdrMergeFailures);
+ PendingOdrMergeFailures.clear();
+ for (auto &Merge : OdrMergeFailures) {
+ Merge.first->buildLookup();
+ Merge.first->decls_begin();
+ Merge.first->bases_begin();
+ Merge.first->vbases_begin();
+ for (auto *RD : Merge.second) {
+ RD->decls_begin();
+ RD->bases_begin();
+ RD->vbases_begin();
+ }
+ }
+
+ // For each declaration from a merged context, check that the canonical
+ // definition of that context also contains a declaration of the same
+ // entity.
+ //
+ // Caution: this loop does things that might invalidate iterators into
+ // PendingOdrMergeChecks. Don't turn this into a range-based for loop!
+ while (!PendingOdrMergeChecks.empty()) {
+ NamedDecl *D = PendingOdrMergeChecks.pop_back_val();
+
+ // FIXME: Skip over implicit declarations for now. This matters for things
+ // like implicitly-declared special member functions. This isn't entirely
+ // correct; we can end up with multiple unmerged declarations of the same
+ // implicit entity.
+ if (D->isImplicit())
+ continue;
+
+ DeclContext *CanonDef = D->getDeclContext();
+
+ bool Found = false;
+ const Decl *DCanon = D->getCanonicalDecl();
+
+ for (auto RI : D->redecls()) {
+ if (RI->getLexicalDeclContext() == CanonDef) {
+ Found = true;
+ break;
+ }
+ }
+ if (Found)
+ continue;
+
+ llvm::SmallVector<const NamedDecl*, 4> Candidates;
+ DeclContext::lookup_result R = CanonDef->lookup(D->getDeclName());
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end();
+ !Found && I != E; ++I) {
+ for (auto RI : (*I)->redecls()) {
+ if (RI->getLexicalDeclContext() == CanonDef) {
+ // This declaration is present in the canonical definition. If it's
+ // in the same redecl chain, it's the one we're looking for.
+ if (RI->getCanonicalDecl() == DCanon)
+ Found = true;
+ else
+ Candidates.push_back(cast<NamedDecl>(RI));
+ break;
+ }
+ }
+ }
+
+ if (!Found) {
+ // The AST doesn't like TagDecls becoming invalid after they've been
+ // completed. We only really need to mark FieldDecls as invalid here.
+ if (!isa<TagDecl>(D))
+ D->setInvalidDecl();
+
+ std::string CanonDefModule =
+ getOwningModuleNameForDiagnostic(cast<Decl>(CanonDef));
+ Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl)
+ << D << getOwningModuleNameForDiagnostic(D)
+ << CanonDef << CanonDefModule.empty() << CanonDefModule;
+
+ if (Candidates.empty())
+ Diag(cast<Decl>(CanonDef)->getLocation(),
+ diag::note_module_odr_violation_no_possible_decls) << D;
+ else {
+ for (unsigned I = 0, N = Candidates.size(); I != N; ++I)
+ Diag(Candidates[I]->getLocation(),
+ diag::note_module_odr_violation_possible_decl)
+ << Candidates[I];
+ }
+
+ DiagnosedOdrMergeFailures.insert(CanonDef);
+ }
+ }
// Issue any pending ODR-failure diagnostics.
- for (auto &Merge : PendingOdrMergeFailures) {
- if (!DiagnosedOdrMergeFailures.insert(Merge.first))
+ for (auto &Merge : OdrMergeFailures) {
+ // If we've already pointed out a specific problem with this class, don't
+ // bother issuing a general "something's different" diagnostic.
+ if (!DiagnosedOdrMergeFailures.insert(Merge.first).second)
continue;
bool Diagnosed = false;
@@ -8282,7 +8501,6 @@ void ASTReader::finishPendingActions() {
<< Merge.first;
}
}
- PendingOdrMergeFailures.clear();
}
void ASTReader::FinishedDeserializing() {
@@ -8295,10 +8513,13 @@ void ASTReader::FinishedDeserializing() {
}
--NumCurrentElementsDeserializing;
- if (NumCurrentElementsDeserializing == 0 && Consumer) {
+ if (NumCurrentElementsDeserializing == 0) {
+ diagnoseOdrViolations();
+
// We are not in recursive loading, so it's safe to pass the "interesting"
// decls to the consumer.
- PassInterestingDeclsToConsumer();
+ if (Consumer)
+ PassInterestingDeclsToConsumer();
}
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 9ed1bf97ec7a..a783183d2ef6 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -43,6 +43,9 @@ namespace clang {
const RecordData &Record;
unsigned &Idx;
TypeID TypeIDForTypeDecl;
+ unsigned AnonymousDeclNumber;
+ GlobalDeclID NamedDeclForTagDecl;
+ IdentifierInfo *TypedefNameForLinkage;
bool HasPendingBody;
@@ -106,6 +109,12 @@ namespace clang {
void MergeDefinitionData(CXXRecordDecl *D,
struct CXXRecordDecl::DefinitionData &NewDD);
+ static NamedDecl *getAnonymousDeclForMerging(ASTReader &Reader,
+ DeclContext *DC,
+ unsigned Index);
+ static void setAnonymousDeclForMerging(ASTReader &Reader, DeclContext *DC,
+ unsigned Index, NamedDecl *D);
+
/// \brief RAII class used to capture the first ID within a redeclaration
/// chain and to introduce it into the list of pending redeclaration chains
/// on destruction.
@@ -134,7 +143,7 @@ namespace clang {
~RedeclarableResult() {
if (FirstID && Owning && isRedeclarableDeclKind(DeclKind) &&
- Reader.PendingDeclChainsKnown.insert(FirstID))
+ Reader.PendingDeclChainsKnown.insert(FirstID).second)
Reader.PendingDeclChains.push_back(FirstID);
}
@@ -158,50 +167,59 @@ namespace clang {
NamedDecl *New;
NamedDecl *Existing;
mutable bool AddResult;
-
+
+ unsigned AnonymousDeclNumber;
+ IdentifierInfo *TypedefNameForLinkage;
+
void operator=(FindExistingResult&) LLVM_DELETED_FUNCTION;
-
+
public:
FindExistingResult(ASTReader &Reader)
- : Reader(Reader), New(nullptr), Existing(nullptr), AddResult(false) {}
+ : Reader(Reader), New(nullptr), Existing(nullptr), AddResult(false),
+ AnonymousDeclNumber(0), TypedefNameForLinkage(0) {}
+
+ FindExistingResult(ASTReader &Reader, NamedDecl *New, NamedDecl *Existing,
+ unsigned AnonymousDeclNumber,
+ IdentifierInfo *TypedefNameForLinkage)
+ : Reader(Reader), New(New), Existing(Existing), AddResult(true),
+ AnonymousDeclNumber(AnonymousDeclNumber),
+ TypedefNameForLinkage(TypedefNameForLinkage) {}
- FindExistingResult(ASTReader &Reader, NamedDecl *New, NamedDecl *Existing)
- : Reader(Reader), New(New), Existing(Existing), AddResult(true) { }
-
FindExistingResult(const FindExistingResult &Other)
- : Reader(Other.Reader), New(Other.New), Existing(Other.Existing),
- AddResult(Other.AddResult)
- {
+ : Reader(Other.Reader), New(Other.New), Existing(Other.Existing),
+ AddResult(Other.AddResult),
+ AnonymousDeclNumber(Other.AnonymousDeclNumber),
+ TypedefNameForLinkage(Other.TypedefNameForLinkage) {
Other.AddResult = false;
}
-
+
~FindExistingResult();
-
+
/// \brief Suppress the addition of this result into the known set of
/// names.
void suppress() { AddResult = false; }
-
+
operator NamedDecl*() const { return Existing; }
-
+
template<typename T>
operator T*() const { return dyn_cast_or_null<T>(Existing); }
};
-
+
FindExistingResult findExisting(NamedDecl *D);
-
+
public:
- ASTDeclReader(ASTReader &Reader, ModuleFile &F,
- DeclID thisDeclID,
- unsigned RawLocation,
- const RecordData &Record, unsigned &Idx)
- : Reader(Reader), F(F), ThisDeclID(thisDeclID),
- RawLocation(RawLocation), Record(Record), Idx(Idx),
- TypeIDForTypeDecl(0), HasPendingBody(false) { }
+ ASTDeclReader(ASTReader &Reader, ModuleFile &F, DeclID thisDeclID,
+ unsigned RawLocation, const RecordData &Record, unsigned &Idx)
+ : Reader(Reader), F(F), ThisDeclID(thisDeclID),
+ RawLocation(RawLocation), Record(Record), Idx(Idx),
+ TypeIDForTypeDecl(0), NamedDeclForTagDecl(0),
+ TypedefNameForLinkage(nullptr), HasPendingBody(false) {}
template <typename DeclT>
- static void attachPreviousDeclImpl(Redeclarable<DeclT> *D, Decl *Previous);
- static void attachPreviousDeclImpl(...);
- static void attachPreviousDecl(Decl *D, Decl *previous);
+ static void attachPreviousDeclImpl(ASTReader &Reader,
+ Redeclarable<DeclT> *D, Decl *Previous);
+ static void attachPreviousDeclImpl(ASTReader &Reader, ...);
+ static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous);
template <typename DeclT>
static void attachLatestDeclImpl(Redeclarable<DeclT> *D, Decl *Latest);
@@ -233,7 +251,7 @@ namespace clang {
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *TD);
- void VisitTypedefNameDecl(TypedefNameDecl *TD);
+ RedeclarableResult VisitTypedefNameDecl(TypedefNameDecl *TD);
void VisitTypedefDecl(TypedefDecl *TD);
void VisitTypeAliasDecl(TypeAliasDecl *TD);
void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
@@ -359,6 +377,12 @@ void ASTDeclReader::Visit(Decl *D) {
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
// We have a fully initialized TypeDecl. Read its type now.
TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
+
+ // If this is a tag declaration with a typedef name for linkage, it's safe
+ // to load that typedef now.
+ if (NamedDeclForTagDecl)
+ cast<TagDecl>(D)->NamedDeclOrQualifier =
+ cast<NamedDecl>(Reader.GetDecl(NamedDeclForTagDecl));
} else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
// if we have a fully initialized TypeDecl, we can safely read its type now.
ID->TypeForDecl = Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull();
@@ -446,6 +470,8 @@ void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) {
VisitDecl(ND);
ND->setDeclName(Reader.ReadDeclarationName(F, Record, Idx));
+ if (needsAnonymousDeclarationNumber(ND))
+ AnonymousDeclNumber = Record[Idx++];
}
void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) {
@@ -455,7 +481,8 @@ void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) {
TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
}
-void ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) {
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) {
RedeclarableResult Redecl = VisitRedeclarable(TD);
VisitTypeDecl(TD);
TypeSourceInfo *TInfo = GetTypeSourceInfo(Record, Idx);
@@ -464,15 +491,21 @@ void ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) {
TD->setModedTypeSourceInfo(TInfo, modedT);
} else
TD->setTypeSourceInfo(TInfo);
- mergeRedeclarable(TD, Redecl);
+ return Redecl;
}
void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
- VisitTypedefNameDecl(TD);
+ RedeclarableResult Redecl = VisitTypedefNameDecl(TD);
+ mergeRedeclarable(TD, Redecl);
}
void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) {
- VisitTypedefNameDecl(TD);
+ RedeclarableResult Redecl = VisitTypedefNameDecl(TD);
+ if (auto *Template = ReadDeclAs<TypeAliasTemplateDecl>(Record, Idx))
+ // Merged when we merge the template.
+ TD->setDescribedAliasTemplate(Template);
+ else
+ mergeRedeclarable(TD, Redecl);
}
ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
@@ -481,18 +514,32 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
TD->IdentifierNamespace = Record[Idx++];
TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
- TD->setCompleteDefinition(Record[Idx++]);
+ if (!isa<CXXRecordDecl>(TD))
+ TD->setCompleteDefinition(Record[Idx++]);
TD->setEmbeddedInDeclarator(Record[Idx++]);
TD->setFreeStanding(Record[Idx++]);
TD->setCompleteDefinitionRequired(Record[Idx++]);
TD->setRBraceLoc(ReadSourceLocation(Record, Idx));
- if (Record[Idx++]) { // hasExtInfo
+ switch (Record[Idx++]) {
+ case 0:
+ break;
+ case 1: { // ExtInfo
TagDecl::ExtInfo *Info = new (Reader.getContext()) TagDecl::ExtInfo();
ReadQualifierInfo(*Info, Record, Idx);
TD->NamedDeclOrQualifier = Info;
- } else
- TD->NamedDeclOrQualifier = ReadDeclAs<NamedDecl>(Record, Idx);
+ break;
+ }
+ case 2: // TypedefNameForAnonDecl
+ NamedDeclForTagDecl = ReadDeclID(Record, Idx);
+ TypedefNameForLinkage = Reader.GetIdentifierInfo(F, Record, Idx);
+ break;
+ case 3: // DeclaratorForAnonDecl
+ NamedDeclForTagDecl = ReadDeclID(Record, Idx);
+ break;
+ default:
+ llvm_unreachable("unexpected tag info kind");
+ }
if (!isa<CXXRecordDecl>(TD))
mergeRedeclarable(TD, Redecl);
@@ -953,8 +1000,15 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
VisitDeclaratorDecl(FD);
FD->Mutable = Record[Idx++];
if (int BitWidthOrInitializer = Record[Idx++]) {
- FD->InitializerOrBitWidth.setInt(BitWidthOrInitializer - 1);
- FD->InitializerOrBitWidth.setPointer(Reader.ReadExpr(F));
+ FD->InitStorage.setInt(
+ static_cast<FieldDecl::InitStorageKind>(BitWidthOrInitializer - 1));
+ if (FD->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) {
+ // Read captured variable length array.
+ FD->InitStorage.setPointer(
+ Reader.readType(F, Record, Idx).getAsOpaquePtr());
+ } else {
+ FD->InitStorage.setPointer(Reader.ReadExpr(F));
+ }
}
if (!FD->getDeclName()) {
if (FieldDecl *Tmpl = ReadDeclAs<FieldDecl>(Record, Idx))
@@ -1140,7 +1194,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
// any other module's anonymous namespaces, so don't attach the anonymous
// namespace at all.
NamespaceDecl *Anon = ReadDeclAs<NamespaceDecl>(Record, Idx);
- if (F.Kind != MK_Module)
+ if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule)
D->setAnonymousNamespace(Anon);
} else {
// Link this namespace back to the first declaration, which has already
@@ -1152,11 +1206,13 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
}
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
D->NamespaceLoc = ReadSourceLocation(Record, Idx);
D->IdentLoc = ReadSourceLocation(Record, Idx);
D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
D->Namespace = ReadDeclAs<NamedDecl>(Record, Idx);
+ mergeRedeclarable(D, Redecl);
}
void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
@@ -1168,6 +1224,7 @@ void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
D->setTypename(Record[Idx++]);
if (NamedDecl *Pattern = ReadDeclAs<NamedDecl>(Record, Idx))
Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern);
+ mergeMergeable(D);
}
void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
@@ -1195,6 +1252,7 @@ void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
D->setUsingLoc(ReadSourceLocation(Record, Idx));
D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx);
+ mergeMergeable(D);
}
void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
@@ -1202,6 +1260,7 @@ void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
VisitTypeDecl(D);
D->TypenameLocation = ReadSourceLocation(Record, Idx);
D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ mergeMergeable(D);
}
void ASTDeclReader::ReadCXXDefinitionData(
@@ -1279,6 +1338,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
LambdaCaptureKind Kind = static_cast<LambdaCaptureKind>(Record[Idx++]);
switch (Kind) {
case LCK_This:
+ case LCK_VLAType:
*ToCapture++ = Capture(Loc, IsImplicit, Kind, nullptr,SourceLocation());
break;
case LCK_ByCopy:
@@ -1300,8 +1360,11 @@ void ASTDeclReader::MergeDefinitionData(
// If the new definition has new special members, let the name lookup
// code know that it needs to look in the new definition too.
- if ((MergeDD.DeclaredSpecialMembers & ~DD.DeclaredSpecialMembers) &&
- DD.Definition != MergeDD.Definition) {
+ //
+ // FIXME: We only need to do this if the merged definition declares members
+ // that this definition did not declare, or if it defines members that this
+ // definition did not define.
+ if (MergeDD.DeclaredSpecialMembers && DD.Definition != MergeDD.Definition) {
Reader.MergedLookups[DD.Definition].push_back(MergeDD.Definition);
DD.Definition->setHasExternalVisibleStorage();
}
@@ -1493,12 +1556,19 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
VisitFunctionDecl(D);
+
unsigned NumOverridenMethods = Record[Idx++];
- while (NumOverridenMethods--) {
- // Avoid invariant checking of CXXMethodDecl::addOverriddenMethod,
- // MD may be initializing.
- if (CXXMethodDecl *MD = ReadDeclAs<CXXMethodDecl>(Record, Idx))
- Reader.getContext().addOverriddenMethod(D, MD);
+ if (D->isCanonicalDecl()) {
+ while (NumOverridenMethods--) {
+ // Avoid invariant checking of CXXMethodDecl::addOverriddenMethod,
+ // MD may be initializing.
+ if (CXXMethodDecl *MD = ReadDeclAs<CXXMethodDecl>(Record, Idx))
+ Reader.getContext().addOverriddenMethod(D, MD->getCanonicalDecl());
+ }
+ } else {
+ // We don't care about which declarations this used to override; we get
+ // the relevant information from the canonical declaration.
+ Idx += NumOverridenMethods;
}
}
@@ -2015,6 +2085,8 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase,
T *D = static_cast<T*>(DBase);
T *DCanon = D->getCanonicalDecl();
if (D != DCanon &&
+ // IDs < NUM_PREDEF_DECL_IDS are not loaded from an AST file.
+ Redecl.getFirstID() >= NUM_PREDEF_DECL_IDS &&
(!Reader.getContext().getLangOpts().Modules ||
Reader.getOwningModuleFile(DCanon) == Reader.getOwningModuleFile(D))) {
// All redeclarations between this declaration and its originally-canonical
@@ -2075,6 +2147,9 @@ void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D,
Result);
if (auto *DVar = dyn_cast<VarDecl>(DPattern))
return mergeRedeclarable(DVar, cast<VarDecl>(ExistingPattern), Result);
+ if (auto *DAlias = dyn_cast<TypeAliasDecl>(DPattern))
+ return mergeRedeclarable(DAlias, cast<TypedefNameDecl>(ExistingPattern),
+ Result);
llvm_unreachable("merged an unknown kind of redeclarable template");
}
@@ -2199,7 +2274,8 @@ static bool isConsumerInterestedIn(Decl *D, bool HasBody) {
if (isa<FileScopeAsmDecl>(D) ||
isa<ObjCProtocolDecl>(D) ||
isa<ObjCImplDecl>(D) ||
- isa<ImportDecl>(D))
+ isa<ImportDecl>(D) ||
+ isa<OMPThreadPrivateDecl>(D))
return true;
if (VarDecl *Var = dyn_cast<VarDecl>(D))
return Var->isFileVarDecl() &&
@@ -2269,6 +2345,53 @@ static bool isSameTemplateParameter(const NamedDecl *X,
TY->getTemplateParameters());
}
+static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) {
+ if (auto *NS = X->getAsNamespace())
+ return NS;
+ if (auto *NAS = X->getAsNamespaceAlias())
+ return NAS->getNamespace();
+ return nullptr;
+}
+
+static bool isSameQualifier(const NestedNameSpecifier *X,
+ const NestedNameSpecifier *Y) {
+ if (auto *NSX = getNamespace(X)) {
+ auto *NSY = getNamespace(Y);
+ if (!NSY || NSX->getCanonicalDecl() != NSY->getCanonicalDecl())
+ return false;
+ } else if (X->getKind() != Y->getKind())
+ return false;
+
+ // FIXME: For namespaces and types, we're permitted to check that the entity
+ // is named via the same tokens. We should probably do so.
+ switch (X->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ if (X->getAsIdentifier() != Y->getAsIdentifier())
+ return false;
+ break;
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ // We've already checked that we named the same namespace.
+ break;
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ if (X->getAsType()->getCanonicalTypeInternal() !=
+ Y->getAsType()->getCanonicalTypeInternal())
+ return false;
+ break;
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
+ return true;
+ }
+
+ // Recurse into earlier portion of NNS, if any.
+ auto *PX = X->getPrefix();
+ auto *PY = Y->getPrefix();
+ if (PX && PY)
+ return isSameQualifier(PX, PY);
+ return !PX && !PY;
+}
+
/// \brief Determine whether two template parameter lists are similar enough
/// that they may be used in declarations of the same template.
static bool isSameTemplateParameterList(const TemplateParameterList *X,
@@ -2286,10 +2409,10 @@ static bool isSameTemplateParameterList(const TemplateParameterList *X,
/// \brief Determine whether the two declarations refer to the same entity.
static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!");
-
+
if (X == Y)
return true;
-
+
// Must be in the same context.
if (!X->getDeclContext()->getRedeclContext()->Equals(
Y->getDeclContext()->getRedeclContext()))
@@ -2301,11 +2424,11 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
if (TypedefNameDecl *TypedefY = dyn_cast<TypedefNameDecl>(Y))
return X->getASTContext().hasSameType(TypedefX->getUnderlyingType(),
TypedefY->getUnderlyingType());
-
+
// Must have the same kind.
if (X->getKind() != Y->getKind())
return false;
-
+
// Objective-C classes and protocols with the same name always match.
if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
return true;
@@ -2327,8 +2450,8 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
}
// Functions with the same type and linkage match.
- // FIXME: This needs to cope with function template specializations,
- // merging of prototyped/non-prototyped functions, etc.
+ // FIXME: This needs to cope with merging of prototyped/non-prototyped
+ // functions, etc.
if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) {
FunctionDecl *FuncY = cast<FunctionDecl>(Y);
return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) &&
@@ -2361,7 +2484,6 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
// Fields with the same name and the same type match.
if (FieldDecl *FDX = dyn_cast<FieldDecl>(X)) {
FieldDecl *FDY = cast<FieldDecl>(Y);
- // FIXME: Diagnose if the types don't match.
// FIXME: Also check the bitwidth is odr-equivalent, if any.
return X->getASTContext().hasSameType(FDX->getType(), FDY->getType());
}
@@ -2377,6 +2499,30 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
return USX->getTargetDecl() == USY->getTargetDecl();
}
+ // Using declarations with the same qualifier match. (We already know that
+ // the name matches.)
+ if (auto *UX = dyn_cast<UsingDecl>(X)) {
+ auto *UY = cast<UsingDecl>(Y);
+ return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
+ UX->hasTypename() == UY->hasTypename() &&
+ UX->isAccessDeclaration() == UY->isAccessDeclaration();
+ }
+ if (auto *UX = dyn_cast<UnresolvedUsingValueDecl>(X)) {
+ auto *UY = cast<UnresolvedUsingValueDecl>(Y);
+ return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
+ UX->isAccessDeclaration() == UY->isAccessDeclaration();
+ }
+ if (auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X))
+ return isSameQualifier(
+ UX->getQualifier(),
+ cast<UnresolvedUsingTypenameDecl>(Y)->getQualifier());
+
+ // Namespace alias definitions with the same target match.
+ if (auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) {
+ auto *NAY = cast<NamespaceAliasDecl>(Y);
+ return NAX->getNamespace()->Equals(NAY->getNamespace());
+ }
+
// FIXME: Many other cases to implement.
return false;
}
@@ -2387,8 +2533,14 @@ static DeclContext *getPrimaryContextForMerging(DeclContext *DC) {
if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
return ND->getOriginalNamespace();
+ // There is one tricky case here: if DC is a class with no definition, then
+ // we're merging a declaration whose definition is added by an update record,
+ // but we've not yet loaded that update record. In this case, we use the
+ // canonical declaration for merging until we get a real definition.
+ // FIXME: When we add a definition, we may need to move the partial lookup
+ // information from the canonical declaration onto the chosen definition.
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC))
- return RD->getDefinition();
+ return RD->getPrimaryContext();
if (EnumDecl *ED = dyn_cast<EnumDecl>(DC))
return ED->getASTContext().getLangOpts().CPlusPlus? ED->getDefinition()
@@ -2401,9 +2553,17 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() {
if (!AddResult || Existing)
return;
+ DeclarationName Name = New->getDeclName();
DeclContext *DC = New->getDeclContext()->getRedeclContext();
- if (DC->isTranslationUnit() && Reader.SemaObj) {
- Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, New->getDeclName());
+ if (TypedefNameForLinkage) {
+ Reader.ImportedTypedefNamesForLinkage.insert(
+ std::make_pair(std::make_pair(DC, TypedefNameForLinkage), New));
+ } else if (!Name) {
+ assert(needsAnonymousDeclarationNumber(New));
+ setAnonymousDeclForMerging(Reader, New->getLexicalDeclContext(),
+ AnonymousDeclNumber, New);
+ } else if (DC->isTranslationUnit() && Reader.SemaObj) {
+ Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name);
} else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) {
// Add the declaration to its redeclaration context so later merging
// lookups will find it.
@@ -2411,11 +2571,81 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() {
}
}
+/// Find the declaration that should be merged into, given the declaration found
+/// by name lookup. If we're merging an anonymous declaration within a typedef,
+/// we need a matching typedef, and we merge with the type inside it.
+static NamedDecl *getDeclForMerging(NamedDecl *Found,
+ bool IsTypedefNameForLinkage) {
+ if (!IsTypedefNameForLinkage)
+ return Found;
+
+ // If we found a typedef declaration that gives a name to some other
+ // declaration, then we want that inner declaration. Declarations from
+ // AST files are handled via ImportedTypedefNamesForLinkage.
+ if (Found->isFromASTFile()) return 0;
+ if (auto *TND = dyn_cast<TypedefNameDecl>(Found)) {
+ if (auto *TT = TND->getTypeSourceInfo()->getType()->getAs<TagType>())
+ if (TT->getDecl()->getTypedefNameForAnonDecl() == TND)
+ return TT->getDecl();
+ }
+
+ return 0;
+}
+
+NamedDecl *ASTDeclReader::getAnonymousDeclForMerging(ASTReader &Reader,
+ DeclContext *DC,
+ unsigned Index) {
+ // If the lexical context has been merged, look into the now-canonical
+ // definition.
+ if (auto *Merged = Reader.MergedDeclContexts.lookup(DC))
+ DC = Merged;
+
+ // If we've seen this before, return the canonical declaration.
+ auto &Previous = Reader.AnonymousDeclarationsForMerging[DC];
+ if (Index < Previous.size() && Previous[Index])
+ return Previous[Index];
+
+ // If this is the first time, but we have parsed a declaration of the context,
+ // build the anonymous declaration list from the parsed declaration.
+ if (!cast<Decl>(DC)->isFromASTFile()) {
+ unsigned Index = 0;
+ for (Decl *LexicalD : DC->decls()) {
+ auto *ND = dyn_cast<NamedDecl>(LexicalD);
+ if (!ND || !needsAnonymousDeclarationNumber(ND))
+ continue;
+ if (Previous.size() == Index)
+ Previous.push_back(cast<NamedDecl>(ND->getCanonicalDecl()));
+ else
+ Previous[Index] = cast<NamedDecl>(ND->getCanonicalDecl());
+ ++Index;
+ }
+ }
+
+ return Index < Previous.size() ? Previous[Index] : nullptr;
+}
+
+void ASTDeclReader::setAnonymousDeclForMerging(ASTReader &Reader,
+ DeclContext *DC, unsigned Index,
+ NamedDecl *D) {
+ if (auto *Merged = Reader.MergedDeclContexts.lookup(DC))
+ DC = Merged;
+
+ auto &Previous = Reader.AnonymousDeclarationsForMerging[DC];
+ if (Index >= Previous.size())
+ Previous.resize(Index + 1);
+ if (!Previous[Index])
+ Previous[Index] = D;
+}
+
ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
- DeclarationName Name = D->getDeclName();
- if (!Name) {
- // Don't bother trying to find unnamed declarations.
- FindExistingResult Result(Reader, D, /*Existing=*/nullptr);
+ DeclarationName Name = TypedefNameForLinkage ? TypedefNameForLinkage
+ : D->getDeclName();
+
+ if (!Name && !needsAnonymousDeclarationNumber(D)) {
+ // Don't bother trying to find unnamed declarations that are in
+ // unmergeable contexts.
+ FindExistingResult Result(Reader, D, /*Existing=*/nullptr,
+ AnonymousDeclNumber, TypedefNameForLinkage);
// FIXME: We may still need to pull in the redeclaration chain; there can
// be redeclarations via 'decltype'.
Result.suppress();
@@ -2426,7 +2656,27 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
// necessary merging already.
DeclContext *DC = D->getDeclContext()->getRedeclContext();
- if (DC->isTranslationUnit() && Reader.SemaObj) {
+ if (TypedefNameForLinkage) {
+ auto It = Reader.ImportedTypedefNamesForLinkage.find(
+ std::make_pair(DC, TypedefNameForLinkage));
+ if (It != Reader.ImportedTypedefNamesForLinkage.end())
+ if (isSameEntity(It->second, D))
+ return FindExistingResult(Reader, D, It->second, AnonymousDeclNumber,
+ TypedefNameForLinkage);
+ // Go on to check in other places in case an existing typedef name
+ // was not imported.
+ }
+
+ if (!Name) {
+ // This is an anonymous declaration that we may need to merge. Look it up
+ // in its context by number.
+ assert(needsAnonymousDeclarationNumber(D));
+ if (auto *Existing = getAnonymousDeclForMerging(
+ Reader, D->getLexicalDeclContext(), AnonymousDeclNumber))
+ if (isSameEntity(Existing, D))
+ return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
+ TypedefNameForLinkage);
+ } else if (DC->isTranslationUnit() && Reader.SemaObj) {
IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
// Temporarily consider the identifier to be up-to-date. We don't want to
@@ -2455,14 +2705,18 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
for (IdentifierResolver::iterator I = IdResolver.begin(Name),
IEnd = IdResolver.end();
I != IEnd; ++I) {
- if (isSameEntity(*I, D))
- return FindExistingResult(Reader, D, *I);
+ if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage))
+ if (isSameEntity(Existing, D))
+ return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
+ TypedefNameForLinkage);
}
} else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) {
DeclContext::lookup_result R = MergeDC->noload_lookup(Name);
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
- if (isSameEntity(*I, D))
- return FindExistingResult(Reader, D, *I);
+ if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage))
+ if (isSameEntity(Existing, D))
+ return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
+ TypedefNameForLinkage);
}
} else {
// Not in a mergeable context.
@@ -2474,29 +2728,78 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
//
// FIXME: We should do something similar if we merge two definitions of the
// same template specialization into the same CXXRecordDecl.
- if (Reader.MergedDeclContexts.count(D->getLexicalDeclContext()))
+ auto MergedDCIt = Reader.MergedDeclContexts.find(D->getLexicalDeclContext());
+ if (MergedDCIt != Reader.MergedDeclContexts.end() &&
+ MergedDCIt->second == D->getDeclContext())
Reader.PendingOdrMergeChecks.push_back(D);
- return FindExistingResult(Reader, D, /*Existing=*/nullptr);
+ return FindExistingResult(Reader, D, /*Existing=*/nullptr,
+ AnonymousDeclNumber, TypedefNameForLinkage);
}
template<typename DeclT>
-void ASTDeclReader::attachPreviousDeclImpl(Redeclarable<DeclT> *D,
+void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
+ Redeclarable<DeclT> *D,
Decl *Previous) {
D->RedeclLink.setPrevious(cast<DeclT>(Previous));
}
-void ASTDeclReader::attachPreviousDeclImpl(...) {
+namespace clang {
+template<>
+void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
+ Redeclarable<FunctionDecl> *D,
+ Decl *Previous) {
+ FunctionDecl *FD = static_cast<FunctionDecl*>(D);
+ FunctionDecl *PrevFD = cast<FunctionDecl>(Previous);
+
+ FD->RedeclLink.setPrevious(PrevFD);
+
+ // If the previous declaration is an inline function declaration, then this
+ // declaration is too.
+ if (PrevFD->IsInline != FD->IsInline) {
+ // FIXME: [dcl.fct.spec]p4:
+ // If a function with external linkage is declared inline in one
+ // translation unit, it shall be declared inline in all translation
+ // units in which it appears.
+ //
+ // Be careful of this case:
+ //
+ // module A:
+ // template<typename T> struct X { void f(); };
+ // template<typename T> inline void X<T>::f() {}
+ //
+ // module B instantiates the declaration of X<int>::f
+ // module C instantiates the definition of X<int>::f
+ //
+ // If module B and C are merged, we do not have a violation of this rule.
+ FD->IsInline = true;
+ }
+
+ // If this declaration has an unresolved exception specification but the
+ // previous declaration had a resolved one, resolve the exception
+ // specification now.
+ auto *FPT = FD->getType()->getAs<FunctionProtoType>();
+ auto *PrevFPT = PrevFD->getType()->getAs<FunctionProtoType>();
+ if (FPT && PrevFPT &&
+ isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
+ !isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType())) {
+ Reader.Context.adjustExceptionSpec(
+ FD, PrevFPT->getExtProtoInfo().ExceptionSpec);
+ }
+}
+}
+void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, ...) {
llvm_unreachable("attachPreviousDecl on non-redeclarable declaration");
}
-void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *Previous) {
+void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
+ Decl *Previous) {
assert(D && Previous);
switch (D->getKind()) {
#define ABSTRACT_DECL(TYPE)
-#define DECL(TYPE, BASE) \
- case Decl::TYPE: \
- attachPreviousDeclImpl(cast<TYPE##Decl>(D), Previous); \
+#define DECL(TYPE, BASE) \
+ case Decl::TYPE: \
+ attachPreviousDeclImpl(Reader, cast<TYPE##Decl>(D), Previous); \
break;
#include "clang/AST/DeclNodes.inc"
}
@@ -2514,32 +2817,6 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *Previous) {
// be too.
if (Previous->Used)
D->Used = true;
-
- // If the previous declaration is an inline function declaration, then this
- // declaration is too.
- if (auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (cast<FunctionDecl>(Previous)->IsInline != FD->IsInline) {
- // FIXME: [dcl.fct.spec]p4:
- // If a function with external linkage is declared inline in one
- // translation unit, it shall be declared inline in all translation
- // units in which it appears.
- //
- // Be careful of this case:
- //
- // module A:
- // template<typename T> struct X { void f(); };
- // template<typename T> inline void X<T>::f() {}
- //
- // module B instantiates the declaration of X<int>::f
- // module C instantiates the definition of X<int>::f
- //
- // If module B and C are merged, we do not have a violation of this rule.
- //
- //if (!FD->IsInline || Previous->getOwningModule())
- // Diag(FD->getLocation(), diag::err_odr_differing_inline);
- FD->IsInline = true;
- }
- }
}
template<typename DeclT>
@@ -2593,11 +2870,11 @@ ASTReader::combineStoredMergedDecls(Decl *Canon, GlobalDeclID CanonID) {
// Append the stored merged declarations to the merged declarations set.
MergedDeclsMap::iterator Pos = MergedDecls.find(Canon);
if (Pos == MergedDecls.end())
- Pos = MergedDecls.insert(std::make_pair(Canon,
+ Pos = MergedDecls.insert(std::make_pair(Canon,
SmallVector<DeclID, 2>())).first;
Pos->second.append(StoredPos->second.begin(), StoredPos->second.end());
StoredMergedDecls.erase(StoredPos);
-
+
// Sort and uniquify the set of merged declarations.
llvm::array_pod_sort(Pos->second.begin(), Pos->second.end());
Pos->second.erase(std::unique(Pos->second.begin(), Pos->second.end()),
@@ -2927,13 +3204,13 @@ namespace {
class RedeclChainVisitor {
ASTReader &Reader;
SmallVectorImpl<DeclID> &SearchDecls;
- llvm::SmallPtrSet<Decl *, 16> &Deserialized;
+ llvm::SmallPtrSetImpl<Decl *> &Deserialized;
GlobalDeclID CanonID;
SmallVector<Decl *, 4> Chain;
public:
RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl<DeclID> &SearchDecls,
- llvm::SmallPtrSet<Decl *, 16> &Deserialized,
+ llvm::SmallPtrSetImpl<Decl *> &Deserialized,
GlobalDeclID CanonID)
: Reader(Reader), SearchDecls(SearchDecls), Deserialized(Deserialized),
CanonID(CanonID) {
@@ -3038,7 +3315,7 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
if (Chain[I] == CanonDecl)
continue;
- ASTDeclReader::attachPreviousDecl(Chain[I], MostRecent);
+ ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent);
MostRecent = Chain[I];
}
@@ -3052,7 +3329,7 @@ namespace {
ASTReader &Reader;
serialization::GlobalDeclID InterfaceID;
ObjCInterfaceDecl *Interface;
- llvm::SmallPtrSet<ObjCCategoryDecl *, 16> &Deserialized;
+ llvm::SmallPtrSetImpl<ObjCCategoryDecl *> &Deserialized;
unsigned PreviousGeneration;
ObjCCategoryDecl *Tail;
llvm::DenseMap<DeclarationName, ObjCCategoryDecl *> NameCategoryMap;
@@ -3100,7 +3377,7 @@ namespace {
ObjCCategoriesVisitor(ASTReader &Reader,
serialization::GlobalDeclID InterfaceID,
ObjCInterfaceDecl *Interface,
- llvm::SmallPtrSet<ObjCCategoryDecl *, 16> &Deserialized,
+ llvm::SmallPtrSetImpl<ObjCCategoryDecl *> &Deserialized,
unsigned PreviousGeneration)
: Reader(Reader), InterfaceID(InterfaceID), Interface(Interface),
Deserialized(Deserialized), PreviousGeneration(PreviousGeneration),
@@ -3168,13 +3445,80 @@ void ASTReader::loadObjCCategories(serialization::GlobalDeclID ID,
ModuleMgr.visit(ObjCCategoriesVisitor::visit, &Visitor);
}
+namespace {
+/// Iterator over the redeclarations of a declaration that have already
+/// been merged into the same redeclaration chain.
+template<typename DeclT>
+class MergedRedeclIterator {
+ DeclT *Start, *Canonical, *Current;
+public:
+ MergedRedeclIterator() : Current(nullptr) {}
+ MergedRedeclIterator(DeclT *Start)
+ : Start(Start), Canonical(nullptr), Current(Start) {}
+
+ DeclT *operator*() { return Current; }
+
+ MergedRedeclIterator &operator++() {
+ if (Current->isFirstDecl()) {
+ Canonical = Current;
+ Current = Current->getMostRecentDecl();
+ } else
+ Current = Current->getPreviousDecl();
+
+ // If we started in the merged portion, we'll reach our start position
+ // eventually. Otherwise, we'll never reach it, but the second declaration
+ // we reached was the canonical declaration, so stop when we see that one
+ // again.
+ if (Current == Start || Current == Canonical)
+ Current = nullptr;
+ return *this;
+ }
+
+ friend bool operator!=(const MergedRedeclIterator &A,
+ const MergedRedeclIterator &B) {
+ return A.Current != B.Current;
+ }
+};
+}
+template<typename DeclT>
+llvm::iterator_range<MergedRedeclIterator<DeclT>> merged_redecls(DeclT *D) {
+ return llvm::iterator_range<MergedRedeclIterator<DeclT>>(
+ MergedRedeclIterator<DeclT>(D),
+ MergedRedeclIterator<DeclT>());
+}
+
+template<typename DeclT, typename Fn>
+static void forAllLaterRedecls(DeclT *D, Fn F) {
+ F(D);
+
+ // Check whether we've already merged D into its redeclaration chain.
+ // MostRecent may or may not be nullptr if D has not been merged. If
+ // not, walk the merged redecl chain and see if it's there.
+ auto *MostRecent = D->getMostRecentDecl();
+ bool Found = false;
+ for (auto *Redecl = MostRecent; Redecl && !Found;
+ Redecl = Redecl->getPreviousDecl())
+ Found = (Redecl == D);
+
+ // If this declaration is merged, apply the functor to all later decls.
+ if (Found) {
+ for (auto *Redecl = MostRecent; Redecl != D;
+ Redecl = Redecl->getPreviousDecl())
+ F(Redecl);
+ }
+}
+
void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
const RecordData &Record) {
while (Idx < Record.size()) {
switch ((DeclUpdateKind)Record[Idx++]) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
+ // FIXME: If we also have an update record for instantiating the
+ // definition of D, we need that to happen before we get here.
Decl *MD = Reader.ReadDecl(ModuleFile, Record, Idx);
assert(MD && "couldn't read decl from update record");
+ // FIXME: We should call addHiddenDecl instead, to add the member
+ // to its DeclContext.
cast<CXXRecordDecl>(D)->addedMember(MD);
break;
}
@@ -3191,7 +3535,8 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
// Each module has its own anonymous namespace, which is disjoint from
// any other module's anonymous namespaces, so don't attach the anonymous
// namespace at all.
- if (ModuleFile.Kind != MK_Module) {
+ if (ModuleFile.Kind != MK_ImplicitModule &&
+ ModuleFile.Kind != MK_ExplicitModule) {
if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D))
TU->setAnonymousNamespace(Anon);
else
@@ -3205,7 +3550,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
Reader.ReadSourceLocation(ModuleFile, Record, Idx));
break;
- case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION: {
+ case UPD_CXX_ADDED_FUNCTION_DEFINITION: {
FunctionDecl *FD = cast<FunctionDecl>(D);
if (Reader.PendingBodies[FD]) {
// FIXME: Maybe check for ODR violations.
@@ -3217,17 +3562,18 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
// Maintain AST consistency: any later redeclarations of this function
// are inline if this one is. (We might have merged another declaration
// into this one.)
- for (auto *D = FD->getMostRecentDecl(); /**/;
- D = D->getPreviousDecl()) {
- D->setImplicitlyInline();
- if (D == FD)
- break;
- }
+ forAllLaterRedecls(FD, [](FunctionDecl *FD) {
+ FD->setImplicitlyInline();
+ });
}
FD->setInnerLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
std::tie(CD->CtorInitializers, CD->NumCtorInitializers) =
Reader.ReadCXXCtorInitializers(ModuleFile, Record, Idx);
+ if (auto *DD = dyn_cast<CXXDestructorDecl>(FD))
+ // FIXME: Check consistency.
+ DD->setOperatorDelete(Reader.ReadDeclAs<FunctionDecl>(ModuleFile,
+ Record, Idx));
// Store the offset of the body so we can lazily load it later.
Reader.PendingBodies[FD] = GetCurrentCursorOffset();
HasPendingBody = true;
@@ -3246,6 +3592,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
Reader.ReadDeclContextStorage(ModuleFile, ModuleFile.DeclsCursor,
std::make_pair(LexicalOffset, 0),
ModuleFile.DeclContextInfos[RD]);
+ Reader.PendingDefinitions.insert(RD);
}
auto TSK = (TemplateSpecializationKind)Record[Idx++];
@@ -3267,7 +3614,12 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
auto *TemplArgList = TemplateArgumentList::CreateCopy(
Reader.getContext(), TemplArgs.data(), TemplArgs.size());
- Spec->setInstantiationOf(PartialSpec, TemplArgList);
+
+ // FIXME: If we already have a partial specialization set,
+ // check that it matches.
+ if (!Spec->getSpecializedTemplateOrPartial()
+ .is<ClassTemplatePartialSpecializationDecl *>())
+ Spec->setInstantiationOf(PartialSpec, TemplArgList);
}
}
@@ -3285,20 +3637,35 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
}
case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
- auto *FD = cast<FunctionDecl>(D);
- auto *FPT = FD->getType()->castAs<FunctionProtoType>();
- auto EPI = FPT->getExtProtoInfo();
+ // FIXME: This doesn't send the right notifications if there are
+ // ASTMutationListeners other than an ASTWriter.
+ FunctionProtoType::ExceptionSpecInfo ESI;
SmallVector<QualType, 8> ExceptionStorage;
- Reader.readExceptionSpec(ModuleFile, ExceptionStorage, EPI, Record, Idx);
- FD->setType(Reader.Context.getFunctionType(FPT->getReturnType(),
- FPT->getParamTypes(), EPI));
+ Reader.readExceptionSpec(ModuleFile, ExceptionStorage, ESI, Record, Idx);
+ for (auto *Redecl : merged_redecls(D)) {
+ auto *FD = cast<FunctionDecl>(Redecl);
+ auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+ if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
+ // AST invariant: if any exception spec in the redecl chain is
+ // resolved, all are resolved. We don't need to go any further.
+ // FIXME: If the exception spec is resolved, check that it matches.
+ break;
+ }
+ FD->setType(Reader.Context.getFunctionType(
+ FPT->getReturnType(), FPT->getParamTypes(),
+ FPT->getExtProtoInfo().withExceptionSpec(ESI)));
+ }
break;
}
case UPD_CXX_DEDUCED_RETURN_TYPE: {
- FunctionDecl *FD = cast<FunctionDecl>(D);
- Reader.Context.adjustDeducedFunctionResultType(
- FD, Reader.readType(ModuleFile, Record, Idx));
+ // FIXME: Also do this when merging redecls.
+ QualType DeducedResultType = Reader.readType(ModuleFile, Record, Idx);
+ for (auto *Redecl : merged_redecls(D)) {
+ // FIXME: If the return type is already deduced, check that it matches.
+ FunctionDecl *FD = cast<FunctionDecl>(Redecl);
+ Reader.Context.adjustDeducedFunctionResultType(FD, DeducedResultType);
+ }
break;
}
@@ -3306,17 +3673,8 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
// FIXME: This doesn't send the right notifications if there are
// ASTMutationListeners other than an ASTWriter.
- // FIXME: We can't both pull in declarations (and thus create new pending
- // redeclaration chains) *and* walk redeclaration chains in this function.
- // We should defer the updates that require walking redecl chains.
-
// Maintain AST consistency: any later redeclarations are used too.
- for (auto *Redecl = D->getMostRecentDecl(); /**/;
- Redecl = Redecl->getPreviousDecl()) {
- Redecl->Used = true;
- if (Redecl == D)
- break;
- }
+ forAllLaterRedecls(D, [](Decl *D) { D->Used = true; });
break;
}
@@ -3327,6 +3685,10 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
case UPD_STATIC_LOCAL_NUMBER:
Reader.Context.setStaticLocalNumber(cast<VarDecl>(D), Record[Idx++]);
break;
+ case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
+ D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
+ Reader.Context, ReadSourceRange(Record, Idx)));
+ break;
}
}
}
diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h
index a63e362eb64f..d1b032b27ac2 100644
--- a/lib/Serialization/ASTReaderInternals.h
+++ b/lib/Serialization/ASTReaderInternals.h
@@ -10,8 +10,8 @@
// This file provides internal definitions used in the AST reader.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H
-#define LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H
+#ifndef LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H
+#define LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H
#include "clang/AST/DeclarationName.h"
#include "clang/Serialization/ASTBitCodes.h"
@@ -156,6 +156,8 @@ public:
SelectorID ID;
unsigned InstanceBits;
unsigned FactoryBits;
+ bool InstanceHasMoreThanOneDecl;
+ bool FactoryHasMoreThanOneDecl;
SmallVector<ObjCMethodDecl *, 2> Instance;
SmallVector<ObjCMethodDecl *, 2> Factory;
};
@@ -194,8 +196,8 @@ typedef llvm::OnDiskChainedHashTable<ASTSelectorLookupTrait>
///
/// The on-disk hash table contains a mapping from each header path to
/// information about that header (how many times it has been included, its
-/// controlling macro, etc.). Note that we actually hash based on the
-/// filename, and support "deep" comparisons of file names based on current
+/// controlling macro, etc.). Note that we actually hash based on the size
+/// and mtime, and support "deep" comparisons of file names based on current
/// inode numbers, so that the search can cope with non-normalized path names
/// and symlinks.
class HeaderFileInfoTrait {
@@ -211,6 +213,7 @@ public:
off_t Size;
time_t ModTime;
const char *Filename;
+ bool Imported;
};
typedef const internal_key_type &internal_key_ref;
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 8bf17d51b3e8..4ef2e73062a5 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -135,8 +135,8 @@ void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) {
while (NumStmts--)
Stmts.push_back(Reader.ReadSubStmt());
S->setStmts(Reader.getContext(), Stmts.data(), Stmts.size());
- S->setLBracLoc(ReadSourceLocation(Record, Idx));
- S->setRBracLoc(ReadSourceLocation(Record, Idx));
+ S->LBraceLoc = ReadSourceLocation(Record, Idx);
+ S->RBraceLoc = ReadSourceLocation(Record, Idx);
}
void ASTStmtReader::VisitSwitchCase(SwitchCase *S) {
@@ -422,7 +422,8 @@ void ASTStmtReader::VisitExpr(Expr *E) {
void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
VisitExpr(E);
E->setLocation(ReadSourceLocation(Record, Idx));
- E->setIdentType((PredefinedExpr::IdentType)Record[Idx++]);
+ E->Type = (PredefinedExpr::IdentType)Record[Idx++];
+ E->FnName = cast_or_null<StringLiteral>(Reader.ReadSubExpr());
}
void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
@@ -432,7 +433,7 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
E->DeclRefExprBits.HasFoundDecl = Record[Idx++];
E->DeclRefExprBits.HasTemplateKWAndArgsInfo = Record[Idx++];
E->DeclRefExprBits.HadMultipleCandidates = Record[Idx++];
- E->DeclRefExprBits.RefersToEnclosingLocal = Record[Idx++];
+ E->DeclRefExprBits.RefersToEnclosingVariableOrCapture = Record[Idx++];
unsigned NumTemplateArgs = 0;
if (E->hasTemplateKWAndArgsInfo())
NumTemplateArgs = Record[Idx++];
@@ -634,7 +635,7 @@ void ASTStmtReader::VisitCastExpr(CastExpr *E) {
unsigned NumBaseSpecs = Record[Idx++];
assert(NumBaseSpecs == E->path_size());
E->setSubExpr(Reader.ReadSubExpr());
- E->setCastKind((CastExpr::CastKind)Record[Idx++]);
+ E->setCastKind((CastKind)Record[Idx++]);
CastExpr::path_iterator BaseI = E->path_begin();
while (NumBaseSpecs--) {
CXXBaseSpecifier *BaseSpec = new (Reader.getContext()) CXXBaseSpecifier;
@@ -1579,12 +1580,26 @@ void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
E->setExtendingDecl(VD, ManglingNumber);
}
+void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) {
+ VisitExpr(E);
+ E->LParenLoc = ReadSourceLocation(Record, Idx);
+ E->EllipsisLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+ E->SubExprs[0] = Reader.ReadSubExpr();
+ E->SubExprs[1] = Reader.ReadSubExpr();
+ E->Opcode = (BinaryOperatorKind)Record[Idx++];
+}
+
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
E->SourceExpr = Reader.ReadSubExpr();
E->Loc = ReadSourceLocation(Record, Idx);
}
+void ASTStmtReader::VisitTypoExpr(TypoExpr *E) {
+ llvm_unreachable("Cannot read TypoExpr nodes");
+}
+
//===----------------------------------------------------------------------===//
// Microsoft Expressions and Statements
//===----------------------------------------------------------------------===//
@@ -1715,6 +1730,21 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_mergeable:
C = new (Context) OMPMergeableClause();
break;
+ case OMPC_read:
+ C = new (Context) OMPReadClause();
+ break;
+ case OMPC_write:
+ C = new (Context) OMPWriteClause();
+ break;
+ case OMPC_update:
+ C = new (Context) OMPUpdateClause();
+ break;
+ case OMPC_capture:
+ C = new (Context) OMPCaptureClause();
+ break;
+ case OMPC_seq_cst:
+ C = new (Context) OMPSeqCstClause();
+ break;
case OMPC_private:
C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]);
break;
@@ -1809,6 +1839,16 @@ void OMPClauseReader::VisitOMPUntiedClause(OMPUntiedClause *) {}
void OMPClauseReader::VisitOMPMergeableClause(OMPMergeableClause *) {}
+void OMPClauseReader::VisitOMPReadClause(OMPReadClause *) {}
+
+void OMPClauseReader::VisitOMPWriteClause(OMPWriteClause *) {}
+
+void OMPClauseReader::VisitOMPUpdateClause(OMPUpdateClause *) {}
+
+void OMPClauseReader::VisitOMPCaptureClause(OMPCaptureClause *) {}
+
+void OMPClauseReader::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
+
void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
@@ -1817,6 +1857,10 @@ void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
for (unsigned i = 0; i != NumVars; ++i)
Vars.push_back(Reader->Reader.ReadSubExpr());
C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setPrivateCopies(Vars);
}
void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
@@ -1827,6 +1871,14 @@ void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
for (unsigned i = 0; i != NumVars; ++i)
Vars.push_back(Reader->Reader.ReadSubExpr());
C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setPrivateCopies(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setInits(Vars);
}
void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
@@ -1936,6 +1988,45 @@ void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
E->setAssociatedStmt(Reader.ReadSubStmt());
}
+void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) {
+ VisitStmt(D);
+ // Two fields (NumClauses and CollapsedNum) were read in ReadStmtFromStream.
+ Idx += 2;
+ VisitOMPExecutableDirective(D);
+ D->setIterationVariable(Reader.ReadSubExpr());
+ D->setLastIteration(Reader.ReadSubExpr());
+ D->setCalcLastIteration(Reader.ReadSubExpr());
+ D->setPreCond(Reader.ReadSubExpr());
+ auto Fst = Reader.ReadSubExpr();
+ auto Snd = Reader.ReadSubExpr();
+ D->setCond(Fst, Snd);
+ D->setInit(Reader.ReadSubExpr());
+ D->setInc(Reader.ReadSubExpr());
+ if (isOpenMPWorksharingDirective(D->getDirectiveKind())) {
+ D->setIsLastIterVariable(Reader.ReadSubExpr());
+ D->setLowerBoundVariable(Reader.ReadSubExpr());
+ D->setUpperBoundVariable(Reader.ReadSubExpr());
+ D->setStrideVariable(Reader.ReadSubExpr());
+ D->setEnsureUpperBound(Reader.ReadSubExpr());
+ D->setNextLowerBound(Reader.ReadSubExpr());
+ D->setNextUpperBound(Reader.ReadSubExpr());
+ }
+ SmallVector<Expr *, 4> Sub;
+ unsigned CollapsedNum = D->getCollapsedNumber();
+ Sub.reserve(CollapsedNum);
+ for (unsigned i = 0; i < CollapsedNum; ++i)
+ Sub.push_back(Reader.ReadSubExpr());
+ D->setCounters(Sub);
+ Sub.clear();
+ for (unsigned i = 0; i < CollapsedNum; ++i)
+ Sub.push_back(Reader.ReadSubExpr());
+ D->setUpdates(Sub);
+ Sub.clear();
+ for (unsigned i = 0; i < CollapsedNum; ++i)
+ Sub.push_back(Reader.ReadSubExpr());
+ D->setFinals(Sub);
+}
+
void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) {
VisitStmt(D);
// The NumClauses field was read in ReadStmtFromStream.
@@ -1944,17 +2035,15 @@ void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) {
}
void ASTStmtReader::VisitOMPSimdDirective(OMPSimdDirective *D) {
- VisitStmt(D);
- // Two fields (NumClauses and CollapsedNum) were read in ReadStmtFromStream.
- Idx += 2;
- VisitOMPExecutableDirective(D);
+ VisitOMPLoopDirective(D);
}
void ASTStmtReader::VisitOMPForDirective(OMPForDirective *D) {
- VisitStmt(D);
- // Two fields (NumClauses and CollapsedNum) were read in ReadStmtFromStream.
- Idx += 2;
- VisitOMPExecutableDirective(D);
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPForSimdDirective(OMPForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
}
void ASTStmtReader::VisitOMPSectionsDirective(OMPSectionsDirective *D) {
@@ -1988,10 +2077,12 @@ void ASTStmtReader::VisitOMPCriticalDirective(OMPCriticalDirective *D) {
}
void ASTStmtReader::VisitOMPParallelForDirective(OMPParallelForDirective *D) {
- VisitStmt(D);
- // Two fields (NumClauses and CollapsedNum) were read in ReadStmtFromStream.
- Idx += 2;
- VisitOMPExecutableDirective(D);
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPParallelForSimdDirective(
+ OMPParallelForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
}
void ASTStmtReader::VisitOMPParallelSectionsDirective(
@@ -2031,6 +2122,35 @@ void ASTStmtReader::VisitOMPFlushDirective(OMPFlushDirective *D) {
VisitOMPExecutableDirective(D);
}
+void ASTStmtReader::VisitOMPOrderedDirective(OMPOrderedDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPAtomicDirective(OMPAtomicDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+ D->setX(Reader.ReadSubExpr());
+ D->setV(Reader.ReadSubExpr());
+ D->setExpr(Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitOMPTargetDirective(OMPTargetDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPTeamsDirective(OMPTeamsDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
//===----------------------------------------------------------------------===//
// ASTReader Implementation
//===----------------------------------------------------------------------===//
@@ -2529,6 +2649,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
+ case STMT_OMP_FOR_SIMD_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPForSimdDirective::CreateEmpty(Context, NumClauses, CollapsedNum,
+ Empty);
+ break;
+ }
+
case STMT_OMP_SECTIONS_DIRECTIVE:
S = OMPSectionsDirective::CreateEmpty(
Context, Record[ASTStmtReader::NumStmtFields], Empty);
@@ -2559,6 +2687,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
+ case STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPParallelForSimdDirective::CreateEmpty(Context, NumClauses,
+ CollapsedNum, Empty);
+ break;
+ }
+
case STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE:
S = OMPParallelSectionsDirective::CreateEmpty(
Context, Record[ASTStmtReader::NumStmtFields], Empty);
@@ -2586,6 +2722,25 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
Context, Record[ASTStmtReader::NumStmtFields], Empty);
break;
+ case STMT_OMP_ORDERED_DIRECTIVE:
+ S = OMPOrderedDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_ATOMIC_DIRECTIVE:
+ S = OMPAtomicDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_TARGET_DIRECTIVE:
+ S = OMPTargetDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_TEAMS_DIRECTIVE:
+ S = OMPTeamsDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
case EXPR_CXX_OPERATOR_CALL:
S = new (Context) CXXOperatorCallExpr(Context, Empty);
break;
@@ -2775,7 +2930,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
case EXPR_MATERIALIZE_TEMPORARY:
S = new (Context) MaterializeTemporaryExpr(Empty);
break;
-
+
+ case EXPR_CXX_FOLD:
+ S = new (Context) CXXFoldExpr(Empty);
+ break;
+
case EXPR_OPAQUE_VALUE:
S = new (Context) OpaqueValueExpr(Empty);
break;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 0f52a9fd0408..6c60d45503de 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -51,6 +51,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
#include <algorithm>
#include <cstdio>
#include <string.h>
@@ -83,6 +84,8 @@ namespace {
public:
/// \brief Type code that corresponds to the record generated.
TypeCode Code;
+ /// \brief Abbreviation to use for the record, if any.
+ unsigned AbbrevToUse;
ASTTypeWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record)
: Writer(Writer), Record(Record), Code(TYPE_EXT_QUAL) { }
@@ -190,6 +193,9 @@ void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
// FIXME: need to stabilize encoding of calling convention...
Record.push_back(C.getCC());
Record.push_back(C.getProducesResult());
+
+ if (C.getHasRegParm() || C.getRegParm() || C.getProducesResult())
+ AbbrevToUse = 0;
}
void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
@@ -216,14 +222,21 @@ static void addExceptionSpec(ASTWriter &Writer, const FunctionProtoType *T,
void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
VisitFunctionType(T);
- Record.push_back(T->getNumParams());
- for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
- Writer.AddTypeRef(T->getParamType(I), Record);
+
Record.push_back(T->isVariadic());
Record.push_back(T->hasTrailingReturn());
Record.push_back(T->getTypeQuals());
Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
addExceptionSpec(Writer, T, Record);
+
+ Record.push_back(T->getNumParams());
+ for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
+ Writer.AddTypeRef(T->getParamType(I), Record);
+
+ if (T->isVariadic() || T->hasTrailingReturn() || T->getTypeQuals() ||
+ T->getRefQualifier() || T->getExceptionSpecType() != EST_None)
+ AbbrevToUse = 0;
+
Code = TYPE_FUNCTION_PROTO;
}
@@ -649,6 +662,40 @@ void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
}
+void ASTWriter::WriteTypeAbbrevs() {
+ using namespace llvm;
+
+ BitCodeAbbrev *Abv;
+
+ // Abbreviation for TYPE_EXT_QUAL
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::TYPE_EXT_QUAL));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 3)); // Quals
+ TypeExtQualAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for TYPE_FUNCTION_PROTO
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::TYPE_FUNCTION_PROTO));
+ // FunctionType
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ReturnType
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // NoReturn
+ Abv->Add(BitCodeAbbrevOp(0)); // HasRegParm
+ Abv->Add(BitCodeAbbrevOp(0)); // RegParm
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // CC
+ Abv->Add(BitCodeAbbrevOp(0)); // ProducesResult
+ // FunctionProtoType
+ Abv->Add(BitCodeAbbrevOp(0)); // IsVariadic
+ Abv->Add(BitCodeAbbrevOp(0)); // HasTrailingReturn
+ Abv->Add(BitCodeAbbrevOp(0)); // TypeQuals
+ Abv->Add(BitCodeAbbrevOp(0)); // RefQualifier
+ Abv->Add(BitCodeAbbrevOp(EST_None)); // ExceptionSpec
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // NumParams
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Params
+ TypeFunctionProtoAbbrev = Stream.EmitAbbrev(Abv);
+}
+
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
@@ -684,6 +731,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
RECORD(STMT_STOP);
RECORD(STMT_NULL_PTR);
+ RECORD(STMT_REF_PTR);
RECORD(STMT_NULL);
RECORD(STMT_COMPOUND);
RECORD(STMT_CASE);
@@ -711,6 +759,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_STRING_LITERAL);
RECORD(EXPR_CHARACTER_LITERAL);
RECORD(EXPR_PAREN);
+ RECORD(EXPR_PAREN_LIST);
RECORD(EXPR_UNARY_OPERATOR);
RECORD(EXPR_SIZEOF_ALIGN_OF);
RECORD(EXPR_ARRAY_SUBSCRIPT);
@@ -752,8 +801,13 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(STMT_OBJC_AT_SYNCHRONIZED);
RECORD(STMT_OBJC_AT_THROW);
RECORD(EXPR_OBJC_BOOL_LITERAL);
+ RECORD(STMT_CXX_CATCH);
+ RECORD(STMT_CXX_TRY);
+ RECORD(STMT_CXX_FOR_RANGE);
RECORD(EXPR_CXX_OPERATOR_CALL);
+ RECORD(EXPR_CXX_MEMBER_CALL);
RECORD(EXPR_CXX_CONSTRUCT);
+ RECORD(EXPR_CXX_TEMPORARY_OBJECT);
RECORD(EXPR_CXX_STATIC_CAST);
RECORD(EXPR_CXX_DYNAMIC_CAST);
RECORD(EXPR_CXX_REINTERPRET_CAST);
@@ -765,11 +819,10 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_CXX_NULL_PTR_LITERAL);
RECORD(EXPR_CXX_TYPEID_EXPR);
RECORD(EXPR_CXX_TYPEID_TYPE);
- RECORD(EXPR_CXX_UUIDOF_EXPR);
- RECORD(EXPR_CXX_UUIDOF_TYPE);
RECORD(EXPR_CXX_THIS);
RECORD(EXPR_CXX_THROW);
RECORD(EXPR_CXX_DEFAULT_ARG);
+ RECORD(EXPR_CXX_DEFAULT_INIT);
RECORD(EXPR_CXX_BIND_TEMPORARY);
RECORD(EXPR_CXX_SCALAR_VALUE_INIT);
RECORD(EXPR_CXX_NEW);
@@ -781,12 +834,22 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_CXX_UNRESOLVED_CONSTRUCT);
RECORD(EXPR_CXX_UNRESOLVED_MEMBER);
RECORD(EXPR_CXX_UNRESOLVED_LOOKUP);
+ RECORD(EXPR_CXX_EXPRESSION_TRAIT);
RECORD(EXPR_CXX_NOEXCEPT);
RECORD(EXPR_OPAQUE_VALUE);
+ RECORD(EXPR_BINARY_CONDITIONAL_OPERATOR);
+ RECORD(EXPR_TYPE_TRAIT);
+ RECORD(EXPR_ARRAY_TYPE_TRAIT);
RECORD(EXPR_PACK_EXPANSION);
RECORD(EXPR_SIZEOF_PACK);
+ RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM);
RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK);
+ RECORD(EXPR_FUNCTION_PARM_PACK);
+ RECORD(EXPR_MATERIALIZE_TEMPORARY);
RECORD(EXPR_CUDA_KERNEL_CALL);
+ RECORD(EXPR_CXX_UUIDOF_EXPR);
+ RECORD(EXPR_CXX_UUIDOF_TYPE);
+ RECORD(EXPR_LAMBDA);
#undef RECORD
}
@@ -800,6 +863,7 @@ void ASTWriter::WriteBlockInfoBlock() {
// Control Block.
BLOCK(CONTROL_BLOCK);
RECORD(METADATA);
+ RECORD(SIGNATURE);
RECORD(MODULE_NAME);
RECORD(MODULE_MAP_FILE);
RECORD(IMPORTS);
@@ -895,15 +959,14 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(TYPE_VARIABLE_ARRAY);
RECORD(TYPE_VECTOR);
RECORD(TYPE_EXT_VECTOR);
- RECORD(TYPE_FUNCTION_PROTO);
RECORD(TYPE_FUNCTION_NO_PROTO);
+ RECORD(TYPE_FUNCTION_PROTO);
RECORD(TYPE_TYPEDEF);
RECORD(TYPE_TYPEOF_EXPR);
RECORD(TYPE_TYPEOF);
RECORD(TYPE_RECORD);
RECORD(TYPE_ENUM);
RECORD(TYPE_OBJC_INTERFACE);
- RECORD(TYPE_OBJC_OBJECT);
RECORD(TYPE_OBJC_OBJECT_POINTER);
RECORD(TYPE_DECLTYPE);
RECORD(TYPE_ELABORATED);
@@ -920,8 +983,13 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(TYPE_PACK_EXPANSION);
RECORD(TYPE_ATTRIBUTED);
RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK);
+ RECORD(TYPE_AUTO);
+ RECORD(TYPE_UNARY_TRANSFORM);
RECORD(TYPE_ATOMIC);
+ RECORD(TYPE_DECAYED);
+ RECORD(TYPE_ADJUSTED);
RECORD(DECL_TYPEDEF);
+ RECORD(DECL_TYPEALIAS);
RECORD(DECL_ENUM);
RECORD(DECL_RECORD);
RECORD(DECL_ENUM_CONSTANT);
@@ -990,42 +1058,76 @@ void ASTWriter::WriteBlockInfoBlock() {
Stream.ExitBlock();
}
+/// \brief Prepares a path for being written to an AST file by converting it
+/// to an absolute path and removing nested './'s.
+///
+/// \return \c true if the path was changed.
+bool cleanPathForOutput(FileManager &FileMgr, SmallVectorImpl<char> &Path) {
+ bool Changed = false;
+
+ if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
+ llvm::sys::fs::make_absolute(Path);
+ Changed = true;
+ }
+
+ return Changed | FileMgr.removeDotPaths(Path);
+}
+
/// \brief Adjusts the given filename to only write out the portion of the
/// filename that is not part of the system root directory.
///
/// \param Filename the file name to adjust.
///
-/// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and
-/// the returned filename will be adjusted by this system root.
+/// \param BaseDir When non-NULL, the PCH file is a relocatable AST file and
+/// the returned filename will be adjusted by this root directory.
///
/// \returns either the original filename (if it needs no adjustment) or the
/// adjusted filename (which points into the @p Filename parameter).
static const char *
-adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) {
+adjustFilenameForRelocatableAST(const char *Filename, StringRef BaseDir) {
assert(Filename && "No file name to adjust?");
- if (isysroot.empty())
+ if (BaseDir.empty())
return Filename;
// Verify that the filename and the system root have the same prefix.
unsigned Pos = 0;
- for (; Filename[Pos] && Pos < isysroot.size(); ++Pos)
- if (Filename[Pos] != isysroot[Pos])
+ for (; Filename[Pos] && Pos < BaseDir.size(); ++Pos)
+ if (Filename[Pos] != BaseDir[Pos])
return Filename; // Prefixes don't match.
// We hit the end of the filename before we hit the end of the system root.
if (!Filename[Pos])
return Filename;
- // If the file name has a '/' at the current position, skip over the '/'.
- // We distinguish sysroot-based includes from absolute includes by the
- // absence of '/' at the beginning of sysroot-based includes.
- if (Filename[Pos] == '/')
+ // If there's not a path separator at the end of the base directory nor
+ // immediately after it, then this isn't within the base directory.
+ if (!llvm::sys::path::is_separator(Filename[Pos])) {
+ if (!llvm::sys::path::is_separator(BaseDir.back()))
+ return Filename;
+ } else {
+ // If the file name has a '/' at the current position, skip over the '/'.
+ // We distinguish relative paths from absolute paths by the
+ // absence of '/' at the beginning of relative paths.
+ //
+ // FIXME: This is wrong. We distinguish them by asking if the path is
+ // absolute, which isn't the same thing. And there might be multiple '/'s
+ // in a row. Use a better mechanism to indicate whether we have emitted an
+ // absolute or relative path.
++Pos;
+ }
return Filename + Pos;
}
+static ASTFileSignature getSignature() {
+ while (1) {
+ if (ASTFileSignature S = llvm::sys::Process::GetRandomNumber())
+ return S;
+ // Rely on GetRandomNumber to eventually return non-zero...
+ }
+}
+
/// \brief Write the control block.
void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
StringRef isysroot,
@@ -1050,13 +1152,20 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Record.push_back(VERSION_MINOR);
Record.push_back(CLANG_VERSION_MAJOR);
Record.push_back(CLANG_VERSION_MINOR);
+ assert((!WritingModule || isysroot.empty()) &&
+ "writing module as a relocatable PCH?");
Record.push_back(!isysroot.empty());
Record.push_back(ASTHasCompilerErrors);
Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
getClangFullRepositoryVersion());
- // Module name
+ // Signature
+ Record.clear();
+ Record.push_back(getSignature());
+ Stream.EmitRecord(SIGNATURE, Record);
+
if (WritingModule) {
+ // Module name
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
@@ -1066,19 +1175,46 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name);
}
- // Module map file
- if (WritingModule) {
+ if (WritingModule && WritingModule->Directory) {
+ // Module directory.
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(MODULE_MAP_FILE));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename
+ Abbrev->Add(BitCodeAbbrevOp(MODULE_DIRECTORY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Directory
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
-
- assert(WritingModule->ModuleMap && "missing module map");
- SmallString<128> ModuleMap(WritingModule->ModuleMap->getName());
- llvm::sys::fs::make_absolute(ModuleMap);
RecordData Record;
- Record.push_back(MODULE_MAP_FILE);
- Stream.EmitRecordWithBlob(AbbrevCode, Record, ModuleMap.str());
+ Record.push_back(MODULE_DIRECTORY);
+
+ SmallString<128> BaseDir(WritingModule->Directory->getName());
+ cleanPathForOutput(Context.getSourceManager().getFileManager(), BaseDir);
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, BaseDir);
+
+ // Write out all other paths relative to the base directory if possible.
+ BaseDirectory.assign(BaseDir.begin(), BaseDir.end());
+ } else if (!isysroot.empty()) {
+ // Write out paths relative to the sysroot if possible.
+ BaseDirectory = isysroot;
+ }
+
+ // Module map file
+ if (WritingModule) {
+ Record.clear();
+
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+
+ // Primary module map file.
+ AddPath(Map.getModuleMapFileForUniquing(WritingModule)->getName(), Record);
+
+ // Additional module map files.
+ if (auto *AdditionalModMaps =
+ Map.getAdditionalModuleMapFiles(WritingModule)) {
+ Record.push_back(AdditionalModMaps->size());
+ for (const FileEntry *F : *AdditionalModMaps)
+ AddPath(F->getName(), Record);
+ } else {
+ Record.push_back(0);
+ }
+
+ Stream.EmitRecord(MODULE_MAP_FILE, Record);
}
// Imports
@@ -1096,9 +1232,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
AddSourceLocation((*M)->ImportLoc, Record);
Record.push_back((*M)->File->getSize());
Record.push_back((*M)->File->getModificationTime());
- const std::string &FileName = (*M)->FileName;
- Record.push_back(FileName.size());
- Record.append(FileName.begin(), FileName.end());
+ Record.push_back((*M)->Signature);
+ AddPath((*M)->FileName, Record);
}
Stream.EmitRecord(IMPORTS, Record);
}
@@ -1110,8 +1245,9 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Record.push_back(LangOpts.Name);
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
-#include "clang/Basic/LangOptions.def"
-#define SANITIZER(NAME, ID) Record.push_back(LangOpts.Sanitize.ID);
+#include "clang/Basic/LangOptions.def"
+#define SANITIZER(NAME, ID) \
+ Record.push_back(LangOpts.Sanitize.has(SanitizerKind::ID));
#include "clang/Basic/Sanitizers.def"
Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind());
@@ -1245,17 +1381,10 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
- SmallString<128> MainFilePath(MainFile->getName());
-
- llvm::sys::fs::make_absolute(MainFilePath);
-
- const char *MainFileNameStr = MainFilePath.c_str();
- MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
- isysroot);
Record.clear();
Record.push_back(ORIGINAL_FILE);
Record.push_back(SM.getMainFileID().getOpaqueValue());
- Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
+ EmitRecordWithPath(FileAbbrevCode, Record, MainFile->getName());
}
Record.clear();
@@ -1281,7 +1410,6 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
WriteInputFiles(Context.SourceMgr,
PP.getHeaderSearchInfo().getHeaderSearchOpts(),
- isysroot,
PP.getLangOpts().Modules);
Stream.ExitBlock();
}
@@ -1297,7 +1425,6 @@ namespace {
void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
HeaderSearchOptions &HSOpts,
- StringRef isysroot,
bool Modules) {
using namespace llvm;
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
@@ -1368,23 +1495,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
// Whether this file was overridden.
Record.push_back(Entry.BufferOverridden);
- // Turn the file name into an absolute path, if it isn't already.
- const char *Filename = Entry.File->getName();
- SmallString<128> FilePath(Filename);
-
- // Ask the file manager to fixup the relative path for us. This will
- // honor the working directory.
- SourceMgr.getFileManager().FixupRelativePath(FilePath);
-
- // FIXME: This call to make_absolute shouldn't be necessary, the
- // call to FixupRelativePath should always return an absolute path.
- llvm::sys::fs::make_absolute(FilePath);
- Filename = FilePath.c_str();
-
- Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
-
- Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename);
- }
+ EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
+ }
Stream.ExitBlock();
@@ -1494,6 +1606,9 @@ namespace {
// The hash is based only on size/time of the file, so that the reader can
// match even when symlinking or excess path elements ("foo/../", "../")
// change the form of the name. However, complete path is still the key.
+ //
+ // FIXME: Using the mtime here will cause problems for explicit module
+ // imports.
return llvm::hash_combine(key.FE->getSize(),
key.FE->getModificationTime());
}
@@ -1574,7 +1689,7 @@ namespace {
/// \brief Write the header search block for the list of files that
///
/// \param HS The header search structure to save.
-void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
+void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
SmallVector<const FileEntry *, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
@@ -1598,17 +1713,16 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
(HFI.isModuleHeader && !HFI.isCompilingModuleHeader))
continue;
- // Turn the file name into an absolute path, if it isn't already.
+ // Massage the file path into an appropriate form.
const char *Filename = File->getName();
- Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
-
- // If we performed any translation on the file name at all, we need to
- // save this string, since the generator will refer to it later.
- if (Filename != File->getName()) {
- Filename = strdup(Filename);
+ SmallString<128> FilenameTmp(Filename);
+ if (PreparePathForOutput(FilenameTmp)) {
+ // If we performed any translation on the file name at all, we need to
+ // save this string, since the generator will refer to it later.
+ Filename = strdup(FilenameTmp.c_str());
SavedStrings.push_back(Filename);
}
-
+
HeaderFileInfoTrait::key_type key = { File, Filename };
Generator.insert(key, HFI, GeneratorTrait);
++NumHeaderSearchEntries;
@@ -1658,8 +1772,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
/// errors), we probably won't have to create file entries for any of
/// the files in the AST.
void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
- const Preprocessor &PP,
- StringRef isysroot) {
+ const Preprocessor &PP) {
RecordData Record;
// Enter the source manager block.
@@ -1808,17 +1921,10 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
LineTableInfo &LineTable = SourceMgr.getLineTable();
Record.clear();
- // Emit the file names
+ // Emit the file names.
Record.push_back(LineTable.getNumFilenames());
- for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) {
- // Emit the file name
- const char *Filename = LineTable.getFilename(I);
- Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
- unsigned FilenameLen = Filename? strlen(Filename) : 0;
- Record.push_back(FilenameLen);
- if (FilenameLen)
- Record.insert(Record.end(), Filename, Filename + FilenameLen);
- }
+ for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I)
+ AddPath(LineTable.getFilename(I), Record);
// Emit the line entries
for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
@@ -1904,10 +2010,8 @@ static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule,
if (IsModule) {
// Re-export any imported directives.
- // FIXME: Also ensure we re-export imported #undef directives.
- if (auto *DMD = dyn_cast<DefMacroDirective>(MD))
- if (DMD->isImported())
- return false;
+ if (MD->isImported())
+ return false;
SourceLocation Loc = MD->getLocation();
if (Loc.isInvalid())
@@ -1986,16 +2090,24 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
AddSourceLocation(MD->getLocation(), Record);
Record.push_back(MD->getKind());
- if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ if (auto *DefMD = dyn_cast<DefMacroDirective>(MD)) {
MacroID InfoID = getMacroRef(DefMD->getInfo(), Name);
Record.push_back(InfoID);
- Record.push_back(DefMD->isImported());
+ Record.push_back(DefMD->getOwningModuleID());
Record.push_back(DefMD->isAmbiguous());
-
- } else if (VisibilityMacroDirective *
- VisMD = dyn_cast<VisibilityMacroDirective>(MD)) {
+ } else if (auto *UndefMD = dyn_cast<UndefMacroDirective>(MD)) {
+ Record.push_back(UndefMD->getOwningModuleID());
+ } else {
+ auto *VisMD = cast<VisibilityMacroDirective>(MD);
Record.push_back(VisMD->isPublic());
}
+
+ if (MD->isImported()) {
+ auto Overrides = MD->getOverriddenModules();
+ Record.push_back(Overrides.size());
+ for (auto Override : Overrides)
+ Record.push_back(Override);
+ }
}
if (Record.empty())
continue;
@@ -2271,7 +2383,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
}
// Enter the submodule description block.
- Stream.EnterSubblock(SUBMODULE_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
+ Stream.EnterSubblock(SUBMODULE_BLOCK_ID, /*bits for abbreviations*/5);
// Write the abbreviations needed for the submodules block.
using namespace llvm;
@@ -2322,11 +2434,21 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TEXTUAL_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned TextualHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_HEADER));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned PrivateHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_TEXTUAL_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned PrivateTextualHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
@@ -2398,35 +2520,34 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record,
UmbrellaDir->getName());
}
-
+
// Emit the headers.
- for (unsigned I = 0, N = Mod->NormalHeaders.size(); I != N; ++I) {
- Record.clear();
- Record.push_back(SUBMODULE_HEADER);
- Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
- Mod->NormalHeaders[I]->getName());
- }
- // Emit the excluded headers.
- for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) {
- Record.clear();
- Record.push_back(SUBMODULE_EXCLUDED_HEADER);
- Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record,
- Mod->ExcludedHeaders[I]->getName());
- }
- // Emit the private headers.
- for (unsigned I = 0, N = Mod->PrivateHeaders.size(); I != N; ++I) {
+ struct {
+ unsigned RecordKind;
+ unsigned Abbrev;
+ Module::HeaderKind HeaderKind;
+ } HeaderLists[] = {
+ {SUBMODULE_HEADER, HeaderAbbrev, Module::HK_Normal},
+ {SUBMODULE_TEXTUAL_HEADER, TextualHeaderAbbrev, Module::HK_Textual},
+ {SUBMODULE_PRIVATE_HEADER, PrivateHeaderAbbrev, Module::HK_Private},
+ {SUBMODULE_PRIVATE_TEXTUAL_HEADER, PrivateTextualHeaderAbbrev,
+ Module::HK_PrivateTextual},
+ {SUBMODULE_EXCLUDED_HEADER, ExcludedHeaderAbbrev, Module::HK_Excluded}
+ };
+ for (auto &HL : HeaderLists) {
Record.clear();
- Record.push_back(SUBMODULE_PRIVATE_HEADER);
- Stream.EmitRecordWithBlob(PrivateHeaderAbbrev, Record,
- Mod->PrivateHeaders[I]->getName());
+ Record.push_back(HL.RecordKind);
+ for (auto &H : Mod->Headers[HL.HeaderKind])
+ Stream.EmitRecordWithBlob(HL.Abbrev, Record, H.NameAsWritten);
}
- ArrayRef<const FileEntry *>
- TopHeaders = Mod->getTopHeaders(PP->getFileManager());
- for (unsigned I = 0, N = TopHeaders.size(); I != N; ++I) {
+
+ // Emit the top headers.
+ {
+ auto TopHeaders = Mod->getTopHeaders(PP->getFileManager());
Record.clear();
Record.push_back(SUBMODULE_TOPHEADER);
- Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record,
- TopHeaders[I]->getName());
+ for (auto *H : TopHeaders)
+ Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record, H->getName());
}
// Emit the imports.
@@ -2434,7 +2555,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Record.clear();
for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
unsigned ImportedID = getSubmoduleID(Mod->Imports[I]);
- assert(ImportedID && "Unknown submodule!");
+ assert(ImportedID && "Unknown submodule!");
Record.push_back(ImportedID);
}
Stream.EmitRecord(SUBMODULE_IMPORTS, Record);
@@ -2611,12 +2732,14 @@ void ASTWriter::WriteType(QualType T) {
// Emit the type's representation.
ASTTypeWriter W(*this, Record);
+ W.AbbrevToUse = 0;
if (T.hasLocalNonFastQualifiers()) {
Qualifiers Qs = T.getLocalQualifiers();
AddTypeRef(T.getLocalUnqualifiedType(), Record);
Record.push_back(Qs.getAsOpaqueValue());
W.Code = TYPE_EXT_QUAL;
+ W.AbbrevToUse = TypeExtQualAbbrev;
} else {
switch (T->getTypeClass()) {
// For all of the concrete, non-dependent types, call the
@@ -2629,7 +2752,7 @@ void ASTWriter::WriteType(QualType T) {
}
// Emit the serialized record.
- Stream.EmitRecord(W.Code, Record);
+ Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
// Flush any expressions that were written as part of this type.
FlushStmts();
@@ -2772,11 +2895,11 @@ public:
unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts
for (const ObjCMethodList *Method = &Methods.Instance; Method;
Method = Method->getNext())
- if (Method->Method)
+ if (Method->getMethod())
DataLen += 4;
for (const ObjCMethodList *Method = &Methods.Factory; Method;
Method = Method->getNext())
- if (Method->Method)
+ if (Method->getMethod())
DataLen += 4;
LE.write<uint16_t>(DataLen);
return std::make_pair(KeyLen, DataLen);
@@ -2806,32 +2929,39 @@ public:
unsigned NumInstanceMethods = 0;
for (const ObjCMethodList *Method = &Methods.Instance; Method;
Method = Method->getNext())
- if (Method->Method)
+ if (Method->getMethod())
++NumInstanceMethods;
unsigned NumFactoryMethods = 0;
for (const ObjCMethodList *Method = &Methods.Factory; Method;
Method = Method->getNext())
- if (Method->Method)
+ if (Method->getMethod())
++NumFactoryMethods;
unsigned InstanceBits = Methods.Instance.getBits();
assert(InstanceBits < 4);
- unsigned NumInstanceMethodsAndBits =
- (NumInstanceMethods << 2) | InstanceBits;
+ unsigned InstanceHasMoreThanOneDeclBit =
+ Methods.Instance.hasMoreThanOneDecl();
+ unsigned FullInstanceBits = (NumInstanceMethods << 3) |
+ (InstanceHasMoreThanOneDeclBit << 2) |
+ InstanceBits;
unsigned FactoryBits = Methods.Factory.getBits();
assert(FactoryBits < 4);
- unsigned NumFactoryMethodsAndBits = (NumFactoryMethods << 2) | FactoryBits;
- LE.write<uint16_t>(NumInstanceMethodsAndBits);
- LE.write<uint16_t>(NumFactoryMethodsAndBits);
+ unsigned FactoryHasMoreThanOneDeclBit =
+ Methods.Factory.hasMoreThanOneDecl();
+ unsigned FullFactoryBits = (NumFactoryMethods << 3) |
+ (FactoryHasMoreThanOneDeclBit << 2) |
+ FactoryBits;
+ LE.write<uint16_t>(FullInstanceBits);
+ LE.write<uint16_t>(FullFactoryBits);
for (const ObjCMethodList *Method = &Methods.Instance; Method;
Method = Method->getNext())
- if (Method->Method)
- LE.write<uint32_t>(Writer.getDeclID(Method->Method));
+ if (Method->getMethod())
+ LE.write<uint32_t>(Writer.getDeclID(Method->getMethod()));
for (const ObjCMethodList *Method = &Methods.Factory; Method;
Method = Method->getNext())
- if (Method->Method)
- LE.write<uint32_t>(Writer.getDeclID(Method->Method));
+ if (Method->getMethod())
+ LE.write<uint32_t>(Writer.getDeclID(Method->getMethod()));
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
@@ -2877,19 +3007,19 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
if (Chain && I->second < FirstSelectorID) {
// Selector already exists. Did it change?
bool changed = false;
- for (ObjCMethodList *M = &Data.Instance; !changed && M && M->Method;
- M = M->getNext()) {
- if (!M->Method->isFromASTFile())
+ for (ObjCMethodList *M = &Data.Instance;
+ !changed && M && M->getMethod(); M = M->getNext()) {
+ if (!M->getMethod()->isFromASTFile())
changed = true;
}
- for (ObjCMethodList *M = &Data.Factory; !changed && M && M->Method;
+ for (ObjCMethodList *M = &Data.Factory; !changed && M && M->getMethod();
M = M->getNext()) {
- if (!M->Method->isFromASTFile())
+ if (!M->getMethod()->isFromASTFile())
changed = true;
}
if (!changed)
continue;
- } else if (Data.Instance.Method || Data.Factory.Method) {
+ } else if (Data.Instance.getMethod() || Data.Factory.getMethod()) {
// A new method pool entry.
++NumTableEntries;
}
@@ -2995,115 +3125,140 @@ class ASTIdentifierTableTrait {
if (Macro || (Macro = PP.getMacroDirectiveHistory(II))) {
if (!IsModule)
return !shouldIgnoreMacro(Macro, IsModule, PP);
- SubmoduleID ModID;
- if (getFirstPublicSubmoduleMacro(Macro, ModID))
+
+ MacroState State;
+ if (getFirstPublicSubmoduleMacro(Macro, State))
return true;
}
return false;
}
- typedef llvm::SmallVectorImpl<SubmoduleID> OverriddenList;
+ enum class SubmoduleMacroState {
+ /// We've seen nothing about this macro.
+ None,
+ /// We've seen a public visibility directive.
+ Public,
+ /// We've either exported a macro for this module or found that the
+ /// module's definition of this macro is private.
+ Done
+ };
+ typedef llvm::DenseMap<SubmoduleID, SubmoduleMacroState> MacroState;
MacroDirective *
- getFirstPublicSubmoduleMacro(MacroDirective *MD, SubmoduleID &ModID) {
- ModID = 0;
- llvm::SmallVector<SubmoduleID, 1> Overridden;
- if (MacroDirective *NextMD = getPublicSubmoduleMacro(MD, ModID, Overridden))
- if (!shouldIgnoreMacro(NextMD, IsModule, PP))
- return NextMD;
+ getFirstPublicSubmoduleMacro(MacroDirective *MD, MacroState &State) {
+ if (MacroDirective *NextMD = getPublicSubmoduleMacro(MD, State))
+ return NextMD;
return nullptr;
}
MacroDirective *
- getNextPublicSubmoduleMacro(MacroDirective *MD, SubmoduleID &ModID,
- OverriddenList &Overridden) {
+ getNextPublicSubmoduleMacro(MacroDirective *MD, MacroState &State) {
if (MacroDirective *NextMD =
- getPublicSubmoduleMacro(MD->getPrevious(), ModID, Overridden))
- if (!shouldIgnoreMacro(NextMD, IsModule, PP))
- return NextMD;
+ getPublicSubmoduleMacro(MD->getPrevious(), State))
+ return NextMD;
return nullptr;
}
- /// \brief Traverses the macro directives history and returns the latest
- /// public macro definition or undefinition that is not in ModID.
+ /// \brief Traverses the macro directives history and returns the next
+ /// public macro definition or undefinition that has not been found so far.
+ ///
/// A macro that is defined in submodule A and undefined in submodule B
/// will still be considered as defined/exported from submodule A.
- /// ModID is updated to the module containing the returned directive.
- ///
- /// FIXME: This process breaks down if a module defines a macro, imports
- /// another submodule that changes the macro, then changes the
- /// macro again itself.
MacroDirective *getPublicSubmoduleMacro(MacroDirective *MD,
- SubmoduleID &ModID,
- OverriddenList &Overridden) {
- Overridden.clear();
+ MacroState &State) {
if (!MD)
return nullptr;
- SubmoduleID OrigModID = ModID;
Optional<bool> IsPublic;
for (; MD; MD = MD->getPrevious()) {
- SubmoduleID ThisModID = getSubmoduleID(MD);
- if (ThisModID == 0) {
- IsPublic = Optional<bool>();
-
- // If we have no directive location, this macro was installed when
- // finalizing the ASTReader.
- if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD))
- if (DefMD->getInfo()->getOwningModuleID())
- return MD;
- // Skip imports that only produce #undefs for now.
- // FIXME: We should still re-export them!
+ // Once we hit an ignored macro, we're done: the rest of the chain
+ // will all be ignored macros.
+ if (shouldIgnoreMacro(MD, IsModule, PP))
+ break;
+
+ // If this macro was imported, re-export it.
+ if (MD->isImported())
+ return MD;
+ SubmoduleID ModID = getSubmoduleID(MD);
+ auto &S = State[ModID];
+ assert(ModID && "found macro in no submodule");
+
+ if (S == SubmoduleMacroState::Done)
continue;
+
+ if (auto *VisMD = dyn_cast<VisibilityMacroDirective>(MD)) {
+ // The latest visibility directive for a name in a submodule affects all
+ // the directives that come before it.
+ if (S == SubmoduleMacroState::None)
+ S = VisMD->isPublic() ? SubmoduleMacroState::Public
+ : SubmoduleMacroState::Done;
+ } else {
+ S = SubmoduleMacroState::Done;
+ return MD;
}
- if (ThisModID != ModID) {
- ModID = ThisModID;
- IsPublic = Optional<bool>();
- }
+ }
+
+ return nullptr;
+ }
+
+ ArrayRef<SubmoduleID>
+ getOverriddenSubmodules(MacroDirective *MD,
+ SmallVectorImpl<SubmoduleID> &ScratchSpace) {
+ assert(!isa<VisibilityMacroDirective>(MD) &&
+ "only #define and #undef can override");
+ if (MD->isImported())
+ return MD->getOverriddenModules();
+
+ ScratchSpace.clear();
+ SubmoduleID ModID = getSubmoduleID(MD);
+ for (MD = MD->getPrevious(); MD; MD = MD->getPrevious()) {
+ if (shouldIgnoreMacro(MD, IsModule, PP))
+ break;
// If this is a definition from a submodule import, that submodule's
// definition is overridden by the definition or undefinition that we
// started with.
- // FIXME: This should only apply to macros defined in OrigModID.
- // We can't do that currently, because a #include of a different submodule
- // of the same module just leaks through macros instead of providing new
- // DefMacroDirectives for them.
- if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
- // Figure out which submodule the macro was originally defined within.
- SubmoduleID SourceID = DefMD->getInfo()->getOwningModuleID();
- if (!SourceID) {
- SourceLocation DefLoc = DefMD->getInfo()->getDefinitionLoc();
- if (DefLoc == MD->getLocation())
- SourceID = ThisModID;
- else
- SourceID = Writer.inferSubmoduleIDFromLocation(DefLoc);
+ if (MD->isImported()) {
+ if (auto *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ SubmoduleID DefModuleID = DefMD->getInfo()->getOwningModuleID();
+ assert(DefModuleID && "imported macro has no owning module");
+ ScratchSpace.push_back(DefModuleID);
+ } else if (auto *UndefMD = dyn_cast<UndefMacroDirective>(MD)) {
+ // If we override a #undef, we override anything that #undef overrides.
+ // We don't need to override it, since an active #undef doesn't affect
+ // the meaning of a macro.
+ auto Overrides = UndefMD->getOverriddenModules();
+ ScratchSpace.insert(ScratchSpace.end(),
+ Overrides.begin(), Overrides.end());
}
- if (OrigModID && SourceID != OrigModID)
- Overridden.push_back(SourceID);
}
- // We are looking for a definition in a different submodule than the one
- // that we started with. If a submodule has re-definitions of the same
- // macro, only the last definition will be used as the "exported" one.
- if (ModID == OrigModID)
- continue;
-
- // The latest visibility directive for a name in a submodule affects all
- // the directives that come before it.
- if (VisibilityMacroDirective *VisMD =
- dyn_cast<VisibilityMacroDirective>(MD)) {
- if (!IsPublic.hasValue())
- IsPublic = VisMD->isPublic();
- } else if (!IsPublic.hasValue() || IsPublic.getValue()) {
- // FIXME: If we find an imported macro, we should include its list of
- // overrides in our export.
- return MD;
+ // Stop once we leave the original macro's submodule.
+ //
+ // Either this submodule #included another submodule of the same
+ // module or it just happened to be built after the other module.
+ // In the former case, we override the submodule's macro.
+ //
+ // FIXME: In the latter case, we shouldn't do so, but we can't tell
+ // these cases apart.
+ //
+ // FIXME: We can leave this submodule and re-enter it if it #includes a
+ // header within a different submodule of the same module. In such cases
+ // the overrides list will be incomplete.
+ SubmoduleID DirectiveModuleID = getSubmoduleID(MD);
+ if (DirectiveModuleID != ModID) {
+ if (DirectiveModuleID && !MD->isImported())
+ ScratchSpace.push_back(DirectiveModuleID);
+ break;
}
}
- return nullptr;
+ std::sort(ScratchSpace.begin(), ScratchSpace.end());
+ ScratchSpace.erase(std::unique(ScratchSpace.begin(), ScratchSpace.end()),
+ ScratchSpace.end());
+ return ScratchSpace;
}
SubmoduleID getSubmoduleID(MacroDirective *MD) {
@@ -3139,27 +3294,23 @@ public:
if (hadMacroDefinition(II, Macro)) {
DataLen += 4; // MacroDirectives offset.
if (IsModule) {
- SubmoduleID ModID;
- llvm::SmallVector<SubmoduleID, 4> Overridden;
- for (MacroDirective *
- MD = getFirstPublicSubmoduleMacro(Macro, ModID);
- MD; MD = getNextPublicSubmoduleMacro(MD, ModID, Overridden)) {
- // Previous macro's overrides.
- if (!Overridden.empty())
- DataLen += 4 * (1 + Overridden.size());
+ MacroState State;
+ SmallVector<SubmoduleID, 16> Scratch;
+ for (MacroDirective *MD = getFirstPublicSubmoduleMacro(Macro, State);
+ MD; MD = getNextPublicSubmoduleMacro(MD, State)) {
DataLen += 4; // MacroInfo ID or ModuleID.
+ if (unsigned NumOverrides =
+ getOverriddenSubmodules(MD, Scratch).size())
+ DataLen += 4 * (1 + NumOverrides);
}
- // Previous macro's overrides.
- if (!Overridden.empty())
- DataLen += 4 * (1 + Overridden.size());
- DataLen += 4;
+ DataLen += 4; // 0 terminator.
}
}
for (IdentifierResolver::iterator D = IdResolver.begin(II),
DEnd = IdResolver.end();
D != DEnd; ++D)
- DataLen += sizeof(DeclID);
+ DataLen += 4;
}
using namespace llvm::support;
endian::Writer<little> LE(Out);
@@ -3186,8 +3337,10 @@ public:
using namespace llvm::support;
endian::Writer<little> LE(Out);
LE.write<uint32_t>(Overridden.size() | 0x80000000U);
- for (unsigned I = 0, N = Overridden.size(); I != N; ++I)
+ for (unsigned I = 0, N = Overridden.size(); I != N; ++I) {
+ assert(Overridden[I] && "zero module ID for override");
LE.write<uint32_t>(Overridden[I]);
+ }
}
}
@@ -3219,24 +3372,28 @@ public:
LE.write<uint32_t>(Writer.getMacroDirectivesOffset(II));
if (IsModule) {
// Write the IDs of macros coming from different submodules.
- SubmoduleID ModID;
- llvm::SmallVector<SubmoduleID, 4> Overridden;
- for (MacroDirective *
- MD = getFirstPublicSubmoduleMacro(Macro, ModID);
- MD; MD = getNextPublicSubmoduleMacro(MD, ModID, Overridden)) {
- MacroID InfoID = 0;
- emitMacroOverrides(Out, Overridden);
+ MacroState State;
+ SmallVector<SubmoduleID, 16> Scratch;
+ for (MacroDirective *MD = getFirstPublicSubmoduleMacro(Macro, State);
+ MD; MD = getNextPublicSubmoduleMacro(MD, State)) {
if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
- InfoID = Writer.getMacroID(DefMD->getInfo());
+ // FIXME: If this macro directive was created by #pragma pop_macros,
+ // or if it was created implicitly by resolving conflicting macros,
+ // it may be for a different submodule from the one in the MacroInfo
+ // object. If so, we should write out its owning ModuleID.
+ MacroID InfoID = Writer.getMacroID(DefMD->getInfo());
assert(InfoID);
LE.write<uint32_t>(InfoID << 1);
} else {
- assert(isa<UndefMacroDirective>(MD));
- LE.write<uint32_t>((ModID << 1) | 1);
+ auto *UndefMD = cast<UndefMacroDirective>(MD);
+ SubmoduleID Mod = UndefMD->isImported()
+ ? UndefMD->getOwningModuleID()
+ : getSubmoduleID(UndefMD);
+ LE.write<uint32_t>((Mod << 1) | 1);
}
+ emitMacroOverrides(Out, getOverriddenSubmodules(MD, Scratch));
}
- emitMacroOverrides(Out, Overridden);
- LE.write<uint32_t>(0);
+ LE.write<uint32_t>(0xdeadbeef);
}
}
@@ -3367,6 +3524,31 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
// DeclContext's Name Lookup Table Serialization
//===----------------------------------------------------------------------===//
+/// Determine the declaration that should be put into the name lookup table to
+/// represent the given declaration in this module. This is usually D itself,
+/// but if D was imported and merged into a local declaration, we want the most
+/// recent local declaration instead. The chosen declaration will be the most
+/// recent declaration in any module that imports this one.
+static NamedDecl *getDeclForLocalLookup(NamedDecl *D) {
+ if (!D->isFromASTFile())
+ return D;
+
+ if (Decl *Redecl = D->getPreviousDecl()) {
+ // For Redeclarable decls, a prior declaration might be local.
+ for (; Redecl; Redecl = Redecl->getPreviousDecl())
+ if (!Redecl->isFromASTFile())
+ return cast<NamedDecl>(Redecl);
+ } else if (Decl *First = D->getCanonicalDecl()) {
+ // For Mergeable decls, the first decl might be local.
+ if (!First->isFromASTFile())
+ return cast<NamedDecl>(First);
+ }
+
+ // All declarations are imported. Our most recent declaration will also be
+ // the most recent one in anyone who imports us.
+ return D;
+}
+
namespace {
// Trait used for the on-disk hash table used in the method pool.
class ASTDeclContextNameLookupTrait {
@@ -3484,7 +3666,7 @@ public:
LE.write<uint16_t>(Lookup.size());
for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end();
I != E; ++I)
- LE.write<uint32_t>(Writer.GetDeclRef(*I));
+ LE.write<uint32_t>(Writer.GetDeclRef(getDeclForLocalLookup(*I)));
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
@@ -3524,13 +3706,13 @@ static void visitLocalLookupResults(const DeclContext *ConstDC,
}
void ASTWriter::AddUpdatedDeclContext(const DeclContext *DC) {
- if (UpdatedDeclContexts.insert(DC) && WritingAST) {
+ if (UpdatedDeclContexts.insert(DC).second && WritingAST) {
// Ensure we emit all the visible declarations.
visitLocalLookupResults(DC, DC->NeedToReconcileExternalVisibleStorage,
[&](DeclarationName Name,
DeclContext::lookup_const_result Result) {
for (auto *Decl : Result)
- GetDeclRef(Decl);
+ GetDeclRef(getDeclForLocalLookup(Decl));
});
}
}
@@ -3646,8 +3828,6 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
Record.push_back(BucketOffset);
Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record,
LookupTable.str());
-
- Stream.EmitRecord(DECL_CONTEXT_VISIBLE, Record);
++NumVisibleDeclContexts;
return Offset;
}
@@ -3729,6 +3909,8 @@ void ASTWriter::WriteRedeclarations() {
FirstFromAST = Prev;
}
+ // FIXME: Do we need to do this for the first declaration from each
+ // redeclaration chain that was merged into this one?
Chain->MergedDecls[FirstFromAST].push_back(getDeclID(First));
}
@@ -3914,6 +4096,37 @@ void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) {
Record.insert(Record.end(), Str.begin(), Str.end());
}
+bool ASTWriter::PreparePathForOutput(SmallVectorImpl<char> &Path) {
+ assert(Context && "should have context when outputting path");
+
+ bool Changed =
+ cleanPathForOutput(Context->getSourceManager().getFileManager(), Path);
+
+ // Remove a prefix to make the path relative, if relevant.
+ const char *PathBegin = Path.data();
+ const char *PathPtr =
+ adjustFilenameForRelocatableAST(PathBegin, BaseDirectory);
+ if (PathPtr != PathBegin) {
+ Path.erase(Path.begin(), Path.begin() + (PathPtr - PathBegin));
+ Changed = true;
+ }
+
+ return Changed;
+}
+
+void ASTWriter::AddPath(StringRef Path, RecordDataImpl &Record) {
+ SmallString<128> FilePath(Path);
+ PreparePathForOutput(FilePath);
+ AddString(FilePath, Record);
+}
+
+void ASTWriter::EmitRecordWithPath(unsigned Abbrev, RecordDataImpl &Record,
+ StringRef Path) {
+ SmallString<128> FilePath(Path);
+ PreparePathForOutput(FilePath);
+ Stream.EmitRecordWithBlob(Abbrev, Record, FilePath);
+}
+
void ASTWriter::AddVersionTuple(const VersionTuple &Version,
RecordDataImpl &Record) {
Record.push_back(Version.getMajor());
@@ -3950,29 +4163,26 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
}
ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
- : Stream(Stream), Context(nullptr), PP(nullptr), Chain(nullptr),
- WritingModule(nullptr), WritingAST(false), DoneWritingDeclsAndTypes(false),
- ASTHasCompilerErrors(false),
- FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
- FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
- FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
- FirstMacroID(NUM_PREDEF_MACRO_IDS), NextMacroID(FirstMacroID),
- FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS),
- NextSubmoduleID(FirstSubmoduleID),
- FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),
- CollectedStmts(&StmtsToEmit),
- NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
- NumVisibleDeclContexts(0),
- 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)
-{
-}
+ : Stream(Stream), Context(nullptr), PP(nullptr), Chain(nullptr),
+ WritingModule(nullptr), WritingAST(false),
+ DoneWritingDeclsAndTypes(false), ASTHasCompilerErrors(false),
+ FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
+ FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
+ FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
+ FirstMacroID(NUM_PREDEF_MACRO_IDS), NextMacroID(FirstMacroID),
+ FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS),
+ NextSubmoduleID(FirstSubmoduleID),
+ FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),
+ CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0),
+ NumLexicalDeclContexts(0), NumVisibleDeclContexts(0),
+ NextCXXBaseSpecifiersID(1), TypeExtQualAbbrev(0),
+ TypeFunctionProtoAbbrev(0), DeclParmVarAbbrev(0),
+ DeclContextLexicalAbbrev(0), DeclContextVisibleLookupAbbrev(0),
+ UpdateVisibleAbbrev(0), DeclRecordAbbrev(0), DeclTypedefAbbrev(0),
+ DeclVarAbbrev(0), DeclFieldAbbrev(0), DeclEnumAbbrev(0),
+ DeclObjCIvarAbbrev(0), DeclCXXMethodAbbrev(0), DeclRefExprAbbrev(0),
+ CharacterLiteralAbbrev(0), IntegerLiteralAbbrev(0),
+ ExprImplicitCastAbbrev(0) {}
ASTWriter::~ASTWriter() {
llvm::DeleteContainerSeconds(FileDeclIDs);
@@ -4001,6 +4211,7 @@ void ASTWriter::WriteAST(Sema &SemaRef,
Context = nullptr;
PP = nullptr;
this->WritingModule = nullptr;
+ this->BaseDirectory.clear();
WritingAST = false;
}
@@ -4150,6 +4361,11 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
}
+ // Build a record containing all of the UnusedLocalTypedefNameCandidates.
+ RecordData UnusedLocalTypedefNameCandidates;
+ for (const TypedefNameDecl *TD : SemaRef.UnusedLocalTypedefNameCandidates)
+ AddDeclRef(TD, UnusedLocalTypedefNameCandidates);
+
// Build a record containing all of dynamic classes declarations.
RecordData DynamicClasses;
AddLazyVectorDecls(*this, SemaRef.DynamicClasses, DynamicClasses);
@@ -4316,22 +4532,36 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
SmallString<2048> Buffer;
{
llvm::raw_svector_ostream Out(Buffer);
- for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(),
- MEnd = Chain->ModuleMgr.end();
- M != MEnd; ++M) {
+ for (ModuleFile *M : Chain->ModuleMgr) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
- StringRef FileName = (*M)->FileName;
+ StringRef FileName = M->FileName;
LE.write<uint16_t>(FileName.size());
Out.write(FileName.data(), FileName.size());
- LE.write<uint32_t>((*M)->SLocEntryBaseOffset);
- LE.write<uint32_t>((*M)->BaseIdentifierID);
- LE.write<uint32_t>((*M)->BaseMacroID);
- LE.write<uint32_t>((*M)->BasePreprocessedEntityID);
- LE.write<uint32_t>((*M)->BaseSubmoduleID);
- LE.write<uint32_t>((*M)->BaseSelectorID);
- LE.write<uint32_t>((*M)->BaseDeclID);
- LE.write<uint32_t>((*M)->BaseTypeIndex);
+
+ // Note: if a base ID was uint max, it would not be possible to load
+ // another module after it or have more than one entity inside it.
+ uint32_t None = std::numeric_limits<uint32_t>::max();
+
+ auto writeBaseIDOrNone = [&](uint32_t BaseID, bool ShouldWrite) {
+ assert(BaseID < std::numeric_limits<uint32_t>::max() && "base id too high");
+ if (ShouldWrite)
+ LE.write<uint32_t>(BaseID);
+ else
+ LE.write<uint32_t>(None);
+ };
+
+ // These values should be unique within a chain, since they will be read
+ // as keys into ContinuousRangeMaps.
+ writeBaseIDOrNone(M->SLocEntryBaseOffset, M->LocalNumSLocEntries);
+ writeBaseIDOrNone(M->BaseIdentifierID, M->LocalNumIdentifiers);
+ writeBaseIDOrNone(M->BaseMacroID, M->LocalNumMacros);
+ writeBaseIDOrNone(M->BasePreprocessedEntityID,
+ M->NumPreprocessedEntities);
+ writeBaseIDOrNone(M->BaseSubmoduleID, M->LocalNumSubmodules);
+ writeBaseIDOrNone(M->BaseSelectorID, M->LocalNumSelectors);
+ writeBaseIDOrNone(M->BaseDeclID, M->LocalNumDecls);
+ writeBaseIDOrNone(M->BaseTypeIndex, M->LocalNumTypes);
}
}
Record.clear();
@@ -4344,8 +4574,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Keep writing types, declarations, and declaration update records
// until we've emitted all of them.
- Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
- WriteDeclsBlockAbbrevs();
+ Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5);
+ WriteTypeAbbrevs();
+ WriteDeclAbbrevs();
for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(),
E = DeclsToRewrite.end();
I != E; ++I)
@@ -4371,11 +4602,11 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord);
WriteCXXBaseSpecifiersOffsets();
WriteFileDeclIDsMap();
- WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
+ WriteSourceManagerBlock(Context.getSourceManager(), PP);
WriteComments();
WritePreprocessor(PP, isModule);
- WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
+ WriteHeaderSearch(PP.getHeaderSearchInfo());
WriteSelectors(SemaRef);
WriteReferencedSelectorsPool(SemaRef);
WriteIdentifierTable(PP, SemaRef.IdResolver, isModule);
@@ -4423,6 +4654,11 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
if (!DynamicClasses.empty())
Stream.EmitRecord(DYNAMIC_CLASSES, DynamicClasses);
+ // Write the record containing potentially unused local typedefs.
+ if (!UnusedLocalTypedefNameCandidates.empty())
+ Stream.EmitRecord(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES,
+ UnusedLocalTypedefNameCandidates);
+
// Write the record containing pending implicit instantiations.
if (!PendingInstantiations.empty())
Stream.EmitRecord(PENDING_IMPLICIT_INSTANTIATIONS, PendingInstantiations);
@@ -4469,10 +4705,13 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
auto Cmp = [](const ModuleInfo &A, const ModuleInfo &B) {
return A.ID < B.ID;
};
+ auto Eq = [](const ModuleInfo &A, const ModuleInfo &B) {
+ return A.ID == B.ID;
+ };
// Sort and deduplicate module IDs.
std::sort(Imports.begin(), Imports.end(), Cmp);
- Imports.erase(std::unique(Imports.begin(), Imports.end(), Cmp),
+ Imports.erase(std::unique(Imports.begin(), Imports.end(), Eq),
Imports.end());
RecordData ImportedModules;
@@ -4532,17 +4771,17 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
Record.push_back(GetDeclRef(Update.getDecl()));
break;
- case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
- AddSourceLocation(Update.getLoc(), Record);
- break;
-
- case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION:
+ case UPD_CXX_ADDED_FUNCTION_DEFINITION:
// An updated body is emitted last, so that the reader doesn't need
// to skip over the lazy body to reach statements for other records.
Record.pop_back();
HasUpdatedBody = true;
break;
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
+ AddSourceLocation(Update.getLoc(), Record);
+ break;
+
case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
auto *RD = cast<CXXRecordDecl>(D);
AddUpdatedDeclContext(RD->getPrimaryContext());
@@ -4582,8 +4821,8 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
// Instantiation may change attributes; write them all out afresh.
Record.push_back(D->hasAttrs());
if (Record.back())
- WriteAttributes(ArrayRef<const Attr*>(D->getAttrs().begin(),
- D->getAttrs().size()), Record);
+ WriteAttributes(llvm::makeArrayRef(D->getAttrs().begin(),
+ D->getAttrs().size()), Record);
// FIXME: Ensure we don't get here for explicit instantiations.
break;
@@ -4607,15 +4846,21 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
case UPD_STATIC_LOCAL_NUMBER:
Record.push_back(Update.getNumber());
break;
+ case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
+ AddSourceRange(D->getAttr<OMPThreadPrivateDeclAttr>()->getRange(),
+ Record);
+ break;
}
}
if (HasUpdatedBody) {
const FunctionDecl *Def = cast<FunctionDecl>(D);
- Record.push_back(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION);
+ Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION);
Record.push_back(Def->isInlined());
AddSourceLocation(Def->getInnerLocStart(), Record);
AddFunctionDefinition(Def, Record);
+ if (auto *DD = dyn_cast<CXXDestructorDecl>(Def))
+ Record.push_back(GetDeclRef(DD->getOperatorDelete()));
}
OffsetsRecord.push_back(GetDeclRef(D));
@@ -4981,6 +5226,30 @@ void ASTWriter::AddDeclarationName(DeclarationName Name, RecordDataImpl &Record)
}
}
+unsigned ASTWriter::getAnonymousDeclarationNumber(const NamedDecl *D) {
+ assert(needsAnonymousDeclarationNumber(D) &&
+ "expected an anonymous declaration");
+
+ // Number the anonymous declarations within this context, if we've not
+ // already done so.
+ auto It = AnonymousDeclarationNumbers.find(D);
+ if (It == AnonymousDeclarationNumbers.end()) {
+ unsigned Index = 0;
+ for (Decl *LexicalD : D->getLexicalDeclContext()->decls()) {
+ auto *ND = dyn_cast<NamedDecl>(LexicalD);
+ if (!ND || !needsAnonymousDeclarationNumber(ND))
+ continue;
+ AnonymousDeclarationNumbers[ND] = Index++;
+ }
+
+ It = AnonymousDeclarationNumbers.find(D);
+ assert(It != AnonymousDeclarationNumbers.end() &&
+ "declaration not found within its lexical context");
+ }
+
+ return It->second;
+}
+
void ASTWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc,
DeclarationName Name, RecordDataImpl &Record) {
switch (Name.getNameKind()) {
@@ -5068,6 +5337,10 @@ void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
case NestedNameSpecifier::Global:
// Don't need to write an associated value.
break;
+
+ case NestedNameSpecifier::Super:
+ AddDeclRef(NNS->getAsRecordDecl(), Record);
+ break;
}
}
}
@@ -5117,6 +5390,11 @@ void ASTWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
case NestedNameSpecifier::Global:
AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record);
break;
+
+ case NestedNameSpecifier::Super:
+ AddDeclRef(NNS.getNestedNameSpecifier()->getAsRecordDecl(), Record);
+ AddSourceRange(NNS.getLocalSourceRange(), Record);
+ break;
}
}
}
@@ -5186,7 +5464,7 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
break;
case TemplateArgument::Declaration:
AddDeclRef(Arg.getAsDecl(), Record);
- Record.push_back(Arg.isDeclForReferenceParam());
+ AddTypeRef(Arg.getParamTypeForDecl(), Record);
break;
case TemplateArgument::NullPtr:
AddTypeRef(Arg.getNullPtrType(), Record);
@@ -5418,6 +5696,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Capture.getCaptureKind());
switch (Capture.getCaptureKind()) {
case LCK_This:
+ case LCK_VLAType:
break;
case LCK_ByCopy:
case LCK_ByRef:
@@ -5521,8 +5800,6 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
}
void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
- assert(!WritingAST && "Already writing the AST!");
-
// TU and namespaces are handled elsewhere.
if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC))
return;
@@ -5531,12 +5808,12 @@ void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
return; // Not a source decl added to a DeclContext from PCH.
assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!");
+ assert(!WritingAST && "Already writing the AST!");
AddUpdatedDeclContext(DC);
UpdatingVisibleDecls.push_back(D);
}
void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {
- assert(!WritingAST && "Already writing the AST!");
assert(D->isImplicit());
if (!(!D->isFromASTFile() && RD->isFromASTFile()))
return; // Not a source member added to a class from PCH.
@@ -5545,17 +5822,18 @@ void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {
// A decl coming from PCH was modified.
assert(RD->isCompleteDefinition());
+ assert(!WritingAST && "Already writing the AST!");
DeclUpdates[RD].push_back(DeclUpdate(UPD_CXX_ADDED_IMPLICIT_MEMBER, D));
}
void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
const ClassTemplateSpecializationDecl *D) {
// The specializations set is kept in the canonical template.
- assert(!WritingAST && "Already writing the AST!");
TD = TD->getCanonicalDecl();
if (!(!D->isFromASTFile() && TD->isFromASTFile()))
return; // Not a source specialization added to a template from PCH.
+ assert(!WritingAST && "Already writing the AST!");
DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
D));
}
@@ -5563,11 +5841,11 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
void ASTWriter::AddedCXXTemplateSpecialization(
const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) {
// The specializations set is kept in the canonical template.
- assert(!WritingAST && "Already writing the AST!");
TD = TD->getCanonicalDecl();
if (!(!D->isFromASTFile() && TD->isFromASTFile()))
return; // Not a source specialization added to a template from PCH.
+ assert(!WritingAST && "Already writing the AST!");
DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
D));
}
@@ -5575,11 +5853,11 @@ void ASTWriter::AddedCXXTemplateSpecialization(
void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) {
// The specializations set is kept in the canonical template.
- assert(!WritingAST && "Already writing the AST!");
TD = TD->getCanonicalDecl();
if (!(!D->isFromASTFile() && TD->isFromASTFile()))
return; // Not a source specialization added to a template from PCH.
+ assert(!WritingAST && "Already writing the AST!");
DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
D));
}
@@ -5607,9 +5885,8 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
if (!D->isFromASTFile())
return; // Declaration not imported from PCH.
- // Implicit decl from a PCH was defined.
- // FIXME: Should implicit definition be a separate FunctionDecl?
- RewriteDecl(D);
+ // Implicit function decl from a PCH was defined.
+ DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
}
void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) {
@@ -5617,10 +5894,8 @@ void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) {
if (!D->isFromASTFile())
return;
- // Since the actual instantiation is delayed, this really means that we need
- // to update the instantiation location.
DeclUpdates[D].push_back(
- DeclUpdate(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION));
+ DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
}
void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
@@ -5668,3 +5943,11 @@ void ASTWriter::DeclarationMarkedUsed(const Decl *D) {
DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_USED));
}
+
+void ASTWriter::DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return;
+
+ DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE));
+}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 47ce747d5bd3..4017ec63d4f2 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -167,8 +167,8 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Record.push_back(D->isInvalidDecl());
Record.push_back(D->hasAttrs());
if (D->hasAttrs())
- Writer.WriteAttributes(ArrayRef<const Attr*>(D->getAttrs().begin(),
- D->getAttrs().size()), Record);
+ Writer.WriteAttributes(llvm::makeArrayRef(D->getAttrs().begin(),
+ D->getAttrs().size()), Record);
Record.push_back(D->isImplicit());
Record.push_back(D->isUsed(false));
Record.push_back(D->isReferenced());
@@ -203,6 +203,8 @@ void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) {
VisitDecl(D);
Writer.AddDeclarationName(D->getDeclName(), Record);
+ if (needsAnonymousDeclarationNumber(D))
+ Record.push_back(Writer.getAnonymousDeclarationNumber(D));
}
void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) {
@@ -224,13 +226,11 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
VisitTypedefNameDecl(D);
if (!D->hasAttrs() &&
!D->isImplicit() &&
- !D->isUsed(false) &&
D->getFirstDecl() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
- !D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
- D->getAccess() == AS_none &&
!D->isModulePrivate() &&
+ !needsAnonymousDeclarationNumber(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclTypedefAbbrev();
@@ -239,6 +239,7 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) {
VisitTypedefNameDecl(D);
+ Writer.AddDeclRef(D->getDescribedAliasTemplate(), Record);
Code = serialization::DECL_TYPEALIAS;
}
@@ -247,18 +248,26 @@ void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
VisitTypeDecl(D);
Record.push_back(D->getIdentifierNamespace());
Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
- Record.push_back(D->isCompleteDefinition());
+ if (!isa<CXXRecordDecl>(D))
+ Record.push_back(D->isCompleteDefinition());
Record.push_back(D->isEmbeddedInDeclarator());
Record.push_back(D->isFreeStanding());
Record.push_back(D->isCompleteDefinitionRequired());
Writer.AddSourceLocation(D->getRBraceLoc(), Record);
- Record.push_back(D->hasExtInfo());
- if (D->hasExtInfo())
+
+ if (D->hasExtInfo()) {
+ Record.push_back(1);
Writer.AddQualifierInfo(*D->getExtInfo(), Record);
- else if (D->hasDeclaratorForAnonDecl())
- Writer.AddDeclRef(D->getDeclaratorForAnonDecl(), Record);
- else
- Writer.AddDeclRef(D->getTypedefNameForAnonDecl(), Record);
+ } else if (auto *TD = D->getTypedefNameForAnonDecl()) {
+ Record.push_back(2);
+ Writer.AddDeclRef(TD, Record);
+ Writer.AddIdentifierRef(TD->getDeclName().getAsIdentifierInfo(), Record);
+ } else if (auto *DD = D->getDeclaratorForAnonDecl()) {
+ Record.push_back(3);
+ Writer.AddDeclRef(DD, Record);
+ } else {
+ Record.push_back(0);
+ }
}
void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
@@ -284,6 +293,8 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
+ !D->getTypedefNameForAnonDecl() &&
+ !D->getDeclaratorForAnonDecl() &&
D->getFirstDecl() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
@@ -293,6 +304,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
!CXXRecordDecl::classofKind(D->getKind()) &&
!D->getIntegerTypeSourceInfo() &&
!D->getMemberSpecializationInfo() &&
+ !needsAnonymousDeclarationNumber(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclEnumAbbrev();
@@ -310,6 +322,8 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
+ !D->getTypedefNameForAnonDecl() &&
+ !D->getDeclaratorForAnonDecl() &&
D->getFirstDecl() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
@@ -317,6 +331,7 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
+ !needsAnonymousDeclarationNumber(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclRecordAbbrev();
@@ -349,7 +364,6 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
VisitRedeclarable(D);
VisitDeclaratorDecl(D);
-
Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
Record.push_back(D->getIdentifierNamespace());
@@ -663,12 +677,17 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
VisitDeclaratorDecl(D);
Record.push_back(D->isMutable());
- if (D->InitializerOrBitWidth.getInt() != ICIS_NoInit ||
- D->InitializerOrBitWidth.getPointer()) {
- Record.push_back(D->InitializerOrBitWidth.getInt() + 1);
- Writer.AddStmt(D->InitializerOrBitWidth.getPointer());
- } else {
+ if (D->InitStorage.getInt() == FieldDecl::ISK_BitWidthOrNothing &&
+ D->InitStorage.getPointer() == nullptr) {
Record.push_back(0);
+ } else if (D->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) {
+ Record.push_back(D->InitStorage.getInt() + 1);
+ Writer.AddTypeRef(
+ QualType(static_cast<Type *>(D->InitStorage.getPointer()), 0),
+ Record);
+ } else {
+ Record.push_back(D->InitStorage.getInt() + 1);
+ Writer.AddStmt(static_cast<Expr *>(D->InitStorage.getPointer()));
}
if (!D->getDeclName())
Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record);
@@ -753,6 +772,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
!D->isTopLevelDeclInObjCContainer() &&
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
+ !needsAnonymousDeclarationNumber(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
D->getFirstDecl() == D->getMostRecentDecl() &&
@@ -930,6 +950,7 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
}
void ASTDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ VisitRedeclarable(D);
VisitNamedDecl(D);
Writer.AddSourceLocation(D->getNamespaceLoc(), Record);
Writer.AddSourceLocation(D->getTargetNameLoc(), Record);
@@ -1027,6 +1048,17 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
// We only need to record overridden methods once for the canonical decl.
Record.push_back(0);
}
+
+ if (D->getFirstDecl() == D->getMostRecentDecl() &&
+ !D->isInvalidDecl() &&
+ !D->hasAttrs() &&
+ !D->isTopLevelDeclInObjCContainer() &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier &&
+ !D->hasExtInfo() &&
+ !D->hasInheritedPrototype() &&
+ D->hasWrittenPrototype())
+ AbbrevToUse = Writer.getDeclCXXMethodAbbrev();
+
Code = serialization::DECL_CXX_METHOD;
}
@@ -1449,7 +1481,7 @@ void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
-void ASTWriter::WriteDeclsBlockAbbrevs() {
+void ASTWriter::WriteDeclAbbrevs() {
using namespace llvm;
BitCodeAbbrev *Abv;
@@ -1552,8 +1584,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsCompleteDefinitionRequired
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
- Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // ExtInfoKind
// EnumDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddTypeRef
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IntegerType
@@ -1600,8 +1631,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsCompleteDefinitionRequired
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
- Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // ExtInfoKind
// RecordDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion
@@ -1676,10 +1706,10 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
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, 1)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isReferenced
Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
- Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
@@ -1738,6 +1768,63 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
DeclVarAbbrev = Stream.EmitAbbrev(Abv);
+ // Abbreviation for DECL_CXX_METHOD
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_CXX_METHOD));
+ // RedeclarableDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // CanonicalDecl
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // Invalid
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Implicit
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Used
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Referenced
+ Abv->Add(BitCodeAbbrevOp(0)); // InObjCContainer
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Access
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Identifier
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerLocStart
+ Abv->Add(BitCodeAbbrevOp(0)); // HasExtInfo
+ // FunctionDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 11)); // IDNS
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Inline
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InlineSpecified
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // VirtualAsWritten
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure
+ Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedProto
+ Abv->Add(BitCodeAbbrevOp(1)); // HasWrittenProto
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // DeletedAsWritten
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Trivial
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Defaulted
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitlyDefaulted
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ImplicitReturnZero
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Constexpr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // SkippedBody
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // LateParsed
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LocEnd
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // TemplateKind
+ // This Array slurps the rest of the record. Fortunately we want to encode
+ // (nearly) all the remaining (variable number of) fields in the same way.
+ //
+ // This is the function template information if any, then
+ // NumParams and Params[] from FunctionDecl, and
+ // NumOverriddenMethods, OverriddenMethods[] from CXXMethodDecl.
+ //
+ // Add an AbbrevOp for 'size then elements' and use it here.
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ DeclCXXMethodAbbrev = Stream.EmitAbbrev(Abv);
+
// Abbreviation for EXPR_DECL_REF
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_DECL_REF));
@@ -1755,7 +1842,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HadMultipleCandidates
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //RefersToEnclosingLocal
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+ 1)); // RefersToEnclosingVariableOrCapture
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
DeclRefExprAbbrev = Stream.EmitAbbrev(Abv);
@@ -1796,6 +1884,24 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getKind
CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv);
+ // Abbreviation for EXPR_IMPLICIT_CAST
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_IMPLICIT_CAST));
+ // Stmt
+ // Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ // CastExpr
+ Abv->Add(BitCodeAbbrevOp(0)); // PathSize
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 6)); // CastKind
+ // ImplicitCastExpr
+ ExprImplicitCastAbbrev = Stream.EmitAbbrev(Abv);
+
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_LEXICAL));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index a43b3527a711..e980ce783f5e 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -307,7 +307,7 @@ void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
// Captures
for (const auto &I : S->captures()) {
- if (I.capturesThis())
+ if (I.capturesThis() || I.capturesVariableArrayType())
Writer.AddDeclRef(nullptr, Record);
else
Writer.AddDeclRef(I.getCapturedVar(), Record);
@@ -333,6 +333,7 @@ void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) {
VisitExpr(E);
Writer.AddSourceLocation(E->getLocation(), Record);
Record.push_back(E->getIdentType()); // FIXME: stable encoding
+ Writer.AddStmt(E->getFunctionName());
Code = serialization::EXPR_PREDEFINED;
}
@@ -343,7 +344,7 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
Record.push_back(E->getDecl() != E->getFoundDecl());
Record.push_back(E->hasTemplateKWAndArgsInfo());
Record.push_back(E->hadMultipleCandidates());
- Record.push_back(E->refersToEnclosingLocal());
+ Record.push_back(E->refersToEnclosingVariableOrCapture());
if (E->hasTemplateKWAndArgsInfo()) {
unsigned NumTemplateArgs = E->getNumTemplateArgs();
@@ -635,6 +636,10 @@ ASTStmtWriter::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
void ASTStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
VisitCastExpr(E);
+
+ if (E->path_size() == 0)
+ AbbrevToUse = Writer.getExprImplicitCastAbbrev();
+
Code = serialization::EXPR_IMPLICIT_CAST;
}
@@ -1574,6 +1579,17 @@ void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
Code = serialization::EXPR_MATERIALIZE_TEMPORARY;
}
+void ASTStmtWriter::VisitCXXFoldExpr(CXXFoldExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->LParenLoc, Record);
+ Writer.AddSourceLocation(E->EllipsisLoc, Record);
+ Writer.AddSourceLocation(E->RParenLoc, Record);
+ Writer.AddStmt(E->SubExprs[0]);
+ Writer.AddStmt(E->SubExprs[1]);
+ Record.push_back(E->Opcode);
+ Code = serialization::EXPR_CXX_FOLD;
+}
+
void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
Writer.AddStmt(E->getSourceExpr());
@@ -1581,6 +1597,12 @@ void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
Code = serialization::EXPR_OPAQUE_VALUE;
}
+void ASTStmtWriter::VisitTypoExpr(TypoExpr *E) {
+ VisitExpr(E);
+ // TODO: Figure out sane writer behavior for a TypoExpr, if necessary
+ assert(false && "Cannot write TypoExpr nodes");
+}
+
//===----------------------------------------------------------------------===//
// CUDA Expressions and Statements.
//===----------------------------------------------------------------------===//
@@ -1735,18 +1757,39 @@ void OMPClauseWriter::VisitOMPUntiedClause(OMPUntiedClause *) {}
void OMPClauseWriter::VisitOMPMergeableClause(OMPMergeableClause *) {}
+void OMPClauseWriter::VisitOMPReadClause(OMPReadClause *) {}
+
+void OMPClauseWriter::VisitOMPWriteClause(OMPWriteClause *) {}
+
+void OMPClauseWriter::VisitOMPUpdateClause(OMPUpdateClause *) {}
+
+void OMPClauseWriter::VisitOMPCaptureClause(OMPCaptureClause *) {}
+
+void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
+
void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
- for (auto *VE : C->varlists())
+ for (auto *VE : C->varlists()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->private_copies()) {
Writer->Writer.AddStmt(VE);
+ }
}
void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
- for (auto *VE : C->varlists())
+ for (auto *VE : C->varlists()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->private_copies()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->inits()) {
Writer->Writer.AddStmt(VE);
+ }
}
void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
@@ -1826,29 +1869,61 @@ void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
Writer.AddStmt(E->getAssociatedStmt());
}
-void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) {
+void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) {
VisitStmt(D);
Record.push_back(D->getNumClauses());
+ Record.push_back(D->getCollapsedNumber());
VisitOMPExecutableDirective(D);
- Code = serialization::STMT_OMP_PARALLEL_DIRECTIVE;
+ Writer.AddStmt(D->getIterationVariable());
+ Writer.AddStmt(D->getLastIteration());
+ Writer.AddStmt(D->getCalcLastIteration());
+ Writer.AddStmt(D->getPreCond());
+ Writer.AddStmt(D->getCond(/* SeparateIter */ false));
+ Writer.AddStmt(D->getCond(/* SeparateIter */ true));
+ Writer.AddStmt(D->getInit());
+ Writer.AddStmt(D->getInc());
+ if (isOpenMPWorksharingDirective(D->getDirectiveKind())) {
+ Writer.AddStmt(D->getIsLastIterVariable());
+ Writer.AddStmt(D->getLowerBoundVariable());
+ Writer.AddStmt(D->getUpperBoundVariable());
+ Writer.AddStmt(D->getStrideVariable());
+ Writer.AddStmt(D->getEnsureUpperBound());
+ Writer.AddStmt(D->getNextLowerBound());
+ Writer.AddStmt(D->getNextUpperBound());
+ }
+ for (auto I : D->counters()) {
+ Writer.AddStmt(I);
+ }
+ for (auto I : D->updates()) {
+ Writer.AddStmt(I);
+ }
+ for (auto I : D->finals()) {
+ Writer.AddStmt(I);
+ }
}
-void ASTStmtWriter::VisitOMPSimdDirective(OMPSimdDirective *D) {
+void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) {
VisitStmt(D);
Record.push_back(D->getNumClauses());
- Record.push_back(D->getCollapsedNumber());
VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPSimdDirective(OMPSimdDirective *D) {
+ VisitOMPLoopDirective(D);
Code = serialization::STMT_OMP_SIMD_DIRECTIVE;
}
void ASTStmtWriter::VisitOMPForDirective(OMPForDirective *D) {
- VisitStmt(D);
- Record.push_back(D->getNumClauses());
- Record.push_back(D->getCollapsedNumber());
- VisitOMPExecutableDirective(D);
+ VisitOMPLoopDirective(D);
Code = serialization::STMT_OMP_FOR_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPForSimdDirective(OMPForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_FOR_SIMD_DIRECTIVE;
+}
+
void ASTStmtWriter::VisitOMPSectionsDirective(OMPSectionsDirective *D) {
VisitStmt(D);
Record.push_back(D->getNumClauses());
@@ -1883,13 +1958,16 @@ void ASTStmtWriter::VisitOMPCriticalDirective(OMPCriticalDirective *D) {
}
void ASTStmtWriter::VisitOMPParallelForDirective(OMPParallelForDirective *D) {
- VisitStmt(D);
- Record.push_back(D->getNumClauses());
- Record.push_back(D->getCollapsedNumber());
- VisitOMPExecutableDirective(D);
+ VisitOMPLoopDirective(D);
Code = serialization::STMT_OMP_PARALLEL_FOR_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPParallelForSimdDirective(
+ OMPParallelForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE;
+}
+
void ASTStmtWriter::VisitOMPParallelSectionsDirective(
OMPParallelSectionsDirective *D) {
VisitStmt(D);
@@ -1905,6 +1983,23 @@ void ASTStmtWriter::VisitOMPTaskDirective(OMPTaskDirective *D) {
Code = serialization::STMT_OMP_TASK_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPAtomicDirective(OMPAtomicDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Writer.AddStmt(D->getX());
+ Writer.AddStmt(D->getV());
+ Writer.AddStmt(D->getExpr());
+ Code = serialization::STMT_OMP_ATOMIC_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTargetDirective(OMPTargetDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TARGET_DIRECTIVE;
+}
+
void ASTStmtWriter::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *D) {
VisitStmt(D);
VisitOMPExecutableDirective(D);
@@ -1930,6 +2025,19 @@ void ASTStmtWriter::VisitOMPFlushDirective(OMPFlushDirective *D) {
Code = serialization::STMT_OMP_FLUSH_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPOrderedDirective(OMPOrderedDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_ORDERED_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTeamsDirective(OMPTeamsDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TEAMS_DIRECTIVE;
+}
+
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp
index 985812232505..479138804547 100644
--- a/lib/Serialization/GlobalModuleIndex.cpp
+++ b/lib/Serialization/GlobalModuleIndex.cpp
@@ -122,11 +122,10 @@ typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait>
}
-GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
+GlobalModuleIndex::GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer,
llvm::BitstreamCursor Cursor)
- : Buffer(Buffer), IdentifierIndex(),
- NumIdentifierLookups(), NumIdentifierLookupHits()
-{
+ : Buffer(std::move(Buffer)), IdentifierIndex(), NumIdentifierLookups(),
+ NumIdentifierLookupHits() {
// Read the global index.
bool InGlobalIndexBlock = false;
bool Done = false;
@@ -260,7 +259,7 @@ GlobalModuleIndex::readIndex(StringRef Path) {
return std::make_pair(nullptr, EC_IOError);
}
- return std::make_pair(new GlobalModuleIndex(Buffer.release(), Cursor),
+ return std::make_pair(new GlobalModuleIndex(std::move(Buffer), Cursor),
EC_None);
}
@@ -494,19 +493,17 @@ namespace {
bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
// Open the module file.
- std::unique_ptr<llvm::MemoryBuffer> Buffer;
- std::string ErrorStr;
- Buffer.reset(FileMgr.getBufferForFile(File, &ErrorStr, /*isVolatile=*/true));
+
+ auto Buffer = FileMgr.getBufferForFile(File, /*isVolatile=*/true);
if (!Buffer) {
return true;
}
// Initialize the input stream
llvm::BitstreamReader InStreamFile;
- llvm::BitstreamCursor InStream;
- InStreamFile.init((const unsigned char *)Buffer->getBufferStart(),
- (const unsigned char *)Buffer->getBufferEnd());
- InStream.init(InStreamFile);
+ InStreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(),
+ (const unsigned char *)(*Buffer)->getBufferEnd());
+ llvm::BitstreamCursor InStream(InStreamFile);
// Sniff for the signature.
if (InStream.Read(8) != 'C' ||
@@ -591,6 +588,10 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
off_t StoredSize = (off_t)Record[Idx++];
time_t StoredModTime = (time_t)Record[Idx++];
+ // Skip the stored signature.
+ // FIXME: we could read the signature out of the import and validate it.
+ Idx++;
+
// Retrieve the imported file name.
unsigned Length = Record[Idx++];
SmallString<128> ImportedFile(Record.begin() + Idx,
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index 6f2a3c220430..6c48a41187c2 100644
--- a/lib/Serialization/Module.cpp
+++ b/lib/Serialization/Module.cpp
@@ -21,7 +21,7 @@ using namespace serialization;
using namespace reader;
ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
- : Kind(Kind), File(nullptr), DirectlyImported(false),
+ : Kind(Kind), File(nullptr), Signature(0), DirectlyImported(false),
Generation(Generation), SizeInBits(0),
LocalNumSLocEntries(0), SLocEntryBaseID(0),
SLocEntryBaseOffset(0), SLocEntryOffsets(nullptr),
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index 2c10c119a07b..ac98ca0b8720 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -45,10 +45,11 @@ ModuleFile *ModuleManager::lookup(const FileEntry *File) {
return Known->second;
}
-llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
+std::unique_ptr<llvm::MemoryBuffer>
+ModuleManager::lookupBuffer(StringRef Name) {
const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
/*cacheFailure=*/false);
- return InMemoryBuffers[Entry];
+ return std::move(InMemoryBuffers[Entry]);
}
ModuleManager::AddModuleResult
@@ -56,6 +57,9 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
SourceLocation ImportLoc, ModuleFile *ImportedBy,
unsigned Generation,
off_t ExpectedSize, time_t ExpectedModTime,
+ ASTFileSignature ExpectedSignature,
+ std::function<ASTFileSignature(llvm::BitstreamReader &)>
+ ReadSignature,
ModuleFile *&Module,
std::string &ErrorStr) {
Module = nullptr;
@@ -63,6 +67,13 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
// Look for the file entry. This only fails if the expected size or
// modification time differ.
const FileEntry *Entry;
+ if (Type == MK_ExplicitModule) {
+ // If we're not expecting to pull this file out of the module cache, it
+ // might have a different mtime due to being moved across filesystems in
+ // a distributed build. The size must still match, though. (As must the
+ // contents, but we can't check that.)
+ ExpectedModTime = 0;
+ }
if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) {
ErrorStr = "module file out of date";
return OutOfDate;
@@ -88,7 +99,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
ModuleEntry = New;
New->InputFilesValidationTimestamp = 0;
- if (New->Kind == MK_Module) {
+ if (New->Kind == MK_ImplicitModule) {
std::string TimestampFilename = New->getTimestampFilename();
vfs::Status Status;
// A cached stat value would be fine as well.
@@ -98,39 +109,59 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
}
// Load the contents of the module
- if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
+ if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
// The buffer was already provided for us.
- assert(Buffer && "Passed null buffer");
- New->Buffer.reset(Buffer);
+ New->Buffer = std::move(Buffer);
} else {
// Open the AST file.
- std::error_code ec;
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf(
+ (std::error_code()));
if (FileName == "-") {
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf =
- llvm::MemoryBuffer::getSTDIN();
- ec = Buf.getError();
- if (ec)
- ErrorStr = ec.message();
- else
- New->Buffer = std::move(Buf.get());
+ Buf = llvm::MemoryBuffer::getSTDIN();
} else {
// Leave the FileEntry open so if it gets read again by another
// ModuleManager it must be the same underlying file.
// FIXME: Because FileManager::getFile() doesn't guarantee that it will
// give us an open file, this may not be 100% reliable.
- New->Buffer.reset(FileMgr.getBufferForFile(New->File, &ErrorStr,
- /*IsVolatile*/false,
- /*ShouldClose*/false));
+ Buf = FileMgr.getBufferForFile(New->File,
+ /*IsVolatile=*/false,
+ /*ShouldClose=*/false);
}
-
- if (!New->Buffer)
+
+ if (!Buf) {
+ ErrorStr = Buf.getError().message();
return Missing;
+ }
+
+ New->Buffer = std::move(*Buf);
}
// Initialize the stream
New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
(const unsigned char *)New->Buffer->getBufferEnd());
}
+
+ if (ExpectedSignature) {
+ if (NewModule)
+ ModuleEntry->Signature = ReadSignature(ModuleEntry->StreamFile);
+ else
+ assert(ModuleEntry->Signature == ReadSignature(ModuleEntry->StreamFile));
+
+ if (ModuleEntry->Signature != ExpectedSignature) {
+ ErrorStr = ModuleEntry->Signature ? "signature mismatch"
+ : "could not read module signature";
+
+ if (NewModule) {
+ // Remove the module file immediately, since removeModules might try to
+ // invalidate the file cache for Entry, and that is not safe if this
+ // module is *itself* up to date, but has an out-of-date importer.
+ Modules.erase(Entry);
+ Chain.pop_back();
+ delete ModuleEntry;
+ }
+ return OutOfDate;
+ }
+ }
if (ImportedBy) {
ModuleEntry->ImportedBy.insert(ImportedBy);
@@ -187,12 +218,13 @@ void ModuleManager::removeModules(
Chain.erase(first, last);
}
-void ModuleManager::addInMemoryBuffer(StringRef FileName,
- llvm::MemoryBuffer *Buffer) {
-
- const FileEntry *Entry = FileMgr.getVirtualFile(FileName,
- Buffer->getBufferSize(), 0);
- InMemoryBuffers[Entry] = Buffer;
+void
+ModuleManager::addInMemoryBuffer(StringRef FileName,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+
+ const FileEntry *Entry =
+ FileMgr.getVirtualFile(FileName, Buffer->getBufferSize(), 0);
+ InMemoryBuffers[Entry] = std::move(Buffer);
}
ModuleManager::VisitState *ModuleManager::allocateVisitState() {
@@ -249,7 +281,7 @@ ModuleManager::~ModuleManager() {
void
ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
void *UserData,
- llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit) {
+ llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
// If the visitation order vector is the wrong size, recompute the order.
if (VisitOrder.size() != Chain.size()) {
unsigned N = size();
diff --git a/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h b/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h
index 2b314a3b749a..048418ef62db 100644
--- a/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h
+++ b/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SA_LIB_CHECKERS_ALLOC_DIAGS_H
-#define LLVM_CLANG_SA_LIB_CHECKERS_ALLOC_DIAGS_H
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ALLOCATIONDIAGNOSTICS_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ALLOCATIONDIAGNOSTICS_H
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 20360efccfe4..e462e2b2f15e 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -218,17 +218,6 @@ void RegionRawOffsetV2::dumpToStream(raw_ostream &os) const {
os << "raw_offset_v2{" << getRegion() << ',' << getByteOffset() << '}';
}
-// FIXME: Merge with the implementation of the same method in Store.cpp
-static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *D = RT->getDecl();
- if (!D->getDefinition())
- return false;
- }
-
- return true;
-}
-
// Lazily computes a value to be used by 'computeOffset'. If 'val'
// is unknown or undefined, we lazily substitute '0'. Otherwise,
@@ -288,7 +277,7 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
QualType elemType = elemReg->getElementType();
// If the element is an incomplete type, go no further.
ASTContext &astContext = svalBuilder.getContext();
- if (!IsCompleteType(astContext, elemType))
+ if (elemType->isIncompleteType())
return RegionRawOffsetV2();
// Update the offset.
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index a87104984883..104a81eac4c7 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -42,8 +42,10 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
return false;
case Builtin::BI__builtin_expect:
+ case Builtin::BI__builtin_assume_aligned:
case Builtin::BI__builtin_addressof: {
- // For __builtin_expect, just return the value of the subexpression.
+ // For __builtin_expect and __builtin_assume_aligned, just return the value
+ // of the subexpression.
// __builtin_addressof is going from a reference to a pointer, but those
// are represented the same way in the analyzer.
assert (CE->arg_begin() != CE->arg_end());
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 0693bd6fd94d..e91a7e16802e 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -969,8 +969,13 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// Get the length to copy.
if (Optional<NonLoc> lenValNonLoc = sizeVal.getAs<NonLoc>()) {
// Get the byte after the last byte copied.
+ SValBuilder &SvalBuilder = C.getSValBuilder();
+ ASTContext &Ctx = SvalBuilder.getContext();
+ QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
+ loc::MemRegionVal DestRegCharVal = SvalBuilder.evalCast(destRegVal,
+ CharPtrTy, Dest->getType()).castAs<loc::MemRegionVal>();
SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
- destRegVal,
+ DestRegCharVal,
*lenValNonLoc,
Dest->getType());
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index d186144b9ddd..339af8f03324 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -28,27 +28,6 @@
using namespace clang;
using namespace ento;
-static bool scan_dealloc(Stmt *S, Selector Dealloc) {
-
- if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getSelector() == Dealloc) {
- switch (ME->getReceiverKind()) {
- case ObjCMessageExpr::Instance: return false;
- case ObjCMessageExpr::SuperInstance: return true;
- case ObjCMessageExpr::Class: break;
- case ObjCMessageExpr::SuperClass: break;
- }
- }
-
- // Recurse to children.
-
- for (Stmt::child_iterator I = S->child_begin(), E= S->child_end(); I!=E; ++I)
- if (*I && scan_dealloc(*I, Dealloc))
- return true;
-
- return false;
-}
-
static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
const ObjCPropertyDecl *PD,
Selector Release,
@@ -181,24 +160,6 @@ static void checkObjCDealloc(const CheckerBase *Checker,
return;
}
- // dealloc found. Scan for missing [super dealloc].
- if (MD->getBody() && !scan_dealloc(MD->getBody(), S)) {
-
- const char* name = LOpts.getGC() == LangOptions::NonGC
- ? "missing [super dealloc]"
- : "missing [super dealloc] (Hybrid MM, non-GC)";
-
- std::string buf;
- llvm::raw_string_ostream os(buf);
- os << "The 'dealloc' instance method in Objective-C class '" << *D
- << "' does not send a 'dealloc' message to its super class"
- " (missing [super dealloc])";
-
- BR.EmitBasicReport(MD, Checker, name, categories::CoreFoundationObjectiveC,
- os.str(), DLoc);
- return;
- }
-
// Get the "release" selector.
IdentifierInfo* RII = &Ctx.Idents.get("release");
Selector RS = Ctx.Selectors.getSelector(0, &RII);
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 44eb64187bfb..ba5b4fa3c66c 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -184,6 +184,10 @@ def NewDeleteChecker : Checker<"NewDelete">,
HelpText<"Check for double-free and use-after-free problems. Traces memory managed by new/delete.">,
DescFile<"MallocChecker.cpp">;
+def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">,
+ HelpText<"Check for memory leaks. Traces memory managed by new/delete.">,
+ DescFile<"MallocChecker.cpp">;
+
} // end: "cplusplus"
let ParentPackage = CplusplusAlpha in {
@@ -192,10 +196,6 @@ def VirtualCallChecker : Checker<"VirtualCall">,
HelpText<"Check virtual function calls during construction or destruction">,
DescFile<"VirtualCallChecker.cpp">;
-def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">,
- HelpText<"Check for memory leaks. Traces memory managed by new/delete.">,
- DescFile<"MallocChecker.cpp">;
-
} // end: "alpha.cplusplus"
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
index de2ebce52c02..05b4a61c5af1 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SA_LIB_CHECKERS_CLANGSACHECKERS_H
-#define LLVM_CLANG_SA_LIB_CHECKERS_CLANGSACHECKERS_H
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_CLANGSACHECKERS_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_CLANGSACHECKERS_H
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
diff --git a/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
index d5c52b4c6a31..58d0783f3974 100644
--- a/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
@@ -445,7 +445,12 @@ static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
case Stmt::IntegerLiteralClass: {
const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1);
const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2);
- return IntLit1->getValue() == IntLit2->getValue();
+
+ llvm::APInt I1 = IntLit1->getValue();
+ llvm::APInt I2 = IntLit2->getValue();
+ if (I1.getBitWidth() != I2.getBitWidth())
+ return false;
+ return I1 == I2;
}
case Stmt::FloatingLiteralClass: {
const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1);
@@ -455,7 +460,7 @@ static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
case Stmt::StringLiteralClass: {
const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
- return StringLit1->getString() == StringLit2->getString();
+ return StringLit1->getBytes() == StringLit2->getBytes();
}
case Stmt::MemberExprClass: {
const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
diff --git a/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h b/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
index e35557f24bbc..b7549fd17da9 100644
--- a/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
+++ b/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
@@ -10,8 +10,8 @@
// inter-checker communications.
//===----------------------------------------------------------------------===//
-#ifndef INTERCHECKERAPI_H_
-#define INTERCHECKERAPI_H_
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_INTERCHECKERAPI_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_INTERCHECKERAPI_H
namespace clang {
namespace ento {
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 0f227bba0000..13ea4d3ed090 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -270,7 +270,7 @@ void MacOSKeychainAPIChecker::
os << "Deallocator doesn't match the allocator: '"
<< FunctionsToTrack[PDeallocIdx].Name << "' should be used.";
BugReport *Report = new BugReport(*BT, os.str(), N);
- Report->addVisitor(new SecKeychainBugVisitor(AP.first));
+ Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first));
Report->addRange(ArgExpr->getSourceRange());
markInteresting(Report, AP);
C.emitReport(Report);
@@ -311,7 +311,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
<< FunctionsToTrack[DIdx].Name
<< "'.";
BugReport *Report = new BugReport(*BT, os.str(), N);
- Report->addVisitor(new SecKeychainBugVisitor(V));
+ Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(V));
Report->addRange(ArgExpr->getSourceRange());
Report->markInteresting(AS->Region);
C.emitReport(Report);
@@ -430,7 +430,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
initBugType();
BugReport *Report = new BugReport(*BT,
"Only call free if a valid (non-NULL) buffer was returned.", N);
- Report->addVisitor(new SecKeychainBugVisitor(ArgSM));
+ Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(ArgSM));
Report->addRange(ArgExpr->getSourceRange());
Report->markInteresting(AS->Region);
C.emitReport(Report);
@@ -540,7 +540,7 @@ BugReport *MacOSKeychainAPIChecker::
BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing,
AllocNode->getLocationContext()->getDecl());
- Report->addVisitor(new SecKeychainBugVisitor(AP.first));
+ Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first));
markInteresting(Report, AP);
return Report;
}
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index a03fa259005a..aee5a43048b9 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -15,6 +15,7 @@
#include "ClangSACheckers.h"
#include "InterCheckerAPI.h"
#include "clang/AST/Attr.h"
+#include "clang/AST/ParentMap.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -41,7 +42,8 @@ enum AllocationFamily {
AF_None,
AF_Malloc,
AF_CXXNew,
- AF_CXXNewArray
+ AF_CXXNewArray,
+ AF_IfNameIndex
};
class RefState {
@@ -160,7 +162,8 @@ public:
MallocChecker()
: II_malloc(nullptr), II_free(nullptr), II_realloc(nullptr),
II_calloc(nullptr), II_valloc(nullptr), II_reallocf(nullptr),
- II_strndup(nullptr), II_strdup(nullptr), II_kmalloc(nullptr) {}
+ II_strndup(nullptr), II_strdup(nullptr), II_kmalloc(nullptr),
+ II_if_nameindex(nullptr), II_if_freenameindex(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
@@ -173,6 +176,12 @@ public:
CK_NumCheckKinds
};
+ enum class MemoryOperationKind {
+ MOK_Allocate,
+ MOK_Free,
+ MOK_Any
+ };
+
DefaultBool ChecksEnabled[CK_NumCheckKinds];
CheckName CheckNames[CK_NumCheckKinds];
@@ -211,7 +220,7 @@ private:
mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
*II_valloc, *II_reallocf, *II_strndup, *II_strdup,
- *II_kmalloc;
+ *II_kmalloc, *II_if_nameindex, *II_if_freenameindex;
mutable Optional<uint64_t> KernelZeroFlagVal;
void initIdentifierInfo(ASTContext &C) const;
@@ -237,8 +246,10 @@ private:
/// Check if this is one of the functions which can allocate/reallocate memory
/// pointed to by one of its arguments.
bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
- bool isFreeFunction(const FunctionDecl *FD, ASTContext &C) const;
- bool isAllocationFunction(const FunctionDecl *FD, ASTContext &C) const;
+ bool isCMemFunction(const FunctionDecl *FD,
+ ASTContext &C,
+ AllocationFamily Family,
+ MemoryOperationKind MemKind) const;
bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
///@}
ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
@@ -419,9 +430,9 @@ private:
BugReporterContext &BRC,
BugReport &BR) override;
- PathDiagnosticPiece* getEndPath(BugReporterContext &BRC,
- const ExplodedNode *EndPathNode,
- BugReport &BR) override {
+ std::unique_ptr<PathDiagnosticPiece>
+ getEndPath(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
+ BugReport &BR) override {
if (!IsLeak)
return nullptr;
@@ -429,7 +440,8 @@ private:
PathDiagnosticLocation::createEndOfPath(EndPathNode,
BRC.getSourceManager());
// Do not add the statement itself as a range in case of leak.
- return new PathDiagnosticEventPiece(L, BR.getDescription(), false);
+ return llvm::make_unique<PathDiagnosticEventPiece>(L, BR.getDescription(),
+ false);
}
private:
@@ -494,13 +506,15 @@ void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
II_strdup = &Ctx.Idents.get("strdup");
II_strndup = &Ctx.Idents.get("strndup");
II_kmalloc = &Ctx.Idents.get("kmalloc");
+ II_if_nameindex = &Ctx.Idents.get("if_nameindex");
+ II_if_freenameindex = &Ctx.Idents.get("if_freenameindex");
}
bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
- if (isFreeFunction(FD, C))
+ if (isCMemFunction(FD, C, AF_Malloc, MemoryOperationKind::MOK_Any))
return true;
- if (isAllocationFunction(FD, C))
+ if (isCMemFunction(FD, C, AF_IfNameIndex, MemoryOperationKind::MOK_Any))
return true;
if (isStandardNewDelete(FD, C))
@@ -509,45 +523,61 @@ bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
return false;
}
-bool MallocChecker::isAllocationFunction(const FunctionDecl *FD,
- ASTContext &C) const {
+bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
+ ASTContext &C,
+ AllocationFamily Family,
+ MemoryOperationKind MemKind) const {
if (!FD)
return false;
+ bool CheckFree = (MemKind == MemoryOperationKind::MOK_Any ||
+ MemKind == MemoryOperationKind::MOK_Free);
+ bool CheckAlloc = (MemKind == MemoryOperationKind::MOK_Any ||
+ MemKind == MemoryOperationKind::MOK_Allocate);
+
if (FD->getKind() == Decl::Function) {
- IdentifierInfo *FunI = FD->getIdentifier();
+ const IdentifierInfo *FunI = FD->getIdentifier();
initIdentifierInfo(C);
- if (FunI == II_malloc || FunI == II_realloc ||
- FunI == II_reallocf || FunI == II_calloc || FunI == II_valloc ||
- FunI == II_strdup || FunI == II_strndup || FunI == II_kmalloc)
- return true;
- }
+ if (Family == AF_Malloc && CheckFree) {
+ if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf)
+ return true;
+ }
- if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs())
- for (const auto *I : FD->specific_attrs<OwnershipAttr>())
- if (I->getOwnKind() == OwnershipAttr::Returns)
+ if (Family == AF_Malloc && CheckAlloc) {
+ if (FunI == II_malloc || FunI == II_realloc || FunI == II_reallocf ||
+ FunI == II_calloc || FunI == II_valloc || FunI == II_strdup ||
+ FunI == II_strndup || FunI == II_kmalloc)
return true;
- return false;
-}
+ }
-bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const {
- if (!FD)
- return false;
+ if (Family == AF_IfNameIndex && CheckFree) {
+ if (FunI == II_if_freenameindex)
+ return true;
+ }
- if (FD->getKind() == Decl::Function) {
- IdentifierInfo *FunI = FD->getIdentifier();
- initIdentifierInfo(C);
+ if (Family == AF_IfNameIndex && CheckAlloc) {
+ if (FunI == II_if_nameindex)
+ return true;
+ }
+ }
- if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf)
- return true;
+ if (Family != AF_Malloc)
+ return false;
+
+ if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs()) {
+ for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
+ OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
+ if(OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds) {
+ if (CheckFree)
+ return true;
+ } else if (OwnKind == OwnershipAttr::Returns) {
+ if (CheckAlloc)
+ return true;
+ }
+ }
}
- if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs())
- for (const auto *I : FD->specific_attrs<OwnershipAttr>())
- if (I->getOwnKind() == OwnershipAttr::Takes ||
- I->getOwnKind() == OwnershipAttr::Holds)
- return true;
return false;
}
@@ -730,6 +760,13 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
else
llvm_unreachable("not a new/delete operator");
+ } else if (FunI == II_if_nameindex) {
+ // Should we model this differently? We can allocate a fixed number of
+ // elements with zeros in the last one.
+ State = MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State,
+ AF_IfNameIndex);
+ } else if (FunI == II_if_freenameindex) {
+ State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
}
}
@@ -753,6 +790,42 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
C.addTransition(State);
}
+static QualType getDeepPointeeType(QualType T) {
+ QualType Result = T, PointeeType = T->getPointeeType();
+ while (!PointeeType.isNull()) {
+ Result = PointeeType;
+ PointeeType = PointeeType->getPointeeType();
+ }
+ return Result;
+}
+
+static bool treatUnusedNewEscaped(const CXXNewExpr *NE) {
+
+ const CXXConstructExpr *ConstructE = NE->getConstructExpr();
+ if (!ConstructE)
+ return false;
+
+ if (!NE->getAllocatedType()->getAsCXXRecordDecl())
+ return false;
+
+ const CXXConstructorDecl *CtorD = ConstructE->getConstructor();
+
+ // Iterate over the constructor parameters.
+ for (const auto *CtorParam : CtorD->params()) {
+
+ QualType CtorParamPointeeT = CtorParam->getType()->getPointeeType();
+ if (CtorParamPointeeT.isNull())
+ continue;
+
+ CtorParamPointeeT = getDeepPointeeType(CtorParamPointeeT);
+
+ if (CtorParamPointeeT->getAsCXXRecordDecl())
+ return true;
+ }
+
+ return false;
+}
+
void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
CheckerContext &C) const {
@@ -765,6 +838,10 @@ void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
if (!isStandardNewDelete(NE->getOperatorNew(), C.getASTContext()))
return;
+ ParentMap &PM = C.getLocationContext()->getParentMap();
+ if (!PM.isConsumedExpr(NE) && treatUnusedNewEscaped(NE))
+ return;
+
ProgramStateRef State = C.getState();
// The return value from operator new is bound to a specified initialization
// value (if any) and we don't want to loose this value. So we call
@@ -859,6 +936,10 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
ProgramStateRef State,
AllocationFamily Family) {
+ // We expect the malloc functions to return a pointer.
+ if (!Loc::isLocType(CE->getType()))
+ return nullptr;
+
// Bind the return value to the symbolic value from the heap region.
// TODO: We could rewrite post visit to eval call; 'malloc' does not have
// side effects other than what we model here.
@@ -869,10 +950,6 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
.castAs<DefinedSVal>();
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
- // We expect the malloc functions to return a pointer.
- if (!RetVal.getAs<Loc>())
- return nullptr;
-
// Fill the region with the initialization value.
State = State->bindDefault(RetVal, Init);
@@ -974,7 +1051,7 @@ AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
ASTContext &Ctx = C.getASTContext();
- if (isAllocationFunction(FD, Ctx) || isFreeFunction(FD, Ctx))
+ if (isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Any))
return AF_Malloc;
if (isStandardNewDelete(FD, Ctx)) {
@@ -985,6 +1062,9 @@ AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
return AF_CXXNewArray;
}
+ if (isCMemFunction(FD, Ctx, AF_IfNameIndex, MemoryOperationKind::MOK_Any))
+ return AF_IfNameIndex;
+
return AF_None;
}
@@ -1048,6 +1128,7 @@ void MallocChecker::printExpectedAllocName(raw_ostream &os, CheckerContext &C,
case AF_Malloc: os << "malloc()"; return;
case AF_CXXNew: os << "'new'"; return;
case AF_CXXNewArray: os << "'new[]'"; return;
+ case AF_IfNameIndex: os << "'if_nameindex()'"; return;
case AF_None: llvm_unreachable("not a deallocation expression");
}
}
@@ -1058,6 +1139,7 @@ void MallocChecker::printExpectedDeallocName(raw_ostream &os,
case AF_Malloc: os << "free()"; return;
case AF_CXXNew: os << "'delete'"; return;
case AF_CXXNewArray: os << "'delete[]'"; return;
+ case AF_IfNameIndex: os << "'if_freenameindex()'"; return;
case AF_None: llvm_unreachable("suspicious AF_None argument");
}
}
@@ -1201,7 +1283,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
Optional<MallocChecker::CheckKind>
MallocChecker::getCheckIfTracked(AllocationFamily Family) const {
switch (Family) {
- case AF_Malloc: {
+ case AF_Malloc:
+ case AF_IfNameIndex: {
if (ChecksEnabled[CK_MallocOptimistic]) {
return CK_MallocOptimistic;
} else if (ChecksEnabled[CK_MallocPessimistic]) {
@@ -1425,7 +1508,7 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
BugReport *R = new BugReport(*BT_MismatchedDealloc, os.str(), N);
R->markInteresting(Sym);
R->addRange(Range);
- R->addVisitor(new MallocBugVisitor(Sym));
+ R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
C.emitReport(R);
}
}
@@ -1509,7 +1592,7 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
R->markInteresting(Sym);
R->addRange(Range);
- R->addVisitor(new MallocBugVisitor(Sym));
+ R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
C.emitReport(R);
}
}
@@ -1541,7 +1624,7 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
R->markInteresting(Sym);
if (PrevSym)
R->markInteresting(PrevSym);
- R->addVisitor(new MallocBugVisitor(Sym));
+ R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
C.emitReport(R);
}
}
@@ -1565,7 +1648,7 @@ void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
"Attempt to delete released memory", N);
R->markInteresting(Sym);
- R->addVisitor(new MallocBugVisitor(Sym));
+ R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
C.emitReport(R);
}
}
@@ -1793,7 +1876,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
new BugReport(*BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
AllocNode->getLocationContext()->getDecl());
R->markInteresting(Sym);
- R->addVisitor(new MallocBugVisitor(Sym, true));
+ R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym, true));
C.emitReport(R);
}
@@ -1865,13 +1948,16 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
if (!FD)
return;
+ ASTContext &Ctx = C.getASTContext();
if ((ChecksEnabled[CK_MallocOptimistic] ||
ChecksEnabled[CK_MallocPessimistic]) &&
- isFreeFunction(FD, C.getASTContext()))
+ (isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Free) ||
+ isCMemFunction(FD, Ctx, AF_IfNameIndex,
+ MemoryOperationKind::MOK_Free)))
return;
if (ChecksEnabled[CK_NewDeleteChecker] &&
- isStandardNewDelete(FD, C.getASTContext()))
+ isStandardNewDelete(FD, Ctx))
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
index 4a50d9362874..296aec66805a 100644
--- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
@@ -137,6 +137,10 @@ public:
// Determine if the pointee and sizeof types are compatible. Here
// we ignore constness of pointer types.
static bool typesCompatible(ASTContext &C, QualType A, QualType B) {
+ // sizeof(void*) is compatible with any other pointer.
+ if (B->isVoidPointerType() && A->getAs<PointerType>())
+ return true;
+
while (true) {
A = A.getCanonicalType();
B = B.getCanonicalType();
diff --git a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index 61d2b87cb0c0..cb2d46b58310 100644
--- a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -49,14 +49,27 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
if (!FD)
return;
- const NonNullAttr *Att = FD->getAttr<NonNullAttr>();
+ // Merge all non-null attributes
+ unsigned NumArgs = Call.getNumArgs();
+ llvm::SmallBitVector AttrNonNull(NumArgs);
+ for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
+ if (!NonNull->args_size()) {
+ AttrNonNull.set(0, NumArgs);
+ break;
+ }
+ for (unsigned Val : NonNull->args()) {
+ if (Val >= NumArgs)
+ continue;
+ AttrNonNull.set(Val);
+ }
+ }
ProgramStateRef state = C.getState();
CallEvent::param_type_iterator TyI = Call.param_type_begin(),
TyE = Call.param_type_end();
- for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx){
+ for (unsigned idx = 0; idx < NumArgs; ++idx) {
// Check if the parameter is a reference. We want to report when reference
// to a null pointer is passed as a paramter.
@@ -66,7 +79,7 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
TyI++;
}
- bool haveAttrNonNull = Att && Att->isNonNull(idx);
+ bool haveAttrNonNull = AttrNonNull[idx];
if (!haveAttrNonNull) {
// Check if the parameter is also marked 'nonnull'.
ArrayRef<ParmVarDecl*> parms = Call.parameters();
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index eb699d694087..9a460ba50ddd 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -1359,6 +1359,7 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
// Check the method family, and apply any default annotations.
switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) {
case OMF_None:
+ case OMF_initialize:
case OMF_performSelector:
// Assume all Objective-C methods follow Cocoa Memory Management rules.
// FIXME: Does the non-threaded performSelector family really belong here?
@@ -1579,19 +1580,19 @@ void RetainSummaryManager::InitializeMethodSummaries() {
// Create summaries QCRenderer/QCView -createSnapShotImageOfType:
addInstMethSummary("QCRenderer", AllocSumm,
- "createSnapshotImageOfType", NULL);
+ "createSnapshotImageOfType", nullptr);
addInstMethSummary("QCView", AllocSumm,
- "createSnapshotImageOfType", NULL);
+ "createSnapshotImageOfType", nullptr);
// Create summaries for CIContext, 'createCGImage' and
// 'createCGLayerWithSize'. These objects are CF objects, and are not
// automatically garbage collected.
addInstMethSummary("CIContext", CFAllocSumm,
- "createCGImage", "fromRect", NULL);
- addInstMethSummary("CIContext", CFAllocSumm,
- "createCGImage", "fromRect", "format", "colorSpace", NULL);
- addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize",
- "info", NULL);
+ "createCGImage", "fromRect", nullptr);
+ addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect",
+ "format", "colorSpace", nullptr);
+ addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info",
+ nullptr);
}
//===----------------------------------------------------------------------===//
@@ -1716,9 +1717,9 @@ namespace {
BugReporterContext &BRC,
BugReport &BR) override;
- PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
- const ExplodedNode *N,
- BugReport &BR) override;
+ std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) override;
};
class CFRefLeakReportVisitor : public CFRefReportVisitor {
@@ -1727,17 +1728,17 @@ namespace {
const SummaryLogTy &log)
: CFRefReportVisitor(sym, GCEnabled, log) {}
- PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
- const ExplodedNode *N,
- BugReport &BR) override;
+ std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) override;
- BugReporterVisitor *clone() const override {
+ std::unique_ptr<BugReporterVisitor> clone() const override {
// The curiously-recurring template pattern only works for one level of
// subclassing. Rather than make a new template base for
// CFRefReportVisitor, we simply override clone() to do the right thing.
// This could be trouble someday if BugReporterVisitorImpl is ever
// used for something else besides a convenient implementation of clone().
- return new CFRefLeakReportVisitor(*this);
+ return llvm::make_unique<CFRefLeakReportVisitor>(*this);
}
};
@@ -1750,7 +1751,7 @@ namespace {
bool registerVisitor = true)
: BugReport(D, D.getDescription(), n) {
if (registerVisitor)
- addVisitor(new CFRefReportVisitor(sym, GCEnabled, Log));
+ addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, GCEnabled, Log));
addGCModeDescription(LOpts, GCEnabled);
}
@@ -1758,7 +1759,7 @@ namespace {
const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
StringRef endText)
: BugReport(D, D.getDescription(), endText, n) {
- addVisitor(new CFRefReportVisitor(sym, GCEnabled, Log));
+ addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, GCEnabled, Log));
addGCModeDescription(LOpts, GCEnabled);
}
@@ -2218,18 +2219,16 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
InterestingMethodContext);
}
-PathDiagnosticPiece*
+std::unique_ptr<PathDiagnosticPiece>
CFRefReportVisitor::getEndPath(BugReporterContext &BRC,
- const ExplodedNode *EndN,
- BugReport &BR) {
+ const ExplodedNode *EndN, BugReport &BR) {
BR.markInteresting(Sym);
return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
}
-PathDiagnosticPiece*
+std::unique_ptr<PathDiagnosticPiece>
CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
- const ExplodedNode *EndN,
- BugReport &BR) {
+ const ExplodedNode *EndN, BugReport &BR) {
// Tell the BugReporterContext to report cases when the tracked symbol is
// assigned to different variables, etc.
@@ -2309,7 +2308,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
os << " is not referenced later in this execution path and has a retain "
"count of +" << RV->getCount();
- return new PathDiagnosticEventPiece(L, os.str());
+ return llvm::make_unique<PathDiagnosticEventPiece>(L, os.str());
}
CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
@@ -2388,7 +2387,7 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
}
}
- addVisitor(new CFRefLeakReportVisitor(sym, GCEnabled, Log));
+ addVisitor(llvm::make_unique<CFRefLeakReportVisitor>(sym, GCEnabled, Log));
}
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/SelectorExtras.h b/lib/StaticAnalyzer/Checkers/SelectorExtras.h
index 48d96eb42234..41f70d7d5b69 100644
--- a/lib/StaticAnalyzer/Checkers/SelectorExtras.h
+++ b/lib/StaticAnalyzer/Checkers/SelectorExtras.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SA_CHECKERS_SELECTOREXTRAS
-#define LLVM_CLANG_SA_CHECKERS_SELECTOREXTRAS
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SELECTOREXTRAS_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SELECTOREXTRAS_H
#include "clang/AST/ASTContext.h"
#include <cstdarg>
@@ -34,7 +34,7 @@ static inline Selector getKeywordSelector(ASTContext &Ctx, va_list argp) {
return getKeywordSelectorImpl(Ctx, First, argp);
}
-END_WITH_NULL
+LLVM_END_WITH_NULL
static inline Selector getKeywordSelector(ASTContext &Ctx,
const char *First, ...) {
va_list argp;
@@ -44,7 +44,7 @@ static inline Selector getKeywordSelector(ASTContext &Ctx,
return result;
}
-END_WITH_NULL
+LLVM_END_WITH_NULL
static inline void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx,
const char *First, ...) {
if (!Sel.isNull())
diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index 3e9b57bdc507..ccf816c80c1e 100644
--- a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -63,8 +63,7 @@ class SimpleStreamChecker : public Checker<check::PostCall,
const CallEvent &Call,
CheckerContext &C) const;
- void reportLeaks(SymbolVector LeakedStreams,
- CheckerContext &C,
+ void reportLeaks(ArrayRef<SymbolRef> LeakedStreams, CheckerContext &C,
ExplodedNode *ErrNode) const;
bool guaranteedNotToCloseFile(const CallEvent &Call) const;
@@ -222,16 +221,15 @@ void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym,
C.emitReport(R);
}
-void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
- CheckerContext &C,
- ExplodedNode *ErrNode) const {
+void SimpleStreamChecker::reportLeaks(ArrayRef<SymbolRef> LeakedStreams,
+ CheckerContext &C,
+ ExplodedNode *ErrNode) const {
// Attach bug reports to the leak node.
// TODO: Identify the leaked file descriptor.
- for (SmallVectorImpl<SymbolRef>::iterator
- I = LeakedStreams.begin(), E = LeakedStreams.end(); I != E; ++I) {
+ for (SymbolRef LeakedStream : LeakedStreams) {
BugReport *R = new BugReport(*LeakBugType,
"Opened file is never closed; potential resource leak", ErrNode);
- R->markInteresting(*I);
+ R->markInteresting(LeakedStream);
C.emitReport(R);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
index dad5c0d3bab8..083075db8fb9 100644
--- a/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
@@ -176,7 +176,8 @@ void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const {
"already been used for division",
N);
- R->addVisitor(new DivisionBRVisitor(Val.getAsSymbol(), C.getStackFrame()));
+ R->addVisitor(llvm::make_unique<DivisionBRVisitor>(Val.getAsSymbol(),
+ C.getStackFrame()));
C.emitReport(R);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 93687db073f9..8976e0a699ec 100644
--- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -92,8 +92,8 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
BugReport *R = new BugReport(*BT, os.str(), N);
if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
R->addRange(Ex->getSourceRange());
- R->addVisitor(new FindLastStoreBRVisitor(*V, VR,
- /*EnableNullFPSuppression*/false));
+ R->addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
+ *V, VR, /*EnableNullFPSuppression*/ false));
R->disablePathPruning();
// need location of block
C.emitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 4887d804c607..4bfed8504f98 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -62,6 +62,10 @@ private:
return;
BT.reset(new BugType(this, name, categories::UnixAPI));
}
+ void ReportOpenBug(CheckerContext &C,
+ ProgramStateRef State,
+ const char *Msg,
+ SourceRange SR) const;
};
} //end anonymous namespace
@@ -69,7 +73,44 @@ private:
// "open" (man 2 open)
//===----------------------------------------------------------------------===//
+void UnixAPIChecker::ReportOpenBug(CheckerContext &C,
+ ProgramStateRef State,
+ const char *Msg,
+ SourceRange SR) const {
+ ExplodedNode *N = C.generateSink(State);
+ if (!N)
+ return;
+
+ LazyInitialize(BT_open, "Improper use of 'open'");
+
+ BugReport *Report = new BugReport(*BT_open, Msg, N);
+ Report->addRange(SR);
+ C.emitReport(Report);
+}
+
void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
+ ProgramStateRef state = C.getState();
+
+ if (CE->getNumArgs() < 2) {
+ // The frontend should issue a warning for this case, so this is a sanity
+ // check.
+ return;
+ } else if (CE->getNumArgs() == 3) {
+ const Expr *Arg = CE->getArg(2);
+ QualType QT = Arg->getType();
+ if (!QT->isIntegerType()) {
+ ReportOpenBug(C, state,
+ "Third argument to 'open' is not an integer",
+ Arg->getSourceRange());
+ return;
+ }
+ } else if (CE->getNumArgs() > 3) {
+ ReportOpenBug(C, state,
+ "Call to 'open' with more than three arguments",
+ CE->getArg(3)->getSourceRange());
+ return;
+ }
+
// The definition of O_CREAT is platform specific. We need a better way
// of querying this information from the checking environment.
if (!Val_O_CREAT.hasValue()) {
@@ -85,15 +126,6 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
}
}
- // Look at the 'oflags' argument for the O_CREAT flag.
- ProgramStateRef state = C.getState();
-
- if (CE->getNumArgs() < 2) {
- // The frontend should issue a warning for this case, so this is a sanity
- // check.
- return;
- }
-
// Now check if oflags has O_CREAT set.
const Expr *oflagsEx = CE->getArg(1);
const SVal V = state->getSVal(oflagsEx, C.getLocationContext());
@@ -122,18 +154,10 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
return;
if (CE->getNumArgs() < 3) {
- ExplodedNode *N = C.generateSink(trueState);
- if (!N)
- return;
-
- LazyInitialize(BT_open, "Improper use of 'open'");
-
- BugReport *report =
- new BugReport(*BT_open,
- "Call to 'open' requires a third argument when "
- "the 'O_CREAT' flag is set", N);
- report->addRange(oflagsEx->getSourceRange());
- C.emitReport(report);
+ ReportOpenBug(C, trueState,
+ "Call to 'open' requires a third argument when "
+ "the 'O_CREAT' flag is set",
+ oflagsEx->getSourceRange());
}
}
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index 198a6285c908..cceffef82b36 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -30,7 +30,7 @@ using namespace ento;
namespace {
class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > {
mutable std::unique_ptr<BugType> BT;
- enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted };
+ enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted, VLA_Negative };
void reportBug(VLASize_Kind Kind,
const Expr *SizeE,
@@ -67,6 +67,9 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind,
case VLA_Tainted:
os << "has tainted size";
break;
+ case VLA_Negative:
+ os << "has negative size";
+ break;
}
BugReport *report = new BugReport(*BT, os.str(), N);
@@ -128,8 +131,27 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// declared. We do this by multiplying the array length by the element size,
// then matching that with the array region's extent symbol.
- // Convert the array length to size_t.
+ // Check if the size is negative.
SValBuilder &svalBuilder = C.getSValBuilder();
+
+ QualType Ty = SE->getType();
+ DefinedOrUnknownSVal Zero = svalBuilder.makeZeroVal(Ty);
+
+ SVal LessThanZeroVal = svalBuilder.evalBinOp(state, BO_LT, sizeD, Zero, Ty);
+ if (Optional<DefinedSVal> LessThanZeroDVal =
+ LessThanZeroVal.getAs<DefinedSVal>()) {
+ ConstraintManager &CM = C.getConstraintManager();
+ ProgramStateRef StatePos, StateNeg;
+
+ std::tie(StateNeg, StatePos) = CM.assumeDual(state, *LessThanZeroDVal);
+ if (StateNeg && !StatePos) {
+ reportBug(VLA_Negative, SE, state, C);
+ return;
+ }
+ state = StatePos;
+ }
+
+ // Convert the array length to size_t.
QualType SizeTy = Ctx.getSizeType();
NonLoc ArrayLength =
svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>();
diff --git a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index f8f5cf93ca89..7e1fc1eb54ad 100644
--- a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -146,15 +146,22 @@ void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
if (CME->getQualifier())
callIsNonVirtual = true;
- // Elide analyzing the call entirely if the base pointer is not 'this'.
- if (Expr *base = CME->getBase()->IgnoreImpCasts())
+ if (Expr *base = CME->getBase()->IgnoreImpCasts()) {
+ // Elide analyzing the call entirely if the base pointer is not 'this'.
if (!isa<CXXThisExpr>(base))
return;
+
+ // If the most derived class is marked final, we know that now subclass
+ // can override this member.
+ if (base->getBestDynamicClassType()->hasAttr<FinalAttr>())
+ callIsNonVirtual = true;
+ }
}
// Get the callee.
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CE->getDirectCallee());
- if (MD && MD->isVirtual() && !callIsNonVirtual)
+ if (MD && MD->isVirtual() && !callIsNonVirtual && !MD->hasAttr<FinalAttr>() &&
+ !MD->getParent()->hasAttr<FinalAttr>())
ReportVirtualCall(CE, MD->isPure());
Enqueue(CE);
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 747b73c4164b..5798f01370de 100644
--- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -20,13 +20,16 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
- AnalyzerOptions &Options)
+ AnalyzerOptions &Options,
+ CodeInjector *injector)
: AnaCtxMgr(Options.UnoptimizedCFG,
/*AddImplicitDtors=*/true,
/*AddInitializers=*/true,
Options.includeTemporaryDtorsInCFG(),
Options.shouldSynthesizeBodies(),
- Options.shouldConditionalizeStaticInitializers()),
+ Options.shouldConditionalizeStaticInitializers(),
+ /*addCXXNewAllocator=*/true,
+ injector),
Ctx(ctx),
Diags(diags),
LangOpts(lang),
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 7944c7eb0003..d717e3fe86d2 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -23,7 +23,8 @@ using namespace llvm;
AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() {
if (UserMode == UMK_NotSet) {
- StringRef ModeStr(Config.GetOrCreateValue("mode", "deep").getValue());
+ StringRef ModeStr =
+ Config.insert(std::make_pair("mode", "deep")).first->second;
UserMode = llvm::StringSwitch<UserModeKind>(ModeStr)
.Case("shallow", UMK_Shallow)
.Case("deep", UMK_Deep)
@@ -48,7 +49,8 @@ IPAKind AnalyzerOptions::getIPAMode() {
assert(DefaultIPA);
// Lookup the ipa configuration option, use the default from User Mode.
- StringRef ModeStr(Config.GetOrCreateValue("ipa", DefaultIPA).getValue());
+ StringRef ModeStr =
+ Config.insert(std::make_pair("ipa", DefaultIPA)).first->second;
IPAKind IPAConfig = llvm::StringSwitch<IPAKind>(ModeStr)
.Case("none", IPAK_None)
.Case("basic-inlining", IPAK_BasicInlining)
@@ -72,9 +74,9 @@ AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) {
if (!CXXMemberInliningMode) {
static const char *ModeKey = "c++-inlining";
-
- StringRef ModeStr(Config.GetOrCreateValue(ModeKey,
- "destructors").getValue());
+
+ StringRef ModeStr =
+ Config.insert(std::make_pair(ModeKey, "destructors")).first->second;
CXXInlineableMemberKind &MutableMode =
const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode);
@@ -102,7 +104,8 @@ bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) {
// FIXME: We should emit a warning here if the value is something other than
// "true", "false", or the empty string (meaning the default value),
// but the AnalyzerOptions doesn't have access to a diagnostic engine.
- StringRef V(Config.GetOrCreateValue(Name, toString(DefaultVal)).getValue());
+ StringRef V =
+ Config.insert(std::make_pair(Name, toString(DefaultVal))).first->second;
return llvm::StringSwitch<bool>(V)
.Case("true", true)
.Case("false", false)
@@ -200,8 +203,8 @@ int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
SmallString<10> StrBuf;
llvm::raw_svector_ostream OS(StrBuf);
OS << DefaultVal;
-
- StringRef V(Config.GetOrCreateValue(Name, OS.str()).getValue());
+
+ StringRef V = Config.insert(std::make_pair(Name, OS.str())).first->second;
int Res = DefaultVal;
bool b = V.getAsInteger(10, Res);
assert(!b && "analyzer-config option should be numeric");
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 141a48ba10b3..dff81e383ea6 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -499,10 +499,9 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
//===----------------------------------------------------------------------===//
// "Visitors only" path diagnostic generation algorithm.
//===----------------------------------------------------------------------===//
-static bool GenerateVisitorsOnlyPathDiagnostic(PathDiagnostic &PD,
- PathDiagnosticBuilder &PDB,
- const ExplodedNode *N,
- ArrayRef<BugReporterVisitor *> visitors) {
+static bool GenerateVisitorsOnlyPathDiagnostic(
+ PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N,
+ ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
// All path generation skips the very first node (the error node).
// This is because there is special handling for the end-of-path note.
N = N->getFirstPred();
@@ -511,11 +510,9 @@ static bool GenerateVisitorsOnlyPathDiagnostic(PathDiagnostic &PD,
BugReport *R = PDB.getBugReport();
while (const ExplodedNode *Pred = N->getFirstPred()) {
- for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(),
- E = visitors.end();
- I != E; ++I) {
+ for (auto &V : visitors) {
// Visit all the node pairs, but throw the path pieces away.
- PathDiagnosticPiece *Piece = (*I)->VisitNode(N, Pred, PDB, *R);
+ PathDiagnosticPiece *Piece = V->VisitNode(N, Pred, PDB, *R);
delete Piece;
}
@@ -556,11 +553,10 @@ static void updateStackPiecesWithMessage(PathDiagnosticPiece *P,
static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM);
-static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
- PathDiagnosticBuilder &PDB,
- const ExplodedNode *N,
- LocationContextMap &LCM,
- ArrayRef<BugReporterVisitor *> visitors) {
+static bool GenerateMinimalPathDiagnostic(
+ PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N,
+ LocationContextMap &LCM,
+ ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
SourceManager& SMgr = PDB.getSourceManager();
const LocationContext *LC = PDB.LC;
@@ -870,10 +866,8 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (NextNode) {
// Add diagnostic pieces from custom visitors.
BugReport *R = PDB.getBugReport();
- for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(),
- E = visitors.end();
- I != E; ++I) {
- if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R)) {
+ for (auto &V : visitors) {
+ if (PathDiagnosticPiece *p = V->VisitNode(N, NextNode, PDB, *R)) {
PD.getActivePath().push_front(p);
updateStackPiecesWithMessage(p, CallStack);
}
@@ -1392,11 +1386,10 @@ static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) {
// Top-level logic for generating extensive path diagnostics.
//===----------------------------------------------------------------------===//
-static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
- PathDiagnosticBuilder &PDB,
- const ExplodedNode *N,
- LocationContextMap &LCM,
- ArrayRef<BugReporterVisitor *> visitors) {
+static bool GenerateExtensivePathDiagnostic(
+ PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N,
+ LocationContextMap &LCM,
+ ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
EdgeBuilder EB(PD, PDB);
const SourceManager& SM = PDB.getSourceManager();
StackDiagVector CallStack;
@@ -1573,10 +1566,8 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
// Add pieces from custom visitors.
BugReport *R = PDB.getBugReport();
- for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(),
- E = visitors.end();
- I != E; ++I) {
- if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R)) {
+ for (auto &V : visitors) {
+ if (PathDiagnosticPiece *p = V->VisitNode(N, NextNode, PDB, *R)) {
const PathDiagnosticLocation &Loc = p->getLocation();
EB.addEdge(Loc, true);
PD.getActivePath().push_front(p);
@@ -1635,12 +1626,10 @@ static const char StrLoopRangeEmpty[] =
static const char StrLoopCollectionEmpty[] =
"Loop body skipped when collection is empty";
-static bool
-GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
- PathDiagnosticBuilder &PDB,
- const ExplodedNode *N,
- LocationContextMap &LCM,
- ArrayRef<BugReporterVisitor *> visitors) {
+static bool GenerateAlternateExtensivePathDiagnostic(
+ PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N,
+ LocationContextMap &LCM,
+ ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
BugReport *report = PDB.getBugReport();
const SourceManager& SM = PDB.getSourceManager();
@@ -1867,10 +1856,8 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
continue;
// Add pieces from custom visitors.
- for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(),
- E = visitors.end();
- I != E; ++I) {
- if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *report)) {
+ for (auto &V : visitors) {
+ if (PathDiagnosticPiece *p = V->VisitNode(N, NextNode, PDB, *report)) {
addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), PDB.LC);
PD.getActivePath().push_front(p);
updateStackPiecesWithMessage(p, CallStack);
@@ -2547,7 +2534,7 @@ void BuiltinBug::anchor() {}
void BugReport::NodeResolver::anchor() {}
-void BugReport::addVisitor(BugReporterVisitor* visitor) {
+void BugReport::addVisitor(std::unique_ptr<BugReporterVisitor> visitor) {
if (!visitor)
return;
@@ -2555,20 +2542,15 @@ void BugReport::addVisitor(BugReporterVisitor* visitor) {
visitor->Profile(ID);
void *InsertPos;
- if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
- delete visitor;
+ if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos))
return;
- }
- CallbacksSet.InsertNode(visitor, InsertPos);
- Callbacks.push_back(visitor);
+ CallbacksSet.InsertNode(visitor.get(), InsertPos);
+ Callbacks.push_back(std::move(visitor));
++ConfigurationChangeToken;
}
BugReport::~BugReport() {
- for (visitor_iterator I = visitor_begin(), E = visitor_end(); I != E; ++I) {
- delete *I;
- }
while (!interestingSymbols.empty()) {
popInterestingSymbolsAndRegions();
}
@@ -2874,7 +2856,7 @@ TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph,
// The trimmed graph is created in the body of the constructor to ensure
// that the DenseMaps have been initialized already.
InterExplodedGraphMap ForwardMap;
- G.reset(OriginalGraph->trim(Nodes, &ForwardMap, &InverseMap));
+ G = OriginalGraph->trim(Nodes, &ForwardMap, &InverseMap);
// Find the (first) error node in the trimmed graph. We just need to consult
// the node map which maps from nodes in the original graph to nodes
@@ -2938,8 +2920,7 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
// Create a new graph with a single path. This is the graph
// that will be returned to the caller.
- ExplodedGraph *GNew = new ExplodedGraph();
- GraphWrapper.Graph.reset(GNew);
+ auto GNew = llvm::make_unique<ExplodedGraph>();
GraphWrapper.BackMap.clear();
// Now walk from the error node up the BFS path, always taking the
@@ -2976,6 +2957,8 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
PriorityCompare<false>(PriorityMap));
}
+ GraphWrapper.Graph = std::move(GNew);
+
return true;
}
@@ -3126,9 +3109,9 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
const ExplodedNode *N = ErrorGraph.ErrorNode;
// Register additional node visitors.
- R->addVisitor(new NilReceiverBRVisitor());
- R->addVisitor(new ConditionBRVisitor());
- R->addVisitor(new LikelyFalsePositiveSuppressionBRVisitor());
+ R->addVisitor(llvm::make_unique<NilReceiverBRVisitor>());
+ R->addVisitor(llvm::make_unique<ConditionBRVisitor>());
+ R->addVisitor(llvm::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
BugReport::VisitorList visitors;
unsigned origReportConfigToken, finalReportConfigToken;
@@ -3153,18 +3136,19 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
std::unique_ptr<PathDiagnosticPiece> LastPiece;
for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end();
I != E; ++I) {
- if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
+ if (std::unique_ptr<PathDiagnosticPiece> Piece =
+ (*I)->getEndPath(PDB, N, *R)) {
assert (!LastPiece &&
"There can only be one final piece in a diagnostic.");
- LastPiece.reset(Piece);
+ LastPiece = std::move(Piece);
}
}
if (ActiveScheme != PathDiagnosticConsumer::None) {
if (!LastPiece)
- LastPiece.reset(BugReporterVisitor::getDefaultEndPath(PDB, N, *R));
+ LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
assert(LastPiece);
- PD.setEndOfPath(LastPiece.release());
+ PD.setEndOfPath(std::move(LastPiece));
}
// Make sure we get a clean location context map so we don't
@@ -3187,7 +3171,7 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
}
// Clean up the visitors we used.
- llvm::DeleteContainerPointers(visitors);
+ visitors.clear();
// Did anything change while generating this path?
finalReportConfigToken = R->getConfigurationChangeToken();
@@ -3247,15 +3231,15 @@ void BugReporter::emitReport(BugReport* R) {
// To guarantee memory release.
std::unique_ptr<BugReport> UniqueR(R);
- // Defensive checking: throw the bug away if it comes from a BodyFarm-
- // generated body. We do this very early because report processing relies
- // on the report's location being valid.
- // FIXME: Valid bugs can occur in BodyFarm-generated bodies, so really we
- // need to just find a reasonable location like we do later on with the path
- // pieces.
if (const ExplodedNode *E = R->getErrorNode()) {
- const LocationContext *LCtx = E->getLocationContext();
- if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized())
+ const AnalysisDeclContext *DeclCtx =
+ E->getLocationContext()->getAnalysisDeclContext();
+ // The source of autosynthesized body can be handcrafted AST or a model
+ // file. The locations from handcrafted ASTs have no valid source locations
+ // and have to be discarded. Locations from model files should be preserved
+ // for processing and reporting.
+ if (DeclCtx->isBodyAutosynthesized() &&
+ !DeclCtx->isBodyAutosynthesizedFromModelFile())
return;
}
@@ -3277,12 +3261,11 @@ void BugReporter::emitReport(BugReport* R) {
BugReportEquivClass* EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos);
if (!EQ) {
- EQ = new BugReportEquivClass(UniqueR.release());
+ EQ = new BugReportEquivClass(std::move(UniqueR));
EQClasses.InsertNode(EQ, InsertPos);
EQClassesVector.push_back(EQ);
- }
- else
- EQ->AddReport(UniqueR.release());
+ } else
+ EQ->AddReport(std::move(UniqueR));
}
@@ -3449,13 +3432,13 @@ void BugReporter::FlushReport(BugReport *exampleReport,
// of the issue.
if (D->path.empty()) {
PathDiagnosticLocation L = exampleReport->getLocation(getSourceManager());
- PathDiagnosticPiece *piece =
- new PathDiagnosticEventPiece(L, exampleReport->getDescription());
+ auto piece = llvm::make_unique<PathDiagnosticEventPiece>(
+ L, exampleReport->getDescription());
BugReport::ranges_iterator Beg, End;
std::tie(Beg, End) = exampleReport->getRanges();
for ( ; Beg != End; ++Beg)
piece->addRange(*Beg);
- D->setEndOfPath(piece);
+ D->setEndOfPath(std::move(piece));
}
// Get the meta data.
@@ -3465,7 +3448,7 @@ void BugReporter::FlushReport(BugReport *exampleReport,
D->addMeta(*i);
}
- PD.HandlePathDiagnostic(D.release());
+ PD.HandlePathDiagnostic(std::move(D));
}
void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
@@ -3497,13 +3480,9 @@ BugType *BugReporter::getBugTypeForName(CheckName CheckName, StringRef name,
SmallString<136> fullDesc;
llvm::raw_svector_ostream(fullDesc) << CheckName.getName() << ":" << name
<< ":" << category;
- llvm::StringMapEntry<BugType *> &
- entry = StrBugTypes.GetOrCreateValue(fullDesc);
- BugType *BT = entry.getValue();
- if (!BT) {
+ BugType *&BT = StrBugTypes[fullDesc];
+ if (!BT)
BT = new BugType(CheckName, name, category);
- entry.setValue(BT);
- }
return BT;
}
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 0503acec051a..2d56bd088497 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -100,17 +100,14 @@ const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) {
// Definitions for bug reporter visitors.
//===----------------------------------------------------------------------===//
-PathDiagnosticPiece*
+std::unique_ptr<PathDiagnosticPiece>
BugReporterVisitor::getEndPath(BugReporterContext &BRC,
- const ExplodedNode *EndPathNode,
- BugReport &BR) {
+ const ExplodedNode *EndPathNode, BugReport &BR) {
return nullptr;
}
-PathDiagnosticPiece*
-BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC,
- const ExplodedNode *EndPathNode,
- BugReport &BR) {
+std::unique_ptr<PathDiagnosticPiece> BugReporterVisitor::getDefaultEndPath(
+ BugReporterContext &BRC, const ExplodedNode *EndPathNode, BugReport &BR) {
PathDiagnosticLocation L =
PathDiagnosticLocation::createEndOfPath(EndPathNode,BRC.getSourceManager());
@@ -119,13 +116,12 @@ BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC,
// Only add the statement itself as a range if we didn't specify any
// special ranges for this report.
- PathDiagnosticPiece *P = new PathDiagnosticEventPiece(L,
- BR.getDescription(),
- Beg == End);
+ auto P = llvm::make_unique<PathDiagnosticEventPiece>(L, BR.getDescription(),
+ Beg == End);
for (; Beg != End; ++Beg)
P->addRange(*Beg);
- return P;
+ return std::move(P);
}
@@ -222,7 +218,8 @@ public:
EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
BR.markInteresting(CalleeContext);
- BR.addVisitor(new ReturnVisitor(CalleeContext, EnableNullFPSuppression));
+ BR.addVisitor(llvm::make_unique<ReturnVisitor>(CalleeContext,
+ EnableNullFPSuppression));
}
/// Returns true if any counter-suppression heuristics are enabled for
@@ -399,9 +396,9 @@ public:
llvm_unreachable("Invalid visit mode!");
}
- PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
- const ExplodedNode *N,
- BugReport &BR) override {
+ std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) override {
if (EnableNullFPSuppression)
BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
return nullptr;
@@ -569,8 +566,8 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
if (Optional<KnownSVal> KV =
State->getSVal(OriginalR).getAs<KnownSVal>())
- BR.addVisitor(new FindLastStoreBRVisitor(*KV, OriginalR,
- EnableNullFPSuppression));
+ BR.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
+ *KV, OriginalR, EnableNullFPSuppression));
}
}
}
@@ -979,8 +976,8 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
// got initialized.
if (const MemRegion *RR = getLocationRegionIfReference(Inner, N)) {
if (Optional<KnownSVal> KV = LVal.getAs<KnownSVal>())
- report.addVisitor(new FindLastStoreBRVisitor(*KV, RR,
- EnableNullFPSuppression));
+ report.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
+ *KV, RR, EnableNullFPSuppression));
}
}
@@ -990,30 +987,26 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
report.markInteresting(R);
report.markInteresting(V);
- report.addVisitor(new UndefOrNullArgVisitor(R));
+ report.addVisitor(llvm::make_unique<UndefOrNullArgVisitor>(R));
// If the contents are symbolic, find out when they became null.
- if (V.getAsLocSymbol(/*IncludeBaseRegions*/ true)) {
- BugReporterVisitor *ConstraintTracker =
- new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false);
- report.addVisitor(ConstraintTracker);
- }
+ if (V.getAsLocSymbol(/*IncludeBaseRegions*/ true))
+ report.addVisitor(llvm::make_unique<TrackConstraintBRVisitor>(
+ V.castAs<DefinedSVal>(), false));
// Add visitor, which will suppress inline defensive checks.
if (Optional<DefinedSVal> DV = V.getAs<DefinedSVal>()) {
- if (!DV->isZeroConstant() &&
- LVState->isNull(*DV).isConstrainedTrue() &&
- EnableNullFPSuppression) {
- BugReporterVisitor *IDCSuppressor =
- new SuppressInlineDefensiveChecksVisitor(*DV,
- LVNode);
- report.addVisitor(IDCSuppressor);
+ if (!DV->isZeroConstant() && LVState->isNull(*DV).isConstrainedTrue() &&
+ EnableNullFPSuppression) {
+ report.addVisitor(
+ llvm::make_unique<SuppressInlineDefensiveChecksVisitor>(*DV,
+ LVNode));
}
}
if (Optional<KnownSVal> KV = V.getAs<KnownSVal>())
- report.addVisitor(new FindLastStoreBRVisitor(*KV, R,
- EnableNullFPSuppression));
+ report.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
+ *KV, R, EnableNullFPSuppression));
return true;
}
}
@@ -1044,12 +1037,12 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
RVal = state->getSVal(L->getRegion());
const MemRegion *RegionRVal = RVal.getAsRegion();
- report.addVisitor(new UndefOrNullArgVisitor(L->getRegion()));
+ report.addVisitor(llvm::make_unique<UndefOrNullArgVisitor>(L->getRegion()));
if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
report.markInteresting(RegionRVal);
- report.addVisitor(new TrackConstraintBRVisitor(
- loc::MemRegionVal(RegionRVal), false));
+ report.addVisitor(llvm::make_unique<TrackConstraintBRVisitor>(
+ loc::MemRegionVal(RegionRVal), false));
}
}
@@ -1132,8 +1125,8 @@ void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
if (V.getAs<loc::ConcreteInt>() || V.getAs<nonloc::ConcreteInt>()) {
// Register a new visitor with the BugReport.
- BR.addVisitor(new FindLastStoreBRVisitor(V.castAs<KnownSVal>(), R,
- EnableNullFPSuppression));
+ BR.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
+ V.castAs<KnownSVal>(), R, EnableNullFPSuppression));
}
}
}
@@ -1517,8 +1510,7 @@ static bool isInStdNamespace(const Decl *D) {
return ND->isStdNamespace();
}
-
-PathDiagnosticPiece *
+std::unique_ptr<PathDiagnosticPiece>
LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
BugReport &BR) {
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index 7e0670a06608..f67354466006 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -607,7 +607,7 @@ RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const {
ArrayRef<ParmVarDecl*> ObjCMethodCall::parameters() const {
const ObjCMethodDecl *D = getDecl();
if (!D)
- return ArrayRef<ParmVarDecl*>();
+ return None;
return D->parameters();
}
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 4623c358a9e2..7844ad4a9c04 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
@@ -164,7 +165,7 @@ WorkList* WorkList::makeBFSBlockDFSContents() {
bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
ProgramStateRef InitState) {
- if (G->num_roots() == 0) { // Initialize the analysis by constructing
+ if (G.num_roots() == 0) { // Initialize the analysis by constructing
// the root if none exists.
const CFGBlock *Entry = &(L->getCFG()->getEntry());
@@ -273,8 +274,8 @@ bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
ProgramStateRef InitState,
ExplodedNodeSet &Dst) {
bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
- for (ExplodedGraph::eop_iterator I = G->eop_begin(),
- E = G->eop_end(); I != E; ++I) {
+ for (ExplodedGraph::eop_iterator I = G.eop_begin(), E = G.eop_end(); I != E;
+ ++I) {
Dst.Add(*I);
}
return DidNotFinish;
@@ -346,6 +347,11 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
default:
llvm_unreachable("Analysis for this terminator not implemented.");
+ case Stmt::CXXBindTemporaryExprClass:
+ HandleCleanupTemporaryBranch(
+ cast<CXXBindTemporaryExpr>(B->getTerminator().getStmt()), B, Pred);
+ return;
+
// Model static initializers.
case Stmt::DeclStmtClass:
HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
@@ -461,6 +467,17 @@ void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
enqueue(Dst);
}
+void CoreEngine::HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
+ const CFGBlock *B,
+ ExplodedNode *Pred) {
+ assert(B->succ_size() == 2);
+ NodeBuilderContext Ctx(*this, B, Pred);
+ ExplodedNodeSet Dst;
+ SubEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->succ_begin()),
+ *(B->succ_begin() + 1));
+ // Enqueue the new frontier onto the worklist.
+ enqueue(Dst);
+}
void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
ExplodedNode *Pred) {
@@ -494,13 +511,13 @@ void CoreEngine::generateNode(const ProgramPoint &Loc,
ExplodedNode *Pred) {
bool IsNew;
- ExplodedNode *Node = G->getNode(Loc, State, false, &IsNew);
+ ExplodedNode *Node = G.getNode(Loc, State, false, &IsNew);
if (Pred)
- Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor.
+ Node->addPredecessor(Pred, G); // Link 'Node' with its predecessor.
else {
assert (IsNew);
- G->addRoot(Node); // 'Node' has no predecessor. Make it a root.
+ G.addRoot(Node); // 'Node' has no predecessor. Make it a root.
}
// Only add 'Node' to the worklist if it was freshly generated.
@@ -549,8 +566,8 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
}
bool IsNew;
- ExplodedNode *Succ = G->getNode(Loc, N->getState(), false, &IsNew);
- Succ->addPredecessor(N, *G);
+ ExplodedNode *Succ = G.getNode(Loc, N->getState(), false, &IsNew);
+ Succ->addPredecessor(N, G);
if (IsNew)
WList->enqueue(Succ, Block, Idx+1);
@@ -565,8 +582,8 @@ ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N) {
CallExitBegin Loc(LocCtx);
bool isNew;
- ExplodedNode *Node = G->getNode(Loc, N->getState(), false, &isNew);
- Node->addPredecessor(N, *G);
+ ExplodedNode *Node = G.getNode(Loc, N->getState(), false, &isNew);
+ Node->addPredecessor(N, G);
return isNew ? Node : nullptr;
}
@@ -596,7 +613,7 @@ void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set) {
WList->enqueue(N);
} else {
// TODO: We should run remove dead bindings here.
- G->addEndOfPath(N);
+ G.addEndOfPath(N);
NumPathsExplored++;
}
}
@@ -611,8 +628,8 @@ ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc,
bool MarkAsSink) {
HasGeneratedNodes = true;
bool IsNew;
- ExplodedNode *N = C.Eng.G->getNode(Loc, State, MarkAsSink, &IsNew);
- N->addPredecessor(FromN, *C.Eng.G);
+ ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew);
+ N->addPredecessor(FromN, C.Eng.G);
Frontier.erase(FromN);
if (!IsNew)
@@ -653,10 +670,10 @@ IndirectGotoNodeBuilder::generateNode(const iterator &I,
ProgramStateRef St,
bool IsSink) {
bool IsNew;
- ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
- Pred->getLocationContext()), St,
- IsSink, &IsNew);
- Succ->addPredecessor(Pred, *Eng.G);
+ ExplodedNode *Succ =
+ Eng.G.getNode(BlockEdge(Src, I.getBlock(), Pred->getLocationContext()),
+ St, IsSink, &IsNew);
+ Succ->addPredecessor(Pred, Eng.G);
if (!IsNew)
return nullptr;
@@ -673,10 +690,10 @@ SwitchNodeBuilder::generateCaseStmtNode(const iterator &I,
ProgramStateRef St) {
bool IsNew;
- ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
- Pred->getLocationContext()), St,
- false, &IsNew);
- Succ->addPredecessor(Pred, *Eng.G);
+ ExplodedNode *Succ =
+ Eng.G.getNode(BlockEdge(Src, I.getBlock(), Pred->getLocationContext()),
+ St, false, &IsNew);
+ Succ->addPredecessor(Pred, Eng.G);
if (!IsNew)
return nullptr;
@@ -698,10 +715,10 @@ SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St,
return nullptr;
bool IsNew;
- ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock,
- Pred->getLocationContext()), St,
- IsSink, &IsNew);
- Succ->addPredecessor(Pred, *Eng.G);
+ ExplodedNode *Succ =
+ Eng.G.getNode(BlockEdge(Src, DefaultBlock, Pred->getLocationContext()),
+ St, IsSink, &IsNew);
+ Succ->addPredecessor(Pred, Eng.G);
if (!IsNew)
return nullptr;
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index 1c9a282b8298..010d26e48e1d 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -336,10 +336,10 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
return V;
}
-ExplodedGraph *
+std::unique_ptr<ExplodedGraph>
ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
InterExplodedGraphMap *ForwardMap,
- InterExplodedGraphMap *InverseMap) const{
+ InterExplodedGraphMap *InverseMap) const {
if (Nodes.empty())
return nullptr;
@@ -365,12 +365,9 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
const ExplodedNode *N = WL1.pop_back_val();
// Have we already visited this node? If so, continue to the next one.
- if (Pass1.count(N))
+ if (!Pass1.insert(N).second)
continue;
- // Otherwise, mark this node as visited.
- Pass1.insert(N);
-
// If this is a root enqueue it to the second worklist.
if (N->Preds.empty()) {
WL2.push_back(N);
@@ -378,9 +375,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
}
// Visit our predecessors and enqueue them.
- for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end();
- I != E; ++I)
- WL1.push_back(*I);
+ WL1.append(N->Preds.begin(), N->Preds.end());
}
// We didn't hit a root? Return with a null pointer for the new graph.
@@ -388,7 +383,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
return nullptr;
// Create an empty graph.
- ExplodedGraph* G = MakeEmptyGraph();
+ std::unique_ptr<ExplodedGraph> G = MakeEmptyGraph();
// ===- Pass 2 (forward DFS to construct the new graph) -===
while (!WL2.empty()) {
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 4e4095c5e0d8..4699df8819bd 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -51,6 +51,15 @@ STATISTIC(NumMaxBlockCountReachedInInlined,
STATISTIC(NumTimesRetriedWithoutInlining,
"The # of times we re-evaluated a call without inlining");
+typedef std::pair<const CXXBindTemporaryExpr *, const StackFrameContext *>
+ CXXBindTemporaryContext;
+
+// Keeps track of whether CXXBindTemporaryExpr nodes have been evaluated.
+// The StackFrameContext assures that nested calls due to inlined recursive
+// functions do not interfere.
+REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedTemporariesSet,
+ llvm::ImmutableSet<CXXBindTemporaryContext>)
+
//===----------------------------------------------------------------------===//
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
@@ -659,13 +668,71 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ ExplodedNodeSet CleanDtorState;
+ StmtNodeBuilder StmtBldr(Pred, CleanDtorState, *currBldrCtx);
+ ProgramStateRef State = Pred->getState();
+ if (State->contains<InitializedTemporariesSet>(
+ std::make_pair(D.getBindTemporaryExpr(), Pred->getStackFrame()))) {
+ // FIXME: Currently we insert temporary destructors for default parameters,
+ // but we don't insert the constructors.
+ State = State->remove<InitializedTemporariesSet>(
+ std::make_pair(D.getBindTemporaryExpr(), Pred->getStackFrame()));
+ }
+ StmtBldr.generateNode(D.getBindTemporaryExpr(), Pred, State);
QualType varType = D.getBindTemporaryExpr()->getSubExpr()->getType();
-
- // FIXME: Inlining of temporary destructors is not supported yet anyway, so we
- // just put a NULL region for now. This will need to be changed later.
+ // FIXME: Currently CleanDtorState can be empty here due to temporaries being
+ // bound to default parameters.
+ assert(CleanDtorState.size() <= 1);
+ ExplodedNode *CleanPred =
+ CleanDtorState.empty() ? Pred : *CleanDtorState.begin();
+ // FIXME: Inlining of temporary destructors is not supported yet anyway, so
+ // we just put a NULL region for now. This will need to be changed later.
VisitCXXDestructor(varType, nullptr, D.getBindTemporaryExpr(),
- /*IsBase=*/ false, Pred, Dst);
+ /*IsBase=*/false, CleanPred, Dst);
+}
+
+void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
+ NodeBuilderContext &BldCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) {
+ BranchNodeBuilder TempDtorBuilder(Pred, Dst, BldCtx, DstT, DstF);
+ if (Pred->getState()->contains<InitializedTemporariesSet>(
+ std::make_pair(BTE, Pred->getStackFrame()))) {
+ TempDtorBuilder.markInfeasible(false);
+ TempDtorBuilder.generateNode(Pred->getState(), true, Pred);
+ } else {
+ TempDtorBuilder.markInfeasible(true);
+ TempDtorBuilder.generateNode(Pred->getState(), false, Pred);
+ }
+}
+
+void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
+ ExplodedNodeSet &PreVisit,
+ ExplodedNodeSet &Dst) {
+ if (!getAnalysisManager().options.includeTemporaryDtorsInCFG()) {
+ // In case we don't have temporary destructors in the CFG, do not mark
+ // the initialization - we would otherwise never clean it up.
+ Dst = PreVisit;
+ return;
+ }
+ StmtNodeBuilder StmtBldr(PreVisit, Dst, *currBldrCtx);
+ for (ExplodedNode *Node : PreVisit) {
+ ProgramStateRef State = Node->getState();
+
+ if (!State->contains<InitializedTemporariesSet>(
+ std::make_pair(BTE, Node->getStackFrame()))) {
+ // FIXME: Currently the state might already contain the marker due to
+ // incorrect handling of temporaries bound to default parameters; for
+ // those, we currently skip the CXXBindTemporaryExpr but rely on adding
+ // temporary destructor nodes.
+ State = State->add<InitializedTemporariesSet>(
+ std::make_pair(BTE, Node->getStackFrame()));
+ }
+ StmtBldr.generateNode(BTE, Node, State);
+ }
}
void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
@@ -685,6 +752,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXTryStmtClass:
case Stmt::CXXTypeidExprClass:
case Stmt::CXXUuidofExprClass:
+ case Stmt::CXXFoldExprClass:
case Stmt::MSPropertyRefExprClass:
case Stmt::CXXUnresolvedConstructExprClass:
case Stmt::DependentScopeDeclRefExprClass:
@@ -693,6 +761,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::ExpressionTraitExprClass:
case Stmt::UnresolvedLookupExprClass:
case Stmt::UnresolvedMemberExprClass:
+ case Stmt::TypoExprClass:
case Stmt::CXXNoexceptExprClass:
case Stmt::PackExpansionExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
@@ -734,18 +803,24 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPParallelDirectiveClass:
case Stmt::OMPSimdDirectiveClass:
case Stmt::OMPForDirectiveClass:
+ case Stmt::OMPForSimdDirectiveClass:
case Stmt::OMPSectionsDirectiveClass:
case Stmt::OMPSectionDirectiveClass:
case Stmt::OMPSingleDirectiveClass:
case Stmt::OMPMasterDirectiveClass:
case Stmt::OMPCriticalDirectiveClass:
case Stmt::OMPParallelForDirectiveClass:
+ case Stmt::OMPParallelForSimdDirectiveClass:
case Stmt::OMPParallelSectionsDirectiveClass:
case Stmt::OMPTaskDirectiveClass:
case Stmt::OMPTaskyieldDirectiveClass:
case Stmt::OMPBarrierDirectiveClass:
case Stmt::OMPTaskwaitDirectiveClass:
case Stmt::OMPFlushDirectiveClass:
+ case Stmt::OMPOrderedDirectiveClass:
+ case Stmt::OMPAtomicDirectiveClass:
+ case Stmt::OMPTargetDirectiveClass:
+ case Stmt::OMPTeamsDirectiveClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
case Stmt::ObjCSubscriptRefExprClass:
@@ -771,6 +846,17 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// Handled due to fully linearised CFG.
break;
+ case Stmt::CXXBindTemporaryExprClass: {
+ Bldr.takeNodes(Pred);
+ ExplodedNodeSet PreVisit;
+ getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
+ ExplodedNodeSet Next;
+ VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), PreVisit, Next);
+ getCheckerManager().runCheckersForPostStmt(Dst, Next, S, *this);
+ Bldr.addNodes(Dst);
+ break;
+ }
+
// Cases not handled yet; but will handle some day.
case Stmt::DesignatedInitExprClass:
case Stmt::ExtVectorElementExprClass:
@@ -784,7 +870,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::ObjCProtocolExprClass:
case Stmt::ObjCSelectorExprClass:
case Stmt::ParenListExprClass:
- case Stmt::PredefinedExprClass:
case Stmt::ShuffleVectorExprClass:
case Stmt::ConvertVectorExprClass:
case Stmt::VAArgExprClass:
@@ -796,6 +881,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// Cases we intentionally don't evaluate, since they don't need
// to be explicitly evaluated.
+ case Stmt::PredefinedExprClass:
case Stmt::AddrLabelExprClass:
case Stmt::AttributedStmtClass:
case Stmt::IntegerLiteralClass:
@@ -808,7 +894,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::SizeOfPackExprClass:
case Stmt::StringLiteralClass:
case Stmt::ObjCStringLiteralClass:
- case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXPseudoDestructorExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::CXXNullPtrLiteralExprClass: {
@@ -1403,11 +1488,8 @@ static const Stmt *ResolveCondition(const Stmt *Condition,
if (!BO || !BO->isLogicalOp())
return Condition;
- // FIXME: This is a workaround until we handle temporary destructor branches
- // correctly; currently, temporary destructor branches lead to blocks that
- // only have a terminator (and no statements). These blocks violate the
- // invariant this function assumes.
- if (B->getTerminator().isTemporaryDtorsBranch()) return Condition;
+ assert(!B->getTerminator().isTemporaryDtorsBranch() &&
+ "Temporary destructor branches handled by processBindTemporary.");
// For logical operations, we still have the case where some branches
// use the traditional "merge" approach and others sink the branch
@@ -1436,6 +1518,8 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) {
+ assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) &&
+ "CXXBindTemporaryExprs are handled by processBindTemporary.");
const LocationContext *LCtx = Pred->getLocationContext();
PrettyStackTraceLocationContext StackCrashInfo(LCtx);
currBldrCtx = &BldCtx;
@@ -1599,10 +1683,29 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
builder.generateNode(I, state);
}
+#if 0
+static bool stackFrameDoesNotContainInitializedTemporaries(ExplodedNode &Pred) {
+ const StackFrameContext* Frame = Pred.getStackFrame();
+ const llvm::ImmutableSet<CXXBindTemporaryContext> &Set =
+ Pred.getState()->get<InitializedTemporariesSet>();
+ return std::find_if(Set.begin(), Set.end(),
+ [&](const CXXBindTemporaryContext &Ctx) {
+ if (Ctx.second == Frame) {
+ Ctx.first->dump();
+ llvm::errs() << "\n";
+ }
+ return Ctx.second == Frame;
+ }) == Set.end();
+}
+#endif
+
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
ExplodedNode *Pred) {
+ // FIXME: Assert that stackFrameDoesNotContainInitializedTemporaries(*Pred)).
+ // We currently cannot enable this assert, as lifetime extended temporaries
+ // are not modelled correctly.
PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
StateMgr.EndPath(Pred->getState());
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index b1e9f06cae00..88b5464d44be 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -20,8 +20,8 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 22711f54239a..76cead623298 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1116,17 +1116,6 @@ const SymbolicRegion *MemRegion::getSymbolicBase() const {
return nullptr;
}
-// FIXME: Merge with the implementation of the same method in Store.cpp
-static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *D = RT->getDecl();
- if (!D->getDefinition())
- return false;
- }
-
- return true;
-}
-
RegionRawOffset ElementRegion::getAsArrayOffset() const {
CharUnits offset = CharUnits::Zero();
const ElementRegion *ER = this;
@@ -1148,7 +1137,7 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const {
QualType elemType = ER->getElementType();
// If we are pointing to an incomplete type, go no further.
- if (!IsCompleteType(C, elemType)) {
+ if (elemType->isIncompleteType()) {
superR = ER;
break;
}
@@ -1288,7 +1277,7 @@ RegionOffset MemRegion::getAsOffset() const {
R = ER->getSuperRegion();
QualType EleTy = ER->getValueType();
- if (!IsCompleteType(getContext(), EleTy)) {
+ if (EleTy->isIncompleteType()) {
// We cannot compute the offset of the base class.
SymbolicOffsetBase = R;
continue;
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index fd25bd8e3af3..b971fff642d4 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -197,9 +197,8 @@ PathDiagnosticConsumer::~PathDiagnosticConsumer() {
}
}
-void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
- std::unique_ptr<PathDiagnostic> OwningD(D);
-
+void PathDiagnosticConsumer::HandlePathDiagnostic(
+ std::unique_ptr<PathDiagnostic> D) {
if (!D || D->path.empty())
return;
@@ -213,7 +212,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
if (!supportsCrossFileDiagnostics()) {
// Verify that the entire path is from the same FileID.
FileID FID;
- const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
+ const SourceManager &SMgr = D->path.front()->getLocation().getManager();
SmallVector<const PathPieces *, 5> WorkList;
WorkList.push_back(&D->path);
@@ -272,12 +271,12 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
if (orig_size <= new_size)
return;
- assert(orig != D);
+ assert(orig != D.get());
Diags.RemoveNode(orig);
delete orig;
}
- Diags.InsertNode(OwningD.release());
+ Diags.InsertNode(D.release());
}
static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index ba3ad2ef16c5..a2c66f881482 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -42,7 +42,7 @@ namespace {
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
FilesMade *filesMade) override;
- virtual StringRef getName() const override {
+ StringRef getName() const override {
return "PlistDiagnostics";
}
@@ -338,10 +338,10 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
}
// Open the file.
- std::string ErrMsg;
- llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg, llvm::sys::fs::F_Text);
- if (!ErrMsg.empty()) {
- llvm::errs() << "warning: could not create file: " << OutputFile << '\n';
+ std::error_code EC;
+ llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::F_Text);
+ if (EC) {
+ llvm::errs() << "warning: could not create file: " << EC.message() << '\n';
return;
}
diff --git a/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h b/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
index c2af36f40704..e7cc23ca8234 100644
--- a/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
+++ b/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_STATICANALYZER_PRETTYSTACKTRACELOCATIONCONTEXT_H
-#define LLVM_CLANG_STATICANALYZER_PRETTYSTACKTRACELOCATIONCONTEXT_H
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CORE_PRETTYSTACKTRACELOCATIONCONTEXT_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CORE_PRETTYSTACKTRACELOCATIONCONTEXT_H
#include "clang/Analysis/AnalysisContext.h"
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 1714a2744a1a..60b32c722ebf 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -75,8 +75,8 @@ ProgramStateManager::ProgramStateManager(ASTContext &Ctx,
: Eng(SubEng), EnvMgr(alloc), GDMFactory(alloc),
svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
CallEventMgr(new CallEventManager(alloc)), Alloc(alloc) {
- StoreMgr.reset((*CreateSMgr)(*this));
- ConstraintMgr.reset((*CreateCMgr)(*this, SubEng));
+ StoreMgr = (*CreateSMgr)(*this);
+ ConstraintMgr = (*CreateCMgr)(*this, SubEng);
}
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 77578d378fb3..170f7c02b882 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -328,9 +328,9 @@ private:
} // end anonymous namespace
-ConstraintManager *
+std::unique_ptr<ConstraintManager>
ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
- return new RangeConstraintManager(Eng, StMgr.getSValBuilder());
+ return llvm::make_unique<RangeConstraintManager>(Eng, StMgr.getSValBuilder());
}
const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St,
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 3bbbb3430792..45056226c9e0 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -609,16 +609,17 @@ public: // Part of public interface to class.
// RegionStore creation.
//===----------------------------------------------------------------------===//
-StoreManager *ento::CreateRegionStoreManager(ProgramStateManager& StMgr) {
+std::unique_ptr<StoreManager>
+ento::CreateRegionStoreManager(ProgramStateManager &StMgr) {
RegionStoreFeatures F = maximal_features_tag();
- return new RegionStoreManager(StMgr, F);
+ return llvm::make_unique<RegionStoreManager>(StMgr, F);
}
-StoreManager *
+std::unique_ptr<StoreManager>
ento::CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr) {
RegionStoreFeatures F = minimal_features_tag();
F.enableFields(true);
- return new RegionStoreManager(StMgr, F);
+ return llvm::make_unique<RegionStoreManager>(StMgr, F);
}
@@ -708,7 +709,7 @@ public:
}
bool AddToWorkList(WorkListElement E, const ClusterBindings *C) {
- if (C && !Visited.insert(C))
+ if (C && !Visited.insert(C).second)
return false;
WL.push_back(E);
return true;
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index 21e2283511ae..a72d1d4f9218 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_SIMPLE_CONSTRAINT_MANAGER_H
-#define LLVM_CLANG_GR_SIMPLE_CONSTRAINT_MANAGER_H
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CORE_SIMPLECONSTRAINTMANAGER_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CORE_SIMPLECONSTRAINTMANAGER_H
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index e38be3e0b7dd..99ec1e704340 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -48,17 +48,6 @@ const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
return MRMgr.getElementRegion(EleTy, idx, Base, svalBuilder.getContext());
}
-// FIXME: Merge with the implementation of the same method in MemRegion.cpp
-static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *D = RT->getDecl();
- if (!D->getDefinition())
- return false;
- }
-
- return true;
-}
-
StoreRef StoreManager::BindDefault(Store store, const MemRegion *R, SVal V) {
return StoreRef(store, *this);
}
@@ -196,7 +185,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
const MemRegion *newSuperR = nullptr;
// We can only compute sizeof(PointeeTy) if it is a complete type.
- if (IsCompleteType(Ctx, PointeeTy)) {
+ if (!PointeeTy->isIncompleteType()) {
// Compute the size in **bytes**.
CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy);
if (!pointeeTySize.isZero()) {
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index f0dd2742352b..183ef358df63 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
+#include "ModelInjector.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DataRecursiveASTVisitor.h"
#include "clang/AST/Decl.h"
@@ -21,8 +22,10 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CallGraph.h"
+#include "clang/Analysis/CodeInjector.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
@@ -51,7 +54,7 @@ using llvm::SmallPtrSet;
#define DEBUG_TYPE "AnalysisConsumer"
-static ExplodedNode::Auditor* CreateUbiViz();
+static std::unique_ptr<ExplodedNode::Auditor> CreateUbiViz();
STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
STATISTIC(NumFunctionsAnalyzed,
@@ -157,6 +160,7 @@ public:
const std::string OutDir;
AnalyzerOptionsRef Opts;
ArrayRef<std::string> Plugins;
+ CodeInjector *Injector;
/// \brief Stores the declarations from the local translation unit.
/// Note, we pre-compute the local declarations at parse time as an
@@ -184,9 +188,10 @@ public:
AnalysisConsumer(const Preprocessor& pp,
const std::string& outdir,
AnalyzerOptionsRef opts,
- ArrayRef<std::string> plugins)
- : RecVisitorMode(0), RecVisitorBR(nullptr),
- Ctx(nullptr), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) {
+ ArrayRef<std::string> plugins,
+ CodeInjector *injector)
+ : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr), PP(pp),
+ OutDir(outdir), Opts(opts), Plugins(plugins), Injector(injector) {
DigestAnalyzerOptions();
if (Opts->PrintStats) {
llvm::EnableStatistics();
@@ -284,16 +289,12 @@ public:
void Initialize(ASTContext &Context) override {
Ctx = &Context;
- checkerMgr.reset(createCheckerManager(*Opts, PP.getLangOpts(), Plugins,
- PP.getDiagnostics()));
- Mgr.reset(new AnalysisManager(*Ctx,
- PP.getDiagnostics(),
- PP.getLangOpts(),
- PathConsumers,
- CreateStoreMgr,
- CreateConstraintMgr,
- checkerMgr.get(),
- *Opts));
+ checkerMgr = createCheckerManager(*Opts, PP.getLangOpts(), Plugins,
+ PP.getDiagnostics());
+
+ Mgr = llvm::make_unique<AnalysisManager>(
+ *Ctx, PP.getDiagnostics(), PP.getLangOpts(), PathConsumers,
+ CreateStoreMgr, CreateConstraintMgr, checkerMgr.get(), *Opts, Injector);
}
/// \brief Store the top level decls in the set to be processed later on.
@@ -307,7 +308,7 @@ public:
/// analyzed. This allows to redefine the default inlining policies when
/// analyzing a given function.
ExprEngine::InliningModes
- getInliningModeForFunction(const Decl *D, const SetOfConstDecls &Visited);
+ getInliningModeForFunction(const Decl *D, const SetOfConstDecls &Visited);
/// \brief Build the call graph for all the top level decls of this TU and
/// use it to define the order in which the functions should be visited.
@@ -506,6 +507,11 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
return;
+ // Don't analyze if the user explicitly asked for no checks to be performed
+ // on this file.
+ if (Opts->DisableAllChecks)
+ return;
+
{
if (TUTotalTimer) TUTotalTimer->startTimer();
@@ -643,7 +649,7 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
// Set the graph auditor.
std::unique_ptr<ExplodedNode::Auditor> Auditor;
if (Mgr->options.visualizeExplodedGraphWithUbiGraph) {
- Auditor.reset(CreateUbiViz());
+ Auditor = CreateUbiViz();
ExplodedNode::SetAuditor(Auditor.get());
}
@@ -687,14 +693,18 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
// AnalysisConsumer creation.
//===----------------------------------------------------------------------===//
-AnalysisASTConsumer *
-ento::CreateAnalysisConsumer(const Preprocessor &pp, const std::string &outDir,
- AnalyzerOptionsRef opts,
- ArrayRef<std::string> plugins) {
+std::unique_ptr<AnalysisASTConsumer>
+ento::CreateAnalysisConsumer(CompilerInstance &CI) {
// Disable the effects of '-Werror' when using the AnalysisConsumer.
- pp.getDiagnostics().setWarningsAsErrors(false);
+ CI.getPreprocessor().getDiagnostics().setWarningsAsErrors(false);
+
+ AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
+ bool hasModelPath = analyzerOpts->Config.count("model-path") > 0;
- return new AnalysisConsumer(pp, outDir, opts, plugins);
+ return llvm::make_unique<AnalysisConsumer>(
+ CI.getPreprocessor(), CI.getFrontendOpts().OutputFile, analyzerOpts,
+ CI.getFrontendOpts().Plugins,
+ hasModelPath ? new ModelInjector(CI) : nullptr);
}
//===----------------------------------------------------------------------===//
@@ -721,7 +731,7 @@ public:
} // end anonymous namespace
-static ExplodedNode::Auditor* CreateUbiViz() {
+static std::unique_ptr<ExplodedNode::Auditor> CreateUbiViz() {
SmallString<128> P;
int FD;
llvm::sys::fs::createTemporaryFile("llvm_ubi", "", FD, P);
@@ -729,7 +739,7 @@ static ExplodedNode::Auditor* CreateUbiViz() {
auto Stream = llvm::make_unique<llvm::raw_fd_ostream>(FD, true);
- return new UbigraphViz(std::move(Stream), P);
+ return llvm::make_unique<UbigraphViz>(std::move(Stream), P);
}
void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
@@ -778,7 +788,9 @@ UbigraphViz::~UbigraphViz() {
Out.reset();
llvm::errs() << "Running 'ubiviz' program... ";
std::string ErrMsg;
- std::string Ubiviz = llvm::sys::FindProgramByName("ubiviz");
+ std::string Ubiviz;
+ if (auto Path = llvm::sys::findProgramByName("ubiviz"))
+ Ubiviz = *Path;
std::vector<const char*> args;
args.push_back(Ubiviz.c_str());
args.push_back(Filename.c_str());
diff --git a/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
index 5349ed93e2c4..e3ca91aec9cd 100644
--- a/lib/StaticAnalyzer/Frontend/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
@@ -7,13 +7,16 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangStaticAnalyzerFrontend
AnalysisConsumer.cpp
CheckerRegistration.cpp
+ ModelConsumer.cpp
FrontendActions.cpp
+ ModelInjector.cpp
LINK_LIBS
clangAST
clangAnalysis
clangBasic
clangFrontend
+ clangLex
clangStaticAnalyzerCheckers
clangStaticAnalyzerCore
)
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index e2577c3c729f..36565cb6e2ca 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -99,11 +99,10 @@ void ClangCheckerRegistry::warnIncompatible(DiagnosticsEngine *diags,
<< pluginAPIVersion;
}
-
-CheckerManager *ento::createCheckerManager(AnalyzerOptions &opts,
- const LangOptions &langOpts,
- ArrayRef<std::string> plugins,
- DiagnosticsEngine &diags) {
+std::unique_ptr<CheckerManager>
+ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts,
+ ArrayRef<std::string> plugins,
+ DiagnosticsEngine &diags) {
std::unique_ptr<CheckerManager> checkerMgr(
new CheckerManager(langOpts, &opts));
@@ -118,12 +117,15 @@ CheckerManager *ento::createCheckerManager(AnalyzerOptions &opts,
checkerMgr->finishedCheckerRegistration();
for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) {
- if (checkerOpts[i].isUnclaimed())
+ if (checkerOpts[i].isUnclaimed()) {
diags.Report(diag::err_unknown_analyzer_checker)
<< checkerOpts[i].getName();
+ diags.Report(diag::note_suggest_disabling_all_checkers);
+ }
+
}
- return checkerMgr.release();
+ return std::move(checkerMgr);
}
void ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) {
diff --git a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
index aa3807732632..b33608042ce3 100644
--- a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
+++ b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
@@ -8,16 +8,21 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
-#include "clang/Frontend/CompilerInstance.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
+#include "clang/StaticAnalyzer/Frontend/ModelConsumer.h"
using namespace clang;
using namespace ento;
-ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- return CreateAnalysisConsumer(CI.getPreprocessor(),
- CI.getFrontendOpts().OutputFile,
- CI.getAnalyzerOpts(),
- CI.getFrontendOpts().Plugins);
+std::unique_ptr<ASTConsumer>
+AnalysisAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+ return CreateAnalysisConsumer(CI);
}
+ParseModelFileAction::ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies)
+ : Bodies(Bodies) {}
+
+std::unique_ptr<ASTConsumer>
+ParseModelFileAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ return llvm::make_unique<ModelConsumer>(Bodies);
+}
diff --git a/lib/StaticAnalyzer/Frontend/ModelConsumer.cpp b/lib/StaticAnalyzer/Frontend/ModelConsumer.cpp
new file mode 100644
index 000000000000..a65a5ee0a451
--- /dev/null
+++ b/lib/StaticAnalyzer/Frontend/ModelConsumer.cpp
@@ -0,0 +1,42 @@
+//===--- ModelConsumer.cpp - ASTConsumer for consuming model files --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements an ASTConsumer for consuming model files.
+///
+/// This ASTConsumer handles the AST of a parsed model file. All top level
+/// function definitions will be collected from that model file for later
+/// retrieval during the static analysis. The body of these functions will not
+/// be injected into the ASTUnit of the analyzed translation unit. It will be
+/// available through the BodyFarm which is utilized by the AnalysisDeclContext
+/// class.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Frontend/ModelConsumer.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
+
+using namespace clang;
+using namespace ento;
+
+ModelConsumer::ModelConsumer(llvm::StringMap<Stmt *> &Bodies)
+ : Bodies(Bodies) {}
+
+bool ModelConsumer::HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
+
+ // Only interested in definitions.
+ const FunctionDecl *func = llvm::dyn_cast<FunctionDecl>(*I);
+ if (func && func->hasBody()) {
+ Bodies.insert(std::make_pair(func->getName(), func->getBody()));
+ }
+ }
+ return true;
+}
diff --git a/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
new file mode 100644
index 000000000000..63bb1e245885
--- /dev/null
+++ b/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
@@ -0,0 +1,117 @@
+//===-- ModelInjector.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ModelInjector.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/FileSystem.h"
+#include <string>
+#include <utility>
+
+using namespace clang;
+using namespace ento;
+
+ModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {}
+
+Stmt *ModelInjector::getBody(const FunctionDecl *D) {
+ onBodySynthesis(D);
+ return Bodies[D->getName()];
+}
+
+Stmt *ModelInjector::getBody(const ObjCMethodDecl *D) {
+ onBodySynthesis(D);
+ return Bodies[D->getName()];
+}
+
+void ModelInjector::onBodySynthesis(const NamedDecl *D) {
+
+ // FIXME: what about overloads? Declarations can be used as keys but what
+ // about file name index? Mangled names may not be suitable for that either.
+ if (Bodies.count(D->getName()) != 0)
+ return;
+
+ SourceManager &SM = CI.getSourceManager();
+ FileID mainFileID = SM.getMainFileID();
+
+ AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
+ llvm::StringRef modelPath = analyzerOpts->Config["model-path"];
+
+ llvm::SmallString<128> fileName;
+
+ if (!modelPath.empty())
+ fileName =
+ llvm::StringRef(modelPath.str() + "/" + D->getName().str() + ".model");
+ else
+ fileName = llvm::StringRef(D->getName().str() + ".model");
+
+ if (!llvm::sys::fs::exists(fileName.str())) {
+ Bodies[D->getName()] = nullptr;
+ return;
+ }
+
+ IntrusiveRefCntPtr<CompilerInvocation> Invocation(
+ new CompilerInvocation(CI.getInvocation()));
+
+ FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
+ InputKind IK = IK_CXX; // FIXME
+ FrontendOpts.Inputs.clear();
+ FrontendOpts.Inputs.push_back(FrontendInputFile(fileName, IK));
+ FrontendOpts.DisableFree = true;
+
+ Invocation->getDiagnosticOpts().VerifyDiagnostics = 0;
+
+ // Modules are parsed by a separate CompilerInstance, so this code mimics that
+ // behavior for models
+ CompilerInstance Instance;
+ Instance.setInvocation(&*Invocation);
+ Instance.createDiagnostics(
+ new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
+ /*ShouldOwnClient=*/true);
+
+ Instance.getDiagnostics().setSourceManager(&SM);
+
+ Instance.setVirtualFileSystem(&CI.getVirtualFileSystem());
+
+ // The instance wants to take ownership, however DisableFree frontend option
+ // is set to true to avoid double free issues
+ Instance.setFileManager(&CI.getFileManager());
+ Instance.setSourceManager(&SM);
+ Instance.setPreprocessor(&CI.getPreprocessor());
+ Instance.setASTContext(&CI.getASTContext());
+
+ Instance.getPreprocessor().InitializeForModelFile();
+
+ ParseModelFileAction parseModelFile(Bodies);
+
+ const unsigned ThreadStackSize = 8 << 20;
+ llvm::CrashRecoveryContext CRC;
+
+ CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(parseModelFile); },
+ ThreadStackSize);
+
+ Instance.getPreprocessor().FinalizeForModelFile();
+
+ Instance.resetAndLeakSourceManager();
+ Instance.resetAndLeakFileManager();
+ Instance.resetAndLeakPreprocessor();
+
+ // The preprocessor enters to the main file id when parsing is started, so
+ // the main file id is changed to the model file during parsing and it needs
+ // to be reseted to the former main file id after parsing of the model file
+ // is done.
+ SM.setMainFileID(mainFileID);
+}
diff --git a/lib/StaticAnalyzer/Frontend/ModelInjector.h b/lib/StaticAnalyzer/Frontend/ModelInjector.h
new file mode 100644
index 000000000000..fd24e32f3a3d
--- /dev/null
+++ b/lib/StaticAnalyzer/Frontend/ModelInjector.h
@@ -0,0 +1,74 @@
+//===-- ModelInjector.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file defines the clang::ento::ModelInjector class which implements the
+/// clang::CodeInjector interface. This class is responsible for injecting
+/// function definitions that were synthesized from model files.
+///
+/// Model files allow definitions of functions to be lazily constituted for functions
+/// which lack bodies in the original source code. This allows the analyzer
+/// to more precisely analyze code that calls such functions, analyzing the
+/// artificial definitions (which typically approximate the semantics of the
+/// called function) when called by client code. These definitions are
+/// reconstituted lazily, on-demand, by the static analyzer engine.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SA_FRONTEND_MODELINJECTOR_H
+#define LLVM_CLANG_SA_FRONTEND_MODELINJECTOR_H
+
+#include "clang/Analysis/CodeInjector.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringMap.h"
+#include <map>
+#include <memory>
+#include <vector>
+
+namespace clang {
+
+class CompilerInstance;
+class ASTUnit;
+class ASTReader;
+class NamedDecl;
+class Module;
+
+namespace ento {
+class ModelInjector : public CodeInjector {
+public:
+ ModelInjector(CompilerInstance &CI);
+ Stmt *getBody(const FunctionDecl *D);
+ Stmt *getBody(const ObjCMethodDecl *D);
+
+private:
+ /// \brief Synthesize a body for a declaration
+ ///
+ /// This method first looks up the appropriate model file based on the
+ /// model-path configuration option and the name of the declaration that is
+ /// looked up. If no model were synthesized yet for a function with that name
+ /// it will create a new compiler instance to parse the model file using the
+ /// ASTContext, Preprocessor, SourceManager of the original compiler instance.
+ /// The former resources are shared between the two compiler instance, so the
+ /// newly created instance have to "leak" these objects, since they are owned
+ /// by the original instance.
+ ///
+ /// The model-path should be either an absolute path or relative to the
+ /// working directory of the compiler.
+ void onBodySynthesis(const NamedDecl *D);
+
+ CompilerInstance &CI;
+
+ // FIXME: double memoization is redundant, with memoization both here and in
+ // BodyFarm.
+ llvm::StringMap<Stmt *> Bodies;
+};
+}
+}
+
+#endif
diff --git a/lib/Tooling/ArgumentsAdjusters.cpp b/lib/Tooling/ArgumentsAdjusters.cpp
index a69971e006eb..5a67db0e176f 100644
--- a/lib/Tooling/ArgumentsAdjusters.cpp
+++ b/lib/Tooling/ArgumentsAdjusters.cpp
@@ -19,39 +19,66 @@
namespace clang {
namespace tooling {
-void ArgumentsAdjuster::anchor() {
+/// Add -fsyntax-only option to the commnand line arguments.
+ArgumentsAdjuster getClangSyntaxOnlyAdjuster() {
+ return [](const CommandLineArguments &Args) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t i = 0, e = Args.size(); i != e; ++i) {
+ StringRef Arg = Args[i];
+ // FIXME: Remove options that generate output.
+ if (!Arg.startswith("-fcolor-diagnostics") &&
+ !Arg.startswith("-fdiagnostics-color"))
+ AdjustedArgs.push_back(Args[i]);
+ }
+ AdjustedArgs.push_back("-fsyntax-only");
+ return AdjustedArgs;
+ };
}
-/// Add -fsyntax-only option to the commnand line arguments.
-CommandLineArguments
-ClangSyntaxOnlyAdjuster::Adjust(const CommandLineArguments &Args) {
- CommandLineArguments AdjustedArgs;
- for (size_t i = 0, e = Args.size(); i != e; ++i) {
- StringRef Arg = Args[i];
- // FIXME: Remove options that generate output.
- if (!Arg.startswith("-fcolor-diagnostics") &&
- !Arg.startswith("-fdiagnostics-color"))
- AdjustedArgs.push_back(Args[i]);
- }
- AdjustedArgs.push_back("-fsyntax-only");
- return AdjustedArgs;
+ArgumentsAdjuster getClangStripOutputAdjuster() {
+ return [](const CommandLineArguments &Args) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t i = 0, e = Args.size(); i < e; ++i) {
+ StringRef Arg = Args[i];
+ if (!Arg.startswith("-o"))
+ AdjustedArgs.push_back(Args[i]);
+
+ if (Arg == "-o") {
+ // Output is specified as -o foo. Skip the next argument also.
+ ++i;
+ }
+ // Else, the output is specified as -ofoo. Just do nothing.
+ }
+ return AdjustedArgs;
+ };
}
-CommandLineArguments
-ClangStripOutputAdjuster::Adjust(const CommandLineArguments &Args) {
- CommandLineArguments AdjustedArgs;
- for (size_t i = 0, e = Args.size(); i < e; ++i) {
- StringRef Arg = Args[i];
- if(!Arg.startswith("-o"))
- AdjustedArgs.push_back(Args[i]);
-
- if(Arg == "-o") {
- // Output is specified as -o foo. Skip the next argument also.
- ++i;
+ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra,
+ ArgumentInsertPosition Pos) {
+ return [Extra, Pos](const CommandLineArguments &Args) {
+ CommandLineArguments Return(Args);
+
+ CommandLineArguments::iterator I;
+ if (Pos == ArgumentInsertPosition::END) {
+ I = Return.end();
+ } else {
+ I = Return.begin();
+ ++I; // To leave the program name in place
}
- // Else, the output is specified as -ofoo. Just do nothing.
- }
- return AdjustedArgs;
+
+ Return.insert(I, Extra.begin(), Extra.end());
+ return Return;
+ };
+}
+
+ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra,
+ ArgumentInsertPosition Pos) {
+ return getInsertArgumentAdjuster(CommandLineArguments(1, Extra), Pos);
+}
+
+ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
+ ArgumentsAdjuster Second) {
+ return std::bind(Second, std::bind(First, std::placeholders::_1));
}
} // end namespace tooling
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
index 2bf9652fa376..b5c3d54e5fc1 100644
--- a/lib/Tooling/CMakeLists.txt
+++ b/lib/Tooling/CMakeLists.txt
@@ -1,5 +1,7 @@
set(LLVM_LINK_COMPONENTS support)
+add_subdirectory(Core)
+
add_clang_library(clangTooling
ArgumentsAdjusters.cpp
CommonOptionsParser.cpp
@@ -18,4 +20,5 @@ add_clang_library(clangTooling
clangFrontend
clangLex
clangRewrite
+ clangToolingCore
)
diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp
index e0b844c067d4..91c74a4c3359 100644
--- a/lib/Tooling/CommonOptionsParser.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -25,6 +25,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/CommandLine.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
@@ -53,6 +54,42 @@ const char *const CommonOptionsParser::HelpMessage =
"\tsuffix of a path in the compile command database.\n"
"\n";
+class ArgumentsAdjustingCompilations : public CompilationDatabase {
+public:
+ ArgumentsAdjustingCompilations(
+ std::unique_ptr<CompilationDatabase> Compilations)
+ : Compilations(std::move(Compilations)) {}
+
+ void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) {
+ Adjusters.push_back(Adjuster);
+ }
+
+ std::vector<CompileCommand>
+ getCompileCommands(StringRef FilePath) const override {
+ return adjustCommands(Compilations->getCompileCommands(FilePath));
+ }
+
+ std::vector<std::string> getAllFiles() const override {
+ return Compilations->getAllFiles();
+ }
+
+ std::vector<CompileCommand> getAllCompileCommands() const override {
+ return adjustCommands(Compilations->getAllCompileCommands());
+ }
+
+private:
+ std::unique_ptr<CompilationDatabase> Compilations;
+ std::vector<ArgumentsAdjuster> Adjusters;
+
+ std::vector<CompileCommand>
+ adjustCommands(std::vector<CompileCommand> Commands) const {
+ for (CompileCommand &Command : Commands)
+ for (const auto &Adjuster : Adjusters)
+ Command.CommandLine = Adjuster(Command.CommandLine);
+ return Commands;
+ }
+};
+
CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv,
cl::OptionCategory &Category,
const char *Overview) {
@@ -65,6 +102,16 @@ CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv,
cl::Positional, cl::desc("<source0> [... <sourceN>]"), cl::OneOrMore,
cl::cat(Category));
+ static cl::list<std::string> ArgsAfter(
+ "extra-arg",
+ cl::desc("Additional argument to append to the compiler command line"),
+ cl::cat(Category));
+
+ static cl::list<std::string> ArgsBefore(
+ "extra-arg-before",
+ cl::desc("Additional argument to prepend to the compiler command line"),
+ cl::cat(Category));
+
// Hide unrelated options.
StringMap<cl::Option*> Options;
cl::getRegisteredOptions(Options);
@@ -82,13 +129,21 @@ CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv,
if (!Compilations) {
std::string ErrorMessage;
if (!BuildPath.empty()) {
- Compilations.reset(CompilationDatabase::autoDetectFromDirectory(
- BuildPath, ErrorMessage));
+ Compilations =
+ CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage);
} else {
- Compilations.reset(CompilationDatabase::autoDetectFromSource(
- SourcePaths[0], ErrorMessage));
+ Compilations = CompilationDatabase::autoDetectFromSource(SourcePaths[0],
+ ErrorMessage);
}
if (!Compilations)
llvm::report_fatal_error(ErrorMessage);
}
+ auto AdjustingCompilations =
+ llvm::make_unique<ArgumentsAdjustingCompilations>(
+ std::move(Compilations));
+ AdjustingCompilations->appendArgumentsAdjuster(
+ getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN));
+ AdjustingCompilations->appendArgumentsAdjuster(
+ getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END));
+ Compilations = std::move(AdjustingCompilations);
}
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 4b776bf3c73d..7613988c96d9 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -35,7 +35,7 @@ namespace tooling {
CompilationDatabase::~CompilationDatabase() {}
-CompilationDatabase *
+std::unique_ptr<CompilationDatabase>
CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
std::string &ErrorMessage) {
std::stringstream ErrorStream;
@@ -45,17 +45,16 @@ CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
It != Ie; ++It) {
std::string DatabaseErrorMessage;
std::unique_ptr<CompilationDatabasePlugin> Plugin(It->instantiate());
- if (CompilationDatabase *DB =
- Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
+ if (std::unique_ptr<CompilationDatabase> DB =
+ Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
return DB;
- else
- ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
+ ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
}
ErrorMessage = ErrorStream.str();
return nullptr;
}
-static CompilationDatabase *
+static std::unique_ptr<CompilationDatabase>
findCompilationDatabaseFromDirectory(StringRef Directory,
std::string &ErrorMessage) {
std::stringstream ErrorStream;
@@ -63,8 +62,8 @@ findCompilationDatabaseFromDirectory(StringRef Directory,
while (!Directory.empty()) {
std::string LoadErrorMessage;
- if (CompilationDatabase *DB =
- CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
+ if (std::unique_ptr<CompilationDatabase> DB =
+ CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
return DB;
if (!HasErrorMessage) {
@@ -79,14 +78,14 @@ findCompilationDatabaseFromDirectory(StringRef Directory,
return nullptr;
}
-CompilationDatabase *
+std::unique_ptr<CompilationDatabase>
CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
std::string &ErrorMessage) {
SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
- CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory,
- ErrorMessage);
+ std::unique_ptr<CompilationDatabase> DB =
+ findCompilationDatabaseFromDirectory(Directory, ErrorMessage);
if (!DB)
ErrorMessage = ("Could not auto-detect compilation database for file \"" +
@@ -94,13 +93,13 @@ CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
return DB;
}
-CompilationDatabase *
+std::unique_ptr<CompilationDatabase>
CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
std::string &ErrorMessage) {
SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
- CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath,
- ErrorMessage);
+ std::unique_ptr<CompilationDatabase> DB =
+ findCompilationDatabaseFromDirectory(AbsolutePath, ErrorMessage);
if (!DB)
ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
@@ -250,14 +249,13 @@ static bool stripPositionalArgs(std::vector<const char *> Args,
CompileJobAnalyzer CompileAnalyzer;
- for (driver::JobList::const_iterator I = Jobs.begin(), E = Jobs.end(); I != E;
- ++I) {
- if ((*I)->getKind() == driver::Job::CommandClass) {
- const driver::Command *Cmd = cast<driver::Command>(*I);
+ for (const auto &Job : Jobs) {
+ if (Job.getKind() == driver::Job::CommandClass) {
+ const driver::Command &Cmd = cast<driver::Command>(Job);
// Collect only for Assemble jobs. If we do all jobs we get duplicates
// since Link jobs point to Assemble jobs as inputs.
- if (Cmd->getSource().getKind() == driver::Action::AssembleJobClass)
- CompileAnalyzer.run(&Cmd->getSource());
+ if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass)
+ CompileAnalyzer.run(&Cmd.getSource());
}
}
diff --git a/lib/Tooling/Core/CMakeLists.txt b/lib/Tooling/Core/CMakeLists.txt
new file mode 100644
index 000000000000..c8c75f95f3cb
--- /dev/null
+++ b/lib/Tooling/Core/CMakeLists.txt
@@ -0,0 +1,10 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangToolingCore
+ Replacement.cpp
+
+ LINK_LIBS
+ clangBasic
+ clangLex
+ clangRewrite
+ )
diff --git a/lib/Tooling/Core/Makefile b/lib/Tooling/Core/Makefile
new file mode 100644
index 000000000000..366466c192e4
--- /dev/null
+++ b/lib/Tooling/Core/Makefile
@@ -0,0 +1,13 @@
+##===- clang/lib/Tooling/Core/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 := clangToolingCore
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Tooling/Core/Replacement.cpp b/lib/Tooling/Core/Replacement.cpp
new file mode 100644
index 000000000000..525f7dfa91c6
--- /dev/null
+++ b/lib/Tooling/Core/Replacement.cpp
@@ -0,0 +1,289 @@
+//===--- Replacement.cpp - Framework for clang refactoring tools ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements classes to support/store refactorings.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_os_ostream.h"
+
+namespace clang {
+namespace tooling {
+
+static const char * const InvalidLocation = "";
+
+Replacement::Replacement()
+ : FilePath(InvalidLocation) {}
+
+Replacement::Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
+ StringRef ReplacementText)
+ : FilePath(FilePath), ReplacementRange(Offset, Length),
+ ReplacementText(ReplacementText) {}
+
+Replacement::Replacement(const SourceManager &Sources, SourceLocation Start,
+ unsigned Length, StringRef ReplacementText) {
+ setFromSourceLocation(Sources, Start, Length, ReplacementText);
+}
+
+Replacement::Replacement(const SourceManager &Sources,
+ const CharSourceRange &Range,
+ StringRef ReplacementText) {
+ setFromSourceRange(Sources, Range, ReplacementText);
+}
+
+bool Replacement::isApplicable() const {
+ return FilePath != InvalidLocation;
+}
+
+bool Replacement::apply(Rewriter &Rewrite) const {
+ SourceManager &SM = Rewrite.getSourceMgr();
+ const FileEntry *Entry = SM.getFileManager().getFile(FilePath);
+ if (!Entry)
+ return false;
+ FileID ID;
+ // FIXME: Use SM.translateFile directly.
+ SourceLocation Location = SM.translateFileLineCol(Entry, 1, 1);
+ ID = Location.isValid() ?
+ SM.getFileID(Location) :
+ SM.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
+ // FIXME: We cannot check whether Offset + Length is in the file, as
+ // the remapping API is not public in the RewriteBuffer.
+ const SourceLocation Start =
+ SM.getLocForStartOfFile(ID).
+ getLocWithOffset(ReplacementRange.getOffset());
+ // ReplaceText returns false on success.
+ // ReplaceText only fails if the source location is not a file location, in
+ // which case we already returned false earlier.
+ bool RewriteSucceeded = !Rewrite.ReplaceText(
+ Start, ReplacementRange.getLength(), ReplacementText);
+ assert(RewriteSucceeded);
+ return RewriteSucceeded;
+}
+
+std::string Replacement::toString() const {
+ std::string result;
+ llvm::raw_string_ostream stream(result);
+ stream << FilePath << ": " << ReplacementRange.getOffset() << ":+"
+ << ReplacementRange.getLength() << ":\"" << ReplacementText << "\"";
+ return result;
+}
+
+bool operator<(const Replacement &LHS, const Replacement &RHS) {
+ if (LHS.getOffset() != RHS.getOffset())
+ return LHS.getOffset() < RHS.getOffset();
+ if (LHS.getLength() != RHS.getLength())
+ return LHS.getLength() < RHS.getLength();
+ if (LHS.getFilePath() != RHS.getFilePath())
+ return LHS.getFilePath() < RHS.getFilePath();
+ return LHS.getReplacementText() < RHS.getReplacementText();
+}
+
+bool operator==(const Replacement &LHS, const Replacement &RHS) {
+ return LHS.getOffset() == RHS.getOffset() &&
+ LHS.getLength() == RHS.getLength() &&
+ LHS.getFilePath() == RHS.getFilePath() &&
+ LHS.getReplacementText() == RHS.getReplacementText();
+}
+
+void Replacement::setFromSourceLocation(const SourceManager &Sources,
+ SourceLocation Start, unsigned Length,
+ StringRef ReplacementText) {
+ const std::pair<FileID, unsigned> DecomposedLocation =
+ Sources.getDecomposedLoc(Start);
+ const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
+ if (Entry) {
+ // Make FilePath absolute so replacements can be applied correctly when
+ // relative paths for files are used.
+ llvm::SmallString<256> FilePath(Entry->getName());
+ std::error_code EC = llvm::sys::fs::make_absolute(FilePath);
+ this->FilePath = EC ? FilePath.c_str() : Entry->getName();
+ } else {
+ this->FilePath = InvalidLocation;
+ }
+ this->ReplacementRange = Range(DecomposedLocation.second, Length);
+ this->ReplacementText = ReplacementText;
+}
+
+// FIXME: This should go into the Lexer, but we need to figure out how
+// to handle ranges for refactoring in general first - there is no obvious
+// good way how to integrate this into the Lexer yet.
+static int getRangeSize(const SourceManager &Sources,
+ const CharSourceRange &Range) {
+ SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin());
+ SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd());
+ std::pair<FileID, unsigned> Start = Sources.getDecomposedLoc(SpellingBegin);
+ std::pair<FileID, unsigned> End = Sources.getDecomposedLoc(SpellingEnd);
+ if (Start.first != End.first) return -1;
+ if (Range.isTokenRange())
+ End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources,
+ LangOptions());
+ return End.second - Start.second;
+}
+
+void Replacement::setFromSourceRange(const SourceManager &Sources,
+ const CharSourceRange &Range,
+ StringRef ReplacementText) {
+ setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
+ getRangeSize(Sources, Range), ReplacementText);
+}
+
+unsigned shiftedCodePosition(const Replacements &Replaces, unsigned Position) {
+ unsigned NewPosition = Position;
+ for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
+ ++I) {
+ if (I->getOffset() >= Position)
+ break;
+ if (I->getOffset() + I->getLength() > Position)
+ NewPosition += I->getOffset() + I->getLength() - Position;
+ NewPosition += I->getReplacementText().size() - I->getLength();
+ }
+ return NewPosition;
+}
+
+// FIXME: Remove this function when Replacements is implemented as std::vector
+// instead of std::set.
+unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
+ unsigned Position) {
+ unsigned NewPosition = Position;
+ for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
+ E = Replaces.end();
+ I != E; ++I) {
+ if (I->getOffset() >= Position)
+ break;
+ if (I->getOffset() + I->getLength() > Position)
+ NewPosition += I->getOffset() + I->getLength() - Position;
+ NewPosition += I->getReplacementText().size() - I->getLength();
+ }
+ return NewPosition;
+}
+
+void deduplicate(std::vector<Replacement> &Replaces,
+ std::vector<Range> &Conflicts) {
+ if (Replaces.empty())
+ return;
+
+ auto LessNoPath = [](const Replacement &LHS, const Replacement &RHS) {
+ if (LHS.getOffset() != RHS.getOffset())
+ return LHS.getOffset() < RHS.getOffset();
+ if (LHS.getLength() != RHS.getLength())
+ return LHS.getLength() < RHS.getLength();
+ return LHS.getReplacementText() < RHS.getReplacementText();
+ };
+
+ auto EqualNoPath = [](const Replacement &LHS, const Replacement &RHS) {
+ return LHS.getOffset() == RHS.getOffset() &&
+ LHS.getLength() == RHS.getLength() &&
+ LHS.getReplacementText() == RHS.getReplacementText();
+ };
+
+ // Deduplicate. We don't want to deduplicate based on the path as we assume
+ // that all replacements refer to the same file (or are symlinks).
+ std::sort(Replaces.begin(), Replaces.end(), LessNoPath);
+ Replaces.erase(std::unique(Replaces.begin(), Replaces.end(), EqualNoPath),
+ Replaces.end());
+
+ // Detect conflicts
+ Range ConflictRange(Replaces.front().getOffset(),
+ Replaces.front().getLength());
+ unsigned ConflictStart = 0;
+ unsigned ConflictLength = 1;
+ for (unsigned i = 1; i < Replaces.size(); ++i) {
+ Range Current(Replaces[i].getOffset(), Replaces[i].getLength());
+ if (ConflictRange.overlapsWith(Current)) {
+ // Extend conflicted range
+ ConflictRange = Range(ConflictRange.getOffset(),
+ std::max(ConflictRange.getLength(),
+ Current.getOffset() + Current.getLength() -
+ ConflictRange.getOffset()));
+ ++ConflictLength;
+ } else {
+ if (ConflictLength > 1)
+ Conflicts.push_back(Range(ConflictStart, ConflictLength));
+ ConflictRange = Current;
+ ConflictStart = i;
+ ConflictLength = 1;
+ }
+ }
+
+ if (ConflictLength > 1)
+ Conflicts.push_back(Range(ConflictStart, ConflictLength));
+}
+
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
+ bool Result = true;
+ for (Replacements::const_iterator I = Replaces.begin(),
+ E = Replaces.end();
+ I != E; ++I) {
+ if (I->isApplicable()) {
+ Result = I->apply(Rewrite) && Result;
+ } else {
+ Result = false;
+ }
+ }
+ return Result;
+}
+
+// FIXME: Remove this function when Replacements is implemented as std::vector
+// instead of std::set.
+bool applyAllReplacements(const std::vector<Replacement> &Replaces,
+ Rewriter &Rewrite) {
+ bool Result = true;
+ for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
+ E = Replaces.end();
+ I != E; ++I) {
+ if (I->isApplicable()) {
+ Result = I->apply(Rewrite) && Result;
+ } else {
+ Result = false;
+ }
+ }
+ return Result;
+}
+
+std::string applyAllReplacements(StringRef Code, const Replacements &Replaces) {
+ FileManager Files((FileSystemOptions()));
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ new DiagnosticOptions);
+ SourceManager SourceMgr(Diagnostics, Files);
+ Rewriter Rewrite(SourceMgr, LangOptions());
+ std::unique_ptr<llvm::MemoryBuffer> Buf =
+ llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>");
+ const clang::FileEntry *Entry =
+ Files.getVirtualFile("<stdin>", Buf->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(Entry, std::move(Buf));
+ FileID ID =
+ SourceMgr.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User);
+ for (Replacements::const_iterator I = Replaces.begin(), E = Replaces.end();
+ I != E; ++I) {
+ Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
+ I->getReplacementText());
+ if (!Replace.apply(Rewrite))
+ return "";
+ }
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ Rewrite.getEditBuffer(ID).write(OS);
+ OS.flush();
+ return Result;
+}
+
+} // end namespace tooling
+} // end namespace clang
+
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
index 8b8bd293851f..3b5f7e28d02d 100644
--- a/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -118,15 +118,15 @@ std::vector<std::string> unescapeCommandLine(
}
class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
- CompilationDatabase *loadFromDirectory(StringRef Directory,
- std::string &ErrorMessage) override {
+ std::unique_ptr<CompilationDatabase>
+ loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
SmallString<1024> JSONDatabasePath(Directory);
llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
std::unique_ptr<CompilationDatabase> Database(
JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
if (!Database)
return nullptr;
- return Database.release();
+ return Database;
}
};
@@ -141,7 +141,7 @@ X("json-compilation-database", "Reads JSON formatted compilation databases");
// and thus register the JSONCompilationDatabasePlugin.
volatile int JSONAnchorSource = 0;
-JSONCompilationDatabase *
+std::unique_ptr<JSONCompilationDatabase>
JSONCompilationDatabase::loadFromFile(StringRef FilePath,
std::string &ErrorMessage) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
@@ -151,22 +151,22 @@ JSONCompilationDatabase::loadFromFile(StringRef FilePath,
return nullptr;
}
std::unique_ptr<JSONCompilationDatabase> Database(
- new JSONCompilationDatabase(DatabaseBuffer->release()));
+ new JSONCompilationDatabase(std::move(*DatabaseBuffer)));
if (!Database->parse(ErrorMessage))
return nullptr;
- return Database.release();
+ return Database;
}
-JSONCompilationDatabase *
+std::unique_ptr<JSONCompilationDatabase>
JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
std::string &ErrorMessage) {
std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
llvm::MemoryBuffer::getMemBuffer(DatabaseString));
std::unique_ptr<JSONCompilationDatabase> Database(
- new JSONCompilationDatabase(DatabaseBuffer.release()));
+ new JSONCompilationDatabase(std::move(DatabaseBuffer)));
if (!Database->parse(ErrorMessage))
return nullptr;
- return Database.release();
+ return Database;
}
std::vector<CompileCommand>
diff --git a/lib/Tooling/Makefile b/lib/Tooling/Makefile
index 0d2e7a29bcf9..7ea85a8908d6 100644
--- a/lib/Tooling/Makefile
+++ b/lib/Tooling/Makefile
@@ -9,5 +9,6 @@
CLANG_LEVEL := ../..
LIBRARYNAME := clangTooling
+PARALLEL_DIRS := Core
include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index c96b8c92a905..c8173060d8c1 100644
--- a/lib/Tooling/Refactoring.cpp
+++ b/lib/Tooling/Refactoring.cpp
@@ -25,252 +25,6 @@
namespace clang {
namespace tooling {
-static const char * const InvalidLocation = "";
-
-Replacement::Replacement()
- : FilePath(InvalidLocation) {}
-
-Replacement::Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
- StringRef ReplacementText)
- : FilePath(FilePath), ReplacementRange(Offset, Length),
- ReplacementText(ReplacementText) {}
-
-Replacement::Replacement(const SourceManager &Sources, SourceLocation Start,
- unsigned Length, StringRef ReplacementText) {
- setFromSourceLocation(Sources, Start, Length, ReplacementText);
-}
-
-Replacement::Replacement(const SourceManager &Sources,
- const CharSourceRange &Range,
- StringRef ReplacementText) {
- setFromSourceRange(Sources, Range, ReplacementText);
-}
-
-bool Replacement::isApplicable() const {
- return FilePath != InvalidLocation;
-}
-
-bool Replacement::apply(Rewriter &Rewrite) const {
- SourceManager &SM = Rewrite.getSourceMgr();
- const FileEntry *Entry = SM.getFileManager().getFile(FilePath);
- if (!Entry)
- return false;
- FileID ID;
- // FIXME: Use SM.translateFile directly.
- SourceLocation Location = SM.translateFileLineCol(Entry, 1, 1);
- ID = Location.isValid() ?
- SM.getFileID(Location) :
- SM.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
- // FIXME: We cannot check whether Offset + Length is in the file, as
- // the remapping API is not public in the RewriteBuffer.
- const SourceLocation Start =
- SM.getLocForStartOfFile(ID).
- getLocWithOffset(ReplacementRange.getOffset());
- // ReplaceText returns false on success.
- // ReplaceText only fails if the source location is not a file location, in
- // which case we already returned false earlier.
- bool RewriteSucceeded = !Rewrite.ReplaceText(
- Start, ReplacementRange.getLength(), ReplacementText);
- assert(RewriteSucceeded);
- return RewriteSucceeded;
-}
-
-std::string Replacement::toString() const {
- std::string result;
- llvm::raw_string_ostream stream(result);
- stream << FilePath << ": " << ReplacementRange.getOffset() << ":+"
- << ReplacementRange.getLength() << ":\"" << ReplacementText << "\"";
- return result;
-}
-
-bool operator<(const Replacement &LHS, const Replacement &RHS) {
- if (LHS.getOffset() != RHS.getOffset())
- return LHS.getOffset() < RHS.getOffset();
- if (LHS.getLength() != RHS.getLength())
- return LHS.getLength() < RHS.getLength();
- if (LHS.getFilePath() != RHS.getFilePath())
- return LHS.getFilePath() < RHS.getFilePath();
- return LHS.getReplacementText() < RHS.getReplacementText();
-}
-
-bool operator==(const Replacement &LHS, const Replacement &RHS) {
- return LHS.getOffset() == RHS.getOffset() &&
- LHS.getLength() == RHS.getLength() &&
- LHS.getFilePath() == RHS.getFilePath() &&
- LHS.getReplacementText() == RHS.getReplacementText();
-}
-
-void Replacement::setFromSourceLocation(const SourceManager &Sources,
- SourceLocation Start, unsigned Length,
- StringRef ReplacementText) {
- const std::pair<FileID, unsigned> DecomposedLocation =
- Sources.getDecomposedLoc(Start);
- const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
- if (Entry) {
- // Make FilePath absolute so replacements can be applied correctly when
- // relative paths for files are used.
- llvm::SmallString<256> FilePath(Entry->getName());
- std::error_code EC = llvm::sys::fs::make_absolute(FilePath);
- this->FilePath = EC ? FilePath.c_str() : Entry->getName();
- } else {
- this->FilePath = InvalidLocation;
- }
- this->ReplacementRange = Range(DecomposedLocation.second, Length);
- this->ReplacementText = ReplacementText;
-}
-
-// FIXME: This should go into the Lexer, but we need to figure out how
-// to handle ranges for refactoring in general first - there is no obvious
-// good way how to integrate this into the Lexer yet.
-static int getRangeSize(const SourceManager &Sources,
- const CharSourceRange &Range) {
- SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin());
- SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd());
- std::pair<FileID, unsigned> Start = Sources.getDecomposedLoc(SpellingBegin);
- std::pair<FileID, unsigned> End = Sources.getDecomposedLoc(SpellingEnd);
- if (Start.first != End.first) return -1;
- if (Range.isTokenRange())
- End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources,
- LangOptions());
- return End.second - Start.second;
-}
-
-void Replacement::setFromSourceRange(const SourceManager &Sources,
- const CharSourceRange &Range,
- StringRef ReplacementText) {
- setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
- getRangeSize(Sources, Range), ReplacementText);
-}
-
-bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
- bool Result = true;
- for (Replacements::const_iterator I = Replaces.begin(),
- E = Replaces.end();
- I != E; ++I) {
- if (I->isApplicable()) {
- Result = I->apply(Rewrite) && Result;
- } else {
- Result = false;
- }
- }
- return Result;
-}
-
-// FIXME: Remove this function when Replacements is implemented as std::vector
-// instead of std::set.
-bool applyAllReplacements(const std::vector<Replacement> &Replaces,
- Rewriter &Rewrite) {
- bool Result = true;
- for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
- E = Replaces.end();
- I != E; ++I) {
- if (I->isApplicable()) {
- Result = I->apply(Rewrite) && Result;
- } else {
- Result = false;
- }
- }
- return Result;
-}
-
-std::string applyAllReplacements(StringRef Code, const Replacements &Replaces) {
- FileManager Files((FileSystemOptions()));
- DiagnosticsEngine Diagnostics(
- IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
- new DiagnosticOptions);
- Diagnostics.setClient(new TextDiagnosticPrinter(
- llvm::outs(), &Diagnostics.getDiagnosticOptions()));
- SourceManager SourceMgr(Diagnostics, Files);
- Rewriter Rewrite(SourceMgr, LangOptions());
- llvm::MemoryBuffer *Buf = llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>");
- const clang::FileEntry *Entry =
- Files.getVirtualFile("<stdin>", Buf->getBufferSize(), 0);
- SourceMgr.overrideFileContents(Entry, Buf);
- FileID ID =
- SourceMgr.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User);
- for (Replacements::const_iterator I = Replaces.begin(), E = Replaces.end();
- I != E; ++I) {
- Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
- I->getReplacementText());
- if (!Replace.apply(Rewrite))
- return "";
- }
- std::string Result;
- llvm::raw_string_ostream OS(Result);
- Rewrite.getEditBuffer(ID).write(OS);
- OS.flush();
- return Result;
-}
-
-unsigned shiftedCodePosition(const Replacements &Replaces, unsigned Position) {
- unsigned NewPosition = Position;
- for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
- ++I) {
- if (I->getOffset() >= Position)
- break;
- if (I->getOffset() + I->getLength() > Position)
- NewPosition += I->getOffset() + I->getLength() - Position;
- NewPosition += I->getReplacementText().size() - I->getLength();
- }
- return NewPosition;
-}
-
-// FIXME: Remove this function when Replacements is implemented as std::vector
-// instead of std::set.
-unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
- unsigned Position) {
- unsigned NewPosition = Position;
- for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
- E = Replaces.end();
- I != E; ++I) {
- if (I->getOffset() >= Position)
- break;
- if (I->getOffset() + I->getLength() > Position)
- NewPosition += I->getOffset() + I->getLength() - Position;
- NewPosition += I->getReplacementText().size() - I->getLength();
- }
- return NewPosition;
-}
-
-void deduplicate(std::vector<Replacement> &Replaces,
- std::vector<Range> &Conflicts) {
- if (Replaces.empty())
- return;
-
- // Deduplicate
- std::sort(Replaces.begin(), Replaces.end());
- std::vector<Replacement>::iterator End =
- std::unique(Replaces.begin(), Replaces.end());
- Replaces.erase(End, Replaces.end());
-
- // Detect conflicts
- Range ConflictRange(Replaces.front().getOffset(),
- Replaces.front().getLength());
- unsigned ConflictStart = 0;
- unsigned ConflictLength = 1;
- for (unsigned i = 1; i < Replaces.size(); ++i) {
- Range Current(Replaces[i].getOffset(), Replaces[i].getLength());
- if (ConflictRange.overlapsWith(Current)) {
- // Extend conflicted range
- ConflictRange = Range(ConflictRange.getOffset(),
- std::max(ConflictRange.getLength(),
- Current.getOffset() + Current.getLength() -
- ConflictRange.getOffset()));
- ++ConflictLength;
- } else {
- if (ConflictLength > 1)
- Conflicts.push_back(Range(ConflictStart, ConflictLength));
- ConflictRange = Current;
- ConflictStart = i;
- ConflictLength = 1;
- }
- }
-
- if (ConflictLength > 1)
- Conflicts.push_back(Range(ConflictStart, ConflictLength));
-}
-
-
RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths)
: ClangTool(Compilations, SourcePaths) {}
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index 0db38db3c91e..60371fb5e0e6 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -79,14 +79,14 @@ static const llvm::opt::ArgStringList *getCC1Arguments(
}
// The one job we find should be to invoke clang again.
- const clang::driver::Command *Cmd =
+ const clang::driver::Command &Cmd =
cast<clang::driver::Command>(*Jobs.begin());
- if (StringRef(Cmd->getCreator().getName()) != "clang") {
+ if (StringRef(Cmd.getCreator().getName()) != "clang") {
Diagnostics->Report(clang::diag::err_fe_expected_clang_command);
return nullptr;
}
- return &Cmd->getArguments();
+ return &Cmd.getArguments();
}
/// \brief Returns a clang build invocation initialized from the CC1 flags.
@@ -123,17 +123,25 @@ getSyntaxOnlyToolArgs(const std::vector<std::string> &ExtraArgs,
bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
const std::vector<std::string> &Args,
- const Twine &FileName) {
+ const Twine &FileName,
+ const FileContentMappings &VirtualMappedFiles) {
+
SmallString<16> FileNameStorage;
StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
llvm::IntrusiveRefCntPtr<FileManager> Files(
new FileManager(FileSystemOptions()));
- ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction,
- Files.get());
+ ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef),
+ ToolAction, Files.get());
SmallString<1024> CodeStorage;
Invocation.mapVirtualFile(FileNameRef,
Code.toNullTerminatedStringRef(CodeStorage));
+
+ for (auto &FilenameWithContent : VirtualMappedFiles) {
+ Invocation.mapVirtualFile(FilenameWithContent.first,
+ FilenameWithContent.second);
+ }
+
return Invocation.run();
}
@@ -186,10 +194,6 @@ ToolInvocation::~ToolInvocation() {
delete Action;
}
-void ToolInvocation::setDiagnosticConsumer(DiagnosticConsumer *D) {
- DiagConsumer = D;
-}
-
void ToolInvocation::mapVirtualFile(StringRef FilePath, StringRef Content) {
SmallString<1024> PathStorage;
llvm::sys::path::native(FilePath, PathStorage);
@@ -223,8 +227,10 @@ bool ToolInvocation::run() {
newInvocation(&Diagnostics, *CC1Args));
for (const auto &It : MappedFileContents) {
// Inject the code as the given file name into the preprocessor options.
- auto *Input = llvm::MemoryBuffer::getMemBuffer(It.getValue());
- Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(), Input);
+ std::unique_ptr<llvm::MemoryBuffer> Input =
+ llvm::MemoryBuffer::getMemBuffer(It.getValue());
+ Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(),
+ Input.release());
}
return runInvocation(BinaryName, Compilation.get(), Invocation.release());
}
@@ -271,51 +277,27 @@ bool FrontendActionFactory::runInvocation(CompilerInvocation *Invocation,
ClangTool::ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths)
- : Files(new FileManager(FileSystemOptions())), DiagConsumer(nullptr) {
- ArgsAdjusters.push_back(new ClangStripOutputAdjuster());
- ArgsAdjusters.push_back(new ClangSyntaxOnlyAdjuster());
- for (const auto &SourcePath : SourcePaths) {
- std::string File(getAbsolutePath(SourcePath));
-
- std::vector<CompileCommand> CompileCommandsForFile =
- Compilations.getCompileCommands(File);
- if (!CompileCommandsForFile.empty()) {
- for (CompileCommand &CompileCommand : CompileCommandsForFile) {
- CompileCommands.push_back(
- std::make_pair(File, std::move(CompileCommand)));
- }
- } else {
- // FIXME: There are two use cases here: doing a fuzzy
- // "find . -name '*.cc' |xargs tool" match, where as a user I don't care
- // about the .cc files that were not found, and the use case where I
- // specify all files I want to run over explicitly, where this should
- // be an error. We'll want to add an option for this.
- llvm::errs() << "Skipping " << File << ". Compile command not found.\n";
- }
- }
+ : Compilations(Compilations), SourcePaths(SourcePaths),
+ Files(new FileManager(FileSystemOptions())), DiagConsumer(nullptr) {
+ appendArgumentsAdjuster(getClangStripOutputAdjuster());
+ appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
}
-void ClangTool::setDiagnosticConsumer(DiagnosticConsumer *D) {
- DiagConsumer = D;
-}
+ClangTool::~ClangTool() {}
void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) {
MappedFileContents.push_back(std::make_pair(FilePath, Content));
}
-void ClangTool::setArgumentsAdjuster(ArgumentsAdjuster *Adjuster) {
- clearArgumentsAdjusters();
- appendArgumentsAdjuster(Adjuster);
-}
-
-void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster *Adjuster) {
- ArgsAdjusters.push_back(Adjuster);
+void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) {
+ if (ArgsAdjuster)
+ ArgsAdjuster = combineAdjusters(ArgsAdjuster, Adjuster);
+ else
+ ArgsAdjuster = Adjuster;
}
void ClangTool::clearArgumentsAdjusters() {
- for (unsigned I = 0, E = ArgsAdjusters.size(); I != E; ++I)
- delete ArgsAdjusters[I];
- ArgsAdjusters.clear();
+ ArgsAdjuster = nullptr;
}
int ClangTool::run(ToolAction *Action) {
@@ -330,37 +312,65 @@ int ClangTool::run(ToolAction *Action) {
std::string MainExecutable =
llvm::sys::fs::getMainExecutable("clang_tool", &StaticSymbol);
+ llvm::SmallString<128> InitialDirectory;
+ if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
+ llvm::report_fatal_error("Cannot detect current path: " +
+ Twine(EC.message()));
bool ProcessingFailed = false;
- for (const auto &Command : CompileCommands) {
- // FIXME: chdir is thread hostile; on the other hand, creating the same
- // behavior as chdir is complex: chdir resolves the path once, thus
- // guaranteeing that all subsequent relative path operations work
- // on the same path the original chdir resulted in. This makes a difference
- // for example on network filesystems, where symlinks might be switched
- // during runtime of the tool. Fixing this depends on having a file system
- // abstraction that allows openat() style interactions.
- if (chdir(Command.second.Directory.c_str()))
- llvm::report_fatal_error("Cannot chdir into \"" +
- Twine(Command.second.Directory) + "\n!");
- std::vector<std::string> CommandLine = Command.second.CommandLine;
- for (ArgumentsAdjuster *Adjuster : ArgsAdjusters)
- CommandLine = Adjuster->Adjust(CommandLine);
- assert(!CommandLine.empty());
- CommandLine[0] = MainExecutable;
- // FIXME: We need a callback mechanism for the tool writer to output a
- // customized message for each file.
- DEBUG({
- llvm::dbgs() << "Processing: " << Command.first << ".\n";
- });
- ToolInvocation Invocation(std::move(CommandLine), Action, Files.get());
- Invocation.setDiagnosticConsumer(DiagConsumer);
- for (const auto &MappedFile : MappedFileContents) {
- Invocation.mapVirtualFile(MappedFile.first, MappedFile.second);
+ for (const auto &SourcePath : SourcePaths) {
+ std::string File(getAbsolutePath(SourcePath));
+
+ // Currently implementations of CompilationDatabase::getCompileCommands can
+ // change the state of the file system (e.g. prepare generated headers), so
+ // this method needs to run right before we invoke the tool, as the next
+ // file may require a different (incompatible) state of the file system.
+ //
+ // FIXME: Make the compilation database interface more explicit about the
+ // requirements to the order of invocation of its members.
+ std::vector<CompileCommand> CompileCommandsForFile =
+ Compilations.getCompileCommands(File);
+ if (CompileCommandsForFile.empty()) {
+ // FIXME: There are two use cases here: doing a fuzzy
+ // "find . -name '*.cc' |xargs tool" match, where as a user I don't care
+ // about the .cc files that were not found, and the use case where I
+ // specify all files I want to run over explicitly, where this should
+ // be an error. We'll want to add an option for this.
+ llvm::errs() << "Skipping " << File << ". Compile command not found.\n";
+ continue;
}
- if (!Invocation.run()) {
- // FIXME: Diagnostics should be used instead.
- llvm::errs() << "Error while processing " << Command.first << ".\n";
- ProcessingFailed = true;
+ for (CompileCommand &CompileCommand : CompileCommandsForFile) {
+ // FIXME: chdir is thread hostile; on the other hand, creating the same
+ // behavior as chdir is complex: chdir resolves the path once, thus
+ // guaranteeing that all subsequent relative path operations work
+ // on the same path the original chdir resulted in. This makes a
+ // difference for example on network filesystems, where symlinks might be
+ // switched during runtime of the tool. Fixing this depends on having a
+ // file system abstraction that allows openat() style interactions.
+ if (chdir(CompileCommand.Directory.c_str()))
+ llvm::report_fatal_error("Cannot chdir into \"" +
+ Twine(CompileCommand.Directory) + "\n!");
+ std::vector<std::string> CommandLine = CompileCommand.CommandLine;
+ if (ArgsAdjuster)
+ CommandLine = ArgsAdjuster(CommandLine);
+ assert(!CommandLine.empty());
+ CommandLine[0] = MainExecutable;
+ // FIXME: We need a callback mechanism for the tool writer to output a
+ // customized message for each file.
+ DEBUG({ llvm::dbgs() << "Processing: " << File << ".\n"; });
+ ToolInvocation Invocation(std::move(CommandLine), Action, Files.get());
+ Invocation.setDiagnosticConsumer(DiagConsumer);
+ for (const auto &MappedFile : MappedFileContents)
+ Invocation.mapVirtualFile(MappedFile.first, MappedFile.second);
+ if (!Invocation.run()) {
+ // FIXME: Diagnostics should be used instead.
+ llvm::errs() << "Error while processing " << File << ".\n";
+ ProcessingFailed = true;
+ }
+ // Return to the initial directory to correctly resolve next file by
+ // relative path.
+ if (chdir(InitialDirectory.c_str()))
+ llvm::report_fatal_error("Cannot chdir into \"" +
+ Twine(InitialDirectory) + "\n!");
}
}
return ProcessingFailed ? 1 : 0;
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index dc14541323ad..ad383f6cf7e0 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -87,8 +87,8 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
FileCheck count not llvm-nm llvm-symbolizer)
# Add top-level targets for various compiler-rt test suites.
- set(COMPILER_RT_TEST_SUITES check-asan check-dfsan check-lsan check-msan
- check-sanitizer check-tsan check-ubsan)
+ set(COMPILER_RT_TEST_SUITES check-asan check-asan-dynamic check-dfsan
+ check-lsan check-msan check-sanitizer check-tsan check-ubsan)
foreach(test_suite ${COMPILER_RT_TEST_SUITES})
get_ext_project_build_command(run_test_suite ${test_suite})
add_custom_target(${test_suite}
diff --git a/runtime/compiler-rt/Makefile b/runtime/compiler-rt/Makefile
index ccd83a357048..f06ef990f8e5 100644
--- a/runtime/compiler-rt/Makefile
+++ b/runtime/compiler-rt/Makefile
@@ -27,10 +27,6 @@ ResourceIncludeDir := $(ResourceDir)/include
PROJ_resources_lib := $(PROJ_resources)/lib
PROJ_resources_include := $(PROJ_resources)/include
-# Initialize a variable to use for extra flags to pass to the
-# compiler-rt make process.
-COMPILERRT_MAKE_FLAGS :=
-
# Expect compiler-rt to be in llvm/projects/compiler-rt
COMPILERRT_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/compiler-rt
@@ -80,32 +76,32 @@ RuntimeDirs :=
ifeq ($(OS),Darwin)
RuntimeDirs += darwin macho_embedded
RuntimeLibrary.darwin.Configs := \
- eprintf.a 10.4.a osx.a ios.a cc_kext.a cc_kext_ios5.a \
+ eprintf.a 10.4.a osx.a cc_kext.a \
asan_osx_dynamic.dylib \
- profile_osx.a profile_ios.a \
+ profile_osx.a \
ubsan_osx.a
-RuntimeLibrary.macho_embedded.Configs := \
- hard_static.a hard_pic.a
-ifneq (,$(findstring ARM,$(TARGETS_TO_BUILD)))
-RuntimeLibrary.macho_embedded.Configs += \
- soft_static.a soft_pic.a
+IOS_SDK := $(shell xcrun --show-sdk-path -sdk iphoneos 2> /dev/null)
+IOSSIM_SDK := $(shell xcrun --show-sdk-path -sdk iphonesimulator 2> /dev/null)
+
+ifneq ($(IOS_SDK)$(IOSSIM_SDK),)
+RuntimeLibrary.darwin.Configs += ios.a profile_ios.a
endif
-# Support building compiler-rt with relocatable SDKs.
-#
-# This will cause make to put SDKROOT in the environment, and since we
-# are using the built Clang to build compiler-rt, it to pick up that
-# location as the default value for the include system root.
-ACTIVE_SDK_PATH := $(shell xcrun --show-sdk-path 2> /dev/null)
-ifneq ($(ACTIVE_SDK_PATH),)
-COMPILERRT_MAKE_FLAGS := SDKROOT=$(ACTIVE_SDK_PATH)
+ifneq ($(IOS_SDK),)
+RuntimeLibrary.darwin.Configs += cc_kext_ios5.a
endif
-IOSSIM_SDK_PATH := $(shell xcrun --show-sdk-path -sdk iphonesimulator 2> /dev/null)
-ifneq ($(IOSSIM_SDK_PATH),)
+
+ifneq ($(IOSSIM_SDK),)
RuntimeLibrary.darwin.Configs += asan_iossim_dynamic.dylib
endif
+RuntimeLibrary.macho_embedded.Configs := \
+ hard_static.a hard_pic.a
+ifneq (,$(findstring ARM,$(TARGETS_TO_BUILD)))
+RuntimeLibrary.macho_embedded.Configs += \
+ soft_static.a soft_pic.a
+endif
endif
# On Linux, include a library which has all the runtime functions.
@@ -171,7 +167,6 @@ BuildRuntimeLibraries:
CC="$(ToolDir)/clang" \
VERBOSE=$(VERBOSE) \
LLVM_ANDROID_TOOLCHAIN_DIR="$(LLVM_ANDROID_TOOLCHAIN_DIR)" \
- $(COMPILERRT_MAKE_FLAGS) \
$(RuntimeDirs:%=clang_%)
.PHONY: BuildRuntimeLibraries
CleanRuntimeLibraries:
@@ -179,7 +174,6 @@ CleanRuntimeLibraries:
ProjSrcRoot=$(COMPILERRT_SRC_ROOT) \
ProjObjRoot=$(PROJ_OBJ_DIR) \
VERBOSE=$(VERBOSE) \
- $(COMPILERRT_MAKE_FLAGS) \
clean
.PHONY: CleanRuntimeLibraries
RuntimeHeader: $(ResourceIncludeDir)/sanitizer
@@ -221,8 +215,6 @@ $(ResourceLibDir)/$1/libclang_rt.%.dylib: \
$(ResourceLibDir)/$1/.dir
$(Echo) Copying runtime library $1/$$* to build dir
$(Verb) cp $(PROJ_OBJ_DIR)/clang_$1/$$*/libcompiler_rt.dylib $$@
- $(Echo) Fixing LC_ID_DYLIB of $$@
- $(Verb) install_name_tool $$@ -id $$@
RuntimeLibrary.$1: \
$(RuntimeLibrary.$1.Configs:%=$(ResourceLibDir)/$1/libclang_rt.%)
.PHONY: RuntimeLibrary.$1
diff --git a/test/ARCMT/checking.m b/test/ARCMT/checking.m
index 7815103822a1..6a7cf76c3865 100644
--- a/test/ARCMT/checking.m
+++ b/test/ARCMT/checking.m
@@ -182,7 +182,7 @@ void test6(unsigned cond) {
;
id x; // expected-note {{jump bypasses initialization of retaining variable}}
- case 1: // expected-error {{switch case is in protected scope}}
+ case 1: // expected-error {{cannot jump}}
x = 0;
break;
}
@@ -304,7 +304,7 @@ void rdar9491791(int p) {
// rdar://9504750
void rdar9504750(id p) {
- RELEASE_MACRO(p); // expected-error {{ARC forbids explicit message send of 'release'}}
+ RELEASE_MACRO(p); // expected-error {{ARC forbids explicit message send of 'release'}}
}
// rdar://8939557
diff --git a/test/ARCMT/objcmt-boxing.m b/test/ARCMT/objcmt-boxing.m
index 2ad65a1399db..c4b6f42b1bd5 100644
--- a/test/ARCMT/objcmt-boxing.m
+++ b/test/ARCMT/objcmt-boxing.m
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c++ -verify
+// RUN: %clang_cc1 -fobjc-arc -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c++ -verify
// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c++ %s.result
@@ -68,6 +68,7 @@ typedef NSUInteger NSStringEncoding;
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+ (id)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;
+ (id)stringWithCString:(const char *)bytes;
+- (instancetype)initWithUTF8String:(const char *)nullTerminatedCString;
@end
enum MyEnm {
@@ -99,4 +100,8 @@ void boxString() {
static const char strarr[] = "coolbox";
s = [NSString stringWithUTF8String:strarr];
+ // rdar://18080352
+ const char *utf8Bytes = "blah";
+ NSString *string1 = [NSString stringWithUTF8String:utf8Bytes];
+ NSString *string2 = [[NSString alloc] initWithUTF8String:utf8Bytes];
}
diff --git a/test/ARCMT/objcmt-boxing.m.result b/test/ARCMT/objcmt-boxing.m.result
index f1019892ff37..59fdb88d51a3 100644
--- a/test/ARCMT/objcmt-boxing.m.result
+++ b/test/ARCMT/objcmt-boxing.m.result
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c++ -verify
+// RUN: %clang_cc1 -fobjc-arc -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c++ -verify
// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c++ %s.result
@@ -68,6 +68,7 @@ typedef NSUInteger NSStringEncoding;
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+ (id)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;
+ (id)stringWithCString:(const char *)bytes;
+- (instancetype)initWithUTF8String:(const char *)nullTerminatedCString;
@end
enum MyEnm {
@@ -99,4 +100,8 @@ void boxString() {
static const char strarr[] = "coolbox";
s = @(strarr);
+ // rdar://18080352
+ const char *utf8Bytes = "blah";
+ NSString *string1 = @(utf8Bytes);
+ NSString *string2 = @(utf8Bytes);
}
diff --git a/test/ARCMT/objcmt-ns-macros.m b/test/ARCMT/objcmt-ns-macros.m
index 1bf55d8ed46b..1d5583b92f26 100644
--- a/test/ARCMT/objcmt-ns-macros.m
+++ b/test/ARCMT/objcmt-ns-macros.m
@@ -3,8 +3,17 @@
// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+typedef signed char int8_t;
+typedef short int16_t;
+typedef int int32_t;
typedef long NSInteger;
+typedef long long int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
typedef unsigned long NSUInteger;
+typedef unsigned long long uint64_t;
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
@@ -294,3 +303,63 @@ enum {
NSWindowToolbarButton,
NSWindowDocumentIconButton
};
+
+// rdar://18262255
+typedef enum : NSUInteger {
+ ThingOne,
+ ThingTwo,
+ ThingThree,
+} Thing;
+
+// rdar://18498539
+typedef enum {
+ one = 1
+} NumericEnum;
+
+typedef enum {
+ Two = 2
+}NumericEnum2;
+
+typedef enum {
+ Three = 3
+}
+NumericEnum3;
+
+typedef enum {
+ Four = 4
+}
+
+ NumericEnum4;
+
+// rdar://18532199
+enum
+{
+ UI8one = 1
+};
+typedef int8_t MyEnumeratedType;
+
+
+enum {
+ UI16One = 0,
+ UI16Two = 0x1,
+ UI16three = 0x8,
+ UI16Four = 0x100
+};
+typedef int16_t UI16;
+
+enum {
+ UI32ViewAutoresizingNone = 0,
+ UI32ViewAutoresizingFlexibleLeftMargin,
+ UI32ViewAutoresizingFlexibleWidth,
+ UI32ViewAutoresizingFlexibleRightMargin,
+ UI32ViewAutoresizingFlexibleTopMargin,
+ UI32ViewAutoresizingFlexibleHeight,
+ UI32ViewAutoresizingFlexibleBottomMargin
+};
+typedef uint32_t UI32TableViewCellStyle;
+
+enum
+{
+ UIU8one = 1
+};
+typedef uint8_t UI8Type;
diff --git a/test/ARCMT/objcmt-ns-macros.m.result b/test/ARCMT/objcmt-ns-macros.m.result
index 0b640ac35676..63eec7d37ede 100644
--- a/test/ARCMT/objcmt-ns-macros.m.result
+++ b/test/ARCMT/objcmt-ns-macros.m.result
@@ -3,13 +3,25 @@
// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+typedef signed char int8_t;
+typedef short int16_t;
+typedef int int32_t;
typedef long NSInteger;
+typedef long long int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
typedef unsigned long NSUInteger;
+typedef unsigned long long uint64_t;
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
#define DEPRECATED __attribute__((deprecated))
+#ifndef NS_ENUM
+#import <Foundation/Foundation.h>
+#endif
typedef NS_ENUM(NSInteger, wibble) {
blah,
blarg
@@ -25,15 +37,15 @@ typedef NS_ENUM(NSUInteger, UITableViewCellStyle) {
UIViewAutoresizingFlexibleBottomMargin
};
-typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
+typedef NS_ENUM(unsigned int, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
-} ;
+};
-typedef NS_OPTIONS(NSUInteger, UITableView) {
+typedef NS_OPTIONS(unsigned int, UITableView) {
UIViewOne = 0,
UIViewTwo = 1 << 0,
UIViewThree = 1 << 1,
@@ -41,7 +53,7 @@ typedef NS_OPTIONS(NSUInteger, UITableView) {
UIViewFive = 1 << 3,
UIViewSix = 1 << 4,
UIViewSeven = 1 << 5
-} ;
+};
typedef NS_OPTIONS(NSUInteger, UI) {
UIOne = 0,
@@ -50,12 +62,12 @@ typedef NS_OPTIONS(NSUInteger, UI) {
UIFour = 0x100
};
-typedef NS_OPTIONS(NSUInteger, UIPOWER2) {
+typedef NS_OPTIONS(unsigned int, UIPOWER2) {
UIP2One = 0,
UIP2Two = 0x1,
UIP2three = 0x8,
UIP2Four = 0x100
-} ;
+};
enum {
UNOne,
@@ -68,12 +80,12 @@ typedef NS_ENUM(NSInteger, UIK) {
UIKTwo = 2,
};
-typedef NS_ENUM(NSInteger, NSTickMarkPosition) {
+typedef NS_ENUM(unsigned int, NSTickMarkPosition) {
NSTickMarkBelow = 0,
NSTickMarkAbove = 1,
NSTickMarkLeft = NSTickMarkAbove,
NSTickMarkRight = NSTickMarkBelow
-} ;
+};
typedef NS_OPTIONS(NSUInteger, UITableStyle) {
UIViewNone = 0x0,
@@ -138,55 +150,55 @@ typedef NS_OPTIONS(NSUInteger, NSFOptions) {
NSFCopyIn NS_ENUM_AVAILABLE(10_5, 6_0) = (1UL << 16),
};
-typedef NS_ENUM(NSInteger, UIP) {
+typedef NS_ENUM(unsigned int, UIP) {
UIP0One = 0,
UIP0Two = 1,
UIP0Three = 2,
UIP0Four = 10,
UIP0Last = 0x100
-} ;
+};
-typedef NS_OPTIONS(NSUInteger, UIP_3) {
+typedef NS_OPTIONS(unsigned int, UIP_3) {
UIPZero = 0x0,
UIPOne = 0x1,
UIPTwo = 0x2,
UIP10 = 0x10,
UIPHundred = 0x100
-} ;
+};
-typedef NS_ENUM(NSInteger, UIP4_3) {
+typedef NS_ENUM(unsigned int, UIP4_3) {
UIP4Zero = 0x0,
UIP4One = 0x1,
UIP4Two = 0x2,
UIP410 = 0x10,
UIP4Hundred = 100
-} ;
+};
-typedef NS_OPTIONS(NSUInteger, UIP5_3) {
+typedef NS_OPTIONS(unsigned int, UIP5_3) {
UIP5Zero = 0x0,
UIP5Two = 0x2,
UIP510 = 0x3,
UIP5Hundred = 0x4
-} ;
+};
-typedef NS_ENUM(NSInteger, UIP6_3) {
+typedef NS_ENUM(unsigned int, UIP6_3) {
UIP6Zero = 0x0,
UIP6One = 0x1,
UIP6Two = 0x2,
UIP610 = 10,
UIP6Hundred = 0x100
-} ;
+};
-typedef NS_ENUM(NSInteger, UIP7_3) {
+typedef NS_ENUM(unsigned int, UIP7_3) {
UIP7Zero = 0x0,
UIP7One = 1,
UIP7Two = 0x2,
UIP710 = 10,
UIP7Hundred = 100
-} ;
+};
-typedef NS_ENUM(NSInteger, UIP8_3) {
+typedef NS_ENUM(unsigned int, UIP8_3) {
Random = 0,
Random1 = 2,
Random2 = 4,
@@ -194,7 +206,7 @@ typedef NS_ENUM(NSInteger, UIP8_3) {
Random4 = 0x3444444,
Random5 = 0xbadbeef,
Random6
-} ;
+};
// rdar://15200602
#define NS_AVAILABLE_MAC(X) __attribute__((availability(macosx,introduced=X)))
@@ -277,3 +289,56 @@ typedef NS_ENUM(NSUInteger, NSSelectionDirection) {
};
// standard window buttons
+
+// rdar://18262255
+typedef enum : NSUInteger {
+ ThingOne,
+ ThingTwo,
+ ThingThree,
+} Thing;
+
+// rdar://18498539
+typedef NS_ENUM(unsigned int, NumericEnum) {
+ one = 1
+};
+
+typedef NS_ENUM(unsigned int, NumericEnum2) {
+ Two = 2
+};
+
+typedef NS_ENUM(unsigned int, NumericEnum3) {
+ Three = 3
+};
+
+typedef NS_OPTIONS(unsigned int, NumericEnum4) {
+ Four = 4
+};
+
+// rdar://18532199
+typedef NS_ENUM(int8_t, MyEnumeratedType)
+{
+ UI8one = 1
+};
+
+
+typedef NS_OPTIONS(uint16_t, UI16) {
+ UI16One = 0,
+ UI16Two = 0x1,
+ UI16three = 0x8,
+ UI16Four = 0x100
+};
+
+typedef NS_ENUM(uint32_t, UI32TableViewCellStyle) {
+ UI32ViewAutoresizingNone = 0,
+ UI32ViewAutoresizingFlexibleLeftMargin,
+ UI32ViewAutoresizingFlexibleWidth,
+ UI32ViewAutoresizingFlexibleRightMargin,
+ UI32ViewAutoresizingFlexibleTopMargin,
+ UI32ViewAutoresizingFlexibleHeight,
+ UI32ViewAutoresizingFlexibleBottomMargin
+};
+
+typedef NS_ENUM(uint8_t, UI8Type)
+{
+ UIU8one = 1
+};
diff --git a/test/ARCMT/objcmt-property-dot-syntax.m b/test/ARCMT/objcmt-property-dot-syntax.m
new file mode 100644
index 000000000000..0e25abcb89ec
--- /dev/null
+++ b/test/ARCMT/objcmt-property-dot-syntax.m
@@ -0,0 +1,61 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-property-dot-syntax -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+// rdar://18498572
+@interface NSObject @end
+
+@interface P : NSObject
+{
+ P* obj;
+ int i1, i2, i3;
+}
+@property int count;
+@property (copy) P* PropertyReturnsPObj;
+- (P*) MethodReturnsPObj;
+@end
+
+P* fun();
+
+@implementation P
+- (int) Meth : (P*)array {
+ [obj setCount : 100];
+
+ [(P*)0 setCount : [array count]];
+
+ [[obj PropertyReturnsPObj] setCount : [array count]];
+
+ [obj setCount : (i1+i2*i3 - 100)];
+
+ return [obj count] -
+ [(P*)0 count] + [array count] +
+ [fun() count] -
+ [[obj PropertyReturnsPObj] count] +
+ [self->obj count];
+}
+
+- (P*) MethodReturnsPObj { return 0; }
+@end
+
+// rdar://19140267
+@interface Sub : P
+@end
+
+@implementation Sub
+- (int) Meth : (P*)array {
+ [super setCount : 100];
+
+ [super setCount : [array count]];
+
+ [[super PropertyReturnsPObj] setCount : [array count]];
+
+ [super setCount : (i1+i2*i3 - 100)];
+
+ return [super count] -
+ [(P*)0 count] + [array count] +
+ [fun() count] -
+ [[super PropertyReturnsPObj] count] +
+ [self->obj count];
+}
+@end
diff --git a/test/ARCMT/objcmt-property-dot-syntax.m.result b/test/ARCMT/objcmt-property-dot-syntax.m.result
new file mode 100644
index 000000000000..6822d44ac0a5
--- /dev/null
+++ b/test/ARCMT/objcmt-property-dot-syntax.m.result
@@ -0,0 +1,61 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-property-dot-syntax -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+// rdar://18498572
+@interface NSObject @end
+
+@interface P : NSObject
+{
+ P* obj;
+ int i1, i2, i3;
+}
+@property int count;
+@property (copy) P* PropertyReturnsPObj;
+- (P*) MethodReturnsPObj;
+@end
+
+P* fun();
+
+@implementation P
+- (int) Meth : (P*)array {
+ obj.count = 100;
+
+ ((P*)0).count = array.count;
+
+ obj.PropertyReturnsPObj.count = array.count;
+
+ obj.count = (i1+i2*i3 - 100);
+
+ return obj.count -
+ ((P*)0).count + array.count +
+ fun().count -
+ obj.PropertyReturnsPObj.count +
+ self->obj.count;
+}
+
+- (P*) MethodReturnsPObj { return 0; }
+@end
+
+// rdar://19140267
+@interface Sub : P
+@end
+
+@implementation Sub
+- (int) Meth : (P*)array {
+ super.count = 100;
+
+ super.count = array.count;
+
+ super.PropertyReturnsPObj.count = array.count;
+
+ super.count = (i1+i2*i3 - 100);
+
+ return super.count -
+ ((P*)0).count + array.count +
+ fun().count -
+ super.PropertyReturnsPObj.count +
+ self->obj.count;
+}
+@end
diff --git a/test/ARCMT/objcmt-undefined-ns-macros.m b/test/ARCMT/objcmt-undefined-ns-macros.m
new file mode 100644
index 000000000000..2e1fa51d04b8
--- /dev/null
+++ b/test/ARCMT/objcmt-undefined-ns-macros.m
@@ -0,0 +1,24 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -objcmt-migrate-ns-macros -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+
+// rdar://18498550
+
+typedef long NSInteger;
+enum {
+ UIViewNone = 0x0,
+ UIViewMargin = 0x1,
+ UIViewWidth = 0x2,
+ UIViewRightMargin = 0x3,
+ UIViewBottomMargin = 0xbadbeef
+};
+typedef NSInteger UITableStyle;
+
+
+typedef
+ enum { two = 1 } NumericEnum2;
+
+typedef enum { three = 1 } NumericEnum3;
+
+typedef enum { four = 1 } NumericEnum4;
+
diff --git a/test/ARCMT/objcmt-undefined-ns-macros.m.result b/test/ARCMT/objcmt-undefined-ns-macros.m.result
new file mode 100644
index 000000000000..30277ac57d49
--- /dev/null
+++ b/test/ARCMT/objcmt-undefined-ns-macros.m.result
@@ -0,0 +1,26 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -objcmt-migrate-ns-macros -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+
+// rdar://18498550
+
+typedef long NSInteger;
+#ifndef NS_ENUM
+@import Foundation;
+#endif
+typedef NS_OPTIONS(NSUInteger, UITableStyle) {
+ UIViewNone = 0x0,
+ UIViewMargin = 0x1,
+ UIViewWidth = 0x2,
+ UIViewRightMargin = 0x3,
+ UIViewBottomMargin = 0xbadbeef
+};
+
+
+typedef
+ NS_ENUM(unsigned int, NumericEnum2) { two = 1 };
+
+typedef NS_ENUM(unsigned int, NumericEnum3) { three = 1 };
+
+typedef NS_ENUM(unsigned int, NumericEnum4) { four = 1 };
+
diff --git a/test/Analysis/Inputs/Models/modeledFunction.model b/test/Analysis/Inputs/Models/modeledFunction.model
new file mode 100644
index 000000000000..3aff5fc1b443
--- /dev/null
+++ b/test/Analysis/Inputs/Models/modeledFunction.model
@@ -0,0 +1,3 @@
+void modelled(intptr p) {
+ ++*p;
+} \ No newline at end of file
diff --git a/test/Analysis/Inputs/Models/notzero.model b/test/Analysis/Inputs/Models/notzero.model
new file mode 100644
index 000000000000..26161029d6ed
--- /dev/null
+++ b/test/Analysis/Inputs/Models/notzero.model
@@ -0,0 +1,3 @@
+bool notzero(int i) {
+ return i != 0;
+} \ No newline at end of file
diff --git a/test/Analysis/Inputs/system-header-simulator-for-pthread-lock.h b/test/Analysis/Inputs/system-header-simulator-for-pthread-lock.h
new file mode 100644
index 000000000000..b290ffe8d879
--- /dev/null
+++ b/test/Analysis/Inputs/system-header-simulator-for-pthread-lock.h
@@ -0,0 +1,28 @@
+// Like the compiler, the static analyzer treats some functions differently if
+// they come from a system header -- for example, pthread_mutex* functions
+// should not invalidate regions of their arguments.
+#pragma clang system_header
+
+typedef struct {
+ void *foo;
+} pthread_mutex_t;
+
+typedef struct {
+ void *foo;
+} pthread_mutexattr_t;
+
+typedef struct {
+ void *foo;
+} lck_grp_t;
+
+typedef pthread_mutex_t lck_mtx_t;
+
+extern int pthread_mutex_lock(pthread_mutex_t *);
+extern int pthread_mutex_unlock(pthread_mutex_t *);
+extern int pthread_mutex_trylock(pthread_mutex_t *);
+extern int pthread_mutex_destroy(pthread_mutex_t *);
+extern int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
+extern int lck_mtx_lock(lck_mtx_t *);
+extern int lck_mtx_unlock(lck_mtx_t *);
+extern int lck_mtx_try_lock(lck_mtx_t *);
+extern void lck_mtx_destroy(lck_mtx_t *lck, lck_grp_t *grp);
diff --git a/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp b/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
index 5a596d47eca8..fca02aa278fd 100644
--- a/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
+++ b/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete -std=c++11 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete,alpha.cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -verify %s
#include "Inputs/system-header-simulator-for-malloc.h"
diff --git a/test/Analysis/Malloc+NewDelete_intersections.cpp b/test/Analysis/Malloc+NewDelete_intersections.cpp
index 310663646a10..d10020dc8e66 100644
--- a/test/Analysis/Malloc+NewDelete_intersections.cpp
+++ b/test/Analysis/Malloc+NewDelete_intersections.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete -std=c++11 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,alpha.cplusplus.NewDeleteLeaks -std=c++11 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -std=c++11 -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
diff --git a/test/Analysis/NSContainers.m b/test/Analysis/NSContainers.m
index 4b3492645682..402ce2c90a17 100644
--- a/test/Analysis/NSContainers.m
+++ b/test/Analysis/NSContainers.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops,debug.ExprInspection -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -Wno-objc-literal-conversion -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops,debug.ExprInspection -verify -Wno-objc-root-class %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp b/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
index b606f23ec8cc..49358f6a2aba 100644
--- a/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
+++ b/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,unix.MismatchedDeallocator -std=c++11 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,alpha.cplusplus.NewDeleteLeaks,unix.MismatchedDeallocator -DLEAKS -std=c++11 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.MismatchedDeallocator -DLEAKS -std=c++11 -verify %s
// expected-no-diagnostics
typedef __typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/NewDelete-checker-test.cpp b/test/Analysis/NewDelete-checker-test.cpp
index 855b05d66333..84176c9097ca 100644
--- a/test/Analysis/NewDelete-checker-test.cpp
+++ b/test/Analysis/NewDelete-checker-test.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
#include "Inputs/system-header-simulator-cxx.h"
typedef __typeof__(sizeof(int)) size_t;
diff --git a/test/Analysis/NewDelete-custom.cpp b/test/Analysis/NewDelete-custom.cpp
index c64bfce2dee3..d368889c968e 100644
--- a/test/Analysis/NewDelete-custom.cpp
+++ b/test/Analysis/NewDelete-custom.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,unix.Malloc -std=c++11 -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,alpha.cplusplus.NewDeleteLeaks,unix.Malloc -std=c++11 -DLEAKS -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.Malloc -std=c++11 -DLEAKS -fblocks -verify %s
#include "Inputs/system-header-simulator-cxx.h"
#ifndef LEAKS
diff --git a/test/Analysis/NewDelete-intersections.mm b/test/Analysis/NewDelete-intersections.mm
index 9024ed57668b..886df1268f9f 100644
--- a/test/Analysis/NewDelete-intersections.mm
+++ b/test/Analysis/NewDelete-intersections.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,alpha.cplusplus.NewDeleteLeaks -std=c++11 -DLEAKS -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -std=c++11 -DLEAKS -fblocks -verify %s
#include "Inputs/system-header-simulator-cxx.h"
#include "Inputs/system-header-simulator-objc.h"
diff --git a/test/Analysis/NewDelete-variadic.cpp b/test/Analysis/NewDelete-variadic.cpp
index 62a7d17e1b2a..f9ef079bfe80 100644
--- a/test/Analysis/NewDelete-variadic.cpp
+++ b/test/Analysis/NewDelete-variadic.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,alpha.cplusplus.NewDeleteLeaks,unix.Malloc -std=c++11 -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.Malloc -std=c++11 -fblocks -verify %s
// expected-no-diagnostics
namespace std {
diff --git a/test/Analysis/NewDeleteLeaks-PR18394.cpp b/test/Analysis/NewDeleteLeaks-PR18394.cpp
index dfd94561628f..d0d70375f5a2 100644
--- a/test/Analysis/NewDeleteLeaks-PR18394.cpp
+++ b/test/Analysis/NewDeleteLeaks-PR18394.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyzer-config graph-trim-interval=1 -analyzer-max-loop 1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDeleteLeaks -verify %s
+// RUN: %clang_cc1 -analyzer-config graph-trim-interval=1 -analyzer-max-loop 1 -analyze -analyzer-checker=core,cplusplus.NewDeleteLeaks -verify %s
// expected-no-diagnostics
class A {
diff --git a/test/Analysis/NewDeleteLeaks-PR19102.cpp b/test/Analysis/NewDeleteLeaks-PR19102.cpp
new file mode 100644
index 000000000000..b141301e456f
--- /dev/null
+++ b/test/Analysis/NewDeleteLeaks-PR19102.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDeleteLeaks -verify %s
+
+class A0 {};
+
+class A1 {
+public:
+ A1(int);
+};
+
+struct S{
+ int i;
+};
+
+class A2 {
+public:
+ A2();
+ A2(S);
+ A2(int*);
+ A2(S*);
+ A2(S&, int);
+ A2(int, S**);
+};
+
+void test() {
+ new int; // expected-warning@+1 {{Potential memory leak}}
+ new A0; // expected-warning@+1 {{Potential memory leak}}
+ new A1(0); // expected-warning@+1 {{Potential memory leak}}
+ new A2; // expected-warning@+1 {{Potential memory leak}}
+ S s;
+ s.i = 1;
+ S* ps = new S;
+ new A2(s); // expected-warning@+1 {{Potential memory leak}}
+ new A2(&(s.i)); // expected-warning@+1 {{Potential memory leak}}
+ new A2(ps); // no warning
+ new A2(*ps, 1); // no warning
+ new A2(1, &ps); // no warning
+
+ // Tests to ensure that leaks are reported for consumed news no matter what the arguments are.
+ A2 *a2p1 = new A2; // expected-warning@+1 {{Potential leak of memory}}
+ A2 *a2p2 = new A2(ps); // expected-warning@+1 {{Potential leak of memory}}
+ A2 *a2p3 = new A2(*ps, 1); // expected-warning@+1 {{Potential leak of memory}}
+ A2 *a2p4 = new A2(1, &ps); // expected-warning@+1 {{Potential leak of memory}}
+}
diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c
index 69d281afee4a..824aa7c063b7 100644
--- a/test/Analysis/bstring.c
+++ b/test/Analysis/bstring.c
@@ -257,6 +257,45 @@ void mempcpy13() {
mempcpy(a, 0, 0); // no-warning
}
+void mempcpy14() {
+ int src[] = {1, 2, 3, 4};
+ int dst[5] = {0};
+ int *p;
+
+ p = mempcpy(dst, src, 4 * sizeof(int));
+
+ clang_analyzer_eval(p == &dst[4]); // expected-warning{{TRUE}}
+}
+
+struct st {
+ int i;
+ int j;
+};
+
+void mempcpy15() {
+ struct st s1 = {0};
+ struct st s2;
+ struct st *p1;
+ struct st *p2;
+
+ p1 = (&s2) + 1;
+ p2 = mempcpy(&s2, &s1, sizeof(struct st));
+
+ clang_analyzer_eval(p1 == p2); // expected-warning{{TRUE}}
+}
+
+void mempcpy16() {
+ struct st s1[10] = {{0}};
+ struct st s2[10];
+ struct st *p1;
+ struct st *p2;
+
+ p1 = (&s2[0]) + 5;
+ p2 = mempcpy(&s2[0], &s1[0], 5 * sizeof(struct st));
+
+ clang_analyzer_eval(p1 == p2); // expected-warning{{TRUE}}
+}
+
void mempcpy_unknown_size_warn (size_t n) {
char a[4];
void *result = mempcpy(a, 0, n); // expected-warning{{Null pointer argument in call to memory copy function}}
diff --git a/test/Analysis/builtin-functions.cpp b/test/Analysis/builtin-functions.cpp
index 72d5ad23b16e..d3afab5bd615 100644
--- a/test/Analysis/builtin-functions.cpp
+++ b/test/Analysis/builtin-functions.cpp
@@ -22,3 +22,31 @@ void testSize() {
clang_analyzer_eval(i == 0); // expected-warning{{TRUE}}
}
+
+void test_assume_aligned_1(char *p) {
+ char *q;
+
+ q = (char*) __builtin_assume_aligned(p, 16);
+ clang_analyzer_eval(p == q); // expected-warning{{TRUE}}
+}
+
+void test_assume_aligned_2(char *p) {
+ char *q;
+
+ q = (char*) __builtin_assume_aligned(p, 16, 8);
+ clang_analyzer_eval(p == q); // expected-warning{{TRUE}}
+}
+
+void test_assume_aligned_3(char *p) {
+ void *q;
+
+ q = __builtin_assume_aligned(p, 16, 8);
+ clang_analyzer_eval(p == q); // expected-warning{{TRUE}}
+}
+
+void test_assume_aligned_4(char *p) {
+ char *q;
+
+ q = (char*) __builtin_assume_aligned(p + 1, 16);
+ clang_analyzer_eval(p == q); // expected-warning{{FALSE}}
+}
diff --git a/test/Analysis/cfg.cpp b/test/Analysis/cfg.cpp
index 65060b168744..28cc440c46fc 100644
--- a/test/Analysis/cfg.cpp
+++ b/test/Analysis/cfg.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++11 %s > %t 2>&1
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -analyzer-config cfg-temporary-dtors=true -std=c++11 %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
// CHECK-LABEL: void checkWrap(int i)
@@ -377,6 +377,61 @@ void test_placement_new_array() {
}
+// CHECK-LABEL: void test_lifetime_extended_temporaries()
+// CHECK: [B1]
+struct LifetimeExtend { LifetimeExtend(int); ~LifetimeExtend(); };
+struct Aggregate { const LifetimeExtend a; const LifetimeExtend b; };
+struct AggregateRef { const LifetimeExtend &a; const LifetimeExtend &b; };
+void test_lifetime_extended_temporaries() {
+ // CHECK: LifetimeExtend(1);
+ // CHECK-NEXT: : 1
+ // CHECK-NEXT: ~LifetimeExtend()
+ // CHECK-NOT: ~LifetimeExtend()
+ {
+ const LifetimeExtend &l = LifetimeExtend(1);
+ 1;
+ }
+ // CHECK: LifetimeExtend(2)
+ // CHECK-NEXT: ~LifetimeExtend()
+ // CHECK-NEXT: : 2
+ // CHECK-NOT: ~LifetimeExtend()
+ {
+ // No life-time extension.
+ const int &l = (LifetimeExtend(2), 2);
+ 2;
+ }
+ // CHECK: LifetimeExtend(3)
+ // CHECK-NEXT: : 3
+ // CHECK-NEXT: ~LifetimeExtend()
+ // CHECK-NOT: ~LifetimeExtend()
+ {
+ // The last one is lifetime extended.
+ const LifetimeExtend &l = (3, LifetimeExtend(3));
+ 3;
+ }
+ // CHECK: LifetimeExtend(4)
+ // CHECK-NEXT: ~LifetimeExtend()
+ // CHECK-NEXT: ~LifetimeExtend()
+ // CHECK-NEXT: : 4
+ // CHECK-NOT: ~LifetimeExtend()
+ {
+ Aggregate a{LifetimeExtend(4), LifetimeExtend(4)};
+ 4;
+ }
+ // CHECK: LifetimeExtend(5)
+ // CHECK-NEXT: : 5
+ // FIXME: We want to emit the destructors of the lifetime
+ // extended variables here.
+ // CHECK-NOT: ~LifetimeExtend()
+ {
+ AggregateRef a{LifetimeExtend(5), LifetimeExtend(5)};
+ 5;
+ }
+ // FIXME: Add tests for lifetime extension via subobject
+ // references (LifetimeExtend().some_member).
+}
+
+
// CHECK-LABEL: int *PR18472()
// CHECK: [B2 (ENTRY)]
// CHECK-NEXT: Succs (1): B1
diff --git a/test/Analysis/debug-CallGraph.c b/test/Analysis/debug-CallGraph.c
index 4523c789351b..64259e2069a4 100644
--- a/test/Analysis/debug-CallGraph.c
+++ b/test/Analysis/debug-CallGraph.c
@@ -23,11 +23,22 @@ void bbb(int y) {
foo(x, y);
}();
}
+void ccc();
+void ddd() { ccc(); }
+void ccc() {}
+
+void eee();
+void eee() {}
+void fff() { eee(); }
// CHECK:--- Call graph Dump ---
-// CHECK: Function: < root > calls: mmm foo aaa < > bbb
-// CHECK: Function: bbb calls: < >
-// CHECK: Function: < > calls: foo
-// CHECK: Function: aaa calls: foo
-// CHECK: Function: foo calls: mmm
-// CHECK: Function: mmm calls:
+// CHECK-NEXT: {{Function: < root > calls: mmm foo aaa < > bbb ccc ddd eee fff $}}
+// CHECK-NEXT: {{Function: fff calls: eee $}}
+// CHECK-NEXT: {{Function: eee calls: $}}
+// CHECK-NEXT: {{Function: ddd calls: ccc $}}
+// CHECK-NEXT: {{Function: ccc calls: $}}
+// CHECK-NEXT: {{Function: bbb calls: < > $}}
+// CHECK-NEXT: {{Function: < > calls: foo $}}
+// CHECK-NEXT: {{Function: aaa calls: foo $}}
+// CHECK-NEXT: {{Function: foo calls: mmm $}}
+// CHECK-NEXT: {{Function: mmm calls: $}}
diff --git a/test/Analysis/disable-all-checks.c b/test/Analysis/disable-all-checks.c
new file mode 100644
index 000000000000..461e6d9bf94a
--- /dev/null
+++ b/test/Analysis/disable-all-checks.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-disable-all-checks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-disable-all-checks -analyzer-checker=core -analyzer-store=region -verify %s
+// RUN: %clang --analyze -Xanalyzer -analyzer-disable-all-checks -Xclang -verify %s
+// RUN: not %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-disable-checker -verify %s 2>&1 | FileCheck %s
+// expected-no-diagnostics
+
+// CHECK: use -analyzer-disable-all-checks to disable all static analyzer checkers
+int buggy() {
+ int x = 0;
+ return 5/x; // no warning
+} \ No newline at end of file
diff --git a/test/Analysis/identical-expressions.cpp b/test/Analysis/identical-expressions.cpp
index 85e3322002dd..46dd56289c4e 100644
--- a/test/Analysis/identical-expressions.cpp
+++ b/test/Analysis/identical-expressions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.IdenticalExpr -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.IdenticalExpr -w -verify %s
/* Only one expected warning per function allowed at the very end. */
@@ -1511,3 +1511,22 @@ void test_nowarn_chained_if_stmts_3(int x) {
else if (x++) // no-warning
;
}
+
+void test_warn_wchar() {
+ const wchar_t * a = 0 ? L"Warning" : L"Warning"; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
+}
+void test_nowarn_wchar() {
+ const wchar_t * a = 0 ? L"No" : L"Warning";
+}
+
+void test_nowarn_long() {
+ int a = 0, b = 0;
+ long c;
+ if (0) {
+ b -= a;
+ c = 0;
+ } else { // no-warning
+ b -= a;
+ c = 0LL;
+ }
+}
diff --git a/test/Analysis/logical-ops.c b/test/Analysis/logical-ops.c
index afaa2f107780..0b63bc9ec835 100644
--- a/test/Analysis/logical-ops.c
+++ b/test/Analysis/logical-ops.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_cc1 -Wno-pointer-bool-conversion -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/malloc-protoype.c b/test/Analysis/malloc-protoype.c
new file mode 100644
index 000000000000..f056f0f2855d
--- /dev/null
+++ b/test/Analysis/malloc-protoype.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -w -analyze -analyzer-checker=core,unix.Malloc -verify %s
+// expected-no-diagnostics
+
+// Test that strange prototypes doesn't crash the analyzer
+
+void malloc(int i);
+void valloc(int i);
+
+void test1()
+{
+ malloc(1);
+}
+
+void test2()
+{
+ valloc(1);
+}
diff --git a/test/Analysis/malloc-sizeof.cpp b/test/Analysis/malloc-sizeof.cpp
new file mode 100644
index 000000000000..8589975f8fc2
--- /dev/null
+++ b/test/Analysis/malloc-sizeof.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix.MallocSizeof -verify %s
+
+#include <stddef.h>
+
+void *malloc(size_t size);
+void *calloc(size_t nmemb, size_t size);
+void *realloc(void *ptr, size_t size);
+void free(void *ptr);
+
+struct A {};
+struct B {};
+
+void foo(unsigned int unsignedInt, unsigned int readSize) {
+ // Sanity check the checker is working as expected.
+ A* a = static_cast<A*>(malloc(sizeof(int))); // expected-warning {{Result of 'malloc' is converted to a pointer of type 'struct A', which is incompatible with sizeof operand type 'int'}}
+ free(a);
+}
+
+void bar() {
+ A *x = static_cast<A*>(calloc(10, sizeof(void*))); // expected-warning {{Result of 'calloc' is converted to a pointer of type 'struct A', which is incompatible with sizeof operand type 'void *'}}
+ // sizeof(void*) is compatible with any pointer.
+ A **y = static_cast<A**>(calloc(10, sizeof(void*))); // no-warning
+ free(x);
+ free(y);
+}
+
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index 6da9604467de..ad7393b82d30 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -118,19 +118,6 @@ __m128i vec128i(long long __q1, long long __q0) {
return __extension__ (__m128i)(__v2di){ __q0, __q1 };
}
-// Zero-sized VLAs.
-void check_zero_sized_VLA(int x) {
- if (x)
- return;
-
- int vla[x]; // expected-warning{{Declared variable-length array (VLA) has zero size}}
-}
-
-void check_uninit_sized_VLA() {
- int x;
- int vla[x]; // expected-warning{{Declared variable-length array (VLA) uses a garbage value as its size}}
-}
-
// sizeof(void)
// - Tests a regression reported in PR 3211: http://llvm.org/bugs/show_bug.cgi?id=3211
void handle_sizeof_void(unsigned flag) {
diff --git a/test/Analysis/model-file.cpp b/test/Analysis/model-file.cpp
new file mode 100644
index 000000000000..24d6e9312da9
--- /dev/null
+++ b/test/Analysis/model-file.cpp
@@ -0,0 +1,288 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config faux-bodies=true,model-path=%S/Inputs/Models -analyzer-output=plist-multi-file -verify %s -o %t
+// RUN: FileCheck --input-file=%t %s
+
+typedef int* intptr;
+
+// This function is modeled and the p pointer is dereferenced in the model
+// function and there is no function definition available. The modeled
+// function can use any types that are available in the original translation
+// unit, for example intptr in this case.
+void modeledFunction(intptr p);
+
+// This function is modeled and returns true if the parameter is not zero
+// and there is no function definition available.
+bool notzero(int i);
+
+// This functions is not modeled and there is no function definition.
+// available
+bool notzero_notmodeled(int i);
+
+int main() {
+ // There is a nullpointer dereference inside this function.
+ modeledFunction(0);
+
+ int p = 0;
+ if (notzero(p)) {
+ // It is known that p != 0 because of the information provided by the
+ // model of the notzero function.
+ int j = 5 / p;
+ }
+
+ if (notzero_notmodeled(p)) {
+ // There is no information about the value of p, because
+ // notzero_notmodeled is not modeled and the function definition
+ // is not available.
+ int j = 5 / p; // expected-warning {{Division by zero}}
+ }
+
+ return 0;
+}
+
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to 0</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>main</string>
+// CHECK-NEXT: <key>issue_hash</key><string>15</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array> \ No newline at end of file
diff --git a/test/Analysis/nonnull.m b/test/Analysis/nonnull.m
index 0cea80b536d8..c21360ded8d1 100644
--- a/test/Analysis/nonnull.m
+++ b/test/Analysis/nonnull.m
@@ -75,3 +75,121 @@ int rdar16153464(union rdar16153464_full_ctx_t inner)
rdar16153464_check(inner); // no-warning
rdar16153464_check(0); // expected-warning{{nonnull}}
}
+
+// Multiple attributes, the basic case
+void multipleAttributes_1(char *p, char *q) __attribute((nonnull(1))) __attribute((nonnull(2)));
+
+void testMultiple_1(void) {
+ char c;
+ multipleAttributes_1(&c, &c); // no-warning
+}
+
+void testMultiple_2(void) {
+ char c;
+ multipleAttributes_1(0, &c); // expected-warning{{nonnull}}
+}
+
+void testMultiple_3(void) {
+ char c;
+ multipleAttributes_1(&c, 0); // expected-warning{{nonnull}}
+}
+
+void testMultiple_4(void) {
+ multipleAttributes_1(0, 0);// expected-warning{{nonnull}}
+}
+
+// Multiple attributes, multiple prototypes
+void multipleAttributes_2(char *p, char *q) __attribute((nonnull(1)));
+void multipleAttributes_2(char *p, char *q) __attribute((nonnull(2)));
+
+void testMultiple_5(void) {
+ char c;
+ multipleAttributes_2(0, &c);// expected-warning{{nonnull}}
+}
+
+void testMultiple_6(void) {
+ char c;
+ multipleAttributes_2(&c, 0);// expected-warning{{nonnull}}
+}
+
+void testMultiple_7(void) {
+ multipleAttributes_2(0, 0);// expected-warning{{nonnull}}
+}
+
+// Multiple attributes, same index
+void multipleAttributes_3(char *p, char *q) __attribute((nonnull(1))) __attribute((nonnull(1)));
+
+void testMultiple_8(void) {
+ char c;
+ multipleAttributes_3(0, &c); // expected-warning{{nonnull}}
+}
+
+void testMultiple_9(void) {
+ char c;
+ multipleAttributes_3(&c, 0); // no-warning
+}
+
+// Multiple attributes, the middle argument is missing an attribute
+void multipleAttributes_4(char *p, char *q, char *r) __attribute((nonnull(1))) __attribute((nonnull(3)));
+
+void testMultiple_10(void) {
+ char c;
+ multipleAttributes_4(0, &c, &c); // expected-warning{{nonnull}}
+}
+
+void testMultiple_11(void) {
+ char c;
+ multipleAttributes_4(&c, 0, &c); // no-warning
+}
+
+void testMultiple_12(void) {
+ char c;
+ multipleAttributes_4(&c, &c, 0); // expected-warning{{nonnull}}
+}
+
+
+// Multiple attributes, when the last is without index
+void multipleAttributes_all_1(char *p, char *q) __attribute((nonnull(1))) __attribute((nonnull));
+
+void testMultiple_13(void) {
+ char c;
+ multipleAttributes_all_1(0, &c); // expected-warning{{nonnull}}
+}
+
+void testMultiple_14(void) {
+ char c;
+ multipleAttributes_all_1(&c, 0); // expected-warning{{nonnull}}
+}
+
+// Multiple attributes, when the first is without index
+void multipleAttributes_all_2(char *p, char *q) __attribute((nonnull)) __attribute((nonnull(2)));
+
+void testMultiple_15(void) {
+ char c;
+ multipleAttributes_all_2(0, &c); // expected-warning{{nonnull}}
+}
+
+void testMultiple_16(void) {
+ char c;
+ multipleAttributes_all_2(&c, 0); // expected-warning{{nonnull}}
+}
+
+void testVararg(int k, void *p) {
+ extern void testVararg_check(int, ...) __attribute__((nonnull));
+ void *n = 0;
+ testVararg_check(0);
+ testVararg_check(1, p);
+ if (k == 1)
+ testVararg_check(1, n); // expected-warning{{nonnull}}
+ testVararg_check(2, p, p);
+ if (k == 2)
+ testVararg_check(2, n, p); // expected-warning{{nonnull}}
+ if (k == 3)
+ testVararg_check(2, p, n); // expected-warning{{nonnull}}
+}
+
+void testNotPtr() {
+ struct S { int a; int b; int c; } s = {};
+ extern void testNotPtr_check(struct S, int) __attribute__((nonnull(1, 2)));
+ testNotPtr_check(s, 0);
+}
diff --git a/test/Analysis/objc-boxing.m b/test/Analysis/objc-boxing.m
index c23192e17e5d..73386f463bc8 100644
--- a/test/Analysis/objc-boxing.m
+++ b/test/Analysis/objc-boxing.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,osx.cocoa.NonNilReturnValue,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -Wno-objc-literal-conversion -analyze -analyzer-checker=core,unix.Malloc,osx.cocoa.NonNilReturnValue,debug.ExprInspection -analyzer-store=region -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/pthreadlock.c b/test/Analysis/pthreadlock.c
index 2a59e0ffe98a..a6e29e78ff38 100644
--- a/test/Analysis/pthreadlock.c
+++ b/test/Analysis/pthreadlock.c
@@ -2,31 +2,10 @@
// Tests performing normal locking patterns and wrong locking orders
-typedef struct {
- void *foo;
-} pthread_mutex_t;
-
-typedef struct {
- void *foo;
-} pthread_mutexattr_t;
-
-typedef struct {
- void *foo;
-} lck_grp_t;
-
-typedef pthread_mutex_t lck_mtx_t;
-
-extern int pthread_mutex_lock(pthread_mutex_t *);
-extern int pthread_mutex_unlock(pthread_mutex_t *);
-extern int pthread_mutex_trylock(pthread_mutex_t *);
-extern int pthread_mutex_destroy(pthread_mutex_t *);
-extern int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
-extern int lck_mtx_lock(lck_mtx_t *);
-extern int lck_mtx_unlock(lck_mtx_t *);
-extern int lck_mtx_try_lock(lck_mtx_t *);
-extern void lck_mtx_destroy(lck_mtx_t *lck, lck_grp_t *grp);
+#include "Inputs/system-header-simulator-for-pthread-lock.h"
pthread_mutex_t mtx1, mtx2;
+pthread_mutex_t *pmtx;
lck_mtx_t lck1, lck2;
lck_grp_t grp1;
@@ -184,6 +163,21 @@ ok20(void)
}
void
+ok21(void) {
+ pthread_mutex_lock(pmtx); // no-warning
+ pthread_mutex_unlock(pmtx); // no-warning
+}
+
+void
+ok22(void) {
+ pthread_mutex_lock(pmtx); // no-warning
+ pthread_mutex_unlock(pmtx); // no-warning
+ pthread_mutex_lock(pmtx); // no-warning
+ pthread_mutex_unlock(pmtx); // no-warning
+}
+
+
+void
bad1(void)
{
pthread_mutex_lock(&mtx1); // no-warning
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index 5fb33d36b855..491c68e1bc8b 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -324,7 +324,7 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B3]
// CHECK: 1: [B5.8] && [B4.5]
// CHECK: 2: [B5.3]([B3.1])
-// CHECK: T: (Temp Dtor) [B5.8] && ...
+// CHECK: T: (Temp Dtor) [B4.2]
// CHECK: Preds (2): B4 B5
// CHECK: Succs (2): B2 B1
// CHECK: [B4]
@@ -354,7 +354,7 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B7]
// CHECK: 1: [B9.5] && [B8.5]
// CHECK: 2: bool a = A() && B();
-// CHECK: T: (Temp Dtor) [B9.5] && ...
+// CHECK: T: (Temp Dtor) [B8.2]
// CHECK: Preds (2): B8 B9
// CHECK: Succs (2): B6 B5
// CHECK: [B8]
@@ -390,9 +390,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B3]
// CHECK: 1: [B5.8] || [B4.5]
// CHECK: 2: [B5.3]([B3.1])
-// CHECK: T: (Temp Dtor) [B5.8] || ...
+// CHECK: T: (Temp Dtor) [B4.2]
// CHECK: Preds (2): B4 B5
-// CHECK: Succs (2): B1 B2
+// CHECK: Succs (2): B2 B1
// CHECK: [B4]
// CHECK: 1: B() (CXXConstructExpr, class B)
// CHECK: 2: [B4.1] (BindTemporary)
@@ -420,9 +420,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B7]
// CHECK: 1: [B9.5] || [B8.5]
// CHECK: 2: bool a = A() || B();
-// CHECK: T: (Temp Dtor) [B9.5] || ...
+// CHECK: T: (Temp Dtor) [B8.2]
// CHECK: Preds (2): B8 B9
-// CHECK: Succs (2): B5 B6
+// CHECK: Succs (2): B6 B5
// CHECK: [B8]
// CHECK: 1: B() (CXXConstructExpr, class B)
// CHECK: 2: [B8.1] (BindTemporary)
@@ -492,9 +492,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: 3: [B7.2]
// CHECK: 4: [B7.3] (CXXConstructExpr, class A)
// CHECK: 5: A a = B() ? A() : A(B());
-// CHECK: T: (Temp Dtor) [B10.5] ? ... : ...
+// CHECK: T: (Temp Dtor) [B9.2]
// CHECK: Preds (2): B8 B9
-// CHECK: Succs (2): B5 B6
+// CHECK: Succs (2): B6 B5
// CHECK: [B8]
// CHECK: 1: A() (CXXConstructExpr, class A)
// CHECK: 2: [B8.1] (BindTemporary)
@@ -533,7 +533,6 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (2): B8 B9
// CHECK: [B0 (EXIT)]
// CHECK: Preds (1): B1
-// CHECK: C() : b_(true)
// CHECK: [B2 (ENTRY)]
// CHECK: Succs (1): B1
// CHECK: [B1]
@@ -543,12 +542,10 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B0 (EXIT)]
// CHECK: Preds (1): B1
-// CHECK: ~C()
// CHECK: [B1 (ENTRY)]
// CHECK: Succs (1): B0
// CHECK: [B0 (EXIT)]
// CHECK: Preds (1): B1
-// CHECK: operator bool()
// CHECK: [B2 (ENTRY)]
// CHECK: Succs (1): B1
// CHECK: [B1]
@@ -560,7 +557,6 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B0 (EXIT)]
// CHECK: Preds (1): B1
-// CHECK: D() : b_(true)
// CHECK: [B2 (ENTRY)]
// CHECK: Succs (1): B1
// CHECK: [B1]
@@ -570,7 +566,6 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B0 (EXIT)]
// CHECK: Preds (1): B1
-// CHECK: operator bool()
// CHECK: [B2 (ENTRY)]
// CHECK: Succs (1): B1
// CHECK: [B1]
@@ -582,7 +577,6 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B0 (EXIT)]
// CHECK: Preds (1): B1
-// CHECK: int test_cond_unnamed_custom_destructor()
// CHECK: [B4 (ENTRY)]
// CHECK: Succs (1): B3
// CHECK: [B1]
@@ -607,7 +601,6 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (2): B2 B1
// CHECK: [B0 (EXIT)]
// CHECK: Preds (2): B1 B2
-// CHECK: int test_cond_named_custom_destructor()
// CHECK: [B5 (ENTRY)]
// CHECK: Succs (1): B4
// CHECK: [B1]
@@ -642,7 +635,6 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (2): B3 B2
// CHECK: [B0 (EXIT)]
// CHECK: Preds (3): B1 B2 B3
-// CHECK: int test_cond_unnamed_auto_destructor()
// CHECK: [B4 (ENTRY)]
// CHECK: Succs (1): B3
// CHECK: [B1]
@@ -665,7 +657,6 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (2): B2 B1
// CHECK: [B0 (EXIT)]
// CHECK: Preds (2): B1 B2
-// CHECK: int test_cond_named_auto_destructor()
// CHECK: [B4 (ENTRY)]
// CHECK: Succs (1): B3
// CHECK: [B1]
@@ -718,9 +709,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B4.2]
// CHECK: 4: [B7.3]([B4.3])
-// CHECK: T: (Temp Dtor) [B7.8] ? ... : ...
+// CHECK: T: (Temp Dtor) [B6.2]
// CHECK: Preds (2): B5 B6
-// CHECK: Succs (2): B2 B3
+// CHECK: Succs (2): B3 B2
// CHECK: [B5]
// CHECK: 1: A() (CXXConstructExpr, class A)
// CHECK: 2: [B5.1] (BindTemporary)
@@ -775,9 +766,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B10.2]
// CHECK: 4: const A &a = B() ? A() : A(B());
-// CHECK: T: (Temp Dtor) [B13.5] ? ... : ...
+// CHECK: T: (Temp Dtor) [B12.2]
// CHECK: Preds (2): B11 B12
-// CHECK: Succs (2): B8 B9
+// CHECK: Succs (2): B9 B8
// CHECK: [B11]
// CHECK: 1: A() (CXXConstructExpr, class A)
// CHECK: 2: [B11.1] (BindTemporary)
@@ -819,9 +810,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B8 (ENTRY)]
// CHECK: Succs (1): B7
// CHECK: [B1]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: 3: [B4.5].~A() (Implicit destructor)
+// CHECK: 1: int b;
+// CHECK: 2: [B4.5].~A() (Implicit destructor)
// CHECK: Preds (2): B2 B3
// CHECK: Succs (1): B0
// CHECK: [B2]
@@ -839,9 +829,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: 3: [B4.2]
// CHECK: 4: [B4.3] (CXXConstructExpr, class A)
// CHECK: 5: A a = A() ?: A();
-// CHECK: T: (Temp Dtor) [B7.5] ? ... : ...
+// CHECK: T: (Temp Dtor) [B6.2]
// CHECK: Preds (2): B5 B6
-// CHECK: Succs (2): B2 B3
+// CHECK: Succs (2): B3 B2
// CHECK: [B5]
// CHECK: 1: [B7.2] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 2: [B5.1]
@@ -872,9 +862,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B13 (ENTRY)]
// CHECK: Succs (1): B12
// CHECK: [B1]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: 3: [B9.4].~A() (Implicit destructor)
+// CHECK: 1: int b;
+// CHECK: 2: [B9.4].~A() (Implicit destructor)
// CHECK: Preds (2): B2 B3
// CHECK: Succs (1): B0
// CHECK: [B2]
@@ -887,15 +876,15 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (1): B4
// CHECK: Succs (1): B1
// CHECK: [B4]
-// CHECK: 1: [B7.5] ?: [B6.6]
+// CHECK: 1: [B7.4] ?: [B6.6]
// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B4.2]
-// CHECK: 4: [B7.3]([B4.3])
-// CHECK: T: (Temp Dtor) [B7.8] ? ... : ...
+// CHECK: 4: [B7.2]([B4.3])
+// CHECK: T: (Temp Dtor) [B6.2]
// CHECK: Preds (2): B5 B6
-// CHECK: Succs (2): B2 B3
+// CHECK: Succs (2): B3 B2
// CHECK: [B5]
-// CHECK: 1: [B7.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 1: [B7.4] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 2: [B5.1]
// CHECK: 3: [B5.2] (CXXConstructExpr, class A)
// CHECK: 4: [B5.3] (BindTemporary)
@@ -911,16 +900,15 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (1): B7
// CHECK: Succs (1): B4
// CHECK: [B7]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: foo
-// CHECK: 3: [B7.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
-// CHECK: 4: A() (CXXConstructExpr, class A)
-// CHECK: 5: [B7.4] (BindTemporary)
-// CHECK: 6: [B7.5].operator bool
-// CHECK: 7: [B7.5]
-// CHECK: 8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B7.8] ? ... : ...
-// CHECK: Preds (2): B9 B8
+// CHECK: 1: foo
+// CHECK: 2: [B7.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK: 3: A() (CXXConstructExpr, class A)
+// CHECK: 4: [B7.3] (BindTemporary)
+// CHECK: 5: [B7.4].operator bool
+// CHECK: 6: [B7.4]
+// CHECK: 7: [B7.6] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B7.7] ? ... : ...
+// CHECK: Preds (2): B8 B9
// CHECK: Succs (2): B5 B6
// CHECK: [B8]
// CHECK: 1: ~A() (Temporary object destructor)
@@ -931,9 +919,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: 2: [B9.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B9.2]
// CHECK: 4: const A &a = A() ?: A();
-// CHECK: T: (Temp Dtor) [B12.5] ? ... : ...
+// CHECK: T: (Temp Dtor) [B11.2]
// CHECK: Preds (2): B10 B11
-// CHECK: Succs (2): B7 B8
+// CHECK: Succs (2): B8 B7
// CHECK: [B10]
// CHECK: 1: [B12.2] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 2: [B10.1]
@@ -1089,6 +1077,7 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B2
// CHECK: [B1]
// CHECK: 1: int b;
+// CHECK: Preds (1): B2(Unreachable)
// CHECK: Succs (1): B0
// CHECK: [B2 (NORETURN)]
// CHECK: 1: int a;
@@ -1105,6 +1094,7 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B2
// CHECK: [B1]
// CHECK: 1: int b;
+// CHECK: Preds (1): B2(Unreachable)
// CHECK: Succs (1): B0
// CHECK: [B2 (NORETURN)]
// CHECK: 1: int a;
@@ -1117,7 +1107,6 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B0 (EXIT)]
// CHECK: Preds (2): B1 B2
-// CHECK: int testConsistencyNestedSimple(bool value)
// CHECK: [B9 (ENTRY)]
// CHECK: Succs (1): B8
// CHECK: [B1]
@@ -1132,7 +1121,7 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B3]
// CHECK: T: if [B5.1]
-// CHECK: Preds (1): B5
+// CHECK: Preds (2): B4(Unreachable) B5
// CHECK: Succs (2): B2 B1
// CHECK: [B4 (NORETURN)]
// CHECK: 1: ~NoReturn() (Temporary object destructor)
@@ -1140,9 +1129,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B5]
// CHECK: 1: [B7.3] || [B6.7]
-// CHECK: T: (Temp Dtor) [B7.3] || ...
+// CHECK: T: (Temp Dtor) [B6.4]
// CHECK: Preds (2): B6 B7
-// CHECK: Succs (2): B3 B4
+// CHECK: Succs (2): B4 B3
// CHECK: [B6]
// CHECK: 1: check
// CHECK: 2: [B6.1] (ImplicitCastExpr, FunctionToPointerDecay, _Bool (*)(const class NoReturn &))
@@ -1168,7 +1157,6 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (2): B7 B1
// CHECK: [B0 (EXIT)]
// CHECK: Preds (3): B1 B2 B4
-// CHECK: int testConsistencyNestedComplex(bool value)
// CHECK: [B10 (ENTRY)]
// CHECK: Succs (1): B9
// CHECK: [B1]
@@ -1183,7 +1171,7 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B3]
// CHECK: T: if [B5.1]
-// CHECK: Preds (1): B5
+// CHECK: Preds (2): B4(Unreachable) B5
// CHECK: Succs (2): B2 B1
// CHECK: [B4 (NORETURN)]
// CHECK: 1: ~NoReturn() (Temporary object destructor)
@@ -1191,9 +1179,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B5]
// CHECK: 1: [B8.3] || [B7.3] || [B6.7]
-// CHECK: T: (Temp Dtor) [B8.3] || [B7.3] || ...
+// CHECK: T: (Temp Dtor) [B6.4]
// CHECK: Preds (3): B6 B7 B8
-// CHECK: Succs (2): B3 B4
+// CHECK: Succs (2): B4 B3
// CHECK: [B6]
// CHECK: 1: check
// CHECK: 2: [B6.1] (ImplicitCastExpr, FunctionToPointerDecay, _Bool (*)(const class NoReturn &))
@@ -1226,7 +1214,6 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (2): B8 B1
// CHECK: [B0 (EXIT)]
// CHECK: Preds (3): B1 B2 B4
-// CHECK: int testConsistencyNestedNormalReturn(bool value)
// CHECK: [B10 (ENTRY)]
// CHECK: Succs (1): B9
// CHECK: [B1]
@@ -1241,7 +1228,7 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B3]
// CHECK: T: if [B5.1]
-// CHECK: Preds (1): B5
+// CHECK: Preds (2): B4(Unreachable) B5
// CHECK: Succs (2): B2 B1
// CHECK: [B4 (NORETURN)]
// CHECK: 1: ~NoReturn() (Temporary object destructor)
@@ -1249,9 +1236,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B0
// CHECK: [B5]
// CHECK: 1: [B8.3] || [B7.2] || [B6.7]
-// CHECK: T: (Temp Dtor) [B8.3] || [B7.2] || ...
+// CHECK: T: (Temp Dtor) [B6.4]
// CHECK: Preds (3): B6 B7 B8
-// CHECK: Succs (2): B3 B4
+// CHECK: Succs (2): B4 B3
// CHECK: [B6]
// CHECK: 1: check
// CHECK: 2: [B6.1] (ImplicitCastExpr, FunctionToPointerDecay, _Bool (*)(const class NoReturn &))
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
index c57d984a1dc8..6e476339cb77 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -1,8 +1,9 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s -std=c++11
extern bool clang_analyzer_eval(bool);
+extern bool clang_analyzer_warnIfReached();
struct Trivial {
Trivial(int x) : value(x) {}
@@ -111,13 +112,13 @@ namespace compound_literals {
}
namespace destructors {
- void testPR16664andPR18159Crash() {
- struct Dtor {
- ~Dtor();
- };
- extern bool coin();
- extern bool check(const Dtor &);
+ struct Dtor {
+ ~Dtor();
+ };
+ extern bool coin();
+ extern bool check(const Dtor &);
+ void testPR16664andPR18159Crash() {
// Regression test: we used to assert here when tmp dtors are enabled.
// PR16664 and PR18159
if (coin() && (coin() || coin() || check(Dtor()))) {
@@ -193,8 +194,7 @@ namespace destructors {
(i == 4 || i == 4 ||
compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
i != 4) {
- // FIXME: This shouldn't cause a warning.
- clang_analyzer_eval(true); // expected-warning{{TRUE}}
+ clang_analyzer_eval(true); // no warning, unreachable code
}
}
@@ -211,8 +211,7 @@ namespace destructors {
void testConsistencyNestedComplex(bool value) {
if (value) {
if (!value || !value || check(NoReturnDtor())) {
- // FIXME: This shouldn't cause a warning.
- clang_analyzer_eval(true); // expected-warning{{TRUE}}
+ clang_analyzer_eval(true); // no warning, unreachable code
}
}
}
@@ -225,6 +224,120 @@ namespace destructors {
}
}
}
+ // PR16664 and PR18159
+ void testConsistencyNestedComplexMidBranch(bool value) {
+ if (value) {
+ if (!value || !value || check(NoReturnDtor()) || value) {
+ clang_analyzer_eval(true); // no warning, unreachable code
+ }
+ }
+ }
+
+ // PR16664 and PR18159
+ void testConsistencyNestedComplexNestedBranch(bool value) {
+ if (value) {
+ if (!value || (!value || check(NoReturnDtor()) || value)) {
+ clang_analyzer_eval(true); // no warning, unreachable code
+ }
+ }
+ }
+
+ // PR16664 and PR18159
+ void testConsistencyNestedVariableModification(bool value) {
+ bool other = true;
+ if (value) {
+ if (!other || !value || (other = false) || check(NoReturnDtor()) ||
+ !other) {
+ clang_analyzer_eval(true); // no warning, unreachable code
+ }
+ }
+ }
+
+ void testTernaryNoReturnTrueBranch(bool value) {
+ if (value) {
+ bool b = value && (value ? check(NoReturnDtor()) : true);
+ clang_analyzer_eval(true); // no warning, unreachable code
+ }
+ }
+ void testTernaryNoReturnFalseBranch(bool value) {
+ if (value) {
+ bool b = !value && !value ? true : check(NoReturnDtor());
+ clang_analyzer_eval(true); // no warning, unreachable code
+ }
+ }
+ void testTernaryIgnoreNoreturnBranch(bool value) {
+ if (value) {
+ bool b = !value && !value ? check(NoReturnDtor()) : true;
+ clang_analyzer_eval(true); // expected-warning{{TRUE}}
+ }
+ }
+ void testTernaryTrueBranchReached(bool value) {
+ value ? clang_analyzer_warnIfReached() : // expected-warning{{REACHABLE}}
+ check(NoReturnDtor());
+ }
+ void testTernaryFalseBranchReached(bool value) {
+ value ? check(NoReturnDtor()) :
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ }
+
+ void testLoop() {
+ for (int i = 0; i < 10; ++i) {
+ if (i < 3 && (i >= 2 || check(NoReturnDtor()))) {
+ clang_analyzer_eval(true); // no warning, unreachable code
+ }
+ }
+ }
+
+ bool testRecursiveFrames(bool isInner) {
+ if (isInner ||
+ (clang_analyzer_warnIfReached(), false) || // expected-warning{{REACHABLE}}
+ check(NoReturnDtor()) ||
+ testRecursiveFrames(true)) {
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ }
+ }
+ void testRecursiveFramesStart() { testRecursiveFrames(false); }
+
+ void testLambdas() {
+ // This is the test we would like to write:
+ // []() { check(NoReturnDtor()); } != nullptr || check(Dtor());
+ // But currently the analyzer stops when it encounters a lambda:
+ [] {};
+ // The CFG for this now looks correct, but we still do not reach the line
+ // below.
+ clang_analyzer_warnIfReached(); // FIXME: Should warn.
+ }
+
+ void testGnuExpressionStatements(int v) {
+ ({ ++v; v == 10 || check(NoReturnDtor()); v == 42; }) || v == 23;
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+
+ ({ ++v; check(NoReturnDtor()); v == 42; }) || v == 23;
+ clang_analyzer_warnIfReached(); // no warning, unreachable code
+ }
+
+ void testGnuExpressionStatementsDestructionPoint(int v) {
+ // In normal context, the temporary destructor runs at the end of the full
+ // statement, thus the last statement is reached.
+ (++v, check(NoReturnDtor()), v == 42),
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+
+ // GNU expression statements execute temporary destructors within the
+ // blocks, thus the last statement is not reached.
+ ({ ++v; check(NoReturnDtor()); v == 42; }),
+ clang_analyzer_warnIfReached(); // no warning, unreachable code
+ }
+
+ void testMultipleTemporaries(bool value) {
+ if (value) {
+ // FIXME: Find a way to verify construction order.
+ // ~Dtor should run before ~NoReturnDtor() because construction order is
+ // guaranteed by comma operator.
+ if (!value || check((NoReturnDtor(), Dtor())) || value) {
+ clang_analyzer_eval(true); // no warning, unreachable code
+ }
+ }
+ }
void testBinaryOperatorShortcut(bool value) {
if (value) {
@@ -234,6 +347,78 @@ namespace destructors {
}
}
+ void testIfAtEndOfLoop() {
+ int y = 0;
+ while (true) {
+ if (y > 0) {
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ }
+ ++y;
+ // Test that the CFG gets hooked up correctly when temporary destructors
+ // are handled after a statically known branch condition.
+ if (true) (void)0; else (void)check(NoReturnDtor());
+ }
+ }
+
+ void testTernaryAtEndOfLoop() {
+ int y = 0;
+ while (true) {
+ if (y > 0) {
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ }
+ ++y;
+ // Test that the CFG gets hooked up correctly when temporary destructors
+ // are handled after a statically known branch condition.
+ true ? (void)0 : (void)check(NoReturnDtor());
+ }
+ }
+
+ void testNoReturnInComplexCondition() {
+ check(Dtor()) &&
+ (check(NoReturnDtor()) || check(NoReturnDtor())) && check(Dtor());
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ }
+
+ void testSequencingOfConditionalTempDtors(bool b) {
+ b || (check(Dtor()), check(NoReturnDtor()));
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ }
+
+ void testSequencingOfConditionalTempDtors2(bool b) {
+ (b || check(Dtor())), check(NoReturnDtor());
+ clang_analyzer_warnIfReached(); // no warning, unreachable code
+ }
+
+ void testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b) {
+ b || (check(Dtor()) + check(NoReturnDtor()));
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ }
+
+ void f(Dtor d = Dtor());
+ void testDefaultParameters() {
+ f();
+ }
+
+ struct DefaultParam {
+ DefaultParam(int, const Dtor& d = Dtor());
+ ~DefaultParam();
+ };
+ void testDefaultParamConstructorsInLoops() {
+ while (true) {
+ // FIXME: This exact pattern triggers the temporary cleanup logic
+ // to fail when adding a 'clean' state.
+ DefaultParam(42);
+ DefaultParam(42);
+ }
+ }
+ void testDefaultParamConstructorsInTernariesInLoops(bool value) {
+ while (true) {
+ // FIXME: This exact pattern triggers the temporary cleanup logic
+ // to visit the bind-temporary logic with a state that already has that
+ // temporary marked as executed.
+ value ? DefaultParam(42) : DefaultParam(42);
+ }
+ }
#endif // TEMPORARY_DTORS
}
diff --git a/test/Analysis/unix-api.c b/test/Analysis/unix-api.c
new file mode 100644
index 000000000000..86c702d72594
--- /dev/null
+++ b/test/Analysis/unix-api.c
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.API -verify %s
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+
+#ifndef NULL
+#define NULL ((void*) 0)
+#endif
+
+int open(const char *, int, ...);
+int close(int fildes);
+
+void open_1(const char *path) {
+ int fd;
+ fd = open(path, O_RDONLY); // no-warning
+ if (fd > -1)
+ close(fd);
+}
+
+void open_2(const char *path) {
+ int fd;
+ int mode = 0x0;
+ fd = open(path, O_RDONLY, mode, NULL); // expected-warning{{Call to 'open' with more than three arguments}}
+ if (fd > -1)
+ close(fd);
+}
+
+void open_3(const char *path) {
+ int fd;
+ fd = open(path, O_RDONLY, NULL); // expected-warning{{Third argument to 'open' is not an integer}}
+ if (fd > -1)
+ close(fd);
+}
+
+void open_4(const char *path) {
+ int fd;
+ fd = open(path, O_RDONLY, ""); // expected-warning{{Third argument to 'open' is not an integer}}
+ if (fd > -1)
+ close(fd);
+}
+
+void open_5(const char *path) {
+ int fd;
+ struct {
+ int val;
+ } st = {0};
+ fd = open(path, O_RDONLY, st); // expected-warning{{Third argument to 'open' is not an integer}}
+ if (fd > -1)
+ close(fd);
+}
+
+void open_6(const char *path) {
+ int fd;
+ struct {
+ int val;
+ } st = {0};
+ fd = open(path, O_RDONLY, st.val); // no-warning
+ if (fd > -1)
+ close(fd);
+}
+
+void open_7(const char *path) {
+ int fd;
+ fd = open(path, O_RDONLY, &open); // expected-warning{{Third argument to 'open' is not an integer}}
+ if (fd > -1)
+ close(fd);
+}
+
+void open_8(const char *path) {
+ int fd;
+ fd = open(path, O_RDONLY, 0.0f); // expected-warning{{Third argument to 'open' is not an integer}}
+ if (fd > -1)
+ close(fd);
+}
diff --git a/test/Analysis/virtualcall.cpp b/test/Analysis/virtualcall.cpp
index c3319b0ac54f..8ce1d4103b9c 100644
--- a/test/Analysis/virtualcall.cpp
+++ b/test/Analysis/virtualcall.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.VirtualCall -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.VirtualCall -analyzer-store region -verify -std=c++11 %s
class A {
public:
@@ -46,10 +46,31 @@ C::C() {
f(foo()); // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}}
}
+class D : public B {
+public:
+ D() {
+ foo(); // no-warning
+ }
+ ~D() { bar(); }
+ int foo() final;
+ void bar() final { foo(); } // no-warning
+};
+
+class E final : public B {
+public:
+ E() {
+ foo(); // no-warning
+ }
+ ~E() { bar(); }
+ int foo() override;
+};
+
int main() {
A *a;
B *b;
C *c;
+ D *d;
+ E *e;
}
#include "virtualcall.h"
diff --git a/test/Analysis/vla.c b/test/Analysis/vla.c
new file mode 100644
index 000000000000..f94bea96e8f6
--- /dev/null
+++ b/test/Analysis/vla.c
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+
+// Zero-sized VLAs.
+void check_zero_sized_VLA(int x) {
+ if (x)
+ return;
+
+ int vla[x]; // expected-warning{{Declared variable-length array (VLA) has zero size}}
+}
+
+void check_uninit_sized_VLA() {
+ int x;
+ int vla[x]; // expected-warning{{Declared variable-length array (VLA) uses a garbage value as its size}}
+}
+
+// Negative VLAs.
+static void vla_allocate_signed(int x) {
+ int vla[x]; // expected-warning{{Declared variable-length array (VLA) has negative size}}
+}
+
+static void vla_allocate_unsigned(unsigned int x) {
+ int vla[x]; // no-warning
+}
+
+void check_negative_sized_VLA_1() {
+ vla_allocate_signed(-1);
+}
+
+void check_negative_sized_VLA_2() {
+ vla_allocate_unsigned(-1);
+}
+
+void check_negative_sized_VLA_3() {
+ int x = -1;
+ int vla[x]; // expected-warning{{Declared variable-length array (VLA) has negative size}}
+}
+
+void check_negative_sized_VLA_4() {
+ unsigned int x = -1;
+ int vla[x]; // no-warning
+}
+
+void check_negative_sized_VLA_5() {
+ signed char x = -1;
+ int vla[x]; // expected-warning{{Declared variable-length array (VLA) has negative size}}
+}
+
+void check_negative_sized_VLA_6() {
+ unsigned char x = -1;
+ int vla[x]; // no-warning
+}
+
+void check_negative_sized_VLA_7() {
+ signed char x = -1;
+ int vla[x + 2]; // no-warning
+}
+
+void check_negative_sized_VLA_8() {
+ signed char x = 1;
+ int vla[x - 2]; // expected-warning{{Declared variable-length array (VLA) has negative size}}
+}
+
+void check_negative_sized_VLA_9() {
+ int x = 1;
+ int vla[x]; // no-warning
+}
+
+static void check_negative_sized_VLA_10_sub(int x)
+{
+ int vla[x]; // expected-warning{{Declared variable-length array (VLA) has negative size}}
+}
+
+void check_negative_sized_VLA_10(int x) {
+ if (x < 0)
+ check_negative_sized_VLA_10_sub(x);
+}
+
+static void check_negative_sized_VLA_11_sub(int x)
+{
+ int vla[x]; // no-warning
+}
+
+void check_negative_sized_VLA_11(int x) {
+ if (x > 0)
+ check_negative_sized_VLA_11_sub(x);
+}
diff --git a/test/CXX/basic/basic.types/p10.cpp b/test/CXX/basic/basic.types/p10.cpp
index 9d99a777449b..7b1af00b5d5c 100644
--- a/test/CXX/basic/basic.types/p10.cpp
+++ b/test/CXX/basic/basic.types/p10.cpp
@@ -38,15 +38,14 @@ constexpr ClassTemp<int> classtemplate2[] = {};
// - it has a trivial destructor
struct UserProvDtor {
- constexpr int f() const; // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
~UserProvDtor(); // expected-note {{has a user-provided destructor}}
};
-
+constexpr int f(UserProvDtor) { return 0; } // expected-error {{'UserProvDtor' is not a literal type}}
struct NonTrivDtor {
constexpr NonTrivDtor();
- constexpr int f() const; // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}} expected-note {{because it is virtual}}
};
+constexpr int f(NonTrivDtor) { return 0; } // expected-error {{'NonTrivDtor' is not a literal type}}
struct NonTrivDtorBase {
~NonTrivDtorBase();
};
@@ -77,12 +76,12 @@ struct CtorTemplate {
};
struct CopyCtorOnly { // expected-note {{'CopyCtorOnly' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors}}
constexpr CopyCtorOnly(CopyCtorOnly&);
- constexpr int f() const; // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}}
};
+constexpr int f(CopyCtorOnly) { return 0; } // expected-error {{'CopyCtorOnly' is not a literal type}}
struct MoveCtorOnly { // expected-note {{no constexpr constructors other than copy or move constructors}}
constexpr MoveCtorOnly(MoveCtorOnly&&);
- constexpr int f() const; // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}}
};
+constexpr int f(MoveCtorOnly) { return 0; } // expected-error {{'MoveCtorOnly' is not a literal type}}
template<typename T>
struct CtorArg {
constexpr CtorArg(T);
@@ -110,8 +109,8 @@ constexpr int f(NonLitMember) {} // expected-error {{1st parameter type 'NonLitM
struct NonLitBase :
S { // expected-note {{base class 'S' of non-literal type}}
constexpr NonLitBase();
- constexpr int f() const { return 0; } // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
};
+constexpr int f(NonLitBase) { return 0; } // expected-error {{'NonLitBase' is not a literal type}}
struct LitMemBase : Agg {
Agg agg;
};
diff --git a/test/CXX/class.access/class.friend/p11.cpp b/test/CXX/class.access/class.friend/p11.cpp
index ba44a0d49245..a5107fd20728 100644
--- a/test/CXX/class.access/class.friend/p11.cpp
+++ b/test/CXX/class.access/class.friend/p11.cpp
@@ -24,6 +24,8 @@ namespace test2 {
void foo() { // expected-note {{'::test2::foo' declared here}}
struct S1 {
friend void foo(); // expected-error {{no matching function 'foo' found in local scope; did you mean '::test2::foo'?}}
+ // expected-note@-1{{'::test2::foo' declared here}}
+ // TODO: the above note should go on line 24
};
void foo(); // expected-note {{local declaration nearly matches}}
@@ -40,17 +42,19 @@ namespace test2 {
{
int foo;
struct S3 {
- friend void foo(); // expected-error {{no matching function found in local scope}}
+ friend void foo(); // expected-error {{no matching function 'foo' found in local scope; did you mean '::test2::foo'?}}
};
}
struct S4 {
friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean '::test2::bar'?}}
+ // expected-note@-1 2 {{'::test2::bar' declared here}}
+ // TODO: the above two notes should go on line 22
};
{ void bar(); }
struct S5 {
- friend void bar(); // expected-error {{no matching function found in local scope}}
+ friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean '::test2::bar'?}}
};
{
@@ -85,7 +89,7 @@ namespace test2 {
void quux() {}
void foo() {
struct Inner1 {
- friend void bar(); // expected-error {{no matching function found in local scope}}
+ friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean '::test2::bar'?}}
friend void quux(); // expected-error {{no matching function found in local scope}}
};
diff --git a/test/CXX/class/class.mem/p2.cpp b/test/CXX/class/class.mem/p2.cpp
index 4aa4a5c6f1b7..d45c03860654 100644
--- a/test/CXX/class/class.mem/p2.cpp
+++ b/test/CXX/class/class.mem/p2.cpp
@@ -56,3 +56,33 @@ namespace test3 {
template struct A2<int>;
}
+
+namespace PR12629 {
+ struct S {
+ static int (f)() throw();
+ static int ((((((g))))() throw(U)));
+ int (*h)() noexcept(false);
+ static int (&i)() noexcept(true);
+ static int (*j)() throw(U); // expected-error {{unknown type name 'U'}}
+ static int (k)() throw(U);
+
+ struct U {};
+ };
+ static_assert(noexcept(S::f()), "");
+ static_assert(!noexcept(S::g()), "");
+ static_assert(!noexcept(S().h()), "");
+ static_assert(noexcept(S::i()), "");
+}
+
+namespace PR12688 {
+ struct S {
+ // FIXME: Producing one error saying this can't have the same name
+ // as the class because it's not a constructor, then producing
+ // another error saying this can't have a return type because
+ // it is a constructor, is redundant and inconsistent.
+ nonsense S() throw (more_nonsense); // \
+ // expected-error {{'nonsense'}} \
+ // expected-error {{has the same name as its class}} \
+ // expected-error {{constructor cannot have a return type}}
+ };
+}
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
index 4f89dcfb3f52..ebe5388d65ac 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
@@ -17,6 +17,11 @@ void f() {
using X::s; // expected-error{{using declaration cannot refer to class member}}
}
+template <typename T>
+struct PR21933 : T {
+ static void StaticFun() { using T::member; } // expected-error{{using declaration cannot refer to class member}}
+};
+
struct S {
static int n;
struct Q {};
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
index 3bbbf9eed6e4..a27cea84db45 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
@@ -21,8 +21,7 @@ e my_enum; // expected-warning {{'e' is deprecated}}
template <typename T> class X {};
template <> class [[deprecated]] X<int> {}; // expected-note {{'X<int>' has been explicitly marked deprecated here}}
X<char> x1;
-// FIXME: The diagnostic here could be much better by mentioning X<int>.
-X<int> x2; // expected-warning {{'X' is deprecated}}
+X<int> x2; // expected-warning {{'X<int>' is deprecated}}
template <typename T> class [[deprecated]] X2 {};
template <> class X2<int> {};
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
index 08fefdc91fb5..35dbec93e5bb 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
@@ -71,7 +71,7 @@ struct ConstexprDtor {
template <typename T> constexpr T ft(T t) { return t; }
template <typename T> T gt(T t) { return t; }
struct S {
- template<typename T> constexpr T f(); // expected-warning {{C++1y}}
+ template<typename T> constexpr T f(); // expected-warning {{C++14}}
template <typename T>
T g() const; // expected-note-re {{candidate template ignored: could not match 'T (){{( __attribute__\(\(thiscall\)\))?}} const' against 'char (){{( __attribute__\(\(thiscall\)\))?}}'}}
};
@@ -82,7 +82,7 @@ template <> char ft(char c) { return c; } // expected-note {{previous}}
template <> constexpr char ft(char nl); // expected-error {{constexpr declaration of 'ft<char>' follows non-constexpr declaration}}
template <> constexpr int gt(int nl) { return nl; }
template <> notlit S::f() const { return notlit(); }
-template <> constexpr int S::g() { return 0; } // expected-note {{previous}} expected-warning {{C++1y}}
+template <> constexpr int S::g() { return 0; } // expected-note {{previous}} expected-warning {{C++14}}
template <> int S::g() const; // expected-error {{non-constexpr declaration of 'g<int>' follows constexpr declaration}}
// specializations can drop the 'constexpr' but not the implied 'const'.
template <> char S::g() { return 0; } // expected-error {{no function template matches}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
index 780a420959d6..1e3734e54311 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
@@ -21,15 +21,15 @@ struct Literal {
struct S {
virtual int ImplicitlyVirtual() const = 0; // expected-note {{overridden virtual function}}
};
-struct SS : S {
+struct SS : S {
int ImplicitlyVirtual() const;
};
// The definition of a constexpr function shall satisfy the following
// constraints:
-struct T : SS, NonLiteral { // expected-note {{base class 'NonLiteral' of non-literal type}}
+struct T : SS, NonLiteral {
constexpr T();
- constexpr int f() const; // expected-error {{non-literal type 'T' cannot have constexpr members}}
+ constexpr int f() const;
// - it shall not be virtual;
virtual constexpr int ExplicitlyVirtual() const { return 0; } // expected-error {{virtual function cannot be constexpr}}
@@ -62,7 +62,7 @@ struct T : SS, NonLiteral { // expected-note {{base class 'NonLiteral' of non-li
constexpr T &operator=(const T&) = default;
#ifndef CXX1Y
// expected-error@-2 {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}}
- // expected-warning@-3 {{C++1y}}
+ // expected-warning@-3 {{C++14}}
#else
// expected-error@-5 {{defaulted definition of copy assignment operator is not constexpr}}
#endif
@@ -161,21 +161,21 @@ constexpr int ForStmt() {
constexpr int VarDecl() {
int a = 0;
#ifndef CXX1Y
- // expected-error@-2 {{variable declaration in a constexpr function is a C++1y extension}}
+ // expected-error@-2 {{variable declaration in a constexpr function is a C++14 extension}}
#endif
return 0;
}
constexpr int ConstexprVarDecl() {
constexpr int a = 0;
#ifndef CXX1Y
- // expected-error@-2 {{variable declaration in a constexpr function is a C++1y extension}}
+ // expected-error@-2 {{variable declaration in a constexpr function is a C++14 extension}}
#endif
return 0;
}
constexpr int VarWithCtorDecl() {
Literal a;
#ifndef CXX1Y
- // expected-error@-2 {{variable declaration in a constexpr function is a C++1y extension}}
+ // expected-error@-2 {{variable declaration in a constexpr function is a C++14 extension}}
#endif
return 0;
}
@@ -183,7 +183,7 @@ NonLiteral nl;
constexpr NonLiteral &ExternNonLiteralVarDecl() {
extern NonLiteral nl;
#ifndef CXX1Y
- // expected-error@-2 {{variable declaration in a constexpr function is a C++1y extension}}
+ // expected-error@-2 {{variable declaration in a constexpr function is a C++14 extension}}
#endif
return nl;
}
@@ -191,28 +191,28 @@ static_assert(&ExternNonLiteralVarDecl() == &nl, "");
constexpr int FuncDecl() {
constexpr int ForwardDecl(int);
#ifndef CXX1Y
- // expected-error@-2 {{use of this statement in a constexpr function is a C++1y extension}}
+ // expected-error@-2 {{use of this statement in a constexpr function is a C++14 extension}}
#endif
return ForwardDecl(42);
}
constexpr int ClassDecl1() {
typedef struct { } S1;
#ifndef CXX1Y
- // expected-error@-2 {{type definition in a constexpr function is a C++1y extension}}
+ // expected-error@-2 {{type definition in a constexpr function is a C++14 extension}}
#endif
return 0;
}
constexpr int ClassDecl2() {
using S2 = struct { };
#ifndef CXX1Y
- // expected-error@-2 {{type definition in a constexpr function is a C++1y extension}}
+ // expected-error@-2 {{type definition in a constexpr function is a C++14 extension}}
#endif
return 0;
}
constexpr int ClassDecl3() {
struct S3 { };
#ifndef CXX1Y
- // expected-error@-2 {{type definition in a constexpr function is a C++1y extension}}
+ // expected-error@-2 {{type definition in a constexpr function is a C++14 extension}}
#endif
return 0;
}
@@ -245,11 +245,11 @@ namespace DR1364 {
namespace rdar13584715 {
typedef __PTRDIFF_TYPE__ ptrdiff_t;
-
+
template<typename T> struct X {
static T value() {};
};
-
+
void foo(ptrdiff_t id) {
switch (id) {
case reinterpret_cast<ptrdiff_t>(&X<long>::value): // expected-error{{case value is not a constant expression}} \
@@ -269,7 +269,7 @@ namespace std_example {
constexpr int abs(int x) {
if (x < 0)
#ifndef CXX1Y
- // expected-error@-2 {{C++1y}}
+ // expected-error@-2 {{C++14}}
#endif
x = -x;
return x;
@@ -295,7 +295,7 @@ namespace std_example {
return r;
}
#ifndef CXX1Y
- // expected-error@-5 {{C++1y}}
+ // expected-error@-5 {{C++14}}
// expected-error@-5 {{statement not allowed}}
#endif
}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
index 708c259d5b61..9c1cab54b617 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
@@ -92,37 +92,37 @@ struct V {
constexpr V(int(&)[2]) {
constexpr int a = 0;
#ifndef CXX1Y
- // expected-error@-2 {{variable declaration in a constexpr constructor is a C++1y extension}}
+ // expected-error@-2 {{variable declaration in a constexpr constructor is a C++14 extension}}
#endif
}
constexpr V(int(&)[3]) {
constexpr int ForwardDecl(int);
#ifndef CXX1Y
- // expected-error@-2 {{use of this statement in a constexpr constructor is a C++1y extension}}
+ // expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}}
#endif
}
constexpr V(int(&)[4]) {
typedef struct { } S1;
#ifndef CXX1Y
- // expected-error@-2 {{type definition in a constexpr constructor is a C++1y extension}}
+ // expected-error@-2 {{type definition in a constexpr constructor is a C++14 extension}}
#endif
}
constexpr V(int(&)[5]) {
using S2 = struct { };
#ifndef CXX1Y
- // expected-error@-2 {{type definition in a constexpr constructor is a C++1y extension}}
+ // expected-error@-2 {{type definition in a constexpr constructor is a C++14 extension}}
#endif
}
constexpr V(int(&)[6]) {
struct S3 { };
#ifndef CXX1Y
- // expected-error@-2 {{type definition in a constexpr constructor is a C++1y extension}}
+ // expected-error@-2 {{type definition in a constexpr constructor is a C++14 extension}}
#endif
}
constexpr V(int(&)[7]) {
return;
#ifndef CXX1Y
- // expected-error@-2 {{use of this statement in a constexpr constructor is a C++1y extension}}
+ // expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}}
#endif
}
};
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
index 5e40f69d77ba..48973237ea0b 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
@@ -102,7 +102,7 @@ X x = cmin(X(), X()); // ok, not constexpr
template<typename T>
struct Y {
constexpr Y() {}
- constexpr int get() { return T(); } // expected-warning {{C++1y}}
+ constexpr int get() { return T(); } // expected-warning {{C++14}}
};
struct Z { operator int(); };
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
index 40aa600ba1f7..428fd50b270f 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
@@ -3,13 +3,13 @@
using size_t = decltype(sizeof(int));
struct S {
- constexpr int f(); // expected-warning {{C++1y}}
+ constexpr int f(); // expected-warning {{C++14}}
constexpr int g() const;
- constexpr int h(); // expected-warning {{C++1y}}
+ constexpr int h(); // expected-warning {{C++14}}
int h();
static constexpr int Sf();
/*static*/ constexpr void *operator new(size_t) noexcept;
- template<typename T> constexpr T tm(); // expected-warning {{C++1y}}
+ template<typename T> constexpr T tm(); // expected-warning {{C++14}}
template<typename T> static constexpr T ts();
};
@@ -26,20 +26,20 @@ void f(const S &s) {
}
constexpr int S::f() const { return 0; }
-constexpr int S::g() { return 1; } // expected-warning {{C++1y}}
-constexpr int S::h() { return 0; } // expected-warning {{C++1y}}
+constexpr int S::g() { return 1; } // expected-warning {{C++14}}
+constexpr int S::h() { return 0; } // expected-warning {{C++14}}
int S::h() { return 0; }
constexpr int S::Sf() { return 2; }
constexpr void *S::operator new(size_t) noexcept { return 0; }
-template<typename T> constexpr T S::tm() { return T(); } // expected-warning {{C++1y}}
+template<typename T> constexpr T S::tm() { return T(); } // expected-warning {{C++14}}
template<typename T> constexpr T S::ts() { return T(); }
namespace std_example {
- class debug_flag { // expected-note {{not an aggregate and has no constexpr constructors}}
+ class debug_flag {
public:
explicit debug_flag(bool);
- constexpr bool is_on() const; // expected-error {{non-literal type 'std_example::debug_flag' cannot have constexpr members}}
+ constexpr bool is_on() const; // ok (dr1684)
private:
bool flag;
};
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
index 2412a145f866..5f102e7458ea 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
@@ -17,7 +17,7 @@ extern int (*const d)(int);
// A variable declaration which uses the constexpr specifier shall have an
// initializer and shall be initialized by a constant expression.
-constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}}
+constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'ni1'}}
constexpr struct C { C(); } ni2; // expected-error {{cannot have non-literal type 'const struct C'}} expected-note 3{{has no constexpr constructors}}
constexpr double &ni3; // expected-error {{declaration of reference variable 'ni3' requires an initializer}}
@@ -34,4 +34,4 @@ struct pixel {
int x, y;
};
constexpr pixel ur = { 1294, 1024 }; // ok
-constexpr pixel origin; // expected-error {{default initialization of an object of const type 'const pixel' requires a user-provided default constructor}}
+constexpr pixel origin; // expected-error {{default initialization of an object of const type 'const pixel' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'origin'}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
index cc44f74a5547..865abb081a44 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
@@ -44,7 +44,7 @@ namespace VariableLengthArrays {
void f() {
int n = 42;
- goto foo; // expected-error {{goto into protected scope}}
+ goto foo; // expected-error {{cannot jump}}
using T = int[n]; // expected-note {{bypasses initialization of VLA type alias}}
foo: ;
}
diff --git a/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
index b9a1bc52886c..81876192caa7 100644
--- a/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
+++ b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
@@ -36,7 +36,7 @@ struct S3 {
constexpr S3 s3a = S3(0);
constexpr S3 s3b = s3a;
constexpr S3 s3c = S3();
-constexpr S3 s3d; // expected-error {{default initialization of an object of const type 'const S3' requires a user-provided default constructor}}
+constexpr S3 s3d; // expected-error {{default initialization of an object of const type 'const S3' without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 's3d'}}
struct S4 {
S4() = default;
@@ -119,6 +119,6 @@ namespace PR13492 {
};
void f() {
- const B b; // expected-error {{default initialization of an object of const type 'const PR13492::B' requires a user-provided default constructor}}
+ const B b; // expected-error {{default initialization of an object of const type 'const PR13492::B' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'b'}}
}
}
diff --git a/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.general/p8.cpp b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.general/p8.cpp
new file mode 100644
index 000000000000..ff5d3dec3083
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.general/p8.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+// expected-no-diagnostics
+
+using size_t = decltype(sizeof(0));
+template<typename T> struct check;
+template<size_t N> struct check<const char[N]> {};
+
+constexpr bool startswith(const char *p, const char *q) {
+ return !*q || (*p == *q && startswith(p + 1, q + 1));
+}
+constexpr bool contains(const char *p, const char *q) {
+ return *p && (startswith(p, q) || contains(p + 1, q));
+}
+
+void foo() {
+ check<decltype(__func__)>();
+ static_assert(contains(__func__, "foo"), "");
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
index 971e0c11aff1..d7ffd0758a68 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
@@ -4,7 +4,7 @@ namespace std {
typedef decltype(sizeof(int)) size_t;
template <typename E>
- struct initializer_list // expected-note 2{{candidate}}
+ struct initializer_list
{
const E *p;
size_t n;
@@ -112,15 +112,16 @@ namespace bullet8 {
}
namespace rdar13395022 {
- struct MoveOnly {
- MoveOnly(MoveOnly&&);
+ struct MoveOnly { // expected-note {{candidate}}
+ MoveOnly(MoveOnly&&); // expected-note 2{{copy constructor is implicitly deleted because}} expected-note {{candidate}}
};
void test(MoveOnly mo) {
- // FIXME: These diagnostics are poor.
- auto &&list1 = {mo}; // expected-error{{no viable conversion}}
- MoveOnly (&&list2)[1] = {mo}; // expected-error{{no viable conversion}}
+ auto &&list1 = {mo}; // expected-error {{call to implicitly-deleted copy constructor}} expected-note {{in initialization of temporary of type 'std::initializer_list}}
+ MoveOnly (&&list2)[1] = {mo}; // expected-error {{call to implicitly-deleted copy constructor}} expected-note {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]'}}
std::initializer_list<MoveOnly> &&list3 = {};
- MoveOnly (&&list4)[1] = {}; // expected-error{{uninitialized}}
+ MoveOnly (&&list4)[1] = {}; // expected-error {{no matching constructor}}
+ // expected-note@-1 {{in implicit initialization of array element 0 with omitted initializer}}
+ // expected-note@-2 {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]' created to list-initialize this reference}}
}
}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
index 4ba75efebbb3..f86b24e99259 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option -Wbind-to-temporary-copy -verify %s
// C++03 requires that we check for a copy constructor when binding a
// reference to a temporary, since we are allowed to make a copy, Even
diff --git a/test/CXX/dcl.decl/dcl.init/p6.cpp b/test/CXX/dcl.decl/dcl.init/p6.cpp
index 514fd0c9b620..76b7e7625d57 100644
--- a/test/CXX/dcl.decl/dcl.init/p6.cpp
+++ b/test/CXX/dcl.decl/dcl.init/p6.cpp
@@ -10,15 +10,15 @@ struct NoUserDefault : public MakeNonPOD { };
struct HasUserDefault { HasUserDefault(); };
void test_const_default_init() {
- const NoUserDefault x1; // expected-error{{default initialization of an object of const type 'const NoUserDefault' requires a user-provided default constructor}}
+ const NoUserDefault x1; // expected-error{{default initialization of an object of const type 'const NoUserDefault' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'x1'}}
const HasUserDefault x2;
- const int x3; // expected-error{{default initialization of an object of const type 'const int'}}
+ const int x3; // expected-error{{default initialization of an object of const type 'const int'}} expected-note{{add an explicit initializer to initialize 'x3'}}
}
// 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}}
+const struct s0 s1::foo; // expected-error{{default initialization of an object of const type 'const struct s0' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'foo'}}
template<typename T>
struct s2 {
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
index 19a5f23e3f17..de1c5a708db6 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
@@ -46,3 +46,34 @@ struct X2 {
template<typename T>
void f4(T ...args); // expected-error{{type 'T' of function parameter pack does not contain any unexpanded parameter packs}}
+void f4i(int ... x); // expected-error{{type 'int' of function parameter pack does not contain any unexpanded parameter packs}}
+void f4i0(int ...);
+
+namespace array_type {
+template<typename T>
+void a(T[] ... x); // expected-error{{expected ')'}} expected-note{{to match this '('}}
+
+template<typename T>
+void b(T[] ...);
+
+template<typename T>
+void c(T ... []); // expected-error{{type 'T []' of function parameter pack does not contain any unexpanded parameter packs}}
+
+template<typename T>
+void d(T ... x[]); // expected-error{{type 'T []' of function parameter pack does not contain any unexpanded parameter packs}}
+
+void ai(int[] ... x); // expected-error{{expected ')'}} expected-note{{to match this '('}}
+void bi(int[] ...);
+void ci(int ... []); // expected-error{{type 'int []' of function parameter pack does not contain any unexpanded parameter packs}}
+void di(int ... x[]); // expected-error{{type 'int []' of function parameter pack does not contain any unexpanded parameter packs}}
+}
+
+void f5a(auto fp(int)->unk ...) {} // expected-error{{unknown type name 'unk'}}
+void f5b(auto fp(int)->auto ...) {} // expected-error{{'auto' not allowed in function return type}}
+void f5c(auto fp()->...) {} // expected-error{{expected a type}}
+
+// FIXME: Expand for function and member pointer types.
+
+
+
+
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
index bc249b5a087b..ac9344dea1c1 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-// expected-no-diagnostics
template<typename T> struct identity;
template<typename ...Types> struct tuple;
@@ -22,7 +21,7 @@ template<typename T> struct is_same<T, T> {
template<typename T, typename ...Types>
struct X0 {
typedef identity<T(Types...)> function_pack_1;
- typedef identity<T(Types......)> variadic_function_pack_1;
+ typedef identity<T(Types......)> variadic_function_pack_1; // expected-warning {{varargs}} expected-note {{pack}} expected-note {{insert ','}}
typedef identity<T(T...)> variadic_1;
typedef tuple<T(Types, ...)...> template_arg_expansion_1;
};
diff --git a/test/CXX/dcl.decl/dcl.meaning/p1.cpp b/test/CXX/dcl.decl/dcl.meaning/p1.cpp
index 5747380f2806..cefee7b8dc41 100644
--- a/test/CXX/dcl.decl/dcl.meaning/p1.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/p1.cpp
@@ -27,6 +27,7 @@ namespace NS {
struct X;
template<typename T> struct Y;
template<typename T> void wibble(T);
+ struct Z;
}
namespace NS {
// Under DR482, these are all valid, except for forward-declaring a struct
@@ -43,3 +44,6 @@ namespace NS {
template<typename T> struct NS::Y { }; // expected-warning{{extra qualification on member 'Y'}}
template<typename T> void NS::wibble(T) { } // expected-warning{{extra qualification on member 'wibble'}}
}
+
+struct ::{} a; // expected-error{{expected identifier}}
+struct NS::Z:: {} b; // expected-error{{expected identifier}}
diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp
index 29e1720b1bbf..5b34cc3380c1 100644
--- a/test/CXX/drs/dr0xx.cpp
+++ b/test/CXX/drs/dr0xx.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -Wno-bind-to-temporary-copy
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
namespace dr1 { // dr1: no
namespace X { extern "C" void dr1_f(int a = 1); }
@@ -520,17 +521,28 @@ namespace dr48 { // dr48: yes
}
namespace dr49 { // dr49: yes
- template<int*> struct A {}; // expected-note {{here}}
+ template<int*> struct A {}; // expected-note 0-2{{here}}
int k;
#if __has_feature(cxx_constexpr)
constexpr
#endif
- int *const p = &k;
+ int *const p = &k; // expected-note 0-2{{here}}
A<&k> a;
- A<p> b; // expected-error {{must have its address taken}}
+ A<p> b;
+#if __cplusplus <= 201402L
+ // expected-error@-2 {{must have its address taken}}
+#endif
+#if __cplusplus < 201103L
+ // expected-error@-5 {{internal linkage}}
+#endif
+ int *q = &k;
+ A<q> c;
#if __cplusplus < 201103L
- // expected-error@-2 {{internal linkage}}
- // expected-note@-5 {{here}}
+ // expected-error@-2 {{must have its address taken}}
+#else
+ // expected-error@-4 {{constant expression}}
+ // expected-note@-5 {{read of non-constexpr}}
+ // expected-note@-7 {{declared here}}
#endif
}
@@ -822,7 +834,7 @@ namespace dr70 { // dr70: yes
namespace dr73 { // dr73: no
// The resolution to dr73 is unworkable. Consider:
int a, b;
- static_assert(&a + 1 != &b, "");
+ static_assert(&a + 1 != &b, ""); // expected-error {{not an integral constant expression}}
}
#endif
@@ -852,7 +864,7 @@ namespace dr77 { // dr77: yes
namespace dr78 { // dr78: sup ????
// Under DR78, this is valid, because 'k' has static storage duration, so is
// zero-initialized.
- const int k; // expected-error {{default initialization of an object of const}}
+ const int k; // expected-error {{default initialization of an object of const}} expected-note{{add an explicit initializer to initialize 'k'}}
}
// dr79: na
@@ -994,6 +1006,10 @@ namespace dr92 { // dr92: yes
g(q); // expected-error {{is not superset}}
}
+ // Prior to C++17, this is OK because the exception specification is not
+ // considered in this context. In C++17, we *do* perform an implicit
+ // conversion (which performs initialization), but we convert to the type of
+ // the template parameter, which does not include the exception specification.
template<void() throw()> struct X {};
X<&f> xp; // ok
}
@@ -1051,18 +1067,18 @@ namespace dr98 { // dr98: yes
void test(int n) {
switch (n) {
try { // expected-note 2{{bypasses}}
- case 0: // expected-error {{protected}}
+ case 0: // expected-error {{cannot jump}}
x:
throw n;
} catch (...) { // expected-note 2{{bypasses}}
- case 1: // expected-error {{protected}}
+ case 1: // expected-error {{cannot jump}}
y:
throw n;
}
case 2:
- goto x; // expected-error {{protected}}
+ goto x; // expected-error {{cannot jump}}
case 3:
- goto y; // expected-error {{protected}}
+ goto y; // expected-error {{cannot jump}}
}
}
}
diff --git a/test/CXX/drs/dr10xx.cpp b/test/CXX/drs/dr10xx.cpp
index 64c71b2b0f92..a1d7ef67c66d 100644
--- a/test/CXX/drs/dr10xx.cpp
+++ b/test/CXX/drs/dr10xx.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// expected-no-diagnostics
@@ -13,6 +14,24 @@ namespace std {
};
}
+namespace dr1048 { // dr1048: 3.6
+ struct A {};
+ const A f();
+ A g();
+ typedef const A CA;
+#if __cplusplus >= 201103L
+ // ok: we deduce non-const A in each case.
+ A &&a = [] (int n) {
+ while (1) switch (n) {
+ case 0: return f();
+ case 1: return g();
+ case 2: return A();
+ case 3: return CA();
+ }
+ } (0);
+#endif
+}
+
namespace dr1070 { // dr1070: 3.5
#if __cplusplus >= 201103L
struct A {
diff --git a/test/CXX/drs/dr13xx.cpp b/test/CXX/drs/dr13xx.cpp
index 5827291142dc..29b39cbb95a1 100644
--- a/test/CXX/drs/dr13xx.cpp
+++ b/test/CXX/drs/dr13xx.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
namespace dr1346 { // dr1346: 3.5
auto a(1); // expected-error 0-1{{extension}}
diff --git a/test/CXX/drs/dr14xx.cpp b/test/CXX/drs/dr14xx.cpp
index 8de1b8d623a9..e93192427268 100644
--- a/test/CXX/drs/dr14xx.cpp
+++ b/test/CXX/drs/dr14xx.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
#if __cplusplus < 201103L
// expected-no-diagnostics
diff --git a/test/CXX/drs/dr15xx.cpp b/test/CXX/drs/dr15xx.cpp
index 66618c1716d6..d7c2b9225c4d 100644
--- a/test/CXX/drs/dr15xx.cpp
+++ b/test/CXX/drs/dr15xx.cpp
@@ -1,16 +1,17 @@
// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1y -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// expected-no-diagnostics
-namespace DR1550 { // dr1550: yes
+namespace dr1550 { // dr1550: yes
int f(bool b, int n) {
return (b ? (throw 0) : n) + (b ? n : (throw 0));
}
}
-namespace DR1560 { // dr1560: 3.5
+namespace dr1560 { // dr1560: 3.5
void f(bool b, int n) {
(b ? throw 0 : n) = (b ? n : throw 0) = 0;
}
diff --git a/test/CXX/drs/dr16xx.cpp b/test/CXX/drs/dr16xx.cpp
new file mode 100644
index 000000000000..62040f1a130a
--- /dev/null
+++ b/test/CXX/drs/dr16xx.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+#if __cplusplus < 201103L
+// expected-no-diagnostics
+#endif
+
+namespace dr1684 { // dr1684: 3.6
+#if __cplusplus >= 201103L
+ struct NonLiteral { // expected-note {{because}}
+ NonLiteral();
+ constexpr int f() { return 0; } // expected-warning 0-1{{will not be implicitly 'const'}}
+ };
+ constexpr int f(NonLiteral &) { return 0; }
+ constexpr int f(NonLiteral) { return 0; } // expected-error {{not a literal type}}
+#endif
+}
diff --git a/test/CXX/drs/dr18xx.cpp b/test/CXX/drs/dr18xx.cpp
new file mode 100644
index 000000000000..bc72b67d1e0b
--- /dev/null
+++ b/test/CXX/drs/dr18xx.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+#if __cplusplus < 201103L
+// expected-no-diagnostics
+#endif
+
+void dr1891() { // dr1891: 3.6
+#if __cplusplus >= 201103L
+ int n;
+ auto a = []{}; // expected-note 2{{candidate}}
+ auto b = [=]{ return n; }; // expected-note 2{{candidate}}
+ typedef decltype(a) A;
+ typedef decltype(b) B;
+
+ static_assert(!__has_trivial_constructor(A), "");
+ static_assert(!__has_trivial_constructor(B), "");
+
+ A x; // expected-error {{no matching constructor}}
+ B y; // expected-error {{no matching constructor}}
+#endif
+}
diff --git a/test/CXX/drs/dr1xx.cpp b/test/CXX/drs/dr1xx.cpp
index 6aff43c6a488..cc6c5af81708 100644
--- a/test/CXX/drs/dr1xx.cpp
+++ b/test/CXX/drs/dr1xx.cpp
@@ -1,10 +1,11 @@
// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1y -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
namespace dr100 { // dr100: yes
- template<const char *> struct A {}; // expected-note {{declared here}}
- template<const char (&)[4]> struct B {}; // expected-note {{declared here}}
+ template<const char *> struct A {}; // expected-note 0-1{{declared here}}
+ template<const char (&)[4]> struct B {}; // expected-note 0-1{{declared here}}
A<"foo"> a; // expected-error {{does not refer to any declaration}}
B<"bar"> b; // expected-error {{does not refer to any declaration}}
}
diff --git a/test/CXX/drs/dr2xx.cpp b/test/CXX/drs/dr2xx.cpp
index bb9af9fd9337..bb1f13ac64ee 100644
--- a/test/CXX/drs/dr2xx.cpp
+++ b/test/CXX/drs/dr2xx.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// PR13819 -- __SIZE_TYPE__ is incompatible.
typedef __SIZE_TYPE__ size_t; // expected-error 0-1 {{extension}}
@@ -195,8 +196,8 @@ namespace dr218 { // dr218: yes
// dr220: na
namespace dr221 { // dr221: yes
- struct A {
- A &operator=(int&);
+ struct A { // expected-note 2-4{{candidate}}
+ A &operator=(int&); // expected-note 2{{candidate}}
A &operator+=(int&);
static A &operator=(A&, double&); // expected-error {{cannot be a static member}}
static A &operator+=(A&, double&); // expected-error {{cannot be a static member}}
@@ -209,9 +210,9 @@ namespace dr221 { // dr221: yes
void test(A a, int n, char c, float f) {
a = n;
a += n;
- a = c;
+ a = c; // expected-error {{no viable}}
a += c;
- a = f;
+ a = f; // expected-error {{no viable}}
a += f;
}
}
@@ -466,7 +467,7 @@ namespace dr243 { // dr243: yes
A a2 = b; // expected-error {{ambiguous}}
}
-namespace dr244 { // dr244: 3.5
+namespace dr244 { // dr244: partial
struct B {}; struct D : B {}; // expected-note {{here}}
D D_object;
@@ -484,6 +485,28 @@ namespace dr244 { // dr244: 3.5
B_ptr->dr244::~B(); // expected-error {{refers to a member in namespace}}
B_ptr->dr244::~B_alias(); // expected-error {{refers to a member in namespace}}
}
+
+ namespace N {
+ template<typename T> struct E {};
+ typedef E<int> F;
+ }
+ void g(N::F f) {
+ typedef N::F G;
+ f.~G();
+ f.G::~E();
+ f.G::~F(); // expected-error {{expected the class name after '~' to name a destructor}}
+ f.G::~G();
+ // This is technically ill-formed; E is looked up in 'N::' and names the
+ // class template, not the injected-class-name of the class. But that's
+ // probably a bug in the standard.
+ f.N::F::~E();
+ // This is valid; we look up the second F in the same scope in which we
+ // found the first one, that is, 'N::'.
+ f.N::F::~F(); // FIXME: expected-error {{expected the class name after '~' to name a destructor}}
+ // This is technically ill-formed; G is looked up in 'N::' and is not found;
+ // as above, this is probably a bug in the standard.
+ f.N::F::~G();
+ }
}
namespace dr245 { // dr245: yes
@@ -499,7 +522,7 @@ namespace dr246 { // dr246: yes
throw 0;
X: ;
} catch (int) {
- goto X; // expected-error {{protected scope}}
+ goto X; // expected-error {{cannot jump}}
}
};
}
@@ -968,12 +991,11 @@ namespace dr289 { // dr289: yes
namespace dr294 { // dr294: no
void f() throw(int);
int main() {
- // FIXME: we reject this for the wrong reason, because we don't implement
- // dr87 yet.
- (void)static_cast<void (*)() throw()>(f); // expected-error {{not superset}}
- void (*p)() throw() = f; // expected-error {{not superset}}
-
+ (void)static_cast<void (*)() throw()>(f); // FIXME: ill-formed
(void)static_cast<void (*)() throw(int)>(f); // FIXME: ill-formed
+
+ void (*p)() throw() = f; // expected-error {{not superset}}
+ void (*q)() throw(int) = f;
}
}
diff --git a/test/CXX/drs/dr3xx.cpp b/test/CXX/drs/dr3xx.cpp
index 53fc20e23fe6..cea4d64e7eb6 100644
--- a/test/CXX/drs/dr3xx.cpp
+++ b/test/CXX/drs/dr3xx.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
namespace dr300 { // dr300: yes
template<typename R, typename A> void f(R (&)(A)) {}
@@ -181,9 +182,15 @@ namespace dr308 { // dr308: yes
namespace dr311 { // dr311: yes
namespace X { namespace Y {} }
- namespace X::Y {} // expected-error {{must define each namespace separately}}
+ namespace X::Y {}
+#if __cplusplus <= 201402L
+ // expected-error@-2 {{define each namespace separately}}
+#endif
namespace X {
- namespace X::Y {} // expected-error {{must define each namespace separately}}
+ namespace X::Y {}
+#if __cplusplus <= 201402L
+ // expected-error@-2 {{define each namespace separately}}
+#endif
}
// FIXME: The diagnostics here are not very good.
namespace ::dr311::X {} // expected-error 2+{{}} // expected-warning {{extra qual}}
@@ -199,7 +206,7 @@ namespace dr313 { // dr313: dup 299 c++11
#endif
}
-namespace dr314 { // dr314: dup 1710
+namespace dr314 { // FIXME 314: dup 1710
template<typename T> struct A {
template<typename U> struct B {};
};
@@ -322,6 +329,7 @@ namespace dr324 { // dr324: yes
int *f = &(true ? s.n : s.n); // expected-error {{address of bit-field}}
int &g = (void(), s.n); // expected-error {{non-const reference cannot bind to bit-field}}
int *h = &(void(), s.n); // expected-error {{address of bit-field}}
+ int *i = &++s.n; // expected-error {{address of bit-field}}
}
namespace dr326 { // dr326: yes
@@ -365,7 +373,7 @@ namespace dr331 { // dr331: yes
} const a, b(a); // expected-error {{no matching constructor}}
}
-namespace dr332 { // dr332: dup 557
+namespace dr332 { // dr332: dup 577
void f(volatile void); // expected-error {{'void' as parameter must not have type qualifiers}}
void g(const void); // expected-error {{'void' as parameter must not have type qualifiers}}
void h(int n, volatile void); // expected-error {{'void' must be the first and only parameter}}
@@ -497,7 +505,7 @@ namespace dr341 {
// dr342: na
-namespace dr343 { // dr343: no
+namespace dr343 { // FIXME 343: no
// FIXME: dup 1710
template<typename T> struct A {
template<typename U> struct B {};
@@ -697,7 +705,7 @@ namespace dr354 { // dr354: yes c++11
// FIXME: Should we allow this in C++98 too?
struct S {};
- template<int*> struct ptr {}; // expected-note +{{here}}
+ template<int*> struct ptr {}; // expected-note 0-4{{here}}
ptr<0> p0;
ptr<(int*)0> p1;
ptr<(float*)0> p2;
@@ -707,11 +715,16 @@ namespace dr354 { // dr354: yes c++11
// expected-error@-5 {{does not refer to any decl}}
// expected-error@-5 {{does not refer to any decl}}
// expected-error@-5 {{does not refer to any decl}}
-#else
+#elif __cplusplus <= 201402L
// expected-error@-10 {{must be cast}}
// ok
// expected-error@-10 {{does not match}}
// expected-error@-10 {{does not match}}
+#else
+ // expected-error@-15 {{conversion from 'int' to 'int *' is not allowed}}
+ // ok
+ // expected-error@-15 {{'float *' is not implicitly convertible to 'int *'}}
+ // expected-error@-15 {{'int dr354::S::*' is not implicitly convertible to 'int *'}}
#endif
template<int*> int both();
@@ -724,7 +737,7 @@ namespace dr354 { // dr354: yes c++11
// expected-note@-6 {{candidate}}
#endif
- template<int S::*> struct ptr_mem {}; // expected-note +{{here}}
+ template<int S::*> struct ptr_mem {}; // expected-note 0-4{{here}}
ptr_mem<0> m0;
ptr_mem<(int S::*)0> m1;
ptr_mem<(float S::*)0> m2;
@@ -734,11 +747,16 @@ namespace dr354 { // dr354: yes c++11
// expected-error@-5 {{is not a pointer to member constant}}
// expected-error@-5 {{cannot be converted}}
// expected-error@-5 {{cannot be converted}}
-#else
+#elif __cplusplus <= 201402L
// expected-error@-10 {{must be cast}}
// ok
// expected-error@-10 {{does not match}}
// expected-error@-10 {{does not match}}
+#else
+ // expected-error@-15 {{conversion from 'int' to 'int dr354::S::*' is not allowed}}
+ // ok
+ // expected-error@-15 {{'float dr354::S::*' is not implicitly convertible to 'int dr354::S::*'}}
+ // expected-error@-15 {{'int *' is not implicitly convertible to 'int dr354::S::*'}}
#endif
}
@@ -1201,7 +1219,7 @@ namespace dr391 { // dr391: yes c++11
namespace dr395 { // dr395: yes
struct S {
- template <typename T, int N>(&operator T())[N]; // expected-error {{must use a typedef}}
+ template <typename T, int N>(&operator T())[N]; // expected-error {{cannot specify any part of a return type}}
template <typename T, int N> operator(T (&)[N])(); // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error +{{}}
template <typename T> operator T *() const { return 0; }
template <typename T, typename U> operator T U::*() const { return 0; }
diff --git a/test/CXX/drs/dr412.cpp b/test/CXX/drs/dr412.cpp
index cb33e206a632..39cdd6182d20 100644
--- a/test/CXX/drs/dr412.cpp
+++ b/test/CXX/drs/dr412.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -DNOEXCEPT="throw()" -DBAD_ALLOC="throw(std::bad_alloc)"
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -DNOEXCEPT=noexcept -DBAD_ALLOC=
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -DNOEXCEPT=noexcept -DBAD_ALLOC=
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -DNOEXCEPT=noexcept -DBAD_ALLOC=
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -DNOEXCEPT=noexcept -DBAD_ALLOC=
// dr412: yes
// lwg404: yes
diff --git a/test/CXX/drs/dr4xx.cpp b/test/CXX/drs/dr4xx.cpp
index 815dbfc0b401..42c6774dd186 100644
--- a/test/CXX/drs/dr4xx.cpp
+++ b/test/CXX/drs/dr4xx.cpp
@@ -1,6 +1,7 @@
// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// FIXME: __SIZE_TYPE__ expands to 'long long' on some targets.
__extension__ typedef __SIZE_TYPE__ size_t;
@@ -501,15 +502,15 @@ namespace dr436 { // dr436: yes
void f(); // expected-error {{redefinition}}
}
-namespace dr437 { // dr437: no
+namespace dr437 { // dr437: sup 1308
// This is superseded by 1308, which is in turn superseded by 1330,
// which restores this rule.
- template<typename U> struct T : U {}; // expected-error {{incomplete}}
- struct S { // expected-note {{not complete}}
+ template<typename U> struct T : U {};
+ struct S {
void f() throw(S);
- void g() throw(T<S>); // expected-note {{in instantiation of}}
- struct U; // expected-note {{forward}}
- void h() throw(U); // expected-error {{incomplete}}
+ void g() throw(T<S>);
+ struct U;
+ void h() throw(U);
struct U {};
};
}
@@ -755,7 +756,7 @@ namespace dr467 { // dr467: yes
return k;
}
int g() {
- goto later; // expected-error {{protected scope}}
+ goto later; // expected-error {{cannot jump}}
int k = stuff(); // expected-note {{bypasses variable initialization}}
later:
return k;
@@ -1201,7 +1202,7 @@ namespace dr497 { // dr497: yes
struct S {
mutable int i;
};
- const S cs; // expected-error {{default initialization}}
+ const S cs; // expected-error {{default initialization}} expected-note {{add an explicit initializer}}
int S::*pm = &S::i;
cs.*pm = 88;
}
diff --git a/test/CXX/drs/dr5xx.cpp b/test/CXX/drs/dr5xx.cpp
index 0c0d451c4b22..5bf085f52204 100644
--- a/test/CXX/drs/dr5xx.cpp
+++ b/test/CXX/drs/dr5xx.cpp
@@ -1,6 +1,13 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+// FIXME: This is included to avoid a diagnostic with no source location
+// pointing at the implicit operator new. We can't match such a diagnostic
+// with -verify.
+__extension__ typedef __SIZE_TYPE__ size_t;
+void *operator new(size_t); // expected-warning 0-1{{missing exception spec}} expected-note{{candidate}}
namespace dr500 { // dr500: dup 372
class D;
@@ -195,6 +202,153 @@ namespace dr525 { // dr525: yes
}
}
+namespace dr526 { // dr526: yes
+ template<int> struct S {};
+ template<int N> void f1(S<N> s);
+ template<int N> void f2(S<(N)> s); // expected-note {{couldn't infer}}
+ template<int N> void f3(S<+N> s); // expected-note {{couldn't infer}}
+ template<int N> void g1(int (&)[N]);
+ template<int N> void g2(int (&)[(N)]); // expected-note {{couldn't infer}}
+ template<int N> void g3(int (&)[+N]); // expected-note {{couldn't infer}}
+
+ void test(int (&a)[3], S<3> s) {
+ f1(s);
+ f2(s); // expected-error {{no matching}}
+ f3(s); // expected-error {{no matching}}
+ g1(a);
+ g2(a); // expected-error {{no matching}}
+ g3(a); // expected-error {{no matching}}
+ }
+
+ template<int N> struct X {
+ typedef int type;
+ X<N>::type v1;
+ X<(N)>::type v2; // expected-error {{missing 'typename'}}
+ X<+N>::type v3; // expected-error {{missing 'typename'}}
+ };
+}
+
+namespace dr527 { // dr527: na
+ // This DR is meaningless. It removes a required diagnostic from the case
+ // where a not-externally-visible object is odr-used but not defined, which
+ // requires a diagnostic for a different reason.
+ extern struct { int x; } a; // FIXME: We should reject this, per dr389.
+ static struct { int x; } b;
+ extern "C" struct { int x; } c;
+ namespace { extern struct { int x; } d; }
+ typedef struct { int x; } *P;
+ struct E { static P e; }; // FIXME: We should reject this, per dr389.
+ namespace { struct F { static P f; }; }
+
+ int ax = a.x, bx = b.x, cx = c.x, dx = d.x, ex = E::e->x, fx = F::f->x;
+}
+
+namespace dr530 { // dr530: yes
+ template<int*> struct S { enum { N = 1 }; };
+ template<void(*)()> struct T { enum { N = 1 }; };
+ int n;
+ void f();
+ int a[S<&n>::N];
+ int b[T<&f>::N];
+}
+
+namespace dr531 { // dr531: partial
+ namespace good {
+ template<typename T> struct A {
+ void f(T) { T::error; }
+ template<typename U> void g(T, U) { T::error; }
+ struct B { typename T::error error; };
+ template<typename U> struct C { typename T::error error; };
+ static T n;
+ };
+ template<typename T> T A<T>::n = T::error;
+
+ template<> void A<int>::f(int) {}
+ template<> template<typename U> void A<int>::g(int, U) {}
+ template<> struct A<int>::B {};
+ template<> template<typename U> struct A<int>::C {};
+ template<> int A<int>::n = 0;
+
+ void use(A<int> a) {
+ a.f(a.n);
+ a.g(0, 0);
+ A<int>::B b;
+ A<int>::C<int> c;
+ }
+
+ template<> struct A<char> {
+ void f(char);
+ template<typename U> void g(char, U);
+ struct B;
+ template<typename U> struct C;
+ static char n;
+ };
+
+ void A<char>::f(char) {}
+ template<typename U> void A<char>::g(char, U) {}
+ struct A<char>::B {};
+ template<typename U> struct A<char>::C {};
+ char A<char>::n = 0;
+ }
+
+ namespace bad {
+ template<typename T> struct A {
+ void f(T) { T::error; }
+ template<typename U> void g(T, U) { T::error; }
+ struct B { typename T::error error; };
+ template<typename U> struct C { typename T::error error; }; // expected-note {{here}}
+ static T n;
+ };
+ template<typename T> T A<T>::n = T::error;
+
+ void A<int>::f(int) {} // expected-error {{requires 'template<>'}}
+ template<typename U> void A<int>::g(int, U) {} // expected-error {{should be empty}}
+ struct A<int>::B {}; // expected-error {{requires 'template<>'}}
+ template<typename U> struct A<int>::C {}; // expected-error {{should be empty}} expected-error {{different kind of symbol}}
+ int A<int>::n = 0; // expected-error {{requires 'template<>'}}
+
+ template<> struct A<char> { // expected-note 2{{here}}
+ void f(char);
+ template<typename U> void g(char, U);
+ struct B; // expected-note {{here}}
+ template<typename U> struct C;
+ static char n;
+ };
+
+ template<> void A<char>::f(char) {} // expected-error {{no function template matches}}
+ // FIXME: This is ill-formed; -pedantic-errors should reject.
+ template<> template<typename U> void A<char>::g(char, U) {} // expected-warning {{extraneous template parameter list}}
+ template<> struct A<char>::B {}; // expected-error {{extraneous 'template<>'}} expected-error {{does not specialize}}
+ // FIXME: This is ill-formed; -pedantic-errors should reject.
+ template<> template<typename U> struct A<char>::C {}; // expected-warning {{extraneous template parameter list}}
+ template<> char A<char>::n = 0; // expected-error {{extraneous 'template<>'}}
+ }
+
+ namespace nested {
+ template<typename T> struct A {
+ template<typename U> struct B;
+ };
+ template<> template<typename U> struct A<int>::B {
+ void f();
+ void g();
+ template<typename V> void h();
+ template<typename V> void i();
+ };
+ template<> template<typename U> void A<int>::B<U>::f() {}
+ template<typename U> void A<int>::B<U>::g() {} // expected-error {{should be empty}}
+
+ template<> template<typename U> template<typename V> void A<int>::B<U>::h() {}
+ template<typename U> template<typename V> void A<int>::B<U>::i() {} // expected-error {{should be empty}}
+
+ template<> template<> void A<int>::B<int>::f() {}
+ template<> template<> template<typename V> void A<int>::B<int>::h() {}
+ template<> template<> template<> void A<int>::B<int>::h<int>() {}
+
+ template<> void A<int>::B<char>::f() {} // expected-error {{requires 'template<>'}}
+ template<> template<typename V> void A<int>::B<char>::h() {} // expected-error {{should be empty}}
+ }
+}
+
// PR8130
namespace dr532 { // dr532: 3.5
struct A { };
@@ -210,3 +364,632 @@ namespace dr532 { // dr532: 3.5
int &ir = b * a;
}
}
+
+// dr533: na
+
+namespace dr534 { // dr534: yes
+ struct S {};
+ template<typename T> void operator+(S, T);
+ template<typename T> void operator+<T*>(S, T*) {} // expected-error {{function template partial spec}}
+}
+
+namespace dr535 { // dr535: yes
+ class X { private: X(const X&); };
+ struct A {
+ X x;
+ template<typename T> A(T&);
+ };
+ struct B : A {
+ X y;
+ B(volatile A&);
+ };
+
+ extern A a1;
+ A a2(a1); // ok, uses constructor template
+
+ extern volatile B b1;
+ B b2(b1); // ok, uses converting constructor
+
+ void f() { throw a1; }
+
+#if __cplusplus >= 201103L
+ struct C {
+ constexpr C() : n(0) {}
+ template<typename T> constexpr C(T&t) : n(t.n == 0 ? throw 0 : 0) {}
+ int n;
+ };
+ constexpr C c() { return C(); }
+ // ok, copy is elided
+ constexpr C x = c();
+#endif
+}
+
+// dr537: na
+// dr538: na
+
+// dr539: yes
+const dr539( // expected-error {{requires a type specifier}}
+ const a) { // expected-error {{unknown type name 'a'}}
+ const b; // expected-error {{requires a type specifier}}
+ new const; // expected-error {{expected a type}}
+ try {} catch (const n) {} // expected-error {{unknown type name 'n'}}
+ try {} catch (const) {} // expected-error {{expected a type}}
+ if (const n = 0) {} // expected-error {{requires a type specifier}}
+ switch (const n = 0) {} // expected-error {{requires a type specifier}}
+ while (const n = 0) {} // expected-error {{requires a type specifier}}
+ for (const n = 0; // expected-error {{requires a type specifier}}
+ const m = 0; ) {} // expected-error {{requires a type specifier}}
+ sizeof(const); // expected-error {{requires a type specifier}}
+ struct S {
+ const n; // expected-error {{requires a type specifier}}
+ operator const(); // expected-error {{expected a type}}
+ };
+#if __cplusplus >= 201103L
+ int arr[3];
+ // FIXME: The extra braces here are to avoid the parser getting too
+ // badly confused when recovering here. We should fix this recovery.
+ { for (const n // expected-error {{unknown type name 'n'}} expected-note {{}}
+ : arr) ; {} } // expected-error +{{}}
+ (void) [](const) {}; // expected-error {{requires a type specifier}}
+ (void) [](const n) {}; // expected-error {{unknown type name 'n'}}
+ enum E : const {}; // expected-error {{expected a type}}
+ using T = const; // expected-error {{expected a type}}
+ auto f() -> const; // expected-error {{expected a type}}
+#endif
+}
+
+namespace dr540 { // dr540: yes
+ typedef int &a;
+ typedef const a &a; // expected-warning {{has no effect}}
+ typedef const int &b;
+ typedef b &b;
+ typedef const a &c; // expected-note {{previous}} expected-warning {{has no effect}}
+ typedef const b &c; // expected-error {{different}} expected-warning {{has no effect}}
+}
+
+namespace dr541 { // dr541: yes
+ template<int> struct X { typedef int type; };
+ template<typename T> struct S {
+ int f(T);
+
+ int g(int);
+ T g(bool);
+
+ int h();
+ int h(T);
+
+ void x() {
+ // These are type-dependent expressions, even though we could
+ // determine that all calls have type 'int'.
+ X<sizeof(f(0))>::type a; // expected-error +{{}}
+ X<sizeof(g(0))>::type b; // expected-error +{{}}
+ X<sizeof(h(0))>::type b; // expected-error +{{}}
+
+ typename X<sizeof(f(0))>::type a;
+ typename X<sizeof(h(0))>::type b;
+ }
+ };
+}
+
+namespace dr542 { // dr542: yes
+#if __cplusplus >= 201103L
+ struct A { A() = delete; int n; };
+ A a[32] = {}; // ok, constructor not called
+
+ struct B {
+ int n;
+ private:
+ B() = default;
+ };
+ B b[32] = {}; // ok, constructor not called
+#endif
+}
+
+namespace dr543 { // dr543: yes
+ // In C++98+DR543, this is valid because value-initialization doesn't call a
+ // trivial default constructor, so we never notice that defining the
+ // constructor would be ill-formed.
+ //
+ // In C++11+DR543, this is ill-formed, because the default constructor is
+ // deleted, and value-initialization *does* call a deleted default
+ // constructor, even if it is trivial.
+ struct A {
+ const int n;
+ };
+ A a = A();
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{deleted}}
+ // expected-note@-5 {{would not be initialized}}
+#endif
+}
+
+namespace dr544 { // dr544: yes
+ int *n;
+
+ template<class T> struct A { int n; };
+ template<class T> struct B : A<T> { int get(); };
+ template<> int B<int>::get() { return n; }
+ int k = B<int>().get();
+}
+
+namespace dr546 { // dr546: yes
+ template<typename T> struct A { void f(); };
+ template struct A<int>;
+ template<typename T> void A<T>::f() { T::error; }
+}
+
+namespace dr547 { // dr547: yes
+ // When targeting the MS x86 ABI, the type of a member function includes a
+ // __thiscall qualifier. This is non-conforming, but we still implement
+ // the intent of dr547
+#if defined(_M_IX86) || (defined(__MINGW32__) && !defined(__MINGW64__))
+#define THISCALL __thiscall
+#else
+#define THISCALL
+#endif
+
+ template<typename T> struct X;
+ template<typename T> struct X<THISCALL T() const> {};
+ template<typename T, typename C> X<T> f(T C::*) { return X<T>(); }
+
+ struct S { void f() const; };
+ X<THISCALL void() const> x = f(&S::f);
+
+#undef THISCALL
+}
+
+namespace dr548 { // dr548: dup 482
+ template<typename T> struct S {};
+ template<typename T> void f() {}
+ template struct dr548::S<int>;
+ template void dr548::f<int>();
+}
+
+namespace dr551 { // dr551: yes c++11
+ // FIXME: This obviously should apply in C++98 mode too.
+ template<typename T> void f() {}
+ template inline void f<int>();
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{cannot be 'inline'}}
+#endif
+
+ template<typename T> inline void g() {}
+ template inline void g<int>();
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{cannot be 'inline'}}
+#endif
+
+ template<typename T> struct X {
+ void f() {}
+ };
+ template inline void X<int>::f();
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{cannot be 'inline'}}
+#endif
+}
+
+namespace dr552 { // dr552: yes
+ template<typename T, typename T::U> struct X {};
+ struct Y { typedef int U; };
+ X<Y, 0> x;
+}
+
+struct dr553_class {
+ friend void *operator new(size_t, dr553_class);
+};
+namespace dr553 {
+ dr553_class c;
+ // Contrary to the apparent intention of the DR, operator new is not actually
+ // looked up with a lookup mechanism that performs ADL; the standard says it
+ // "is looked up in global scope", where it is not visible.
+ void *p = new (c) int; // expected-error {{no matching function}}
+
+ struct namespace_scope {
+ friend void *operator new(size_t, namespace_scope); // expected-error {{cannot be declared inside a namespace}}
+ };
+}
+
+// dr556: na
+
+namespace dr557 { // dr557: yes
+ template<typename T> struct S {
+ friend void f(S<T> *);
+ friend void g(S<S<T> > *);
+ };
+ void x(S<int> *p, S<S<int> > *q) {
+ f(p);
+ g(q);
+ }
+}
+
+namespace dr558 { // dr558: yes
+ wchar_t a = L'\uD7FF';
+ wchar_t b = L'\xD7FF';
+ wchar_t c = L'\uD800'; // expected-error {{invalid universal character}}
+ wchar_t d = L'\xD800';
+ wchar_t e = L'\uDFFF'; // expected-error {{invalid universal character}}
+ wchar_t f = L'\xDFFF';
+ wchar_t g = L'\uE000';
+ wchar_t h = L'\xE000';
+}
+
+template<typename> struct dr559 { typedef int T; dr559::T u; }; // dr559: yes
+
+namespace dr561 { // dr561: yes
+ template<typename T> void f(int);
+ template<typename T> void g(T t) {
+ f<T>(t);
+ }
+ namespace {
+ struct S {};
+ template<typename T> static void f(S);
+ }
+ void h(S s) {
+ g(s);
+ }
+}
+
+namespace dr564 { // dr564: yes
+ extern "C++" void f(int);
+ void f(int); // ok
+ extern "C++" { extern int n; }
+ int n; // ok
+}
+
+namespace dr565 { // dr565: yes
+ namespace N {
+ template<typename T> int f(T); // expected-note {{target}}
+ }
+ using N::f; // expected-note {{using}}
+ template<typename T> int f(T*);
+ template<typename T> void f(T);
+ template<typename T, int = 0> int f(T); // expected-error 0-1{{extension}}
+ template<typename T> int f(T, int = 0);
+ template<typename T> int f(T); // expected-error {{conflicts with}}
+}
+
+namespace dr566 { // dr566: yes
+#if __cplusplus >= 201103L
+ int check[int(-3.99) == -3 ? 1 : -1];
+#endif
+}
+
+// dr567: na
+
+namespace dr568 { // dr568: yes c++11
+ // FIXME: This is a DR issue against C++98, so should probably apply there
+ // too.
+ struct x { int y; };
+ class trivial : x {
+ x y;
+ public:
+ int n;
+ };
+ int check_trivial[__is_trivial(trivial) ? 1 : -1];
+
+ struct std_layout {
+ std_layout();
+ std_layout(const std_layout &);
+ ~std_layout();
+ private:
+ int n;
+ };
+ int check_std_layout[__is_standard_layout(std_layout) ? 1 : -1];
+
+ struct aggregate {
+ int x;
+ int y;
+ trivial t;
+ std_layout sl;
+ };
+ aggregate aggr = {};
+
+ void f(...);
+ void g(trivial t) { f(t); }
+#if __cplusplus < 201103L
+ // expected-error@-2 {{non-POD}}
+#endif
+
+ void jump() {
+ goto x;
+#if __cplusplus < 201103L
+ // expected-error@-2 {{cannot jump}}
+ // expected-note@+2 {{non-POD}}
+#endif
+ trivial t;
+ x: ;
+ }
+}
+
+namespace dr569 { // dr569: yes c++11
+ // FIXME: This is a DR issue against C++98, so should probably apply there
+ // too.
+ ;;;;;
+#if __cplusplus < 201103L
+ // expected-error@-2 {{C++11 extension}}
+#endif
+}
+
+namespace dr570 { // dr570: dup 633
+ int n;
+ int &r = n; // expected-note {{previous}}
+ int &r = n; // expected-error {{redefinition}}
+}
+
+namespace dr571 { // dr571 unknown
+ // FIXME: Add a codegen test.
+ typedef int &ir;
+ int n;
+ const ir r = n; // expected-warning {{has no effect}} FIXME: Test if this has internal linkage.
+}
+
+namespace dr572 { // dr572: yes
+ enum E { a = 1, b = 2 };
+ int check[a + b == 3 ? 1 : -1];
+}
+
+namespace dr573 { // dr573: no
+ void *a;
+ int *b = reinterpret_cast<int*>(a);
+ void (*c)() = reinterpret_cast<void(*)()>(a);
+ void *d = reinterpret_cast<void*>(c);
+#if __cplusplus < 201103L
+ // expected-error@-3 {{extension}}
+ // expected-error@-3 {{extension}}
+#endif
+ void f() { delete a; } // expected-error {{cannot delete}}
+ int n = d - a; // expected-error {{arithmetic on pointers to void}}
+ // FIXME: This is ill-formed.
+ template<void*> struct S;
+ template<int*> struct T;
+}
+
+namespace dr574 { // dr574: yes
+ struct A {
+ A &operator=(const A&) const; // expected-note {{does not match because it is const}}
+ };
+ struct B {
+ B &operator=(const B&) volatile; // expected-note {{nearly matches}}
+ };
+#if __cplusplus >= 201103L
+ struct C {
+ C &operator=(const C&) &; // expected-note {{not viable}} expected-note {{nearly matches}} expected-note {{here}}
+ };
+ struct D {
+ D &operator=(const D&) &&; // expected-note {{not viable}} expected-note {{nearly matches}} expected-note {{here}}
+ };
+ void test(C c, D d) {
+ c = c;
+ C() = c; // expected-error {{no viable}}
+ d = d; // expected-error {{no viable}}
+ D() = d;
+ }
+#endif
+ struct Test {
+ friend A &A::operator=(const A&); // expected-error {{does not match}}
+ friend B &B::operator=(const B&); // expected-error {{does not match}}
+#if __cplusplus >= 201103L
+ // FIXME: We shouldn't produce the 'cannot overload' diagnostics here.
+ friend C &C::operator=(const C&); // expected-error {{does not match}} expected-error {{cannot overload}}
+ friend D &D::operator=(const D&); // expected-error {{does not match}} expected-error {{cannot overload}}
+#endif
+ };
+}
+
+namespace dr575 { // dr575: yes
+ template<typename T, typename U = typename T::type> void a(T); void a(...); // expected-error 0-1{{extension}}
+ template<typename T, typename T::type U = 0> void b(T); void b(...); // expected-error 0-1{{extension}}
+ template<typename T, int U = T::value> void c(T); void c(...); // expected-error 0-1{{extension}}
+ template<typename T> void d(T, int = T::value); void d(...); // expected-error {{cannot be used prior to '::'}}
+ void x() {
+ a(0);
+ b(0);
+ c(0);
+ d(0); // expected-note {{in instantiation of default function argument}}
+ }
+
+ template<typename T = int&> void f(T* = 0); // expected-error 0-1{{extension}}
+ template<typename T = int> void f(T = 0); // expected-error 0-1{{extension}}
+ void g() { f<>(); }
+
+ template<typename T> T &h(T *);
+ template<typename T> T *h(T *);
+ void *p = h((void*)0);
+}
+
+namespace dr576 { // dr576: yes
+ typedef void f() {} // expected-error {{function definition declared 'typedef'}}
+ void f(typedef int n); // expected-error {{invalid storage class}}
+ void f(char c) { typedef int n; }
+}
+
+namespace dr577 { // dr577: yes
+ typedef void V;
+ typedef const void CV;
+ void a(void);
+ void b(const void); // expected-error {{qualifiers}}
+ void c(V);
+ void d(CV); // expected-error {{qualifiers}}
+ void (*e)(void) = c;
+ void (*f)(const void); // expected-error {{qualifiers}}
+ void (*g)(V) = a;
+ void (*h)(CV); // expected-error {{qualifiers}}
+ template<typename T> void i(T); // expected-note 2{{requires 1 arg}}
+ template<typename T> void j(void (*)(T)); // expected-note 2{{argument may not have 'void' type}}
+ void k() {
+ a();
+ c();
+ i<void>(); // expected-error {{no match}}
+ i<const void>(); // expected-error {{no match}}
+ j<void>(0); // expected-error {{no match}}
+ j<const void>(0); // expected-error {{no match}}
+ }
+}
+
+namespace dr580 { // dr580: no
+ class C;
+ struct A { static C c; };
+ struct B { static C c; };
+ class C {
+ C(); // expected-note {{here}}
+ ~C(); // expected-note {{here}}
+
+ typedef int I; // expected-note {{here}}
+ template<int> struct X;
+ template<int> friend struct Y;
+ template<int> void f();
+ template<int> friend void g();
+ friend struct A;
+ };
+
+ template<C::I> struct C::X {};
+ template<C::I> struct Y {};
+ template<C::I> struct Z {}; // FIXME: should reject, accepted because C befriends A!
+
+ template<C::I> void C::f() {}
+ template<C::I> void g() {}
+ template<C::I> void h() {} // expected-error {{private}}
+
+ C A::c;
+ C B::c; // expected-error 2{{private}}
+}
+
+// dr582: na
+
+namespace dr583 { // dr583: no
+ // see n3624
+ int *p;
+ // FIXME: These are all ill-formed.
+ bool b1 = p < 0;
+ bool b2 = p > 0;
+ bool b3 = p <= 0;
+ bool b4 = p >= 0;
+}
+
+// dr584: na
+
+namespace dr585 { // dr585: yes
+ template<typename> struct T;
+ struct A {
+ friend T; // expected-error {{requires a type specifier}} expected-error {{can only be classes or functions}}
+ // FIXME: It's not clear whether the standard allows this or what it means,
+ // but the DR585 writeup suggests it as an alternative.
+ template<typename U> friend T<U>; // expected-error {{must use an elaborated type}}
+ };
+ template<template<typename> class T> struct B {
+ friend T; // expected-error {{requires a type specifier}} expected-error {{can only be classes or functions}}
+ template<typename U> friend T<U>; // expected-error {{must use an elaborated type}}
+ };
+}
+
+// dr586: na
+
+namespace dr587 { // dr587: yes
+ template<typename T> void f(bool b, const T x, T y) {
+ const T *p = &(b ? x : y);
+ }
+ struct S {};
+ template void f(bool, const int, int);
+ template void f(bool, const S, S);
+}
+
+namespace dr588 { // dr588: yes
+ struct A { int n; }; // expected-note {{ambiguous}}
+ template<typename T> int f() {
+ struct S : A, T { int f() { return n; } } s;
+ int a = s.f();
+ int b = s.n; // expected-error {{found in multiple}}
+ }
+ struct B { int n; }; // expected-note {{ambiguous}}
+ int k = f<B>(); // expected-note {{here}}
+}
+
+namespace dr589 { // dr589: yes
+ struct B { };
+ struct D : B { };
+ D f();
+ extern const B &b;
+ bool a;
+ const B *p = &(a ? f() : b); // expected-error {{temporary}}
+ const B *q = &(a ? D() : b); // expected-error {{temporary}}
+}
+
+namespace dr590 { // dr590: yes
+ template<typename T> struct A {
+ struct B {
+ struct C {
+ A<T>::B::C f(A<T>::B::C); // ok, no 'typename' required.
+ };
+ };
+ };
+ template<typename T> typename A<T>::B::C A<T>::B::C::f(A<T>::B::C) {}
+}
+
+namespace dr591 { // dr591: no
+ template<typename T> struct A {
+ typedef int M;
+ struct B {
+ typedef void M;
+ struct C;
+ };
+ };
+
+ template<typename T> struct A<T>::B::C : A<T> {
+ // FIXME: Should find member of non-dependent base class A<T>.
+ M m; // expected-error {{incomplete type 'M' (aka 'void'}}
+ };
+}
+
+// dr592: na
+// dr593 needs an IRGen test.
+// dr594: na
+
+namespace dr595 { // dr595: dup 1330
+ template<class T> struct X {
+ void f() throw(T) {}
+ };
+ struct S {
+ X<S> xs;
+ };
+}
+
+// dr597: na
+
+namespace dr598 { // dr598: yes
+ namespace N {
+ void f(int);
+ void f(char);
+ // Not found by ADL.
+ void g(void (*)(int));
+ void h(void (*)(int));
+
+ namespace M {
+ struct S {};
+ int &h(void (*)(S));
+ }
+ void i(M::S);
+ void i();
+ }
+ int &g(void(*)(char));
+ int &r = g(N::f);
+ int &s = h(N::f); // expected-error {{undeclared}}
+ int &t = h(N::i);
+}
+
+namespace dr599 { // dr599: partial
+ typedef int Fn();
+ struct S { operator void*(); };
+ struct T { operator Fn*(); };
+ struct U { operator int*(); operator void*(); }; // expected-note 2{{conversion}}
+ struct V { operator int*(); operator Fn*(); };
+ void f(void *p, void (*q)(), S s, T t, U u, V v) {
+ delete p; // expected-error {{cannot delete}}
+ delete q; // expected-error {{cannot delete}}
+ delete s; // expected-error {{cannot delete}}
+ delete t; // expected-error {{cannot delete}}
+ // FIXME: This is valid, but is rejected due to a non-conforming GNU
+ // extension allowing deletion of pointers to void.
+ delete u; // expected-error {{ambiguous}}
+ delete v;
+ }
+}
diff --git a/test/CXX/drs/dr6xx.cpp b/test/CXX/drs/dr6xx.cpp
new file mode 100644
index 000000000000..988c8f43011d
--- /dev/null
+++ b/test/CXX/drs/dr6xx.cpp
@@ -0,0 +1,349 @@
+// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+namespace std { struct type_info {}; }
+
+namespace dr601 { // dr601: yes
+#if __cplusplus >= 201103L
+#define MAX __LLONG_MAX__
+#else
+#define MAX __LONG_MAX__
+#endif
+
+#if 0x8000 < -1
+#error 0x8000 should be signed
+#endif
+
+#if MAX > 0xFFFFFFFF && 0x80000000 < -1
+#error 0x80000000 should be signed
+#endif
+
+#if __INT_MAX__ == 0x7FFFFFFF
+_Static_assert(0x80000000 < -1, "0x80000000 should be unsigned"); // expected-error {{C11}}
+#endif
+
+#if MAX > 0xFFFFFFFFFFFFFFFF && 0x8000000000000000 < -1
+#error 0x8000000000000000 should be signed
+#endif
+
+#if __cplusplus >= 201103L && __LLONG_MAX__ == 0x7FFFFFFFFFFFFFFF
+static_assert(0x8000000000000000 < -1, "0x8000000000000000 should be unsigned"); // expected-error {{C11}}
+#endif
+
+#undef MAX
+}
+
+namespace dr602 { // dr602: yes
+ template<class T> struct A {
+ template<class U> friend struct A;
+ };
+
+ template<class T> struct B {
+ class C {
+ template<class U> friend struct B;
+ typedef int type;
+ };
+ typename C::type ct; // ok, befriended
+ };
+ B<int> b;
+}
+
+namespace dr603 { // dr603: yes
+ template<unsigned char> struct S {};
+ typedef S<'\001'> S1;
+ typedef S<(1ul << __CHAR_BIT__) + 1> S1;
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{cannot be narrowed}}
+#endif
+}
+
+// dr604: na
+// dr605 needs IRGen test
+
+namespace dr606 { // dr606: yes
+#if __cplusplus >= 201103L
+ template<typename T> struct S {};
+ template<typename T> void f(S<T> &&); // expected-note {{no known conversion from 'S<int>' to 'S<int> &&'}}
+ template<typename T> void g(T &&);
+ template<typename T> void h(const T &&); // expected-note {{no known conversion from 'S<int>' to 'const dr606::S<int> &&'}}
+
+ void test(S<int> s) {
+ f(s); // expected-error {{no match}}
+ g(s);
+ h(s); // expected-error {{no match}}
+
+ g(test);
+ h(test); // ok, an rvalue reference can bind to a function lvalue
+ }
+#endif
+}
+
+namespace dr608 { // dr608: yes
+ struct A { virtual void f(); };
+ struct B : A {};
+ struct C : A { void f(); };
+ struct D : B, C {};
+}
+
+int dr610[-0u == 0u ? 1 : -1]; // dr610: yes
+
+namespace dr611 { // dr611: yes
+ int k;
+ struct S { int &r; } s = { k ? k : k };
+}
+
+// dr612: na
+
+namespace dr613 { // dr613: yes c++11
+ // see also n2253
+ struct A { int n; static void f(); };
+ int f(int);
+ struct B { virtual void f(); };
+ B &g(int);
+
+ int an1 = sizeof(A::n);
+ int an2 = sizeof(A::n + 1); // valid per dr850
+ int an3 = sizeof A::n;
+ int an4 = sizeof(f(A::n));
+ int an5 = sizeof(g(A::n));
+ const std::type_info &an6 = typeid(A::n);
+ const std::type_info &an7 = typeid(A::n + 1);
+ const std::type_info &an8 = typeid(f(A::n));
+ const std::type_info &an9 = typeid(g(A::n)); // expected-error {{non-static}}
+#if __cplusplus < 201103L
+ // expected-error@-10 {{non-static}}
+ // expected-error@-10 {{non-static}}
+ // expected-error@-10 {{non-static}}
+ // expected-error@-10 {{non-static}}
+ // expected-error@-10 {{non-static}}
+ // expected-error@-10 {{non-static}}
+ // expected-error@-10 {{non-static}}
+ // expected-error@-10 {{non-static}}
+#endif
+
+ void A::f() {
+ int an1 = sizeof n;
+ const std::type_info &an2 = typeid(n + 1);
+#if __cplusplus < 201103L
+ // expected-error@-3 {{static}}
+ // expected-error@-3 {{static}}
+#endif
+ const std::type_info &an3 = typeid(g(n)); // expected-error {{static}}
+ }
+}
+
+int dr614_a[(-1) / 2 == 0 ? 1 : -1]; // dr614: yes
+int dr614_b[(-1) % 2 == -1 ? 1 : -1];
+
+namespace dr615 { // dr615: yes
+ int f();
+ static int n = f();
+}
+
+namespace dr616 { // dr616: no
+#if __cplusplus >= 201103L
+ struct S { int n; } s;
+ // FIXME: These should all be 'int &&'
+ using T = decltype(S().n); // expected-note 2{{previous}}
+ using T = decltype(static_cast<S&&>(s).n);
+ using T = decltype(S().*&S::n);
+ using T = decltype(static_cast<S&&>(s).*&S::n); // expected-error {{different type}}
+ using T = int&&; // expected-error {{different type}}
+#endif
+}
+
+namespace dr618 { // dr618: yes
+#if (unsigned)-1 > 0
+#error wrong
+#endif
+}
+
+namespace dr619 { // dr619: yes
+ extern int x[10];
+ struct S { static int x[10]; };
+
+ int x[];
+ _Static_assert(sizeof(x) == sizeof(int) * 10, ""); // expected-error {{C11}}
+ extern int x[];
+ _Static_assert(sizeof(x) == sizeof(int) * 10, ""); // expected-error {{C11}}
+
+ int S::x[];
+ _Static_assert(sizeof(S::x) == sizeof(int) * 10, ""); // expected-error {{C11}}
+
+ void f() {
+ extern int x[];
+ sizeof(x); // expected-error {{incomplete}}
+ }
+}
+
+// dr620: dup 568
+
+namespace dr621 {
+ template<typename T> T f();
+ template<> int f() {} // expected-note {{previous}}
+ template<> int f<int>() {} // expected-error {{redefinition}}
+}
+
+// dr623: na
+// FIXME: Add documentation saying we allow invalid pointer values.
+
+// dr624 needs an IRGen check.
+
+namespace dr625 { // dr625: yes
+ template<typename T> struct A {};
+ A<auto> x = A<int>(); // expected-error {{'auto' not allowed in template argument}} expected-error 0-1{{extension}}
+ void f(int);
+ void (*p)(auto) = f; // expected-error {{'auto' not allowed in function prototype}} expected-error 0-1{{extension}}
+}
+
+namespace dr626 { // dr626: yes
+#define STR(x) #x
+ char c[2] = STR(c); // ok, type matches
+ wchar_t w[2] = STR(w); // expected-error {{initializing wide char array with non-wide string literal}}
+}
+
+namespace dr627 { // dr627: yes
+ void f() {
+ true a = 0; // expected-error +{{}} expected-warning {{unused}}
+ }
+}
+
+// dr628: na
+
+namespace dr629 { // dr629: yes
+ typedef int T;
+ int n = 1;
+ void f() {
+ auto T = 2;
+#if __cplusplus < 201103L
+ // expected-error@-2 {{expected unqualified-id}}
+#else
+ // expected-note@-4 {{previous}}
+#endif
+
+ auto T(n);
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{redefinition of 'T'}}
+#endif
+ }
+}
+
+namespace dr630 { // dr630: yes
+const bool MB_EQ_WC =
+ ' ' == L' ' && '\t' == L'\t' && '\v' == L'\v' && '\r' == L'\r' &&
+ '\n' == L'\n' && //
+ 'a' == L'a' && 'b' == L'b' && 'c' == L'c' && 'd' == L'd' && 'e' == L'e' &&
+ 'f' == L'f' && 'g' == L'g' && 'h' == L'h' && 'i' == L'i' && 'j' == L'j' &&
+ 'k' == L'k' && 'l' == L'l' && 'm' == L'm' && 'n' == L'n' && 'o' == L'o' &&
+ 'p' == L'p' && 'q' == L'q' && 'r' == L'r' && 's' == L's' && 't' == L't' &&
+ 'u' == L'u' && 'v' == L'v' && 'w' == L'w' && 'x' == L'x' && 'y' == L'y' &&
+ 'z' == L'z' && //
+ 'A' == L'A' && 'B' == L'B' && 'C' == L'C' && 'D' == L'D' && 'E' == L'E' &&
+ 'F' == L'F' && 'G' == L'G' && 'H' == L'H' && 'I' == L'I' && 'J' == L'J' &&
+ 'K' == L'K' && 'L' == L'L' && 'M' == L'M' && 'N' == L'N' && 'O' == L'O' &&
+ 'P' == L'P' && 'Q' == L'Q' && 'R' == L'R' && 'S' == L'S' && 'T' == L'T' &&
+ 'U' == L'U' && 'V' == L'V' && 'W' == L'W' && 'X' == L'X' && 'Y' == L'Y' &&
+ 'Z' == L'Z' && //
+ '0' == L'0' && '1' == L'1' && '2' == L'2' && '3' == L'3' && '4' == L'4' &&
+ '5' == L'5' && '6' == L'6' && '7' == L'7' && '8' == L'8' &&
+ '9' == L'9' && //
+ '_' == L'_' && '{' == L'{' && '}' == L'}' && '[' == L'[' && ']' == L']' &&
+ '#' == L'#' && '(' == L'(' && ')' == L')' && '<' == L'<' && '>' == L'>' &&
+ '%' == L'%' && ':' == L':' && ';' == L';' && '.' == L'.' && '?' == L'?' &&
+ '*' == L'*' && '+' == L'+' && '-' == L'-' && '/' == L'/' && '^' == L'^' &&
+ '&' == L'&' && '|' == L'|' && '~' == L'~' && '!' == L'!' && '=' == L'=' &&
+ ',' == L',' && '\\' == L'\\' && '"' == L'"' && '\'' == L'\'';
+#if __STDC_MB_MIGHT_NEQ_WC__
+#ifndef __FreeBSD__ // PR22208, FreeBSD expects us to give a bad (but conforming) answer here.
+_Static_assert(!MB_EQ_WC, "__STDC_MB_MIGHT_NEQ_WC__ but all basic source characters have same representation"); // expected-error {{C11}}
+#endif
+#else
+_Static_assert(MB_EQ_WC, "!__STDC_MB_MIGHT_NEQ_WC__ but some character differs"); // expected-error {{C11}}
+#endif
+}
+
+// dr631: na
+
+namespace dr632 { // dr632: yes
+ struct S { int n; } s = {{5}}; // expected-warning {{braces}}
+}
+
+// dr633: na
+// see also n2993
+
+namespace dr634 { // dr634: yes
+ struct S { S(); S(const S&); virtual void f(); ~S(); };
+ int f(...);
+ char f(int);
+ template<typename T> int (&g(T))[sizeof f(T())];
+ int (&a)[sizeof(int)] = g(S());
+ int (&b)[1] = g(0);
+ int k = f(S()); // expected-error {{cannot pass}}
+}
+
+namespace dr635 { // dr635: yes
+ template<typename T> struct A { A(); ~A(); };
+ template<typename T> A<T>::A<T>() {} // expected-error {{cannot have template arguments}}
+ template<typename T> A<T>::~A<T>() {}
+
+ template<typename T> struct B { B(); ~B(); };
+ template<typename T> B<T>::B() {}
+ template<typename T> B<T>::~B() {}
+
+ struct C { template<typename T> C(); C(); };
+ template<typename T> C::C() {}
+ C::C() {}
+ template<> C::C<int>() {} // expected-error {{constructor name}} expected-error {{unqualified-id}}
+ /*FIXME: needed for error recovery:*/;
+
+ template<typename T> struct D { template<typename U> D(); D(); };
+ template<typename T> D<T>::D() {} // expected-note {{previous}}
+ template<typename T> template<typename U> D<T>::D() {}
+ template<typename T> D<T>::D<T>() {} // expected-error {{redefinition}} expected-error {{cannot have template arg}}
+}
+
+namespace dr637 { // dr637: yes
+ void f(int i) {
+ i = ++i + 1;
+ i = i++ + 1; // expected-warning {{unsequenced}}
+ }
+}
+
+namespace dr638 { // dr638: no
+ template<typename T> struct A {
+ struct B;
+ void f();
+ void g();
+ struct C {
+ void h();
+ };
+ };
+
+ class X {
+ typedef int type;
+ template<class T> friend struct A<T>::B; // expected-warning {{not supported}}
+ template<class T> friend void A<T>::f(); // expected-warning {{not supported}}
+ template<class T> friend void A<T>::g(); // expected-warning {{not supported}}
+ template<class T> friend void A<T>::C::h(); // expected-warning {{not supported}}
+ };
+
+ template<> struct A<int> {
+ X::type a; // FIXME: private
+ struct B {
+ X::type b; // ok
+ };
+ int f() { X::type c; } // FIXME: private
+ void g() { X::type d; } // ok
+ struct D {
+ void h() { X::type e; } // FIXME: private
+ };
+ };
+}
+
+namespace dr639 { // dr639: yes
+ void f(int i) {
+ void((i = 0) + (i = 0)); // expected-warning {{unsequenced}}
+ }
+}
diff --git a/test/CXX/drs/dr9xx.cpp b/test/CXX/drs/dr9xx.cpp
index 40dc2821adc3..4bcd6565e068 100644
--- a/test/CXX/drs/dr9xx.cpp
+++ b/test/CXX/drs/dr9xx.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
#if __cplusplus < 201103L
// expected-no-diagnostics
diff --git a/test/CXX/except/except.spec/p1.cpp b/test/CXX/except/except.spec/p1.cpp
index a32f37d55208..fa53c9f5d23f 100644
--- a/test/CXX/except/except.spec/p1.cpp
+++ b/test/CXX/except/except.spec/p1.cpp
@@ -77,5 +77,12 @@ namespace PR11084 {
static int f() noexcept(1/X) { return 10; } // expected-error{{argument to noexcept specifier must be a constant expression}} expected-note{{division by zero}}
};
- void g() { A<0>::f(); } // expected-note{{in instantiation of exception specification for 'f' requested here}}
+ template<int X> void f() {
+ int (*p)() noexcept(1/X); // expected-error{{argument to noexcept specifier must be a constant expression}} expected-note{{division by zero}}
+ };
+
+ void g() {
+ A<0>::f(); // expected-note{{in instantiation of exception specification for 'f'}}
+ f<0>(); // expected-note{{in instantiation of function template specialization}}
+ }
}
diff --git a/test/CXX/except/except.spec/p5-delayed.cpp b/test/CXX/except/except.spec/p5-delayed.cpp
new file mode 100644
index 000000000000..99c0e2de31a9
--- /dev/null
+++ b/test/CXX/except/except.spec/p5-delayed.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -fexceptions -fcxx-exceptions
+
+struct A { struct X { virtual ~X() throw(Y); }; struct Y : X {}; };
+struct B { struct X { virtual void f() throw(Y); }; struct Y : X { void f() throw(Y); }; };
+struct C { struct X { virtual void f() throw(Y); }; struct Y : X { void f() throw(); }; };
+struct D { struct X { virtual void f() throw(Y); }; struct Y : X { void f() noexcept; }; };
+struct E { struct Y; struct X { virtual Y &operator=(const Y&) throw(Y); }; struct Y : X {}; };
+struct F {
+ struct X {
+ virtual void f() throw(Y); // expected-note {{here}}
+ };
+ struct Y : X {
+ void f() throw(int); // expected-error {{more lax}}
+ };
+};
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index bcf45a0c05b4..d027c7a388bb 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -131,14 +131,14 @@ namespace IncompleteClassTypeAddr {
namespace UndefinedBehavior {
void f(int n) {
switch (n) {
- case (int)4.4e9: // expected-error {{constant expression}} expected-note {{value 4.4E+9 is outside the range of representable values of type 'int'}} expected-note {{previous case defined here}}
+ case (int)4.4e9: // expected-error {{constant expression}} expected-note {{value 4.4E+9 is outside the range of representable values of type 'int'}}
case (int)0x80000000u: // ok
case (int)10000000000ll: // expected-note {{here}}
case (unsigned int)10000000000ll: // expected-error {{duplicate case value}}
case (int)(unsigned)(long long)4.4e9: // ok
- case (int)(float)1e300: // expected-error {{constant expression}} expected-note {{value 1.0E+300 is outside the range of representable values of type 'float'}} expected-error {{duplicate case value '2147483647'}} expected-note {{previous case defined here}}
+ case (int)(float)1e300: // expected-error {{constant expression}} expected-note {{value 1.0E+300 is outside the range of representable values of type 'float'}}
case (int)((float)1e37 / 1e30): // ok
- case (int)(__fp16)65536: // expected-error {{constant expression}} expected-note {{value 65536 is outside the range of representable values of type '__fp16'}} expected-error {{duplicate case value '2147483647'}}
+ case (int)(__fp16)65536: // expected-error {{constant expression}} expected-note {{value 65536 is outside the range of representable values of type '__fp16'}}
break;
}
}
@@ -277,7 +277,7 @@ namespace UndefinedBehavior {
// - a lambda-expression (5.1.2);
struct Lambda {
- int n : []{ return 1; }(); // expected-error {{constant expression}} expected-error {{integral constant expression}}
+ int n : []{ return 1; }(); // expected-error {{constant expression}} expected-error {{integral constant expression}} expected-note {{non-literal type}}
};
// - an lvalue-to-rvalue conversion (4.1) unless it is applied to
diff --git a/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp b/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp
index fd90482ae8d2..0e948ce00031 100644
--- a/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp
@@ -136,12 +136,11 @@ namespace Static {
namespace PR12564 {
struct Base {
- void bar(Base&) {} // FIXME: expected-note {{here}}
+ void bar(Base&) {}
};
struct Derived : Base {
- // FIXME: This should be accepted.
- void foo(Derived& d) noexcept(noexcept(d.bar(d))) {} // expected-error {{cannot bind to a value of unrelated type}}
+ void foo(Derived& d) noexcept(noexcept(d.bar(d))) {}
};
}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
index 35b77896c868..40360e40694c 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
@@ -7,10 +7,10 @@ struct MoveOnly {
template<typename T> T &&move(T&);
void test_special_member_functions(MoveOnly mo, int i) {
- auto lambda1 = [i]() { }; // expected-note 2 {{lambda expression begins here}}
+ auto lambda1 = [i]() { }; // expected-note {{lambda expression begins here}} expected-note 2{{candidate}}
// Default constructor
- decltype(lambda1) lambda2; // expected-error{{call to implicitly-deleted default constructor of 'decltype(lambda1)' (aka '(lambda}}
+ decltype(lambda1) lambda2; // expected-error{{no matching constructor}}
// Copy assignment operator
lambda1 = lambda1; // expected-error{{copy assignment operator is implicitly deleted}}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
index 03147a692dd5..d791ed60cfca 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
@@ -18,7 +18,7 @@ void unevaluated_operand(P &p, int i) { //expected-note{{declared here}}
// FIXME: this should only emit one error.
int i2 = sizeof([](auto a, auto b)->void{}(3, '4')); // expected-error{{lambda expression in an unevaluated operand}} \
// expected-error{{invalid application of 'sizeof'}}
- const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i));
+ const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i)); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i)); // expected-error{{lambda expression in an unevaluated operand}}\
// expected-error{{cannot be implicitly captured}}\
// expected-note{{begins here}}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
index 1fbe28722a41..647c76d604e4 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-unused-value %s -verify
// prvalue
void prvalue() {
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp
index 562f92a78bbc..80771d7a229a 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp
@@ -1,6 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
void test_nonaggregate(int i) {
- auto lambda = [i]() -> void {}; // expected-note 3{{candidate constructor}}
+ auto lambda = [i]() -> void {}; // expected-note 2{{candidate constructor}}
decltype(lambda) foo = { 1 }; // expected-error{{no matching constructor}}
+ static_assert(!__is_literal(decltype(lambda)), "");
+
+ auto lambda2 = []{}; // expected-note 2{{candidate constructor}}
+ decltype(lambda2) bar = {}; // expected-error{{no matching constructor}}
+ static_assert(!__is_literal(decltype(lambda2)), "");
}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
index 1016cb1d3056..a36175af6fec 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
@@ -34,15 +34,12 @@ X infer_X_return_type(X x) {
}(5);
}
-X infer_X_return_type_fail(X x) {
+X infer_X_return_type_2(X x) {
return [x](int y) {
if (y > 0)
return X();
else
- return x;
-#if __cplusplus <= 201103L
- // expected-error@-2 {{return type 'const X' must match previous return type 'X' when lambda expression has unspecified explicit return type}}
-#endif
+ return x; // ok even in c++11, per dr1048.
}(5);
}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
index 407b083231a3..90cbf02b2a6a 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
@@ -140,11 +140,11 @@ namespace NonLocalLambdaInstantation {
}
template<typename T>
- struct X2 {
+ struct X2 { // expected-note{{in instantiation of default member initializer 'NonLocalLambdaInstantation::X2<int *>::x' requested here}}
int x = []{ return T(); }(); // expected-error{{cannot initialize a member subobject of type 'int' with an rvalue of type 'int *'}}
};
X2<int> x2i;
X2<float> x2f;
- X2<int*> x2ip; // expected-note{{in instantiation of template class 'NonLocalLambdaInstantation::X2<int *>' requested here}}
+ X2<int*> x2ip; // expected-note{{implicit default constructor for 'NonLocalLambdaInstantation::X2<int *>' first required here}}
}
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 427e8c5007f2..a2a57956df9b 100644
--- a/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -fms-extensions -Wno-delete-incomplete %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -fms-extensions -Wno-delete-incomplete -Wno-unused-value %s
// expected-no-diagnostics
#define P(e) static_assert(noexcept(e), "expected nothrow")
diff --git a/test/CXX/lex/lex.literal/lex.ext/p3.cpp b/test/CXX/lex/lex.literal/lex.ext/p3.cpp
index e812ddddd8a4..d764989312c2 100644
--- a/test/CXX/lex/lex.literal/lex.ext/p3.cpp
+++ b/test/CXX/lex/lex.literal/lex.ext/p3.cpp
@@ -9,7 +9,7 @@ int &i2 = 45_x1;
template<char...> char &operator "" _x1 ();
int &i3 = 0377_x1;
-int &i4 = 90000000000000000000000000000000000000000000000_x1; // expected-error {{integer constant is larger than the largest unsigned integer type}}
+int &i4 = 90000000000000000000000000000000000000000000000_x1; // expected-error {{integer literal is too large to be represented in any integer type}}
double &operator "" _x2 (const char *);
double &i5 = 123123123123123123123123123123123123123123123_x2;
diff --git a/test/CXX/lex/lex.trigraph/p1.cpp b/test/CXX/lex/lex.trigraph/p1.cpp
index aacbc55b28fe..a80b00eabe7e 100644
--- a/test/CXX/lex/lex.trigraph/p1.cpp
+++ b/test/CXX/lex/lex.trigraph/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -trigraphs -Wtrigraphs -verify %s
+// RUN: %clang_cc1 -fsyntax-only -ftrigraphs -Wtrigraphs -verify %s
??=pragma // expected-warning {{trigraph converted to '#' character}}
diff --git a/test/CXX/lex/lex.trigraph/p2.cpp b/test/CXX/lex/lex.trigraph/p2.cpp
index 7d11d5bf5d59..6502aa8d7921 100644
--- a/test/CXX/lex/lex.trigraph/p2.cpp
+++ b/test/CXX/lex/lex.trigraph/p2.cpp
@@ -1,3 +1,3 @@
-// RUN: %clang_cc1 -fsyntax-only -trigraphs -Wtrigraphs -verify %s
+// RUN: %clang_cc1 -fsyntax-only -ftrigraphs -Wtrigraphs -verify %s
??=define arraycheck(a,b) a??(b??) ??!??! b??(a??) // expected-warning {{trigraph converted to '#' character}} expected-warning {{trigraph converted to '[' character}} expected-warning {{trigraph converted to ']' character}} expected-warning {{trigraph converted to '|' character}} expected-warning {{trigraph converted to '|' character}} expected-warning {{trigraph converted to '[' character}} expected-warning {{trigraph converted to ']' character}}
diff --git a/test/CXX/lex/lex.trigraph/p3.cpp b/test/CXX/lex/lex.trigraph/p3.cpp
index c74d8f358d02..bf935708a243 100644
--- a/test/CXX/lex/lex.trigraph/p3.cpp
+++ b/test/CXX/lex/lex.trigraph/p3.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -trigraphs -Wtrigraphs -verify %s
+// RUN: %clang_cc1 -fsyntax-only -ftrigraphs -Wtrigraphs -verify %s
// expected-no-diagnostics
char a[] =
diff --git a/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp b/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
index 574cb40c4670..d7726c944cdb 100644
--- a/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
+++ b/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
@@ -30,11 +30,11 @@ struct Y {
void f();
void test_Y() {
- goto end; // expected-error{{goto into protected scope}}
+ goto end; // expected-error{{cannot jump from this goto statement to its label}}
Y y; // expected-note{{jump bypasses variable with a non-trivial destructor}}
end:
f();
- goto inner; // expected-error{{goto into protected scope}}
+ goto inner; // expected-error{{cannot jump from this goto statement to its label}}
{
Y y2; // expected-note{{jump bypasses variable with a non-trivial destructor}}
inner:
diff --git a/test/CXX/stmt.stmt/stmt.dcl/p3.cpp b/test/CXX/stmt.stmt/stmt.dcl/p3.cpp
index f52e3b6d142d..4bcc648e84aa 100644
--- a/test/CXX/stmt.stmt/stmt.dcl/p3.cpp
+++ b/test/CXX/stmt.stmt/stmt.dcl/p3.cpp
@@ -29,7 +29,7 @@ struct Y {
};
void test_Y() {
- goto end; // expected-error{{goto into protected scope}}
+ goto end; // expected-error{{cannot jump from this goto statement to its label}}
Y y; // expected-note{{jump bypasses variable with a non-trivial destructor}}
end:
return;
@@ -40,7 +40,7 @@ struct Z {
};
void test_Z() {
- goto end; // expected-error{{goto into protected scope}}
+ goto end; // expected-error{{cannot jump from this goto statement to its label}}
Z z; // expected-note{{jump bypasses initialization of non-POD variable}}
end:
return;
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
index 8a3168e5f806..b0305dd756a6 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
@@ -8,7 +8,7 @@ struct X0 {
template<typename T>
T X0<T>::value = 0; // expected-error{{no viable conversion}}
-struct X1 {
+struct X1 {
X1(int);
};
@@ -19,8 +19,8 @@ X1& get_X1() { return X0<X1>::value; }
double*& get_double_ptr() { return X0<int*>::value; } // expected-error{{non-const lvalue reference to type 'double *' cannot bind to a value of unrelated type 'int *'}}
-X2& get_X2() {
+X2& get_X2() {
return X0<X2>::value; // expected-note{{instantiation}}
}
-
-template<typename T> T x; // expected-warning{{variable templates are a C++1y extension}}
+
+template<typename T> T x; // expected-warning{{variable templates are a C++14 extension}}
diff --git a/test/CXX/temp/temp.decls/temp.friend/p5.cpp b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
index b26abb64f838..c4f9d63b7c66 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
@@ -20,7 +20,7 @@ namespace test1 {
class C {
static void foo();
- template <class T> friend void A<T>::f();
+ template <class T> friend void A<T>::f(); // expected-warning {{not supported}}
};
template <class T> struct A {
@@ -42,7 +42,7 @@ namespace test2 {
class C {
static void foo();
- template <class T> friend void A<T>::g();
+ template <class T> friend void A<T>::g(); // expected-warning {{not supported}}
};
template <class T> struct A {
@@ -86,7 +86,7 @@ namespace test4 {
template <class V>
template <class U>
- friend void X<V>::operator+=(U);
+ friend void X<V>::operator+=(U); // expected-warning {{not supported}}
};
void test() {
@@ -96,7 +96,7 @@ namespace test4 {
namespace test5 {
template<template <class> class T> struct A {
- template<template <class> class U> friend void A<U>::foo();
+ template<template <class> class U> friend void A<U>::foo(); // expected-warning {{not supported}}
};
template <class> struct B {};
diff --git a/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp b/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
index 73cbd0749cbd..f1231f61111e 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
@@ -243,7 +243,7 @@ namespace FunctionTypes {
};
template<typename R, typename ...Types>
- struct Arity<R(Types......)> {
+ struct Arity<R(Types......)> { // expected-warning {{varargs}} expected-note {{pack}} expected-note {{insert ','}}
static const unsigned value = sizeof...(Types);
};
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index dae686566691..4f9368f6b605 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -354,6 +354,7 @@ void test_unexpanded_exprs(Types ...values) {
for (auto t : values) { } // expected-error{{expression contains unexpanded parameter pack 'values'}}
switch (values) { } // expected-error{{expression contains unexpanded parameter pack 'values'}}
+ switch (0) { case 0: case values: ; } // expected-error{{expression contains unexpanded parameter pack 'values'}}
do { } while (values); // expected-error{{expression contains unexpanded parameter pack 'values'}}
@@ -422,3 +423,17 @@ namespace PR16303 {
B<1,2>::C<4,5,6> c1; // expected-note{{in instantiation of}}
B<1,2,3,4>::C<4,5,6> c2; // expected-note{{in instantiation of}}
}
+
+namespace PR21289 {
+ template<int> using T = int;
+ template<typename> struct S { static const int value = 0; };
+ template<typename> const int vt = 0; // expected-warning {{extension}}
+ int f(...);
+ template<int ...Ns> void g() {
+ f(T<Ns>()...);
+ f(S<T<Ns>>::value...);
+ f(vt<T<Ns>>...);
+ }
+ template void g<>();
+ template void g<1, 2, 3>();
+}
diff --git a/test/CXX/temp/temp.param/p5.cpp b/test/CXX/temp/temp.param/p5.cpp
index c25868267e49..ab430fb8741f 100644
--- a/test/CXX/temp/temp.param/p5.cpp
+++ b/test/CXX/temp/temp.param/p5.cpp
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -verify %s -std=c++11
-template<const int I> struct S {
+template<const int I> struct S { // expected-note {{instantiation}}
decltype(I) n;
int &&r = I; // expected-warning 2{{binding reference member 'r' to a temporary value}} expected-note 2{{declared here}}
};
-S<5> s; // expected-note {{instantiation}}
+S<5> s;
-template<typename T, T v> struct U {
+template<typename T, T v> struct U { // expected-note {{instantiation}}
decltype(v) n;
int &&r = v; // expected-warning {{binding reference member 'r' to a temporary value}} expected-note {{declared here}}
};
-U<const int, 6> u; // expected-note {{instantiation}}
+U<const int, 6> u;
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
index f804d4db1299..580ef3151e5d 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
@@ -9,7 +9,7 @@ template inline void X<int>::f(); // expected-error{{explicit instantiation cann
template<typename T>
struct Y {
- constexpr int f() { return 0; } // expected-warning{{C++1y}}
+ constexpr int f() { return 0; } // expected-warning{{C++14}}
};
template constexpr int Y<int>::f() const; // expected-error{{explicit instantiation cannot be 'constexpr'}}
diff --git a/test/CodeGen/2003-08-21-WideString.c b/test/CodeGen/2003-08-21-WideString.c
index 4071d17c7970..1a6e5b7c8829 100644
--- a/test/CodeGen/2003-08-21-WideString.c
+++ b/test/CodeGen/2003-08-21-WideString.c
@@ -5,9 +5,9 @@ typedef __WCHAR_TYPE__ wchar_t;
#if defined(_WIN32) || defined(_M_IX86) || defined(__CYGWIN__) \
|| defined(_M_X64) || defined(SHORT_WCHAR)
#define WCHAR_T_TYPE unsigned short
-#elif defined(__sun) || defined(__AuroraUX__)
+#elif defined(__sun)
#define WCHAR_T_TYPE long
-#else /* Solaris or AuroraUX. */
+#else /* Solaris. */
#define WCHAR_T_TYPE int
#endif
diff --git a/test/CodeGen/2005-06-15-ExpandGotoInternalProblem.c b/test/CodeGen/2005-06-15-ExpandGotoInternalProblem.c
index dd1acc54bc1d..0698601ad133 100644
--- a/test/CodeGen/2005-06-15-ExpandGotoInternalProblem.c
+++ b/test/CodeGen/2005-06-15-ExpandGotoInternalProblem.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -std=c99 %s -emit-llvm -o - | \
-// RUN: opt -std-compile-opts -disable-output
+// RUN: opt -O3 -disable-output
// PR580
int X, Y;
diff --git a/test/CodeGen/2005-09-24-AsmUserPrefix.c b/test/CodeGen/2005-09-24-AsmUserPrefix.c
index 16283130beb0..d0e5bd1c3a44 100644
--- a/test/CodeGen/2005-09-24-AsmUserPrefix.c
+++ b/test/CodeGen/2005-09-24-AsmUserPrefix.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | opt -std-compile-opts | llc | \
+// RUN: %clang_cc1 %s -emit-llvm -o - | opt -O3 | llc | \
// RUN: not grep _foo2
void foo() __asm__("foo2");
diff --git a/test/CodeGen/2007-06-18-SextAttrAggregate.c b/test/CodeGen/2007-06-18-SextAttrAggregate.c
index 92171e2bd9b7..23c211d3ba04 100644
--- a/test/CodeGen/2007-06-18-SextAttrAggregate.c
+++ b/test/CodeGen/2007-06-18-SextAttrAggregate.c
@@ -1,11 +1,13 @@
// RUN: %clang_cc1 %s -o - -emit-llvm | FileCheck %s
-// XFAIL: aarch64, arm64
+// XFAIL: aarch64, arm64, x86_64-pc-win32, x86_64-w64-mingw32
// PR1513
// AArch64 ABI actually requires the reverse of what this is testing: the callee
// does any extensions and remaining bits are unspecified.
+// Win64 ABI does expect extensions for type smaller than 64bits.
+
// Technically this test wasn't written to test that feature, but it's a
// valuable check nevertheless.
diff --git a/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c b/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
index 33bd800456f9..7401e114ddd0 100644
--- a/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
+++ b/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
@@ -8,5 +8,4 @@ struct et7 {
52,
};
-// CHECK: @yv7 = global
-// CHECK: i8 52,
+// CHECK: @yv7 = global %struct.et7 { [0 x float] zeroinitializer, i8 52 }
diff --git a/test/CodeGen/2009-07-15-pad-wchar_t-array.c b/test/CodeGen/2009-07-15-pad-wchar_t-array.c
index df12cae90ea0..4ae35158fa8a 100644
--- a/test/CodeGen/2009-07-15-pad-wchar_t-array.c
+++ b/test/CodeGen/2009-07-15-pad-wchar_t-array.c
@@ -5,9 +5,9 @@ typedef __WCHAR_TYPE__ wchar_t;
#if defined(_WIN32) || defined(_M_IX86) || defined(__CYGWIN__) \
|| defined(_M_X64) || defined(SHORT_WCHAR)
#define WCHAR_T_TYPE unsigned short
-#elif defined(__sun) || defined(__AuroraUX__)
+#elif defined(__sun)
#define WCHAR_T_TYPE long
-#else /* Solaris or AuroraUX. */
+#else /* Solaris. */
#define WCHAR_T_TYPE int
#endif
diff --git a/test/CodeGen/2009-10-20-GlobalDebug.c b/test/CodeGen/2009-10-20-GlobalDebug.c
index c48ad28ad065..e56f227d2ac6 100644
--- a/test/CodeGen/2009-10-20-GlobalDebug.c
+++ b/test/CodeGen/2009-10-20-GlobalDebug.c
@@ -6,5 +6,5 @@ int main() {
return 0;
}
-// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !{{.*}}, metadata !"localstatic", metadata !"localstatic", metadata !"", metadata !{{.*}}, i32 5, metadata !{{.*}}, i32 1, i32 1, i32* @main.localstatic, null} ; [ DW_TAG_variable ]
-// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"global", metadata !"global", metadata !"", metadata !{{.*}}, i32 3, metadata !{{.*}}, i32 0, i32 1, i32* @global, null} ; [ DW_TAG_variable ]
+// CHECK: !"0x34\00localstatic\00localstatic\00\005\001\001", !{{.*}}, !{{.*}}, !{{.*}}, i32* @main.localstatic, null} ; [ DW_TAG_variable ]
+// CHECK: !"0x34\00global\00global\00\003\000\001", null, !{{.*}}, !{{.*}}, i32* @global, null} ; [ DW_TAG_variable ]
diff --git a/test/CodeGen/2010-02-15-DbgStaticVar.c b/test/CodeGen/2010-02-15-DbgStaticVar.c
index facd14e03ee6..8980b60cf68d 100644
--- a/test/CodeGen/2010-02-15-DbgStaticVar.c
+++ b/test/CodeGen/2010-02-15-DbgStaticVar.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -g -emit-llvm %s -o - | grep "metadata ..b., metadata ..b., metadata ...,"
+// RUN: %clang_cc1 -g -emit-llvm %s -o - | FileCheck %s
// Test to check intentionally empty linkage name for a static variable.
// Radar 7651244.
static int foo(int a)
@@ -11,3 +11,4 @@ int main() {
int j = foo(1);
return 0;
}
+// CHECK: !"0x34\00b\00b\00\00{{.*}}",
diff --git a/test/CodeGen/2010-07-08-DeclDebugLineNo.c b/test/CodeGen/2010-07-08-DeclDebugLineNo.c
index 5e9edd9acd99..44c973acda67 100644
--- a/test/CodeGen/2010-07-08-DeclDebugLineNo.c
+++ b/test/CodeGen/2010-07-08-DeclDebugLineNo.c
@@ -6,5 +6,5 @@ void foo() {
int p = 0; // line #5: CHECK: {{call.*llvm.dbg.declare.*%p.*\!dbg }}[[variable_p:![0-9]+]]
}
// Now match the line number records:
-// CHECK: {{^}}[[variable_l]]{{ = metadata ![{]i32 5,}}
-// CHECK: {{^}}[[variable_p]]{{ = metadata ![{]i32 6,}}
+// CHECK: {{^}}[[variable_l]] = !MDLocation(line: 5,
+// CHECK: {{^}}[[variable_p]] = !MDLocation(line: 6,
diff --git a/test/CodeGen/24-bit.c b/test/CodeGen/24-bit.c
new file mode 100644
index 000000000000..9dd0157fd3b4
--- /dev/null
+++ b/test/CodeGen/24-bit.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -O0 -o - %s | FileCheck %s
+
+static union ibtt2
+{
+ struct ibtt0 { signed ibt0:10; unsigned short ibt1; } ibt5;
+ struct ibtt1 { signed ibt2:3; signed ibt3:9; signed ibt4:9; } ibt6;
+} ibt15 = {{267, 15266}};
+
+void callee_ibt0f(union ibtt2 ibtp5);
+
+void test(void) {
+// CHECK: = load i32*
+ callee_ibt0f(ibt15);
+}
diff --git a/test/CodeGen/Atomics.c b/test/CodeGen/Atomics.c
index 684f36d40440..f957883575de 100644
--- a/test/CodeGen/Atomics.c
+++ b/test/CodeGen/Atomics.c
@@ -49,6 +49,15 @@ void test_op_ignore (void) // CHECK-LABEL: define void @test_op_ignore
(void) __sync_fetch_and_xor (&sll, 1); // CHECK: atomicrmw xor i64
(void) __sync_fetch_and_xor (&ull, 1); // CHECK: atomicrmw xor i64
+ (void) __sync_fetch_and_nand (&sc, 1); // CHECK: atomicrmw nand i8
+ (void) __sync_fetch_and_nand (&uc, 1); // CHECK: atomicrmw nand i8
+ (void) __sync_fetch_and_nand (&ss, 1); // CHECK: atomicrmw nand i16
+ (void) __sync_fetch_and_nand (&us, 1); // CHECK: atomicrmw nand i16
+ (void) __sync_fetch_and_nand (&si, 1); // CHECK: atomicrmw nand i32
+ (void) __sync_fetch_and_nand (&ui, 1); // CHECK: atomicrmw nand i32
+ (void) __sync_fetch_and_nand (&sll, 1); // CHECK: atomicrmw nand i64
+ (void) __sync_fetch_and_nand (&ull, 1); // CHECK: atomicrmw nand i64
+
(void) __sync_fetch_and_and (&sc, 1); // CHECK: atomicrmw and i8
(void) __sync_fetch_and_and (&uc, 1); // CHECK: atomicrmw and i8
(void) __sync_fetch_and_and (&ss, 1); // CHECK: atomicrmw and i16
@@ -98,6 +107,15 @@ void test_fetch_and_op (void) // CHECK-LABEL: define void @test_fetch_and_op
sll = __sync_fetch_and_xor (&sll, 11); // CHECK: atomicrmw xor
ull = __sync_fetch_and_xor (&ull, 11); // CHECK: atomicrmw xor
+ sc = __sync_fetch_and_nand (&sc, 11); // CHECK: atomicrmw nand
+ uc = __sync_fetch_and_nand (&uc, 11); // CHECK: atomicrmw nand
+ ss = __sync_fetch_and_nand (&ss, 11); // CHECK: atomicrmw nand
+ us = __sync_fetch_and_nand (&us, 11); // CHECK: atomicrmw nand
+ si = __sync_fetch_and_nand (&si, 11); // CHECK: atomicrmw nand
+ ui = __sync_fetch_and_nand (&ui, 11); // CHECK: atomicrmw nand
+ sll = __sync_fetch_and_nand (&sll, 11); // CHECK: atomicrmw nand
+ ull = __sync_fetch_and_nand (&ull, 11); // CHECK: atomicrmw nand
+
sc = __sync_fetch_and_and (&sc, 11); // CHECK: atomicrmw and
uc = __sync_fetch_and_and (&uc, 11); // CHECK: atomicrmw and
ss = __sync_fetch_and_and (&ss, 11); // CHECK: atomicrmw and
@@ -147,6 +165,31 @@ void test_op_and_fetch (void)
sll = __sync_xor_and_fetch (&sll, uc); // CHECK: atomicrmw xor
ull = __sync_xor_and_fetch (&ull, uc); // CHECK: atomicrmw xor
+ sc = __sync_nand_and_fetch (&sc, uc); // CHECK: atomicrmw nand
+ // CHECK: and
+ // CHECK: xor
+ uc = __sync_nand_and_fetch (&uc, uc); // CHECK: atomicrmw nand
+ // CHECK: and
+ // CHECK: xor
+ ss = __sync_nand_and_fetch (&ss, uc); // CHECK: atomicrmw nand
+ // CHECK: and
+ // CHECK: xor
+ us = __sync_nand_and_fetch (&us, uc); // CHECK: atomicrmw nand
+ // CHECK: and
+ // CHECK: xor
+ si = __sync_nand_and_fetch (&si, uc); // CHECK: atomicrmw nand
+ // CHECK: and
+ // CHECK: xor
+ ui = __sync_nand_and_fetch (&ui, uc); // CHECK: atomicrmw nand
+ // CHECK: and
+ // CHECK: xor
+ sll = __sync_nand_and_fetch (&sll, uc); // CHECK: atomicrmw nand
+ // CHECK: and
+ // CHECK: xor
+ ull = __sync_nand_and_fetch (&ull, uc); // CHECK: atomicrmw nand
+ // CHECK: and
+ // CHECK: xor
+
sc = __sync_and_and_fetch (&sc, uc); // CHECK: atomicrmw and
uc = __sync_and_and_fetch (&uc, uc); // CHECK: atomicrmw and
ss = __sync_and_and_fetch (&ss, uc); // CHECK: atomicrmw and
diff --git a/test/CodeGen/aarch64-fix-cortex-a53-835769.c b/test/CodeGen/aarch64-fix-cortex-a53-835769.c
new file mode 100644
index 000000000000..7ad124012e6d
--- /dev/null
+++ b/test/CodeGen/aarch64-fix-cortex-a53-835769.c
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang -O3 -target aarch64-linux-eabi %s -S -o- \
+// RUN: | FileCheck --check-prefix=CHECK-NO --check-prefix=CHECK %s
+// RUN: %clang -O3 -target aarch64-linux-eabi -mfix-cortex-a53-835769 %s -S -o- 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-YES --check-prefix=CHECK %s
+// RUN: %clang -O3 -target aarch64-linux-eabi -mno-fix-cortex-a53-835769 %s -S -o- 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO --check-prefix=CHECK %s
+
+// RUN: %clang -O3 -target aarch64-android-eabi %s -S -o- \
+// RUN: | FileCheck --check-prefix=CHECK-YES --check-prefix=CHECK %s
+// RUN: %clang -O3 -target aarch64-android-eabi -mfix-cortex-a53-835769 %s -S -o- \
+// RUN: | FileCheck --check-prefix=CHECK-YES --check-prefix=CHECK %s
+// RUN: %clang -O3 -target aarch64-android-eabi -mno-fix-cortex-a53-835769 %s -S -o- \
+// RUN: | FileCheck --check-prefix=CHECK-NO --check-prefix=CHECK %s
+
+typedef long int64_t;
+
+int64_t f_load_madd_64(int64_t a, int64_t b, int64_t *c) {
+ int64_t result = a+b*(*c);
+ return result;
+}
+
+// CHECK: ldr
+// CHECK-YES-NEXT: nop
+// CHECK-NO-NEXT-NOT: nop
+// CHECK-NEXT: madd
diff --git a/test/CodeGen/aarch64-poly64.c b/test/CodeGen/aarch64-poly64.c
index 290cc69bd43f..a14162c05353 100644
--- a/test/CodeGen/aarch64-poly64.c
+++ b/test/CodeGen/aarch64-poly64.c
@@ -102,6 +102,18 @@ poly64x2_t test_vdupq_n_p64(poly64_t a) {
// CHECK: dup {{v[0-9]+}}.2d, {{x[0-9]+}}
}
+poly64x1_t test_vmov_n_p64(poly64_t a) {
+ // CHECK-LABEL: test_vmov_n_p64
+ return vmov_n_p64(a);
+ // CHECK: fmov {{d[0-9]+}}, {{x[0-9]+}}
+}
+
+poly64x2_t test_vmovq_n_p64(poly64_t a) {
+ // CHECK-LABEL: test_vmovq_n_p64
+ return vmovq_n_p64(a);
+ // CHECK: dup {{v[0-9]+}}.2d, {{x[0-9]+}}
+}
+
poly64x1_t test_vdup_lane_p64(poly64x1_t vec) {
// CHECK-LABEL: test_vdup_lane_p64
return vdup_lane_p64(vec, 0);
diff --git a/test/CodeGen/aarch64-type-sizes.c b/test/CodeGen/aarch64-type-sizes.c
index b331b6c3c32c..3ff8c4f0d4d0 100644
--- a/test/CodeGen/aarch64-type-sizes.c
+++ b/test/CodeGen/aarch64-type-sizes.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64_be-none-linux-gnu -emit-llvm -w -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
+// RUN: %clang_cc1 -triple aarch64_be-none-linux-gnu -emit-llvm -w -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
// char by definition has size 1
// CHECK-LE: target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
diff --git a/test/CodeGen/aarch64-varargs.c b/test/CodeGen/aarch64-varargs.c
index f787afe37e51..248f1c10cec4 100644
--- a/test/CodeGen/aarch64-varargs.c
+++ b/test/CodeGen/aarch64-varargs.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-LE %s
-// RUN: %clang_cc1 -triple arm64_be-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
+// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
#include <stdarg.h>
diff --git a/test/CodeGen/adc-builtins.c b/test/CodeGen/adc-builtins.c
new file mode 100644
index 000000000000..5577d22c60b3
--- /dev/null
+++ b/test/CodeGen/adc-builtins.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffreestanding -emit-llvm -o - %s | FileCheck %s
+
+#include <x86intrin.h>
+
+unsigned char test_addcarry_u32(unsigned char __cf, unsigned int __x,
+ unsigned int __y, unsigned int *__p) {
+// CHECK-LABEL: test_addcarry_u32
+// CHECK: call i8 @llvm.x86.addcarry.u32
+ return _addcarry_u32(__cf, __x, __y, __p);
+}
+
+unsigned char test_addcarry_u64(unsigned char __cf, unsigned long long __x,
+ unsigned long long __y,
+ unsigned long long *__p) {
+// CHECK-LABEL: test_addcarry_u64
+// CHECK: call i8 @llvm.x86.addcarry.u64
+ return _addcarry_u64(__cf, __x, __y, __p);
+}
+
+unsigned char test_subborrow_u32(unsigned char __cf, unsigned int __x,
+ unsigned int __y, unsigned int *__p) {
+// CHECK-LABEL: test_subborrow_u32
+// CHECK: call i8 @llvm.x86.subborrow.u32
+ return _subborrow_u32(__cf, __x, __y, __p);
+}
+
+unsigned char test_subborrow_u64(unsigned char __cf, unsigned long long __x,
+ unsigned long long __y,
+ unsigned long long *__p) {
+// CHECK-LABEL: test_subborrow_u64
+// CHECK: call i8 @llvm.x86.subborrow.u64
+ return _subborrow_u64(__cf, __x, __y, __p);
+}
diff --git a/test/CodeGen/address-safety-attr.cpp b/test/CodeGen/address-safety-attr.cpp
index f94efd62c9c0..031d013a9b50 100644
--- a/test/CodeGen/address-safety-attr.cpp
+++ b/test/CodeGen/address-safety-attr.cpp
@@ -1,9 +1,16 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address | FileCheck -check-prefix=ASAN %s
-// RUN: echo "src:%s" > %t.file.blacklist
+int DefinedInDifferentFile(int *a);
+// RUN: echo "int DefinedInDifferentFile(int *a) { return *a; }" > %t.extra-source.cpp
+// RUN: echo "struct S { S(){} ~S(){} };" >> %t.extra-source.cpp
+// RUN: echo "S glob_array[5];" >> %t.extra-source.cpp
+
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp | FileCheck -check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address | FileCheck -check-prefix=ASAN %s
+
// RUN: echo "fun:*BlacklistedFunction*" > %t.func.blacklist
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s
+
+// RUN: echo "src:%s" > %t.file.blacklist
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s
// FIXME: %t.file.blacklist is like "src:x:\path\to\clang\test\CodeGen\address-safety-attr.cpp"
// REQUIRES: shell
@@ -12,7 +19,25 @@
// when AddressSanitizer is enabled, unless no_sanitize_address attribute
// is present.
-// WITHOUT: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
+// Attributes for function defined in different source file:
+// WITHOUT: DefinedInDifferentFile{{.*}} [[NOATTR:#[0-9]+]]
+// BLFILE: DefinedInDifferentFile{{.*}} [[WITH:#[0-9]+]]
+// BLFUNC: DefinedInDifferentFile{{.*}} [[WITH:#[0-9]+]]
+// ASAN: DefinedInDifferentFile{{.*}} [[WITH:#[0-9]+]]
+
+// Check that functions generated for global in different source file are
+// not blacklisted.
+// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
+// WITHOUT: @__cxx_global_array_dtor{{.*}}[[NOATTR_NO_TF]]
+// BLFILE: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
+// BLFILE: @__cxx_global_array_dtor{{.*}}[[WITH_NO_TF]]
+// BLFUNC: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
+// BLFUNC: @__cxx_global_array_dtor{{.*}}[[WITH_NO_TF]]
+// ASAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
+// ASAN: @__cxx_global_array_dtor{{.*}}[[WITH_NO_TF]]
+
+
+// WITHOUT: NoAddressSafety1{{.*}}) [[NOATTR]]
// BLFILE: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
// BLFUNC: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
// ASAN: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
@@ -29,8 +54,8 @@ int NoAddressSafety2(int *a) { return *a; }
// WITHOUT: AddressSafetyOk{{.*}}) [[NOATTR]]
// BLFILE: AddressSafetyOk{{.*}}) [[NOATTR]]
-// BLFUNC: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]]
-// ASAN: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]]
+// BLFUNC: AddressSafetyOk{{.*}}) [[WITH]]
+// ASAN: AddressSafetyOk{{.*}}) [[WITH]]
int AddressSafetyOk(int *a) { return *a; }
// WITHOUT: BlacklistedFunction{{.*}}) [[NOATTR]]
@@ -39,6 +64,21 @@ int AddressSafetyOk(int *a) { return *a; }
// ASAN: BlacklistedFunction{{.*}}) [[WITH]]
int BlacklistedFunction(int *a) { return *a; }
+#define GENERATE_FUNC(name) \
+ int name(int *a) { return *a; }
+// WITHOUT: GeneratedFunction{{.*}}) [[NOATTR]]
+// BLFILE: GeneratedFunction{{.*}}) [[NOATTR]]
+// BLFUNC: GeneratedFunction{{.*}}) [[WITH]]
+// ASAN: GeneratedFunction{{.*}}) [[WITH]]
+GENERATE_FUNC(GeneratedFunction)
+
+#define GENERATE_NAME(name) name##_generated
+// WITHOUT: Function_generated{{.*}}) [[NOATTR]]
+// BLFILE: Function_generated{{.*}}) [[NOATTR]]
+// BLFUNC: Function_generated{{.*}}) [[WITH]]
+// ASAN: Function_generated{{.*}}) [[WITH]]
+int GENERATE_NAME(Function)(int *a) { return *a; }
+
// WITHOUT: TemplateAddressSafetyOk{{.*}}) [[NOATTR]]
// BLFILE: TemplateAddressSafetyOk{{.*}}) [[NOATTR]]
// BLFUNC: TemplateAddressSafetyOk{{.*}}) [[WITH]]
@@ -60,21 +100,23 @@ int force_instance = TemplateAddressSafetyOk<42>()
// Check that __cxx_global_var_init* get the sanitize_address attribute.
int global1 = 0;
int global2 = *(int*)((char*)&global1+1);
-// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
+// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF]]
// BLFILE: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
-// BLFUNC: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
-// ASAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
+// BLFUNC: @__cxx_global_var_init{{.*}}[[WITH_NO_TF]]
+// ASAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF]]
// WITHOUT: attributes [[NOATTR]] = { nounwind{{.*}} }
// WITHOUT: attributes [[NOATTR_NO_TF]] = { nounwind }
-// BLFILE: attributes [[NOATTR]] = { nounwind{{.*}} }
+// BLFILE: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
+// BLFILE: attributes [[WITH_NO_TF]] = { nounwind sanitize_address }
// BLFILE: attributes [[NOATTR_NO_TF]] = { nounwind }
+// BLFILE: attributes [[NOATTR]] = { nounwind{{.*}} }
-// BLFUNC: attributes [[NOATTR]] = { nounwind{{.*}} }
// BLFUNC: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
// BLFUNC: attributes [[WITH_NO_TF]] = { nounwind sanitize_address }
+// BLFUNC: attributes [[NOATTR]] = { nounwind{{.*}} }
-// ASAN: attributes [[NOATTR]] = { nounwind{{.*}} }
// ASAN: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
// ASAN: attributes [[WITH_NO_TF]] = { nounwind sanitize_address }
+// ASAN: attributes [[NOATTR]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/address-sanitizer-and-array-cookie.cpp b/test/CodeGen/address-sanitizer-and-array-cookie.cpp
new file mode 100644
index 000000000000..ea8953778916
--- /dev/null
+++ b/test/CodeGen/address-sanitizer-and-array-cookie.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -triple x86_64-gnu-linux -emit-llvm -o - %s | FileCheck %s -check-prefix=PLAIN
+// RUN: %clang_cc1 -triple x86_64-gnu-linux -emit-llvm -o - -fsanitize=address %s | FileCheck %s -check-prefix=ASAN
+
+typedef __typeof__(sizeof(0)) size_t;
+namespace std {
+ struct nothrow_t {};
+ std::nothrow_t nothrow;
+}
+void *operator new[](size_t, const std::nothrow_t &) throw();
+void *operator new[](size_t, char *);
+
+struct C {
+ int x;
+ ~C();
+};
+
+C *CallNew() {
+ return new C[10];
+}
+// PLAIN-LABEL: CallNew
+// PLAIN-NOT: nosanitize
+// PLAIN-NOT: __asan_poison_cxx_array_cookie
+// ASAN-LABEL: CallNew
+// ASAN: store{{.*}}nosanitize
+// ASAN-NOT: nosanitize
+// ASAN: call void @__asan_poison_cxx_array_cookie
+
+C *CallNewNoThrow() {
+ return new (std::nothrow) C[10];
+}
+// PLAIN-LABEL: CallNewNoThrow
+// PLAIN-NOT: nosanitize
+// PLAIN-NOT: __asan_poison_cxx_array_cookie
+// ASAN-LABEL: CallNewNoThrow
+// ASAN: store{{.*}}nosanitize
+// ASAN-NOT: nosanitize
+// ASAN: call void @__asan_poison_cxx_array_cookie
+
+void CallDelete(C *c) {
+ delete [] c;
+}
+
+// PLAIN-LABEL: CallDelete
+// PLAIN-NOT: nosanitize
+// ASAN-LABEL: CallDelete
+// ASAN-NOT: nosanitize
+// ASAN: call i64 @__asan_load_cxx_array_cookie
+// ASAN-NOT: nosanitize
+
+char Buffer[20];
+C *CallPlacementNew() {
+ return new (Buffer) C[20];
+}
+// ASAN-LABEL: CallPlacementNew
+// ASAN-NOT: __asan_poison_cxx_array_cookie
diff --git a/test/CodeGen/adx-builtins.c b/test/CodeGen/adx-builtins.c
new file mode 100644
index 000000000000..8738c5d17715
--- /dev/null
+++ b/test/CodeGen/adx-builtins.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffreestanding -target-feature +adx -emit-llvm -o - %s | FileCheck %s
+
+#include <x86intrin.h>
+
+unsigned char test_addcarryx_u32(unsigned char __cf, unsigned int __x,
+ unsigned int __y, unsigned int *__p) {
+// CHECK-LABEL: test_addcarryx_u32
+// CHECK: call i8 @llvm.x86.addcarryx.u32
+ return _addcarryx_u32(__cf, __x, __y, __p);
+}
+
+unsigned char test_addcarryx_u64(unsigned char __cf, unsigned long long __x,
+ unsigned long long __y,
+ unsigned long long *__p) {
+// CHECK-LABEL: test_addcarryx_u64
+// CHECK: call i8 @llvm.x86.addcarryx.u64
+ return _addcarryx_u64(__cf, __x, __y, __p);
+}
diff --git a/test/CodeGen/alias.c b/test/CodeGen/alias.c
index 98449d36edf6..b773cc8de938 100644
--- a/test/CodeGen/alias.c
+++ b/test/CodeGen/alias.c
@@ -3,6 +3,8 @@
int g0;
// CHECKBASIC: @g0 = common global i32 0
+__thread int TL_WITH_ALIAS;
+// CHECKBASIC-DAG: @TL_WITH_ALIAS = thread_local global i32 0, align 4
static int bar1 = 42;
// CHECKBASIC: @bar1 = internal global i32 42
@@ -10,11 +12,14 @@ extern int g1;
extern int g1 __attribute((alias("g0")));
// CHECKBASIC-DAG: @g1 = alias i32* @g0
+extern __thread int __libc_errno __attribute__ ((alias ("TL_WITH_ALIAS")));
+// CHECKBASIC-DAG: @__libc_errno = thread_local alias i32* @TL_WITH_ALIAS
+
void f0(void) { }
extern void f1(void);
extern void f1(void) __attribute((alias("f0")));
// CHECKBASIC-DAG: @f1 = alias void ()* @f0
-// CHECKBASIC-DAG: @test8_foo = alias weak bitcast (void ()* @test8_bar to void (...)*)
+// CHECKBASIC-DAG: @test8_foo = weak alias bitcast (void ()* @test8_bar to void (...)*)
// CHECKBASIC-DAG: @test8_zed = alias bitcast (void ()* @test8_bar to void (...)*)
// CHECKBASIC-DAG: @test9_zed = alias void ()* @test9_bar
// CHECKBASIC: define void @f0() [[NUW:#[0-9]+]] {
diff --git a/test/CodeGen/align_value.cpp b/test/CodeGen/align_value.cpp
new file mode 100644
index 000000000000..6d0e48128cb2
--- /dev/null
+++ b/test/CodeGen/align_value.cpp
@@ -0,0 +1,103 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+typedef double * __attribute__((align_value(64))) aligned_double;
+
+void foo(aligned_double x, double * y __attribute__((align_value(32))),
+ double & z __attribute__((align_value(128)))) { };
+// CHECK: define void @_Z3fooPdS_Rd(double* align 64 %x, double* align 32 %y, double* dereferenceable(8) align 128 %z)
+
+struct ad_struct {
+ aligned_double a;
+};
+
+double *foo(ad_struct& x) {
+// CHECK-LABEL: @_Z3fooR9ad_struct
+
+// CHECK: [[PTRINT1:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR1:%.+]] = and i64 [[PTRINT1]], 63
+// CHECK: [[MASKCOND1:%.+]] = icmp eq i64 [[MASKEDPTR1]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND1]])
+ return x.a;
+}
+
+double *goo(ad_struct *x) {
+// CHECK-LABEL: @_Z3gooP9ad_struct
+
+// CHECK: [[PTRINT2:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR2:%.+]] = and i64 [[PTRINT2]], 63
+// CHECK: [[MASKCOND2:%.+]] = icmp eq i64 [[MASKEDPTR2]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND2]])
+ return x->a;
+}
+
+double *bar(aligned_double *x) {
+// CHECK-LABEL: @_Z3barPPd
+
+// CHECK: [[PTRINT3:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR3:%.+]] = and i64 [[PTRINT3]], 63
+// CHECK: [[MASKCOND3:%.+]] = icmp eq i64 [[MASKEDPTR3]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND3]])
+ return *x;
+}
+
+double *car(aligned_double &x) {
+// CHECK-LABEL: @_Z3carRPd
+
+// CHECK: [[PTRINT4:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR4:%.+]] = and i64 [[PTRINT4]], 63
+// CHECK: [[MASKCOND4:%.+]] = icmp eq i64 [[MASKEDPTR4]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND4]])
+ return x;
+}
+
+double *dar(aligned_double *x) {
+// CHECK-LABEL: @_Z3darPPd
+
+// CHECK: [[PTRINT5:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR5:%.+]] = and i64 [[PTRINT5]], 63
+// CHECK: [[MASKCOND5:%.+]] = icmp eq i64 [[MASKEDPTR5]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND5]])
+ return x[5];
+}
+
+aligned_double eep();
+double *ret() {
+// CHECK-LABEL: @_Z3retv
+
+// CHECK: [[PTRINT6:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR6:%.+]] = and i64 [[PTRINT6]], 63
+// CHECK: [[MASKCOND6:%.+]] = icmp eq i64 [[MASKEDPTR6]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND6]])
+ return eep();
+}
+
+double **no1(aligned_double *x) {
+// CHECK-LABEL: @_Z3no1PPd
+ return x;
+// CHECK-NOT: call void @llvm.assume
+}
+
+double *&no2(aligned_double &x) {
+// CHECK-LABEL: @_Z3no2RPd
+ return x;
+// CHECK-NOT: call void @llvm.assume
+}
+
+double **no3(aligned_double &x) {
+// CHECK-LABEL: @_Z3no3RPd
+ return &x;
+// CHECK-NOT: call void @llvm.assume
+}
+
+double no3(aligned_double x) {
+// CHECK-LABEL: @_Z3no3Pd
+ return *x;
+// CHECK-NOT: call void @llvm.assume
+}
+
+double *no4(aligned_double x) {
+// CHECK-LABEL: @_Z3no4Pd
+ return x;
+// CHECK-NOT: call void @llvm.assume
+}
+
diff --git a/test/CodeGen/arm-aapcs-vfp.c b/test/CodeGen/arm-aapcs-vfp.c
index eea6ab2f154d..7ef7c4e52edb 100644
--- a/test/CodeGen/arm-aapcs-vfp.c
+++ b/test/CodeGen/arm-aapcs-vfp.c
@@ -1,4 +1,5 @@
// REQUIRES: arm-registered-target
+// REQUIRES: aarch64-registered-target
// RUN: %clang_cc1 -triple thumbv7-apple-darwin9 \
// RUN: -target-abi aapcs \
// RUN: -target-cpu cortex-a8 \
@@ -28,7 +29,7 @@ struct homogeneous_struct {
float f4;
};
// CHECK: define arm_aapcs_vfpcc %struct.homogeneous_struct @test_struct(%struct.homogeneous_struct %{{.*}})
-// CHECK64: define %struct.homogeneous_struct @test_struct(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}})
+// CHECK64: define %struct.homogeneous_struct @test_struct([4 x float] %{{.*}})
extern struct homogeneous_struct struct_callee(struct homogeneous_struct);
struct homogeneous_struct test_struct(struct homogeneous_struct arg) {
return struct_callee(arg);
@@ -43,7 +44,7 @@ struct nested_array {
double d[4];
};
// CHECK: define arm_aapcs_vfpcc void @test_array(%struct.nested_array %{{.*}})
-// CHECK64: define void @test_array(double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}})
+// CHECK64: define void @test_array([4 x double] %{{.*}})
extern void array_callee(struct nested_array);
void test_array(struct nested_array arg) {
array_callee(arg);
@@ -51,7 +52,7 @@ void test_array(struct nested_array arg) {
extern void complex_callee(__complex__ double);
// CHECK: define arm_aapcs_vfpcc void @test_complex({ double, double } %{{.*}})
-// CHECK64: define void @test_complex(double %{{.*}}, double %{{.*}})
+// CHECK64: define void @test_complex([2 x double] %cd.coerce)
void test_complex(__complex__ double cd) {
complex_callee(cd);
}
@@ -72,7 +73,7 @@ struct big_struct {
float f3;
float f4;
};
-// CHECK: define arm_aapcs_vfpcc void @test_big({ [5 x i32] } %{{.*}})
+// CHECK: define arm_aapcs_vfpcc void @test_big([5 x i32] %{{.*}})
// CHECK64: define void @test_big(%struct.big_struct* %{{.*}})
// CHECK64: call void @llvm.memcpy
// CHECK64: call void @big_callee(%struct.big_struct*
@@ -88,7 +89,7 @@ struct heterogeneous_struct {
float f1;
int i2;
};
-// CHECK: define arm_aapcs_vfpcc void @test_hetero({ [2 x i32] } %{{.*}})
+// CHECK: define arm_aapcs_vfpcc void @test_hetero([2 x i32] %{{.*}})
// CHECK64: define void @test_hetero(i64 %{{.*}})
extern void hetero_callee(struct heterogeneous_struct);
void test_hetero(struct heterogeneous_struct arg) {
@@ -97,7 +98,7 @@ void test_hetero(struct heterogeneous_struct arg) {
// Neon multi-vector types are homogeneous aggregates.
// CHECK: define arm_aapcs_vfpcc <16 x i8> @f0(%struct.int8x16x4_t %{{.*}})
-// CHECK64: define <16 x i8> @f0(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+// CHECK64: define <16 x i8> @f0([4 x <16 x i8>] %{{.*}})
int8x16_t f0(int8x16x4_t v4) {
return vaddq_s8(v4.val[0], v4.val[3]);
}
@@ -111,7 +112,7 @@ struct neon_struct {
int16x4_t v4;
};
// CHECK: define arm_aapcs_vfpcc void @test_neon(%struct.neon_struct %{{.*}})
-// CHECK64: define void @test_neon(<8 x i8> %{{.*}}, <8 x i8> %{{.*}}, <2 x i32> %{{.*}}, <4 x i16> %{{.*}})
+// CHECK64: define void @test_neon([4 x <8 x i8>] %{{.*}})
extern void neon_callee(struct neon_struct);
void test_neon(struct neon_struct arg) {
neon_callee(arg);
@@ -125,25 +126,25 @@ typedef struct { long long x; int y; } struct_long_long_int;
// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_1(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, i64 %k, i32 %l)
void test_vfp_stack_gpr_split_1(double a, double b, double c, double d, double e, double f, double g, double h, double i, int j, long long k, int l) {}
-// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_2(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, [3 x i32], { [2 x i64] } %k.coerce)
+// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_2(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, [3 x i32], [2 x i64] %k.coerce)
void test_vfp_stack_gpr_split_2(double a, double b, double c, double d, double e, double f, double g, double h, double i, int j, struct_long_long_int k) {}
-// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_3(%struct.struct_long_long_int* noalias sret %agg.result, double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, [3 x i32], { [2 x i64] } %k.coerce)
+// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_3(%struct.struct_long_long_int* noalias sret %agg.result, double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, [3 x i32], [2 x i64] %k.coerce)
struct_long_long_int test_vfp_stack_gpr_split_3(double a, double b, double c, double d, double e, double f, double g, double h, double i, struct_long_long_int k) {}
typedef struct { int a; int b:4; int c; } struct_int_bitfield_int;
-// CHECK: define arm_aapcs_vfpcc void @test_test_vfp_stack_gpr_split_bitfield(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, i32 %k, [2 x i32], { [3 x i32] } %l.coerce)
+// CHECK: define arm_aapcs_vfpcc void @test_test_vfp_stack_gpr_split_bitfield(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, i32 %k, [2 x i32], [3 x i32] %l.coerce)
void test_test_vfp_stack_gpr_split_bitfield(double a, double b, double c, double d, double e, double f, double g, double h, double i, int j, int k, struct_int_bitfield_int l) {}
// Note: this struct requires internal padding
typedef struct { int x; long long y; } struct_int_long_long;
-// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_4(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, [3 x i32], { [2 x i64] } %k.coerce)
+// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_4(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, [3 x i32], [2 x i64] %k.coerce)
void test_vfp_stack_gpr_split_4(double a, double b, double c, double d, double e, double f, double g, double h, double i, int j, struct_int_long_long k) {}
// This very large struct (passed byval) uses up the GPRs, so no padding is needed
typedef struct { int x[17]; } struct_seventeen_ints;
typedef struct { int x[4]; } struct_four_ints;
-// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_5(%struct.struct_seventeen_ints* byval align 4 %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, double %j, { [4 x i32] } %k.coerce)
+// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_5(%struct.struct_seventeen_ints* byval align 4 %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, double %j, [4 x i32] %k.coerce)
void test_vfp_stack_gpr_split_5(struct_seventeen_ints a, double b, double c, double d, double e, double f, double g, double h, double i, double j, struct_four_ints k) {}
// Here, parameter k would need padding to prevent it from being split, but it
diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c
index 2c5df91c58ac..e4a10fd9e27b 100644
--- a/test/CodeGen/arm-arguments.c
+++ b/test/CodeGen/arm-arguments.c
@@ -183,14 +183,9 @@ void f33(struct s33 s) { }
struct s34 { char c; };
void f34(struct s34 s);
void g34(struct s34 *s) { f34(*s); }
-// APCS-GNU: @g34(%struct.s34* %s)
-// APCS-GNU: %[[a:.*]] = alloca { [1 x i32] }
-// APCS-GNU: %[[gep:.*]] = getelementptr { [1 x i32] }* %[[a]], i32 0, i32 0
-// APCS-GNU: load [1 x i32]* %[[gep]]
// AAPCS: @g34(%struct.s34* %s)
-// AAPCS: %[[a:.*]] = alloca { [1 x i32] }
-// AAPCS: %[[gep:.*]] = getelementptr { [1 x i32] }* %[[a]], i32 0, i32 0
-// AAPCS: load [1 x i32]* %[[gep]]
+// AAPCS: %[[a:.*]] = alloca [1 x i32]
+// AAPCS: load [1 x i32]* %[[a]]
// rdar://12596507
struct s35
diff --git a/test/CodeGen/arm-homogenous.c b/test/CodeGen/arm-homogenous.c
index d1b489793f98..3426d995caef 100644
--- a/test/CodeGen/arm-homogenous.c
+++ b/test/CodeGen/arm-homogenous.c
@@ -5,7 +5,7 @@
// RUN: -ffreestanding -emit-llvm -w -o - %s | FileCheck -check-prefix=CHECK64 %s
// RUN: %clang_cc1 -triple arm64-linux-gnu -ffreestanding -emit-llvm -w -o - %s \
-// RUN: | FileCheck --check-prefix=CHECK64-AAPCS %s
+// RUN: | FileCheck --check-prefix=CHECK64 %s
typedef long long int64_t;
typedef unsigned int uint32_t;
@@ -22,7 +22,7 @@ extern union_with_first_floats returns_union_with_first_floats(void);
void test_union_with_first_floats(void) {
takes_union_with_first_floats(g_u_f);
}
-// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_first_floats({ [4 x i32] })
+// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_first_floats([4 x i32])
void test_return_union_with_first_floats(void) {
g_u_f = returns_union_with_first_floats();
@@ -42,7 +42,7 @@ extern union_with_non_first_floats returns_union_with_non_first_floats(void);
void test_union_with_non_first_floats(void) {
takes_union_with_non_first_floats(g_u_nf_f);
}
-// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_non_first_floats({ [4 x i32] })
+// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_non_first_floats([4 x i32])
void test_return_union_with_non_first_floats(void) {
g_u_nf_f = returns_union_with_non_first_floats();
@@ -62,7 +62,7 @@ extern struct_with_union_with_first_floats returns_struct_with_union_with_first_
void test_struct_with_union_with_first_floats(void) {
takes_struct_with_union_with_first_floats(g_s_f);
}
-// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_first_floats({ [5 x i32] })
+// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_first_floats([5 x i32])
void test_return_struct_with_union_with_first_floats(void) {
g_s_f = returns_struct_with_union_with_first_floats();
@@ -82,7 +82,7 @@ extern struct_with_union_with_non_first_floats returns_struct_with_union_with_no
void test_struct_with_union_with_non_first_floats(void) {
takes_struct_with_union_with_non_first_floats(g_s_nf_f);
}
-// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_non_first_floats({ [5 x i32] })
+// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_non_first_floats([5 x i32])
void test_return_struct_with_union_with_non_first_floats(void) {
g_s_nf_f = returns_struct_with_union_with_non_first_floats();
@@ -176,9 +176,7 @@ void test_struct_of_four_doubles(void) {
// CHECK: test_struct_of_four_doubles
// CHECK: call arm_aapcs_vfpcc void @takes_struct_of_four_doubles(double {{.*}}, %struct.struct_of_four_doubles {{.*}}, %struct.struct_of_four_doubles {{.*}}, double {{.*}})
// CHECK64: test_struct_of_four_doubles
-// CHECK64: call void @takes_struct_of_four_doubles(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [3 x float] undef, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}})
-// CHECK64-AAPCS: test_struct_of_four_doubles
-// CHECK64-AAPCS: call void @takes_struct_of_four_doubles(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [3 x float] undef, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}})
+// CHECK64: call void @takes_struct_of_four_doubles(double {{.*}}, [4 x double] {{.*}}, [4 x double] {{.*}}, double {{.*}})
takes_struct_of_four_doubles(3.0, g_s4d, g_s4d, 4.0);
}
@@ -186,7 +184,7 @@ extern void takes_struct_of_four_doubles_variadic(double a, struct_of_four_doubl
void test_struct_of_four_doubles_variadic(void) {
// CHECK: test_struct_of_four_doubles_variadic
-// CHECK: call arm_aapcs_vfpcc void (double, { [4 x i64] }, { [4 x i64] }, double, ...)* @takes_struct_of_four_doubles_variadic(double {{.*}}, { [4 x i64] } {{.*}}, { [4 x i64] } {{.*}}, double {{.*}})
+// CHECK: call arm_aapcs_vfpcc void (double, [4 x i64], [4 x i64], double, ...)* @takes_struct_of_four_doubles_variadic(double {{.*}}, [4 x i64] {{.*}}, [4 x i64] {{.*}}, double {{.*}})
takes_struct_of_four_doubles_variadic(3.0, g_s4d, g_s4d, 4.0);
}
@@ -212,9 +210,7 @@ void test_struct_of_vecs(void) {
// CHECK: test_struct_of_vecs
// CHECK: call arm_aapcs_vfpcc void @takes_struct_of_vecs(double {{.*}}, %struct.struct_of_vecs {{.*}}, %struct.struct_of_vecs {{.*}}, double {{.*}})
// CHECK64: test_struct_of_vecs
-// CHECK64: call void @takes_struct_of_vecs(double {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, [3 x float] undef, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, double {{.*}})
-// CHECK64-AAPCS: test_struct_of_vecs
-// CHECK64-AAPCS: call void @takes_struct_of_vecs(double {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, [3 x float] undef, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, double {{.*}})
+// CHECK64: call void @takes_struct_of_vecs(double {{.*}}, [4 x <8 x i8>] {{.*}}, [4 x <8 x i8>] {{.*}}, double {{.*}})
takes_struct_of_vecs(3.0, g_vec, g_vec, 4.0);
}
diff --git a/test/CodeGen/arm-metadata.c b/test/CodeGen/arm-metadata.c
index 1cd9880f1b53..1f7756cc8d48 100644
--- a/test/CodeGen/arm-metadata.c
+++ b/test/CodeGen/arm-metadata.c
@@ -2,11 +2,11 @@
// RUN: %clang_cc1 -triple armv7a-linux-gnueabi -emit-llvm -o - %s -fshort-enums | FileCheck -check-prefix=SHORT-ENUM %s
// RUN: %clang_cc1 -triple armv7a-linux-gnueabi -emit-llvm -o - %s -fshort-wchar | FileCheck -check-prefix=SHORT-WCHAR %s
-// DEFAULT: !{{[0-9]+}} = metadata !{i32 1, metadata !"wchar_size", i32 4}
-// DEFAULT: !{{[0-9]+}} = metadata !{i32 1, metadata !"min_enum_size", i32 4}
+// DEFAULT: !{{[0-9]+}} = !{i32 1, !"wchar_size", i32 4}
+// DEFAULT: !{{[0-9]+}} = !{i32 1, !"min_enum_size", i32 4}
-// SHORT-WCHAR: !{{[0-9]+}} = metadata !{i32 1, metadata !"wchar_size", i32 2}
-// SHORT-WCHAR: !{{[0-9]+}} = metadata !{i32 1, metadata !"min_enum_size", i32 4}
+// SHORT-WCHAR: !{{[0-9]+}} = !{i32 1, !"wchar_size", i32 2}
+// SHORT-WCHAR: !{{[0-9]+}} = !{i32 1, !"min_enum_size", i32 4}
-// SHORT_ENUM: !{{[0-9]+}} = metadata !{i32 1, metadata !"wchar_size", i32 4}
-// SHORT-ENUM: !{{[0-9]+}} = metadata !{i32 1, metadata !"min_enum_size", i32 1}
+// SHORT_ENUM: !{{[0-9]+}} = !{i32 1, !"wchar_size", i32 4}
+// SHORT-ENUM: !{{[0-9]+}} = !{i32 1, !"min_enum_size", i32 1}
diff --git a/test/CodeGen/arm-neon-directed-rounding.c b/test/CodeGen/arm-neon-directed-rounding.c
new file mode 100644
index 000000000000..84029318865c
--- /dev/null
+++ b/test/CodeGen/arm-neon-directed-rounding.c
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a57 -ffreestanding -O1 -emit-llvm %s -o - | FileCheck %s
+
+#include <arm_neon.h>
+
+float32x2_t test_vrnda_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vrnda_f32
+ // CHECK: call <2 x float> @llvm.arm.neon.vrinta.v2f32(<2 x float> %a)
+ return vrnda_f32(a);
+}
+
+float32x4_t test_vrndaq_f32(float32x4_t a) {
+ // CHECK-LABEL: test_vrndaq_f32
+ // CHECK: call <4 x float> @llvm.arm.neon.vrinta.v4f32(<4 x float> %a)
+ return vrndaq_f32(a);
+}
+
+float32x2_t test_vrndm_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vrndm_f32
+ // CHECK: call <2 x float> @llvm.arm.neon.vrintm.v2f32(<2 x float> %a)
+ return vrndm_f32(a);
+}
+
+float32x4_t test_vrndmq_f32(float32x4_t a) {
+ // CHECK-LABEL: test_vrndmq_f32
+ // CHECK: call <4 x float> @llvm.arm.neon.vrintm.v4f32(<4 x float> %a)
+ return vrndmq_f32(a);
+}
+
+float32x2_t test_vrndn_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vrndn_f32
+ // CHECK: call <2 x float> @llvm.arm.neon.vrintn.v2f32(<2 x float> %a)
+ return vrndn_f32(a);
+}
+
+float32x4_t test_vrndnq_f32(float32x4_t a) {
+ // CHECK-LABEL: test_vrndnq_f32
+ // CHECK: call <4 x float> @llvm.arm.neon.vrintn.v4f32(<4 x float> %a)
+ return vrndnq_f32(a);
+}
+
+float32x2_t test_vrndp_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vrndp_f32
+ // CHECK: call <2 x float> @llvm.arm.neon.vrintp.v2f32(<2 x float> %a)
+ return vrndp_f32(a);
+}
+
+float32x4_t test_vrndpq_f32(float32x4_t a) {
+ // CHECK-LABEL: test_vrndpq_f32
+ // CHECK: call <4 x float> @llvm.arm.neon.vrintp.v4f32(<4 x float> %a)
+ return vrndpq_f32(a);
+}
+
+float32x2_t test_vrndx_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vrndx_f32
+ // CHECK: call <2 x float> @llvm.arm.neon.vrintx.v2f32(<2 x float> %a)
+ return vrndx_f32(a);
+}
+
+float32x4_t test_vrndxq_f32(float32x4_t a) {
+ // CHECK-LABEL: test_vrndxq_f32
+ // CHECK: call <4 x float> @llvm.arm.neon.vrintx.v4f32(<4 x float> %a)
+ return vrndxq_f32(a);
+}
+
+float32x2_t test_vrnd_f32(float32x2_t a) {
+ // CHECK-LABEL: test_vrnd_f32
+ // CHECK: call <2 x float> @llvm.arm.neon.vrintz.v2f32(<2 x float> %a)
+ return vrnd_f32(a);
+}
+
+float32x4_t test_vrndq_f32(float32x4_t a) {
+ // CHECK-LABEL: test_vrndq_f32
+ // CHECK: call <4 x float> @llvm.arm.neon.vrintz.v4f32(<4 x float> %a)
+ return vrndq_f32(a);
+}
diff --git a/test/CodeGen/arm-neon-numeric-maxmin.c b/test/CodeGen/arm-neon-numeric-maxmin.c
new file mode 100644
index 000000000000..615a854b5e21
--- /dev/null
+++ b/test/CodeGen/arm-neon-numeric-maxmin.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a57 -ffreestanding -O1 -emit-llvm %s -o - | FileCheck %s
+
+#include <arm_neon.h>
+
+float32x2_t test_vmaxnm_f32(float32x2_t a, float32x2_t b) {
+ // CHECK-LABEL: test_vmaxnm_f32
+ // CHECK: call <2 x float> @llvm.arm.neon.vmaxnm.v2f32(<2 x float> %a, <2 x float> %b)
+ return vmaxnm_f32(a, b);
+}
+
+float32x4_t test_vmaxnmq_f32(float32x4_t a, float32x4_t b) {
+ // CHECK-LABEL: test_vmaxnmq_f32
+ // CHECK: call <4 x float> @llvm.arm.neon.vmaxnm.v4f32(<4 x float> %a, <4 x float> %b)
+ return vmaxnmq_f32(a, b);
+}
+
+float32x2_t test_vminnm_f32(float32x2_t a, float32x2_t b) {
+ // CHECK-LABEL: test_vminnm_f32
+ // CHECK: call <2 x float> @llvm.arm.neon.vminnm.v2f32(<2 x float> %a, <2 x float> %b)
+ return vminnm_f32(a, b);
+}
+
+float32x4_t test_vminnmq_f32(float32x4_t a, float32x4_t b) {
+ // CHECK-LABEL: test_vminnmq_f32
+ // CHECK: call <4 x float> @llvm.arm.neon.vminnm.v4f32(<4 x float> %a, <4 x float> %b)
+ return vminnmq_f32(a, b);
+}
diff --git a/test/CodeGen/arm64-aapcs-arguments.c b/test/CodeGen/arm64-aapcs-arguments.c
index b430630b0711..ab302d407041 100644
--- a/test/CodeGen/arm64-aapcs-arguments.c
+++ b/test/CodeGen/arm64-aapcs-arguments.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-linux-gnu -target-feature +neon -target-abi aapcs -ffreestanding -emit-llvm -w -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon -target-abi aapcs -ffreestanding -fallow-half-arguments-and-returns -emit-llvm -w -o - %s | FileCheck %s
// AAPCS clause C.8 says: If the argument has an alignment of 16 then the NGRN
// is rounded up to the next even number.
@@ -17,7 +17,7 @@ void test2(int x0, Small x2_x3, int x4, Small x6_x7, int sp, Small sp16) {
// stack in order to avoid holes. Make sure we get all of them, and not just the
// first:
-// CHECK: void @test3(float %s0_s3.0, float %s0_s3.1, float %s0_s3.2, float %s0_s3.3, float %s4, [3 x float], [2 x double] %sp.coerce, [2 x double] %sp16.coerce)
+// CHECK: void @test3([4 x float] %s0_s3.coerce, float %s4, [4 x float] %sp.coerce, [4 x float] %sp16.coerce)
typedef struct { float arr[4]; } HFA;
void test3(HFA s0_s3, float s4, HFA sp, HFA sp16) {
}
@@ -28,7 +28,7 @@ void test3(HFA s0_s3, float s4, HFA sp, HFA sp16) {
// fp128] or something, but leaving them as-is retains more information for
// users to debug.
-// CHECK: void @test4(<16 x i8> %v0_v2.0, <16 x i8> %v0_v2.1, <16 x i8> %v0_v2.2, <16 x i8> %v3_v5.0, <16 x i8> %v3_v5.1, <16 x i8> %v3_v5.2, [2 x float], <16 x i8> %sp.0, <16 x i8> %sp.1, <16 x i8> %sp.2, double %sp48, <16 x i8> %sp64.0, <16 x i8> %sp64.1, <16 x i8> %sp64.2)
+// CHECK: void @test4([3 x <16 x i8>] %v0_v2.coerce, [3 x <16 x i8>] %v3_v5.coerce, [3 x <16 x i8>] %sp.coerce, double %sp48, [3 x <16 x i8>] %sp64.coerce)
typedef __attribute__((neon_vector_type(16))) signed char int8x16_t;
typedef struct { int8x16_t arr[3]; } BigHFA;
void test4(BigHFA v0_v2, BigHFA v3_v5, BigHFA sp, double sp48, BigHFA sp64) {
@@ -40,3 +40,12 @@ void test4(BigHFA v0_v2, BigHFA v3_v5, BigHFA sp, double sp48, BigHFA sp64) {
// CHECK: define i8 @test5(i8 %a, i16 %b)
unsigned char test5(unsigned char a, signed short b) {
}
+
+// __fp16 can be used as a function argument or return type (ACLE 2.0)
+// CHECK: define half @test_half(half %{{.*}})
+__fp16 test_half(__fp16 A) { }
+
+// __fp16 is a base type for homogeneous floating-point aggregates for AArch64 (but not 32-bit ARM).
+// CHECK: define %struct.HFA_half @test_half_hfa([4 x half] %{{.*}})
+struct HFA_half { __fp16 a[4]; };
+struct HFA_half test_half_hfa(struct HFA_half A) { }
diff --git a/test/CodeGen/arm64-arguments.c b/test/CodeGen/arm64-arguments.c
index b2de08dbe68c..ae1ff98800ac 100644
--- a/test/CodeGen/arm64-arguments.c
+++ b/test/CodeGen/arm64-arguments.c
@@ -123,8 +123,7 @@ void f31(struct s31 s) { }
struct s32 { double x; };
void f32(struct s32 s) { }
-// Expand Homogeneous Aggregate.
-// CHECK: @f32(double %{{.*}})
+// CHECK: @f32([1 x double] %{{.*}})
// A composite type larger than 16 bytes should be passed indirectly.
struct s33 { char buf[32*32]; };
@@ -197,7 +196,7 @@ typedef struct s35 s35_with_align;
typedef __attribute__((neon_vector_type(4))) float float32x4_t;
float32x4_t f35(int i, s35_with_align s1, s35_with_align s2) {
-// CHECK: define <4 x float> @f35(i32 %i, float %s1.0, float %s1.1, float %s1.2, float %s1.3, float %s2.0, float %s2.1, float %s2.2, float %s2.3)
+// CHECK: define <4 x float> @f35(i32 %i, [4 x float] %s1.coerce, [4 x float] %s2.coerce)
// CHECK: %s1 = alloca %struct.s35, align 16
// CHECK: %s2 = alloca %struct.s35, align 16
// CHECK: %[[a:.*]] = bitcast %struct.s35* %s1 to <4 x float>*
@@ -598,24 +597,24 @@ int caller43_stack() {
__attribute__ ((noinline))
int f40_split(int i, int i2, int i3, int i4, int i5, int i6, int i7,
s40_no_align s1, s40_no_align s2) {
-// CHECK: define i32 @f40_split(i32 %i, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, [1 x i32], [2 x i64] %s1.coerce, [2 x i64] %s2.coerce)
+// CHECK: define i32 @f40_split(i32 %i, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, [2 x i64] %s1.coerce, [2 x i64] %s2.coerce)
return s1.i + s2.i + i + i2 + i3 + i4 + i5 + i6 + i7 + s1.s + s2.s;
}
int caller40_split() {
// CHECK: define i32 @caller40_split()
-// CHECK: call i32 @f40_split(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, [1 x i32] undef, [2 x i64] %{{.*}} [2 x i64] %{{.*}})
+// CHECK: call i32 @f40_split(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, [2 x i64] %{{.*}} [2 x i64] %{{.*}})
return f40_split(1, 2, 3, 4, 5, 6, 7, g40, g40_2);
}
__attribute__ ((noinline))
int f41_split(int i, int i2, int i3, int i4, int i5, int i6, int i7,
s41_with_align s1, s41_with_align s2) {
-// CHECK: define i32 @f41_split(i32 %i, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, [1 x i32], i128 %s1.coerce, i128 %s2.coerce)
+// CHECK: define i32 @f41_split(i32 %i, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i128 %s1.coerce, i128 %s2.coerce)
return s1.i + s2.i + i + i2 + i3 + i4 + i5 + i6 + i7 + s1.s + s2.s;
}
int caller41_split() {
// CHECK: define i32 @caller41_split()
-// CHECK: call i32 @f41_split(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, [1 x i32] undef, i128 %{{.*}}, i128 %{{.*}})
+// CHECK: call i32 @f41_split(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i128 %{{.*}}, i128 %{{.*}})
return f41_split(1, 2, 3, 4, 5, 6, 7, g41, g41_2);
}
@@ -642,7 +641,7 @@ float test_hfa(int n, ...) {
float test_hfa_call(struct HFA *a) {
// CHECK-LABEL: define float @test_hfa_call(%struct.HFA* %a)
-// CHECK: call float (i32, ...)* @test_hfa(i32 1, [2 x double] {{.*}})
+// CHECK: call float (i32, ...)* @test_hfa(i32 1, [4 x float] {{.*}})
test_hfa(1, *a);
}
diff --git a/test/CodeGen/arm64-be-bitfield.c b/test/CodeGen/arm64-be-bitfield.c
index f563596bdda3..b8d497c5580d 100644
--- a/test/CodeGen/arm64-be-bitfield.c
+++ b/test/CodeGen/arm64-be-bitfield.c
@@ -1,9 +1,15 @@
-// RUN: %clang_cc1 -triple arm64_be-linux-gnu -ffreestanding -emit-llvm -O0 -o - %s | FileCheck %s
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -ffreestanding -emit-llvm -O0 -o - %s | FileCheck --check-prefix IR %s
+// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -ffreestanding -S -O1 -o - %s | FileCheck --check-prefix ARM %s
struct bt3 { signed b2:10; signed b3:10; } b16;
-// The correct right-shift amount is 40 bits for big endian.
+// Get the high 32-bits and then shift appropriately for big-endian.
signed callee_b0f(struct bt3 bp11) {
-// CHECK: = lshr i64 %{{.*}}, 40
+// IR: callee_b0f(i64 [[ARG:%.*]])
+// IR: store i64 [[ARG]], i64* [[PTR:%.*]]
+// IR: [[BITCAST:%.*]] = bitcast i64* [[PTR]] to i8*
+// IR: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* [[BITCAST]], i64 4
+// ARM: asr x0, x0, #54
return bp11.b2;
}
diff --git a/test/CodeGen/arm64-be-hfa-vararg.c b/test/CodeGen/arm64-be-hfa-vararg.c
index c9d650794d6e..537aab52b3b5 100644
--- a/test/CodeGen/arm64-be-hfa-vararg.c
+++ b/test/CodeGen/arm64-be-hfa-vararg.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64_be-linux-gnu -ffreestanding -emit-llvm -O0 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -ffreestanding -emit-llvm -O0 -o - %s | FileCheck %s
#include <stdarg.h>
diff --git a/test/CodeGen/arm64-lanes.c b/test/CodeGen/arm64-lanes.c
index 8ab2bd4c6690..4e80df9d6c52 100644
--- a/test/CodeGen/arm64-lanes.c
+++ b/test/CodeGen/arm64-lanes.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -O3 -triple arm64_be-linux-gnu -target-feature +neon -ffreestanding -emit-llvm -o - %s | FileCheck %s --check-prefix CHECK-BE
+// RUN: %clang_cc1 -O3 -triple aarch64_be-linux-gnu -target-feature +neon -ffreestanding -emit-llvm -o - %s | FileCheck %s --check-prefix CHECK-BE
#include <arm_neon.h>
diff --git a/test/CodeGen/arm_acle.c b/test/CodeGen/arm_acle.c
index 8550c58b3677..5b024506a50e 100644
--- a/test/CodeGen/arm_acle.c
+++ b/test/CodeGen/arm_acle.c
@@ -62,6 +62,53 @@ void test_sevl(void) {
__sevl();
}
+#if __ARM_32BIT_STATE
+// AArch32-LABEL: test_dbg
+// AArch32: call void @llvm.arm.dbg(i32 0)
+void test_dbg(void) {
+ __dbg(0);
+}
+#endif
+
+/* 8.5 Swap */
+// ARM-LABEL: test_swp
+// AArch32: call i32 @llvm.arm.ldrex
+// AArch32: call i32 @llvm.arm.strex
+// AArch64: call i64 @llvm.aarch64.ldxr
+// AArch64: call i32 @llvm.aarch64.stxr
+uint32_t test_swp(uint32_t x, volatile void *p) {
+ __swp(x, p);
+}
+
+/* 8.6 Memory prefetch intrinsics */
+/* 8.6.1 Data prefetch */
+// ARM-LABEL: test_pld
+// ARM: call void @llvm.prefetch(i8* null, i32 0, i32 3, i32 1)
+void test_pld() {
+ __pld(0);
+}
+
+// ARM-LABEL: test_pldx
+// AArch32: call void @llvm.prefetch(i8* null, i32 1, i32 3, i32 1)
+// AArch64: call void @llvm.prefetch(i8* null, i32 1, i32 1, i32 1)
+void test_pldx() {
+ __pldx(1, 2, 0, 0);
+}
+
+/* 8.6.2 Instruction prefetch */
+// ARM-LABEL: test_pli
+// ARM: call void @llvm.prefetch(i8* null, i32 0, i32 3, i32 0)
+void test_pli() {
+ __pli(0);
+}
+
+// ARM-LABEL: test_plix
+// AArch32: call void @llvm.prefetch(i8* null, i32 0, i32 3, i32 0)
+// AArch64: call void @llvm.prefetch(i8* null, i32 0, i32 1, i32 0)
+void test_plix() {
+ __plix(2, 0, 0);
+}
+
/* 8.7 NOP */
// ARM-LABEL: test_nop
// AArch32: call void @llvm.arm.hint(i32 0)
@@ -72,23 +119,31 @@ void test_nop(void) {
/* 9 DATA-PROCESSING INTRINSICS */
/* 9.2 Miscellaneous data-processing intrinsics */
-// ARM-LABEL: test_rev
-// ARM: call i32 @llvm.bswap.i32(i32 %t)
-uint32_t test_rev(uint32_t t) {
- return __rev(t);
+// ARM-LABEL: test_ror
+// ARM: lshr
+// ARM: sub
+// ARM: shl
+// ARM: or
+uint32_t test_ror(uint32_t x, uint32_t y) {
+ return __ror(x, y);
}
-// ARM-LABEL: test_revl
-// AArch32: call i32 @llvm.bswap.i32(i32 %t)
-// AArch64: call i64 @llvm.bswap.i64(i64 %t)
-long test_revl(long t) {
- return __revl(t);
+// ARM-LABEL: test_rorl
+// ARM: lshr
+// ARM: sub
+// ARM: shl
+// ARM: or
+unsigned long test_rorl(unsigned long x, uint32_t y) {
+ return __rorl(x, y);
}
-// ARM-LABEL: test_revll
-// ARM: call i64 @llvm.bswap.i64(i64 %t)
-uint64_t test_revll(uint64_t t) {
- return __revll(t);
+// ARM-LABEL: test_rorll
+// ARM: lshr
+// ARM: sub
+// ARM: shl
+// ARM: or
+uint64_t test_rorll(uint64_t x, uint32_t y) {
+ return __rorll(x, y);
}
// ARM-LABEL: test_clz
@@ -110,6 +165,80 @@ uint64_t test_clzll(uint64_t t) {
return __clzll(t);
}
+// ARM-LABEL: test_rev
+// ARM: call i32 @llvm.bswap.i32(i32 %t)
+uint32_t test_rev(uint32_t t) {
+ return __rev(t);
+}
+
+// ARM-LABEL: test_revl
+// AArch32: call i32 @llvm.bswap.i32(i32 %t)
+// AArch64: call i64 @llvm.bswap.i64(i64 %t)
+long test_revl(long t) {
+ return __revl(t);
+}
+
+// ARM-LABEL: test_revll
+// ARM: call i64 @llvm.bswap.i64(i64 %t)
+uint64_t test_revll(uint64_t t) {
+ return __revll(t);
+}
+
+// ARM-LABEL: test_rev16
+// ARM: llvm.bswap
+// ARM: lshr
+// ARM: shl
+// ARM: or
+uint32_t test_rev16(uint32_t t) {
+ return __rev16(t);
+}
+
+// ARM-LABEL: test_rev16l
+// ARM: llvm.bswap
+// ARM: lshr
+// ARM: shl
+// ARM: or
+long test_rev16l(long t) {
+ return __rev16l(t);
+}
+
+// ARM-LABEL: test_rev16ll
+// ARM: llvm.bswap
+// ARM: lshr
+// ARM: shl
+// ARM: or
+uint64_t test_rev16ll(uint64_t t) {
+ return __rev16ll(t);
+}
+
+// ARM-LABEL: test_revsh
+// ARM: call i16 @llvm.bswap.i16(i16 %t)
+int16_t test_revsh(int16_t t) {
+ return __revsh(t);
+}
+
+// ARM-LABEL: test_rbit
+// AArch32: call i32 @llvm.arm.rbit
+// AArch64: call i32 @llvm.aarch64.rbit.i32
+uint32_t test_rbit(uint32_t t) {
+ return __rbit(t);
+}
+
+// ARM-LABEL: test_rbitl
+// AArch32: call i32 @llvm.arm.rbit
+// AArch64: call i64 @llvm.aarch64.rbit.i64
+long test_rbitl(long t) {
+ return __rbitl(t);
+}
+
+// ARM-LABEL: test_rbitll
+// AArch32: call i32 @llvm.arm.rbit
+// AArch32: call i32 @llvm.arm.rbit
+// AArch64: call i64 @llvm.aarch64.rbit.i64
+uint64_t test_rbitll(uint64_t t) {
+ return __rbitll(t);
+}
+
/* 9.4 Saturating intrinsics */
#ifdef __ARM_32BIT_STATE
diff --git a/test/CodeGen/arm_neon_intrinsics.c b/test/CodeGen/arm_neon_intrinsics.c
index a084d8b2c84c..756e3b43fc54 100644
--- a/test/CodeGen/arm_neon_intrinsics.c
+++ b/test/CodeGen/arm_neon_intrinsics.c
@@ -1474,79 +1474,109 @@ poly8x16_t test_vcntq_p8(poly8x16_t a) {
// CHECK-LABEL: test_vcombine_s8
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
int8x16_t test_vcombine_s8(int8x8_t a, int8x8_t b) {
return vcombine_s8(a, b);
}
// CHECK-LABEL: test_vcombine_s16
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
int16x8_t test_vcombine_s16(int16x4_t a, int16x4_t b) {
return vcombine_s16(a, b);
}
// CHECK-LABEL: test_vcombine_s32
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
int32x4_t test_vcombine_s32(int32x2_t a, int32x2_t b) {
return vcombine_s32(a, b);
}
// CHECK-LABEL: test_vcombine_s64
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
int64x2_t test_vcombine_s64(int64x1_t a, int64x1_t b) {
return vcombine_s64(a, b);
}
// CHECK-LABEL: test_vcombine_f16
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
float16x8_t test_vcombine_f16(float16x4_t a, float16x4_t b) {
return vcombine_f16(a, b);
}
// CHECK-LABEL: test_vcombine_f32
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
float32x4_t test_vcombine_f32(float32x2_t a, float32x2_t b) {
return vcombine_f32(a, b);
}
// CHECK-LABEL: test_vcombine_u8
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
uint8x16_t test_vcombine_u8(uint8x8_t a, uint8x8_t b) {
return vcombine_u8(a, b);
}
// CHECK-LABEL: test_vcombine_u16
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
uint16x8_t test_vcombine_u16(uint16x4_t a, uint16x4_t b) {
return vcombine_u16(a, b);
}
// CHECK-LABEL: test_vcombine_u32
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
uint32x4_t test_vcombine_u32(uint32x2_t a, uint32x2_t b) {
return vcombine_u32(a, b);
}
// CHECK-LABEL: test_vcombine_u64
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
uint64x2_t test_vcombine_u64(uint64x1_t a, uint64x1_t b) {
return vcombine_u64(a, b);
}
// CHECK-LABEL: test_vcombine_p8
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
poly8x16_t test_vcombine_p8(poly8x8_t a, poly8x8_t b) {
return vcombine_p8(a, b);
}
// CHECK-LABEL: test_vcombine_p16
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
poly16x8_t test_vcombine_p16(poly16x4_t a, poly16x4_t b) {
return vcombine_p16(a, b);
}
// CHECK-LABEL: test_vcreate_s8
+// CHECK: vmov [[REG:d[0-9]+]], r0, r1
+// CHECK: vclz.i8 d{{[0-9]+}}, [[REG]]
int8x8_t test_vcreate_s8(uint64_t a) {
- return vcreate_s8(a);
+ return vclz_s8(vcreate_s8(a));
}
// CHECK-LABEL: test_vcreate_s16
+// CHECK: vmov [[REG:d[0-9]+]], r0, r1
+// CHECK: vclz.i16 d{{[0-9]+}}, [[REG]]
int16x4_t test_vcreate_s16(uint64_t a) {
- return vcreate_s16(a);
+ return vclz_s16(vcreate_s16(a));
}
// CHECK-LABEL: test_vcreate_s32
+// CHECK: vmov [[REG:d[0-9]+]], r0, r1
+// CHECK: vclz.i32 d{{[0-9]+}}, [[REG]]
int32x2_t test_vcreate_s32(uint64_t a) {
- return vcreate_s32(a);
+ return vclz_s32(vcreate_s32(a));
}
// CHECK-LABEL: test_vcreate_f16
@@ -1560,38 +1590,59 @@ float32x2_t test_vcreate_f32(uint64_t a) {
}
// CHECK-LABEL: test_vcreate_u8
+// CHECK: vmov [[REG:d[0-9]+]], r0, r1
+// CHECK: vclz.i8 d{{[0-9]+}}, [[REG]]
uint8x8_t test_vcreate_u8(uint64_t a) {
- return vcreate_u8(a);
+ return vclz_s8(vcreate_u8(a));
}
// CHECK-LABEL: test_vcreate_u16
+// CHECK: vmov [[REG:d[0-9]+]], r0, r1
+// CHECK: vclz.i16 d{{[0-9]+}}, [[REG]]
uint16x4_t test_vcreate_u16(uint64_t a) {
- return vcreate_u16(a);
+ return vclz_s16(vcreate_u16(a));
}
// CHECK-LABEL: test_vcreate_u32
+// CHECK: vmov [[REG:d[0-9]+]], r0, r1
+// CHECK: vclz.i32 d{{[0-9]+}}, [[REG]]
uint32x2_t test_vcreate_u32(uint64_t a) {
- return vcreate_u32(a);
+ return vclz_s32(vcreate_u32(a));
}
+
+// We have two ways of lowering that. Either with one 'vmov d, r, r' or
+// with two 'vmov d[],r'. LLVM does the latter. We may want to be less
+// strict about the matching pattern if it starts causing problem.
// CHECK-LABEL: test_vcreate_u64
+// CHECK: vmov.32 [[REG:d[0-9]+]][0], r0
+// CHECK: vmov.32 [[REG]][1], r1
uint64x1_t test_vcreate_u64(uint64_t a) {
- return vcreate_u64(a);
+ uint64x1_t tmp = vcreate_u64(a);
+ return vadd_u64(tmp, tmp);
+
}
// CHECK-LABEL: test_vcreate_p8
+// CHECK: vmov [[REG:d[0-9]+]], r0, r1
+// CHECK: vcnt.8 d{{[0-9]+}}, [[REG]]
poly8x8_t test_vcreate_p8(uint64_t a) {
- return vcreate_p8(a);
+ return vcnt_p8(vcreate_p8(a));
}
// CHECK-LABEL: test_vcreate_p16
+// CHECK: vmov [[REG:d[0-9]+]], r0, r1
poly16x4_t test_vcreate_p16(uint64_t a) {
- return vcreate_p16(a);
+ poly16x4_t tmp = vcreate_p16(a);
+ return vbsl_p16(tmp, tmp, tmp);
}
// CHECK-LABEL: test_vcreate_s64
+// CHECK: vmov.32 [[REG:d[0-9]+]][0], r0
+// CHECK: vmov.32 [[REG]][1], r1
int64x1_t test_vcreate_s64(uint64_t a) {
- return vcreate_s64(a);
+ int64x1_t tmp = vcreate_s64(a);
+ return vadd_s64(tmp, tmp);
}
@@ -1855,7 +1906,7 @@ uint16x4_t test_vdup_n_u16(uint16_t a) {
}
// CHECK-LABEL: test_vdup_n_u32
-// CHECK: vmov
+// CHECK: mov
uint32x2_t test_vdup_n_u32(uint32_t a) {
return vdup_n_u32(a);
}
@@ -1873,7 +1924,7 @@ int16x4_t test_vdup_n_s16(int16_t a) {
}
// CHECK-LABEL: test_vdup_n_s32
-// CHECK: vmov
+// CHECK: mov
int32x2_t test_vdup_n_s32(int32_t a) {
return vdup_n_s32(a);
}
@@ -1897,7 +1948,7 @@ float16x4_t test_vdup_n_f16(float16_t *a) {
}
// CHECK-LABEL: test_vdup_n_f32
-// CHECK: vmov
+// CHECK: mov
float32x2_t test_vdup_n_f32(float32_t a) {
return vdup_n_f32(a);
}
@@ -1963,27 +2014,32 @@ float32x4_t test_vdupq_n_f32(float32_t a) {
}
// CHECK-LABEL: test_vdup_n_s64
-// CHECK: vmov
+// CHECK: vmov
int64x1_t test_vdup_n_s64(int64_t a) {
- return vdup_n_s64(a);
+ int64x1_t tmp = vdup_n_s64(a);
+ return vadd_s64(tmp, tmp);
}
// CHECK-LABEL: test_vdup_n_u64
-// CHECK: vmov
+// CHECK: vmov
uint64x1_t test_vdup_n_u64(uint64_t a) {
- return vdup_n_u64(a);
+ int64x1_t tmp = vdup_n_u64(a);
+ return vadd_s64(tmp, tmp);
+
}
// CHECK-LABEL: test_vdupq_n_s64
-// CHECK: vmov
+// CHECK: vmov
int64x2_t test_vdupq_n_s64(int64_t a) {
- return vdupq_n_s64(a);
+ int64x2_t tmp = vdupq_n_s64(a);
+ return vaddq_s64(tmp, tmp);
}
// CHECK-LABEL: test_vdupq_n_u64
-// CHECK: vmov
+// CHECK: vmov
uint64x2_t test_vdupq_n_u64(uint64_t a) {
- return vdupq_n_u64(a);
+ int64x2_t tmp = vdupq_n_u64(a);
+ return vaddq_u64(tmp, tmp);
}
@@ -2302,7 +2358,7 @@ uint16_t test_vget_lane_u16(uint16x4_t a) {
}
// CHECK-LABEL: test_vget_lane_u32
-// CHECK: vmov
+// CHECK: mov
uint32_t test_vget_lane_u32(uint32x2_t a) {
return vget_lane_u32(a, 1);
}
@@ -2320,7 +2376,7 @@ int16_t test_vget_lane_s16(int16x4_t a) {
}
// CHECK-LABEL: test_vget_lane_s32
-// CHECK: vmov
+// CHECK: mov
int32_t test_vget_lane_s32(int32x2_t a) {
return vget_lane_s32(a, 1);
}
@@ -2398,13 +2454,13 @@ float32_t test_vgetq_lane_f32(float32x4_t a) {
}
// CHECK-LABEL: test_vget_lane_s64
-// CHECK: vmov
+// The optimizer is able to remove all moves now.
int64_t test_vget_lane_s64(int64x1_t a) {
return vget_lane_s64(a, 0);
}
// CHECK-LABEL: test_vget_lane_u64
-// CHECK: vmov
+// The optimizer is able to remove all moves now.
uint64_t test_vget_lane_u64(uint64x1_t a) {
return vget_lane_u64(a, 0);
}
@@ -4849,49 +4905,49 @@ uint32x2_t test_vmovn_u64(uint64x2_t a) {
// CHECK-LABEL: test_vmov_n_u8
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
uint8x8_t test_vmov_n_u8(uint8_t a) {
return vmov_n_u8(a);
}
// CHECK-LABEL: test_vmov_n_u16
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
uint16x4_t test_vmov_n_u16(uint16_t a) {
return vmov_n_u16(a);
}
// CHECK-LABEL: test_vmov_n_u32
-// CHECK: vmov
+// CHECK: mov {{r[0-9]+}}
uint32x2_t test_vmov_n_u32(uint32_t a) {
return vmov_n_u32(a);
}
// CHECK-LABEL: test_vmov_n_s8
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
int8x8_t test_vmov_n_s8(int8_t a) {
return vmov_n_s8(a);
}
// CHECK-LABEL: test_vmov_n_s16
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
int16x4_t test_vmov_n_s16(int16_t a) {
return vmov_n_s16(a);
}
// CHECK-LABEL: test_vmov_n_s32
-// CHECK: vmov
+// CHECK: mov {{r[0-9]+}}
int32x2_t test_vmov_n_s32(int32_t a) {
return vmov_n_s32(a);
}
// CHECK-LABEL: test_vmov_n_p8
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
poly8x8_t test_vmov_n_p8(poly8_t a) {
return vmov_n_p8(a);
}
// CHECK-LABEL: test_vmov_n_p16
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
poly16x4_t test_vmov_n_p16(poly16_t a) {
return vmov_n_p16(a);
}
@@ -4903,55 +4959,55 @@ float16x4_t test_vmov_n_f16(float16_t *a) {
}
// CHECK-LABEL: test_vmov_n_f32
-// CHECK: vmov
+// CHECK: mov {{r[0-9]+}}
float32x2_t test_vmov_n_f32(float32_t a) {
return vmov_n_f32(a);
}
// CHECK-LABEL: test_vmovq_n_u8
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
uint8x16_t test_vmovq_n_u8(uint8_t a) {
return vmovq_n_u8(a);
}
// CHECK-LABEL: test_vmovq_n_u16
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
uint16x8_t test_vmovq_n_u16(uint16_t a) {
return vmovq_n_u16(a);
}
// CHECK-LABEL: test_vmovq_n_u32
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
uint32x4_t test_vmovq_n_u32(uint32_t a) {
return vmovq_n_u32(a);
}
// CHECK-LABEL: test_vmovq_n_s8
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
int8x16_t test_vmovq_n_s8(int8_t a) {
return vmovq_n_s8(a);
}
// CHECK-LABEL: test_vmovq_n_s16
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
int16x8_t test_vmovq_n_s16(int16_t a) {
return vmovq_n_s16(a);
}
// CHECK-LABEL: test_vmovq_n_s32
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
int32x4_t test_vmovq_n_s32(int32_t a) {
return vmovq_n_s32(a);
}
// CHECK-LABEL: test_vmovq_n_p8
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
poly8x16_t test_vmovq_n_p8(poly8_t a) {
return vmovq_n_p8(a);
}
// CHECK-LABEL: test_vmovq_n_p16
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
poly16x8_t test_vmovq_n_p16(poly16_t a) {
return vmovq_n_p16(a);
}
@@ -4963,31 +5019,35 @@ float16x8_t test_vmovq_n_f16(float16_t *a) {
}
// CHECK-LABEL: test_vmovq_n_f32
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
float32x4_t test_vmovq_n_f32(float32_t a) {
return vmovq_n_f32(a);
}
// CHECK-LABEL: test_vmov_n_s64
-// CHECK: vmov
+// CHECK: vmov.32 [[REG:d[0-9]+]][0], r0
+// CHECK: vmov.32 [[REG]][1], r1
int64x1_t test_vmov_n_s64(int64_t a) {
- return vmov_n_s64(a);
+ int64x1_t tmp = vmov_n_s64(a);
+ return vadd_s64(tmp, tmp);
}
// CHECK-LABEL: test_vmov_n_u64
-// CHECK: vmov
+// CHECK: vmov.32 [[REG:d[0-9]+]][0], r0
+// CHECK: vmov.32 [[REG]][1], r1
uint64x1_t test_vmov_n_u64(uint64_t a) {
- return vmov_n_u64(a);
+ uint64x1_t tmp = vmov_n_u64(a);
+ return vadd_u64(tmp, tmp);
}
// CHECK-LABEL: test_vmovq_n_s64
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
int64x2_t test_vmovq_n_s64(int64_t a) {
return vmovq_n_s64(a);
}
// CHECK-LABEL: test_vmovq_n_u64
-// CHECK: vmov
+// CHECK: vmov {{r[0-9]+}}
uint64x2_t test_vmovq_n_u64(uint64_t a) {
return vmovq_n_u64(a);
}
@@ -9056,7 +9116,7 @@ uint16x4_t test_vset_lane_u16(uint16_t a, uint16x4_t b) {
}
// CHECK-LABEL: test_vset_lane_u32
-// CHECK: vmov
+// CHECK: mov
uint32x2_t test_vset_lane_u32(uint32_t a, uint32x2_t b) {
return vset_lane_u32(a, b, 1);
}
@@ -9074,7 +9134,7 @@ int16x4_t test_vset_lane_s16(int16_t a, int16x4_t b) {
}
// CHECK-LABEL: test_vset_lane_s32
-// CHECK: vmov
+// CHECK: mov
int32x2_t test_vset_lane_s32(int32_t a, int32x2_t b) {
return vset_lane_s32(a, b, 1);
}
@@ -9092,7 +9152,7 @@ poly16x4_t test_vset_lane_p16(poly16_t a, poly16x4_t b) {
}
// CHECK-LABEL: test_vset_lane_f32
-// CHECK: vmov
+// CHECK: mov
float32x2_t test_vset_lane_f32(float32_t a, float32x2_t b) {
return vset_lane_f32(a, b, 1);
}
@@ -9152,13 +9212,13 @@ float32x4_t test_vsetq_lane_f32(float32_t a, float32x4_t b) {
}
// CHECK-LABEL: test_vset_lane_s64
-// CHECK: vmov
+// The optimizer is able to get rid of all moves now.
int64x1_t test_vset_lane_s64(int64_t a, int64x1_t b) {
return vset_lane_s64(a, b, 0);
}
// CHECK-LABEL: test_vset_lane_u64
-// CHECK: vmov
+// The optimizer is able to get rid of all moves now.
uint64x1_t test_vset_lane_u64(uint64_t a, uint64x1_t b) {
return vset_lane_u64(a, b, 0);
}
diff --git a/test/CodeGen/asan-globals.cpp b/test/CodeGen/asan-globals.cpp
index d9ecc6461542..20c1fa702a86 100644
--- a/test/CodeGen/asan-globals.cpp
+++ b/test/CodeGen/asan-globals.cpp
@@ -1,36 +1,37 @@
+// RUN: echo "int extra_global;" > %t.extra-source.cpp
// RUN: echo "global:*blacklisted_global*" > %t.blacklist
-// RUN: %clang_cc1 -fsanitize=address -fsanitize-blacklist=%t.blacklist -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.blacklist -emit-llvm -o - %s | FileCheck %s
// RUN: echo "src:%s" > %t.blacklist-src
-// RUN: %clang_cc1 -fsanitize=address -fsanitize-blacklist=%t.blacklist-src -emit-llvm -o - %s | FileCheck %s --check-prefix=BLACKLIST-SRC
+// RUN: %clang_cc1 -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.blacklist-src -emit-llvm -o - %s | FileCheck %s --check-prefix=BLACKLIST-SRC
// REQUIRES: shell
int global;
-// CHECK: [[GLOBAL_LOC:@.asan_loc_descr[0-9]*]] = private unnamed_addr constant {{.*}} i32 [[@LINE-1]], i32 5
-// CHECK: [[GLOBAL_NAME:@.str[0-9]+]] = private unnamed_addr constant {{.*}} c"global\00"
int dyn_init_global = global;
-// CHECK: [[DYN_INIT_LOC:@.asan_loc_descr[0-9]*]] = {{.*}} i32 [[@LINE-1]], i32 5
-// CHECK: [[DYN_INIT_NAME:@.str[0-9]+]] = private unnamed_addr constant {{.*}} c"dyn_init_global\00"
int blacklisted_global;
void func() {
static int static_var = 0;
- // CHECK: [[STATIC_LOC:@.asan_loc_descr[0-9]*]] = {{.*}} i32 [[@LINE-1]], i32 14
- // CHECK: [[STATIC_NAME:@.str[0-9]+]] = private unnamed_addr constant {{.*}} c"static_var\00"
const char *literal = "Hello, world!";
- // CHECK: [[LITERAL_LOC:@.asan_loc_descr[0-9]*]] = {{.*}} i32 [[@LINE-1]], i32 25
- // CHECK: [[LITERAL_NAME:@.str[0-9]+]] = private unnamed_addr constant {{.*}} c"<string literal>\00"
}
-// CHECK: !llvm.asan.globals = !{![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[BLACKLISTED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]}
-// CHECK: ![[GLOBAL]] = metadata !{{{.*}} [[GLOBAL_LOC]], {{.*}} [[GLOBAL_NAME]], i1 false, i1 false}
-// CHECK: ![[DYN_INIT_GLOBAL]] = metadata !{{{.*}} [[DYN_INIT_LOC]], {{.*}} [[DYN_INIT_NAME]], i1 true, i1 false}
-// CHECK: ![[BLACKLISTED_GLOBAL]] = metadata !{{{.*}}, null, null, i1 false, i1 true}
-// CHECK: ![[STATIC_VAR]] = metadata !{{{.*}} [[STATIC_LOC]], {{.*}} [[STATIC_NAME]], i1 false, i1 false}
-// CHECK: ![[LITERAL]] = metadata !{{{.*}} [[LITERAL_LOC]], {{.*}} [[LITERAL_NAME]], i1 false, i1 false}
+// CHECK: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[BLACKLISTED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]}
+// CHECK: ![[EXTRA_GLOBAL]] = !{{{.*}} ![[EXTRA_GLOBAL_LOC:[0-9]+]], !"extra_global", i1 false, i1 false}
+// CHECK: ![[EXTRA_GLOBAL_LOC]] = !{!"{{.*}}extra-source.cpp", i32 1, i32 5}
+// CHECK: ![[GLOBAL]] = !{{{.*}} ![[GLOBAL_LOC:[0-9]+]], !"global", i1 false, i1 false}
+// CHECK: ![[GLOBAL_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 8, i32 5}
+// CHECK: ![[DYN_INIT_GLOBAL]] = !{{{.*}} ![[DYN_INIT_LOC:[0-9]+]], !"dyn_init_global", i1 true, i1 false}
+// CHECK: ![[DYN_INIT_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 9, i32 5}
+// CHECK: ![[BLACKLISTED_GLOBAL]] = !{{{.*}}, null, null, i1 false, i1 true}
+// CHECK: ![[STATIC_VAR]] = !{{{.*}} ![[STATIC_LOC:[0-9]+]], !"static_var", i1 false, i1 false}
+// CHECK: ![[STATIC_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 13, i32 14}
+// CHECK: ![[LITERAL]] = !{{{.*}} ![[LITERAL_LOC:[0-9]+]], !"<string literal>", i1 false, i1 false}
+// CHECK: ![[LITERAL_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 14, i32 25}
-// BLACKLIST-SRC: !llvm.asan.globals = !{![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[BLACKLISTED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]}
-// BLACKLIST-SRC: ![[GLOBAL]] = metadata !{{{.*}} null, null, i1 false, i1 true}
-// BLACKLIST-SRC: ![[DYN_INIT_GLOBAL]] = metadata !{{{.*}} null, null, i1 true, i1 true}
-// BLACKLIST-SRC: ![[BLACKLISTED_GLOBAL]] = metadata !{{{.*}}, null, null, i1 false, i1 true}
-// BLACKLIST-SRC: ![[STATIC_VAR]] = metadata !{{{.*}} null, null, i1 false, i1 true}
-// BLACKLIST-SRC: ![[LITERAL]] = metadata !{{{.*}} null, null, i1 false, i1 true}
+// BLACKLIST-SRC: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[BLACKLISTED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]}
+// BLACKLIST-SRC: ![[EXTRA_GLOBAL]] = !{{{.*}} ![[EXTRA_GLOBAL_LOC:[0-9]+]], !"extra_global", i1 false, i1 false}
+// BLACKLIST-SRC: ![[EXTRA_GLOBAL_LOC]] = !{!"{{.*}}extra-source.cpp", i32 1, i32 5}
+// BLACKLIST-SRC: ![[GLOBAL]] = !{{{.*}} null, null, i1 false, i1 true}
+// BLACKLIST-SRC: ![[DYN_INIT_GLOBAL]] = !{{{.*}} null, null, i1 true, i1 true}
+// BLACKLIST-SRC: ![[BLACKLISTED_GLOBAL]] = !{{{.*}}, null, null, i1 false, i1 true}
+// BLACKLIST-SRC: ![[STATIC_VAR]] = !{{{.*}} null, null, i1 false, i1 true}
+// BLACKLIST-SRC: ![[LITERAL]] = !{{{.*}} null, null, i1 false, i1 true}
diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c
index 5dbc01b1211d..038d346e9993 100644
--- a/test/CodeGen/asm.c
+++ b/test/CodeGen/asm.c
@@ -248,3 +248,17 @@ void t29(void) {
// CHECK: @t29
// CHECK: call void asm sideeffect "movl %eax, $0", "*m,~{dirflag},~{fpsr},~{flags}"([1 x i32]* @t29_var)
}
+
+void t30(int len) {
+ __asm__ volatile(""
+ : "+&&rm"(len));
+ // CHECK: @t30
+ // CHECK: call void asm sideeffect "", "=*&rm,0,~{dirflag},~{fpsr},~{flags}"
+}
+
+void t31(int len) {
+ __asm__ volatile(""
+ : "+%%rm"(len), "+rm"(len));
+ // CHECK: @t31
+ // CHECK: call void asm sideeffect "", "=*%rm,=*rm,0,1,~{dirflag},~{fpsr},~{flags}"
+}
diff --git a/test/CodeGen/atomic-ops-libcall.c b/test/CodeGen/atomic-ops-libcall.c
index 2a2ff5e80fcf..e55a1bd1eae3 100644
--- a/test/CodeGen/atomic-ops-libcall.c
+++ b/test/CodeGen/atomic-ops-libcall.c
@@ -7,31 +7,31 @@ enum memory_order {
int *test_c11_atomic_fetch_add_int_ptr(_Atomic(int *) *p) {
// CHECK: test_c11_atomic_fetch_add_int_ptr
- // CHECK: {{%[^ ]*}} = tail call i32* @__atomic_fetch_add_4(i8* {{%[0-9]+}}, i32 12, i32 5)
+ // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_add_4(i8* {{%[0-9]+}}, i32 12, i32 5)
return __c11_atomic_fetch_add(p, 3, memory_order_seq_cst);
}
int *test_c11_atomic_fetch_sub_int_ptr(_Atomic(int *) *p) {
// CHECK: test_c11_atomic_fetch_sub_int_ptr
- // CHECK: {{%[^ ]*}} = tail call i32* @__atomic_fetch_sub_4(i8* {{%[0-9]+}}, i32 20, i32 5)
+ // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_sub_4(i8* {{%[0-9]+}}, i32 20, i32 5)
return __c11_atomic_fetch_sub(p, 5, memory_order_seq_cst);
}
int test_c11_atomic_fetch_add_int(_Atomic(int) *p) {
// CHECK: test_c11_atomic_fetch_add_int
- // CHECK: {{%[^ ]*}} = tail call i32 bitcast (i32* (i8*, i32, i32)* @__atomic_fetch_add_4 to i32 (i8*, i32, i32)*)(i8* {{%[0-9]+}}, i32 3, i32 5)
+ // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_add_4(i8* {{%[0-9]+}}, i32 3, i32 5)
return __c11_atomic_fetch_add(p, 3, memory_order_seq_cst);
}
int test_c11_atomic_fetch_sub_int(_Atomic(int) *p) {
// CHECK: test_c11_atomic_fetch_sub_int
- // CHECK: {{%[^ ]*}} = tail call i32 bitcast (i32* (i8*, i32, i32)* @__atomic_fetch_sub_4 to i32 (i8*, i32, i32)*)(i8* {{%[0-9]+}}, i32 5, i32 5)
+ // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_sub_4(i8* {{%[0-9]+}}, i32 5, i32 5)
return __c11_atomic_fetch_sub(p, 5, memory_order_seq_cst);
}
int *fp2a(int **p) {
// CHECK: @fp2a
- // CHECK: {{%[^ ]*}} = tail call i32* @__atomic_fetch_sub_4(i8* {{%[0-9]+}}, i32 4, i32 0)
+ // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_sub_4(i8* {{%[0-9]+}}, i32 4, i32 0)
// Note, the GNU builtins do not multiply by sizeof(T)!
return __atomic_fetch_sub(p, 4, memory_order_relaxed);
}
diff --git a/test/CodeGen/atomic-ops.c b/test/CodeGen/atomic-ops.c
index 9e6b4805e8cb..559b13541323 100644
--- a/test/CodeGen/atomic-ops.c
+++ b/test/CodeGen/atomic-ops.c
@@ -1,18 +1,15 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -ffreestanding -triple=i686-apple-darwin9 | FileCheck %s
// Also test serialization of atomic operations here, to avoid duplicating the
// test.
-// RUN: %clang_cc1 %s -emit-pch -o %t -triple=i686-apple-darwin9
-// RUN: %clang_cc1 %s -include-pch %t -triple=i686-apple-darwin9 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-pch -o %t -ffreestanding -triple=i686-apple-darwin9
+// RUN: %clang_cc1 %s -include-pch %t -ffreestanding -triple=i686-apple-darwin9 -emit-llvm -o - | FileCheck %s
#ifndef ALREADY_INCLUDED
#define ALREADY_INCLUDED
-// Basic IRGen tests for __c11_atomic_* and GNU __atomic_*
+#include <stdatomic.h>
-typedef enum memory_order {
- memory_order_relaxed, memory_order_consume, memory_order_acquire,
- memory_order_release, memory_order_acq_rel, memory_order_seq_cst
-} memory_order;
+// Basic IRGen tests for __c11_atomic_* and GNU __atomic_*
int fi1(_Atomic(int) *i) {
// CHECK-LABEL: @fi1
@@ -34,6 +31,12 @@ int fi1b(int *i) {
return __atomic_load_n(i, memory_order_seq_cst);
}
+int fi1c(atomic_int *i) {
+ // CHECK-LABEL: @fi1c
+ // CHECK: load atomic i32* {{.*}} seq_cst
+ return atomic_load(i);
+}
+
void fi2(_Atomic(int) *i) {
// CHECK-LABEL: @fi2
// CHECK: store atomic i32 {{.*}} seq_cst
@@ -53,6 +56,12 @@ void fi2b(int *i) {
__atomic_store_n(i, 1, memory_order_seq_cst);
}
+void fi2c(atomic_int *i) {
+ // CHECK-LABEL: @fi2c
+ // CHECK: store atomic i32 {{.*}} seq_cst
+ atomic_store(i, 1);
+}
+
int fi3(_Atomic(int) *i) {
// CHECK-LABEL: @fi3
// CHECK: atomicrmw and
@@ -89,8 +98,15 @@ int fi3d(int *i) {
return __atomic_nand_fetch(i, 1, memory_order_seq_cst);
}
+int fi3e(atomic_int *i) {
+ // CHECK-LABEL: @fi3e
+ // CHECK: atomicrmw or
+ // CHECK-NOT: {{ or }}
+ return atomic_fetch_or(i, 1);
+}
+
_Bool fi4(_Atomic(int) *i) {
- // CHECK-LABEL: @fi4
+ // CHECK-LABEL: @fi4(
// CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]]
// CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0
// CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1
@@ -101,7 +117,7 @@ _Bool fi4(_Atomic(int) *i) {
}
_Bool fi4a(int *i) {
- // CHECK-LABEL: @fi4
+ // CHECK-LABEL: @fi4a
// CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]]
// CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0
// CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1
@@ -113,7 +129,7 @@ _Bool fi4a(int *i) {
}
_Bool fi4b(int *i) {
- // CHECK-LABEL: @fi4
+ // CHECK-LABEL: @fi4b(
// CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg weak i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]]
// CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0
// CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1
@@ -123,6 +139,13 @@ _Bool fi4b(int *i) {
return __atomic_compare_exchange_n(i, &cmp, 1, 1, memory_order_acquire, memory_order_acquire);
}
+_Bool fi4c(atomic_int *i) {
+ // CHECK-LABEL: @fi4c
+ // CHECK: cmpxchg i32*
+ int cmp = 0;
+ return atomic_compare_exchange_strong(i, &cmp, 1);
+}
+
float ff1(_Atomic(float) *d) {
// CHECK-LABEL: @ff1
// CHECK: load atomic i32* {{.*}} monotonic
@@ -139,6 +162,79 @@ float ff3(_Atomic(float) *d) {
return __c11_atomic_exchange(d, 2, memory_order_seq_cst);
}
+struct S {
+ double x;
+};
+
+struct S fd1(struct S *a) {
+ // CHECK-LABEL: @fd1
+ // CHECK: [[RETVAL:%.*]] = alloca %struct.S, align 4
+ // CHECK: [[RET:%.*]] = alloca %struct.S, align 4
+ // CHECK: [[CALL:%.*]] = call i64 @__atomic_load_8(
+ // CHECK: [[CAST:%.*]] = bitcast %struct.S* [[RET]] to i64*
+ // CHECK: store i64 [[CALL]], i64* [[CAST]], align 4
+ struct S ret;
+ __atomic_load(a, &ret, memory_order_seq_cst);
+ return ret;
+}
+
+void fd2(struct S *a, struct S *b) {
+ // CHECK-LABEL: @fd2
+ // CHECK: [[A_ADDR:%.*]] = alloca %struct.S*, align 4
+ // CHECK-NEXT: [[B_ADDR:%.*]] = alloca %struct.S*, align 4
+ // CHECK-NEXT: store %struct.S* %a, %struct.S** [[A_ADDR]], align 4
+ // CHECK-NEXT: store %struct.S* %b, %struct.S** [[B_ADDR]], align 4
+ // CHECK-NEXT: [[LOAD_A_PTR:%.*]] = load %struct.S** [[A_ADDR]], align 4
+ // CHECK-NEXT: [[LOAD_B_PTR:%.*]] = load %struct.S** [[B_ADDR]], align 4
+ // CHECK-NEXT: [[COERCED_A:%.*]] = bitcast %struct.S* [[LOAD_A_PTR]] to i8*
+ // CHECK-NEXT: [[COERCED_B:%.*]] = bitcast %struct.S* [[LOAD_B_PTR]] to i64*
+ // CHECK-NEXT: [[LOAD_B:%.*]] = load i64* [[COERCED_B]], align 4
+ // CHECK-NEXT: call void @__atomic_store_8(i8* [[COERCED_A]], i64 [[LOAD_B]],
+ // CHECK-NEXT: ret void
+ __atomic_store(a, b, memory_order_seq_cst);
+}
+
+void fd3(struct S *a, struct S *b, struct S *c) {
+ // CHECK-LABEL: @fd3
+ // CHECK: [[A_ADDR:%.*]] = alloca %struct.S*, align 4
+ // CHECK-NEXT: [[B_ADDR:%.*]] = alloca %struct.S*, align 4
+ // CHECK-NEXT: [[C_ADDR:%.*]] = alloca %struct.S*, align 4
+ // CHECK-NEXT: store %struct.S* %a, %struct.S** [[A_ADDR]], align 4
+ // CHECK-NEXT: store %struct.S* %b, %struct.S** [[B_ADDR]], align 4
+ // CHECK-NEXT: store %struct.S* %c, %struct.S** [[C_ADDR]], align 4
+ // CHECK-NEXT: [[LOAD_A_PTR:%.*]] = load %struct.S** [[A_ADDR]], align 4
+ // CHECK-NEXT: [[LOAD_B_PTR:%.*]] = load %struct.S** [[B_ADDR]], align 4
+ // CHECK-NEXT: [[LOAD_C_PTR:%.*]] = load %struct.S** [[C_ADDR]], align 4
+ // CHECK-NEXT: [[COERCED_A:%.*]] = bitcast %struct.S* [[LOAD_A_PTR]] to i8*
+ // CHECK-NEXT: [[COERCED_B:%.*]] = bitcast %struct.S* [[LOAD_B_PTR]] to i64*
+ // CHECK-NEXT: [[LOAD_B:%.*]] = load i64* [[COERCED_B]], align 4
+ // CHECK-NEXT: [[CALL:%.*]] = call i64 @__atomic_exchange_8(i8* [[COERCED_A]], i64 [[LOAD_B]],
+ // CHECK-NEXT: [[COERCED_C:%.*]] = bitcast %struct.S* [[LOAD_C_PTR]] to i64*
+ // CHECK-NEXT: store i64 [[CALL]], i64* [[COERCED_C]], align 4
+
+ __atomic_exchange(a, b, c, memory_order_seq_cst);
+}
+
+_Bool fd4(struct S *a, struct S *b, struct S *c) {
+ // CHECK-LABEL: @fd4
+ // CHECK: [[A_ADDR:%.*]] = alloca %struct.S*, align 4
+ // CHECK-NEXT: [[B_ADDR:%.*]] = alloca %struct.S*, align 4
+ // CHECK-NEXT: [[C_ADDR:%.*]] = alloca %struct.S*, align 4
+ // CHECK: store %struct.S* %a, %struct.S** [[A_ADDR]], align 4
+ // CHECK-NEXT: store %struct.S* %b, %struct.S** [[B_ADDR]], align 4
+ // CHECK-NEXT: store %struct.S* %c, %struct.S** [[C_ADDR]], align 4
+ // CHECK-NEXT: [[LOAD_A_PTR:%.*]] = load %struct.S** [[A_ADDR]], align 4
+ // CHECK-NEXT: [[LOAD_B_PTR:%.*]] = load %struct.S** [[B_ADDR]], align 4
+ // CHECK-NEXT: [[LOAD_C_PTR:%.*]] = load %struct.S** [[C_ADDR]], align 4
+ // CHECK-NEXT: [[COERCED_A:%.*]] = bitcast %struct.S* [[LOAD_A_PTR]] to i8*
+ // CHECK-NEXT: [[COERCED_B:%.*]] = bitcast %struct.S* [[LOAD_B_PTR]] to i8*
+ // CHECK-NEXT: [[COERCED_C:%.*]] = bitcast %struct.S* [[LOAD_C_PTR]] to i64*
+ // CHECK-NEXT: [[LOAD_C:%.*]] = load i64* [[COERCED_C]], align 4
+ // CHECK-NEXT: [[CALL:%.*]] = call zeroext i1 @__atomic_compare_exchange_8(i8* [[COERCED_A]], i8* [[COERCED_B]], i64 [[LOAD_C]]
+ // CHECK-NEXT: ret i1 [[CALL]]
+ return __atomic_compare_exchange(a, b, c, 1, 5, 5);
+}
+
int* fp1(_Atomic(int*) *p) {
// CHECK-LABEL: @fp1
// CHECK: load atomic i32* {{.*}} seq_cst
@@ -287,14 +383,23 @@ struct foo structAtomicExchange() {
}
int structAtomicCmpExchange() {
// CHECK-LABEL: @structAtomicCmpExchange
+ // CHECK: %[[x_mem:.*]] = alloca i8
_Bool x = __atomic_compare_exchange(&smallThing, &thing1, &thing2, 1, 5, 5);
- // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 3, {{.*}} @smallThing{{.*}} @thing1{{.*}} @thing2
+ // CHECK: %[[call1:.*]] = call zeroext i1 @__atomic_compare_exchange(i32 3, {{.*}} @smallThing{{.*}} @thing1{{.*}} @thing2
+ // CHECK: %[[zext1:.*]] = zext i1 %[[call1]] to i8
+ // CHECK: store i8 %[[zext1]], i8* %[[x_mem]], align 1
+ // CHECK: %[[x:.*]] = load i8* %[[x_mem]]
+ // CHECK: %[[x_bool:.*]] = trunc i8 %[[x]] to i1
+ // CHECK: %[[conv1:.*]] = zext i1 %[[x_bool]] to i32
struct foo f = {0};
struct foo g = {0};
g.big[12] = 12;
return x & __c11_atomic_compare_exchange_strong(&bigAtomic, &f, g, 5, 5);
- // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+ // CHECK: %[[call2:.*]] = call zeroext i1 @__atomic_compare_exchange(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+ // CHECK: %[[conv2:.*]] = zext i1 %[[call2]] to i32
+ // CHECK: %[[and:.*]] = and i32 %[[conv1]], %[[conv2]]
+ // CHECK: ret i32 %[[and]]
}
// Check that no atomic operations are used in any initialisation of _Atomic
@@ -447,4 +552,51 @@ void EMIT_ALL_THE_THINGS(int *ptr, int *ptr2, int new, _Bool weak, int success,
// CHECK: = cmpxchg weak {{.*}} seq_cst seq_cst
}
+int PR21643() {
+ return __atomic_or_fetch((int __attribute__((address_space(257))) *)0x308, 1,
+ __ATOMIC_RELAXED);
+ // CHECK: %[[atomictmp:.*]] = alloca i32, align 4
+ // CHECK: %[[atomicdst:.*]] = alloca i32, align 4
+ // CHECK: store i32 1, i32* %[[atomictmp]]
+ // CHECK: %[[one:.*]] = load i32* %[[atomictmp]], align 4
+ // CHECK: %[[old:.*]] = atomicrmw or i32 addrspace(257)* inttoptr (i32 776 to i32 addrspace(257)*), i32 %[[one]] monotonic
+ // CHECK: %[[new:.*]] = or i32 %[[old]], %[[one]]
+ // CHECK: store i32 %[[new]], i32* %[[atomicdst]], align 4
+ // CHECK: %[[ret:.*]] = load i32* %[[atomicdst]], align 4
+ // CHECK: ret i32 %[[ret]]
+}
+
+int PR17306_1(volatile _Atomic(int) *i) {
+ // CHECK-LABEL: @PR17306_1
+ // CHECK: %[[i_addr:.*]] = alloca i32
+ // CHECK-NEXT: %[[atomicdst:.*]] = alloca i32
+ // CHECK-NEXT: store i32* %i, i32** %[[i_addr]]
+ // CHECK-NEXT: %[[addr:.*]] = load i32** %[[i_addr]]
+ // CHECK-NEXT: %[[res:.*]] = load atomic volatile i32* %[[addr]] seq_cst
+ // CHECK-NEXT: store i32 %[[res]], i32* %[[atomicdst]]
+ // CHECK-NEXT: %[[retval:.*]] = load i32* %[[atomicdst]]
+ // CHECK-NEXT: ret i32 %[[retval]]
+ return __c11_atomic_load(i, memory_order_seq_cst);
+}
+
+int PR17306_2(volatile int *i, int value) {
+ // CHECK-LABEL: @PR17306_2
+ // CHECK: %[[i_addr:.*]] = alloca i32*
+ // CHECK-NEXT: %[[value_addr:.*]] = alloca i32
+ // CHECK-NEXT: %[[atomictmp:.*]] = alloca i32
+ // CHECK-NEXT: %[[atomicdst:.*]] = alloca i32
+ // CHECK-NEXT: store i32* %i, i32** %[[i_addr]]
+ // CHECK-NEXT: store i32 %value, i32* %[[value_addr]]
+ // CHECK-NEXT: %[[i_lval:.*]] = load i32** %[[i_addr]]
+ // CHECK-NEXT: %[[value:.*]] = load i32* %[[value_addr]]
+ // CHECK-NEXT: store i32 %[[value]], i32* %[[atomictmp]]
+ // CHECK-NEXT: %[[value_lval:.*]] = load i32* %[[atomictmp]]
+ // CHECK-NEXT: %[[old_val:.*]] = atomicrmw volatile add i32* %[[i_lval]], i32 %[[value_lval]] seq_cst
+ // CHECK-NEXT: %[[new_val:.*]] = add i32 %[[old_val]], %[[value_lval]]
+ // CHECK-NEXT: store i32 %[[new_val]], i32* %[[atomicdst]]
+ // CHECK-NEXT: %[[retval:.*]] = load i32* %[[atomicdst]]
+ // CHECK-NEXT: ret i32 %[[retval]]
+ return __atomic_add_fetch(i, value, memory_order_seq_cst);
+}
+
#endif
diff --git a/test/CodeGen/atomic.c b/test/CodeGen/atomic.c
index 43f5bc81ee98..4db3c8e6d69c 100644
--- a/test/CodeGen/atomic.c
+++ b/test/CodeGen/atomic.c
@@ -50,7 +50,10 @@ int atomic(void) {
old = __sync_fetch_and_xor(&val, 0xb);
// CHECK: atomicrmw xor i32* %val, i32 11 seq_cst
-
+
+ old = __sync_fetch_and_nand(&val, 0xc);
+ // CHECK: atomicrmw nand i32* %val, i32 12 seq_cst
+
old = __sync_add_and_fetch(&val, 1);
// CHECK: atomicrmw add i32* %val, i32 1 seq_cst
@@ -65,7 +68,10 @@ int atomic(void) {
old = __sync_xor_and_fetch(&valc, 5);
// CHECK: atomicrmw xor i8* %valc, i8 5 seq_cst
-
+
+ old = __sync_nand_and_fetch(&valc, 6);
+ // CHECK: atomicrmw nand i8* %valc, i8 6 seq_cst
+
__sync_val_compare_and_swap((void **)0, (void *)0, (void *)0);
// CHECK: [[PAIR:%[a-z0-9_.]+]] = cmpxchg i32* null, i32 0, i32 0 seq_cst
// CHECK: extractvalue { i32, i1 } [[PAIR]], 0
diff --git a/test/CodeGen/atomic_ops.c b/test/CodeGen/atomic_ops.c
index 910e9b950506..29009bef894c 100644
--- a/test/CodeGen/atomic_ops.c
+++ b/test/CodeGen/atomic_ops.c
@@ -7,12 +7,12 @@ void foo(int x)
// Check that multiply / divides on atomics produce a cmpxchg loop
i *= 2;
// CHECK: mul nsw i32
- // CHECK: cmpxchg i32*
+ // CHECK: {{(cmpxchg i32*|i1 @__atomic_compare_exchange\(i32 4,)}}
i /= 2;
// CHECK: sdiv i32
- // CHECK: cmpxchg i32*
+ // CHECK: {{(cmpxchg i32*|i1 @__atomic_compare_exchange\(i32 4, )}}
j /= x;
// CHECK: sdiv i32
- // CHECK: cmpxchg i16*
+ // CHECK: {{(cmpxchg i16*|i1 @__atomic_compare_exchange\(i32 2, )}}
}
diff --git a/test/CodeGen/atomics-inlining.c b/test/CodeGen/atomics-inlining.c
index ec916e1b5eef..9cd280294f38 100644
--- a/test/CodeGen/atomics-inlining.c
+++ b/test/CodeGen/atomics-inlining.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=ARM
+// RUN: %clang_cc1 -triple arm-linux-gnueabi -emit-llvm %s -o - | FileCheck %s -check-prefix=ARM
// RUN: %clang_cc1 -triple powerpc-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=PPC32
// RUN: %clang_cc1 -triple powerpc64-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=PPC64
// RUN: %clang_cc1 -triple mipsel-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=MIPS32
@@ -31,17 +31,17 @@ void test1(void) {
(void)__atomic_load(&a1, &a2, memory_order_seq_cst);
(void)__atomic_store(&a1, &a2, memory_order_seq_cst);
-// ARM-LABEL: define arm_aapcscc void @test1
-// ARM: = call arm_aapcscc zeroext i8 @__atomic_load_1(i8* @c1
-// ARM: call arm_aapcscc void @__atomic_store_1(i8* @c1, i8 zeroext
-// ARM: = call arm_aapcscc zeroext i16 @__atomic_load_2(i8* bitcast (i16* @s1 to i8*)
-// ARM: call arm_aapcscc void @__atomic_store_2(i8* bitcast (i16* @s1 to i8*), i16 zeroext
-// ARM: = call arm_aapcscc i32 @__atomic_load_4(i8* bitcast (i32* @i1 to i8*)
-// ARM: call arm_aapcscc void @__atomic_store_4(i8* bitcast (i32* @i1 to i8*), i32
-// ARM: = call arm_aapcscc i64 @__atomic_load_8(i8* bitcast (i64* @ll1 to i8*)
-// ARM: call arm_aapcscc void @__atomic_store_8(i8* bitcast (i64* @ll1 to i8*), i64
-// ARM: call arm_aapcscc void @__atomic_load(i32 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
-// ARM: call arm_aapcscc void @__atomic_store(i32 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
+// ARM-LABEL: define{{.*}} void @test1
+// ARM: = call{{.*}} zeroext i8 @__atomic_load_1(i8* @c1
+// ARM: call{{.*}} void @__atomic_store_1(i8* @c1, i8 zeroext
+// ARM: = call{{.*}} zeroext i16 @__atomic_load_2(i8* bitcast (i16* @s1 to i8*)
+// ARM: call{{.*}} void @__atomic_store_2(i8* bitcast (i16* @s1 to i8*), i16 zeroext
+// ARM: = call{{.*}} i32 @__atomic_load_4(i8* bitcast (i32* @i1 to i8*)
+// ARM: call{{.*}} void @__atomic_store_4(i8* bitcast (i32* @i1 to i8*), i32
+// ARM: = call{{.*}} i64 @__atomic_load_8(i8* bitcast (i64* @ll1 to i8*)
+// ARM: call{{.*}} void @__atomic_store_8(i8* bitcast (i64* @ll1 to i8*), i64
+// ARM: call{{.*}} void @__atomic_load(i32 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
+// ARM: call{{.*}} void @__atomic_store(i32 100, i8* getelementptr inbounds ([100 x i8]* @a1, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8]* @a2, i32 0, i32 0)
// PPC32-LABEL: define void @test1
// PPC32: = load atomic i8* @c1 seq_cst
diff --git a/test/CodeGen/attr-naked.c b/test/CodeGen/attr-naked.c
index c07dd8d3732a..270fc7959f44 100644
--- a/test/CodeGen/attr-naked.c
+++ b/test/CodeGen/attr-naked.c
@@ -12,7 +12,15 @@ void t1()
// Make sure this doesn't explode in the verifier.
// (It doesn't really make sense, but it isn't invalid.)
// CHECK: define void @t2() [[NAKED]] {
-__attribute((naked, always_inline)) void t2() {
+__attribute((naked, always_inline)) void t2() {
+}
+
+// Make sure not to generate prolog or epilog for naked functions.
+__attribute((naked)) void t3(int x) {
+// CHECK: define void @t3(i32)
+// CHECK-NOT: alloca
+// CHECK-NOT: store
+// CHECK: unreachable
}
// CHECK: attributes [[NAKED]] = { naked noinline nounwind{{.*}} }
diff --git a/test/CodeGen/attr-optnone.c b/test/CodeGen/attr-optnone.c
index e7069b10f21a..96493bfe3613 100644
--- a/test/CodeGen/attr-optnone.c
+++ b/test/CodeGen/attr-optnone.c
@@ -1,12 +1,19 @@
// RUN: %clang_cc1 -emit-llvm < %s > %t
// RUN: FileCheck %s --check-prefix=PRESENT < %t
// RUN: FileCheck %s --check-prefix=ABSENT < %t
+// RUN: %clang_cc1 -emit-llvm -Os < %s > %t
+// RUN: FileCheck %s --check-prefix=PRESENT < %t
+// RUN: FileCheck %s --check-prefix=OPTSIZE < %t
+// RUN: %clang_cc1 -emit-llvm -Oz < %s > %t
+// RUN: FileCheck %s --check-prefix=PRESENT < %t
+// RUN: FileCheck %s --check-prefix=MINSIZE < %t
__attribute__((always_inline))
int test2() { return 0; }
-// PRESENT-DAG: @test2{{.*}}[[ATTR2:#[0-9]+]]
+// OPTSIZE: @test2{{.*}}[[ATTR2:#[0-9]+]]
+// MINSIZE: @test2{{.*}}[[ATTR2:#[0-9]+]]
-__attribute__((optnone)) __attribute__((minsize))
+__attribute__((optnone))
int test3() { return 0; }
// PRESENT-DAG: @test3{{.*}}[[ATTR3:#[0-9]+]]
@@ -23,3 +30,13 @@ int test4() { return test2(); }
// Check that no 'optsize' or 'minsize' attributes appear.
// ABSENT-NOT: optsize
// ABSENT-NOT: minsize
+
+// With -Os, check that 'optsize' appears only on test2.
+// OPTSIZE-NOT: optsize
+// OPTSIZE: attributes [[ATTR2]] = { {{.*}}optsize{{.*}} }
+// OPTSIZE-NOT: optsize
+
+// With -Oz, check that 'minsize' appears only on test2.
+// MINSIZE-NOT: minsize
+// MINSIZE: attributes [[ATTR2]] = { {{.*}}minsize{{.*}} }
+// MINSIZE-NOT: minsize
diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c
index 356a17996a88..5c9c90d7cee4 100644
--- a/test/CodeGen/attributes.c
+++ b/test/CodeGen/attributes.c
@@ -26,7 +26,7 @@ int t6 __attribute__((visibility("protected")));
// CHECK: @t12 = global i32 0, section "SECT"
int t12 __attribute__((section("SECT")));
-// CHECK: @t9 = alias weak bitcast (void ()* @__t8 to void (...)*)
+// CHECK: @t9 = weak alias bitcast (void ()* @__t8 to void (...)*)
void __t8() {}
void t9() __attribute__((weak, alias("__t8")));
diff --git a/test/CodeGen/avx2-builtins.c b/test/CodeGen/avx2-builtins.c
index 10c3a1b726a1..04825ffa2f60 100644
--- a/test/CodeGen/avx2-builtins.c
+++ b/test/CodeGen/avx2-builtins.c
@@ -6,7 +6,7 @@
#include <immintrin.h>
__m256i test_mm256_mpsadbw_epu8(__m256i x, __m256i y) {
- // CHECK: @llvm.x86.avx2.mpsadbw({{.*}}, {{.*}}, i32 3)
+ // CHECK: @llvm.x86.avx2.mpsadbw({{.*}}, {{.*}}, i8 3)
return _mm256_mpsadbw_epu8(x, y, 3);
}
diff --git a/test/CodeGen/avx512bw-builtins.c b/test/CodeGen/avx512bw-builtins.c
new file mode 100644
index 000000000000..ada84657a607
--- /dev/null
+++ b/test/CodeGen/avx512bw-builtins.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -O0 -triple=x86_64-apple-darwin -ffreestanding -target-feature +avx512bw -emit-llvm -o - -Werror | FileCheck %s
+
+#include <immintrin.h>
+
+__mmask64 test_mm512_cmpeq_epi8_mask(__m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_cmpeq_epi8_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.b.512
+ return (__mmask64)_mm512_cmpeq_epi8_mask(__a, __b);
+}
+
+__mmask64 test_mm512_mask_cmpeq_epi8_mask(__mmask64 __u, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_mask_cmpeq_epi8_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.b.512
+ return (__mmask64)_mm512_mask_cmpeq_epi8_mask(__u, __a, __b);
+}
+
+__mmask32 test_mm512_cmpeq_epi16_mask(__m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_cmpeq_epi16_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.w.512
+ return (__mmask32)_mm512_cmpeq_epi16_mask(__a, __b);
+}
+
+__mmask32 test_mm512_mask_cmpeq_epi16_mask(__mmask32 __u, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_mask_cmpeq_epi16_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.w.512
+ return (__mmask32)_mm512_mask_cmpeq_epi16_mask(__u, __a, __b);
+}
diff --git a/test/CodeGen/avx512f-builtins.c b/test/CodeGen/avx512f-builtins.c
new file mode 100644
index 000000000000..8bb013fef731
--- /dev/null
+++ b/test/CodeGen/avx512f-builtins.c
@@ -0,0 +1,212 @@
+// RUN: %clang_cc1 %s -O0 -triple=x86_64-apple-darwin -target-feature +avx512f -emit-llvm -o - -Werror | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <immintrin.h>
+
+__m512d test_mm512_sqrt_pd(__m512d a)
+{
+ // CHECK-LABEL: @test_mm512_sqrt_pd
+ // CHECK: @llvm.x86.avx512.sqrt.pd.512
+ return _mm512_sqrt_pd(a);
+}
+
+__m512 test_mm512_sqrt_ps(__m512 a)
+{
+ // CHECK-LABEL: @test_mm512_sqrt_ps
+ // CHECK: @llvm.x86.avx512.sqrt.ps.512
+ return _mm512_sqrt_ps(a);
+}
+
+__m512d test_mm512_rsqrt14_pd(__m512d a)
+{
+ // CHECK-LABEL: @test_mm512_rsqrt14_pd
+ // CHECK: @llvm.x86.avx512.rsqrt14.pd.512
+ return _mm512_rsqrt14_pd(a);
+}
+
+__m512 test_mm512_rsqrt14_ps(__m512 a)
+{
+ // CHECK-LABEL: @test_mm512_rsqrt14_ps
+ // CHECK: @llvm.x86.avx512.rsqrt14.ps.512
+ return _mm512_rsqrt14_ps(a);
+}
+
+__m512 test_mm512_add_ps(__m512 a, __m512 b)
+{
+ // CHECK-LABEL: @test_mm512_add_ps
+ // CHECK: fadd <16 x float>
+ return _mm512_add_ps(a, b);
+}
+
+__m512d test_mm512_add_pd(__m512d a, __m512d b)
+{
+ // CHECK-LABEL: @test_mm512_add_pd
+ // CHECK: fadd <8 x double>
+ return _mm512_add_pd(a, b);
+}
+
+__m512 test_mm512_mul_ps(__m512 a, __m512 b)
+{
+ // CHECK-LABEL: @test_mm512_mul_ps
+ // CHECK: fmul <16 x float>
+ return _mm512_mul_ps(a, b);
+}
+
+__m512d test_mm512_mul_pd(__m512d a, __m512d b)
+{
+ // CHECK-LABEL: @test_mm512_mul_pd
+ // CHECK: fmul <8 x double>
+ return _mm512_mul_pd(a, b);
+}
+
+void test_mm512_storeu_ps(void *p, __m512 a)
+{
+ // CHECK-LABEL: @test_mm512_storeu_ps
+ // CHECK: @llvm.x86.avx512.mask.storeu.ps.512
+ _mm512_storeu_ps(p, a);
+}
+
+void test_mm512_storeu_pd(void *p, __m512d a)
+{
+ // CHECK-LABEL: @test_mm512_storeu_pd
+ // CHECK: @llvm.x86.avx512.mask.storeu.pd.512
+ _mm512_storeu_pd(p, a);
+}
+
+void test_mm512_store_ps(void *p, __m512 a)
+{
+ // CHECK-LABEL: @test_mm512_store_ps
+ // CHECK: store <16 x float>
+ _mm512_store_ps(p, a);
+}
+
+void test_mm512_store_pd(void *p, __m512d a)
+{
+ // CHECK-LABEL: @test_mm512_store_pd
+ // CHECK: store <8 x double>
+ _mm512_store_pd(p, a);
+}
+
+__m512 test_mm512_loadu_ps(void *p)
+{
+ // CHECK-LABEL: @test_mm512_loadu_ps
+ // CHECK: load <16 x float>* {{.*}}, align 1{{$}}
+ return _mm512_loadu_ps(p);
+}
+
+__m512d test_mm512_loadu_pd(void *p)
+{
+ // CHECK-LABEL: @test_mm512_loadu_pd
+ // CHECK: load <8 x double>* {{.*}}, align 1{{$}}
+ return _mm512_loadu_pd(p);
+}
+
+__m512d test_mm512_set1_pd(double d)
+{
+ // CHECK-LABEL: @test_mm512_set1_pd
+ // CHECK: insertelement <8 x double> {{.*}}, i32 0
+ // CHECK: insertelement <8 x double> {{.*}}, i32 1
+ // CHECK: insertelement <8 x double> {{.*}}, i32 2
+ // CHECK: insertelement <8 x double> {{.*}}, i32 3
+ // CHECK: insertelement <8 x double> {{.*}}, i32 4
+ // CHECK: insertelement <8 x double> {{.*}}, i32 5
+ // CHECK: insertelement <8 x double> {{.*}}, i32 6
+ // CHECK: insertelement <8 x double> {{.*}}, i32 7
+ return _mm512_set1_pd(d);
+}
+
+__m512d test_mm512_castpd256_pd512(__m256d a)
+{
+ // CHECK-LABEL: @test_mm512_castpd256_pd512
+ // CHECK: shufflevector <4 x double> {{.*}} <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+ return _mm512_castpd256_pd512(a);
+}
+
+__mmask16 test_mm512_knot(__mmask16 a)
+{
+ // CHECK-LABEL: @test_mm512_knot
+ // CHECK: @llvm.x86.avx512.knot.w
+ return _mm512_knot(a);
+}
+
+__m512i test_mm512_valign_epi64(__m512i a, __m512i b)
+{
+ // CHECK-LABEL: @test_mm512_valign_epi64
+ // CHECK: @llvm.x86.avx512.mask.valign.q.512
+ return _mm512_valign_epi64(a, b, 2);
+}
+
+__m512d test_mm512_broadcastsd_pd(__m128d a)
+{
+ // CHECK-LABEL: @test_mm512_broadcastsd_pd
+ // CHECK: insertelement <8 x double> {{.*}}, i32 0
+ // CHECK: insertelement <8 x double> {{.*}}, i32 1
+ // CHECK: insertelement <8 x double> {{.*}}, i32 2
+ // CHECK: insertelement <8 x double> {{.*}}, i32 3
+ // CHECK: insertelement <8 x double> {{.*}}, i32 4
+ // CHECK: insertelement <8 x double> {{.*}}, i32 5
+ // CHECK: insertelement <8 x double> {{.*}}, i32 6
+ // CHECK: insertelement <8 x double> {{.*}}, i32 7
+ return _mm512_broadcastsd_pd(a);
+}
+
+__m512i test_mm512_fmadd_pd(__m512d a, __m512d b, __m512d c)
+{
+ // CHECK-LABEL: @test_mm512_fmadd_pd
+ // CHECK: @llvm.x86.fma.mask.vfmadd.pd.512
+ return _mm512_fmadd_pd(a, b, c);
+}
+
+__mmask16 test_mm512_cmpeq_epi32_mask(__m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_cmpeq_epi32_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.512
+ return (__mmask16)_mm512_cmpeq_epi32_mask(__a, __b);
+}
+
+__mmask16 test_mm512_mask_cmpeq_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_mask_cmpeq_epi32_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.512
+ return (__mmask16)_mm512_mask_cmpeq_epi32_mask(__u, __a, __b);
+}
+
+__mmask8 test_mm512_mask_cmpeq_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_mask_cmpeq_epi64_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.512
+ return (__mmask8)_mm512_mask_cmpeq_epi64_mask(__u, __a, __b);
+}
+
+__mmask8 test_mm512_cmpeq_epi64_mask(__m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_cmpeq_epi64_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.512
+ return (__mmask8)_mm512_cmpeq_epi64_mask(__a, __b);
+}
+
+__m512d test_mm512_unpackhi_pd(__m512d a, __m512d b)
+{
+ // CHECK-LABEL: @test_mm512_unpackhi_pd
+ // CHECK: shufflevector <8 x double> {{.*}} <i32 1, i32 9, i32 3, i32 11, i32 5, i32 13, i32 7, i32 15>
+ return _mm512_unpackhi_pd(a, b);
+}
+
+__m512d test_mm512_unpacklo_pd(__m512d a, __m512d b)
+{
+ // CHECK-LABEL: @test_mm512_unpacklo_pd
+ // CHECK: shufflevector <8 x double> {{.*}} <i32 0, i32 8, i32 2, i32 10, i32 4, i32 12, i32 6, i32 14>
+ return _mm512_unpacklo_pd(a, b);
+}
+
+__m512d test_mm512_unpackhi_ps(__m512d a, __m512d b)
+{
+ // CHECK-LABEL: @test_mm512_unpackhi_ps
+ // CHECK: shufflevector <16 x float> {{.*}} <i32 2, i32 18, i32 3, i32 19, i32 6, i32 22, i32 7, i32 23, i32 10, i32 26, i32 11, i32 27, i32 14, i32 30, i32 15, i32 31>
+ return _mm512_unpackhi_ps(a, b);
+}
+
+__m512d test_mm512_unpacklo_ps(__m512d a, __m512d b)
+{
+ // CHECK-LABEL: @test_mm512_unpacklo_ps
+ // CHECK: shufflevector <16 x float> {{.*}} <i32 0, i32 16, i32 1, i32 17, i32 4, i32 20, i32 5, i32 21, i32 8, i32 24, i32 9, i32 25, i32 12, i32 28, i32 13, i32 29>
+ return _mm512_unpacklo_ps(a, b);
+}
diff --git a/test/CodeGen/avx512vl-builtins.c b/test/CodeGen/avx512vl-builtins.c
new file mode 100644
index 000000000000..e4b45173bb13
--- /dev/null
+++ b/test/CodeGen/avx512vl-builtins.c
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 %s -O0 -triple=x86_64-apple-darwin -ffreestanding -target-feature +avx512f -target-feature +avx512vl -emit-llvm -o - -Werror | FileCheck %s
+
+#include <immintrin.h>
+
+__mmask8 test_mm256_cmpeq_epi32_mask(__m256i __a, __m256i __b) {
+ // CHECK-LABEL: @test_mm256_cmpeq_epi32_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.256
+ return (__mmask8)_mm256_cmpeq_epi32_mask(__a, __b);
+}
+
+__mmask8 test_mm256_mask_cmpeq_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) {
+ // CHECK-LABEL: @test_mm256_mask_cmpeq_epi32_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.256
+ return (__mmask8)_mm256_mask_cmpeq_epi32_mask(__u, __a, __b);
+}
+
+__mmask8 test_mm_cmpeq_epi32_mask(__m128i __a, __m128i __b) {
+ // CHECK-LABEL: @test_mm_cmpeq_epi32_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.128
+ return (__mmask8)_mm_cmpeq_epi32_mask(__a, __b);
+}
+
+__mmask8 test_mm_mask_cmpeq_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) {
+ // CHECK-LABEL: @test_mm_mask_cmpeq_epi32_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.128
+ return (__mmask8)_mm_mask_cmpeq_epi32_mask(__u, __a, __b);
+}
+
+__mmask8 test_mm256_cmpeq_epi64_mask(__m256i __a, __m256i __b) {
+ // CHECK-LABEL: @test_mm256_cmpeq_epi64_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.256
+ return (__mmask8)_mm256_cmpeq_epi64_mask(__a, __b);
+}
+
+__mmask8 test_mm256_mask_cmpeq_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) {
+ // CHECK-LABEL: @test_mm256_mask_cmpeq_epi64_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.256
+ return (__mmask8)_mm256_mask_cmpeq_epi64_mask(__u, __a, __b);
+}
+
+__mmask8 test_mm_cmpeq_epi64_mask(__m128i __a, __m128i __b) {
+ // CHECK-LABEL: @test_mm_cmpeq_epi64_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.128
+ return (__mmask8)_mm_cmpeq_epi64_mask(__a, __b);
+}
+
+__mmask8 test_mm_mask_cmpeq_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) {
+ // CHECK-LABEL: @test_mm_mask_cmpeq_epi64_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.128
+ return (__mmask8)_mm_mask_cmpeq_epi64_mask(__u, __a, __b);
+}
diff --git a/test/CodeGen/avx512vlbw-builtins.c b/test/CodeGen/avx512vlbw-builtins.c
new file mode 100644
index 000000000000..a304f7b3d361
--- /dev/null
+++ b/test/CodeGen/avx512vlbw-builtins.c
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 %s -O0 -triple=x86_64-apple-darwin -ffreestanding -target-feature +avx512bw -target-feature +avx512vl -emit-llvm -o - -Werror | FileCheck %s
+
+#include <immintrin.h>
+
+__mmask32 test_mm256_cmpeq_epi8_mask(__m256i __a, __m256i __b) {
+ // CHECK-LABEL: @test_mm256_cmpeq_epi8_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.b.256
+ return (__mmask32)_mm256_cmpeq_epi8_mask(__a, __b);
+}
+
+__mmask32 test_mm256_mask_cmpeq_epi8_mask(__mmask32 __u, __m256i __a, __m256i __b) {
+ // CHECK-LABEL: @test_mm256_mask_cmpeq_epi8_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.b.256
+ return (__mmask32)_mm256_mask_cmpeq_epi8_mask(__u, __a, __b);
+}
+
+__mmask16 test_mm_cmpeq_epi8_mask(__m128i __a, __m128i __b) {
+ // CHECK-LABEL: @test_mm_cmpeq_epi8_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.b.128
+ return (__mmask16)_mm_cmpeq_epi8_mask(__a, __b);
+}
+
+__mmask16 test_mm_mask_cmpeq_epi8_mask(__mmask16 __u, __m128i __a, __m128i __b) {
+ // CHECK-LABEL: @test_mm_mask_cmpeq_epi8_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.b.128
+ return (__mmask16)_mm_mask_cmpeq_epi8_mask(__u, __a, __b);
+}
+
+__mmask16 test_mm256_cmpeq_epi16_mask(__m256i __a, __m256i __b) {
+ // CHECK-LABEL: @test_mm256_cmpeq_epi16_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.w.256
+ return (__mmask16)_mm256_cmpeq_epi16_mask(__a, __b);
+}
+
+__mmask16 test_mm256_mask_cmpeq_epi16_mask(__mmask16 __u, __m256i __a, __m256i __b) {
+ // CHECK-LABEL: @test_mm256_mask_cmpeq_epi16_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.w.256
+ return (__mmask16)_mm256_mask_cmpeq_epi16_mask(__u, __a, __b);
+}
+
+__mmask8 test_mm_cmpeq_epi16_mask(__m128i __a, __m128i __b) {
+ // CHECK-LABEL: @test_mm_cmpeq_epi16_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.w.128
+ return (__mmask8)_mm_cmpeq_epi16_mask(__a, __b);
+}
+
+__mmask8 test_mm_mask_cmpeq_epi16_mask(__mmask8 __u, __m128i __a, __m128i __b) {
+ // CHECK-LABEL: @test_mm_mask_cmpeq_epi16_mask
+ // CHECK: @llvm.x86.avx512.mask.pcmpeq.w.128
+ return (__mmask8)_mm_mask_cmpeq_epi16_mask(__u, __a, __b);
+}
diff --git a/test/CodeGen/block-with-perdefinedexpr.c b/test/CodeGen/block-with-perdefinedexpr.c
new file mode 100644
index 000000000000..68fdea60f379
--- /dev/null
+++ b/test/CodeGen/block-with-perdefinedexpr.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks -triple x86_64-apple-darwin10 | FileCheck %s
+// rdar://18961148
+
+void syslog(const char *, ...);
+
+void handler( );
+
+static void (^spd)() = ^()
+{
+ handler( ^(){ syslog("%s", __FUNCTION__); } );
+};
+// CHECK: @__FUNCTION__.spd_block_invoke_2 = private unnamed_addr constant [19 x i8] c"spd_block_invoke_2\00"
+// CHECK: define internal void @spd_block_invoke_2
+// CHECK: @__FUNCTION__.spd_block_invoke_2
diff --git a/test/CodeGen/bmi2-builtins.c b/test/CodeGen/bmi2-builtins.c
index 201cac63b9fe..5aa54fd0ec34 100644
--- a/test/CodeGen/bmi2-builtins.c
+++ b/test/CodeGen/bmi2-builtins.c
@@ -24,9 +24,9 @@ unsigned int test_pext_u32(unsigned int __X, unsigned int __Y) {
unsigned int test_mulx_u32(unsigned int __X, unsigned int __Y,
unsigned int *__P) {
// CHECK: @test_mulx_u32
- // CHECK-NOT: mul i64
+ // CHECK-NOT: mul nuw i64
// B32: @test_mulx_u32
- // B32: mul i64
+ // B32: mul nuw i64
return _mulx_u32(__X, __Y, __P);
}
@@ -48,6 +48,6 @@ unsigned long long test_pext_u64(unsigned long long __X, unsigned long long __Y)
unsigned long long test_mulx_u64(unsigned long long __X, unsigned long long __Y,
unsigned long long *__P) {
// CHECK: @test_mulx_u64
- // CHECK: mul i128
+ // CHECK: mul nuw i128
return _mulx_u64(__X, __Y, __P);
}
diff --git a/test/CodeGen/bool_test.c b/test/CodeGen/bool_test.c
index c836b9830339..cf62dba1df21 100644
--- a/test/CodeGen/bool_test.c
+++ b/test/CodeGen/bool_test.c
@@ -15,4 +15,4 @@ void f(_Bool *x, _Bool *y) {
// CHECK: store i32 [[TOMEM]]
// CHECK: ret void
-// CHECK: metadata !{i32 0, i32 2}
+// CHECK: i32 0, i32 2}
diff --git a/test/CodeGen/builtin-assume-aligned.c b/test/CodeGen/builtin-assume-aligned.c
new file mode 100644
index 000000000000..1d807a40cad4
--- /dev/null
+++ b/test/CodeGen/builtin-assume-aligned.c
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// CHECK-LABEL: @test1
+int test1(int *a) {
+// CHECK: [[PTRINT1:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR1:%.+]] = and i64 [[PTRINT1]], 31
+// CHECK: [[MASKCOND1:%.+]] = icmp eq i64 [[MASKEDPTR1]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND1]])
+ a = __builtin_assume_aligned(a, 32, 0ull);
+ return a[0];
+}
+
+// CHECK-LABEL: @test2
+int test2(int *a) {
+// CHECK: [[PTRINT2:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR2:%.+]] = and i64 [[PTRINT2]], 31
+// CHECK: [[MASKCOND2:%.+]] = icmp eq i64 [[MASKEDPTR2]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND2]])
+ a = __builtin_assume_aligned(a, 32, 0);
+ return a[0];
+}
+
+// CHECK-LABEL: @test3
+int test3(int *a) {
+// CHECK: [[PTRINT3:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR3:%.+]] = and i64 [[PTRINT3]], 31
+// CHECK: [[MASKCOND3:%.+]] = icmp eq i64 [[MASKEDPTR3]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND3]])
+ a = __builtin_assume_aligned(a, 32);
+ return a[0];
+}
+
+// CHECK-LABEL: @test4
+int test4(int *a, int b) {
+// CHECK-DAG: [[PTRINT4:%.+]] = ptrtoint
+// CHECK-DAG: [[CONV4:%.+]] = sext i32
+// CHECK: [[OFFSETPTR4:%.+]] = sub i64 [[PTRINT4]], [[CONV4]]
+// CHECK: [[MASKEDPTR4:%.+]] = and i64 [[OFFSETPTR4]], 31
+// CHECK: [[MASKCOND4:%.+]] = icmp eq i64 [[MASKEDPTR4]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND4]])
+ a = __builtin_assume_aligned(a, 32, b);
+ return a[0];
+}
+
+int *m1() __attribute__((assume_aligned(64)));
+
+// CHECK-LABEL: @test5
+int test5() {
+ return *m1();
+// CHECK: [[PTRINT5:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR5:%.+]] = and i64 [[PTRINT5]], 63
+// CHECK: [[MASKCOND5:%.+]] = icmp eq i64 [[MASKEDPTR5]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND5]])
+}
+
+int *m2() __attribute__((assume_aligned(64, 12)));
+
+// CHECK-LABEL: @test6
+int test6() {
+ return *m2();
+// CHECK: [[PTRINT6:%.+]] = ptrtoint
+// CHECK: [[OFFSETPTR6:%.+]] = sub i64 [[PTRINT6]], 12
+// CHECK: [[MASKEDPTR6:%.+]] = and i64 [[OFFSETPTR6]], 63
+// CHECK: [[MASKCOND6:%.+]] = icmp eq i64 [[MASKEDPTR6]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND6]])
+}
+
diff --git a/test/CodeGen/builtin-assume.c b/test/CodeGen/builtin-assume.c
index a381a4c1dfb0..8411b729abf5 100644
--- a/test/CodeGen/builtin-assume.c
+++ b/test/CodeGen/builtin-assume.c
@@ -1,8 +1,27 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple i386-mingw32 -fms-extensions -emit-llvm -o - %s | FileCheck %s
// CHECK-LABEL: @test1
-int test1(int *a) {
- __assume(a != 0);
+int test1(int *a, int i) {
+// CHECK: store i32* %a, i32** [[A_ADDR:%.+]], align
+// CHECK: [[A:%.+]] = load i32** [[A_ADDR]]
+// CHECK: [[CMP:%.+]] = icmp ne i32* [[A]], null
+// CHECK: call void @llvm.assume(i1 [[CMP]])
+#ifdef _MSC_VER
+ __assume(a != 0)
+#else
+ __builtin_assume(a != 0);
+#endif
+
+// Nothing is generated for an assume with side effects...
+// CHECK-NOT: load i32** %i.addr
+// CHECK-NOT: call void @llvm.assume
+#ifdef _MSC_VER
+ __assume(++i != 0)
+#else
+ __builtin_assume(++i != 0);
+#endif
+
return a[0];
}
diff --git a/test/CodeGen/builtin-recursive.cc b/test/CodeGen/builtin-recursive.cpp
index 81e9b9a37c25..7553a6e48f53 100644
--- a/test/CodeGen/builtin-recursive.cc
+++ b/test/CodeGen/builtin-recursive.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -nostdsysteminc -nobuiltininc -isystem Inputs -emit-llvm-only %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -nostdsysteminc -nobuiltininc -isystem %S/Inputs -emit-llvm-only %s
// This used to cause a read past the end of a global variable.
diff --git a/test/CodeGen/builtins-arm-msvc-compat-error.c b/test/CodeGen/builtins-arm-msvc-compat-error.c
new file mode 100644
index 000000000000..29469deb6a70
--- /dev/null
+++ b/test/CodeGen/builtins-arm-msvc-compat-error.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple thumbv7-windows -fms-extensions -verify %s
+
+void emit_error(unsigned int opcode) {
+ __emit(opcode); // expected-error {{argument to '__emit' must be a constant integer}}
+}
+
diff --git a/test/CodeGen/builtins-arm-msvc-compat-only.c b/test/CodeGen/builtins-arm-msvc-compat-only.c
new file mode 100644
index 000000000000..db82ca406652
--- /dev/null
+++ b/test/CodeGen/builtins-arm-msvc-compat-only.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple thumbv7-windows -fms-extensions -emit-llvm -o - %s \
+// RUN: | FileCheck %s -check-prefix CHECK-MSVC
+// RUN: %clang_cc1 -triple armv7-eabi -emit-llvm %s -o /dev/null 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-EABI
+// REQUIRES: arm-registered-target
+
+void emit() {
+ __emit(0xdefe);
+}
+
+// CHECK-MSVC: call void asm sideeffect ".inst.n 0xDEFE", ""()
+// CHECK-EABI: warning: implicit declaration of function '__emit' is invalid in C99
+
+void emit_truncated() {
+ __emit(0x11110000); // movs r0, r0
+}
+
+// CHECK-MSVC: call void asm sideeffect ".inst.n 0x0", ""()
+
diff --git a/test/CodeGen/builtins-arm.c b/test/CodeGen/builtins-arm.c
index a51df15ce56b..9f3ed9ac78a1 100644
--- a/test/CodeGen/builtins-arm.c
+++ b/test/CodeGen/builtins-arm.c
@@ -55,6 +55,12 @@ void sevl() {
// CHECK: call {{.*}} @llvm.arm.hint(i32 5)
+void dbg() {
+ __builtin_arm_dbg(0);
+}
+
+// CHECK: call {{.*}} @llvm.arm.dbg(i32 0)
+
void test_barrier() {
__builtin_arm_dmb(1); //CHECK: call {{.*}} @llvm.arm.dmb(i32 1)
__builtin_arm_dsb(2); //CHECK: call {{.*}} @llvm.arm.dsb(i32 2)
@@ -66,3 +72,15 @@ void test_barrier() {
unsigned rbit(unsigned a) {
return __builtin_arm_rbit(a);
}
+
+void prefetch(int i) {
+ __builtin_arm_prefetch(&i, 0, 1);
+// CHECK: call {{.*}} @llvm.prefetch(i8* %{{.*}}, i32 0, i32 3, i32 1)
+
+ __builtin_arm_prefetch(&i, 1, 1);
+// CHECK: call {{.*}} @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 1)
+
+
+ __builtin_arm_prefetch(&i, 1, 0);
+// CHECK: call {{.*}} @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 0)
+}
diff --git a/test/CodeGen/builtins-arm64.c b/test/CodeGen/builtins-arm64.c
index cfa118122793..cc1f54732b30 100644
--- a/test/CodeGen/builtins-arm64.c
+++ b/test/CodeGen/builtins-arm64.c
@@ -29,3 +29,17 @@ void barriers() {
__builtin_arm_dsb(2); //CHECK: call {{.*}} @llvm.aarch64.dsb(i32 2)
__builtin_arm_isb(3); //CHECK: call {{.*}} @llvm.aarch64.isb(i32 3)
}
+
+void prefetch() {
+ __builtin_arm_prefetch(0, 1, 2, 0, 1); // pstl3keep
+// CHECK: call {{.*}} @llvm.prefetch(i8* null, i32 1, i32 1, i32 1)
+
+ __builtin_arm_prefetch(0, 0, 0, 1, 1); // pldl1keep
+// CHECK: call {{.*}} @llvm.prefetch(i8* null, i32 0, i32 0, i32 1)
+
+ __builtin_arm_prefetch(0, 0, 0, 1, 1); // pldl1strm
+// CHECK: call {{.*}} @llvm.prefetch(i8* null, i32 0, i32 0, i32 1)
+
+ __builtin_arm_prefetch(0, 0, 0, 0, 0); // plil1keep
+// CHECK: call {{.*}} @llvm.prefetch(i8* null, i32 0, i32 3, i32 0)
+}
diff --git a/test/CodeGen/builtins-nvptx.c b/test/CodeGen/builtins-nvptx.c
index cee9061292bd..5f91f7ad3b0b 100644
--- a/test/CodeGen/builtins-nvptx.c
+++ b/test/CodeGen/builtins-nvptx.c
@@ -155,6 +155,8 @@ void nvvm_math(float f1, float f2, double d1, double d2) {
float t3 = __nvvm_sqrt_rn_f(f1);
// CHECK: call float @llvm.nvvm.rcp.rn.f
float t4 = __nvvm_rcp_rn_f(f2);
+// CHECK: call float @llvm.nvvm.add.rn.f
+ float t5 = __nvvm_add_rn_f(f1, f2);
// CHECK: call double @llvm.nvvm.fmax.d
double td1 = __nvvm_fmax_d(d1, d2);
diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c
index 31491072a1d4..c6aa3c2faac2 100644
--- a/test/CodeGen/builtins-ppc-altivec.c
+++ b/test/CodeGen/builtins-ppc-altivec.c
@@ -1047,7 +1047,7 @@ void test6() {
// CHECK-LE: @llvm.ppc.altivec.vcmpgtfp
/* vec_ctf */
- res_vf = vec_ctf(vi, param_i);
+ res_vf = vec_ctf(vi, 0);
// CHECK: @llvm.ppc.altivec.vcfsx
// CHECK-LE: @llvm.ppc.altivec.vcfsx
@@ -1082,7 +1082,7 @@ void test6() {
// CHECK-LE: @llvm.ppc.altivec.vctuxs
/* vec_dss */
- vec_dss(param_i);
+ vec_dss(0);
// CHECK: @llvm.ppc.altivec.dss
// CHECK-LE: @llvm.ppc.altivec.dss
diff --git a/test/CodeGen/builtins-ppc-vsx.c b/test/CodeGen/builtins-ppc-vsx.c
new file mode 100644
index 000000000000..58a8cc32dce3
--- /dev/null
+++ b/test/CodeGen/builtins-ppc-vsx.c
@@ -0,0 +1,116 @@
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -faltivec -target-feature +vsx -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+vector unsigned char vuc = { 8, 9, 10, 11, 12, 13, 14, 15,
+ 0, 1, 2, 3, 4, 5, 6, 7};
+vector float vf = { -1.5, 2.5, -3.5, 4.5 };
+vector double vd = { 3.5, -7.5 };
+vector signed int vsi = { -1, 2, -3, 4 };
+vector unsigned int vui = { 0, 1, 2, 3 };
+vector signed long long vsll = { 255LL, -937LL };
+vector unsigned long long vull = { 1447LL, 2894LL };
+double d = 23.4;
+
+vector float res_vf;
+vector double res_vd;
+vector signed int res_vsi;
+vector unsigned int res_vui;
+vector signed long long res_vsll;
+vector unsigned long long res_vull;
+double res_d;
+
+void test1() {
+// CHECK-LABEL: define void @test1
+
+ /* vec_div */
+ res_vf = vec_div(vf, vf);
+// CHECK: @llvm.ppc.vsx.xvdivsp
+
+ res_vd = vec_div(vd, vd);
+// CHECK: @llvm.ppc.vsx.xvdivdp
+
+ /* vec_max */
+ res_vf = vec_max(vf, vf);
+// CHECK: @llvm.ppc.vsx.xvmaxsp
+
+ res_vd = vec_max(vd, vd);
+// CHECK: @llvm.ppc.vsx.xvmaxdp
+
+ res_vf = vec_vmaxfp(vf, vf);
+// CHECK: @llvm.ppc.vsx.xvmaxsp
+
+ /* vec_min */
+ res_vf = vec_min(vf, vf);
+// CHECK: @llvm.ppc.vsx.xvminsp
+
+ res_vd = vec_min(vd, vd);
+// CHECK: @llvm.ppc.vsx.xvmindp
+
+ res_vf = vec_vminfp(vf, vf);
+// CHECK: @llvm.ppc.vsx.xvminsp
+
+ res_d = __builtin_vsx_xsmaxdp(d, d);
+// CHECK: @llvm.ppc.vsx.xsmaxdp
+
+ res_d = __builtin_vsx_xsmindp(d, d);
+// CHECK: @llvm.ppc.vsx.xsmindp
+
+ /* vec_perm */
+ res_vsll = vec_perm(vsll, vsll, vuc);
+// CHECK: @llvm.ppc.altivec.vperm
+
+ res_vull = vec_perm(vull, vull, vuc);
+// CHECK: @llvm.ppc.altivec.vperm
+
+ res_vd = vec_perm(vd, vd, vuc);
+// CHECK: @llvm.ppc.altivec.vperm
+
+ res_vsll = vec_vperm(vsll, vsll, vuc);
+// CHECK: @llvm.ppc.altivec.vperm
+
+ res_vull = vec_vperm(vull, vull, vuc);
+// CHECK: @llvm.ppc.altivec.vperm
+
+ res_vd = vec_vperm(vd, vd, vuc);
+// CHECK: @llvm.ppc.altivec.vperm
+
+ /* vec_vsx_ld */
+
+ res_vsi = vec_vsx_ld(0, &vsi);
+// CHECK: @llvm.ppc.vsx.lxvw4x
+
+ res_vui = vec_vsx_ld(0, &vui);
+// CHECK: @llvm.ppc.vsx.lxvw4x
+
+ res_vf = vec_vsx_ld (0, &vf);
+// CHECK: @llvm.ppc.vsx.lxvw4x
+
+ res_vsll = vec_vsx_ld(0, &vsll);
+// CHECK: @llvm.ppc.vsx.lxvd2x
+
+ res_vull = vec_vsx_ld(0, &vull);
+// CHECK: @llvm.ppc.vsx.lxvd2x
+
+ res_vd = vec_vsx_ld(0, &vd);
+// CHECK: @llvm.ppc.vsx.lxvd2x
+
+ /* vec_vsx_st */
+
+ vec_vsx_st(vsi, 0, &res_vsi);
+// CHECK: @llvm.ppc.vsx.stxvw4x
+
+ vec_vsx_st(vui, 0, &res_vui);
+// CHECK: @llvm.ppc.vsx.stxvw4x
+
+ vec_vsx_st(vf, 0, &res_vf);
+// CHECK: @llvm.ppc.vsx.stxvw4x
+
+ vec_vsx_st(vsll, 0, &res_vsll);
+// CHECK: @llvm.ppc.vsx.stxvd2x
+
+ vec_vsx_st(vull, 0, &res_vull);
+// CHECK: @llvm.ppc.vsx.stxvd2x
+
+ vec_vsx_st(vd, 0, &res_vd);
+// CHECK: @llvm.ppc.vsx.stxvd2x
+}
diff --git a/test/CodeGen/builtins-x86.c b/test/CodeGen/builtins-x86.c
index 0f038b87355c..e9ae834b3cfa 100644
--- a/test/CodeGen/builtins-x86.c
+++ b/test/CodeGen/builtins-x86.c
@@ -386,7 +386,7 @@ void f0() {
tmp_V4f = __builtin_ia32_roundss(tmp_V4f, tmp_V4f, imm_i_0_16);
tmp_V2d = __builtin_ia32_roundsd(tmp_V2d, tmp_V2d, imm_i_0_16);
tmp_V2d = __builtin_ia32_roundpd(tmp_V2d, imm_i_0_16);
- tmp_V4f = __builtin_ia32_insertps128(tmp_V4f, tmp_V4f, tmp_i);
+ tmp_V4f = __builtin_ia32_insertps128(tmp_V4f, tmp_V4f, imm_i_0_256);
#endif
tmp_V4d = __builtin_ia32_addsubpd256(tmp_V4d, tmp_V4d);
diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c
index 39bd84c5a5a4..1ab29a659b31 100644
--- a/test/CodeGen/builtins.c
+++ b/test/CodeGen/builtins.c
@@ -171,32 +171,55 @@ void bar() {
void test_float_builtins(float F, double D, long double LD) {
volatile int res;
res = __builtin_isinf(F);
- // CHECK: call float @fabsf(float
+ // CHECK: call float @llvm.fabs.f32(float
// CHECK: fcmp oeq float {{.*}}, 0x7FF0000000000000
res = __builtin_isinf(D);
- // CHECK: call double @fabs(double
+ // CHECK: call double @llvm.fabs.f64(double
// CHECK: fcmp oeq double {{.*}}, 0x7FF0000000000000
res = __builtin_isinf(LD);
- // CHECK: call x86_fp80 @fabsl(x86_fp80
+ // CHECK: call x86_fp80 @llvm.fabs.f80(x86_fp80
// CHECK: fcmp oeq x86_fp80 {{.*}}, 0xK7FFF8000000000000000
res = __builtin_isfinite(F);
// CHECK: fcmp oeq float
- // CHECK: call float @fabsf
+ // CHECK: call float @llvm.fabs.f32(float
// CHECK: fcmp une float {{.*}}, 0x7FF0000000000000
// CHECK: and i1
res = __builtin_isnormal(F);
// CHECK: fcmp oeq float
- // CHECK: call float @fabsf
+ // CHECK: call float @llvm.fabs.f32(float
// CHECK: fcmp ult float {{.*}}, 0x7FF0000000000000
// CHECK: fcmp uge float {{.*}}, 0x3810000000000000
// CHECK: and i1
// CHECK: and i1
}
+// CHECK-LABEL: define void @test_float_builtin_ops
+void test_float_builtin_ops(float F, double D, long double LD) {
+ volatile float resf;
+ volatile double resd;
+ volatile long double resld;
+
+ resf = __builtin_fmodf(F,F);
+ // CHECK: frem float
+
+ resd = __builtin_fmod(D,D);
+ // CHECK: frem double
+
+ resld = __builtin_fmodl(LD,LD);
+ // CHECK: frem x86_fp80
+
+ resf = __builtin_fabsf(F);
+ resd = __builtin_fabs(D);
+ resld = __builtin_fabsl(LD);
+ // CHECK: call float @llvm.fabs.f32(float
+ // CHECK: call double @llvm.fabs.f64(double
+ // CHECK: call x86_fp80 @llvm.fabs.f80(x86_fp80
+}
+
// CHECK-LABEL: define void @test_builtin_longjmp
void test_builtin_longjmp(void **buffer) {
// CHECK: [[BITCAST:%.*]] = bitcast
diff --git a/test/CodeGen/c11atomics-ios.c b/test/CodeGen/c11atomics-ios.c
index ad004fa4b2f3..ad57550441b0 100644
--- a/test/CodeGen/c11atomics-ios.c
+++ b/test/CodeGen/c11atomics-ios.c
@@ -6,7 +6,7 @@
// This work was done in pursuit of <rdar://13338582>.
-// CHECK-LABEL: define arm_aapcscc void @testFloat(float*
+// CHECK-LABEL: define void @testFloat(float*
void testFloat(_Atomic(float) *fp) {
// CHECK: [[FP:%.*]] = alloca float*
// CHECK-NEXT: [[X:%.*]] = alloca float
@@ -37,7 +37,7 @@ void testFloat(_Atomic(float) *fp) {
// CHECK-NEXT: ret void
}
-// CHECK: define arm_aapcscc void @testComplexFloat([[CF:{ float, float }]]*
+// CHECK: define void @testComplexFloat([[CF:{ float, float }]]*
void testComplexFloat(_Atomic(_Complex float) *fp) {
// CHECK: [[FP:%.*]] = alloca [[CF]]*, align 4
// CHECK-NEXT: [[X:%.*]] = alloca [[CF]], align 8
@@ -93,7 +93,7 @@ void testComplexFloat(_Atomic(_Complex float) *fp) {
}
typedef struct { short x, y, z, w; } S;
-// CHECK: define arm_aapcscc void @testStruct([[S:.*]]*
+// CHECK: define void @testStruct([[S:.*]]*
void testStruct(_Atomic(S) *fp) {
// CHECK: [[FP:%.*]] = alloca [[S]]*, align 4
// CHECK-NEXT: [[X:%.*]] = alloca [[S]], align 8
@@ -143,7 +143,7 @@ void testStruct(_Atomic(S) *fp) {
}
typedef struct { short x, y, z; } PS;
-// CHECK: define arm_aapcscc void @testPromotedStruct([[APS:.*]]*
+// CHECK: define void @testPromotedStruct([[APS:.*]]*
void testPromotedStruct(_Atomic(PS) *fp) {
// CHECK: [[FP:%.*]] = alloca [[APS]]*, align 4
// CHECK-NEXT: [[X:%.*]] = alloca [[APS]], align 8
diff --git a/test/CodeGen/c11atomics.c b/test/CodeGen/c11atomics.c
index f4c9522cbdb2..376c58267410 100644
--- a/test/CodeGen/c11atomics.c
+++ b/test/CodeGen/c11atomics.c
@@ -57,7 +57,7 @@ void testinc(void)
// CHECK: testdec
void testdec(void)
{
- // CHECK: cmpxchg i8* @b
+ // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 1, i8* @b
b--;
// CHECK: atomicrmw sub i32* @i, i32 1 seq_cst
i--;
@@ -65,7 +65,7 @@ void testdec(void)
l--;
// CHECK: atomicrmw sub i16* @s, i16 1 seq_cst
s--;
- // CHECK: cmpxchg i8* @b
+ // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 1, i8* @b
--b;
// CHECK: atomicrmw sub i32* @i, i32 1 seq_cst
// CHECK: sub i32
@@ -80,7 +80,7 @@ void testdec(void)
// CHECK: testaddeq
void testaddeq(void)
{
- // CHECK: cmpxchg i8* @b
+ // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 1, i8* @b
// CHECK: atomicrmw add i32* @i, i32 42 seq_cst
// CHECK: atomicrmw add i64* @l, i64 42 seq_cst
// CHECK: atomicrmw add i16* @s, i16 42 seq_cst
@@ -92,7 +92,7 @@ void testaddeq(void)
// CHECK: testsubeq
void testsubeq(void)
{
- // CHECK: cmpxchg i8* @b
+ // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 1, i8* @b
// CHECK: atomicrmw sub i32* @i, i32 42 seq_cst
// CHECK: atomicrmw sub i64* @l, i64 42 seq_cst
// CHECK: atomicrmw sub i16* @s, i16 42 seq_cst
@@ -104,7 +104,7 @@ void testsubeq(void)
// CHECK: testxoreq
void testxoreq(void)
{
- // CHECK: cmpxchg i8* @b
+ // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 1, i8* @b
// CHECK: atomicrmw xor i32* @i, i32 42 seq_cst
// CHECK: atomicrmw xor i64* @l, i64 42 seq_cst
// CHECK: atomicrmw xor i16* @s, i16 42 seq_cst
@@ -116,7 +116,7 @@ void testxoreq(void)
// CHECK: testoreq
void testoreq(void)
{
- // CHECK: cmpxchg i8* @b
+ // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 1, i8* @b
// CHECK: atomicrmw or i32* @i, i32 42 seq_cst
// CHECK: atomicrmw or i64* @l, i64 42 seq_cst
// CHECK: atomicrmw or i16* @s, i16 42 seq_cst
@@ -128,7 +128,7 @@ void testoreq(void)
// CHECK: testandeq
void testandeq(void)
{
- // CHECK: cmpxchg i8* @b
+ // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 1, i8* @b
// CHECK: atomicrmw and i32* @i, i32 42 seq_cst
// CHECK: atomicrmw and i64* @l, i64 42 seq_cst
// CHECK: atomicrmw and i16* @s, i16 42 seq_cst
diff --git a/test/CodeGen/captured-statements-nested.c b/test/CodeGen/captured-statements-nested.c
index 2ff9ee9cc88c..cd20b5a66462 100644
--- a/test/CodeGen/captured-statements-nested.c
+++ b/test/CodeGen/captured-statements-nested.c
@@ -11,9 +11,9 @@ struct A {
void test_nest_captured_stmt(int param, int size, int param_arr[size]) {
int w;
int arr[param][size];
- // CHECK1: %struct.anon{{.*}} = type { i32*, i32*, i{{.+}}*, i32**, i32* }
- // CHECK1: %struct.anon{{.*}} = type { i32*, i32*, i32**, i32*, i{{.+}}*, i32**, i32* }
- // CHECK1: [[T:%struct.anon.*]] = type { i32*, i32*, %struct.A*, i32**, i32*, i{{.+}}*, i32**, i32* }
+ // CHECK1: %struct.anon{{.*}} = type { [[INT:i.+]]*, [[INT]]*, [[SIZE_TYPE:i.+]], [[INT]]**, [[INT]]*, [[SIZE_TYPE]], [[SIZE_TYPE]], [[INT]]* }
+ // CHECK1: %struct.anon{{.*}} = type { [[INT]]*, [[INT]]*, [[INT]]**, [[INT]]*, [[SIZE_TYPE]], [[INT]]**, [[INT]]*, [[SIZE_TYPE]], [[SIZE_TYPE]], [[INT]]* }
+ // CHECK1: [[T:%struct.anon.*]] = type { [[INT]]*, [[INT]]*, %struct.A*, [[INT]]**, [[INT]]*, [[SIZE_TYPE]], [[INT]]**, [[INT]]*, [[SIZE_TYPE]], [[SIZE_TYPE]], [[INT]]* }
#pragma clang __debug captured
{
int x;
@@ -31,39 +31,45 @@ void test_nest_captured_stmt(int param, int size, int param_arr[size]) {
arr[10][z.a] = 12;
// CHECK1: define internal void @__captured_stmt{{.*}}([[T]]
+ // CHECK1: [[PARAM_ARR_SIZE_REF:%.+]] = getelementptr inbounds [[T]]* {{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 5
+ // CHECK1: [[PARAM_ARR_SIZE:%.+]] = load [[SIZE_TYPE]]* [[PARAM_ARR_SIZE_REF]]
+ // CHECK1: [[ARR_SIZE1_REF:%.+]] = getelementptr inbounds [[T]]* {{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 8
+ // CHECK1: [[ARR_SIZE1:%.+]] = load [[SIZE_TYPE]]* [[ARR_SIZE1_REF]]
+ // CHECK1: [[ARR_SIZE2_REF:%.+]] = getelementptr inbounds [[T]]* {{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 9
+ // CHECK1: [[ARR_SIZE2:%.+]] = load [[SIZE_TYPE]]* [[ARR_SIZE2_REF]]
//
- // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
// CHECK1-NEXT: load %struct.A**
// CHECK1-NEXT: getelementptr inbounds %struct.A*
// CHECK1-NEXT: store i{{.+}} 1
//
- // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 1
- // CHECK1-NEXT: load i32**
- // CHECK1-NEXT: store i32 1
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK1-NEXT: load i{{[0-9]+}}**
+ // CHECK1-NEXT: store i{{[0-9]+}} 1
//
- // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 0
- // CHECK1-NEXT: load i32**
- // CHECK1-NEXT: store i32 1
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK1-NEXT: load i{{[0-9]+}}**
+ // CHECK1-NEXT: store i{{[0-9]+}} 1
//
- // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 4
- // CHECK1-NEXT: load i32**
- // CHECK1-NEXT: load i32*
- // CHECK1-NEXT: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 3
- // CHECK1-NEXT: load i32***
- // CHECK1-NEXT: load i32**
- // CHECK1-NEXT: store i32
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i{{[0-9]+}} 0, i{{[0-9]+}} 4
+ // CHECK1-NEXT: load i{{[0-9]+}}**
+ // CHECK1-NEXT: load i{{[0-9]+}}*
+ // CHECK1-NEXT: getelementptr inbounds [[T]]* {{.*}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // CHECK1-NEXT: load i{{[0-9]+}}***
+ // CHECK1-NEXT: load i{{[0-9]+}}**
+ // CHECK1-NEXT: store i{{[0-9]+}}
//
- // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
// CHECK1-NEXT: load %struct.A**
// CHECK1-NEXT: getelementptr inbounds %struct.A*
// CHECK1-NEXT: store float
//
- // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
+ // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
// CHECK1-NEXT: load %struct.A**
// CHECK1-NEXT: getelementptr inbounds %struct.A*
// CHECK1-NEXT: store i8 99
//
- // CHECK1: [[SIZE_ADDR_REF:%.*]] = getelementptr inbounds [[T]]* {{.*}}, i{{.+}} 0, i{{.+}} 5
+ // CHECK1: [[SIZE_ADDR_REF:%.*]] = getelementptr inbounds [[T]]* {{.*}}, i{{.+}} 0, i{{.+}} 7
// CHECK1-DAG: [[SIZE_ADDR:%.*]] = load i{{.+}}** [[SIZE_ADDR_REF]]
// CHECK1-DAG: [[SIZE:%.*]] = load i{{.+}}* [[SIZE_ADDR]]
// CHECK1-DAG: [[PARAM_ARR_IDX:%.*]] = sub nsw i{{.+}} [[SIZE]], 1
@@ -77,7 +83,7 @@ void test_nest_captured_stmt(int param, int size, int param_arr[size]) {
// CHECK1-DAG: [[Z_ADDR:%.*]] = load %struct.A** [[Z_ADDR_REF]]
// CHECK1-DAG: [[Z_A_ADDR:%.*]] = getelementptr inbounds %struct.A* [[Z_ADDR]], i{{.+}} 0, i{{.+}} 0
// CHECK1-DAG: [[ARR_IDX_2:%.*]] = load i{{.+}}* [[Z_A_ADDR]]
- // CHECK1-DAG: [[ARR_ADDR_REF:%.*]] = getelementptr inbounds [[T]]* {{.*}}, i{{.+}} 0, i{{.+}} 7
+ // CHECK1-DAG: [[ARR_ADDR_REF:%.*]] = getelementptr inbounds [[T]]* {{.*}}, i{{.+}} 0, i{{.+}} 10
// CHECK1-DAG: [[ARR_ADDR:%.*]] = load i{{.+}}** [[ARR_ADDR_REF]]
// CHECK1-DAG: [[ARR_IDX_1:%.*]] = mul {{.*}} 10
// CHECK1-DAG: [[ARR_10_ADDR:%.*]] = getelementptr inbounds i{{.+}}* [[ARR_ADDR]], i{{.*}} [[ARR_IDX_1]]
@@ -102,15 +108,15 @@ void test_nest_block() {
// CHECK2: define internal void @{{.*}}test_nest_block_block_invoke
//
- // CHECK2: [[Z:%[0-9a-z_]*]] = alloca i32
+ // CHECK2: [[Z:%[0-9a-z_]*]] = alloca i{{[0-9]+}},
// CHECK2: alloca %struct.anon{{.*}}
//
- // CHECK2: store i32
- // CHECK2: store i32* [[Z]]
+ // CHECK2: store i{{[0-9]+}}
+ // CHECK2: store i{{[0-9]+}}* [[Z]]
//
// CHECK2: getelementptr inbounds %struct.anon
// CHECK2-NEXT: getelementptr inbounds
- // CHECK2-NEXT: store i32*
+ // CHECK2-NEXT: store i{{[0-9]+}}*
//
// CHECK2: call void @__captured_stmt
@@ -128,22 +134,22 @@ void test_nest_block() {
}
// CHECK2: alloca %struct.__block_byref_b
- // CHECK2-NEXT: [[C:%[0-9a-z_]*]] = alloca i32
+ // CHECK2-NEXT: [[C:%[0-9a-z_]*]] = alloca i{{[0-9]+}}
// CHECK2-NEXT: alloca %struct.__block_byref_d
//
// CHECK2: bitcast %struct.__block_byref_b*
// CHECK2-NEXT: store i8*
//
- // CHECK2: [[CapA:%[0-9a-z_.]*]] = getelementptr inbounds {{.*}}, i32 0, i32 7
+ // CHECK2: [[CapA:%[0-9a-z_.]*]] = getelementptr inbounds {{.*}}, i{{[0-9]+}} 0, i{{[0-9]+}} 7
//
- // CHECK2: getelementptr inbounds %struct.anon{{.*}}, i32 0, i32 0
- // CHECK2: load i32**
- // CHECK2: load i32*
- // CHECK2: store i32 {{.*}}, i32* [[CapA]]
+ // CHECK2: getelementptr inbounds %struct.anon{{.*}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK2: load i{{[0-9]+}}**
+ // CHECK2: load i{{[0-9]+}}*
+ // CHECK2: store i{{[0-9]+}} {{.*}}, i{{[0-9]+}}* [[CapA]]
//
- // CHECK2: [[CapC:%[0-9a-z_.]*]] = getelementptr inbounds {{.*}}, i32 0, i32 8
- // CHECK2-NEXT: [[Val:%[0-9a-z_]*]] = load i32* [[C]]
- // CHECK2-NEXT: store i32 [[Val]], i32* [[CapC]]
+ // CHECK2: [[CapC:%[0-9a-z_.]*]] = getelementptr inbounds {{.*}}, i{{[0-9]+}} 0, i{{[0-9]+}} 8
+ // CHECK2-NEXT: [[Val:%[0-9a-z_]*]] = load i{{[0-9]+}}* [[C]]
+ // CHECK2-NEXT: store i{{[0-9]+}} [[Val]], i{{[0-9]+}}* [[CapC]]
//
// CHECK2: bitcast %struct.__block_byref_d*
// CHECK2-NEXT: store i8*
diff --git a/test/CodeGen/captured-statements.c b/test/CodeGen/captured-statements.c
index 85d597aeb3c3..52747fba1e90 100644
--- a/test/CodeGen/captured-statements.c
+++ b/test/CodeGen/captured-statements.c
@@ -4,6 +4,8 @@
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-2
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-3
+typedef __INTPTR_TYPE__ intptr_t;
+
int foo();
int global;
@@ -61,15 +63,16 @@ void test3(int size) {
}
// Capture VLA array
-void test4(int size, int vla_arr[size]) {
+void test4(intptr_t size, intptr_t vla_arr[size]) {
#pragma clang __debug captured
{
vla_arr[0] = 1;
}
- // CHECK-3: test4([[INT:i.+]] {{.*}}[[SIZE:%.+]], [[INT]]*
- // CHECK-3: store [[INT]] {{.*}}[[SIZE]], [[INT]]* [[SIZE_ADDR:%.+]],
+ // CHECK-3: test4([[INTPTR_T:i.+]] {{.*}}[[SIZE_ARG:%.+]], [[INTPTR_T]]*
+ // CHECK-3: store [[INTPTR_T]] {{.*}}[[SIZE_ARG]], [[INTPTR_T]]* [[SIZE_ADDR:%.+]],
+ // CHECK-3: [[SIZE:%.+]] = load [[INTPTR_T]]* [[SIZE_ADDR]],
// CHECK-3: [[REF:%.+]] = getelementptr inbounds
- // CHECK-3: store [[INT]]* [[SIZE_ADDR]], [[INT]]** [[REF]]
+ // CHECK-3: store [[INTPTR_T]] [[SIZE]], [[INTPTR_T]]* [[REF]]
// CHECK-3: call void @__captured_stmt
}
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
index 00962e40f665..c41b37c39bc8 100644
--- a/test/CodeGen/catch-undef-behavior.c
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -1,61 +1,49 @@
-// RUN: %clang_cc1 -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
-// RUN: %clang_cc1 -fsanitize-undefined-trap-on-error -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-TRAP
-// RUN: %clang_cc1 -fsanitize=null -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-NULL
+// RUN: %clang_cc1 -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize-recover=alignment,null,object-size,shift,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-UBSAN
+// RUN: %clang_cc1 -fsanitize-undefined-trap-on-error -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize-recover=alignment,null,object-size,shift,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-TRAP
+// RUN: %clang_cc1 -fsanitize=null -fsanitize-recover=null -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-NULL
// RUN: %clang_cc1 -fsanitize=signed-integer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-OVERFLOW
-// CHECK: @[[INT:.*]] = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" }
+// CHECK-UBSAN: @[[INT:.*]] = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" }
// FIXME: When we only emit each type once, use [[INT]] more below.
-// CHECK: @[[LINE_100:.*]] = private unnamed_addr global {{.*}}, i32 100, i32 5 {{.*}} @[[INT]], i64 4, i8 1
-// CHECK: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 10 {{.*}}, i64 4, i8 0
-// CHECK: @[[LINE_300:.*]] = {{.*}}, i32 300, i32 12 {{.*}} @{{.*}}, {{.*}} @{{.*}}
-// CHECK: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 12 {{.*}} @{{.*}}, {{.*}} @{{.*}}
-// CHECK: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 10 {{.*}} @{{.*}}, i64 4, i8 0 }
-// CHECK: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 3 {{.*}} @{{.*}}, i64 4, i8 1 }
+// CHECK-UBSAN: @[[LINE_100:.*]] = private unnamed_addr global {{.*}}, i32 100, i32 5 {{.*}} @[[INT]], i64 4, i8 1
+// CHECK-UBSAN: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 10 {{.*}}, i64 4, i8 0
+// CHECK-UBSAN: @[[LINE_300:.*]] = {{.*}}, i32 300, i32 12 {{.*}} @{{.*}}, {{.*}} @{{.*}}
+// CHECK-UBSAN: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 12 {{.*}} @{{.*}}, {{.*}} @{{.*}}
+// CHECK-UBSAN: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 10 {{.*}} @{{.*}}, i64 4, i8 0 }
+// CHECK-UBSAN: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 3 {{.*}} @{{.*}}, i64 4, i8 1 }
-// CHECK: @[[STRUCT_S:.*]] = private unnamed_addr constant { i16, i16, [11 x i8] } { i16 -1, i16 0, [11 x i8] c"'struct S'\00" }
+// CHECK-UBSAN: @[[STRUCT_S:.*]] = private unnamed_addr constant { i16, i16, [11 x i8] } { i16 -1, i16 0, [11 x i8] c"'struct S'\00" }
-// CHECK: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 14 {{.*}} @[[STRUCT_S]], i64 4, i8 3 }
-// CHECK: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 12 {{.*}} @{{.*}} }
-// CHECK: @[[LINE_900:.*]] = {{.*}}, i32 900, i32 11 {{.*}} @{{.*}} }
+// CHECK-UBSAN: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 14 {{.*}} @[[STRUCT_S]], i64 4, i8 3 }
+// CHECK-UBSAN: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 12 {{.*}} @{{.*}} }
+// CHECK-UBSAN: @[[LINE_900:.*]] = {{.*}}, i32 900, i32 11 {{.*}} @{{.*}} }
// CHECK-NULL: @[[LINE_100:.*]] = private unnamed_addr global {{.*}}, i32 100, i32 5 {{.*}}
// PR6805
-// CHECK-LABEL: @foo
+// CHECK-COMMON-LABEL: @foo
// CHECK-NULL-LABEL: @foo
-// CHECK-TRAP-LABEL: @foo
void foo() {
union { int i; } u;
- // CHECK: %[[CHECK0:.*]] = icmp ne {{.*}}* %[[PTR:.*]], null
- // CHECK-TRAP: %[[CHECK0:.*]] = icmp ne {{.*}}* %[[PTR:.*]], null
+ // CHECK-COMMON: %[[CHECK0:.*]] = icmp ne {{.*}}* %[[PTR:.*]], null
- // CHECK: %[[I8PTR:.*]] = bitcast i32* %[[PTR]] to i8*
- // CHECK-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* %[[I8PTR]], i1 false)
- // CHECK-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
- // CHECK-NEXT: %[[CHECK01:.*]] = and i1 %[[CHECK0]], %[[CHECK1]]
+ // CHECK-COMMON: %[[I8PTR:.*]] = bitcast i32* %[[PTR]] to i8*
+ // CHECK-COMMON-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* %[[I8PTR]], i1 false)
+ // CHECK-COMMON-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
- // CHECK-TRAP: %[[I8PTR:.*]] = bitcast i32* %[[PTR]] to i8*
- // CHECK-TRAP-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* %[[I8PTR]], i1 false)
- // CHECK-TRAP-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
- // CHECK-TRAP-NEXT: %[[CHECK01:.*]] = and i1 %[[CHECK0]], %[[CHECK1]]
+ // CHECK-COMMON: %[[PTRTOINT:.*]] = ptrtoint {{.*}}* %[[PTR]] to i64
+ // CHECK-COMMON-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRTOINT]], 3
+ // CHECK-COMMON-NEXT: %[[CHECK2:.*]] = icmp eq i64 %[[MISALIGN]], 0
- // CHECK: %[[PTRTOINT:.*]] = ptrtoint {{.*}}* %[[PTR]] to i64
- // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRTOINT]], 3
- // CHECK-NEXT: %[[CHECK2:.*]] = icmp eq i64 %[[MISALIGN]], 0
+ // CHECK-COMMON: %[[CHECK01:.*]] = and i1 %[[CHECK0]], %[[CHECK1]]
+ // CHECK-COMMON-NEXT: %[[OK:.*]] = and i1 %[[CHECK01]], %[[CHECK2]]
- // CHECK-TRAP: %[[PTRTOINT:.*]] = ptrtoint {{.*}}* %[[PTR]] to i64
- // CHECK-TRAP-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRTOINT]], 3
- // CHECK-TRAP-NEXT: %[[CHECK2:.*]] = icmp eq i64 %[[MISALIGN]], 0
+ // CHECK-UBSAN: br i1 %[[OK]], {{.*}} !prof ![[WEIGHT_MD:.*]], !nosanitize
+ // CHECK-TRAP: br i1 %[[OK]], {{.*}}
- // CHECK: %[[OK:.*]] = and i1 %[[CHECK01]], %[[CHECK2]]
- // CHECK-NEXT: br i1 %[[OK]], {{.*}} !prof ![[WEIGHT_MD:.*]], !nosanitize
-
- // CHECK-TRAP: %[[OK:.*]] = and i1 %[[CHECK01]], %[[CHECK2]]
- // CHECK-TRAP-NEXT: br i1 %[[OK]], {{.*}}
-
- // CHECK: %[[ARG:.*]] = ptrtoint {{.*}} %[[PTR]] to i64
- // CHECK-NEXT: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_100]] to i8*), i64 %[[ARG]])
+ // CHECK-UBSAN: %[[ARG:.*]] = ptrtoint {{.*}} %[[PTR]] to i64
+ // CHECK-UBSAN-NEXT: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_100]] to i8*), i64 %[[ARG]])
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW:#[0-9]+]]
// CHECK-TRAP-NEXT: unreachable
@@ -68,25 +56,17 @@ void foo() {
u.i=1;
}
-// CHECK-LABEL: @bar
-// CHECK-TRAP-LABEL: @bar
+// CHECK-COMMON-LABEL: @bar
int bar(int *a) {
- // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
- // CHECK-NEXT: icmp uge i64 %[[SIZE]], 4
-
- // CHECK-TRAP: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
- // CHECK-TRAP-NEXT: icmp uge i64 %[[SIZE]], 4
+ // CHECK-COMMON: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-COMMON-NEXT: icmp uge i64 %[[SIZE]], 4
- // CHECK: %[[PTRINT:.*]] = ptrtoint
- // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
- // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+ // CHECK-COMMON: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-COMMON-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
+ // CHECK-COMMON-NEXT: icmp eq i64 %[[MISALIGN]], 0
- // CHECK-TRAP: %[[PTRINT:.*]] = ptrtoint
- // CHECK-TRAP-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
- // CHECK-TRAP-NEXT: icmp eq i64 %[[MISALIGN]], 0
-
- // CHECK: %[[ARG:.*]] = ptrtoint
- // CHECK-NEXT: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_200]] to i8*), i64 %[[ARG]])
+ // CHECK-UBSAN: %[[ARG:.*]] = ptrtoint
+ // CHECK-UBSAN-NEXT: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_200]] to i8*), i64 %[[ARG]])
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
@@ -95,85 +75,62 @@ int bar(int *a) {
return *a;
}
-// CHECK-LABEL: @addr_space
+// CHECK-UBSAN-LABEL: @addr_space
int addr_space(int __attribute__((address_space(256))) *a) {
- // CHECK-NOT: __ubsan
+ // CHECK-UBSAN-NOT: __ubsan
return *a;
}
-// CHECK-LABEL: @lsh_overflow
-// CHECK-TRAP-LABEL: @lsh_overflow
+// CHECK-COMMON-LABEL: @lsh_overflow
int lsh_overflow(int a, int b) {
- // CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
- // CHECK-NEXT: br i1 %[[INBOUNDS]], label %[[CHECKBB:.*]], label %[[CONTBB:.*]]
-
- // CHECK-TRAP: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
- // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]], label %[[CHECKBB:.*]], label %[[CONTBB:.*]]
+ // CHECK-COMMON: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
+ // CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]], label %[[CHECKBB:.*]], label %[[CONTBB:.*]]
- // CHECK: %[[SHIFTED_OUT_WIDTH:.*]] = sub nuw nsw i32 31, %[[RHS]]
- // CHECK-NEXT: %[[SHIFTED_OUT:.*]] = lshr i32 %[[LHS:.*]], %[[SHIFTED_OUT_WIDTH]]
- // CHECK-NEXT: %[[NO_OVERFLOW:.*]] = icmp eq i32 %[[SHIFTED_OUT]], 0
- // CHECK-NEXT: br label %[[CONTBB]]
+ // CHECK-COMMON: %[[SHIFTED_OUT_WIDTH:.*]] = sub nuw nsw i32 31, %[[RHS]]
+ // CHECK-COMMON-NEXT: %[[SHIFTED_OUT:.*]] = lshr i32 %[[LHS:.*]], %[[SHIFTED_OUT_WIDTH]]
+ // CHECK-COMMON-NEXT: %[[NO_OVERFLOW:.*]] = icmp eq i32 %[[SHIFTED_OUT]], 0
+ // CHECK-COMMON-NEXT: br label %[[CONTBB]]
- // CHECK-TRAP: %[[SHIFTED_OUT_WIDTH:.*]] = sub nuw nsw i32 31, %[[RHS]]
- // CHECK-TRAP-NEXT: %[[SHIFTED_OUT:.*]] = lshr i32 %[[LHS:.*]], %[[SHIFTED_OUT_WIDTH]]
- // CHECK-TRAP-NEXT: %[[NO_OVERFLOW:.*]] = icmp eq i32 %[[SHIFTED_OUT]], 0
- // CHECK-TRAP-NEXT: br label %[[CONTBB]]
+ // CHECK-COMMON: %[[VALID:.*]] = phi i1 [ %[[INBOUNDS]], {{.*}} ], [ %[[NO_OVERFLOW]], %[[CHECKBB]] ]
+ // CHECK-UBSAN: br i1 %[[VALID]], {{.*}} !prof ![[WEIGHT_MD]]
+ // CHECK-TRAP: br i1 %[[VALID]]
- // CHECK: %[[VALID:.*]] = phi i1 [ %[[INBOUNDS]], {{.*}} ], [ %[[NO_OVERFLOW]], %[[CHECKBB]] ]
- // CHECK-NEXT: br i1 %[[VALID]], {{.*}} !prof ![[WEIGHT_MD]]
-
- // CHECK-TRAP: %[[VALID:.*]] = phi i1 [ %[[INBOUNDS]], {{.*}} ], [ %[[NO_OVERFLOW]], %[[CHECKBB]] ]
- // CHECK-TRAP-NEXT: br i1 %[[VALID]]
-
-
- // CHECK: %[[ARG1:.*]] = zext
- // CHECK-NEXT: %[[ARG2:.*]] = zext
- // CHECK-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_300]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]])
- // CHECK-NOT: call void @__ubsan_handle_shift_out_of_bounds
+ // CHECK-UBSAN: %[[ARG1:.*]] = zext
+ // CHECK-UBSAN-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-UBSAN-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_300]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]])
+ // CHECK-UBSAN-NOT: call void @__ubsan_handle_shift_out_of_bounds
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP: unreachable
// CHECK-TRAP-NOT: call void @llvm.trap()
- // CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
- // CHECK-NEXT: ret i32 %[[RET]]
-
- // CHECK-TRAP: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
- // CHECK-TRAP-NEXT: ret i32 %[[RET]]
+ // CHECK-COMMON: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
+ // CHECK-COMMON-NEXT: ret i32 %[[RET]]
#line 300
return a << b;
}
-// CHECK-LABEL: @rsh_inbounds
-// CHECK-TRAP-LABEL: @rsh_inbounds
+// CHECK-COMMON-LABEL: @rsh_inbounds
int rsh_inbounds(int a, int b) {
- // CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
- // CHECK: br i1 %[[INBOUNDS]]
+ // CHECK-COMMON: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
+ // CHECK-COMMON: br i1 %[[INBOUNDS]]
- // CHECK-TRAP: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
- // CHECK-TRAP: br i1 %[[INBOUNDS]]
-
- // CHECK: %[[ARG1:.*]] = zext
- // CHECK-NEXT: %[[ARG2:.*]] = zext
- // CHECK-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_400]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]])
+ // CHECK-UBSAN: %[[ARG1:.*]] = zext
+ // CHECK-UBSAN-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-UBSAN-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_400]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]])
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
- // CHECK: %[[RET:.*]] = ashr i32 %[[LHS]], %[[RHS]]
- // CHECK-NEXT: ret i32 %[[RET]]
-
- // CHECK-TRAP: %[[RET:.*]] = ashr i32 %[[LHS]], %[[RHS]]
- // CHECK-TRAP-NEXT: ret i32 %[[RET]]
+ // CHECK-COMMON: %[[RET:.*]] = ashr i32 %[[LHS]], %[[RHS]]
+ // CHECK-COMMON-NEXT: ret i32 %[[RET]]
#line 400
return a >> b;
}
-// CHECK-LABEL: @load
-// CHECK-TRAP-LABEL: @load
+// CHECK-COMMON-LABEL: @load
int load(int *p) {
- // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_500]] to i8*), i64 %{{.*}})
+ // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_500]] to i8*), i64 %{{.*}})
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
@@ -181,10 +138,9 @@ int load(int *p) {
return *p;
}
-// CHECK-LABEL: @store
-// CHECK-TRAP-LABEL: @store
+// CHECK-COMMON-LABEL: @store
void store(int *p, int q) {
- // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_600]] to i8*), i64 %{{.*}})
+ // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_600]] to i8*), i64 %{{.*}})
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
@@ -194,10 +150,9 @@ void store(int *p, int q) {
struct S { int k; };
-// CHECK-LABEL: @member_access
-// CHECK-TRAP-LABEL: @member_access
+// CHECK-COMMON-LABEL: @member_access
int *member_access(struct S *p) {
- // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_700]] to i8*), i64 %{{.*}})
+ // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_700]] to i8*), i64 %{{.*}})
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
@@ -205,12 +160,11 @@ int *member_access(struct S *p) {
return &p->k;
}
-// CHECK-LABEL: @signed_overflow
-// CHECK-TRAP-LABEL: @signed_overflow
+// CHECK-COMMON-LABEL: @signed_overflow
int signed_overflow(int a, int b) {
- // CHECK: %[[ARG1:.*]] = zext
- // CHECK-NEXT: %[[ARG2:.*]] = zext
- // CHECK-NEXT: call void @__ubsan_handle_add_overflow(i8* bitcast ({{.*}} @[[LINE_800]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]])
+ // CHECK-UBSAN: %[[ARG1:.*]] = zext
+ // CHECK-UBSAN-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-UBSAN-NEXT: call void @__ubsan_handle_add_overflow(i8* bitcast ({{.*}} @[[LINE_800]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]])
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
@@ -218,220 +172,213 @@ int signed_overflow(int a, int b) {
return a + b;
}
-// CHECK-LABEL: @no_return
-// CHECK-TRAP-LABEL: @no_return
+// CHECK-COMMON-LABEL: @no_return
int no_return() {
// Reaching the end of a noreturn function is fine in C.
// FIXME: If the user explicitly requests -fsanitize=return, we should catch
// that here even though it's not undefined behavior.
- // CHECK-NOT: call
- // CHECK-NOT: unreachable
- // CHECK: ret i32
-
- // CHECK-TRAP-NOT: call
- // CHECK-TRAP-NOT: unreachable
- // CHECK-TRAP: ret i32
+ // CHECK-COMMON-NOT: call
+ // CHECK-COMMON-NOT: unreachable
+ // CHECK-COMMON: ret i32
}
-// CHECK-LABEL: @vla_bound
+// CHECK-UBSAN-LABEL: @vla_bound
void vla_bound(int n) {
- // CHECK: icmp sgt i32 %[[PARAM:.*]], 0
+ // CHECK-UBSAN: icmp sgt i32 %[[PARAM:.*]], 0
//
- // CHECK: %[[ARG:.*]] = zext i32 %[[PARAM]] to i64
- // CHECK-NEXT: call void @__ubsan_handle_vla_bound_not_positive(i8* bitcast ({{.*}} @[[LINE_900]] to i8*), i64 %[[ARG]])
+ // CHECK-UBSAN: %[[ARG:.*]] = zext i32 %[[PARAM]] to i64
+ // CHECK-UBSAN-NEXT: call void @__ubsan_handle_vla_bound_not_positive(i8* bitcast ({{.*}} @[[LINE_900]] to i8*), i64 %[[ARG]])
#line 900
int arr[n * 3];
}
-// CHECK-LABEL: @int_float_no_overflow
+// CHECK-UBSAN-LABEL: @int_float_no_overflow
float int_float_no_overflow(__int128 n) {
- // CHECK-NOT: call void @__ubsan_handle
+ // CHECK-UBSAN-NOT: call void @__ubsan_handle
return n;
}
-// CHECK-LABEL: @int_float_overflow
-// CHECK-TRAP-LABEL: @int_float_overflow
+// CHECK-COMMON-LABEL: @int_float_overflow
float int_float_overflow(unsigned __int128 n) {
// This is 2**104. FLT_MAX is 2**128 - 2**104.
- // CHECK: icmp ule i128 %{{.*}}, -20282409603651670423947251286016
- // CHECK: call void @__ubsan_handle_float_cast_overflow(
+ // CHECK-COMMON: %[[INBOUNDS:.*]] = icmp ule i128 %{{.*}}, -20282409603651670423947251286016
+ // CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]]
- // CHECK-TRAP: %[[INBOUNDS:.*]] = icmp ule i128 %{{.*}}, -20282409603651670423947251286016
- // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+ // CHECK-UBSAN: call void @__ubsan_handle_float_cast_overflow(
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
return n;
}
-// CHECK-LABEL: @int_fp16_overflow
-// CHECK-TRAP-LABEL: @int_fp16_overflow
+// CHECK-COMMON-LABEL: @int_fp16_overflow
void int_fp16_overflow(int n, __fp16 *p) {
- // CHECK: %[[GE:.*]] = icmp sge i32 %{{.*}}, -65504
- // CHECK: %[[LE:.*]] = icmp sle i32 %{{.*}}, 65504
- // CHECK: and i1 %[[GE]], %[[LE]]
- // CHECK: call void @__ubsan_handle_float_cast_overflow(
+ // CHECK-COMMON: %[[GE:.*]] = icmp sge i32 %{{.*}}, -65504
+ // CHECK-COMMON: %[[LE:.*]] = icmp sle i32 %{{.*}}, 65504
+ // CHECK-COMMON: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]]
- // CHECK-TRAP: %[[GE:.*]] = icmp sge i32 %{{.*}}, -65504
- // CHECK-TRAP: %[[LE:.*]] = icmp sle i32 %{{.*}}, 65504
- // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
- // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+ // CHECK-UBSAN: call void @__ubsan_handle_float_cast_overflow(
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
*p = n;
}
-// CHECK-LABEL: @float_int_overflow
-// CHECK-TRAP-LABEL: @float_int_overflow
+// CHECK-COMMON-LABEL: @float_int_overflow
int float_int_overflow(float f) {
- // CHECK: %[[GE:.*]] = fcmp ogt float %[[F:.*]], 0xC1E0000020000000
- // CHECK: %[[LE:.*]] = fcmp olt float %[[F]], 0x41E0000000000000
- // CHECK: and i1 %[[GE]], %[[LE]]
-
- // CHECK: %[[CAST:.*]] = bitcast float %[[F]] to i32
- // CHECK: %[[ARG:.*]] = zext i32 %[[CAST]] to i64
- // CHECK: call void @__ubsan_handle_float_cast_overflow({{.*}}, i64 %[[ARG]]
+ // CHECK-COMMON: %[[GE:.*]] = fcmp ogt float %[[F:.*]], 0xC1E0000020000000
+ // CHECK-COMMON: %[[LE:.*]] = fcmp olt float %[[F]], 0x41E0000000000000
+ // CHECK-COMMON: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]]
- // CHECK-TRAP: %[[GE:.*]] = fcmp ogt float %[[F:.*]], 0xC1E0000020000000
- // CHECK-TRAP: %[[LE:.*]] = fcmp olt float %[[F]], 0x41E0000000000000
- // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
- // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+ // CHECK-UBSAN: %[[CAST:.*]] = bitcast float %[[F]] to i32
+ // CHECK-UBSAN: %[[ARG:.*]] = zext i32 %[[CAST]] to i64
+ // CHECK-UBSAN: call void @__ubsan_handle_float_cast_overflow({{.*}}, i64 %[[ARG]]
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
return f;
}
-// CHECK-LABEL: @long_double_int_overflow
-// CHECK-TRAP-LABEL: @long_double_int_overflow
+// CHECK-COMMON-LABEL: @long_double_int_overflow
int long_double_int_overflow(long double ld) {
- // CHECK: alloca x86_fp80
- // CHECK: %[[GE:.*]] = fcmp ogt x86_fp80 %[[F:.*]], 0xKC01E8000000100000000
- // CHECK: %[[LE:.*]] = fcmp olt x86_fp80 %[[F]], 0xK401E8000000000000000
- // CHECK: and i1 %[[GE]], %[[LE]]
+ // CHECK-UBSAN: alloca x86_fp80
- // CHECK: store x86_fp80 %[[F]], x86_fp80* %[[ALLOCA:.*]], !nosanitize
- // CHECK: %[[ARG:.*]] = ptrtoint x86_fp80* %[[ALLOCA]] to i64
- // CHECK: call void @__ubsan_handle_float_cast_overflow({{.*}}, i64 %[[ARG]]
+ // CHECK-COMMON: %[[GE:.*]] = fcmp ogt x86_fp80 %[[F:.*]], 0xKC01E800000010000000
+ // CHECK-COMMON: %[[LE:.*]] = fcmp olt x86_fp80 %[[F]], 0xK401E800000000000000
+ // CHECK-COMMON: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]]
- // CHECK-TRAP: %[[GE:.*]] = fcmp ogt x86_fp80 %[[F:.*]], 0xKC01E800000010000000
- // CHECK-TRAP: %[[LE:.*]] = fcmp olt x86_fp80 %[[F]], 0xK401E800000000000000
- // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
- // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+ // CHECK-UBSAN: store x86_fp80 %[[F]], x86_fp80* %[[ALLOCA:.*]], !nosanitize
+ // CHECK-UBSAN: %[[ARG:.*]] = ptrtoint x86_fp80* %[[ALLOCA]] to i64
+ // CHECK-UBSAN: call void @__ubsan_handle_float_cast_overflow({{.*}}, i64 %[[ARG]]
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
return ld;
}
-// CHECK-LABEL: @float_uint_overflow
-// CHECK-TRAP-LABEL: @float_uint_overflow
+// CHECK-COMMON-LABEL: @float_uint_overflow
unsigned float_uint_overflow(float f) {
- // CHECK: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.{{0*}}e+00
- // CHECK: %[[LE:.*]] = fcmp olt float %[[F]], 0x41F0000000000000
- // CHECK: and i1 %[[GE]], %[[LE]]
- // CHECK: call void @__ubsan_handle_float_cast_overflow(
+ // CHECK-COMMON: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.{{0*}}e+00
+ // CHECK-COMMON: %[[LE:.*]] = fcmp olt float %[[F]], 0x41F0000000000000
+ // CHECK-COMMON: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]]
- // CHECK-TRAP: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.{{0*}}e+00
- // CHECK-TRAP: %[[LE:.*]] = fcmp olt float %[[F]], 0x41F0000000000000
- // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
- // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+ // CHECK-UBSAN: call void @__ubsan_handle_float_cast_overflow(
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
return f;
}
-// CHECK-LABEL: @fp16_char_overflow
-// CHECK-TRAP-LABEL: @fp16_char_overflow
+// CHECK-COMMON-LABEL: @fp16_char_overflow
signed char fp16_char_overflow(__fp16 *p) {
- // CHECK: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.29{{0*}}e+02
- // CHECK: %[[LE:.*]] = fcmp olt float %[[F]], 1.28{{0*}}e+02
- // CHECK: and i1 %[[GE]], %[[LE]]
- // CHECK: call void @__ubsan_handle_float_cast_overflow(
+ // CHECK-COMMON: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.29{{0*}}e+02
+ // CHECK-COMMON: %[[LE:.*]] = fcmp olt float %[[F]], 1.28{{0*}}e+02
+ // CHECK-COMMON: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]]
- // CHECK-TRAP: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.29{{0*}}e+02
- // CHECK-TRAP: %[[LE:.*]] = fcmp olt float %[[F]], 1.28{{0*}}e+02
- // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
- // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+ // CHECK-UBSAN: call void @__ubsan_handle_float_cast_overflow(
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
return *p;
}
-// CHECK-LABEL: @float_float_overflow
-// CHECK-TRAP-LABEL: @float_float_overflow
+// CHECK-COMMON-LABEL: @float_float_overflow
float float_float_overflow(double f) {
- // CHECK: %[[F:.*]] = call double @llvm.fabs.f64(
- // CHECK: %[[GE:.*]] = fcmp ogt double %[[F]], 0x47EFFFFFE0000000
- // CHECK: %[[LE:.*]] = fcmp olt double %[[F]], 0x7FF0000000000000
- // CHECK: and i1 %[[GE]], %[[LE]]
- // CHECK: call void @__ubsan_handle_float_cast_overflow(
-
- // CHECK-TRAP: %[[F:.*]] = call double @llvm.fabs.f64(
- // CHECK-TRAP: %[[GE:.*]] = fcmp ogt double %[[F]], 0x47EFFFFFE0000000
- // CHECK-TRAP: %[[LE:.*]] = fcmp olt double %[[F]], 0x7FF0000000000000
- // CHECK-TRAP: %[[OUTOFBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
- // CHECK-TRAP: %[[INBOUNDS:.*]] = xor i1 %[[OUTOFBOUNDS]], true
- // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+ // CHECK-COMMON: %[[F:.*]] = call double @llvm.fabs.f64(
+ // CHECK-COMMON: %[[GE:.*]] = fcmp ogt double %[[F]], 0x47EFFFFFE0000000
+ // CHECK-COMMON: %[[LE:.*]] = fcmp olt double %[[F]], 0x7FF0000000000000
+ // CHECK-COMMON: %[[OUTOFBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-COMMON: %[[INBOUNDS:.*]] = xor i1 %[[OUTOFBOUNDS]], true
+ // CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK-UBSAN: call void @__ubsan_handle_float_cast_overflow(
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
return f;
}
-// CHECK-LABEL: @int_divide_overflow
+// CHECK-COMMON-LABEL: @int_divide_overflow
// CHECK-OVERFLOW-LABEL: @int_divide_overflow
int int_divide_overflow(int a, int b) {
- // CHECK: %[[ZERO:.*]] = icmp ne i32 %[[B:.*]], 0
+ // CHECK-COMMON: %[[ZERO:.*]] = icmp ne i32 %[[B:.*]], 0
// CHECK-OVERFLOW-NOT: icmp ne i32 %{{.*}}, 0
- // CHECK-TRAP: %[[ZERO:.*]] = icmp ne i32 %[[B:.*]], 0
- // CHECK: %[[AOK:.*]] = icmp ne i32 %[[A:.*]], -2147483648
- // CHECK-NEXT: %[[BOK:.*]] = icmp ne i32 %[[B]], -1
- // CHECK-NEXT: %[[OVER:.*]] = or i1 %[[AOK]], %[[BOK]]
+ // CHECK-COMMON: %[[AOK:.*]] = icmp ne i32 %[[A:.*]], -2147483648
+ // CHECK-COMMON-NEXT: %[[BOK:.*]] = icmp ne i32 %[[B]], -1
+ // CHECK-COMMON-NEXT: %[[OVER:.*]] = or i1 %[[AOK]], %[[BOK]]
+ // CHECK-COMMON: %[[OK:.*]] = and i1 %[[ZERO]], %[[OVER]]
+ // CHECK-COMMON: br i1 %[[OK]]
// CHECK-OVERFLOW: %[[AOK:.*]] = icmp ne i32 %[[A:.*]], -2147483648
// CHECK-OVERFLOW-NEXT: %[[BOK:.*]] = icmp ne i32 %[[B:.*]], -1
// CHECK-OVERFLOW-NEXT: %[[OK:.*]] = or i1 %[[AOK]], %[[BOK]]
-
- // CHECK-TRAP: %[[AOK:.*]] = icmp ne i32 %[[A:.*]], -2147483648
- // CHECK-TRAP-NEXT: %[[BOK:.*]] = icmp ne i32 %[[B]], -1
- // CHECK-TRAP-NEXT: %[[OVER:.*]] = or i1 %[[AOK]], %[[BOK]]
-
- // CHECK: %[[OK:.*]] = and i1 %[[ZERO]], %[[OVER]]
-
- // CHECK: br i1 %[[OK]]
// CHECK-OVERFLOW: br i1 %[[OK]]
- // CHECK-TRAP: %[[OK:.*]] = and i1 %[[ZERO]], %[[OVER]]
- // CHECK-TRAP: br i1 %[[OK]]
-
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP: unreachable
return a / b;
- // CHECK: }
+ // CHECK-COMMON: }
// CHECK-OVERFLOW: }
- // CHECK-TRAP: }
}
-// CHECK-LABEL: @sour_bool
+// CHECK-COMMON-LABEL: @sour_bool
_Bool sour_bool(_Bool *p) {
- // CHECK: %[[OK:.*]] = icmp ule i8 {{.*}}, 1
- // CHECK: br i1 %[[OK]]
- // CHECK: call void @__ubsan_handle_load_invalid_value(i8* bitcast ({{.*}}), i64 {{.*}})
+ // CHECK-COMMON: %[[OK:.*]] = icmp ule i8 {{.*}}, 1
+ // CHECK-COMMON: br i1 %[[OK]]
- // CHECK-TRAP: %[[OK:.*]] = icmp ule i8 {{.*}}, 1
- // CHECK-TRAP: br i1 %[[OK]]
+ // CHECK-UBSAN: call void @__ubsan_handle_load_invalid_value(i8* bitcast ({{.*}}), i64 {{.*}})
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP: unreachable
return *p;
}
-// CHECK: ![[WEIGHT_MD]] = metadata !{metadata !"branch_weights", i32 1048575, i32 1}
+// CHECK-COMMON-LABEL: @ret_nonnull
+__attribute__((returns_nonnull))
+int *ret_nonnull(int *a) {
+ // CHECK-COMMON: [[OK:%.*]] = icmp ne i32* {{.*}}, null
+ // CHECK-COMMON: br i1 [[OK]]
+
+ // CHECK-UBSAN: call void @__ubsan_handle_nonnull_return
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP: unreachable
+ return a;
+}
+
+// CHECK-COMMON-LABEL: @call_decl_nonnull
+__attribute__((nonnull)) void decl_nonnull(int *a);
+void call_decl_nonnull(int *a) {
+ // CHECK-COMMON: [[OK:%.*]] = icmp ne i32* {{.*}}, null
+ // CHECK-COMMON: br i1 [[OK]]
+
+ // CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP: unreachable
+ decl_nonnull(a);
+}
+
+// CHECK-COMMON-LABEL: @call_nonnull_variadic
+__attribute__((nonnull)) void nonnull_variadic(int a, ...);
+void call_nonnull_variadic(int a, int *b) {
+ // CHECK-COMMON: [[OK:%.*]] = icmp ne i32* {{.*}}, null
+ // CHECK-COMMON: br i1 [[OK]]
+
+ // CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
+ // CHECK-UBSAN-NOT: __ubsan_handle_nonnull_arg
+
+ // CHECK-COMMON: call void (i32, ...)* @nonnull_variadic
+ nonnull_variadic(a, b);
+}
+
+// CHECK-UBSAN: ![[WEIGHT_MD]] = !{!"branch_weights", i32 1048575, i32 1}
// CHECK-TRAP: attributes [[NR_NUW]] = { noreturn nounwind }
diff --git a/test/CodeGen/complex-math.c b/test/CodeGen/complex-math.c
new file mode 100644
index 000000000000..36ef271b0ae0
--- /dev/null
+++ b/test/CodeGen/complex-math.c
@@ -0,0 +1,481 @@
+// RUN: %clang_cc1 %s -O1 -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s --check-prefix=X86
+// RUN: %clang_cc1 %s -O1 -emit-llvm -triple x86_64-pc-win64 -o - | FileCheck %s --check-prefix=X86
+// RUN: %clang_cc1 %s -O1 -emit-llvm -triple i686-unknown-unknown -o - | FileCheck %s --check-prefix=X86
+// RUN: %clang_cc1 %s -O1 -emit-llvm -triple powerpc-unknown-unknown -o - | FileCheck %s --check-prefix=PPC
+// RUN: %clang_cc1 %s -O1 -emit-llvm -triple armv7-none-linux-gnueabihf -o - | FileCheck %s --check-prefix=ARM
+
+float _Complex add_float_rr(float a, float b) {
+ // X86-LABEL: @add_float_rr(
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+float _Complex add_float_cr(float _Complex a, float b) {
+ // X86-LABEL: @add_float_cr(
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+float _Complex add_float_rc(float a, float _Complex b) {
+ // X86-LABEL: @add_float_rc(
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+float _Complex add_float_cc(float _Complex a, float _Complex b) {
+ // X86-LABEL: @add_float_cc(
+ // X86: fadd
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+
+float _Complex sub_float_rr(float a, float b) {
+ // X86-LABEL: @sub_float_rr(
+ // X86: fsub
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+float _Complex sub_float_cr(float _Complex a, float b) {
+ // X86-LABEL: @sub_float_cr(
+ // X86: fsub
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+float _Complex sub_float_rc(float a, float _Complex b) {
+ // X86-LABEL: @sub_float_rc(
+ // X86: fsub
+ // X86: fsub float -0.{{0+}}e+00,
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+float _Complex sub_float_cc(float _Complex a, float _Complex b) {
+ // X86-LABEL: @sub_float_cc(
+ // X86: fsub
+ // X86: fsub
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+
+float _Complex mul_float_rr(float a, float b) {
+ // X86-LABEL: @mul_float_rr(
+ // X86: fmul
+ // X86-NOT: fmul
+ // X86: ret
+ return a * b;
+}
+float _Complex mul_float_cr(float _Complex a, float b) {
+ // X86-LABEL: @mul_float_cr(
+ // X86: fmul
+ // X86: fmul
+ // X86-NOT: fmul
+ // X86: ret
+ return a * b;
+}
+float _Complex mul_float_rc(float a, float _Complex b) {
+ // X86-LABEL: @mul_float_rc(
+ // X86: fmul
+ // X86: fmul
+ // X86-NOT: fmul
+ // X86: ret
+ return a * b;
+}
+float _Complex mul_float_cc(float _Complex a, float _Complex b) {
+ // X86-LABEL: @mul_float_cc(
+ // X86: %[[AC:[^ ]+]] = fmul
+ // X86: %[[BD:[^ ]+]] = fmul
+ // X86: %[[AD:[^ ]+]] = fmul
+ // X86: %[[BC:[^ ]+]] = fmul
+ // X86: %[[RR:[^ ]+]] = fsub float %[[AC]], %[[BD]]
+ // X86: %[[RI:[^ ]+]] = fadd float
+ // X86-DAG: %[[AD]]
+ // X86-DAG: ,
+ // X86-DAG: %[[BC]]
+ // X86: fcmp uno float %[[RR]]
+ // X86: fcmp uno float %[[RI]]
+ // X86: call {{.*}} @__mulsc3(
+ // X86: ret
+ return a * b;
+}
+
+float _Complex div_float_rr(float a, float b) {
+ // X86-LABEL: @div_float_rr(
+ // X86: fdiv
+ // X86-NOT: fdiv
+ // X86: ret
+ return a / b;
+}
+float _Complex div_float_cr(float _Complex a, float b) {
+ // X86-LABEL: @div_float_cr(
+ // X86: fdiv
+ // X86: fdiv
+ // X86-NOT: fdiv
+ // X86: ret
+ return a / b;
+}
+float _Complex div_float_rc(float a, float _Complex b) {
+ // X86-LABEL: @div_float_rc(
+ // X86-NOT: fdiv
+ // X86: call {{.*}} @__divsc3(
+ // X86: ret
+ return a / b;
+}
+float _Complex div_float_cc(float _Complex a, float _Complex b) {
+ // X86-LABEL: @div_float_cc(
+ // X86-NOT: fdiv
+ // X86: call {{.*}} @__divsc3(
+ // X86: ret
+ return a / b;
+}
+
+double _Complex add_double_rr(double a, double b) {
+ // X86-LABEL: @add_double_rr(
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+double _Complex add_double_cr(double _Complex a, double b) {
+ // X86-LABEL: @add_double_cr(
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+double _Complex add_double_rc(double a, double _Complex b) {
+ // X86-LABEL: @add_double_rc(
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+double _Complex add_double_cc(double _Complex a, double _Complex b) {
+ // X86-LABEL: @add_double_cc(
+ // X86: fadd
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+
+double _Complex sub_double_rr(double a, double b) {
+ // X86-LABEL: @sub_double_rr(
+ // X86: fsub
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+double _Complex sub_double_cr(double _Complex a, double b) {
+ // X86-LABEL: @sub_double_cr(
+ // X86: fsub
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+double _Complex sub_double_rc(double a, double _Complex b) {
+ // X86-LABEL: @sub_double_rc(
+ // X86: fsub
+ // X86: fsub double -0.{{0+}}e+00,
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+double _Complex sub_double_cc(double _Complex a, double _Complex b) {
+ // X86-LABEL: @sub_double_cc(
+ // X86: fsub
+ // X86: fsub
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+
+double _Complex mul_double_rr(double a, double b) {
+ // X86-LABEL: @mul_double_rr(
+ // X86: fmul
+ // X86-NOT: fmul
+ // X86: ret
+ return a * b;
+}
+double _Complex mul_double_cr(double _Complex a, double b) {
+ // X86-LABEL: @mul_double_cr(
+ // X86: fmul
+ // X86: fmul
+ // X86-NOT: fmul
+ // X86: ret
+ return a * b;
+}
+double _Complex mul_double_rc(double a, double _Complex b) {
+ // X86-LABEL: @mul_double_rc(
+ // X86: fmul
+ // X86: fmul
+ // X86-NOT: fmul
+ // X86: ret
+ return a * b;
+}
+double _Complex mul_double_cc(double _Complex a, double _Complex b) {
+ // X86-LABEL: @mul_double_cc(
+ // X86: %[[AC:[^ ]+]] = fmul
+ // X86: %[[BD:[^ ]+]] = fmul
+ // X86: %[[AD:[^ ]+]] = fmul
+ // X86: %[[BC:[^ ]+]] = fmul
+ // X86: %[[RR:[^ ]+]] = fsub double %[[AC]], %[[BD]]
+ // X86: %[[RI:[^ ]+]] = fadd double
+ // X86-DAG: %[[AD]]
+ // X86-DAG: ,
+ // X86-DAG: %[[BC]]
+ // X86: fcmp uno double %[[RR]]
+ // X86: fcmp uno double %[[RI]]
+ // X86: call {{.*}} @__muldc3(
+ // X86: ret
+ return a * b;
+}
+
+double _Complex div_double_rr(double a, double b) {
+ // X86-LABEL: @div_double_rr(
+ // X86: fdiv
+ // X86-NOT: fdiv
+ // X86: ret
+ return a / b;
+}
+double _Complex div_double_cr(double _Complex a, double b) {
+ // X86-LABEL: @div_double_cr(
+ // X86: fdiv
+ // X86: fdiv
+ // X86-NOT: fdiv
+ // X86: ret
+ return a / b;
+}
+double _Complex div_double_rc(double a, double _Complex b) {
+ // X86-LABEL: @div_double_rc(
+ // X86-NOT: fdiv
+ // X86: call {{.*}} @__divdc3(
+ // X86: ret
+ return a / b;
+}
+double _Complex div_double_cc(double _Complex a, double _Complex b) {
+ // X86-LABEL: @div_double_cc(
+ // X86-NOT: fdiv
+ // X86: call {{.*}} @__divdc3(
+ // X86: ret
+ return a / b;
+}
+
+long double _Complex add_long_double_rr(long double a, long double b) {
+ // X86-LABEL: @add_long_double_rr(
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+long double _Complex add_long_double_cr(long double _Complex a, long double b) {
+ // X86-LABEL: @add_long_double_cr(
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+long double _Complex add_long_double_rc(long double a, long double _Complex b) {
+ // X86-LABEL: @add_long_double_rc(
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+long double _Complex add_long_double_cc(long double _Complex a, long double _Complex b) {
+ // X86-LABEL: @add_long_double_cc(
+ // X86: fadd
+ // X86: fadd
+ // X86-NOT: fadd
+ // X86: ret
+ return a + b;
+}
+
+long double _Complex sub_long_double_rr(long double a, long double b) {
+ // X86-LABEL: @sub_long_double_rr(
+ // X86: fsub
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+long double _Complex sub_long_double_cr(long double _Complex a, long double b) {
+ // X86-LABEL: @sub_long_double_cr(
+ // X86: fsub
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+long double _Complex sub_long_double_rc(long double a, long double _Complex b) {
+ // X86-LABEL: @sub_long_double_rc(
+ // X86: fsub
+ // X86: fsub x86_fp80 0xK8{{0+}},
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+long double _Complex sub_long_double_cc(long double _Complex a, long double _Complex b) {
+ // X86-LABEL: @sub_long_double_cc(
+ // X86: fsub
+ // X86: fsub
+ // X86-NOT: fsub
+ // X86: ret
+ return a - b;
+}
+
+long double _Complex mul_long_double_rr(long double a, long double b) {
+ // X86-LABEL: @mul_long_double_rr(
+ // X86: fmul
+ // X86-NOT: fmul
+ // X86: ret
+ return a * b;
+}
+long double _Complex mul_long_double_cr(long double _Complex a, long double b) {
+ // X86-LABEL: @mul_long_double_cr(
+ // X86: fmul
+ // X86: fmul
+ // X86-NOT: fmul
+ // X86: ret
+ return a * b;
+}
+long double _Complex mul_long_double_rc(long double a, long double _Complex b) {
+ // X86-LABEL: @mul_long_double_rc(
+ // X86: fmul
+ // X86: fmul
+ // X86-NOT: fmul
+ // X86: ret
+ return a * b;
+}
+long double _Complex mul_long_double_cc(long double _Complex a, long double _Complex b) {
+ // X86-LABEL: @mul_long_double_cc(
+ // X86: %[[AC:[^ ]+]] = fmul
+ // X86: %[[BD:[^ ]+]] = fmul
+ // X86: %[[AD:[^ ]+]] = fmul
+ // X86: %[[BC:[^ ]+]] = fmul
+ // X86: %[[RR:[^ ]+]] = fsub x86_fp80 %[[AC]], %[[BD]]
+ // X86: %[[RI:[^ ]+]] = fadd x86_fp80
+ // X86-DAG: %[[AD]]
+ // X86-DAG: ,
+ // X86-DAG: %[[BC]]
+ // X86: fcmp uno x86_fp80 %[[RR]]
+ // X86: fcmp uno x86_fp80 %[[RI]]
+ // X86: call {{.*}} @__mulxc3(
+ // X86: ret
+ // PPC-LABEL: @mul_long_double_cc(
+ // PPC: %[[AC:[^ ]+]] = fmul
+ // PPC: %[[BD:[^ ]+]] = fmul
+ // PPC: %[[AD:[^ ]+]] = fmul
+ // PPC: %[[BC:[^ ]+]] = fmul
+ // PPC: %[[RR:[^ ]+]] = fsub ppc_fp128 %[[AC]], %[[BD]]
+ // PPC: %[[RI:[^ ]+]] = fadd ppc_fp128
+ // PPC-DAG: %[[AD]]
+ // PPC-DAG: ,
+ // PPC-DAG: %[[BC]]
+ // PPC: fcmp uno ppc_fp128 %[[RR]]
+ // PPC: fcmp uno ppc_fp128 %[[RI]]
+ // PPC: call {{.*}} @__multc3(
+ // PPC: ret
+ return a * b;
+}
+
+long double _Complex div_long_double_rr(long double a, long double b) {
+ // X86-LABEL: @div_long_double_rr(
+ // X86: fdiv
+ // X86-NOT: fdiv
+ // X86: ret
+ return a / b;
+}
+long double _Complex div_long_double_cr(long double _Complex a, long double b) {
+ // X86-LABEL: @div_long_double_cr(
+ // X86: fdiv
+ // X86: fdiv
+ // X86-NOT: fdiv
+ // X86: ret
+ return a / b;
+}
+long double _Complex div_long_double_rc(long double a, long double _Complex b) {
+ // X86-LABEL: @div_long_double_rc(
+ // X86-NOT: fdiv
+ // X86: call {{.*}} @__divxc3(
+ // X86: ret
+ // PPC-LABEL: @div_long_double_rc(
+ // PPC-NOT: fdiv
+ // PPC: call {{.*}} @__divtc3(
+ // PPC: ret
+ return a / b;
+}
+long double _Complex div_long_double_cc(long double _Complex a, long double _Complex b) {
+ // X86-LABEL: @div_long_double_cc(
+ // X86-NOT: fdiv
+ // X86: call {{.*}} @__divxc3(
+ // X86: ret
+ // PPC-LABEL: @div_long_double_cc(
+ // PPC-NOT: fdiv
+ // PPC: call {{.*}} @__divtc3(
+ // PPC: ret
+ return a / b;
+}
+
+// Comparison operators don't rely on library calls or have interseting math
+// properties, but test that mixed types work correctly here.
+_Bool eq_float_cr(float _Complex a, float b) {
+ // X86-LABEL: @eq_float_cr(
+ // X86: fcmp oeq
+ // X86: fcmp oeq
+ // X86: and i1
+ // X86: ret
+ return a == b;
+}
+_Bool eq_float_rc(float a, float _Complex b) {
+ // X86-LABEL: @eq_float_rc(
+ // X86: fcmp oeq
+ // X86: fcmp oeq
+ // X86: and i1
+ // X86: ret
+ return a == b;
+}
+_Bool eq_float_cc(float _Complex a, float _Complex b) {
+ // X86-LABEL: @eq_float_cc(
+ // X86: fcmp oeq
+ // X86: fcmp oeq
+ // X86: and i1
+ // X86: ret
+ return a == b;
+}
+_Bool ne_float_cr(float _Complex a, float b) {
+ // X86-LABEL: @ne_float_cr(
+ // X86: fcmp une
+ // X86: fcmp une
+ // X86: or i1
+ // X86: ret
+ return a != b;
+}
+_Bool ne_float_rc(float a, float _Complex b) {
+ // X86-LABEL: @ne_float_rc(
+ // X86: fcmp une
+ // X86: fcmp une
+ // X86: or i1
+ // X86: ret
+ return a != b;
+}
+_Bool ne_float_cc(float _Complex a, float _Complex b) {
+ // X86-LABEL: @ne_float_cc(
+ // X86: fcmp une
+ // X86: fcmp une
+ // X86: or i1
+ // X86: ret
+ return a != b;
+}
+
+// Check that the libcall will obtain proper calling convention on ARM
+_Complex double foo(_Complex double a, _Complex double b) {
+ // ARM-LABEL: @foo(
+ // ARM: call arm_aapcscc { double, double } @__muldc3
+ return a*b;
+}
diff --git a/test/CodeGen/complex.c b/test/CodeGen/complex.c
index 206db253caa4..1c0e7cb2ee95 100644
--- a/test/CodeGen/complex.c
+++ b/test/CodeGen/complex.c
@@ -98,3 +98,19 @@ void t8() {
const _Complex double test9const = 0;
_Complex double test9func() { return test9const; }
+
+// D6217
+void t91() {
+ // Check for proper type promotion of conditional expression
+ char c[(int)(sizeof(typeof((0 ? 2.0f : (_Complex double) 2.0f))) - sizeof(_Complex double))];
+ // Check for proper codegen
+ (0 ? 2.0f : (_Complex double) 2.0f);
+}
+
+void t92() {
+ // Check for proper type promotion of conditional expression
+ char c[(int)(sizeof(typeof((0 ? (_Complex double) 2.0f : 2.0f))) - sizeof(_Complex double))];
+ // Check for proper codegen
+ (0 ? (_Complex double) 2.0f : 2.0f);
+}
+
diff --git a/test/CodeGen/compound-assign-overflow.c b/test/CodeGen/compound-assign-overflow.c
index 15334294d47e..f126bb05d53c 100644
--- a/test/CodeGen/compound-assign-overflow.c
+++ b/test/CodeGen/compound-assign-overflow.c
@@ -1,5 +1,5 @@
// Verify proper type emitted for compound assignments
-// RUN: %clang_cc1 -ffreestanding -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=signed-integer-overflow,unsigned-integer-overflow | FileCheck %s
+// RUN: %clang_cc1 -ffreestanding -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-recover=signed-integer-overflow,unsigned-integer-overflow | FileCheck %s
#include <stdint.h>
diff --git a/test/CodeGen/const-init.c b/test/CodeGen/const-init.c
index 7d7ccae370dd..b86274fc8242 100644
--- a/test/CodeGen/const-init.c
+++ b/test/CodeGen/const-init.c
@@ -159,3 +159,25 @@ void g29() {
static int b[1] = { "asdf" }; // expected-warning {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'char [5]'}}
static int c[1] = { L"a" };
}
+
+// PR21300
+void g30() {
+#pragma pack(1)
+ static struct {
+ int : 1;
+ int x;
+ } a = {};
+ // CHECK: @g30.a = internal global %struct.anon.1 <{ i8 undef, i32 0 }>, align 1
+#pragma pack()
+}
+
+void g31() {
+#pragma pack(4)
+ static struct {
+ short a;
+ long x;
+ short z;
+ } a = {23122, -12312731, -312};
+#pragma pack()
+ // CHECK: @g31.a = internal global %struct.anon.2 { i16 23122, i32 -12312731, i16 -312 }, align 4
+}
diff --git a/test/CodeGen/debug-info-args.c b/test/CodeGen/debug-info-args.c
index 50b85411adb9..33cf5bcbd06c 100644
--- a/test/CodeGen/debug-info-args.c
+++ b/test/CodeGen/debug-info-args.c
@@ -2,8 +2,8 @@
int somefunc(char *x, int y, double z) {
- // CHECK: metadata ![[NUM:[^,]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type
- // CHECK: ![[NUM]] = {{metadata !{metadata ![^,]*, metadata ![^,]*, metadata ![^,]*, metadata ![^,]*}}}
+ // CHECK: ![[NUM:[^,]*]], null, null, null} ; [ DW_TAG_subroutine_type
+ // CHECK: ![[NUM]] = {{!{![^,]*, ![^,]*, ![^,]*, ![^,]*}}}
return y;
}
diff --git a/test/CodeGen/debug-info-block-decl.c b/test/CodeGen/debug-info-block-decl.c
index 06c0e1ad3192..f3f5e6bd0a91 100644
--- a/test/CodeGen/debug-info-block-decl.c
+++ b/test/CodeGen/debug-info-block-decl.c
@@ -9,8 +9,8 @@
int main()
{
-// CHECK: [[ASSIGNMENT]] = metadata !{i32 [[@LINE+2]],
-// CHECK: [[BLOCK_ENTRY]] = metadata !{i32 [[@LINE+1]],
+// CHECK: [[ASSIGNMENT]] = !MDLocation(line: [[@LINE+2]],
+// CHECK: [[BLOCK_ENTRY]] = !MDLocation(line: [[@LINE+1]],
int (^blockptr)(void) = ^(void) {
return 0;
};
diff --git a/test/CodeGen/debug-info-block-out-return.c b/test/CodeGen/debug-info-block-out-return.c
new file mode 100644
index 000000000000..47b90ce6882a
--- /dev/null
+++ b/test/CodeGen/debug-info-block-out-return.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -fblocks -emit-llvm -o - %s | FileCheck %s
+
+// Check that arg numbering is not affected by LLVM IR argument numbering -
+// since the latter is affected by return-by-out-parameter ABI requirements
+
+// 1 for the argument number (1 indexed), 2 for the line number
+// 16777218 == 1 << 24 | 2
+// 33554434 == 2 << 24 | 2
+// This explains the two magic numbers below, testing that these two arguments
+// are numbered correctly. If they are not numbered correctly they may appear
+// out of order or not at all (the latter would occur if they were both assigned
+// the same argument number by mistake).
+
+// CHECK: !"0x101\00.block_descriptor\0016777218\00{{[0-9]+}}", {{.*}} ; [ DW_TAG_arg_variable ] [.block_descriptor]
+// CHECK: !"0x101\00param\0033554434\00{{[0-9]+}}", {{.*}} ; [ DW_TAG_arg_variable ] [param]
+
+// Line directive so we don't have to worry about how many lines preceed the
+// test code (as the line number is mangled in with the argument number as shown
+// above)
+#line 1
+typedef struct { int array[12]; } BigStruct_t;
+BigStruct_t (^a)() = ^(int param) {
+ BigStruct_t b;
+ return b;
+};
diff --git a/test/CodeGen/debug-info-enum.c b/test/CodeGen/debug-info-enum.c
index acf3f524088b..1f6b384d8527 100644
--- a/test/CodeGen/debug-info-enum.c
+++ b/test/CodeGen/debug-info-enum.c
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s
-// CHECK: metadata [[TEST3_ENUMS:![0-9]*]], {{[^,]*}}, null, null, null} ; [ DW_TAG_enumeration_type ] [e]
-// CHECK: [[TEST3_ENUMS]] = metadata !{metadata [[TEST3_E:![0-9]*]]}
-// CHECK: [[TEST3_E]] = {{.*}}, metadata !"E", i64 -1} ; [ DW_TAG_enumerator ] [E :: -1]
+// CHECK: [[TEST3_ENUMS:![0-9]*]], null, null, null} ; [ DW_TAG_enumeration_type ] [e]
+// CHECK: [[TEST3_ENUMS]] = !{[[TEST3_E:![0-9]*]]}
+// CHECK: [[TEST3_E]] = !{!"0x28\00E\00-1"} ; [ DW_TAG_enumerator ] [E :: -1]
enum e;
void func(enum e *p) {
diff --git a/test/CodeGen/debug-info-line3.c b/test/CodeGen/debug-info-line3.c
index d01b023b82d3..d2efcf724094 100644
--- a/test/CodeGen/debug-info-line3.c
+++ b/test/CodeGen/debug-info-line3.c
@@ -13,4 +13,4 @@ void func(char c, char* d)
}
// CHECK: ret void, !dbg [[LINE:.*]]
-// CHECK: [[LINE]] = metadata !{i32 6,
+// CHECK: [[LINE]] = !MDLocation(line: 6,
diff --git a/test/CodeGen/debug-info-line4.c b/test/CodeGen/debug-info-line4.c
index 004176c7a507..2b3e0fe5bc65 100644
--- a/test/CodeGen/debug-info-line4.c
+++ b/test/CodeGen/debug-info-line4.c
@@ -8,4 +8,4 @@ int foo(int a, int b) { int c = a + b;
}
// Without column information we wouldn't change locations for b.
-// CHECK: metadata !{i32 4, i32 20,
+// CHECK: !MDLocation(line: 4, column: 20,
diff --git a/test/CodeGen/debug-info-scope-file.c b/test/CodeGen/debug-info-scope-file.c
index 3479ade7a329..226fb27021eb 100644
--- a/test/CodeGen/debug-info-scope-file.c
+++ b/test/CodeGen/debug-info-scope-file.c
@@ -7,8 +7,8 @@
// CHECK: ret void, !dbg [[F2_LINE:![0-9]*]]
// CHECK: [[F1:![0-9]*]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [f1]
// CHECK: [[F2:![0-9]*]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [f2]
-// CHECK: [[F1_LINE]] = {{.*}}, metadata [[F1]], null}
-// CHECK: [[F2_LINE]] = {{.*}}, metadata [[F2]], null}
+// CHECK: [[F1_LINE]] = !MDLocation({{.*}}, scope: [[F1]])
+// CHECK: [[F2_LINE]] = !MDLocation({{.*}}, scope: [[F2]])
void f1() {
}
diff --git a/test/CodeGen/debug-info-scope.c b/test/CodeGen/debug-info-scope.c
index 9decaeafd50e..d84fafd018d2 100644
--- a/test/CodeGen/debug-info-scope.c
+++ b/test/CodeGen/debug-info-scope.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -g -emit-llvm < %s | FileCheck %s
+// RUN: %clang_cc1 -gline-tables-only -emit-llvm < %s | FileCheck --check-prefix=GMLT %s
// Two variables with same name in separate scope.
// Radar 8330217.
int main() {
@@ -6,10 +7,21 @@ int main() {
int k = 0;
// CHECK: DW_TAG_auto_variable ] [i]
// CHECK-NEXT: DW_TAG_lexical_block
+
+// FIXME: Looks like we don't actually need both these lexical blocks (disc 2
+// just refers to disc 1, nothing actually uses disc 2).
+// GMLT-NOT: DW_TAG_lexical_block
+// GMLT: "0xb\002", {{.*}}} ; [ DW_TAG_lexical_block ]
+// GMLT-NOT: DW_TAG_lexical_block
+// GMLT: "0xb\001", {{.*}}} ; [ DW_TAG_lexical_block ]
+// Make sure we don't have any more lexical blocks because we don't need them in
+// -gmlt.
+// GMLT-NOT: DW_TAG_lexical_block
for (int i = 0; i < 10; i++)
j++;
// CHECK: DW_TAG_auto_variable ] [i]
// CHECK-NEXT: DW_TAG_lexical_block
+// GMLT-NOT: DW_TAG_lexical_block
for (int i = 0; i < 10; i++)
k++;
return 0;
diff --git a/test/CodeGen/debug-info-typedef.c b/test/CodeGen/debug-info-typedef.c
index 51ebcc4d8749..3db7d537890b 100644
--- a/test/CodeGen/debug-info-typedef.c
+++ b/test/CodeGen/debug-info-typedef.c
@@ -7,5 +7,5 @@ typedef int MyType;
MyType a;
-// CHECK: metadata ![[HEADER:[0-9]+]], null, metadata !"MyType"{{.*}} ; [ DW_TAG_typedef ] [MyType] [line 2, size 0, align 0, offset 0] [from int]
-// CHECK: ![[HEADER]] = metadata !{metadata !"b.h",
+// CHECK: !"0x16\00MyType\002\00{{.*}}", ![[HEADER:[0-9]+]], null{{.*}}} ; [ DW_TAG_typedef ] [MyType] [line 2, size 0, align 0, offset 0] [from int]
+// CHECK: ![[HEADER]] = !{!"b.h",
diff --git a/test/CodeGen/debug-info-version.c b/test/CodeGen/debug-info-version.c
index 325345f0b26e..5fe2e4eb570b 100644
--- a/test/CodeGen/debug-info-version.c
+++ b/test/CodeGen/debug-info-version.c
@@ -4,5 +4,5 @@ int main (void) {
return 0;
}
-// CHECK: metadata !{i32 2, metadata !"Debug Info Version", i32 1}
-// NO_DEBUG-NOT: metadata !"Debug Info Version"
+// CHECK: i32 2, !"Debug Info Version", i32 2}
+// NO_DEBUG-NOT: !"Debug Info Version"
diff --git a/test/CodeGen/debug-info-vla.c b/test/CodeGen/debug-info-vla.c
index 7a8da960db47..ac45dd0a7643 100644
--- a/test/CodeGen/debug-info-vla.c
+++ b/test/CodeGen/debug-info-vla.c
@@ -2,7 +2,7 @@
void testVLAwithSize(int s)
{
-// CHECK: metadata !{i32 {{.*}}, metadata {{.*}}, metadata !"vla", metadata {{.*}}, i32 [[@LINE+1]], metadata {{.*}}, i32 8192, i32 0} ; [ DW_TAG_auto_variable ] [vla] [line [[@LINE+1]]]
+// CHECK: !"0x100\00vla\00[[@LINE+1]]\008192", {{.*}}, {{.*}}, {{.*}}} ; [ DW_TAG_auto_variable ] [vla] [line [[@LINE+1]]]
int vla[s];
int i;
for (i = 0; i < s; i++) {
diff --git a/test/CodeGen/debug-info.c b/test/CodeGen/debug-info.c
index 12ba6058d39e..bf08c589809c 100644
--- a/test/CodeGen/debug-info.c
+++ b/test/CodeGen/debug-info.c
@@ -42,7 +42,7 @@ struct foo2 foo2;
// Radar 7325611
-// CHECK: "barfoo"
+// CHECK: !"0x16\00barfoo\00{{.*}}"
typedef int barfoo;
barfoo foo() {
}
diff --git a/test/CodeGen/dependent-lib.c b/test/CodeGen/dependent-lib.c
index 20913d33f5be..b3abc2f5bc41 100644
--- a/test/CodeGen/dependent-lib.c
+++ b/test/CodeGen/dependent-lib.c
@@ -3,13 +3,13 @@
// RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple i686-pc-linux -emit-llvm -o - | FileCheck -check-prefix LINUX %s
// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = metadata !{i32 6, metadata !"Linker Options", metadata ![[link_opts:[0-9]+]]}
-// CHECK: ![[link_opts]] = metadata !{metadata ![[msvcrt:[0-9]+]]}
-// CHECK: ![[msvcrt]] = metadata !{metadata !"/DEFAULTLIB:msvcrt.lib"}
+// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
+// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
+// CHECK: ![[msvcrt]] = !{!"/DEFAULTLIB:msvcrt.lib"}
// LINUX: !llvm.module.flags = !{{{.*}}}
-// LINUX: !{{[0-9]+}} = metadata !{i32 6, metadata !"Linker Options", metadata ![[link_opts:[0-9]+]]}
-// LINUX: ![[link_opts]] = metadata !{metadata ![[msvcrt:[0-9]+]]}
-// LINUX: ![[msvcrt]] = metadata !{metadata !"-lmsvcrt"}
+// LINUX: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
+// LINUX: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
+// LINUX: ![[msvcrt]] = !{!"-lmsvcrt"}
int f();
diff --git a/test/CodeGen/designated-initializers.c b/test/CodeGen/designated-initializers.c
index b11c67a45421..74532c8fa5b4 100644
--- a/test/CodeGen/designated-initializers.c
+++ b/test/CodeGen/designated-initializers.c
@@ -139,6 +139,9 @@ union_16644_t union_16644_instance_4[2] =
[1].b[1] = 4
};
+// CHECK: @lab = global { [4 x i8], i32 } { [4 x i8] undef, i32 123 }
+struct leading_anon_bitfield { int : 32; int n; } lab = { .n = 123 };
+
void test1(int argc, char **argv)
{
// CHECK: internal global %struct.foo { i8* null, i32 1024 }
diff --git a/test/CodeGen/dllimport.c b/test/CodeGen/dllimport.c
index 32ee81f85924..89dbb9f3461c 100644
--- a/test/CodeGen/dllimport.c
+++ b/test/CodeGen/dllimport.c
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 %s
-// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 %s
+// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=GNU %s
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=GNU %s
+// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 --check-prefix=MO1 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 --check-prefix=GO1 %s
#define JOIN2(x, y) x##y
#define JOIN(x, y) JOIN2(x, y)
@@ -44,6 +44,26 @@ __declspec(dllimport) extern int GlobalRedecl3;
extern int GlobalRedecl3; // dllimport ignored
USEVAR(GlobalRedecl3)
+// Make sure this works even if the decl has been used before it's defined (PR20792).
+// CHECK: @GlobalRedecl4 = common global i32
+__declspec(dllimport) extern int GlobalRedecl4;
+USEVAR(GlobalRedecl4)
+ int GlobalRedecl4; // dllimport ignored
+
+// FIXME: dllimport is dropped in the AST; this should be reflected in codegen (PR02803).
+// CHECK: @GlobalRedecl5 = external dllimport global i32
+__declspec(dllimport) extern int GlobalRedecl5;
+USEVAR(GlobalRedecl5)
+ extern int GlobalRedecl5; // dllimport ignored
+
+// Redeclaration in local context.
+// CHECK: @GlobalRedecl6 = external dllimport global i32
+__declspec(dllimport) int GlobalRedecl6;
+int functionScope() {
+ extern int GlobalRedecl6; // still dllimport
+ return GlobalRedecl6;
+}
+
//===----------------------------------------------------------------------===//
@@ -59,14 +79,18 @@ __declspec(dllimport) void decl(void);
void (*use_decl)(void) = &decl;
// Import inline function.
-// CHECK-DAG: declare dllimport void @inlineFunc()
-// O1-DAG: define available_externally dllimport void @inlineFunc()
+// MS-DAG: declare dllimport void @inlineFunc()
+// MO1-DAG: define available_externally dllimport void @inlineFunc()
+// GNU-DAG: declare void @inlineFunc()
+// GO1-DAG: define available_externally void @inlineFunc()
__declspec(dllimport) inline void inlineFunc(void) {}
USE(inlineFunc)
// inline attributes
-// CHECK-DAG: declare dllimport void @noinline()
-// O1-DAG: define available_externally dllimport void @noinline()
+// MS-DAG: declare dllimport void @noinline()
+// MO1-DAG: define available_externally dllimport void @noinline()
+// GNU-DAG: declare void @noinline()
+// GO1-DAG: define available_externally void @noinline()
// CHECK-NOT: @alwaysInline()
// O1-NOT: @alwaysInline()
__declspec(dllimport) __attribute__((noinline)) inline void noinline(void) {}
@@ -91,3 +115,15 @@ USE(redecl2)
__declspec(dllimport) void redecl3(void);
void redecl3(void) {} // dllimport ignored
USE(redecl3)
+
+// Make sure this works even if the decl is used before it's defined (PR20792).
+// CHECK-DAG: define void @redecl4()
+__declspec(dllimport) void redecl4(void);
+USE(redecl4)
+ void redecl4(void) {} // dllimport ignored
+
+// FIXME: dllimport is dropped in the AST; this should be reflected in codegen (PR20803).
+// CHECK-DAG: declare dllimport
+__declspec(dllimport) void redecl5(void);
+USE(redecl5)
+ void redecl5(void); // dllimport ignored
diff --git a/test/CodeGen/dwarf-version.c b/test/CodeGen/dwarf-version.c
index 0c67b4f86eb5..cb95f28bc735 100644
--- a/test/CodeGen/dwarf-version.c
+++ b/test/CodeGen/dwarf-version.c
@@ -5,10 +5,11 @@
// RUN: %clang -target x86_64-apple-darwin -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER2
// RUN: %clang -target powerpc-unknown-openbsd -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER2
// RUN: %clang -target powerpc-unknown-freebsd -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER2
+// RUN: %clang -target i386-pc-solaris -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER2
int main (void) {
return 0;
}
-// VER2: metadata !{i32 2, metadata !"Dwarf Version", i32 2}
-// VER3: metadata !{i32 2, metadata !"Dwarf Version", i32 3}
-// VER4: metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+// VER2: !{i32 2, !"Dwarf Version", i32 2}
+// VER3: !{i32 2, !"Dwarf Version", i32 3}
+// VER4: !{i32 2, !"Dwarf Version", i32 4}
diff --git a/test/CodeGen/ext-vector-indexing.c b/test/CodeGen/ext-vector-indexing.c
new file mode 100644
index 000000000000..28c0e1e9e25a
--- /dev/null
+++ b/test/CodeGen/ext-vector-indexing.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+// CHECK: @test
+void test()
+{
+ float4 va;
+ va.hi[0] = 3.0;
+// CHECK: [[VA:%.*]] = alloca <4 x float>
+// CHECK: [[CONV:%.*]] = bitcast <4 x float>* [[VA]] to float*
+// CHECK: [[ADD:%.*]] = getelementptr inbounds float* [[CONV]], i64 2
+// CHECK: [[ARRIDX:%.*]] = getelementptr inbounds float* [[ADD]], i64 0
+// CHECK: store float 3.000000e+00, float* [[ARRIDX]]
+}
diff --git a/test/CodeGen/fp128_complex.c b/test/CodeGen/fp128_complex.c
new file mode 100644
index 000000000000..877599932951
--- /dev/null
+++ b/test/CodeGen/fp128_complex.c
@@ -0,0 +1,9 @@
+// RUN: %clang -target aarch64-linux-gnuabi %s -O3 -S -emit-llvm -o - | FileCheck %s
+
+_Complex long double a, b, c, d;
+void test_fp128_compound_assign(void) {
+ // CHECK: tail call { fp128, fp128 } @__multc3
+ a *= b;
+ // CHECK: tail call { fp128, fp128 } @__divtc3
+ c /= d;
+}
diff --git a/test/CodeGen/fsgsbase-builtins.c b/test/CodeGen/fsgsbase-builtins.c
new file mode 100644
index 000000000000..14c51a9945f8
--- /dev/null
+++ b/test/CodeGen/fsgsbase-builtins.c
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +fsgsbase -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+unsigned int test_readfsbase_u32()
+{
+ // CHECK: @llvm.x86.rdfsbase.32
+ return _readfsbase_u32();
+}
+
+unsigned long long test_readfsbase_u64()
+{
+ // CHECK: @llvm.x86.rdfsbase.64
+ return _readfsbase_u64();
+}
+
+unsigned int test_readgsbase_u32()
+{
+ // CHECK: @llvm.x86.rdgsbase.32
+ return _readgsbase_u32();
+}
+
+unsigned long long test_readgsbase_u64()
+{
+ // CHECK: @llvm.x86.rdgsbase.64
+ return _readgsbase_u64();
+}
+
+void test_writefsbase_u32(unsigned int __X)
+{
+ // CHECK: @llvm.x86.wrfsbase.32
+ _writefsbase_u32(__X);
+}
+
+void test_writefsbase_u64(unsigned long long __X)
+{
+ // CHECK: @llvm.x86.wrfsbase.64
+ _writefsbase_u64(__X);
+}
+
+void test_writegsbase_u32(unsigned int __X)
+{
+ // CHECK: @llvm.x86.wrgsbase.32
+ _writegsbase_u32(__X);
+}
+
+void test_writegsbase_u64(unsigned long long __X)
+{
+ // CHECK: @llvm.x86.wrgsbase.64
+ _writegsbase_u64(__X);
+}
diff --git a/test/CodeGen/lineno-dbginfo.c b/test/CodeGen/lineno-dbginfo.c
index 1f9b7a569ece..28c72438f542 100644
--- a/test/CodeGen/lineno-dbginfo.c
+++ b/test/CodeGen/lineno-dbginfo.c
@@ -1,5 +1,6 @@
// RUN: echo "#include <stddef.h>" > %t.h
-// RUN: %clang_cc1 -S -g -include %t.h %s -emit-llvm -o %t.ll
-// RUN: grep "i32 5" %t.ll
-// outer is at line number 5.
+// RUN: %clang_cc1 -S -g -include %t.h %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: !"0x34\00outer\00outer\00\00[[@LINE+1]]\000\001"
int outer = 42;
+
diff --git a/test/CodeGen/linetable-endscope.c b/test/CodeGen/linetable-endscope.c
index 236f605d7efa..9a737cf79655 100644
--- a/test/CodeGen/linetable-endscope.c
+++ b/test/CodeGen/linetable-endscope.c
@@ -11,7 +11,7 @@
void foo(char c)
{
int i;
- // CHECK: ![[CONV]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[CONV]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
i = c;
- // CHECK: ![[RET]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RET]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
}
diff --git a/test/CodeGen/link-bitcode-file.c b/test/CodeGen/link-bitcode-file.c
index cf9493f988ae..fb97b4d1f585 100644
--- a/test/CodeGen/link-bitcode-file.c
+++ b/test/CodeGen/link-bitcode-file.c
@@ -6,7 +6,7 @@ int f(void);
#ifdef BITCODE
-// CHECK-BC: 'f': symbol multiply defined
+// CHECK-BC: fatal error: cannot link module {{.*}}'f': symbol multiply defined
int f(void) {
return 42;
}
diff --git a/test/CodeGen/lzcnt-builtins.c b/test/CodeGen/lzcnt-builtins.c
index a43c4eede452..a083de9d35f0 100644
--- a/test/CodeGen/lzcnt-builtins.c
+++ b/test/CodeGen/lzcnt-builtins.c
@@ -22,3 +22,15 @@ unsigned long long test__lzcnt64(unsigned long long __X)
// CHECK: @llvm.ctlz.i64
return __lzcnt64(__X);
}
+
+unsigned int test_lzcnt_u32(unsigned int __X)
+{
+ // CHECK: @llvm.ctlz.i32
+ return _lzcnt_u32(__X);
+}
+
+unsigned long long test__lzcnt_u64(unsigned long long __X)
+{
+ // CHECK: @llvm.ctlz.i64
+ return _lzcnt_u64(__X);
+}
diff --git a/test/CodeGen/mangle-blocks.c b/test/CodeGen/mangle-blocks.c
new file mode 100644
index 000000000000..c5e08e9dd5b1
--- /dev/null
+++ b/test/CodeGen/mangle-blocks.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple i386-apple-ios -fblocks -emit-llvm -o - %s | FileCheck %s
+
+void __assert_rtn(const char *, const char *, int, const char *)
+ __attribute__ (( noreturn ));
+
+void (^mangle(void))(void) {
+ return ^{
+ void (^block)(void) = ^{
+ __assert_rtn(__func__, __FILE__, __LINE__, "mangle");
+ };
+ };
+}
+
+// CHECK: @__func__.__mangle_block_invoke_2 = private unnamed_addr constant [24 x i8] c"__mangle_block_invoke_2\00", align 1
+// CHECK: @.str = private unnamed_addr constant {{.*}}, align 1
+// CHECK: @.str1 = private unnamed_addr constant [7 x i8] c"mangle\00", align 1
+
+// CHECK: define internal void @__mangle_block_invoke(i8* %.block_descriptor)
+
+// CHECK: define internal void @__mangle_block_invoke_2(i8* %.block_descriptor){{.*}}{
+// CHECK: call void @__assert_rtn(i8* getelementptr inbounds ([24 x i8]* @__func__.__mangle_block_invoke_2, i32 0, i32 0), i8* getelementptr inbounds {{.*}}, i32 9, i8* getelementptr inbounds ([7 x i8]* @.str1, i32 0, i32 0))
+// CHECK: }
+
diff --git a/test/CodeGen/mangle-windows.c b/test/CodeGen/mangle-windows.c
index 37d101828358..4a108751aa4b 100644
--- a/test/CodeGen/mangle-windows.c
+++ b/test/CodeGen/mangle-windows.c
@@ -1,33 +1,68 @@
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-mingw32 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-win32 | FileCheck %s --check-prefix=X64
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-mingw32 | FileCheck %s --check-prefix=X64
void __stdcall f1(void) {}
// CHECK: define x86_stdcallcc void @"\01_f1@0"
+// X64: define void @f1(
void __fastcall f2(void) {}
// CHECK: define x86_fastcallcc void @"\01@f2@0"
+// X64: define void @f2(
void __stdcall f3() {}
// CHECK: define x86_stdcallcc void @"\01_f3@0"
+// X64: define void @f3(
void __fastcall f4(char a) {}
// CHECK: define x86_fastcallcc void @"\01@f4@4"
+// X64: define void @f4(
void __fastcall f5(short a) {}
// CHECK: define x86_fastcallcc void @"\01@f5@4"
+// X64: define void @f5(
void __fastcall f6(int a) {}
// CHECK: define x86_fastcallcc void @"\01@f6@4"
+// X64: define void @f6(
void __fastcall f7(long a) {}
// CHECK: define x86_fastcallcc void @"\01@f7@4"
+// X64: define void @f7(
void __fastcall f8(long long a) {}
// CHECK: define x86_fastcallcc void @"\01@f8@8"
+// X64: define void @f8(
void __fastcall f9(long long a, char b, char c, short d) {}
-// CHECK: define x86_fastcallcc void @"\01@f9@20"(i64 %a, i8 signext %b, i8
-// signext %c, i16 signext %d)
+// CHECK: define x86_fastcallcc void @"\01@f9@20"(i64 %a, i8 signext %b, i8 signext %c, i16 signext %d)
+// X64: define void @f9(
void f12(void) {}
// CHECK: define void @f12(
+// X64: define void @f12(
+
+void __vectorcall v1(void) {}
+// CHECK: define x86_vectorcallcc void @"\01v1@@0"(
+// X64: define x86_vectorcallcc void @"\01v1@@0"(
+
+void __vectorcall v2(char a) {}
+// CHECK: define x86_vectorcallcc void @"\01v2@@4"(
+// X64: define x86_vectorcallcc void @"\01v2@@8"(
+
+void __vectorcall v3(short a) {}
+// CHECK: define x86_vectorcallcc void @"\01v3@@4"(
+// X64: define x86_vectorcallcc void @"\01v3@@8"(
+
+void __vectorcall v4(int a) {}
+// CHECK: define x86_vectorcallcc void @"\01v4@@4"(
+// X64: define x86_vectorcallcc void @"\01v4@@8"(
+
+void __vectorcall v5(long long a) {}
+// CHECK: define x86_vectorcallcc void @"\01v5@@8"(
+// X64: define x86_vectorcallcc void @"\01v5@@8"(
+
+void __vectorcall v6(char a, char b) {}
+// CHECK: define x86_vectorcallcc void @"\01v6@@8"(
+// X64: define x86_vectorcallcc void @"\01v6@@16"(
diff --git a/test/CodeGen/may-alias.c b/test/CodeGen/may-alias.c
index 4d6f721f6abb..520b7abea6c1 100644
--- a/test/CodeGen/may-alias.c
+++ b/test/CodeGen/may-alias.c
@@ -27,16 +27,16 @@ void test1(struct Test1MA *p1, struct Test1 *p2) {
// PATH: store i32 3, i32* {{%.*}}, !tbaa [[TAG_test1_x:!.*]]
p2->x = 3;
}
-// CHECK: metadata !{metadata !"any pointer", metadata [[TYPE_CHAR:!.*]],
-// CHECK: [[TYPE_CHAR]] = metadata !{metadata !"omnipotent char", metadata [[TAG_CXX_TBAA:!.*]],
-// CHECK: [[TAG_CXX_TBAA]] = metadata !{metadata !"Simple C/C++ TBAA"}
-// CHECK: [[TAG_CHAR]] = metadata !{metadata [[TYPE_CHAR]], metadata [[TYPE_CHAR]], i64 0}
-// CHECK: [[TAG_INT]] = metadata !{metadata [[TYPE_INT:!.*]], metadata [[TYPE_INT]], i64 0}
-// CHECK: [[TYPE_INT]] = metadata !{metadata !"int", metadata [[TYPE_CHAR]]
+// CHECK: !"any pointer", [[TYPE_CHAR:!.*]],
+// CHECK: [[TYPE_CHAR]] = !{!"omnipotent char", [[TAG_CXX_TBAA:!.*]],
+// CHECK: [[TAG_CXX_TBAA]] = !{!"Simple C/C++ TBAA"}
+// CHECK: [[TAG_CHAR]] = !{[[TYPE_CHAR]], [[TYPE_CHAR]], i64 0}
+// CHECK: [[TAG_INT]] = !{[[TYPE_INT:!.*]], [[TYPE_INT]], i64 0}
+// CHECK: [[TYPE_INT]] = !{!"int", [[TYPE_CHAR]]
-// PATH: [[TYPE_CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata !{{.*}}
-// PATH: [[TAG_CHAR]] = metadata !{metadata [[TYPE_CHAR]], metadata [[TYPE_CHAR]], i64 0}
-// PATH: [[TAG_INT]] = metadata !{metadata [[TYPE_INT:!.*]], metadata [[TYPE_INT]], i64 0}
-// PATH: [[TYPE_INT]] = metadata !{metadata !"int", metadata [[TYPE_CHAR]]
-// PATH: [[TAG_test1_x]] = metadata !{metadata [[TYPE_test1:!.*]], metadata [[TYPE_INT]], i64 0}
-// PATH: [[TYPE_test1]] = metadata !{metadata !"Test1", metadata [[TYPE_INT]], i64 0}
+// PATH: [[TYPE_CHAR:!.*]] = !{!"omnipotent char", !{{.*}}
+// PATH: [[TAG_CHAR]] = !{[[TYPE_CHAR]], [[TYPE_CHAR]], i64 0}
+// PATH: [[TAG_INT]] = !{[[TYPE_INT:!.*]], [[TYPE_INT]], i64 0}
+// PATH: [[TYPE_INT]] = !{!"int", [[TYPE_CHAR]]
+// PATH: [[TAG_test1_x]] = !{[[TYPE_test1:!.*]], [[TYPE_INT]], i64 0}
+// PATH: [[TYPE_test1]] = !{!"Test1", [[TYPE_INT]], i64 0}
diff --git a/test/CodeGen/merge-statics.c b/test/CodeGen/merge-statics.c
index 6716935c4d12..4baf902488c5 100644
--- a/test/CodeGen/merge-statics.c
+++ b/test/CodeGen/merge-statics.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 < %s -emit-llvm | grep internal | count 1
+// RUN: %clang_cc1 < %s -emit-llvm | FileCheck %s
// The two decls for 'a' should merge into one llvm GlobalVariable.
@@ -11,3 +11,6 @@ static struct s a = {
10
};
+// CHECK-NOT: internal global
+// CHECK: @a = internal global %struct.s { i32 10 }
+// CHECK-NOT: internal-global
diff --git a/test/CodeGen/microsoft-call-conv.c b/test/CodeGen/microsoft-call-conv.c
index b80c58dfd1f2..c24db1296f12 100644
--- a/test/CodeGen/microsoft-call-conv.c
+++ b/test/CodeGen/microsoft-call-conv.c
@@ -20,6 +20,11 @@ void __thiscall f6(void) {
f3();
// CHECK: call x86_thiscallcc void @f3()
}
+void __vectorcall f61(void) {
+// CHECK-LABEL: define x86_vectorcallcc void @f61()
+ f3();
+// CHECK: call x86_thiscallcc void @f3()
+}
// PR5280
void (__fastcall *pf1)(void) = f1;
@@ -28,19 +33,22 @@ void (__thiscall *pf3)(void) = f3;
void (__fastcall *pf4)(void) = f4;
void (__stdcall *pf5)(void) = f5;
void (__thiscall *pf6)(void) = f6;
+void (__vectorcall *pf7)(void) = f61;
int main(void) {
- f4(); f5(); f6();
+ f4(); f5(); f6(); f61();
// CHECK: call x86_fastcallcc void @f4()
// CHECK: call x86_stdcallcc void @f5()
// CHECK: call x86_thiscallcc void @f6()
- pf1(); pf2(); pf3(); pf4(); pf5(); pf6();
+ // CHECK: call x86_vectorcallcc void @f61()
+ pf1(); pf2(); pf3(); pf4(); pf5(); pf6(); pf7();
// CHECK: call x86_fastcallcc void %{{.*}}()
// CHECK: call x86_stdcallcc void %{{.*}}()
// CHECK: call x86_thiscallcc void %{{.*}}()
// CHECK: call x86_fastcallcc void %{{.*}}()
// CHECK: call x86_stdcallcc void %{{.*}}()
// CHECK: call x86_thiscallcc void %{{.*}}()
+ // CHECK: call x86_vectorcallcc void %{{.*}}()
return 0;
}
diff --git a/test/CodeGen/mips-constraint-regs.c b/test/CodeGen/mips-constraint-regs.c
index 0d533f5fc771..4dfd62ddbfcf 100644
--- a/test/CodeGen/mips-constraint-regs.c
+++ b/test/CodeGen/mips-constraint-regs.c
@@ -9,7 +9,7 @@ int main()
// 'c': 16 bit address register for Mips16, GPR for all others
// I am using 'c' to constrain both the target and one of the source
// registers. We are looking for syntactical correctness.
- // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "addi $0,$1,$2 \0A\09\09", "=c,c,I"(i32 %{{[0-9]+}}, i32 %{{[0-9]+}}) [[NUW:#[0-9]+]], !srcloc !{{[0-9]+}}
+ // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "addi $0,$1,$2 \0A\09\09", "=c,c,I,~{$1}"(i32 %{{[0-9]+}}, i32 %{{[0-9]+}}) [[NUW:#[0-9]+]], !srcloc !{{[0-9]+}}
int __s, __v = 17;
int __t;
__asm__ __volatile__(
@@ -20,7 +20,7 @@ int main()
// 'l': lo register
// We are making it clear that destination register is lo with the
// use of the 'l' constraint ("=l").
- // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "mtlo $1 \0A\09\09", "=l,r,~{lo}"(i32 %{{[0-9]+}}) [[NUW]], !srcloc !{{[0-9]+}}
+ // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "mtlo $1 \0A\09\09", "=l,r,~{lo},~{$1}"(i32 %{{[0-9]+}}) [[NUW]], !srcloc !{{[0-9]+}}
int i_temp = 44;
int i_result;
__asm__ __volatile__(
@@ -32,7 +32,7 @@ int main()
// 'x': Combined lo/hi registers
// We are specifying that destination registers are the hi/lo pair with the
// use of the 'x' constraint ("=x").
- // CHECK: %{{[0-9]+}} = call i64 asm sideeffect "mthi $1 \0A\09\09mtlo $2 \0A\09\09", "=x,r,r"(i32 %{{[0-9]+}}, i32 %{{[0-9]+}}) [[NUW]], !srcloc !{{[0-9]+}}
+ // CHECK: %{{[0-9]+}} = call i64 asm sideeffect "mthi $1 \0A\09\09mtlo $2 \0A\09\09", "=x,r,r,~{$1}"(i32 %{{[0-9]+}}, i32 %{{[0-9]+}}) [[NUW]], !srcloc !{{[0-9]+}}
int i_hi = 3;
int i_lo = 2;
long long ll_result = 0;
diff --git a/test/CodeGen/mips-constraints-mem.c b/test/CodeGen/mips-constraints-mem.c
index 2c3c01ac11e2..295d67cadf0a 100644
--- a/test/CodeGen/mips-constraints-mem.c
+++ b/test/CodeGen/mips-constraints-mem.c
@@ -9,7 +9,7 @@ int foo()
// 'R': An address that can be used in a non-macro load or stor'
// This test will result in the higher and lower nibbles being
// switched due to the lwl/lwr instruction pairs.
- // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "lwl $0, 1 + $1\0A\09lwr $0, 2 + $1\0A\09", "=r,*R"(i32* %{{[0-9,a-f]+}}) #1,
+ // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "lwl $0, 1 + $1\0A\09lwr $0, 2 + $1\0A\09", "=r,*R,~{$1}"(i32* %{{[0-9,a-f]+}}) #1,
int c = 0xffbbccdd;
diff --git a/test/CodeGen/mips-inline-asm-modifiers.c b/test/CodeGen/mips-inline-asm-modifiers.c
index 9d697e8b228e..9437dbe5abe5 100644
--- a/test/CodeGen/mips-inline-asm-modifiers.c
+++ b/test/CodeGen/mips-inline-asm-modifiers.c
@@ -7,9 +7,9 @@ int printf(const char*, ...);
typedef int v4i32 __attribute__((vector_size(16)));
- // CHECK: %{{[0-9]+}} = call i32 asm ".set noreorder;\0Alw $0,$1;\0A.set reorder;\0A", "=r,*m"(i32* getelementptr inbounds ([8 x i32]* @b, i32 {{[0-9]+}}, i32 {{[0-9]+}})) #2,
- // CHECK: %{{[0-9]+}} = call i32 asm "lw $0,${1:D};\0A", "=r,*m"(i32* getelementptr inbounds ([8 x i32]* @b, i32 {{[0-9]+}}, i32 {{[0-9]+}})) #2,
- // CHECK: %{{[0-9]+}} = call <4 x i32> asm "ldi.w ${0:w},1", "=f"
+ // CHECK: %{{[0-9]+}} = call i32 asm ".set noreorder;\0Alw $0,$1;\0A.set reorder;\0A", "=r,*m,~{$1}"(i32* getelementptr inbounds ([8 x i32]* @b, i32 {{[0-9]+}}, i32 {{[0-9]+}})) #2,
+ // CHECK: %{{[0-9]+}} = call i32 asm "lw $0,${1:D};\0A", "=r,*m,~{$1}"(i32* getelementptr inbounds ([8 x i32]* @b, i32 {{[0-9]+}}, i32 {{[0-9]+}})) #2,
+ // CHECK: %{{[0-9]+}} = call <4 x i32> asm "ldi.w ${0:w},1", "=f,~{$1}"
int b[8] = {0,1,2,3,4,5,6,7};
int main()
{
diff --git a/test/CodeGen/mips-transparent-union.c b/test/CodeGen/mips-transparent-union.c
new file mode 100644
index 000000000000..ad417dd9f5da
--- /dev/null
+++ b/test/CodeGen/mips-transparent-union.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple mips64-linux-gnu -S -o - -emit-llvm %s | FileCheck %s
+//
+// Transparent unions are passed according to the calling convention rules of
+// the first member. In this case, it is as if it were a void pointer so we
+// do not have the inreg attribute we would normally have for unions.
+//
+// This comes up in glibc's wait() function and matters for the big-endian N32
+// case where pointers are promoted to i64 and a non-transparent union would be
+// passed in the upper 32-bits of an i64.
+
+union either_pointer {
+ void *void_ptr;
+ int *int_ptr;
+} __attribute__((transparent_union));
+
+extern void foo(union either_pointer p);
+
+int data;
+
+void bar(void) {
+ return foo(&data);
+}
+
+// CHECK-LABEL: define void @bar()
+// CHECK: call void @foo(i8* %{{[0-9]+}})
+
+// CHECK: declare void @foo(i8*)
diff --git a/test/CodeGen/mips-varargs.c b/test/CodeGen/mips-varargs.c
index ad202ff85bf0..383831f2e824 100644
--- a/test/CodeGen/mips-varargs.c
+++ b/test/CodeGen/mips-varargs.c
@@ -28,18 +28,19 @@ int test_i32(char *fmt, ...) {
// ALL: [[VA1:%.+]] = bitcast i8** %va to i8*
// ALL: call void @llvm.va_start(i8* [[VA1]])
//
-// ALL: [[AP_CUR:%.+]] = load i8** %va, align [[PTRALIGN]]
-//
-// O32: [[TMP0:%.+]] = bitcast i8* [[AP_CUR]] to i32*
-// NEW: [[TMP0:%.+]] = bitcast i8* [[AP_CUR]] to i64*
+// O32: [[TMP0:%.+]] = bitcast i8** %va to i32**
+// O32: [[AP_CUR:%.+]] = load i32** [[TMP0]], align [[PTRALIGN]]
+// NEW: [[TMP0:%.+]] = bitcast i8** %va to i64**
+// NEW: [[AP_CUR:%.+]] = load i64** [[TMP0]], align [[PTRALIGN]]
//
-// O32: [[AP_NEXT:%.+]] = getelementptr i8* [[AP_CUR]], i32 4
-// NEW: [[AP_NEXT:%.+]] = getelementptr i8* [[AP_CUR]], {{i32|i64}} 8
+// O32: [[AP_NEXT:%.+]] = getelementptr i32* [[AP_CUR]], i32 1
+// NEW: [[AP_NEXT:%.+]] = getelementptr i64* [[AP_CUR]], {{i32|i64}} 1
//
-// ALL: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]]
+// O32: store i32* [[AP_NEXT]], i32** [[TMP0]], align [[PTRALIGN]]
+// NEW: store i64* [[AP_NEXT]], i64** [[TMP0]], align [[PTRALIGN]]
//
-// O32: [[ARG1:%.+]] = load i32* [[TMP0]], align 4
-// NEW: [[TMP2:%.+]] = load i64* [[TMP0]], align 8
+// O32: [[ARG1:%.+]] = load i32* [[AP_CUR]], align 4
+// NEW: [[TMP2:%.+]] = load i64* [[AP_CUR]], align 8
// NEW: [[ARG1:%.+]] = trunc i64 [[TMP2]] to i32
//
// ALL: call void @llvm.va_end(i8* [[VA1]])
@@ -63,32 +64,30 @@ int test_i32_2args(char *fmt, ...) {
// ALL: [[VA1:%.+]] = bitcast i8** %va to i8*
// ALL: call void @llvm.va_start(i8* [[VA1]])
//
-// ALL: [[AP_CUR:%.+]] = load i8** %va, align [[PTRALIGN]]
-//
-// O32: [[TMP0:%.+]] = bitcast i8* [[AP_CUR]] to i32*
-// NEW: [[TMP0:%.+]] = bitcast i8* [[AP_CUR]] to i64*
+// O32: [[TMP0:%.+]] = bitcast i8** %va to i32**
+// O32: [[AP_CUR:%.+]] = load i32** [[TMP0]], align [[PTRALIGN]]
+// NEW: [[TMP0:%.+]] = bitcast i8** %va to i64**
+// NEW: [[AP_CUR:%.+]] = load i64** [[TMP0]], align [[PTRALIGN]]
//
-// O32: [[AP_NEXT:%.+]] = getelementptr i8* [[AP_CUR]], i32 4
-// NEW: [[AP_NEXT:%.+]] = getelementptr i8* [[AP_CUR]], [[INTPTR_T:i32|i64]] 8
+// O32: [[AP_NEXT1:%.+]] = getelementptr i32* [[AP_CUR]], i32 1
+// NEW: [[AP_NEXT1:%.+]] = getelementptr i64* [[AP_CUR]], [[INTPTR_T:i32|i64]] 1
//
-// O32: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]]
+// O32: store i32* [[AP_NEXT1]], i32** [[TMP0]], align [[PTRALIGN]]
// FIXME: N32 optimised this store out. Why only for this ABI?
-// N64: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]]
+// N64: store i64* [[AP_NEXT1]], i64** [[TMP0]], align [[PTRALIGN]]
//
-// O32: [[ARG1:%.+]] = load i32* [[TMP0]], align 4
-// NEW: [[TMP3:%.+]] = load i64* [[TMP0]], align 8
+// O32: [[ARG1:%.+]] = load i32* [[AP_CUR]], align 4
+// NEW: [[TMP3:%.+]] = load i64* [[AP_CUR]], align 8
// NEW: [[ARG1:%.+]] = trunc i64 [[TMP3]] to i32
//
-// O32: [[TMP1:%.+]] = bitcast i8* [[AP_NEXT]] to i32*
-// NEW: [[TMP1:%.+]] = bitcast i8* [[AP_NEXT]] to i64*
+// O32: [[AP_NEXT2:%.+]] = getelementptr i32* [[AP_CUR]], i32 2
+// NEW: [[AP_NEXT2:%.+]] = getelementptr i64* [[AP_CUR]], [[INTPTR_T]] 2
//
-// O32: [[AP_NEXT3:%.+]] = getelementptr i8* [[AP_CUR]], i32 8
-// NEW: [[AP_NEXT3:%.+]] = getelementptr i8* [[AP_CUR]], [[INTPTR_T]] 16
+// O32: store i32* [[AP_NEXT2]], i32** [[TMP0]], align [[PTRALIGN]]
+// NEW: store i64* [[AP_NEXT2]], i64** [[TMP0]], align [[PTRALIGN]]
//
-// ALL: store i8* [[AP_NEXT3]], i8** %va, align [[PTRALIGN]]
-//
-// O32: [[ARG2:%.+]] = load i32* [[TMP1]], align 4
-// NEW: [[TMP4:%.+]] = load i64* [[TMP1]], align 8
+// O32: [[ARG2:%.+]] = load i32* [[AP_NEXT1]], align 4
+// NEW: [[TMP4:%.+]] = load i64* [[AP_NEXT1]], align 8
// NEW: [[ARG2:%.+]] = trunc i64 [[TMP4]] to i32
//
// ALL: call void @llvm.va_end(i8* [[VA1]])
@@ -112,9 +111,9 @@ long long test_i64(char *fmt, ...) {
// ALL: [[VA1:%.+]] = bitcast i8** %va to i8*
// ALL: call void @llvm.va_start(i8* [[VA1]])
//
-// ALL: [[AP_CUR:%.+]] = load i8** %va, align [[PTRALIGN]]
-//
-// NEW: [[TMP0:%.+]] = bitcast i8* [[AP_CUR]] to i64*
+// O32: [[AP_CUR:%.+]] = load i8** %va, align [[PTRALIGN]]
+// NEW: [[TMP0:%.+]] = bitcast i8** %va to i64**
+// NEW: [[AP_CUR:%.+]] = load i64** [[TMP0]], align [[PTRALIGN]]
//
// i64 is 8-byte aligned, while this is within O32's stack alignment there's no
// guarantee that the offset is still 8-byte aligned after earlier reads.
@@ -125,17 +124,67 @@ long long test_i64(char *fmt, ...) {
// O32: [[PTR4:%.+]] = inttoptr [[INTPTR_T]] [[PTR2]] to i8*
//
// O32: [[AP_NEXT:%.+]] = getelementptr i8* [[PTR4]], [[INTPTR_T]] 8
-// NEW: [[AP_NEXT:%.+]] = getelementptr i8* [[AP_CUR]], [[INTPTR_T]] 8
+// NEW: [[AP_NEXT:%.+]] = getelementptr i64* [[AP_CUR]], [[INTPTR_T:i32|i64]] 1
//
-// ALL: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]]
+// O32: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]]
+// NEW: store i64* [[AP_NEXT]], i64** [[TMP0]], align [[PTRALIGN]]
//
// O32: [[ARG1:%.+]] = load i64* [[PTR3]], align 8
-// NEW: [[ARG1:%.+]] = load i64* [[TMP0]], align 8
+// NEW: [[ARG1:%.+]] = load i64* [[AP_CUR]], align 8
//
// ALL: call void @llvm.va_end(i8* [[VA1]])
// ALL: ret i64 [[ARG1]]
// ALL: }
+char *test_ptr(char *fmt, ...) {
+ va_list va;
+
+ va_start(va, fmt);
+ char *v = va_arg(va, char *);
+ va_end(va);
+
+ return v;
+}
+
+// ALL-LABEL: define i8* @test_ptr(i8*{{.*}} %fmt, ...)
+//
+// O32: %va = alloca i8*, align [[PTRALIGN:4]]
+// N32: %va = alloca i8*, align [[PTRALIGN:4]]
+// N64: %va = alloca i8*, align [[PTRALIGN:8]]
+//
+// ALL: [[VA1:%.+]] = bitcast i8** %va to i8*
+// ALL: call void @llvm.va_start(i8* [[VA1]])
+//
+// O32: [[TMP0:%.+]] = bitcast i8** %va to i8***
+// O32: [[AP_CUR:%.+]] = load i8*** [[TMP0]], align [[PTRALIGN]]
+// N32 differs because the vararg is not a N32 pointer. It's been promoted to 64-bit.
+// N32: [[TMP0:%.+]] = bitcast i8** %va to i64**
+// N32: [[AP_CUR:%.+]] = load i64** [[TMP0]], align [[PTRALIGN]]
+// N64: [[TMP0:%.+]] = bitcast i8** %va to i8***
+// N64: [[AP_CUR:%.+]] = load i8*** [[TMP0]], align [[PTRALIGN]]
+//
+// O32: [[AP_NEXT:%.+]] = getelementptr i8** [[AP_CUR]], i32 1
+// N32 differs because the vararg is not a N32 pointer. It's been promoted to 64-bit.
+// N32: [[AP_NEXT:%.+]] = getelementptr i64* [[AP_CUR]], {{i32|i64}} 1
+// N64: [[AP_NEXT:%.+]] = getelementptr i8** [[AP_CUR]], {{i32|i64}} 1
+//
+// O32: store i8** [[AP_NEXT]], i8*** [[TMP0]], align [[PTRALIGN]]
+// N32 differs because the vararg is not a N32 pointer. It's been promoted to 64-bit.
+// N32: store i64* [[AP_NEXT]], i64** [[TMP0]], align [[PTRALIGN]]
+// N64: store i8** [[AP_NEXT]], i8*** [[TMP0]], align [[PTRALIGN]]
+//
+// O32: [[ARG1:%.+]] = load i8** [[AP_CUR]], align 4
+// N32 differs because the vararg is not a N32 pointer. It's been promoted to
+// 64-bit so we must truncate the excess and bitcast to a N32 pointer.
+// N32: [[TMP2:%.+]] = load i64* [[AP_CUR]], align 8
+// N32: [[TMP3:%.+]] = trunc i64 [[TMP2]] to i32
+// N32: [[ARG1:%.+]] = inttoptr i32 [[TMP3]] to i8*
+// N64: [[ARG1:%.+]] = load i8** [[AP_CUR]], align 8
+//
+// ALL: call void @llvm.va_end(i8* [[VA1]])
+// ALL: ret i8* [[ARG1]]
+// ALL: }
+
int test_v4i32(char *fmt, ...) {
va_list va;
diff --git a/test/CodeGen/mmx-inline-asm-error.c b/test/CodeGen/mmx-inline-asm-error.c
index 876c664e3b57..1e2246176a11 100644
--- a/test/CodeGen/mmx-inline-asm-error.c
+++ b/test/CodeGen/mmx-inline-asm-error.c
@@ -4,9 +4,9 @@ typedef int vec256 __attribute__((ext_vector_type(8)));
vec256 foo(vec256 in) {
vec256 out;
- asm("something %0" : : "y"(in)); // expected-error {{invalid type 'vec256' (vector of 8 'int' values) in asm input for constraint 'y'}}
- asm("something %0" : "=y"(out)); // expected-error {{invalid type 'vec256' (vector of 8 'int' values) in asm input for constraint 'y'}}
- asm("something %0, %0" : "+y"(out)); // expected-error {{invalid type 'vec256' (vector of 8 'int' values) in asm input for constraint 'y'}}
+ asm("something %0" : : "y"(in)); // expected-error {{invalid input size for constraint 'y'}}
+ asm("something %0" : "=y"(out)); // expected-error {{invalid output size for constraint '=y'}}
+ asm("something %0, %0" : "+y"(out)); // expected-error {{invalid output size for constraint '+y'}}
return out;
}
diff --git a/test/CodeGen/mozilla-ms-inline-asm.c b/test/CodeGen/mozilla-ms-inline-asm.c
index 0f541d70fcdd..b8b7a2d677dd 100644
--- a/test/CodeGen/mozilla-ms-inline-asm.c
+++ b/test/CodeGen/mozilla-ms-inline-asm.c
@@ -3,6 +3,8 @@
// Some test cases for MS inline asm support from Mozilla code base.
+void invoke_copy_to_stack() {}
+
void invoke(void* that, unsigned methodIndex,
unsigned paramCount, void* params)
{
@@ -18,24 +20,25 @@ void invoke(void* that, unsigned methodIndex,
// CHECK: call void asm sideeffect inteldialect
// CHECK: mov edx,dword ptr $1
// CHECK: test edx,edx
-// CHECK: jz noparams
+// CHECK: jz {{[^_]*}}__MSASMLABEL_.0__noparams
+// ^ Can't use {{.*}} here because the matching is greedy.
// CHECK: mov eax,edx
// CHECK: shl eax,$$3
// CHECK: sub esp,eax
// CHECK: mov ecx,esp
// CHECK: push dword ptr $0
-// CHECK: call invoke_copy_to_stack
-// CHECK: noparams:
-// CHECK: mov ecx,dword ptr $2
+// CHECK: call dword ptr $2
+// CHECK: {{.*}}__MSASMLABEL_.0__noparams:
+// CHECK: mov ecx,dword ptr $3
// CHECK: push ecx
// CHECK: mov edx,[ecx]
-// CHECK: mov eax,dword ptr $3
+// CHECK: mov eax,dword ptr $4
// CHECK: call dword ptr[edx+eax*$$4]
// CHECK: mov esp,ebp
// CHECK: pop ebp
// CHECK: ret
-// CHECK: "=*m,*m,*m,*m,~{eax},~{ebp},~{ecx},~{edx},~{flags},~{esp},~{dirflag},~{fpsr},~{flags}"
-// CHECK: (i8** %8, i32* %7, i8** %5, i32* %6)
+// CHECK: "=*m,*m,*m,*m,*m,~{eax},~{ebp},~{ecx},~{edx},~{flags},~{esp},~{dirflag},~{fpsr},~{flags}"
+// CHECK: (i8** %8, i32* %7, void (...)* bitcast (void ()* @invoke_copy_to_stack to void (...)*), i8** %5, i32* %6)
// CHECK: ret void
__asm {
mov edx,paramCount
diff --git a/test/CodeGen/mrtd.c b/test/CodeGen/mrtd.c
index 8fa7cf02cead..f929d4c26b28 100644
--- a/test/CodeGen/mrtd.c
+++ b/test/CodeGen/mrtd.c
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -mrtd -triple i386-unknown-unknown -std=c89 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -mrtd -triple i386-unknown-unknown -std=c89 -emit-llvm -o - %s 2>&1 | FileCheck %s
+
+// CHECK: mrtd.c:10:3: warning: function with no prototype cannot use the stdcall calling convention
void baz(int arg);
diff --git a/test/CodeGen/ms-align-tentative.c b/test/CodeGen/ms-align-tentative.c
new file mode 100644
index 000000000000..ccd761616471
--- /dev/null
+++ b/test/CodeGen/ms-align-tentative.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -fms-compatibility -o - | FileCheck %s
+
+char __declspec(align(8192)) x;
+// CHECK-DAG: @x = global i8 0, align 8192
+
+typedef char __declspec(align(8192)) T;
+T y;
+// CHECK-DAG: @y = global i8 0, align 8192
+
+T __declspec(align(8192)) z;
+// CHECK-DAG: @z = global i8 0, align 8192
+
+int __declspec(align(16)) redef;
+int __declspec(align(32)) redef = 8;
+// CHECK-DAG: @redef = global i32 8, align 32
diff --git a/test/CodeGen/ms-declspecs.c b/test/CodeGen/ms-declspecs.c
index 5dc7787b8fb9..328fc835d347 100644
--- a/test/CodeGen/ms-declspecs.c
+++ b/test/CodeGen/ms-declspecs.c
@@ -2,8 +2,8 @@
__declspec(selectany) int x1 = 1;
const __declspec(selectany) int x2 = 2;
-// CHECK: @x1 = weak_odr global i32 1, align 4
-// CHECK: @x2 = weak_odr constant i32 2, align 4
+// CHECK: @x1 = weak_odr global i32 1, comdat, align 4
+// CHECK: @x2 = weak_odr constant i32 2, comdat, align 4
struct __declspec(align(16)) S {
char x;
diff --git a/test/CodeGen/ms-inline-asm-functions.c b/test/CodeGen/ms-inline-asm-functions.c
new file mode 100644
index 000000000000..1a6ead9286df
--- /dev/null
+++ b/test/CodeGen/ms-inline-asm-functions.c
@@ -0,0 +1,60 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 %s -triple i386-pc-windows-msvc -fms-extensions -S -o - | FileCheck %s
+
+// Yes, this is an assembly test from Clang, because we need to make it all the
+// way through code generation to know if our call became a direct, pc-relative
+// call or an indirect call through memory.
+
+int k(int);
+__declspec(dllimport) int kimport(int);
+int (*kptr)(int);
+int (*gptr())(int);
+
+int foo() {
+ // CHECK-LABEL: _foo:
+ int (*r)(int) = gptr();
+
+ // Simple case: direct call.
+ __asm call k;
+ // CHECK: calll _k
+
+ // Marginally harder: indirect calls, via dllimport or function pointer.
+ __asm call r;
+ // CHECK: calll *({{.*}})
+ __asm call kimport;
+ // CHECK: calll *({{.*}})
+
+ // Broken case: Call through a global function pointer.
+ __asm call kptr;
+ // CHECK: calll _kptr
+ // CHECK-FIXME: calll *_kptr
+}
+
+int bar() {
+ // CHECK-LABEL: _bar:
+ __asm jmp k;
+ // CHECK: jmp _k
+}
+
+int baz() {
+ // CHECK-LABEL: _baz:
+ __asm mov eax, k;
+ // CHECK: movl _k, %eax
+ __asm mov eax, kptr;
+ // CHECK: movl _kptr, %eax
+}
+
+// Test that this asm blob doesn't require more registers than available. This
+// has to be an LLVM code generation test.
+
+void __declspec(naked) naked() {
+ __asm pusha
+ __asm call k
+ __asm popa
+ __asm ret
+ // CHECK-LABEL: _naked:
+ // CHECK: pushal
+ // CHECK-NEXT: calll _k
+ // CHECK-NEXT: popal
+ // CHECK-NEXT: retl
+}
diff --git a/test/CodeGen/ms-inline-asm.c b/test/CodeGen/ms-inline-asm.c
index 2c6710694142..59ff2023a465 100644
--- a/test/CodeGen/ms-inline-asm.c
+++ b/test/CodeGen/ms-inline-asm.c
@@ -10,9 +10,7 @@ void t1() {
void t2() {
// CHECK: @t2
-// CHECK: call void asm sideeffect inteldialect "nop", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "nop", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "nop", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "nop\0A\09nop\0A\09nop", "~{dirflag},~{fpsr},~{flags}"()
// CHECK: ret void
__asm nop
__asm nop
@@ -28,8 +26,7 @@ void t3() {
void t4(void) {
// CHECK: @t4
-// CHECK: call void asm sideeffect inteldialect "mov ebx, eax", "~{ebx},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov ecx, ebx", "~{ecx},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov ebx, eax\0A\09mov ecx, ebx", "~{ebx},~{ecx},~{dirflag},~{fpsr},~{flags}"()
// CHECK: ret void
__asm mov ebx, eax
__asm mov ecx, ebx
@@ -69,9 +66,7 @@ int t8() {
__asm int 4
return 10;
// CHECK: t8
-// CHECK: call void asm sideeffect inteldialect "int $$4", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "int $$4", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call i32 asm sideeffect inteldialect "int $$4\0A\09int $$4", "={eax},~{dirflag},~{fpsr},~{flags}"()
// CHECK: ret i32 10
}
@@ -93,10 +88,11 @@ unsigned t10(void) {
}
return j;
// CHECK: t10
+// CHECK: [[r:%[a-zA-Z0-9]+]] = alloca i32, align 4
// CHECK: [[I:%[a-zA-Z0-9]+]] = alloca i32, align 4
// CHECK: [[J:%[a-zA-Z0-9]+]] = alloca i32, align 4
// CHECK: store i32 1, i32* [[I]], align 4
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $1\0A\09mov dword ptr $0, eax", "=*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}})
+// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $2\0A\09mov dword ptr $0, eax", "=*m,={eax},*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}})
// CHECK: [[RET:%[a-zA-Z0-9]+]] = load i32* [[J]], align 4
// CHECK: ret i32 [[RET]]
}
@@ -117,7 +113,7 @@ unsigned t12(void) {
}
return j + m;
// CHECK: t12
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $2\0A\09mov dword ptr $0, eax\0A\09mov eax, dword ptr $3\0A\09mov dword ptr $1, eax", "=*m,=*m,*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}})
+// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $3\0A\09mov dword ptr $0, eax\0A\09mov eax, dword ptr $4\0A\09mov dword ptr $1, eax", "=*m,=*m,={eax},*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}})
}
void t13() {
@@ -126,8 +122,7 @@ void t13() {
__asm movzx eax, i
__asm movzx eax, j
// CHECK: t13
-// CHECK: call void asm sideeffect inteldialect "movzx eax, byte ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i8* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "movzx eax, word ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i16* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "movzx eax, byte ptr $0\0A\09movzx eax, word ptr $1", "*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i8* %{{.*}}i, i16* %{{.*}}j)
}
void t14() {
@@ -145,14 +140,15 @@ void t14() {
int gvar = 10;
void t15() {
+// CHECK: t15
int lvar = 10;
__asm mov eax, lvar ; eax = 10
+// CHECK: mov eax, dword ptr $0
__asm mov eax, offset lvar ; eax = address of lvar
+// CHECK: mov eax, $1
__asm mov eax, offset gvar ; eax = address of gvar
-// CHECK: t15
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* @{{.*}})
+// CHECK: mov eax, $2
+// CHECK: "*m,r,r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* @{{.*}})
}
void t16() {
@@ -163,50 +159,52 @@ void t16() {
}
void t17() {
+// CHECK: t17
__asm _emit 0x4A
+// CHECK: .byte 0x4A
__asm _emit 0x43
+// CHECK: .byte 0x43
__asm _emit 0x4B
+// CHECK: .byte 0x4B
__asm _EMIT 0x4B
-// CHECK: t17
-// CHECK: call void asm sideeffect inteldialect ".byte 0x4A", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect ".byte 0x43", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect ".byte 0x4B", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect ".byte 0x4B", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: .byte 0x4B
+// CHECK: "~{dirflag},~{fpsr},~{flags}"()
}
void t20() {
+// CHECK: t20
char bar;
int foo;
char _bar[2];
int _foo[4];
__asm mov eax, LENGTH foo
+// CHECK: mov eax, $$1
__asm mov eax, LENGTH bar
+// CHECK: mov eax, $$1
__asm mov eax, LENGTH _foo
+// CHECK: mov eax, $$4
__asm mov eax, LENGTH _bar
-// CHECK: t20
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: mov eax, $$2
__asm mov eax, TYPE foo
+// CHECK: mov eax, $$4
__asm mov eax, TYPE bar
+// CHECK: mov eax, $$1
__asm mov eax, TYPE _foo
+// CHECK: mov eax, $$4
__asm mov eax, TYPE _bar
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: mov eax, $$1
__asm mov eax, SIZE foo
+// CHECK: mov eax, $$4
__asm mov eax, SIZE bar
+// CHECK: mov eax, $$1
__asm mov eax, SIZE _foo
+// CHECK: mov eax, $$16
__asm mov eax, SIZE _bar
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$16", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: mov eax, $$2
+// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t21() {
@@ -242,45 +240,46 @@ void t23() {
the_label:
}
// CHECK: t23
-// CHECK: call void asm sideeffect inteldialect "the_label:", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.0__the_label:", "~{dirflag},~{fpsr},~{flags}"()
}
void t24_helper(void) {}
void t24() {
__asm call t24_helper
// CHECK: t24
-// CHECK: call void asm sideeffect inteldialect "call $0", "r,~{dirflag},~{fpsr},~{flags}"(void ()* @t24_helper)
+// CHECK: call void asm sideeffect inteldialect "call dword ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(void ()* @t24_helper)
}
void t25() {
+// CHECK: t25
__asm mov eax, 0ffffffffh
+// CHECK: mov eax, $$4294967295
__asm mov eax, 0fh
+// CHECK: mov eax, $$15
__asm mov eax, 0a2h
+// CHECK: mov eax, $$162
__asm mov eax, 0xa2h
+// CHECK: mov eax, $$0xa2h
__asm mov eax, 0xa2
-// CHECK: t25
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4294967295", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$15", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$162", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$0xa2h", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$0xa2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: mov eax, $$0xa2
+// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t26() {
+// CHECK: t26
__asm pushad
+// CHECK: pushad
__asm mov eax, 0
+// CHECK: mov eax, $$0
__asm __emit 0fh
+// CHECK: .byte 0fh
__asm __emit 0a2h
+// CHECK: .byte 0a2h
__asm __EMIT 0a2h
+// CHECK: .byte 0a2h
__asm popad
-// FIXME: These all need to be merged into the same asm blob.
-// CHECK: t26
-// CHECK: call void asm sideeffect inteldialect "pushad", "~{esp},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$0", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect ".byte 0fh", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect ".byte 0a2h", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect ".byte 0a2h", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "popad", "~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: popad
+// CHECK: "~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"()
}
void t27() {
@@ -290,160 +289,171 @@ void t27() {
}
void t28() {
+// CHECK: t28
__asm align 8
+// CHECK: .align 3
__asm align 16;
+// CHECK: .align 4
__asm align 128;
+// CHECK: .align 7
__asm ALIGN 256;
-// CHECK: t28
-// CHECK: call void asm sideeffect inteldialect ".align 3", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect ".align 4", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect ".align 7", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect ".align 8", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: .align 8
+// CHECK: "~{dirflag},~{fpsr},~{flags}"()
}
void t29() {
+// CHECK: t29
int arr[2] = {0, 0};
int olen = 0, osize = 0, otype = 0;
__asm mov olen, LENGTH arr
+// CHECK: mov dword ptr $0, $$2
__asm mov osize, SIZE arr
+// CHECK: mov dword ptr $1, $$8
__asm mov otype, TYPE arr
-// CHECK: t29
-// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, $$2", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, $$8", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, $$4", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: mov dword ptr $2, $$4
+// CHECK: "=*m,=*m,=*m,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}})
}
int results[2] = {13, 37};
int *t30()
+// CHECK: t30
{
int *res;
__asm lea edi, results
+// CHECK: lea edi, dword ptr $2
__asm mov res, edi
+// CHECK: mov dword ptr $0, edi
return res;
-// CHECK: t30
-// CHECK: call void asm sideeffect inteldialect "lea edi, dword ptr $0", "*m,~{edi},~{dirflag},~{fpsr},~{flags}"([2 x i32]* @{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, edi", "=*m,~{dirflag},~{fpsr},~{flags}"(i32** %{{.*}})
+// CHECK: "=*m,={eax},*m,~{edi},~{dirflag},~{fpsr},~{flags}"(i32** %{{.*}}, [2 x i32]* @{{.*}})
}
void t31() {
+// CHECK: t31
__asm pushad
+// CHECK: pushad
__asm popad
-// CHECK: t31
-// CHECK: call void asm sideeffect inteldialect "pushad", "~{esp},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "popad", "~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: popad
+// CHECK: "~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"()
}
void t32() {
+// CHECK: t32
int i;
__asm mov eax, i
+// CHECK: mov eax, dword ptr $0
__asm mov eax, dword ptr i
+// CHECK: mov eax, dword ptr $1
__asm mov ax, word ptr i
+// CHECK: mov ax, word ptr $2
__asm mov al, byte ptr i
-// CHECK: t32
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov ax, word ptr $0", "*m,~{ax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov al, byte ptr $0", "*m,~{al},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: mov al, byte ptr $3
+// CHECK: "*m,*m,*m,*m,~{al},~{ax},~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}})
}
void t33() {
+// CHECK: t33
int i;
__asm mov eax, [i]
+// CHECK: mov eax, dword ptr $0
__asm mov eax, dword ptr [i]
+// CHECK: mov eax, dword ptr $1
__asm mov ax, word ptr [i]
+// CHECK: mov ax, word ptr $2
__asm mov al, byte ptr [i]
-// CHECK: t33
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov ax, word ptr $0", "*m,~{ax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
-// CHECK: call void asm sideeffect inteldialect "mov al, byte ptr $0", "*m,~{al},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: mov al, byte ptr $3
+// CHECK: "*m,*m,*m,*m,~{al},~{ax},~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}})
}
void t34() {
+// CHECK: t34
__asm prefetchnta 64[eax]
+// CHECK: prefetchnta $$64[eax]
__asm mov eax, dword ptr 4[eax]
-// CHECK: t34
-// CHECK: call void asm sideeffect inteldialect "prefetchnta $$64[eax]", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4[eax]", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: mov eax, dword ptr $$4[eax]
+// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t35() {
+// CHECK: t35
__asm prefetchnta [eax + (200*64)]
+// CHECK: prefetchnta [eax + ($$200*$$64)]
__asm mov eax, dword ptr [eax + (200*64)]
-// CHECK: t35
-// CHECK: call void asm sideeffect inteldialect "prefetchnta [eax + ($$200*$$64)]", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr [eax + ($$200*$$64)]", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: mov eax, dword ptr [eax + ($$200*$$64)]
+// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t36() {
- int arr[4];
- __asm mov eax, 4[arr]
- __asm mov eax, 4[arr + 4]
- __asm mov eax, 8[arr + 4 + 32*2 - 4]
- __asm mov eax, 12[4 + arr]
- __asm mov eax, 4[4 + arr + 4]
- __asm mov eax, 4[64 + arr + (2*32)]
- __asm mov eax, 4[64 + arr - 2*32]
- __asm mov eax, [arr + 4]
- __asm mov eax, [arr + 4 + 32*2 - 4]
- __asm mov eax, [4 + arr]
- __asm mov eax, [4 + arr + 4]
- __asm mov eax, [64 + arr + (2*32)]
- __asm mov eax, [64 + arr - 2*32]
// CHECK: t36
+ int arr[4];
+ // Work around PR20368: These should be single line blocks
+ __asm { mov eax, 4[arr] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 4[arr + 4] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 8[arr + 4 + 32*2 - 4] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$72$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 12[4 + arr] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$16$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 4[4 + arr + 4] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$12$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 4[64 + arr + (2*32)] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$132$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 4[64 + arr - 2*32] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, [arr + 4] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, [arr + 4 + 32*2 - 4] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$64$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, [4 + arr] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, [4 + arr + 4] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, [64 + arr + (2*32)] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$128$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, [64 + arr - 2*32] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
}
void t37() {
+// CHECK: t37
__asm mov eax, 4 + 8
+// CHECK: mov eax, $$12
__asm mov eax, 4 + 8 * 16
+// CHECK: mov eax, $$132
__asm mov eax, -4 + 8 * 16
+// CHECK: mov eax, $$124
__asm mov eax, (4 + 4) * 16
+// CHECK: mov eax, $$128
__asm mov eax, 4 + 8 * -16
+// CHECK: mov eax, $$4294967172
__asm mov eax, 4 + 16 / -8
+// CHECK: mov eax, $$2
__asm mov eax, (16 + 16) / -8
+// CHECK: mov eax, $$4294967292
__asm mov eax, ~15
-// CHECK: t37
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$12", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$132", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$124", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$128", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4294967172", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4294967292", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4294967280", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: mov eax, $$4294967280
+// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t38() {
- int arr[4];
- __asm mov eax, 4+4[arr]
- __asm mov eax, (4+4)[arr + 4]
- __asm mov eax, 8*2[arr + 4 + 32*2 - 4]
- __asm mov eax, 12+20[4 + arr]
- __asm mov eax, 4*16+4[4 + arr + 4]
- __asm mov eax, 4*4[64 + arr + (2*32)]
- __asm mov eax, 4*(4-2)[64 + arr - 2*32]
- __asm mov eax, 32*(4-2)[arr - 2*32]
// CHECK: t38
+ int arr[4];
+ // Work around PR20368: These should be single line blocks
+ __asm { mov eax, 4+4[arr] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, (4+4)[arr + 4] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$12$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 8*2[arr + 4 + 32*2 - 4] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$80$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 12+20[4 + arr] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$36$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 4*16+4[4 + arr + 4] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$76$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 4*4[64 + arr + (2*32)] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$144$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 4*(4-2)[64 + arr - 2*32] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+ __asm { mov eax, 32*(4-2)[arr - 2*32] }
// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$0$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
}
@@ -459,38 +469,87 @@ typedef struct {
} A;
void t39() {
+// CHECK-LABEL: define void @t39
__asm mov eax, [eax].A.b
+// CHECK: mov eax, [eax].4
__asm mov eax, [eax] A.b
+// CHECK: mov eax, [eax] .4
__asm mov eax, fs:[0] A.b
- // CHECK-LABEL: define void @t39
- // CHECK: call void asm sideeffect inteldialect "mov eax, [eax].4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
- // CHECK: call void asm sideeffect inteldialect "mov eax, [eax] .4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
- // CHECK: call void asm sideeffect inteldialect "mov eax, fs:[$$0] .4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: mov eax, fs:[$$0] .4
+// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t40(float a) {
+// CHECK-LABEL: define void @t40
int i;
__asm fld a
+// CHECK: fld dword ptr $1
__asm fistp i
- // CHECK-LABEL: define void @t40
- // CHECK: call void asm sideeffect inteldialect "fld dword ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(float* {{.*}})
- // CHECK: call void asm sideeffect inteldialect "fistp dword ptr $0", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* {{.*}})
+// CHECK: fistp dword ptr $0
+// CHECK: "=*m,*m,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, float* %{{.*}})
}
void t41(unsigned short a) {
+// CHECK-LABEL: define void @t41(i16 zeroext %a)
__asm mov cs, a;
+// CHECK: mov cs, word ptr $0
__asm mov ds, a;
+// CHECK: mov ds, word ptr $1
__asm mov es, a;
+// CHECK: mov es, word ptr $2
__asm mov fs, a;
+// CHECK: mov fs, word ptr $3
__asm mov gs, a;
+// CHECK: mov gs, word ptr $4
__asm mov ss, a;
- // CHECK-LABEL: define void @t41(i16 zeroext %a)
- // CHECK: [[T41_A_ADDR:%.+]] = alloca i16
- // CHECK: store i16 %a, i16* [[T41_A_ADDR]]
- // CHECK: call void asm sideeffect inteldialect "mov cs, word ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(i16* [[T41_A_ADDR]])
- // CHECK: call void asm sideeffect inteldialect "mov ds, word ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(i16* [[T41_A_ADDR]])
- // CHECK: call void asm sideeffect inteldialect "mov es, word ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(i16* [[T41_A_ADDR]])
- // CHECK: call void asm sideeffect inteldialect "mov fs, word ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(i16* [[T41_A_ADDR]])
- // CHECK: call void asm sideeffect inteldialect "mov gs, word ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(i16* [[T41_A_ADDR]])
- // CHECK: call void asm sideeffect inteldialect "mov ss, word ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(i16* [[T41_A_ADDR]])
+// CHECK: mov ss, word ptr $5
+// CHECK: "*m,*m,*m,*m,*m,*m,~{dirflag},~{fpsr},~{flags}"(i16* {{.*}}, i16* {{.*}}, i16* {{.*}}, i16* {{.*}}, i16* {{.*}}, i16* {{.*}})
+}
+
+void call_clobber() {
+ __asm call t41
+ // CHECK-LABEL: define void @call_clobber
+ // CHECK: call void asm sideeffect inteldialect "call dword ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(void (i16)* @t41)
+}
+
+void xgetbv() {
+ __asm xgetbv
+}
+// CHECK-LABEL: define void @xgetbv()
+// CHECK: call void asm sideeffect inteldialect "xgetbv", "~{eax},~{edx},~{dirflag},~{fpsr},~{flags}"()
+
+void label1() {
+ __asm {
+ label:
+ jmp label
+ }
+ // CHECK-LABEL: define void @label1
+ // CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.1__label:\0A\09jmp {{.*}}__MSASMLABEL_.1__label", "~{dirflag},~{fpsr},~{flags}"()
+}
+
+void label2() {
+ __asm {
+ jmp label
+ label:
+ }
+ // CHECK-LABEL: define void @label2
+ // CHECK: call void asm sideeffect inteldialect "jmp {{.*}}__MSASMLABEL_.2__label\0A\09{{.*}}__MSASMLABEL_.2__label:", "~{dirflag},~{fpsr},~{flags}"()
+}
+
+void label3() {
+ __asm {
+ label:
+ mov eax, label
+ }
+ // CHECK-LABEL: define void @label3
+ // CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.3__label:\0A\09mov eax, {{.*}}__MSASMLABEL_.3__label", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+}
+
+void label4() {
+ __asm {
+ label:
+ mov eax, [label]
+ }
+ // CHECK-LABEL: define void @label4
+ // CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.4__label:\0A\09mov eax, {{.*}}__MSASMLABEL_.4__label", "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
diff --git a/test/CodeGen/ms-inline-asm.cpp b/test/CodeGen/ms-inline-asm.cpp
index 83fe1075aff7..03d971e698b5 100644
--- a/test/CodeGen/ms-inline-asm.cpp
+++ b/test/CodeGen/ms-inline-asm.cpp
@@ -22,11 +22,7 @@ void t1() {
__asm mov eax, dword ptr [Foo :: ptr]
__asm mov eax, dword ptr [Foo :: ptr]
// CHECK: @_Z2t1v
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE)
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3Bar3ptrE)
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE)
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE)
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE)
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0\0A\09mov eax, dword ptr $1\0A\09mov eax, dword ptr $2\0A\09mov eax, dword ptr $3\0A\09mov eax, dword ptr $4", "*m,*m,*m,*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3Bar3ptrE, i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3ptrE)
}
int gvar = 10;
@@ -35,38 +31,26 @@ void t2() {
__asm mov eax, offset Foo::ptr
__asm mov eax, offset Foo::Bar::ptr
// CHECK: t2
-// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE)
-// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3Bar3ptrE)
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0\0A\09mov eax, $1", "r,r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3Bar3ptrE)
}
// CHECK-LABEL: define void @_Z2t3v()
void t3() {
__asm mov eax, LENGTH Foo::ptr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, LENGTH Foo::Bar::ptr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, LENGTH Foo::arr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, LENGTH Foo::Bar::arr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, TYPE Foo::ptr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, TYPE Foo::Bar::ptr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, TYPE Foo::arr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, TYPE Foo::Bar::arr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, SIZE Foo::ptr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, SIZE Foo::Bar::ptr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, SIZE Foo::arr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$16", "~{eax},~{dirflag},~{fpsr},~{flags}"()
__asm mov eax, SIZE Foo::Bar::arr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1\0A\09mov eax, $$1\0A\09mov eax, $$4\0A\09mov eax, $$2\0A\09mov eax, $$4\0A\09mov eax, $$4\0A\09mov eax, $$4\0A\09mov eax, $$1\0A\09mov eax, $$4\0A\09mov eax, $$4\0A\09mov eax, $$16\0A\09mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
@@ -82,9 +66,8 @@ void T4::test() {
// CHECK: [[THIS:%.*]] = load [[T4]]** [[T0]]
// CHECK: [[X:%.*]] = getelementptr inbounds [[T4]]* [[THIS]], i32 0, i32 0
__asm mov eax, x;
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* [[X]])
__asm mov y, eax;
-// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, eax", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* @_ZN2T41yE)
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $1\0A\09mov dword ptr $0, eax", "=*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* @_ZN2T41yE, i32* {{.*}})
}
template <class T> struct T5 {
@@ -97,11 +80,9 @@ void test5() {
// CHECK: [[Y:%.*]] = alloca i32
int x, y;
__asm push y
- // CHECK: call void asm sideeffect inteldialect "push dword ptr $0", "=*m,~{esp},~{dirflag},~{fpsr},~{flags}"(i32* [[Y]])
__asm call T5<int>::create<float>
- // CHECK: call void asm sideeffect inteldialect "call $0", "r,~{dirflag},~{fpsr},~{flags}"(i32 (float)* @_ZN2T5IiE6createIfEEiT_)
__asm mov x, eax
- // CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, eax", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* [[X]])
+ // CHECK: call void asm sideeffect inteldialect "push dword ptr $0\0A\09call dword ptr $2\0A\09mov dword ptr $1, eax", "=*m,=*m,*m,~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %y, i32* %x, i32 (float)* @_ZN2T5IiE6createIfEEiT_)
}
// Just verify this doesn't emit an error.
@@ -141,3 +122,20 @@ void t7_using() {
// CHECK-LABEL: define void @_Z8t7_usingv
// CHECK: call void asm sideeffect inteldialect "mov eax, [eax].4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
+
+void t8() {
+ __asm some_label:
+ // CHECK-LABEL: define void @_Z2t8v()
+ // CHECK: call void asm sideeffect inteldialect "L__MSASMLABEL_.1__some_label:", "~{dirflag},~{fpsr},~{flags}"()
+ struct A {
+ static void g() {
+ __asm jmp some_label ; This should jump forwards
+ __asm some_label:
+ __asm nop
+ // CHECK-LABEL: define internal void @_ZZ2t8vEN1A1gEv()
+ // CHECK: call void asm sideeffect inteldialect "jmp L__MSASMLABEL_.2__some_label\0A\09L__MSASMLABEL_.2__some_label:\0A\09nop", "~{dirflag},~{fpsr},~{flags}"()
+ }
+ };
+ A::g();
+}
+
diff --git a/test/CodeGen/ms-intrinsics.c b/test/CodeGen/ms-intrinsics.c
index fb0f62c61c4b..4498b34bc48d 100644
--- a/test/CodeGen/ms-intrinsics.c
+++ b/test/CodeGen/ms-intrinsics.c
@@ -1,15 +1,28 @@
-// RUN: %clang_cc1 -triple i686--windows -fms-compatibility -Oz -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -triple thumbv7--windows -fms-compatibility -Oz -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
+// RUN: -triple i686--windows -Oz -emit-llvm %s -o - \
+// RUN: | FileCheck %s -check-prefix CHECK -check-prefix CHECK-I386
+// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
+// RUN: -triple thumbv7--windows -Oz -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
+// RUN: -triple x86_64--windows -Oz -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-X64
+
+// Intrin.h needs size_t, but -ffreestanding prevents us from getting it from
+// stddef.h. Work around it with this typedef.
+typedef __SIZE_TYPE__ size_t;
+
+#include <Intrin.h>
void *test_InterlockedExchangePointer(void * volatile *Target, void *Value) {
return _InterlockedExchangePointer(Target, Value);
}
// CHECK: define{{.*}}i8* @test_InterlockedExchangePointer(i8** %Target, i8* %Value){{.*}}{
-// CHECK: %[[TARGET:[0-9]+]] = bitcast i8** %Target to i32*
-// CHECK: %[[VALUE:[0-9]+]] = ptrtoint i8* %Value to i32
-// CHECK: %[[EXCHANGE:[0-9]+]] = atomicrmw xchg i32* %[[TARGET]], i32 %[[VALUE]] seq_cst
-// CHECK: %[[RESULT:[0-9]+]] = inttoptr i32 %[[EXCHANGE]] to i8*
+// CHECK: %[[TARGET:[0-9]+]] = bitcast i8** %Target to [[iPTR:i[0-9]+]]*
+// CHECK: %[[VALUE:[0-9]+]] = ptrtoint i8* %Value to [[iPTR]]
+// CHECK: %[[EXCHANGE:[0-9]+]] = atomicrmw xchg [[iPTR]]* %[[TARGET]], [[iPTR]] %[[VALUE]] seq_cst
+// CHECK: %[[RESULT:[0-9]+]] = inttoptr [[iPTR]] %[[EXCHANGE]] to i8*
// CHECK: ret i8* %[[RESULT]]
// CHECK: }
@@ -19,12 +32,12 @@ void *test_InterlockedCompareExchangePointer(void * volatile *Destination,
}
// CHECK: define{{.*}}i8* @test_InterlockedCompareExchangePointer(i8** %Destination, i8* %Exchange, i8* %Comparand){{.*}}{
-// CHECK: %[[DEST:[0-9]+]] = bitcast i8** %Destination to i32*
-// CHECK: %[[EXCHANGE:[0-9]+]] = ptrtoint i8* %Exchange to i32
-// CHECK: %[[COMPARAND:[0-9]+]] = ptrtoint i8* %Comparand to i32
-// CHECK: %[[XCHG:[0-9]+]] = cmpxchg volatile i32* %[[DEST:[0-9]+]], i32 %[[COMPARAND:[0-9]+]], i32 %[[EXCHANGE:[0-9]+]] seq_cst seq_cst
-// CHECK: %[[EXTRACT:[0-9]+]] = extractvalue { i32, i1 } %[[XCHG]], 0
-// CHECK: %[[RESULT:[0-9]+]] = inttoptr i32 %[[EXTRACT]] to i8*
+// CHECK: %[[DEST:[0-9]+]] = bitcast i8** %Destination to [[iPTR]]*
+// CHECK: %[[EXCHANGE:[0-9]+]] = ptrtoint i8* %Exchange to [[iPTR]]
+// CHECK: %[[COMPARAND:[0-9]+]] = ptrtoint i8* %Comparand to [[iPTR]]
+// CHECK: %[[XCHG:[0-9]+]] = cmpxchg volatile [[iPTR]]* %[[DEST:[0-9]+]], [[iPTR]] %[[COMPARAND:[0-9]+]], [[iPTR]] %[[EXCHANGE:[0-9]+]] seq_cst seq_cst
+// CHECK: %[[EXTRACT:[0-9]+]] = extractvalue { [[iPTR]], i1 } %[[XCHG]], 0
+// CHECK: %[[RESULT:[0-9]+]] = inttoptr [[iPTR]] %[[EXTRACT]] to i8*
// CHECK: ret i8* %[[RESULT:[0-9]+]]
// CHECK: }
@@ -36,3 +49,25 @@ long test_InterlockedExchange(long *Target, long Value) {
// CHECK: %[[EXCHANGE:[0-9]+]] = atomicrmw xchg i32* %Target, i32 %Value seq_cst
// CHECK: ret i32 %[[EXCHANGE:[0-9]+]]
// CHECK: }
+
+#if defined(__i386__)
+long test__readfsdword(unsigned long Offset) {
+ return __readfsdword(Offset);
+}
+
+// CHECK-I386: define i32 @test__readfsdword(i32 %Offset){{.*}}{
+// CHECK-I386: [[PTR:%[0-9]+]] = inttoptr i32 %Offset to i32 addrspace(257)*
+// CHECK-I386: [[VALUE:%[0-9]+]] = load volatile i32 addrspace(257)* [[PTR]], align 4
+// CHECK-I386: ret i32 [[VALUE:%[0-9]+]]
+// CHECK-I386: }
+#endif
+
+#if defined(__x86_64__)
+unsigned __int64 test__umulh(unsigned __int64 a, unsigned __int64 b) {
+ return __umulh(a, b);
+}
+// CHECK-X64-LABEL: define i64 @test__umulh(i64 %a, i64 %b)
+// CHECK-X64: = mul nuw i128 %
+
+#endif
+
diff --git a/test/CodeGen/mult-alt-generic.c b/test/CodeGen/mult-alt-generic.c
index 6c9d789e412b..303edfcf3c42 100644
--- a/test/CodeGen/mult-alt-generic.c
+++ b/test/CodeGen/mult-alt-generic.c
@@ -17,7 +17,7 @@ int marray[2];
// CHECK: @single_m
void single_m()
{
- // CHECK: call void asm "foo $1,$0", "=*m,*m[[CLOBBERS:[a-zA-Z0-9@%{},~_ ]*\"]](i32* {{[a-zA-Z0-9@%]+}}, i32* {{[a-zA-Z0-9@%]+}})
+ // CHECK: call void asm "foo $1,$0", "=*m,*m[[CLOBBERS:[a-zA-Z0-9@%{},~_$ ]*\"]](i32* {{[a-zA-Z0-9@%]+}}, i32* {{[a-zA-Z0-9@%]+}})
asm("foo %1,%0" : "=m" (mout0) : "m" (min1));
}
diff --git a/test/CodeGen/named_reg_global.c b/test/CodeGen/named_reg_global.c
index 8117daef615c..d888a3ff1733 100644
--- a/test/CodeGen/named_reg_global.c
+++ b/test/CodeGen/named_reg_global.c
@@ -44,4 +44,4 @@ void fn2(struct p4_Thread *val) {
// CHECK: call void @llvm.write_register.i[[bits]](metadata !0, i[[bits]] %[[regw]])
// CHECK: !llvm.named.register.sp = !{!0}
-// CHECK: !0 = metadata !{metadata !"sp"}
+// CHECK: !0 = !{!"sp"}
diff --git a/test/CodeGen/nonnull.c b/test/CodeGen/nonnull.c
index 4d6cc4568d8b..7c33e6329fdd 100644
--- a/test/CodeGen/nonnull.c
+++ b/test/CodeGen/nonnull.c
@@ -21,3 +21,31 @@ int * bar3() __attribute__((returns_nonnull)) {
return &a;
}
+// CHECK: define i32 @bar4(i32 %n, i32* nonnull %p)
+int bar4(int n, int *p) __attribute__((nonnull)) {
+ return n + *p;
+}
+
+// CHECK: define i32 @bar5(i32 %n, i32* nonnull %p)
+int bar5(int n, int *p) __attribute__((nonnull(1, 2))) {
+ return n + *p;
+}
+
+typedef union {
+ unsigned long long n;
+ int *p;
+ double d;
+} TransparentUnion __attribute__((transparent_union));
+
+// CHECK: define i32 @bar6(i64 %
+int bar6(TransparentUnion tu) __attribute__((nonnull(1))) {
+ return *tu.p;
+}
+
+// CHECK: define void @bar7(i32* nonnull %a, i32* nonnull %b)
+void bar7(int *a, int *b) __attribute__((nonnull(1)))
+__attribute__((nonnull(2))) {}
+
+// CHECK: define void @bar8(i32* nonnull %a, i32* nonnull %b)
+void bar8(int *a, int *b) __attribute__((nonnull))
+__attribute__((nonnull(1))) {}
diff --git a/test/CodeGen/nvptx-abi.c b/test/CodeGen/nvptx-abi.c
index f846def2de52..58ad6a17f242 100644
--- a/test/CodeGen/nvptx-abi.c
+++ b/test/CodeGen/nvptx-abi.c
@@ -5,13 +5,39 @@ typedef struct float4_s {
float x, y, z, w;
} float4_t;
-float4_t my_function(void);
-
-// CHECK-DAG: declare %struct.float4_s @my_function
+float4_t my_function(void) {
+// CHECK-LABEL: define %struct.float4_s @my_function
+ float4_t t;
+ return t;
+};
float bar(void) {
float4_t ret;
-// CHECK-DAG: call %struct.float4_s @my_function
+// CHECK-LABEL: @bar
+// CHECK: call %struct.float4_s @my_function
ret = my_function();
return ret.x;
}
+
+void foo(float4_t x) {
+// CHECK-LABEL: @foo
+// CHECK: %struct.float4_s* byval %x
+}
+
+void fooN(float4_t x, float4_t y, float4_t z) {
+// CHECK-LABEL: @fooN
+// CHECK: %struct.float4_s* byval %x
+// CHECK: %struct.float4_s* byval %y
+// CHECK: %struct.float4_s* byval %z
+}
+
+typedef struct nested_s {
+ unsigned long long x;
+ float z[64];
+ float4_t t;
+} nested_t;
+
+void baz(nested_t x) {
+// CHECK-LABEL: @baz
+// CHECK: %struct.nested_s* byval %x)
+}
diff --git a/test/CodeGen/piclevels.c b/test/CodeGen/piclevels.c
new file mode 100644
index 000000000000..54744e2efa7d
--- /dev/null
+++ b/test/CodeGen/piclevels.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm -pic-level 2 %s -o - | FileCheck %s -check-prefix=CHECK-BIGPIC
+// RUN: %clang_cc1 -emit-llvm -pic-level 1 %s -o - | FileCheck %s -check-prefix=CHECK-SMALLPIC
+
+// CHECK-BIGPIC: !llvm.module.flags = !{{{.*}}}
+// CHECK-BIGPIC: !{{[0-9]+}} = !{i32 1, !"PIC Level", i32 2}
+// CHECK-SMALLPIC: !llvm.module.flags = !{{{.*}}}
+// CHECK-SMALLPIC: !{{[0-9]+}} = !{i32 1, !"PIC Level", i32 1}
diff --git a/test/CodeGen/ppc-signbit.c b/test/CodeGen/ppc-signbit.c
new file mode 100644
index 000000000000..31b71d8cdbb9
--- /dev/null
+++ b/test/CodeGen/ppc-signbit.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple powerpc64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple powerpc64le-linux-gnu | FileCheck %s
+
+int test(long double x) { return __builtin_signbitl(x); }
+
+// CHECK-LABEL: define signext i32 @test(ppc_fp128 %x)
+// CHECK: bitcast ppc_fp128 %{{.*}} to i128
+// CHECK: trunc i128 %{{.*}} to i64
+// CHECK: icmp slt i64 %{{.*}}, 0
+// CHECK: zext i1 %{{.*}} to i32
+
diff --git a/test/CodeGen/ppc-varargs-struct.c b/test/CodeGen/ppc-varargs-struct.c
new file mode 100644
index 000000000000..f0e075b048d7
--- /dev/null
+++ b/test/CodeGen/ppc-varargs-struct.c
@@ -0,0 +1,112 @@
+// REQUIRES: powerpc-registered-target
+// REQUIRES: asserts
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-PPC
+
+#include <stdarg.h>
+
+struct x {
+ long a;
+ double b;
+};
+
+void testva (int n, ...)
+{
+ va_list ap;
+
+ struct x t = va_arg (ap, struct x);
+// CHECK: bitcast i8* %{{[a-z.0-9]*}} to %struct.x*
+// CHECK: bitcast %struct.x* %t to i8*
+// CHECK: bitcast %struct.x* %{{[0-9]+}} to i8*
+// CHECK: call void @llvm.memcpy
+// CHECK-PPC: [[ARRAYDECAY:%[a-z0-9]+]] = getelementptr inbounds [1 x %struct.__va_list_tag]* %ap, i32 0, i32 0
+// CHECK-PPC-NEXT: [[GPRPTR:%[a-z0-9]+]] = bitcast %struct.__va_list_tag* [[ARRAYDECAY]] to i8*
+// CHECK-PPC-NEXT: [[ZERO:%[0-9]+]] = ptrtoint i8* [[GPRPTR]] to i32
+// CHECK-PPC-NEXT: [[ONE:%[0-9]+]] = add i32 [[ZERO]], 1
+// CHECK-PPC-NEXT: [[TWO:%[0-9]+]] = inttoptr i32 [[ONE]] to i8*
+// CHECK-PPC-NEXT: [[THREE:%[0-9]+]] = add i32 [[ONE]], 3
+// CHECK-PPC-NEXT: [[FOUR:%[0-9]+]] = inttoptr i32 [[THREE]] to i8**
+// CHECK-PPC-NEXT: [[FIVE:%[0-9]+]] = add i32 [[THREE]], 4
+// CHECK-PPC-NEXT: [[SIX:%[0-9]+]] = inttoptr i32 [[FIVE]] to i8**
+// CHECK-PPC-NEXT: [[GPR:%[a-z0-9]+]] = load i8* [[GPRPTR]]
+// CHECK-PPC-NEXT: [[FPR:%[a-z0-9]+]] = load i8* [[TWO]]
+// CHECK-PPC-NEXT: [[OVERFLOW_AREA:%[a-z_0-9]+]] = load i8** [[FOUR]]
+// CHECK-PPC-NEXT: [[SEVEN:%[0-9]+]] = ptrtoint i8* [[OVERFLOW_AREA]] to i32
+// CHECK-PPC-NEXT: [[REGSAVE_AREA:%[a-z_0-9]+]] = load i8** [[SIX]]
+// CHECK-PPC-NEXT: [[EIGHT:%[0-9]+]] = ptrtoint i8* [[REGSAVE_AREA]] to i32
+// CHECK-PPC-NEXT: [[COND:%[a-z0-9]+]] = icmp ult i8 [[GPR]], 8
+// CHECK-PPC-NEXT: [[NINE:%[0-9]+]] = mul i8 [[GPR]], 4
+// CHECK-PPC-NEXT: [[TEN:%[0-9]+]] = sext i8 [[NINE]] to i32
+// CHECK-PPC-NEXT: [[ELEVEN:%[0-9]+]] = add i32 [[EIGHT]], [[TEN]]
+// CHECK-PPC-NEXT: br i1 [[COND]], label [[USING_REGS:%[a-z_0-9]+]], label [[USING_OVERFLOW:%[a-z_0-9]+]]
+//
+// CHECK-PPC1:[[USING_REGS]]
+// CHECK-PPC: [[TWELVE:%[0-9]+]] = inttoptr i32 [[ELEVEN]] to %struct.x*
+// CHECK-PPC-NEXT: [[THIRTEEN:%[0-9]+]] = add i8 [[GPR]], 1
+// CHECK-PPC-NEXT: store i8 [[THIRTEEN]], i8* [[GPRPTR]]
+// CHECK-PPC-NEXT: br label [[CONT:%[a-z0-9]+]]
+//
+// CHECK-PPC1:[[USING_OVERFLOW]]
+// CHECK-PPC: [[FOURTEEN:%[0-9]+]] = inttoptr i32 [[SEVEN]] to %struct.x*
+// CHECK-PPC-NEXT: [[FIFTEEN:%[0-9]+]] = add i32 [[SEVEN]], 4
+// CHECK-PPC-NEXT: [[SIXTEEN:%[0-9]+]] = inttoptr i32 [[FIFTEEN]] to i8*
+// CHECK-PPC-NEXT: store i8* [[SIXTEEN]], i8** [[FOUR]]
+// CHECK-PPC-NEXT: br label [[CONT]]
+//
+// CHECK-PPC1:[[CONT]]
+// CHECK-PPC: [[VAARG_ADDR:%[a-z.0-9]+]] = phi %struct.x* [ [[TWELVE]], [[USING_REGS]] ], [ [[FOURTEEN]], [[USING_OVERFLOW]] ]
+// CHECK-PPC-NEXT: [[AGGRPTR:%[a-z0-9]+]] = bitcast %struct.x* [[VAARG_ADDR]] to i8**
+// CHECK-PPC-NEXT: [[AGGR:%[a-z0-9]+]] = load i8** [[AGGRPTR]]
+// CHECK-PPC-NEXT: [[SEVENTEEN:%[0-9]+]] = bitcast %struct.x* %t to i8*
+// CHECK-PPC-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[SEVENTEEN]], i8* [[AGGR]], i32 16, i32 8, i1 false)
+
+ int v = va_arg (ap, int);
+// CHECK: ptrtoint i8* %{{[a-z.0-9]*}} to i64
+// CHECK: add i64 %{{[0-9]+}}, 4
+// CHECK: inttoptr i64 %{{[0-9]+}} to i8*
+// CHECK: bitcast i8* %{{[0-9]+}} to i32*
+// CHECK-PPC: [[ARRAYDECAY1:%[a-z0-9]+]] = getelementptr inbounds [1 x %struct.__va_list_tag]* %ap, i32 0, i32 0
+// CHECK-PPC-NEXT: [[GPRPTR1:%[a-z0-9]+]] = bitcast %struct.__va_list_tag* [[ARRAYDECAY1]] to i8*
+// CHECK-PPC-NEXT: [[EIGHTEEN:%[0-9]+]] = ptrtoint i8* [[GPRPTR1]] to i32
+// CHECK-PPC-NEXT: [[NINETEEN:%[0-9]+]] = add i32 [[EIGHTEEN]], 1
+// CHECK-PPC-NEXT: [[TWENTY:%[0-9]+]] = inttoptr i32 [[NINETEEN]] to i8*
+// CHECK-PPC-NEXT: [[TWENTYONE:%[0-9]+]] = add i32 [[NINETEEN]], 3
+// CHECK-PPC-NEXT: [[TWENTYTWO:%[0-9]+]] = inttoptr i32 [[TWENTYONE]] to i8**
+// CHECK-PPC-NEXT: [[TWENTYTHREE:%[0-9]+]] = add i32 [[TWENTYONE]], 4
+// CHECK-PPC-NEXT: [[TWENTYFOUR:%[0-9]+]] = inttoptr i32 [[TWENTYTHREE]] to i8**
+// CHECK-PPC-NEXT: [[GPR1:%[a-z0-9]+]] = load i8* [[GPRPTR1]]
+// CHECK-PPC-NEXT: [[FPR1:%[a-z0-9]+]] = load i8* [[TWENTY]]
+// CHECK-PPC-NEXT: [[OVERFLOW_AREA1:%[a-z_0-9]+]] = load i8** [[TWENTYTWO]]
+// CHECK-PPC-NEXT: [[TWENTYFIVE:%[0-9]+]] = ptrtoint i8* [[OVERFLOW_AREA1]] to i32
+// CHECK-PPC-NEXT: [[REGSAVE_AREA1:%[a-z_0-9]+]] = load i8** [[TWENTYFOUR]]
+// CHECK-PPC-NEXT: [[TWENTYSIX:%[0-9]+]] = ptrtoint i8* [[REGSAVE_AREA1]] to i32
+// CHECK-PPC-NEXT: [[COND1:%[a-z0-9]+]] = icmp ult i8 [[GPR1]], 8
+// CHECK-PPC-NEXT: [[TWENTYSEVEN:%[0-9]+]] = mul i8 [[GPR1]], 4
+// CHECK-PPC-NEXT: [[TWENTYEIGHT:%[0-9]+]] = sext i8 [[TWENTYSEVEN]] to i32
+// CHECK-PPC-NEXT: [[TWENTYNINE:%[0-9]+]] = add i32 [[TWENTYSIX]], [[TWENTYEIGHT]]
+// CHECK-PPC-NEXT: br i1 [[COND1]], label [[USING_REGS1:%[a-z_0-9]+]], label [[USING_OVERFLOW1:%[a-z_0-9]+]]
+//
+// CHECK-PPC1:[[USING_REGS1]]:
+// CHECK-PPC: [[THIRTY:%[0-9]+]] = inttoptr i32 [[TWENTYNINE]] to i32*
+// CHECK-PPC-NEXT: [[THIRTYONE:%[0-9]+]] = add i8 [[GPR1]], 1
+// CHECK-PPC-NEXT: store i8 [[THIRTYONE]], i8* [[GPRPTR1]]
+// CHECK-PPC-NEXT: br label [[CONT1:%[a-z0-9]+]]
+//
+// CHECK-PPC1:[[USING_OVERFLOW1]]:
+// CHECK-PPC: [[THIRTYTWO:%[0-9]+]] = inttoptr i32 [[TWENTYFIVE]] to i32*
+// CHECK-PPC-NEXT: [[THIRTYTHREE:%[0-9]+]] = add i32 [[TWENTYFIVE]], 4
+// CHECK-PPC-NEXT: [[THIRTYFOUR:%[0-9]+]] = inttoptr i32 [[THIRTYTHREE]] to i8*
+// CHECK-PPC-NEXT: store i8* [[THIRTYFOUR]], i8** [[TWENTYTWO]]
+// CHECK-PPC-NEXT: br label [[CONT1]]
+//
+// CHECK-PPC1:[[CONT1]]:
+// CHECK-PPC: [[VAARG_ADDR1:%[a-z.0-9]+]] = phi i32* [ [[THIRTY]], [[USING_REGS1]] ], [ [[THIRTYTWO]], [[USING_OVERFLOW1]] ]
+// CHECK-PPC-NEXT: [[THIRTYFIVE:%[0-9]+]] = load i32* [[VAARG_ADDR1]]
+// CHECK-PPC-NEXT: store i32 [[THIRTYFIVE]], i32* %v, align 4
+
+#ifdef __powerpc64__
+ __int128_t u = va_arg (ap, __int128_t);
+#endif
+// CHECK: bitcast i8* %{{[a-z.0-9]+}} to i128*
+// CHECK-NEXT: load i128* %{{[0-9]+}}
+}
diff --git a/test/CodeGen/ppc64-elf-abi.c b/test/CodeGen/ppc64-elf-abi.c
new file mode 100644
index 000000000000..0dd183e2a6da
--- /dev/null
+++ b/test/CodeGen/ppc64-elf-abi.c
@@ -0,0 +1,40 @@
+// REQUIRES: powerpc-registered-target
+
+// Verify ABI selection by the front end
+
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=CHECK-ELFv1
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN: -target-abi elfv1 | FileCheck %s --check-prefix=CHECK-ELFv1
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN: -target-abi elfv2 | FileCheck %s --check-prefix=CHECK-ELFv2
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=CHECK-ELFv2
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN: -target-abi elfv1 | FileCheck %s --check-prefix=CHECK-ELFv1
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN: -target-abi elfv2 | FileCheck %s --check-prefix=CHECK-ELFv2
+
+// CHECK-ELFv1: define void @func_fab(%struct.fab* noalias sret %agg.result, i64 %x.coerce)
+// CHECK-ELFv2: define [2 x float] @func_fab([2 x float] %x.coerce)
+struct fab { float a; float b; };
+struct fab func_fab(struct fab x) { return x; }
+
+// Verify ABI choice is passed on to the back end
+
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -S -o - %s \
+// RUN: | FileCheck %s --check-prefix=CHECK-ASM-ELFv1
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -S -o - %s \
+// RUN: -target-abi elfv1 | FileCheck %s --check-prefix=CHECK-ASM-ELFv1
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -S -o - %s \
+// RUN: -target-abi elfv2 | FileCheck %s --check-prefix=CHECK-ASM-ELFv2
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -S -o - %s \
+// RUN: | FileCheck %s --check-prefix=CHECK-ASM-ELFv2
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -S -o - %s \
+// RUN: -target-abi elfv1 | FileCheck %s --check-prefix=CHECK-ASM-ELFv1
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -S -o - %s \
+// RUN: -target-abi elfv2 | FileCheck %s --check-prefix=CHECK-ASM-ELFv2
+
+// CHECK-ASM-ELFv2: .abiversion 2
+// CHECK-ASM-ELFv1-NOT: .abiversion 2
+
diff --git a/test/CodeGen/ppc64-varargs-struct.c b/test/CodeGen/ppc64-varargs-struct.c
deleted file mode 100644
index 70b242c7f417..000000000000
--- a/test/CodeGen/ppc64-varargs-struct.c
+++ /dev/null
@@ -1,30 +0,0 @@
-// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
-
-#include <stdarg.h>
-
-struct x {
- long a;
- double b;
-};
-
-void testva (int n, ...)
-{
- va_list ap;
-
- struct x t = va_arg (ap, struct x);
-// CHECK: bitcast i8* %{{[a-z.0-9]*}} to %struct.x*
-// CHECK: bitcast %struct.x* %t to i8*
-// CHECK: bitcast %struct.x* %{{[0-9]+}} to i8*
-// CHECK: call void @llvm.memcpy
-
- int v = va_arg (ap, int);
-// CHECK: ptrtoint i8* %{{[a-z.0-9]*}} to i64
-// CHECK: add i64 %{{[0-9]+}}, 4
-// CHECK: inttoptr i64 %{{[0-9]+}} to i8*
-// CHECK: bitcast i8* %{{[0-9]+}} to i32*
-
- __int128_t u = va_arg (ap, __int128_t);
-// CHECK: bitcast i8* %{{[a-z.0-9]+}} to i128*
-// CHECK-NEXT: load i128* %{{[0-9]+}}
-}
diff --git a/test/CodeGen/ppc64le-aggregates.c b/test/CodeGen/ppc64le-aggregates.c
index acf34a8a8012..e193dcc3faef 100644
--- a/test/CodeGen/ppc64le-aggregates.c
+++ b/test/CodeGen/ppc64le-aggregates.c
@@ -1,4 +1,3 @@
-// REQUIRES: powerpc-registered-target
// RUN: %clang_cc1 -faltivec -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
// Test homogeneous float aggregate passing and returning.
@@ -16,6 +15,8 @@ struct f9 { float f[9]; };
struct fab { float a; float b; };
struct fabc { float a; float b; float c; };
+struct f2a2b { float a[2]; float b[2]; };
+
// CHECK: define [1 x float] @func_f1(float inreg %x.coerce)
struct f1 func_f1(struct f1 x) { return x; }
@@ -49,6 +50,9 @@ struct fab func_fab(struct fab x) { return x; }
// CHECK: define [3 x float] @func_fabc([3 x float] %x.coerce)
struct fabc func_fabc(struct fabc x) { return x; }
+// CHECK: define [4 x float] @func_f2a2b([4 x float] %x.coerce)
+struct f2a2b func_f2a2b(struct f2a2b x) { return x; }
+
// CHECK-LABEL: @call_f1
// CHECK: %[[TMP:[^ ]+]] = load float* getelementptr inbounds (%struct.f1* @global_f1, i32 0, i32 0, i32 0), align 1
// CHECK: call [1 x float] @func_f1(float inreg %[[TMP]])
diff --git a/test/CodeGen/pr5406.c b/test/CodeGen/pr5406.c
index 2d198220a770..0f04a8e069cd 100644
--- a/test/CodeGen/pr5406.c
+++ b/test/CodeGen/pr5406.c
@@ -6,7 +6,7 @@ typedef struct { char x[3]; } A0;
void foo (int i, ...);
-// CHECK: call arm_aapcscc void (i32, ...)* @foo(i32 1, [1 x i32] {{.*}})
+// CHECK: call void (i32, ...)* @foo(i32 1, [1 x i32] {{.*}})
int main (void)
{
A0 a3;
diff --git a/test/CodeGen/pragma-comment.c b/test/CodeGen/pragma-comment.c
index 73cc5483bcf6..221cfc87f919 100644
--- a/test/CodeGen/pragma-comment.c
+++ b/test/CodeGen/pragma-comment.c
@@ -10,14 +10,14 @@
#pragma comment(linker," /bar=" BAR)
// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = metadata !{i32 6, metadata !"Linker Options", metadata ![[link_opts:[0-9]+]]}
-// CHECK: ![[link_opts]] = metadata !{metadata ![[msvcrt:[0-9]+]], metadata ![[kernel32:[0-9]+]], metadata ![[USER32:[0-9]+]], metadata ![[bar:[0-9]+]]}
-// CHECK: ![[msvcrt]] = metadata !{metadata !"/DEFAULTLIB:msvcrt.lib"}
-// CHECK: ![[kernel32]] = metadata !{metadata !"/DEFAULTLIB:kernel32.lib"}
-// CHECK: ![[USER32]] = metadata !{metadata !"/DEFAULTLIB:USER32.LIB"}
-// CHECK: ![[bar]] = metadata !{metadata !" /bar=2"}
+// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
+// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]], ![[kernel32:[0-9]+]], ![[USER32:[0-9]+]], ![[bar:[0-9]+]]}
+// CHECK: ![[msvcrt]] = !{!"/DEFAULTLIB:msvcrt.lib"}
+// CHECK: ![[kernel32]] = !{!"/DEFAULTLIB:kernel32.lib"}
+// CHECK: ![[USER32]] = !{!"/DEFAULTLIB:USER32.LIB"}
+// CHECK: ![[bar]] = !{!" /bar=2"}
-// LINUX: metadata !{metadata !"-lmsvcrt.lib"}
-// LINUX: metadata !{metadata !"-lkernel32"}
-// LINUX: metadata !{metadata !"-lUSER32.LIB"}
-// LINUX: metadata !{metadata !" /bar=2"}
+// LINUX: !{!"-lmsvcrt.lib"}
+// LINUX: !{!"-lkernel32"}
+// LINUX: !{!"-lUSER32.LIB"}
+// LINUX: !{!" /bar=2"}
diff --git a/test/CodeGen/pragma-detect_mismatch.c b/test/CodeGen/pragma-detect_mismatch.c
index b223a61c9b03..c5f3af340aae 100644
--- a/test/CodeGen/pragma-detect_mismatch.c
+++ b/test/CodeGen/pragma-detect_mismatch.c
@@ -1,12 +1,12 @@
-// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
-
-#pragma detect_mismatch("test", "1")
-
-#define BAR "2"
-#pragma detect_mismatch("test2", BAR)
-
-// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = metadata !{i32 6, metadata !"Linker Options", metadata ![[link_opts:[0-9]+]]}
-// CHECK: ![[link_opts]] = metadata !{metadata ![[test:[0-9]+]], metadata ![[test2:[0-9]+]]}
-// CHECK: ![[test]] = metadata !{metadata !"/FAILIFMISMATCH:\22test=1\22"}
-// CHECK: ![[test2]] = metadata !{metadata !"/FAILIFMISMATCH:\22test2=2\22"}
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
+
+#pragma detect_mismatch("test", "1")
+
+#define BAR "2"
+#pragma detect_mismatch("test2", BAR)
+
+// CHECK: !llvm.module.flags = !{{{.*}}}
+// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
+// CHECK: ![[link_opts]] = !{![[test:[0-9]+]], ![[test2:[0-9]+]]}
+// CHECK: ![[test]] = !{!"/FAILIFMISMATCH:\22test=1\22"}
+// CHECK: ![[test2]] = !{!"/FAILIFMISMATCH:\22test2=2\22"}
diff --git a/test/CodeGen/pragma-loop.cpp b/test/CodeGen/pragma-loop.cpp
index bdcd30426315..dd40c1d72600 100644
--- a/test/CodeGen/pragma-loop.cpp
+++ b/test/CodeGen/pragma-loop.cpp
@@ -8,7 +8,7 @@ void while_test(int *List, int Length) {
#pragma clang loop vectorize(enable)
#pragma clang loop interleave_count(4)
#pragma clang loop vectorize_width(4)
-#pragma clang loop unroll(enable)
+#pragma clang loop unroll(full)
while (i < Length) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_1:.*]]
List[i] = i * 2;
@@ -28,11 +28,13 @@ void do_test(int *List, int Length) {
} while (i < Length);
}
+enum struct Tuner : short { Interleave = 4, Unroll = 8 };
+
// Verify for loop is recognized after sequence of pragma clang loop directives.
void for_test(int *List, int Length) {
#pragma clang loop interleave(enable)
-#pragma clang loop interleave_count(4)
-#pragma clang loop unroll_count(8)
+#pragma clang loop interleave_count(static_cast<int>(Tuner::Interleave))
+#pragma clang loop unroll_count(static_cast<int>(Tuner::Unroll))
for (int i = 0; i < Length; i++) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_3:.*]]
List[i] = i * 2;
@@ -74,28 +76,74 @@ void for_define_test(int *List, int Length, int Value) {
}
}
+// Verify constant expressions are handled correctly.
+void for_contant_expression_test(int *List, int Length) {
+#pragma clang loop vectorize_width(1 + 4)
+ for (int i = 0; i < Length; i++) {
+ // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_7:.*]]
+ List[i] = i;
+ }
+
+#pragma clang loop vectorize_width(3 + VECWIDTH)
+ for (int i = 0; i < Length; i++) {
+ // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_8:.*]]
+ List[i] += i;
+ }
+}
+
// Verify metadata is generated when template is used.
template <typename A>
void for_template_test(A *List, int Length, A Value) {
-
#pragma clang loop vectorize_width(8) interleave_count(8) unroll_count(8)
for (int i = 0; i < Length; i++) {
- // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_7:.*]]
+ // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_9:.*]]
List[i] = i * Value;
}
}
// Verify define is resolved correctly when template is used.
-template <typename A>
+template <typename A, typename T>
void for_template_define_test(A *List, int Length, A Value) {
-#pragma clang loop vectorize_width(VECWIDTH) interleave_count(INTCOUNT)
-#pragma clang loop unroll_count(UNROLLCOUNT)
+ const T VWidth = VECWIDTH;
+ const T ICount = INTCOUNT;
+ const T UCount = UNROLLCOUNT;
+#pragma clang loop vectorize_width(VWidth) interleave_count(ICount)
+#pragma clang loop unroll_count(UCount)
for (int i = 0; i < Length; i++) {
- // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_8:.*]]
+ // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_10:.*]]
List[i] = i * Value;
}
}
+// Verify templates and constant expressions are handled correctly.
+template <typename A, int V, int I, int U>
+void for_template_constant_expression_test(A *List, int Length) {
+#pragma clang loop vectorize_width(V) interleave_count(I) unroll_count(U)
+ for (int i = 0; i < Length; i++) {
+ // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_11:.*]]
+ List[i] = i;
+ }
+
+#pragma clang loop vectorize_width(V * 2 + VECWIDTH) interleave_count(I * 2 + INTCOUNT) unroll_count(U * 2 + UNROLLCOUNT)
+ for (int i = 0; i < Length; i++) {
+ // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_12:.*]]
+ List[i] += i;
+ }
+
+ const int Scale = 4;
+#pragma clang loop vectorize_width(Scale * V) interleave_count(Scale * I) unroll_count(Scale * U)
+ for (int i = 0; i < Length; i++) {
+ // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_13:.*]]
+ List[i] += i;
+ }
+
+#pragma clang loop vectorize_width((Scale * V) + 2)
+ for (int i = 0; i < Length; i++) {
+ // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_14:.*]]
+ List[i] += i;
+ }
+}
+
#undef VECWIDTH
#undef INTCOUNT
#undef UNROLLCOUNT
@@ -105,25 +153,39 @@ void template_test(double *List, int Length) {
double Value = 10;
for_template_test<double>(List, Length, Value);
- for_template_define_test<double>(List, Length, Value);
+ for_template_define_test<double, int>(List, Length, Value);
+ for_template_constant_expression_test<double, 2, 4, 8>(List, Length);
}
-// CHECK: ![[LOOP_1]] = metadata !{metadata ![[LOOP_1]], metadata ![[UNROLLENABLE_1:.*]], metadata ![[WIDTH_4:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[INTENABLE_1:.*]]}
-// CHECK: ![[UNROLLENABLE_1]] = metadata !{metadata !"llvm.loop.unroll.enable", i1 true}
-// CHECK: ![[WIDTH_4]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 4}
-// CHECK: ![[INTERLEAVE_4]] = metadata !{metadata !"llvm.loop.interleave.count", i32 4}
-// CHECK: ![[INTENABLE_1]] = metadata !{metadata !"llvm.loop.vectorize.enable", i1 true}
-// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]], metadata ![[UNROLLENABLE_0:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[WIDTH_8:.*]]}
-// CHECK: ![[UNROLLENABLE_0]] = metadata !{metadata !"llvm.loop.unroll.enable", i1 false}
-// CHECK: ![[WIDTH_8]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 8}
-// CHECK: ![[LOOP_3]] = metadata !{metadata ![[LOOP_3]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[ENABLE_1:.*]]}
-// CHECK: ![[UNROLL_8]] = metadata !{metadata !"llvm.loop.unroll.count", i32 8}
-// CHECK: ![[LOOP_4]] = metadata !{metadata ![[LOOP_4]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
-// CHECK: ![[INTERLEAVE_2]] = metadata !{metadata !"llvm.loop.interleave.count", i32 2}
-// CHECK: ![[WIDTH_2]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 2}
-// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata ![[UNROLLENABLE_0:.*]], metadata ![[WIDTH_1:.*]]}
-// CHECK: ![[WIDTH_1]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 1}
-// CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
-// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_8:.*]], metadata ![[WIDTH_8:.*]]}
-// CHECK: ![[INTERLEAVE_8]] = metadata !{metadata !"llvm.loop.interleave.count", i32 8}
-// CHECK: ![[LOOP_8]] = metadata !{metadata ![[LOOP_8]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
+// CHECK: ![[LOOP_1]] = distinct !{![[LOOP_1]], ![[UNROLL_FULL:.*]], ![[WIDTH_4:.*]], ![[INTERLEAVE_4:.*]], ![[INTENABLE_1:.*]]}
+// CHECK: ![[UNROLL_FULL]] = !{!"llvm.loop.unroll.full"}
+// CHECK: ![[WIDTH_4]] = !{!"llvm.loop.vectorize.width", i32 4}
+// CHECK: ![[INTERLEAVE_4]] = !{!"llvm.loop.interleave.count", i32 4}
+// CHECK: ![[INTENABLE_1]] = !{!"llvm.loop.vectorize.enable", i1 true}
+// CHECK: ![[LOOP_2]] = distinct !{![[LOOP_2:.*]], ![[UNROLL_DISABLE:.*]], ![[INTERLEAVE_4:.*]], ![[WIDTH_8:.*]]}
+// CHECK: ![[UNROLL_DISABLE]] = !{!"llvm.loop.unroll.disable"}
+// CHECK: ![[WIDTH_8]] = !{!"llvm.loop.vectorize.width", i32 8}
+// CHECK: ![[LOOP_3]] = distinct !{![[LOOP_3]], ![[UNROLL_8:.*]], ![[INTERLEAVE_4:.*]], ![[ENABLE_1:.*]]}
+// CHECK: ![[UNROLL_8]] = !{!"llvm.loop.unroll.count", i32 8}
+// CHECK: ![[LOOP_4]] = distinct !{![[LOOP_4]], ![[INTERLEAVE_2:.*]], ![[WIDTH_2:.*]]}
+// CHECK: ![[INTERLEAVE_2]] = !{!"llvm.loop.interleave.count", i32 2}
+// CHECK: ![[WIDTH_2]] = !{!"llvm.loop.vectorize.width", i32 2}
+// CHECK: ![[LOOP_5]] = distinct !{![[LOOP_5]], ![[UNROLL_DISABLE:.*]], ![[WIDTH_1:.*]]}
+// CHECK: ![[WIDTH_1]] = !{!"llvm.loop.vectorize.width", i32 1}
+// CHECK: ![[LOOP_6]] = distinct !{![[LOOP_6]], ![[UNROLL_8:.*]], ![[INTERLEAVE_2:.*]], ![[WIDTH_2:.*]]}
+// CHECK: ![[LOOP_7]] = distinct !{![[LOOP_7]], ![[WIDTH_5:.*]]}
+// CHECK: ![[WIDTH_5]] = !{!"llvm.loop.vectorize.width", i32 5}
+// CHECK: ![[LOOP_8]] = distinct !{![[LOOP_8]], ![[WIDTH_5:.*]]}
+// CHECK: ![[LOOP_9]] = distinct !{![[LOOP_9]], ![[UNROLL_8:.*]], ![[INTERLEAVE_8:.*]], ![[WIDTH_8:.*]]}
+// CHECK: ![[INTERLEAVE_8]] = !{!"llvm.loop.interleave.count", i32 8}
+// CHECK: ![[LOOP_10]] = distinct !{![[LOOP_10]], ![[UNROLL_8:.*]], ![[INTERLEAVE_2:.*]], ![[WIDTH_2:.*]]}
+// CHECK: ![[LOOP_11]] = distinct !{![[LOOP_11]], ![[UNROLL_8:.*]], ![[INTERLEAVE_4:.*]], ![[WIDTH_2:.*]]}
+// CHECK: ![[LOOP_12]] = distinct !{![[LOOP_12]], ![[UNROLL_24:.*]], ![[INTERLEAVE_10:.*]], ![[WIDTH_6:.*]]}
+// CHECK: ![[UNROLL_24]] = !{!"llvm.loop.unroll.count", i32 24}
+// CHECK: ![[INTERLEAVE_10]] = !{!"llvm.loop.interleave.count", i32 10}
+// CHECK: ![[WIDTH_6]] = !{!"llvm.loop.vectorize.width", i32 6}
+// CHECK: ![[LOOP_13]] = distinct !{![[LOOP_13]], ![[UNROLL_32:.*]], ![[INTERLEAVE_16:.*]], ![[WIDTH_8:.*]]}
+// CHECK: ![[UNROLL_32]] = !{!"llvm.loop.unroll.count", i32 32}
+// CHECK: ![[INTERLEAVE_16]] = !{!"llvm.loop.interleave.count", i32 16}
+// CHECK: ![[LOOP_14]] = distinct !{![[LOOP_14]], ![[WIDTH_10:.*]]}
+// CHECK: ![[WIDTH_10]] = !{!"llvm.loop.vectorize.width", i32 10}
diff --git a/test/CodeGen/pragma-unroll.cpp b/test/CodeGen/pragma-unroll.cpp
index b321e74a1154..8b73fa6c8aab 100644
--- a/test/CodeGen/pragma-unroll.cpp
+++ b/test/CodeGen/pragma-unroll.cpp
@@ -17,7 +17,7 @@ void while_test(int *List, int Length) {
void do_test(int *List, int Length) {
int i = 0;
-#pragma unroll 16
+#pragma nounroll
do {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_2:.*]]
List[i] = i * 2;
@@ -86,14 +86,14 @@ void template_test(double *List, int Length) {
for_template_define_test<double>(List, Length, Value);
}
-// CHECK: ![[LOOP_1]] = metadata !{metadata ![[LOOP_1]], metadata ![[UNROLLENABLE_1:.*]]}
-// CHECK: ![[UNROLLENABLE_1]] = metadata !{metadata !"llvm.loop.unroll.enable", i1 true}
-// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]], metadata ![[UNROLL_16:.*]]}
-// CHECK: ![[UNROLL_16]] = metadata !{metadata !"llvm.loop.unroll.count", i32 16}
-// CHECK: ![[LOOP_3]] = metadata !{metadata ![[LOOP_3]], metadata ![[UNROLL_8:.*]]}
-// CHECK: ![[UNROLL_8]] = metadata !{metadata !"llvm.loop.unroll.count", i32 8}
-// CHECK: ![[LOOP_4]] = metadata !{metadata ![[LOOP_4]], metadata ![[UNROLL_4:.*]]}
-// CHECK: ![[UNROLL_4]] = metadata !{metadata !"llvm.loop.unroll.count", i32 4}
-// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata ![[UNROLL_8:.*]]}
-// CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata ![[UNROLL_8:.*]]}
-// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata ![[UNROLL_8:.*]]}
+// CHECK: ![[LOOP_1]] = distinct !{![[LOOP_1]], ![[UNROLL_FULL:.*]]}
+// CHECK: ![[UNROLL_FULL]] = !{!"llvm.loop.unroll.full"}
+// CHECK: ![[LOOP_2]] = distinct !{![[LOOP_2:.*]], ![[UNROLL_DISABLE:.*]]}
+// CHECK: ![[UNROLL_DISABLE]] = !{!"llvm.loop.unroll.disable"}
+// CHECK: ![[LOOP_3]] = distinct !{![[LOOP_3]], ![[UNROLL_8:.*]]}
+// CHECK: ![[UNROLL_8]] = !{!"llvm.loop.unroll.count", i32 8}
+// CHECK: ![[LOOP_4]] = distinct !{![[LOOP_4]], ![[UNROLL_4:.*]]}
+// CHECK: ![[UNROLL_4]] = !{!"llvm.loop.unroll.count", i32 4}
+// CHECK: ![[LOOP_5]] = distinct !{![[LOOP_5]], ![[UNROLL_8:.*]]}
+// CHECK: ![[LOOP_6]] = distinct !{![[LOOP_6]], ![[UNROLL_8:.*]]}
+// CHECK: ![[LOOP_7]] = distinct !{![[LOOP_7]], ![[UNROLL_8:.*]]}
diff --git a/test/CodeGen/pragma-weak.c b/test/CodeGen/pragma-weak.c
index b5d186324bf6..aba98e185b4e 100644
--- a/test/CodeGen/pragma-weak.c
+++ b/test/CodeGen/pragma-weak.c
@@ -7,16 +7,16 @@
// CHECK-DAG: @both = alias void ()* @__both
// CHECK-DAG: @both2 = alias void ()* @__both2
-// CHECK-DAG: @weakvar_alias = alias weak i32* @__weakvar_alias
-// CHECK-DAG: @foo = alias weak void ()* @__foo
-// CHECK-DAG: @foo2 = alias weak void ()* @__foo2
-// CHECK-DAG: @stutter = alias weak void ()* @__stutter
-// CHECK-DAG: @stutter2 = alias weak void ()* @__stutter2
-// CHECK-DAG: @declfirst = alias weak void ()* @__declfirst
-// CHECK-DAG: @declfirstattr = alias weak void ()* @__declfirstattr
-// CHECK-DAG: @mix2 = alias weak void ()* @__mix2
-// CHECK-DAG: @a1 = alias weak void ()* @__a1
-// CHECK-DAG: @xxx = alias weak void ()* @__xxx
+// CHECK-DAG: @weakvar_alias = weak alias i32* @__weakvar_alias
+// CHECK-DAG: @foo = weak alias void ()* @__foo
+// CHECK-DAG: @foo2 = weak alias void ()* @__foo2
+// CHECK-DAG: @stutter = weak alias void ()* @__stutter
+// CHECK-DAG: @stutter2 = weak alias void ()* @__stutter2
+// CHECK-DAG: @declfirst = weak alias void ()* @__declfirst
+// CHECK-DAG: @declfirstattr = weak alias void ()* @__declfirstattr
+// CHECK-DAG: @mix2 = weak alias void ()* @__mix2
+// CHECK-DAG: @a1 = weak alias void ()* @__a1
+// CHECK-DAG: @xxx = weak alias void ()* @__xxx
diff --git a/test/CodeGen/predefined-expr.c b/test/CodeGen/predefined-expr.c
index 6c94152b737e..3ccdeb3b4ce3 100644
--- a/test/CodeGen/predefined-expr.c
+++ b/test/CodeGen/predefined-expr.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -fms-extensions %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -fms-extensions %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
// CHECK: @__func__.plainFunction = private unnamed_addr constant [14 x i8] c"plainFunction\00"
// CHECK: @__PRETTY_FUNCTION__.plainFunction = private unnamed_addr constant [21 x i8] c"void plainFunction()\00"
diff --git a/test/CodeGen/sanitize-address-field-padding.cpp b/test/CodeGen/sanitize-address-field-padding.cpp
new file mode 100644
index 000000000000..d4eea1b9e69d
--- /dev/null
+++ b/test/CodeGen/sanitize-address-field-padding.cpp
@@ -0,0 +1,237 @@
+// Test -fsanitize-address-field-padding
+// RUN: echo 'type:SomeNamespace::BlacklistedByName=field-padding' > %t.type.blacklist
+// RUN: echo 'src:*sanitize-address-field-padding.cpp=field-padding' > %t.file.blacklist
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsanitize=address -fsanitize-address-field-padding=1 -fsanitize-blacklist=%t.type.blacklist -Rsanitize-address -emit-llvm -o - %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsanitize=address -fsanitize-address-field-padding=1 -fsanitize-blacklist=%t.type.blacklist -Rsanitize-address -emit-llvm -o - %s -O1 -mconstructor-aliases 2>&1 | FileCheck %s --check-prefix=WITH_CTOR_ALIASES
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsanitize=address -fsanitize-address-field-padding=1 -fsanitize-blacklist=%t.file.blacklist -Rsanitize-address -emit-llvm -o - %s 2>&1 | FileCheck %s --check-prefix=FILE_BLACKLIST
+// RUN: %clang_cc1 -fsanitize=address -emit-llvm -o - %s 2>&1 | FileCheck %s --check-prefix=NO_PADDING
+//
+
+// The reasons to ignore a particular class are not set in stone and will change.
+//
+// CHECK: -fsanitize-address-field-padding applied to Positive1
+// CHECK: -fsanitize-address-field-padding ignored for Negative1 because it is trivially copyable
+// CHECK: -fsanitize-address-field-padding ignored for Negative2 because it is trivially copyable
+// CHECK: -fsanitize-address-field-padding ignored for Negative3 because it is a union
+// CHECK: -fsanitize-address-field-padding ignored for Negative4 because it is trivially copyable
+// CHECK: -fsanitize-address-field-padding ignored for Negative5 because it is packed
+// CHECK: -fsanitize-address-field-padding ignored for SomeNamespace::BlacklistedByName because it is blacklisted
+// CHECK: -fsanitize-address-field-padding ignored for ExternCStruct because it is not C++
+//
+// FILE_BLACKLIST: -fsanitize-address-field-padding ignored for Positive1 because it is in a blacklisted file
+// FILE_BLACKLIST-NOT: __asan_poison_intra_object_redzone
+// NO_PADDING-NOT: __asan_poison_intra_object_redzone
+
+
+class Positive1 {
+ public:
+ Positive1() {}
+ ~Positive1() {}
+ int make_it_non_standard_layout;
+ private:
+ char private1;
+ int private2;
+ short private_array[6];
+ long long private3;
+};
+
+Positive1 positive1;
+// Positive1 with extra paddings
+// CHECK: type { i32, [12 x i8], i8, [15 x i8], i32, [12 x i8], [6 x i16], [12 x i8], i64, [8 x i8] }
+
+struct VirtualBase {
+ int foo;
+};
+
+class ClassWithVirtualBase : public virtual VirtualBase {
+ public:
+ ClassWithVirtualBase() {}
+ ~ClassWithVirtualBase() {}
+ int make_it_non_standard_layout;
+ private:
+ char x[7];
+ char y[9];
+};
+
+ClassWithVirtualBase class_with_virtual_base;
+
+class WithFlexibleArray1 {
+ public:
+ WithFlexibleArray1() {}
+ ~WithFlexibleArray1() {}
+ int make_it_non_standard_layout;
+ private:
+ char private1[33];
+ int flexible[]; // Don't insert padding after this field.
+};
+
+WithFlexibleArray1 with_flexible_array1;
+// CHECK: %class.WithFlexibleArray1 = type { i32, [12 x i8], [33 x i8], [15 x i8], [0 x i32] }
+
+class WithFlexibleArray2 {
+ public:
+ char x[21];
+ WithFlexibleArray1 flex1; // Don't insert padding after this field.
+};
+
+WithFlexibleArray2 with_flexible_array2;
+// CHECK: %class.WithFlexibleArray2 = type { [21 x i8], [11 x i8], %class.WithFlexibleArray1 }
+
+class WithFlexibleArray3 {
+ public:
+ char x[13];
+ WithFlexibleArray2 flex2; // Don't insert padding after this field.
+};
+
+WithFlexibleArray3 with_flexible_array3;
+
+
+class Negative1 {
+ public:
+ Negative1() {}
+ int public1, public2;
+};
+Negative1 negative1;
+// CHECK: type { i32, i32 }
+
+class Negative2 {
+ public:
+ Negative2() {}
+ private:
+ int private1, private2;
+};
+Negative2 negative2;
+// CHECK: type { i32, i32 }
+
+union Negative3 {
+ char m1[8];
+ long long m2;
+};
+
+Negative3 negative3;
+// CHECK: type { i64 }
+
+class Negative4 {
+ public:
+ Negative4() {}
+ // No DTOR
+ int make_it_non_standard_layout;
+ private:
+ char private1;
+ int private2;
+};
+
+Negative4 negative4;
+// CHECK: type { i32, i8, i32 }
+
+class __attribute__((packed)) Negative5 {
+ public:
+ Negative5() {}
+ ~Negative5() {}
+ int make_it_non_standard_layout;
+ private:
+ char private1;
+ int private2;
+};
+
+Negative5 negative5;
+// CHECK: type <{ i32, i8, i32 }>
+
+
+namespace SomeNamespace {
+class BlacklistedByName {
+ public:
+ BlacklistedByName() {}
+ ~BlacklistedByName() {}
+ int make_it_non_standard_layout;
+ private:
+ char private1;
+ int private2;
+};
+} // SomeNamespace
+
+SomeNamespace::BlacklistedByName blacklisted_by_name;
+
+extern "C" {
+class ExternCStruct {
+ public:
+ ExternCStruct() {}
+ ~ExternCStruct() {}
+ int make_it_non_standard_layout;
+ private:
+ char private1;
+ int private2;
+};
+} // extern "C"
+
+ExternCStruct extern_C_struct;
+
+// CTOR
+// CHECK-LABEL: define {{.*}}Positive1C1Ev
+// CHECK: call void @__asan_poison_intra_object_redzone({{.*}}12)
+// CHECK: call void @__asan_poison_intra_object_redzone({{.*}}15)
+// CHECK: call void @__asan_poison_intra_object_redzone({{.*}}12)
+// CHECK: call void @__asan_poison_intra_object_redzone({{.*}}12)
+// CHECK: call void @__asan_poison_intra_object_redzone({{.*}}8)
+// CHECK-NOT: __asan_poison_intra_object_redzone
+// CHECK: ret void
+//
+// DTOR
+// CHECK: call void @__asan_unpoison_intra_object_redzone({{.*}}12)
+// CHECK: call void @__asan_unpoison_intra_object_redzone({{.*}}15)
+// CHECK: call void @__asan_unpoison_intra_object_redzone({{.*}}12)
+// CHECK: call void @__asan_unpoison_intra_object_redzone({{.*}}12)
+// CHECK: call void @__asan_unpoison_intra_object_redzone({{.*}}8)
+// CHECK-NOT: __asan_unpoison_intra_object_redzone
+// CHECK: ret void
+//
+//
+// CHECK-LABEL: define linkonce_odr void @_ZN20ClassWithVirtualBaseC1Ev
+// CHECK: call void @__asan_poison_intra_object_redzone({{.*}} 12)
+// CHECK: call void @__asan_poison_intra_object_redzone({{.*}} 9)
+// CHECK: call void @__asan_poison_intra_object_redzone({{.*}} 15)
+// CHECK-NOT: __asan_poison_intra_object_redzone
+// CHECK: ret void
+//
+
+struct WithVirtualDtor {
+ virtual ~WithVirtualDtor();
+ int x, y;
+};
+struct InheritsFrom_WithVirtualDtor: WithVirtualDtor {
+ int a, b;
+ InheritsFrom_WithVirtualDtor() {}
+ ~InheritsFrom_WithVirtualDtor() {}
+};
+
+void Create_InheritsFrom_WithVirtualDtor() {
+ InheritsFrom_WithVirtualDtor x;
+}
+
+
+// Make sure the dtor of InheritsFrom_WithVirtualDtor remains in the code,
+// i.e. we ignore -mconstructor-aliases when field paddings are added
+// because the paddings in InheritsFrom_WithVirtualDtor needs to be unpoisoned
+// in the dtor.
+// WITH_CTOR_ALIASES-LABEL: define void @_Z35Create_InheritsFrom_WithVirtualDtor
+// WITH_CTOR_ALIASES-NOT: call void @_ZN15WithVirtualDtorD2Ev
+// WITH_CTOR_ALIASES: call void @_ZN28InheritsFrom_WithVirtualDtorD2Ev
+// WITH_CTOR_ALIASES: ret void
+
+// Make sure we don't emit memcpy for operator= if paddings are inserted.
+struct ClassWithTrivialCopy {
+ ClassWithTrivialCopy();
+ ~ClassWithTrivialCopy();
+ void *a;
+ private:
+ void *c;
+};
+
+void MakeTrivialCopy(ClassWithTrivialCopy *s1, ClassWithTrivialCopy *s2) {
+ *s1 = *s2;
+ ClassWithTrivialCopy s3(*s2);
+}
+
+// CHECK-LABEL: define void @_Z15MakeTrivialCopyP20ClassWithTrivialCopyS0_
+// CHECK-NOT: memcpy
+// CHECK: ret void
diff --git a/test/CodeGen/sanitize-init-order.cpp b/test/CodeGen/sanitize-init-order.cpp
index 8c662dbe0343..ee53f7b0771e 100644
--- a/test/CodeGen/sanitize-init-order.cpp
+++ b/test/CodeGen/sanitize-init-order.cpp
@@ -1,8 +1,9 @@
// RUN: %clang_cc1 -fsanitize=address -emit-llvm -o - %s | FileCheck %s
// Test blacklist functionality.
-// RUN: echo "global-init-src:%s" > %t-file.blacklist
-// RUN: echo "global-init-type:struct.PODWithCtorAndDtor" > %t-type.blacklist
+// RUN: echo "src:%s=init" > %t-file.blacklist
+// RUN: echo "type:PODWithCtorAndDtor=init" > %t-type.blacklist
+// RUN: echo "type:NS::PODWithCtor=init" >> %t-type.blacklist
// RUN: %clang_cc1 -fsanitize=address -fsanitize-blacklist=%t-file.blacklist -emit-llvm -o - %s | FileCheck %s --check-prefix=BLACKLIST
// RUN: %clang_cc1 -fsanitize=address -fsanitize-blacklist=%t-type.blacklist -emit-llvm -o - %s | FileCheck %s --check-prefix=BLACKLIST
// REQUIRES: shell
@@ -25,14 +26,25 @@ struct PODWithCtorAndDtor {
};
PODWithCtorAndDtor s3;
+namespace NS {
+class PODWithCtor {
+public:
+ PODWithCtor() {}
+};
+
+const volatile PODWithCtor array[5][5];
+}
+
// Check that ASan init-order checking ignores structs with trivial default
// constructor.
-// CHECK: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]]]}
-// CHECK: ![[GLOB_1]] = metadata !{%struct.PODStruct* {{.*}}, i1 false, i1 false}
-// CHECK: ![[GLOB_2]] = metadata !{%struct.PODWithDtor* {{.*}}, i1 false, i1 false}
-// CHECK: ![[GLOB_3]] = metadata !{%struct.PODWithCtorAndDtor* {{.*}}, i1 true, i1 false}
-
-// BLACKLIST: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]]]}
-// BLACKLIST: ![[GLOB_1]] = metadata !{%struct.PODStruct* {{.*}}, i1 false, i1 false}
-// BLACKLIST: ![[GLOB_2]] = metadata !{%struct.PODWithDtor* {{.*}}, i1 false, i1 false}
-// BLACKLIST: ![[GLOB_3]] = metadata !{%struct.PODWithCtorAndDtor* {{.*}}, i1 false, i1 false}
+// CHECK: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]]], ![[GLOB_4:[0-9]]]}
+// CHECK: ![[GLOB_1]] = !{%struct.PODStruct* {{.*}}, i1 false, i1 false}
+// CHECK: ![[GLOB_2]] = !{%struct.PODWithDtor* {{.*}}, i1 false, i1 false}
+// CHECK: ![[GLOB_3]] = !{%struct.PODWithCtorAndDtor* {{.*}}, i1 true, i1 false}
+// CHECK: ![[GLOB_4]] = !{{{.*}}class.NS::PODWithCtor{{.*}}, i1 true, i1 false}
+
+// BLACKLIST: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]]], ![[GLOB_4:[0-9]]]}
+// BLACKLIST: ![[GLOB_1]] = !{%struct.PODStruct* {{.*}}, i1 false, i1 false}
+// BLACKLIST: ![[GLOB_2]] = !{%struct.PODWithDtor* {{.*}}, i1 false, i1 false}
+// BLACKLIST: ![[GLOB_3]] = !{%struct.PODWithCtorAndDtor* {{.*}}, i1 false, i1 false}
+// BLACKLIST: ![[GLOB_4]] = !{{{.*}}class.NS::PODWithCtor{{.*}}, i1 false, i1 false}
diff --git a/test/CodeGen/sanitize-recover.c b/test/CodeGen/sanitize-recover.c
index 3c9c89553813..b263f5163181 100644
--- a/test/CodeGen/sanitize-recover.c
+++ b/test/CodeGen/sanitize-recover.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=unsigned-integer-overflow %s -emit-llvm -o - | FileCheck %s --check-prefix=RECOVER
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=unsigned-integer-overflow -fno-sanitize-recover %s -emit-llvm -o - | FileCheck %s --check-prefix=ABORT
-
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=unsigned-integer-overflow -fsanitize-recover=unsigned-integer-overflow %s -emit-llvm -o - | FileCheck %s --check-prefix=RECOVER
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=unsigned-integer-overflow %s -emit-llvm -o - | FileCheck %s --check-prefix=ABORT
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=null,object-size,alignment -fsanitize-recover=object-size %s -emit-llvm -o - | FileCheck %s --check-prefix=PARTIAL
// RECOVER: @test
// ABORT: @test
@@ -15,3 +15,25 @@ void test() {
// ABORT: unreachable
x = y + z;
}
+
+void foo() {
+ union { int i; } u;
+ u.i=1;
+ // PARTIAL: %[[CHECK0:.*]] = icmp ne {{.*}}* %[[PTR:.*]], null
+
+ // PARTIAL: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
+ // PARTIAL-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
+
+ // PARTIAL: %[[MISALIGN:.*]] = and i64 {{.*}}, 3
+ // PARTIAL-NEXT: %[[CHECK2:.*]] = icmp eq i64 %[[MISALIGN]], 0
+
+ // PARTIAL: %[[CHECK02:.*]] = and i1 %[[CHECK0]], %[[CHECK2]]
+ // PARTIAL-NEXT: %[[CHECK012:.*]] = and i1 %[[CHECK02]], %[[CHECK1]]
+
+ // PARTIAL: br i1 %[[CHECK012]], {{.*}} !prof ![[WEIGHT_MD:.*]], !nosanitize
+
+ // PARTIAL: br i1 %[[CHECK02]], {{.*}}
+ // PARTIAL: call void @__ubsan_handle_type_mismatch_abort(
+ // PARTIAL-NEXT: unreachable
+ // PARTIAL: call void @__ubsan_handle_type_mismatch(
+}
diff --git a/test/CodeGen/sse-builtins.c b/test/CodeGen/sse-builtins.c
index 238454bb92e9..34c2de7d331b 100644
--- a/test/CodeGen/sse-builtins.c
+++ b/test/CodeGen/sse-builtins.c
@@ -255,3 +255,291 @@ __m128i test_blend_epi16(__m128i V1, __m128i V2) {
// CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> %{{.*}}, <8 x i32> <i32 0, i32 9, i32 2, i32 11, i32 4, i32 13, i32 6, i32 7>
return _mm_blend_epi16(V1, V2, 42);
}
+
+__m128 test_mm_cmpeq_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpeq_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 0)
+ return _mm_cmpeq_ss(__a, __b);
+}
+
+__m128 test_mm_cmplt_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmplt_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 1)
+ return _mm_cmplt_ss(__a, __b);
+}
+
+__m128 test_mm_cmple_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmple_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 2)
+ return _mm_cmple_ss(__a, __b);
+}
+
+__m128 test_mm_cmpunord_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpunord_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 3)
+ return _mm_cmpunord_ss(__a, __b);
+}
+
+__m128 test_mm_cmpneq_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpneq_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 4)
+ return _mm_cmpneq_ss(__a, __b);
+}
+
+__m128 test_mm_cmpnlt_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpnlt_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 5)
+ return _mm_cmpnlt_ss(__a, __b);
+}
+
+__m128 test_mm_cmpnle_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpnle_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 6)
+ return _mm_cmpnle_ss(__a, __b);
+}
+
+__m128 test_mm_cmpord_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpord_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 7)
+ return _mm_cmpord_ss(__a, __b);
+}
+
+__m128 test_mm_cmpgt_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpgt_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 1)
+ return _mm_cmpgt_ss(__a, __b);
+}
+
+__m128 test_mm_cmpge_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpge_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 2)
+ return _mm_cmpge_ss(__a, __b);
+}
+
+__m128 test_mm_cmpngt_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpngt_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 5)
+ return _mm_cmpngt_ss(__a, __b);
+}
+
+__m128 test_mm_cmpnge_ss(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpnge_ss
+ // CHECK: @llvm.x86.sse.cmp.ss(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 6)
+ return _mm_cmpnge_ss(__a, __b);
+}
+
+__m128 test_mm_cmpeq_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpeq_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 0)
+ return _mm_cmpeq_ps(__a, __b);
+}
+
+__m128 test_mm_cmplt_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmplt_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 1)
+ return _mm_cmplt_ps(__a, __b);
+}
+
+__m128 test_mm_cmple_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmple_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 2)
+ return _mm_cmple_ps(__a, __b);
+}
+
+__m128 test_mm_cmpunord_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpunord_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 3)
+ return _mm_cmpunord_ps(__a, __b);
+}
+
+__m128 test_mm_cmpneq_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpneq_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 4)
+ return _mm_cmpneq_ps(__a, __b);
+}
+
+__m128 test_mm_cmpnlt_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpnlt_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 5)
+ return _mm_cmpnlt_ps(__a, __b);
+}
+
+__m128 test_mm_cmpnle_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpnle_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 6)
+ return _mm_cmpnle_ps(__a, __b);
+}
+
+__m128 test_mm_cmpord_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpord_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 7)
+ return _mm_cmpord_ps(__a, __b);
+}
+
+__m128 test_mm_cmpgt_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpgt_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 1)
+ return _mm_cmpgt_ps(__a, __b);
+}
+
+__m128 test_mm_cmpge_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpge_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 2)
+ return _mm_cmpge_ps(__a, __b);
+}
+
+__m128 test_mm_cmpngt_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpngt_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 5)
+ return _mm_cmpngt_ps(__a, __b);
+}
+
+__m128 test_mm_cmpnge_ps(__m128 __a, __m128 __b) {
+ // CHECK-LABEL: @test_mm_cmpnge_ps
+ // CHECK: @llvm.x86.sse.cmp.ps(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i8 6)
+ return _mm_cmpnge_ps(__a, __b);
+}
+
+__m128d test_mm_cmpeq_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpeq_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 0)
+ return _mm_cmpeq_sd(__a, __b);
+}
+
+__m128d test_mm_cmplt_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmplt_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 1)
+ return _mm_cmplt_sd(__a, __b);
+}
+
+__m128d test_mm_cmple_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmple_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 2)
+ return _mm_cmple_sd(__a, __b);
+}
+
+__m128d test_mm_cmpunord_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpunord_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 3)
+ return _mm_cmpunord_sd(__a, __b);
+}
+
+__m128d test_mm_cmpneq_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpneq_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 4)
+ return _mm_cmpneq_sd(__a, __b);
+}
+
+__m128d test_mm_cmpnlt_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpnlt_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 5)
+ return _mm_cmpnlt_sd(__a, __b);
+}
+
+__m128d test_mm_cmpnle_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpnle_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 6)
+ return _mm_cmpnle_sd(__a, __b);
+}
+
+__m128d test_mm_cmpord_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpord_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 7)
+ return _mm_cmpord_sd(__a, __b);
+}
+
+__m128d test_mm_cmpgt_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpgt_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 1)
+ return _mm_cmpgt_sd(__a, __b);
+}
+
+__m128d test_mm_cmpge_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpge_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 2)
+ return _mm_cmpge_sd(__a, __b);
+}
+
+__m128d test_mm_cmpngt_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpngt_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 5)
+ return _mm_cmpngt_sd(__a, __b);
+}
+
+__m128d test_mm_cmpnge_sd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpnge_sd
+ // CHECK: @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 6)
+ return _mm_cmpnge_sd(__a, __b);
+}
+
+__m128d test_mm_cmpeq_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpeq_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 0)
+ return _mm_cmpeq_pd(__a, __b);
+}
+
+__m128d test_mm_cmplt_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmplt_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 1)
+ return _mm_cmplt_pd(__a, __b);
+}
+
+__m128d test_mm_cmple_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmple_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 2)
+ return _mm_cmple_pd(__a, __b);
+}
+
+__m128d test_mm_cmpunord_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpunord_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 3)
+ return _mm_cmpunord_pd(__a, __b);
+}
+
+__m128d test_mm_cmpneq_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpneq_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 4)
+ return _mm_cmpneq_pd(__a, __b);
+}
+
+__m128d test_mm_cmpnlt_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpnlt_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 5)
+ return _mm_cmpnlt_pd(__a, __b);
+}
+
+__m128d test_mm_cmpnle_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpnle_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 6)
+ return _mm_cmpnle_pd(__a, __b);
+}
+
+__m128d test_mm_cmpord_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpord_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 7)
+ return _mm_cmpord_pd(__a, __b);
+}
+
+__m128d test_mm_cmpgt_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpgt_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 1)
+ return _mm_cmpgt_pd(__a, __b);
+}
+
+__m128d test_mm_cmpge_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpge_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 2)
+ return _mm_cmpge_pd(__a, __b);
+}
+
+__m128d test_mm_cmpngt_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpngt_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 5)
+ return _mm_cmpngt_pd(__a, __b);
+}
+
+__m128d test_mm_cmpnge_pd(__m128d __a, __m128d __b) {
+ // CHECK-LABEL: @test_mm_cmpnge_pd
+ // CHECK: @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 6)
+ return _mm_cmpnge_pd(__a, __b);
+}
diff --git a/test/CodeGen/target-data.c b/test/CodeGen/target-data.c
index 5153be9075ed..d8e77c5352c2 100644
--- a/test/CodeGen/target-data.c
+++ b/test/CodeGen/target-data.c
@@ -68,7 +68,7 @@
// RUN: %clang_cc1 -triple arm-nacl-gnueabi -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=ARM-NACL
-// ARM-NACL: target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S128"
+// ARM-NACL: target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"
// RUN: %clang_cc1 -triple mipsel-nacl -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=MIPS-NACL
@@ -118,7 +118,7 @@
// RUN: | FileCheck %s -check-prefix=R600D
// R600D: target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"
-// RUN: %clang_cc1 -triple r600-unknown -target-cpu hawaii -o - -emit-llvm %s \
+// RUN: %clang_cc1 -triple amdgcn-unknown -target-cpu hawaii -o - -emit-llvm %s \
// RUN: | FileCheck %s -check-prefix=R600SI
// R600SI: target datalayout = "e-p:32:32-p1:64:64-p2:64:64-p3:32:32-p4:64:64-p5:32:32-p24:64:64-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"
@@ -128,15 +128,15 @@
// RUN: %clang_cc1 -triple thumb-unknown-gnueabi -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=THUMB
-// THUMB: target datalayout = "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-v128:64:128-a:0:32-n32-S64"
+// THUMB: target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
// RUN: %clang_cc1 -triple arm-unknown-gnueabi -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=ARM
-// ARM: target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+// ARM: target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
// RUN: %clang_cc1 -triple thumb-unknown -o - -emit-llvm -target-abi apcs-gnu \
// RUN: %s | FileCheck %s -check-prefix=THUMB-GNU
-// THUMB-GNU: target datalayout = "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
+// THUMB-GNU: target datalayout = "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
// RUN: %clang_cc1 -triple arm-unknown -o - -emit-llvm -target-abi apcs-gnu \
// RUN: %s | FileCheck %s -check-prefix=ARM-GNU
@@ -152,7 +152,7 @@
// RUN: %clang_cc1 -triple msp430-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=MSP430
-// MSP430: target datalayout = "e-m:e-p:16:16-i32:16:32-n8:16"
+// MSP430: target datalayout = "e-m:e-p:16:16-i32:16:32-a:16-n8:16"
// RUN: %clang_cc1 -triple tce-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=TCE
diff --git a/test/CodeGen/tbaa-class.cpp b/test/CodeGen/tbaa-class.cpp
index bdd155d450a9..a8005d605724 100644
--- a/test/CodeGen/tbaa-class.cpp
+++ b/test/CodeGen/tbaa-class.cpp
@@ -198,31 +198,31 @@ uint32_t g12(StructC *C, StructD *D, uint64_t count) {
return b1->a.f32;
}
-// CHECK: [[TYPE_char:!.*]] = metadata !{metadata !"omnipotent char", metadata [[TAG_cxx_tbaa:!.*]],
-// CHECK: [[TAG_cxx_tbaa]] = metadata !{metadata !"Simple C/C++ TBAA"}
-// CHECK: [[TAG_i32]] = metadata !{metadata [[TYPE_i32:!.*]], metadata [[TYPE_i32]], i64 0}
-// CHECK: [[TYPE_i32]] = metadata !{metadata !"int", metadata [[TYPE_char]],
-// CHECK: [[TAG_i16]] = metadata !{metadata [[TYPE_i16:!.*]], metadata [[TYPE_i16]], i64 0}
-// CHECK: [[TYPE_i16]] = metadata !{metadata !"short", metadata [[TYPE_char]],
-
-// PATH: [[TYPE_CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata
-// PATH: [[TAG_i32]] = metadata !{metadata [[TYPE_INT:!.*]], metadata [[TYPE_INT]], i64 0}
-// PATH: [[TYPE_INT]] = metadata !{metadata !"int", metadata [[TYPE_CHAR]]
-// PATH: [[TAG_A_f32]] = metadata !{metadata [[TYPE_A:!.*]], metadata [[TYPE_INT]], i64 4}
-// PATH: [[TYPE_A]] = metadata !{metadata !"_ZTS7StructA", metadata [[TYPE_SHORT:!.*]], i64 0, metadata [[TYPE_INT]], i64 4, metadata [[TYPE_SHORT]], i64 8, metadata [[TYPE_INT]], i64 12}
-// PATH: [[TYPE_SHORT:!.*]] = metadata !{metadata !"short", metadata [[TYPE_CHAR]]
-// PATH: [[TAG_A_f16]] = metadata !{metadata [[TYPE_A]], metadata [[TYPE_SHORT]], i64 0}
-// PATH: [[TAG_B_a_f32]] = metadata !{metadata [[TYPE_B:!.*]], metadata [[TYPE_INT]], i64 8}
-// PATH: [[TYPE_B]] = metadata !{metadata !"_ZTS7StructB", metadata [[TYPE_SHORT]], i64 0, metadata [[TYPE_A]], i64 4, metadata [[TYPE_INT]], i64 20}
-// PATH: [[TAG_B_a_f16]] = metadata !{metadata [[TYPE_B]], metadata [[TYPE_SHORT]], i64 4}
-// PATH: [[TAG_B_f32]] = metadata !{metadata [[TYPE_B]], metadata [[TYPE_INT]], i64 20}
-// PATH: [[TAG_B_a_f32_2]] = metadata !{metadata [[TYPE_B]], metadata [[TYPE_INT]], i64 16}
-// PATH: [[TAG_S_f32]] = metadata !{metadata [[TYPE_S:!.*]], metadata [[TYPE_INT]], i64 4}
-// PATH: [[TYPE_S]] = metadata !{metadata !"_ZTS7StructS", metadata [[TYPE_SHORT]], i64 0, metadata [[TYPE_INT]], i64 4}
-// PATH: [[TAG_S_f16]] = metadata !{metadata [[TYPE_S]], metadata [[TYPE_SHORT]], i64 0}
-// PATH: [[TAG_S2_f32_2]] = metadata !{metadata [[TYPE_S2:!.*]], metadata [[TYPE_INT]], i64 12}
-// PATH: [[TYPE_S2]] = metadata !{metadata !"_ZTS8StructS2", metadata [[TYPE_SHORT]], i64 8, metadata [[TYPE_INT]], i64 12}
-// PATH: [[TAG_C_b_a_f32]] = metadata !{metadata [[TYPE_C:!.*]], metadata [[TYPE_INT]], i64 12}
-// PATH: [[TYPE_C]] = metadata !{metadata !"_ZTS7StructC", metadata [[TYPE_SHORT]], i64 0, metadata [[TYPE_B]], i64 4, metadata [[TYPE_INT]], i64 28}
-// PATH: [[TAG_D_b_a_f32]] = metadata !{metadata [[TYPE_D:!.*]], metadata [[TYPE_INT]], i64 12}
-// PATH: [[TYPE_D]] = metadata !{metadata !"_ZTS7StructD", metadata [[TYPE_SHORT]], i64 0, metadata [[TYPE_B]], i64 4, metadata [[TYPE_INT]], i64 28, metadata [[TYPE_CHAR]], i64 32}
+// CHECK: [[TYPE_char:!.*]] = !{!"omnipotent char", [[TAG_cxx_tbaa:!.*]],
+// CHECK: [[TAG_cxx_tbaa]] = !{!"Simple C/C++ TBAA"}
+// CHECK: [[TAG_i32]] = !{[[TYPE_i32:!.*]], [[TYPE_i32]], i64 0}
+// CHECK: [[TYPE_i32]] = !{!"int", [[TYPE_char]],
+// CHECK: [[TAG_i16]] = !{[[TYPE_i16:!.*]], [[TYPE_i16]], i64 0}
+// CHECK: [[TYPE_i16]] = !{!"short", [[TYPE_char]],
+
+// PATH: [[TYPE_CHAR:!.*]] = !{!"omnipotent char", !
+// PATH: [[TAG_i32]] = !{[[TYPE_INT:!.*]], [[TYPE_INT]], i64 0}
+// PATH: [[TYPE_INT]] = !{!"int", [[TYPE_CHAR]]
+// PATH: [[TAG_A_f32]] = !{[[TYPE_A:!.*]], [[TYPE_INT]], i64 4}
+// PATH: [[TYPE_A]] = !{!"_ZTS7StructA", [[TYPE_SHORT:!.*]], i64 0, [[TYPE_INT]], i64 4, [[TYPE_SHORT]], i64 8, [[TYPE_INT]], i64 12}
+// PATH: [[TYPE_SHORT:!.*]] = !{!"short", [[TYPE_CHAR]]
+// PATH: [[TAG_A_f16]] = !{[[TYPE_A]], [[TYPE_SHORT]], i64 0}
+// PATH: [[TAG_B_a_f32]] = !{[[TYPE_B:!.*]], [[TYPE_INT]], i64 8}
+// PATH: [[TYPE_B]] = !{!"_ZTS7StructB", [[TYPE_SHORT]], i64 0, [[TYPE_A]], i64 4, [[TYPE_INT]], i64 20}
+// PATH: [[TAG_B_a_f16]] = !{[[TYPE_B]], [[TYPE_SHORT]], i64 4}
+// PATH: [[TAG_B_f32]] = !{[[TYPE_B]], [[TYPE_INT]], i64 20}
+// PATH: [[TAG_B_a_f32_2]] = !{[[TYPE_B]], [[TYPE_INT]], i64 16}
+// PATH: [[TAG_S_f32]] = !{[[TYPE_S:!.*]], [[TYPE_INT]], i64 4}
+// PATH: [[TYPE_S]] = !{!"_ZTS7StructS", [[TYPE_SHORT]], i64 0, [[TYPE_INT]], i64 4}
+// PATH: [[TAG_S_f16]] = !{[[TYPE_S]], [[TYPE_SHORT]], i64 0}
+// PATH: [[TAG_S2_f32_2]] = !{[[TYPE_S2:!.*]], [[TYPE_INT]], i64 12}
+// PATH: [[TYPE_S2]] = !{!"_ZTS8StructS2", [[TYPE_SHORT]], i64 8, [[TYPE_INT]], i64 12}
+// PATH: [[TAG_C_b_a_f32]] = !{[[TYPE_C:!.*]], [[TYPE_INT]], i64 12}
+// PATH: [[TYPE_C]] = !{!"_ZTS7StructC", [[TYPE_SHORT]], i64 0, [[TYPE_B]], i64 4, [[TYPE_INT]], i64 28}
+// PATH: [[TAG_D_b_a_f32]] = !{[[TYPE_D:!.*]], [[TYPE_INT]], i64 12}
+// PATH: [[TYPE_D]] = !{!"_ZTS7StructD", [[TYPE_SHORT]], i64 0, [[TYPE_B]], i64 4, [[TYPE_INT]], i64 28, [[TYPE_CHAR]], i64 32}
diff --git a/test/CodeGen/tbaa-for-vptr.cpp b/test/CodeGen/tbaa-for-vptr.cpp
index ded574ea9376..35e95a54dab2 100644
--- a/test/CodeGen/tbaa-for-vptr.cpp
+++ b/test/CodeGen/tbaa-for-vptr.cpp
@@ -30,6 +30,6 @@ void CallFoo(A *a, int (A::*fp)() const) {
// CHECK-LABEL: @_ZN1AC2Ev
// CHECK: store {{.*}} !tbaa ![[NUM]]
//
-// CHECK: [[NUM]] = metadata !{metadata [[TYPE:!.*]], metadata [[TYPE]], i64 0}
-// CHECK: [[TYPE]] = metadata !{metadata !"vtable pointer", metadata !{{.*}}
-// NOTBAA-NOT: = metadata !{metadata !"Simple C/C++ TBAA"}
+// CHECK: [[NUM]] = !{[[TYPE:!.*]], [[TYPE]], i64 0}
+// CHECK: [[TYPE]] = !{!"vtable pointer", !{{.*}}
+// NOTBAA-NOT: = !{!"Simple C/C++ TBAA"}
diff --git a/test/CodeGen/tbaa-ms-abi.cpp b/test/CodeGen/tbaa-ms-abi.cpp
index 2a9e47e40810..878e1b610b59 100644
--- a/test/CodeGen/tbaa-ms-abi.cpp
+++ b/test/CodeGen/tbaa-ms-abi.cpp
@@ -16,7 +16,7 @@ StructB::StructB() {
// CHECK: store i32 42, i32* {{.*}}, !tbaa [[TAG_A_i32:!.*]]
}
-// CHECK: [[TYPE_INT:!.*]] = metadata !{metadata !"int", metadata [[TYPE_CHAR:!.*]], i64 0}
-// CHECK: [[TYPE_CHAR]] = metadata !{metadata !"omnipotent char", metadata
-// CHECK: [[TAG_A_i32]] = metadata !{metadata [[TYPE_A:!.*]], metadata [[TYPE_INT]], i64 0}
-// CHECK: [[TYPE_A]] = metadata !{metadata !"?AUStructA@@", metadata [[TYPE_INT]], i64 0}
+// CHECK: [[TYPE_INT:!.*]] = !{!"int", [[TYPE_CHAR:!.*]], i64 0}
+// CHECK: [[TYPE_CHAR]] = !{!"omnipotent char", !
+// CHECK: [[TAG_A_i32]] = !{[[TYPE_A:!.*]], [[TYPE_INT]], i64 0}
+// CHECK: [[TYPE_A]] = !{!"?AUStructA@@", [[TYPE_INT]], i64 0}
diff --git a/test/CodeGen/tbaa-struct.cpp b/test/CodeGen/tbaa-struct.cpp
index 71d3ed11a173..2623c42c9a3f 100644
--- a/test/CodeGen/tbaa-struct.cpp
+++ b/test/CodeGen/tbaa-struct.cpp
@@ -62,14 +62,14 @@ void copy5(struct six *a, struct six *b) {
}
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 6, i32 1, i1 false), !tbaa.struct [[TS5:!.*]]
-// CHECK: [[TS]] = metadata !{i64 0, i64 2, metadata !{{.*}}, i64 4, i64 4, metadata !{{.*}}, i64 8, i64 1, metadata !{{.*}}, i64 12, i64 4, metadata !{{.*}}}
-// CHECK: [[CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata !{{.*}}}
-// CHECK: [[TAG_INT:!.*]] = metadata !{metadata [[INT:!.*]], metadata [[INT]], i64 0}
-// CHECK: [[INT]] = metadata !{metadata !"int", metadata [[CHAR]]
-// CHECK: [[TAG_CHAR:!.*]] = metadata !{metadata [[CHAR]], metadata [[CHAR]], i64 0}
+// CHECK: [[TS]] = !{i64 0, i64 2, !{{.*}}, i64 4, i64 4, !{{.*}}, i64 8, i64 1, !{{.*}}, i64 12, i64 4, !{{.*}}}
+// CHECK: [[CHAR:!.*]] = !{!"omnipotent char", !{{.*}}}
+// CHECK: [[TAG_INT:!.*]] = !{[[INT:!.*]], [[INT]], i64 0}
+// CHECK: [[INT]] = !{!"int", [[CHAR]]
+// CHECK: [[TAG_CHAR:!.*]] = !{[[CHAR]], [[CHAR]], i64 0}
// (offset, size) = (0,1) char; (4,2) short; (8,4) int; (12,1) char; (16,4) int; (20,4) int
-// CHECK: [[TS2]] = metadata !{i64 0, i64 1, metadata !{{.*}}, i64 4, i64 2, metadata !{{.*}}, i64 8, i64 4, metadata !{{.*}}, i64 12, i64 1, metadata !{{.*}}, i64 16, i64 4, metadata {{.*}}, i64 20, i64 4, metadata {{.*}}}
+// CHECK: [[TS2]] = !{i64 0, i64 1, !{{.*}}, i64 4, i64 2, !{{.*}}, i64 8, i64 4, !{{.*}}, i64 12, i64 1, !{{.*}}, i64 16, i64 4, {{.*}}, i64 20, i64 4, {{.*}}}
// (offset, size) = (0,8) char; (0,2) char; (4,8) char
-// CHECK: [[TS3]] = metadata !{i64 0, i64 8, metadata !{{.*}}, i64 0, i64 2, metadata !{{.*}}, i64 4, i64 8, metadata !{{.*}}}
-// CHECK: [[TS4]] = metadata !{i64 0, i64 1, metadata [[TAG_CHAR]], i64 1, i64 4, metadata [[TAG_INT]], i64 1, i64 1, metadata [[TAG_CHAR]], i64 2, i64 1, metadata [[TAG_CHAR]]}
-// CHECK: [[TS5]] = metadata !{i64 0, i64 1, metadata [[TAG_CHAR]], i64 4, i64 4, metadata [[TAG_INT]], i64 4, i64 1, metadata [[TAG_CHAR]], i64 5, i64 1, metadata [[TAG_CHAR]]}
+// CHECK: [[TS3]] = !{i64 0, i64 8, !{{.*}}, i64 0, i64 2, !{{.*}}, i64 4, i64 8, !{{.*}}}
+// CHECK: [[TS4]] = !{i64 0, i64 1, [[TAG_CHAR]], i64 1, i64 4, [[TAG_INT]], i64 1, i64 1, [[TAG_CHAR]], i64 2, i64 1, [[TAG_CHAR]]}
+// CHECK: [[TS5]] = !{i64 0, i64 1, [[TAG_CHAR]], i64 4, i64 4, [[TAG_INT]], i64 4, i64 1, [[TAG_CHAR]], i64 5, i64 1, [[TAG_CHAR]]}
diff --git a/test/CodeGen/tbaa.cpp b/test/CodeGen/tbaa.cpp
index 92d31e5ae293..4a723f100ecf 100644
--- a/test/CodeGen/tbaa.cpp
+++ b/test/CodeGen/tbaa.cpp
@@ -236,37 +236,37 @@ uint32_t g15(StructS *S, StructS3 *S3, uint64_t count) {
return S->f32;
}
-// CHECK: [[TYPE_char:!.*]] = metadata !{metadata !"omnipotent char", metadata [[TAG_cxx_tbaa:!.*]],
-// CHECK: [[TAG_cxx_tbaa]] = metadata !{metadata !"Simple C/C++ TBAA"}
-// CHECK: [[TAG_i32]] = metadata !{metadata [[TYPE_i32:!.*]], metadata [[TYPE_i32]], i64 0}
-// CHECK: [[TYPE_i32]] = metadata !{metadata !"int", metadata [[TYPE_char]],
-// CHECK: [[TAG_i16]] = metadata !{metadata [[TYPE_i16:!.*]], metadata [[TYPE_i16]], i64 0}
-// CHECK: [[TYPE_i16]] = metadata !{metadata !"short", metadata [[TYPE_char]],
-// CHECK: [[TAG_char]] = metadata !{metadata [[TYPE_char]], metadata [[TYPE_char]], i64 0}
+// CHECK: [[TYPE_char:!.*]] = !{!"omnipotent char", [[TAG_cxx_tbaa:!.*]],
+// CHECK: [[TAG_cxx_tbaa]] = !{!"Simple C/C++ TBAA"}
+// CHECK: [[TAG_i32]] = !{[[TYPE_i32:!.*]], [[TYPE_i32]], i64 0}
+// CHECK: [[TYPE_i32]] = !{!"int", [[TYPE_char]],
+// CHECK: [[TAG_i16]] = !{[[TYPE_i16:!.*]], [[TYPE_i16]], i64 0}
+// CHECK: [[TYPE_i16]] = !{!"short", [[TYPE_char]],
+// CHECK: [[TAG_char]] = !{[[TYPE_char]], [[TYPE_char]], i64 0}
-// PATH: [[TYPE_CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata
-// PATH: [[TAG_i32]] = metadata !{metadata [[TYPE_INT:!.*]], metadata [[TYPE_INT]], i64 0}
-// PATH: [[TYPE_INT]] = metadata !{metadata !"int", metadata [[TYPE_CHAR]]
-// PATH: [[TAG_A_f32]] = metadata !{metadata [[TYPE_A:!.*]], metadata [[TYPE_INT]], i64 4}
-// PATH: [[TYPE_A]] = metadata !{metadata !"_ZTS7StructA", metadata [[TYPE_SHORT:!.*]], i64 0, metadata [[TYPE_INT]], i64 4, metadata [[TYPE_SHORT]], i64 8, metadata [[TYPE_INT]], i64 12}
-// PATH: [[TYPE_SHORT:!.*]] = metadata !{metadata !"short", metadata [[TYPE_CHAR]]
-// PATH: [[TAG_A_f16]] = metadata !{metadata [[TYPE_A]], metadata [[TYPE_SHORT]], i64 0}
-// PATH: [[TAG_B_a_f32]] = metadata !{metadata [[TYPE_B:!.*]], metadata [[TYPE_INT]], i64 8}
-// PATH: [[TYPE_B]] = metadata !{metadata !"_ZTS7StructB", metadata [[TYPE_SHORT]], i64 0, metadata [[TYPE_A]], i64 4, metadata [[TYPE_INT]], i64 20}
-// PATH: [[TAG_B_a_f16]] = metadata !{metadata [[TYPE_B]], metadata [[TYPE_SHORT]], i64 4}
-// PATH: [[TAG_B_f32]] = metadata !{metadata [[TYPE_B]], metadata [[TYPE_INT]], i64 20}
-// PATH: [[TAG_B_a_f32_2]] = metadata !{metadata [[TYPE_B]], metadata [[TYPE_INT]], i64 16}
-// PATH: [[TAG_S_f32]] = metadata !{metadata [[TYPE_S:!.*]], metadata [[TYPE_INT]], i64 4}
-// PATH: [[TYPE_S]] = metadata !{metadata !"_ZTS7StructS", metadata [[TYPE_SHORT]], i64 0, metadata [[TYPE_INT]], i64 4}
-// PATH: [[TAG_S_f16]] = metadata !{metadata [[TYPE_S]], metadata [[TYPE_SHORT]], i64 0}
-// PATH: [[TAG_S2_f32]] = metadata !{metadata [[TYPE_S2:!.*]], metadata [[TYPE_INT]], i64 4}
-// PATH: [[TYPE_S2]] = metadata !{metadata !"_ZTS8StructS2", metadata [[TYPE_SHORT]], i64 0, metadata [[TYPE_INT]], i64 4}
-// PATH: [[TAG_S2_f16]] = metadata !{metadata [[TYPE_S2]], metadata [[TYPE_SHORT]], i64 0}
-// PATH: [[TAG_C_b_a_f32]] = metadata !{metadata [[TYPE_C:!.*]], metadata [[TYPE_INT]], i64 12}
-// PATH: [[TYPE_C]] = metadata !{metadata !"_ZTS7StructC", metadata [[TYPE_SHORT]], i64 0, metadata [[TYPE_B]], i64 4, metadata [[TYPE_INT]], i64 28}
-// PATH: [[TAG_D_b_a_f32]] = metadata !{metadata [[TYPE_D:!.*]], metadata [[TYPE_INT]], i64 12}
-// PATH: [[TYPE_D]] = metadata !{metadata !"_ZTS7StructD", metadata [[TYPE_SHORT]], i64 0, metadata [[TYPE_B]], i64 4, metadata [[TYPE_INT]], i64 28, metadata [[TYPE_CHAR]], i64 32}
-// PATH: [[TAG_five_b]] = metadata !{metadata [[TYPE_five:!.*]], metadata [[TYPE_CHAR]], i64 1}
-// PATH: [[TYPE_five]] = metadata !{metadata !"_ZTS4five", metadata [[TYPE_CHAR]], i64 0, metadata [[TYPE_INT]], i64 1, metadata [[TYPE_CHAR]], i64 1, metadata [[TYPE_CHAR]], i64 2}
-// PATH: [[TAG_six_b]] = metadata !{metadata [[TYPE_six:!.*]], metadata [[TYPE_CHAR]], i64 4}
-// PATH: [[TYPE_six]] = metadata !{metadata !"_ZTS3six", metadata [[TYPE_CHAR]], i64 0, metadata [[TYPE_INT]], i64 4, metadata [[TYPE_CHAR]], i64 4, metadata [[TYPE_CHAR]], i64 5}
+// PATH: [[TYPE_CHAR:!.*]] = !{!"omnipotent char", !
+// PATH: [[TAG_i32]] = !{[[TYPE_INT:!.*]], [[TYPE_INT]], i64 0}
+// PATH: [[TYPE_INT]] = !{!"int", [[TYPE_CHAR]]
+// PATH: [[TAG_A_f32]] = !{[[TYPE_A:!.*]], [[TYPE_INT]], i64 4}
+// PATH: [[TYPE_A]] = !{!"_ZTS7StructA", [[TYPE_SHORT:!.*]], i64 0, [[TYPE_INT]], i64 4, [[TYPE_SHORT]], i64 8, [[TYPE_INT]], i64 12}
+// PATH: [[TYPE_SHORT:!.*]] = !{!"short", [[TYPE_CHAR]]
+// PATH: [[TAG_A_f16]] = !{[[TYPE_A]], [[TYPE_SHORT]], i64 0}
+// PATH: [[TAG_B_a_f32]] = !{[[TYPE_B:!.*]], [[TYPE_INT]], i64 8}
+// PATH: [[TYPE_B]] = !{!"_ZTS7StructB", [[TYPE_SHORT]], i64 0, [[TYPE_A]], i64 4, [[TYPE_INT]], i64 20}
+// PATH: [[TAG_B_a_f16]] = !{[[TYPE_B]], [[TYPE_SHORT]], i64 4}
+// PATH: [[TAG_B_f32]] = !{[[TYPE_B]], [[TYPE_INT]], i64 20}
+// PATH: [[TAG_B_a_f32_2]] = !{[[TYPE_B]], [[TYPE_INT]], i64 16}
+// PATH: [[TAG_S_f32]] = !{[[TYPE_S:!.*]], [[TYPE_INT]], i64 4}
+// PATH: [[TYPE_S]] = !{!"_ZTS7StructS", [[TYPE_SHORT]], i64 0, [[TYPE_INT]], i64 4}
+// PATH: [[TAG_S_f16]] = !{[[TYPE_S]], [[TYPE_SHORT]], i64 0}
+// PATH: [[TAG_S2_f32]] = !{[[TYPE_S2:!.*]], [[TYPE_INT]], i64 4}
+// PATH: [[TYPE_S2]] = !{!"_ZTS8StructS2", [[TYPE_SHORT]], i64 0, [[TYPE_INT]], i64 4}
+// PATH: [[TAG_S2_f16]] = !{[[TYPE_S2]], [[TYPE_SHORT]], i64 0}
+// PATH: [[TAG_C_b_a_f32]] = !{[[TYPE_C:!.*]], [[TYPE_INT]], i64 12}
+// PATH: [[TYPE_C]] = !{!"_ZTS7StructC", [[TYPE_SHORT]], i64 0, [[TYPE_B]], i64 4, [[TYPE_INT]], i64 28}
+// PATH: [[TAG_D_b_a_f32]] = !{[[TYPE_D:!.*]], [[TYPE_INT]], i64 12}
+// PATH: [[TYPE_D]] = !{!"_ZTS7StructD", [[TYPE_SHORT]], i64 0, [[TYPE_B]], i64 4, [[TYPE_INT]], i64 28, [[TYPE_CHAR]], i64 32}
+// PATH: [[TAG_five_b]] = !{[[TYPE_five:!.*]], [[TYPE_CHAR]], i64 1}
+// PATH: [[TYPE_five]] = !{!"_ZTS4five", [[TYPE_CHAR]], i64 0, [[TYPE_INT]], i64 1, [[TYPE_CHAR]], i64 1, [[TYPE_CHAR]], i64 2}
+// PATH: [[TAG_six_b]] = !{[[TYPE_six:!.*]], [[TYPE_CHAR]], i64 4}
+// PATH: [[TYPE_six]] = !{!"_ZTS3six", [[TYPE_CHAR]], i64 0, [[TYPE_INT]], i64 4, [[TYPE_CHAR]], i64 4, [[TYPE_CHAR]], i64 5}
diff --git a/test/CodeGen/transparent-union.c b/test/CodeGen/transparent-union.c
index 21040e4da05b..2f00c2d21a05 100644
--- a/test/CodeGen/transparent-union.c
+++ b/test/CodeGen/transparent-union.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -Werror -triple i386-unknown-unknown -emit-llvm -o %t %s
-// RUN: FileCheck < %t %s
-//
-// FIXME: Note that we don't currently get the ABI right here. f0() should be
-// f0(i8*).
+// RUN: %clang_cc1 -Werror -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Werror -triple i386-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Werror -triple armv7-linux -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM
+// RUN: %clang_cc1 -Werror -triple powerpc64le-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Werror -triple aarch64-linux -emit-llvm -o - %s | FileCheck %s
typedef union {
void *f0;
@@ -10,10 +10,15 @@ typedef union {
void f0(transp_t0 obj);
-// CHECK-LABEL: define void @f1_0(i32* %a0)
-// CHECK: call void @f0(%union.transp_t0* byval align 4 %{{.*}})
+// CHECK-LABEL: define void @f1_0(i32* %a0)
+// CHECK: call void @f0(i8* %{{.*}})
// CHECK: call void %{{.*}}(i8* %{{[a-z0-9]*}})
// CHECK: }
+
+// ARM-LABEL: define arm_aapcscc void @f1_0(i32* %a0)
+// ARM: call arm_aapcscc void @f0(i8* %{{.*}})
+// ARM: call arm_aapcscc void %{{.*}}(i8* %{{[a-z0-9]*}})
+// ARM: }
void f1_0(int *a0) {
void (*f0p)(void *) = f0;
f0(a0);
diff --git a/test/CodeGen/ubsan-type-blacklist.cpp b/test/CodeGen/ubsan-type-blacklist.cpp
index 7dc6fe159b51..b3137e7806c7 100644
--- a/test/CodeGen/ubsan-type-blacklist.cpp
+++ b/test/CodeGen/ubsan-type-blacklist.cpp
@@ -1,9 +1,7 @@
// Verify ubsan vptr does not check down-casts on blacklisted types.
// RUN: echo "type:_ZTI3Foo" > %t-type.blacklist
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -emit-llvm %s -o - | FileCheck %s --check-prefix=DEFAULT
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-blacklist=%t-type.blacklist -emit-llvm %s -o - | FileCheck %s --check-prefix=TYPE
-
-// REQUIRES: shell
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -emit-llvm %s -o - | FileCheck %s --check-prefix=DEFAULT
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -fsanitize-blacklist=%t-type.blacklist -emit-llvm %s -o - | FileCheck %s --check-prefix=TYPE
class Bar {
public:
diff --git a/test/CodeGen/variadic-null-win64.c b/test/CodeGen/variadic-null-win64.c
new file mode 100644
index 000000000000..4f57e7b39f9f
--- /dev/null
+++ b/test/CodeGen/variadic-null-win64.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-windows-msvc | FileCheck %s --check-prefix=WINDOWS
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-linux | FileCheck %s --check-prefix=LINUX
+
+// Make it possible to pass NULL through variadic functions on platforms where
+// NULL has an integer type that is more narrow than a pointer. On such
+// platforms we widen null pointer constants to a pointer-sized integer.
+
+#define NULL 0
+
+void v(const char *f, ...);
+void f(const char *f) {
+ v(f, 1, 2, 3, NULL);
+}
+// WINDOWS: define void @f(i8* %f)
+// WINDOWS: call void (i8*, ...)* @v(i8* {{.*}}, i32 1, i32 2, i32 3, i64 0)
+// LINUX: define void @f(i8* %f)
+// LINUX: call void (i8*, ...)* @v(i8* {{.*}}, i32 1, i32 2, i32 3, i32 0)
diff --git a/test/CodeGen/vectorcall.c b/test/CodeGen/vectorcall.c
new file mode 100644
index 000000000000..17927c7a3de4
--- /dev/null
+++ b/test/CodeGen/vectorcall.c
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-win32 | FileCheck %s --check-prefix=X64
+
+void __vectorcall v1(int a, int b) {}
+// CHECK: define x86_vectorcallcc void @"\01v1@@8"(i32 inreg %a, i32 inreg %b)
+// X64: define x86_vectorcallcc void @"\01v1@@16"(i32 %a, i32 %b)
+
+void __vectorcall v2(char a, char b) {}
+// CHECK: define x86_vectorcallcc void @"\01v2@@8"(i8 inreg signext %a, i8 inreg signext %b)
+// X64: define x86_vectorcallcc void @"\01v2@@16"(i8 %a, i8 %b)
+
+struct Small { int a; };
+void __vectorcall v3(int a, struct Small b, int c) {}
+// CHECK: define x86_vectorcallcc void @"\01v3@@12"(i32 inreg %a, %struct.Small* byval align 4 %b, i32 inreg %c)
+// X64: define x86_vectorcallcc void @"\01v3@@24"(i32 %a, i32 %b.coerce, i32 %c)
+
+struct Large { int a[5]; };
+void __vectorcall v4(int a, struct Large b, int c) {}
+// CHECK: define x86_vectorcallcc void @"\01v4@@28"(i32 inreg %a, %struct.Large* byval align 4 %b, i32 inreg %c)
+// X64: define x86_vectorcallcc void @"\01v4@@40"(i32 %a, %struct.Large* %b, i32 %c)
+
+struct HFA2 { double x, y; };
+struct HFA4 { double w, x, y, z; };
+struct HFA5 { double v, w, x, y, z; };
+
+void __vectorcall hfa1(int a, struct HFA4 b, int c) {}
+// CHECK: define x86_vectorcallcc void @"\01hfa1@@40"(i32 inreg %a, double %b.0, double %b.1, double %b.2, double %b.3, i32 inreg %c)
+// X64: define x86_vectorcallcc void @"\01hfa1@@48"(i32 %a, double %b.0, double %b.1, double %b.2, double %b.3, i32 %c)
+
+// HFAs that would require more than six total SSE registers are passed
+// indirectly. Additional vector arguments can consume the rest of the SSE
+// registers.
+void __vectorcall hfa2(struct HFA4 a, struct HFA4 b, double c) {}
+// CHECK: define x86_vectorcallcc void @"\01hfa2@@72"(double %a.0, double %a.1, double %a.2, double %a.3, %struct.HFA4* inreg %b, double %c)
+// X64: define x86_vectorcallcc void @"\01hfa2@@72"(double %a.0, double %a.1, double %a.2, double %a.3, %struct.HFA4* align 8 %b, double %c)
+
+// Ensure that we pass builtin types directly while counting them against the
+// SSE register usage.
+void __vectorcall hfa3(double a, double b, double c, double d, double e, struct HFA2 f) {}
+// CHECK: define x86_vectorcallcc void @"\01hfa3@@56"(double %a, double %b, double %c, double %d, double %e, %struct.HFA2* inreg %f)
+// X64: define x86_vectorcallcc void @"\01hfa3@@56"(double %a, double %b, double %c, double %d, double %e, %struct.HFA2* align 8 %f)
+
+// Aggregates with more than four elements are not HFAs and are passed byval.
+// Because they are not classified as homogeneous, they don't get special
+// handling to ensure alignment.
+void __vectorcall hfa4(struct HFA5 a) {}
+// CHECK: define x86_vectorcallcc void @"\01hfa4@@40"(%struct.HFA5* byval align 4)
+// X64: define x86_vectorcallcc void @"\01hfa4@@40"(%struct.HFA5* %a)
+
+// Return HFAs of 4 or fewer elements in registers.
+static struct HFA2 g_hfa2;
+struct HFA2 __vectorcall hfa5(void) { return g_hfa2; }
+// CHECK: define x86_vectorcallcc %struct.HFA2 @"\01hfa5@@0"()
+// X64: define x86_vectorcallcc %struct.HFA2 @"\01hfa5@@0"()
+
+typedef float __attribute__((vector_size(16))) v4f32;
+struct HVA2 { v4f32 x, y; };
+struct HVA4 { v4f32 w, x, y, z; };
+
+void __vectorcall hva1(int a, struct HVA4 b, int c) {}
+// CHECK: define x86_vectorcallcc void @"\01hva1@@72"(i32 inreg %a, <4 x float> %b.0, <4 x float> %b.1, <4 x float> %b.2, <4 x float> %b.3, i32 inreg %c)
+// X64: define x86_vectorcallcc void @"\01hva1@@80"(i32 %a, <4 x float> %b.0, <4 x float> %b.1, <4 x float> %b.2, <4 x float> %b.3, i32 %c)
+
+void __vectorcall hva2(struct HVA4 a, struct HVA4 b, v4f32 c) {}
+// CHECK: define x86_vectorcallcc void @"\01hva2@@144"(<4 x float> %a.0, <4 x float> %a.1, <4 x float> %a.2, <4 x float> %a.3, %struct.HVA4* inreg %b, <4 x float> %c)
+// X64: define x86_vectorcallcc void @"\01hva2@@144"(<4 x float> %a.0, <4 x float> %a.1, <4 x float> %a.2, <4 x float> %a.3, %struct.HVA4* align 16 %b, <4 x float> %c)
+
+void __vectorcall hva3(v4f32 a, v4f32 b, v4f32 c, v4f32 d, v4f32 e, struct HVA2 f) {}
+// CHECK: define x86_vectorcallcc void @"\01hva3@@112"(<4 x float> %a, <4 x float> %b, <4 x float> %c, <4 x float> %d, <4 x float> %e, %struct.HVA2* inreg %f)
+// X64: define x86_vectorcallcc void @"\01hva3@@112"(<4 x float> %a, <4 x float> %b, <4 x float> %c, <4 x float> %d, <4 x float> %e, %struct.HVA2* align 16 %f)
+
+typedef float __attribute__((ext_vector_type(3))) v3f32;
+struct OddSizeHVA { v3f32 x, y; };
+
+void __vectorcall odd_size_hva(struct OddSizeHVA a) {}
+// CHECK: define x86_vectorcallcc void @"\01odd_size_hva@@32"(<3 x float> %a.0, <3 x float> %a.1)
+// X64: define x86_vectorcallcc void @"\01odd_size_hva@@32"(<3 x float> %a.0, <3 x float> %a.1)
diff --git a/test/CodeGen/vlt_to_pointer.c b/test/CodeGen/vlt_to_pointer.c
new file mode 100644
index 000000000000..22c620aa6429
--- /dev/null
+++ b/test/CodeGen/vlt_to_pointer.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+int c[1][3*2];
+// CHECK: @{{.+}} = {{.*}} global [1 x [6 x {{i[0-9]+}}]] zeroinitializer
+
+// CHECK-LABEL: @f
+int f(int * const m, int (**v)[*m * 2])
+{
+ return &(c[0][*m]) == &((*v)[0][*m]);
+ // CHECK: icmp
+ // CHECK: ret i{{[0-9]+}}
+}
+
+// CHECK-LABEL: @test
+int test(int n, int (*(*fn)(void))[n]) {
+ return (*fn())[0];
+}
+
+// CHECK-LABEL: @main
+int main()
+{
+ int m = 3;
+ int (*d)[3*2] = c;
+ int (*fn[m])(void);
+ return f(&m, &d) + test(m, &fn);
+
+ // CHECK: call {{.+}} @f(
+ // CHECK: ret i{{[0-9]+}}
+}
+
diff --git a/test/CodeGen/wchar-const.c b/test/CodeGen/wchar-const.c
index 34da249639ea..b461d605f6a9 100644
--- a/test/CodeGen/wchar-const.c
+++ b/test/CodeGen/wchar-const.c
@@ -7,9 +7,9 @@ typedef __WCHAR_TYPE__ wchar_t;
#if defined(_WIN32) || defined(_M_IX86) || defined(__CYGWIN__) \
|| defined(_M_X64) || defined(SHORT_WCHAR)
#define WCHAR_T_TYPE unsigned short
-#elif defined(__sun) || defined(__AuroraUX__)
+#elif defined(__sun)
#define WCHAR_T_TYPE long
-#else /* Solaris or AuroraUX. */
+#else /* Solaris. */
#define WCHAR_T_TYPE int
#endif
diff --git a/test/CodeGen/windows-struct-abi.c b/test/CodeGen/windows-struct-abi.c
new file mode 100644
index 000000000000..4b4a6f1b5db3
--- /dev/null
+++ b/test/CodeGen/windows-struct-abi.c
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -triple i686-windows-itanium -emit-llvm -o - %s | FileCheck %s
+
+struct f1 {
+ float f;
+};
+
+struct f1 return_f1(void) { while (1); }
+
+// CHECK: define i32 @return_f1()
+
+void receive_f1(struct f1 a0) { }
+
+// CHECK: define void @receive_f1(%struct.f1* byval align 4 %a0)
+
+struct f2 {
+ float f;
+ float g;
+};
+
+struct f2 return_f2(void) { while (1); }
+
+// CHECK: define i64 @return_f2()
+
+void receive_f2(struct f2 a0) { }
+
+// CHECK: define void @receive_f2(%struct.f2* byval align 4 %a0)
+
+struct f4 {
+ float f;
+ float g;
+ float h;
+ float i;
+};
+
+struct f4 return_f4(void) { while (1); }
+
+// CHECK: define void @return_f4(%struct.f4* noalias sret %agg.result)
+
+void receive_f4(struct f4 a0) { }
+
+// CHECK: define void @receive_f4(%struct.f4* byval align 4 %a0)
+
diff --git a/test/CodeGen/x86-atomic-long_double.c b/test/CodeGen/x86-atomic-long_double.c
new file mode 100644
index 000000000000..22c7bd4b89c5
--- /dev/null
+++ b/test/CodeGen/x86-atomic-long_double.c
@@ -0,0 +1,469 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -target-cpu core2 %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i686-linux-gnu -target-cpu core2 %s -S -emit-llvm -o - | FileCheck -check-prefix=CHECK32 %s
+
+long double testinc(_Atomic long double *addr) {
+ // CHECK-LABEL: @testinc
+ // CHECK: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 8
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 8
+ // CHECK: [[INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[INT_VALUE:%.+]] = load atomic i128* [[INT_ADDR]] seq_cst, align 16
+ // CHECK: [[INT_LOAD_ADDR:%.+]] = bitcast x86_fp80* [[LD_ADDR:%.+]] to i128*
+ // CHECK: store i128 [[INT_VALUE]], i128* [[INT_LOAD_ADDR]], align 16
+ // CHECK: [[LD_VALUE:%.+]] = load x86_fp80* [[LD_ADDR]], align 16
+ // CHECK: br label %[[ATOMIC_OP:.+]]
+ // CHECK: [[ATOMIC_OP]]
+ // CHECK: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK: [[INC_VALUE:%.+]] = fadd x86_fp80 [[OLD_VALUE]],
+ // CHECK: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 16
+ // CHECK: [[OLD_INT_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i128*
+ // CHECK: [[OLD_INT:%.+]] = load i128* [[OLD_INT_ADDR]], align 16
+ // CHECK: [[NEW_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[NEW_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[INC_VALUE]], x86_fp80* [[NEW_VALUE_ADDR]], align 16
+ // CHECK: [[NEW_INT_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR]] to i128*
+ // CHECK: [[NEW_INT:%.+]] = load i128* [[NEW_INT_ADDR]], align 16
+ // CHECK: [[OBJ_INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[RES:%.+]] = cmpxchg i128* [[OBJ_INT_ADDR]], i128 [[OLD_INT]], i128 [[NEW_INT]] seq_cst seq_cst
+ // CHECK: [[OLD_VALUE:%.+]] = extractvalue { i128, i1 } [[RES]], 0
+ // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1
+ // CHECK: [[OLD_VALUE_RES_INT_PTR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_RES_PTR:%.+]] to i128*
+ // CHECK: store i128 [[OLD_VALUE]], i128* [[OLD_VALUE_RES_INT_PTR]], align 16
+ // CHECK: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_RES_PTR]], align 16
+ // CHECK: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK: [[ATOMIC_CONT]]
+ // CHECK: ret x86_fp80 [[INC_VALUE]]
+ // CHECK32-LABEL: @testinc
+ // CHECK32: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 4
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 4
+ // CHECK32: [[VOID_PTR:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[TEMP_LD_PTR:%.+]] = bitcast x86_fp80* [[TEMP_LD_ADDR:%.+]] to i8*
+ // CHECK32: call void @__atomic_load(i32 12, i8* [[VOID_PTR]], i8* [[TEMP_LD_PTR]], i32 5)
+ // CHECK32: [[LD_VALUE:%.+]] = load x86_fp80* [[TEMP_LD_ADDR]], align 4
+ // CHECK32: br label %[[ATOMIC_OP:.+]]
+ // CHECK32: [[ATOMIC_OP]]
+ // CHECK32: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK32: [[INC_VALUE:%.+]] = fadd x86_fp80 [[OLD_VALUE]],
+ // CHECK32: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: [[DESIRED_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[DESIRED_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[INC_VALUE]], x86_fp80* [[DESIRED_VALUE_ADDR]], align 4
+ // CHECK32: [[OBJ:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[EXPECTED:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i8*
+ // CHECK32: [[DESIRED:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR]] to i8*
+ // CHECK32: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i32 12, i8* [[OBJ]], i8* [[EXPECTED]], i8* [[DESIRED]], i32 7, i32 7)
+ // CHECK32: [[LD_VALUE:%.+]] = load x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK32: [[ATOMIC_CONT]]
+ // CHECK32: ret x86_fp80 [[INC_VALUE]]
+
+ return ++*addr;
+}
+
+long double testdec(_Atomic long double *addr) {
+ // CHECK-LABEL: @testdec
+ // CHECK: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 8
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 8
+ // CHECK: [[INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[INT_VALUE:%.+]] = load atomic i128* [[INT_ADDR]] seq_cst, align 16
+ // CHECK: [[INT_LOAD_ADDR:%.+]] = bitcast x86_fp80* [[LD_ADDR:%.+]] to i128*
+ // CHECK: store i128 [[INT_VALUE]], i128* [[INT_LOAD_ADDR]], align 16
+ // CHECK: [[ORIG_LD_VALUE:%.+]] = load x86_fp80* [[LD_ADDR]], align 16
+ // CHECK: br label %[[ATOMIC_OP:.+]]
+ // CHECK: [[ATOMIC_OP]]
+ // CHECK: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[ORIG_LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK: [[DEC_VALUE:%.+]] = fadd x86_fp80 [[OLD_VALUE]],
+ // CHECK: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 16
+ // CHECK: [[OLD_INT_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i128*
+ // CHECK: [[OLD_INT:%.+]] = load i128* [[OLD_INT_ADDR]], align 16
+ // CHECK: [[NEW_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[NEW_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[DEC_VALUE]], x86_fp80* [[NEW_VALUE_ADDR]], align 16
+ // CHECK: [[NEW_INT_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR]] to i128*
+ // CHECK: [[NEW_INT:%.+]] = load i128* [[NEW_INT_ADDR]], align 16
+ // CHECK: [[OBJ_INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[RES:%.+]] = cmpxchg i128* [[OBJ_INT_ADDR]], i128 [[OLD_INT]], i128 [[NEW_INT]] seq_cst seq_cst
+ // CHECK: [[OLD_VALUE:%.+]] = extractvalue { i128, i1 } [[RES]], 0
+ // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1
+ // CHECK: [[OLD_VALUE_RES_INT_PTR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_RES_PTR:%.+]] to i128*
+ // CHECK: store i128 [[OLD_VALUE]], i128* [[OLD_VALUE_RES_INT_PTR]], align 16
+ // CHECK: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_RES_PTR]], align 16
+ // CHECK: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK: [[ATOMIC_CONT]]
+ // CHECK: ret x86_fp80 [[ORIG_LD_VALUE]]
+ // CHECK32-LABEL: @testdec
+ // CHECK32: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 4
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 4
+ // CHECK32: [[VOID_PTR:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[TEMP_LD_PTR:%.+]] = bitcast x86_fp80* [[TEMP_LD_ADDR:%.+]] to i8*
+ // CHECK32: call void @__atomic_load(i32 12, i8* [[VOID_PTR]], i8* [[TEMP_LD_PTR]], i32 5)
+ // CHECK32: [[ORIG_LD_VALUE:%.+]] = load x86_fp80* [[TEMP_LD_ADDR]], align 4
+ // CHECK32: br label %[[ATOMIC_OP:.+]]
+ // CHECK32: [[ATOMIC_OP]]
+ // CHECK32: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[ORIG_LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK32: [[DEC_VALUE:%.+]] = fadd x86_fp80 [[OLD_VALUE]],
+ // CHECK32: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: [[DESIRED_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[DESIRED_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[DEC_VALUE]], x86_fp80* [[DESIRED_VALUE_ADDR]], align 4
+ // CHECK32: [[OBJ:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[EXPECTED:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i8*
+ // CHECK32: [[DESIRED:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR]] to i8*
+ // CHECK32: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i32 12, i8* [[OBJ]], i8* [[EXPECTED]], i8* [[DESIRED]], i32 7, i32 7)
+ // CHECK32: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK32: [[ATOMIC_CONT]]
+ // CHECK32: ret x86_fp80 [[ORIG_LD_VALUE]]
+
+ return (*addr)--;
+}
+
+long double testcompassign(_Atomic long double *addr) {
+ *addr -= 25;
+ // CHECK-LABEL: @testcompassign
+ // CHECK: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 8
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 8
+ // CHECK: [[INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[INT_VALUE:%.+]] = load atomic i128* [[INT_ADDR]] seq_cst, align 16
+ // CHECK: [[INT_LOAD_ADDR:%.+]] = bitcast x86_fp80* [[LD_ADDR:%.+]] to i128*
+ // CHECK: store i128 [[INT_VALUE]], i128* [[INT_LOAD_ADDR]], align 16
+ // CHECK: [[LD_VALUE:%.+]] = load x86_fp80* [[LD_ADDR]], align 16
+ // CHECK: br label %[[ATOMIC_OP:.+]]
+ // CHECK: [[ATOMIC_OP]]
+ // CHECK: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK: [[SUB_VALUE:%.+]] = fsub x86_fp80 [[OLD_VALUE]],
+ // CHECK: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 16
+ // CHECK: [[OLD_INT_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i128*
+ // CHECK: [[OLD_INT:%.+]] = load i128* [[OLD_INT_ADDR]], align 16
+ // CHECK: [[NEW_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[NEW_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[SUB_VALUE]], x86_fp80* [[NEW_VALUE_ADDR]], align 16
+ // CHECK: [[NEW_INT_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR]] to i128*
+ // CHECK: [[NEW_INT:%.+]] = load i128* [[NEW_INT_ADDR]], align 16
+ // CHECK: [[OBJ_INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[RES:%.+]] = cmpxchg i128* [[OBJ_INT_ADDR]], i128 [[OLD_INT]], i128 [[NEW_INT]] seq_cst seq_cst
+ // CHECK: [[OLD_VALUE:%.+]] = extractvalue { i128, i1 } [[RES]], 0
+ // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1
+ // CHECK: [[OLD_VALUE_RES_INT_PTR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_RES_PTR:%.+]] to i128*
+ // CHECK: store i128 [[OLD_VALUE]], i128* [[OLD_VALUE_RES_INT_PTR]], align 16
+ // CHECK: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_RES_PTR]], align 16
+ // CHECK: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK: [[ATOMIC_CONT]]
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** %{{.+}}, align 8
+ // CHECK: [[ADDR_INT:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[INT_VAL:%.+]] = load atomic i128* [[ADDR_INT]] seq_cst, align 16
+ // CHECK: [[INT_LD_TEMP:%.+]] = bitcast x86_fp80* [[LD_TEMP:%.+]] to i128*
+ // CHECK: store i128 [[INT_VAL]], i128* [[INT_LD_TEMP:%.+]], align 16
+ // CHECK: [[RET_VAL:%.+]] = load x86_fp80* [[LD_TEMP]], align 16
+ // CHECK: ret x86_fp80 [[RET_VAL]]
+ // CHECK32-LABEL: @testcompassign
+ // CHECK32: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 4
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 4
+ // CHECK32: [[VOID_PTR:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[TEMP_LD_PTR:%.+]] = bitcast x86_fp80* [[TEMP_LD_ADDR:%.+]] to i8*
+ // CHECK32: call void @__atomic_load(i32 12, i8* [[VOID_PTR]], i8* [[TEMP_LD_PTR]], i32 5)
+ // CHECK32: [[LD_VALUE:%.+]] = load x86_fp80* [[TEMP_LD_ADDR]], align 4
+ // CHECK32: br label %[[ATOMIC_OP:.+]]
+ // CHECK32: [[ATOMIC_OP]]
+ // CHECK32: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK32: [[INC_VALUE:%.+]] = fsub x86_fp80 [[OLD_VALUE]],
+ // CHECK32: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: [[DESIRED_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[DESIRED_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[INC_VALUE]], x86_fp80* [[DESIRED_VALUE_ADDR]], align 4
+ // CHECK32: [[OBJ:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[EXPECTED:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i8*
+ // CHECK32: [[DESIRED:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR]] to i8*
+ // CHECK32: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i32 12, i8* [[OBJ]], i8* [[EXPECTED]], i8* [[DESIRED]], i32 7, i32 7)
+ // CHECK32: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK32: [[ATOMIC_CONT]]
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** %{{.+}}, align 4
+ // CHECK32: [[VOID_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[VOID_GET_ADDR:%.+]] = bitcast x86_fp80* [[GET_ADDR:%.+]] to i8*
+ // CHECK32: call void @__atomic_load(i32 12, i8* [[VOID_ADDR]], i8* [[VOID_GET_ADDR]], i32 5)
+ // CHECK32: [[RET_VAL:%.+]] = load x86_fp80* [[GET_ADDR]], align 4
+ // CHECK32: ret x86_fp80 [[RET_VAL]]
+ return *addr;
+}
+
+long double testassign(_Atomic long double *addr) {
+ // CHECK-LABEL: @testassign
+ // CHECK: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 8
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 8
+ // CHECK: [[STORE_TEMP_VOID_PTR:%.+]] = bitcast x86_fp80* [[STORE_TEMP_PTR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[STORE_TEMP_VOID_PTR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 {{.+}}, x86_fp80* [[STORE_TEMP_PTR]], align 16
+ // CHECK: [[STORE_TEMP_INT_PTR:%.+]] = bitcast x86_fp80* [[STORE_TEMP_PTR]] to i128*
+ // CHECK: [[STORE_TEMP_INT:%.+]] = load i128* [[STORE_TEMP_INT_PTR]], align 16
+ // CHECK: [[ADDR_INT:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: store atomic i128 [[STORE_TEMP_INT]], i128* [[ADDR_INT]] seq_cst, align 16
+ // CHECK32-LABEL: @testassign
+ // CHECK32: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 4
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 4
+ // CHECK32: [[STORE_TEMP_VOID_PTR:%.+]] = bitcast x86_fp80* [[STORE_TEMP_PTR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[STORE_TEMP_VOID_PTR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 {{.+}}, x86_fp80* [[STORE_TEMP_PTR]], align 4
+ // CHECK32: [[ADDR_VOID:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[STORE_TEMP_VOID_PTR:%.+]] = bitcast x86_fp80* [[STORE_TEMP_PTR]] to i8*
+ // CHECK32: call void @__atomic_store(i32 12, i8* [[ADDR_VOID]], i8* [[STORE_TEMP_VOID_PTR]], i32 5)
+ *addr = 115;
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** %{{.+}}, align 8
+ // CHECK: [[ADDR_INT:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[INT_VAL:%.+]] = load atomic i128* [[ADDR_INT]] seq_cst, align 16
+ // CHECK: [[INT_LD_TEMP:%.+]] = bitcast x86_fp80* [[LD_TEMP:%.+]] to i128*
+ // CHECK: store i128 [[INT_VAL]], i128* [[INT_LD_TEMP:%.+]], align 16
+ // CHECK: [[RET_VAL:%.+]] = load x86_fp80* [[LD_TEMP]], align 16
+ // CHECK: ret x86_fp80 [[RET_VAL]]
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** %{{.+}}, align 4
+ // CHECK32: [[VOID_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[VOID_LD_TEMP:%.+]] = bitcast x86_fp80* [[LD_TEMP:%.+]] to i8*
+ // CHECK32: call void @__atomic_load(i32 12, i8* [[VOID_ADDR]], i8* [[VOID_LD_TEMP]], i32 5)
+ // CHECK32: [[RET_VAL:%.+]] = load x86_fp80* [[LD_TEMP]], align 4
+ // CHECK32: ret x86_fp80 [[RET_VAL]]
+
+ return *addr;
+}
+
+long double test_volatile_inc(volatile _Atomic long double *addr) {
+ // CHECK-LABEL: @test_volatile_inc
+ // CHECK: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 8
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 8
+ // CHECK: [[INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[INT_VALUE:%.+]] = load atomic volatile i128* [[INT_ADDR]] seq_cst, align 16
+ // CHECK: [[INT_LOAD_ADDR:%.+]] = bitcast x86_fp80* [[LD_ADDR:%.+]] to i128*
+ // CHECK: store i128 [[INT_VALUE]], i128* [[INT_LOAD_ADDR]], align 16
+ // CHECK: [[LD_VALUE:%.+]] = load x86_fp80* [[LD_ADDR]], align 16
+ // CHECK: br label %[[ATOMIC_OP:.+]]
+ // CHECK: [[ATOMIC_OP]]
+ // CHECK: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK: [[INC_VALUE:%.+]] = fadd x86_fp80 [[OLD_VALUE]],
+ // CHECK: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 16
+ // CHECK: [[OLD_INT_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i128*
+ // CHECK: [[OLD_INT:%.+]] = load i128* [[OLD_INT_ADDR]], align 16
+ // CHECK: [[NEW_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[NEW_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[INC_VALUE]], x86_fp80* [[NEW_VALUE_ADDR]], align 16
+ // CHECK: [[NEW_INT_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR]] to i128*
+ // CHECK: [[NEW_INT:%.+]] = load i128* [[NEW_INT_ADDR]], align 16
+ // CHECK: [[OBJ_INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[RES:%.+]] = cmpxchg volatile i128* [[OBJ_INT_ADDR]], i128 [[OLD_INT]], i128 [[NEW_INT]] seq_cst seq_cst
+ // CHECK: [[OLD_VALUE:%.+]] = extractvalue { i128, i1 } [[RES]], 0
+ // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1
+ // CHECK: [[OLD_VALUE_RES_INT_PTR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_RES_PTR:%.+]] to i128*
+ // CHECK: store i128 [[OLD_VALUE]], i128* [[OLD_VALUE_RES_INT_PTR]], align 16
+ // CHECK: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_RES_PTR]], align 16
+ // CHECK: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK: [[ATOMIC_CONT]]
+ // CHECK: ret x86_fp80 [[INC_VALUE]]
+ // CHECK32-LABEL: @test_volatile_inc
+ // CHECK32: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 4
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 4
+ // CHECK32: [[VOID_PTR:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[TEMP_LD_PTR:%.+]] = bitcast x86_fp80* [[TEMP_LD_ADDR:%.+]] to i8*
+ // CHECK32: call void @__atomic_load(i32 12, i8* [[VOID_PTR]], i8* [[TEMP_LD_PTR]], i32 5)
+ // CHECK32: [[LD_VALUE:%.+]] = load x86_fp80* [[TEMP_LD_ADDR]], align 4
+ // CHECK32: br label %[[ATOMIC_OP:.+]]
+ // CHECK32: [[ATOMIC_OP]]
+ // CHECK32: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK32: [[INC_VALUE:%.+]] = fadd x86_fp80 [[OLD_VALUE]],
+ // CHECK32: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: [[DESIRED_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[DESIRED_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[INC_VALUE]], x86_fp80* [[DESIRED_VALUE_ADDR]], align 4
+ // CHECK32: [[OBJ:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[EXPECTED:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i8*
+ // CHECK32: [[DESIRED:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR]] to i8*
+ // CHECK32: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i32 12, i8* [[OBJ]], i8* [[EXPECTED]], i8* [[DESIRED]], i32 7, i32 7)
+ // CHECK32: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK32: [[ATOMIC_CONT]]
+ // CHECK32: ret x86_fp80 [[INC_VALUE]]
+ return ++*addr;
+}
+
+long double test_volatile_dec(volatile _Atomic long double *addr) {
+ // CHECK-LABEL: @test_volatile_dec
+ // CHECK: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 8
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 8
+ // CHECK: [[INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[INT_VALUE:%.+]] = load atomic volatile i128* [[INT_ADDR]] seq_cst, align 16
+ // CHECK: [[INT_LOAD_ADDR:%.+]] = bitcast x86_fp80* [[LD_ADDR:%.+]] to i128*
+ // CHECK: store i128 [[INT_VALUE]], i128* [[INT_LOAD_ADDR]], align 16
+ // CHECK: [[ORIG_LD_VALUE:%.+]] = load x86_fp80* [[LD_ADDR]], align 16
+ // CHECK: br label %[[ATOMIC_OP:.+]]
+ // CHECK: [[ATOMIC_OP]]
+ // CHECK: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[ORIG_LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK: [[DEC_VALUE:%.+]] = fadd x86_fp80 [[OLD_VALUE]],
+ // CHECK: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 16
+ // CHECK: [[OLD_INT_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i128*
+ // CHECK: [[OLD_INT:%.+]] = load i128* [[OLD_INT_ADDR]], align 16
+ // CHECK: [[NEW_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[NEW_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[DEC_VALUE]], x86_fp80* [[NEW_VALUE_ADDR]], align 16
+ // CHECK: [[NEW_INT_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR]] to i128*
+ // CHECK: [[NEW_INT:%.+]] = load i128* [[NEW_INT_ADDR]], align 16
+ // CHECK: [[OBJ_INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[RES:%.+]] = cmpxchg volatile i128* [[OBJ_INT_ADDR]], i128 [[OLD_INT]], i128 [[NEW_INT]] seq_cst seq_cst
+ // CHECK: [[OLD_VALUE:%.+]] = extractvalue { i128, i1 } [[RES]], 0
+ // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1
+ // CHECK: [[OLD_VALUE_RES_INT_PTR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_RES_PTR:%.+]] to i128*
+ // CHECK: store i128 [[OLD_VALUE]], i128* [[OLD_VALUE_RES_INT_PTR]], align 16
+ // CHECK: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_RES_PTR]], align 16
+ // CHECK: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK: [[ATOMIC_CONT]]
+ // CHECK: ret x86_fp80 [[ORIG_LD_VALUE]]
+ // CHECK32-LABEL: @test_volatile_dec
+ // CHECK32: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 4
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 4
+ // CHECK32: [[VOID_PTR:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[TEMP_LD_PTR:%.+]] = bitcast x86_fp80* [[TEMP_LD_ADDR:%.+]] to i8*
+ // CHECK32: call void @__atomic_load(i32 12, i8* [[VOID_PTR]], i8* [[TEMP_LD_PTR]], i32 5)
+ // CHECK32: [[ORIG_LD_VALUE:%.+]] = load x86_fp80* [[TEMP_LD_ADDR]], align 4
+ // CHECK32: br label %[[ATOMIC_OP:.+]]
+ // CHECK32: [[ATOMIC_OP]]
+ // CHECK32: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[ORIG_LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK32: [[DEC_VALUE:%.+]] = fadd x86_fp80 [[OLD_VALUE]],
+ // CHECK32: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: [[DESIRED_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[DESIRED_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[DEC_VALUE]], x86_fp80* [[DESIRED_VALUE_ADDR]], align 4
+ // CHECK32: [[OBJ:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[EXPECTED:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i8*
+ // CHECK32: [[DESIRED:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR]] to i8*
+ // CHECK32: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i32 12, i8* [[OBJ]], i8* [[EXPECTED]], i8* [[DESIRED]], i32 7, i32 7)
+ // CHECK32: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK32: [[ATOMIC_CONT]]
+ // CHECK32: ret x86_fp80 [[ORIG_LD_VALUE]]
+ return (*addr)--;
+}
+
+long double test_volatile_compassign(volatile _Atomic long double *addr) {
+ *addr -= 25;
+ // CHECK-LABEL: @test_volatile_compassign
+ // CHECK: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 8
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 8
+ // CHECK: [[INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[INT_VALUE:%.+]] = load atomic volatile i128* [[INT_ADDR]] seq_cst, align 16
+ // CHECK: [[INT_LOAD_ADDR:%.+]] = bitcast x86_fp80* [[LD_ADDR:%.+]] to i128*
+ // CHECK: store i128 [[INT_VALUE]], i128* [[INT_LOAD_ADDR]], align 16
+ // CHECK: [[LD_VALUE:%.+]] = load x86_fp80* [[LD_ADDR]], align 16
+ // CHECK: br label %[[ATOMIC_OP:.+]]
+ // CHECK: [[ATOMIC_OP]]
+ // CHECK: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK: [[SUB_VALUE:%.+]] = fsub x86_fp80 [[OLD_VALUE]],
+ // CHECK: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 16
+ // CHECK: [[OLD_INT_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i128*
+ // CHECK: [[OLD_INT:%.+]] = load i128* [[OLD_INT_ADDR]], align 16
+ // CHECK: [[NEW_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[NEW_VALUE_VOID_ADDR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 [[SUB_VALUE]], x86_fp80* [[NEW_VALUE_ADDR]], align 16
+ // CHECK: [[NEW_INT_ADDR:%.+]] = bitcast x86_fp80* [[NEW_VALUE_ADDR]] to i128*
+ // CHECK: [[NEW_INT:%.+]] = load i128* [[NEW_INT_ADDR]], align 16
+ // CHECK: [[OBJ_INT_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[RES:%.+]] = cmpxchg volatile i128* [[OBJ_INT_ADDR]], i128 [[OLD_INT]], i128 [[NEW_INT]] seq_cst seq_cst
+ // CHECK: [[OLD_VALUE:%.+]] = extractvalue { i128, i1 } [[RES]], 0
+ // CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1
+ // CHECK: [[OLD_VALUE_RES_INT_PTR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_RES_PTR:%.+]] to i128*
+ // CHECK: store i128 [[OLD_VALUE]], i128* [[OLD_VALUE_RES_INT_PTR]], align 16
+ // CHECK: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_RES_PTR]], align 16
+ // CHECK: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK: [[ATOMIC_CONT]]
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** %{{.+}}, align 8
+ // CHECK: [[ADDR_INT:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[INT_VAL:%.+]] = load atomic volatile i128* [[ADDR_INT]] seq_cst, align 16
+ // CHECK: [[INT_LD_TEMP:%.+]] = bitcast x86_fp80* [[LD_TEMP:%.+]] to i128*
+ // CHECK: store i128 [[INT_VAL]], i128* [[INT_LD_TEMP:%.+]], align 16
+ // CHECK: [[RET_VAL:%.+]] = load x86_fp80* [[LD_TEMP]], align 16
+ // CHECK32-LABEL: @test_volatile_compassign
+ // CHECK32: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 4
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 4
+ // CHECK32: [[VOID_PTR:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[TEMP_LD_PTR:%.+]] = bitcast x86_fp80* [[TEMP_LD_ADDR:%.+]] to i8*
+ // CHECK32: call void @__atomic_load(i32 12, i8* [[VOID_PTR]], i8* [[TEMP_LD_PTR]], i32 5)
+ // CHECK32: [[LD_VALUE:%.+]] = load x86_fp80* [[TEMP_LD_ADDR]], align 4
+ // CHECK32: br label %[[ATOMIC_OP:.+]]
+ // CHECK32: [[ATOMIC_OP]]
+ // CHECK32: [[OLD_VALUE:%.+]] = phi x86_fp80 [ [[LD_VALUE]], %{{.+}} ], [ [[LD_VALUE:%.+]], %[[ATOMIC_OP]] ]
+ // CHECK32: [[INC_VALUE:%.+]] = fsub x86_fp80 [[OLD_VALUE]],
+ // CHECK32: [[OLD_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[OLD_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[OLD_VALUE]], x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: [[DESIRED_VALUE_VOID_ADDR:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[DESIRED_VALUE_VOID_ADDR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 [[INC_VALUE]], x86_fp80* [[DESIRED_VALUE_ADDR]], align 4
+ // CHECK32: [[OBJ:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[EXPECTED:%.+]] = bitcast x86_fp80* [[OLD_VALUE_ADDR]] to i8*
+ // CHECK32: [[DESIRED:%.+]] = bitcast x86_fp80* [[DESIRED_VALUE_ADDR]] to i8*
+ // CHECK32: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i32 12, i8* [[OBJ]], i8* [[EXPECTED]], i8* [[DESIRED]], i32 7, i32 7)
+ // CHECK32: [[LD_VALUE]] = load x86_fp80* [[OLD_VALUE_ADDR]], align 4
+ // CHECK32: br i1 [[FAIL_SUCCESS]], label %[[ATOMIC_CONT:.+]], label %[[ATOMIC_OP]]
+ // CHECK32: [[ATOMIC_CONT]]
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** %{{.+}}, align 4
+ // CHECK32: [[VOID_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[VOID_GET_ADDR:%.+]] = bitcast x86_fp80* [[GET_ADDR:%.+]] to i8*
+ // CHECK32: call void @__atomic_load(i32 12, i8* [[VOID_ADDR]], i8* [[VOID_GET_ADDR]], i32 5)
+ // CHECK32: [[RET_VAL:%.+]] = load x86_fp80* [[GET_ADDR]], align 4
+ // CHECK32: ret x86_fp80 [[RET_VAL]]
+ return *addr;
+}
+
+long double test_volatile_assign(volatile _Atomic long double *addr) {
+ // CHECK-LABEL: @test_volatile_assign
+ // CHECK: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 8
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 8
+ // CHECK: [[STORE_TEMP_VOID_PTR:%.+]] = bitcast x86_fp80* [[STORE_TEMP_PTR:%.+]] to i8*
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[STORE_TEMP_VOID_PTR]], i8 0, i64 16, i32 16, i1 false)
+ // CHECK: store x86_fp80 {{.+}}, x86_fp80* [[STORE_TEMP_PTR]], align 16
+ // CHECK: [[STORE_TEMP_INT_PTR:%.+]] = bitcast x86_fp80* [[STORE_TEMP_PTR]] to i128*
+ // CHECK: [[STORE_TEMP_INT:%.+]] = load i128* [[STORE_TEMP_INT_PTR]], align 16
+ // CHECK: [[ADDR_INT:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: store atomic volatile i128 [[STORE_TEMP_INT]], i128* [[ADDR_INT]] seq_cst, align 16
+ // CHECK32-LABEL: @test_volatile_assign
+ // CHECK32: store x86_fp80* %{{.+}}, x86_fp80** [[ADDR_ADDR:%.+]], align 4
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** [[ADDR_ADDR]], align 4
+ // CHECK32: [[STORE_TEMP_VOID_PTR:%.+]] = bitcast x86_fp80* [[STORE_TEMP_PTR:%.+]] to i8*
+ // CHECK32: call void @llvm.memset.p0i8.i64(i8* [[STORE_TEMP_VOID_PTR]], i8 0, i64 12, i32 4, i1 false)
+ // CHECK32: store x86_fp80 {{.+}}, x86_fp80* [[STORE_TEMP_PTR]], align 4
+ // CHECK32: [[ADDR_VOID:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[STORE_TEMP_VOID_PTR:%.+]] = bitcast x86_fp80* [[STORE_TEMP_PTR]] to i8*
+ // CHECK32: call void @__atomic_store(i32 12, i8* [[ADDR_VOID]], i8* [[STORE_TEMP_VOID_PTR]], i32 5)
+ *addr = 115;
+ // CHECK: [[ADDR:%.+]] = load x86_fp80** %{{.+}}, align 8
+ // CHECK: [[ADDR_INT:%.+]] = bitcast x86_fp80* [[ADDR]] to i128*
+ // CHECK: [[INT_VAL:%.+]] = load atomic volatile i128* [[ADDR_INT]] seq_cst, align 16
+ // CHECK: [[INT_LD_TEMP:%.+]] = bitcast x86_fp80* [[LD_TEMP:%.+]] to i128*
+ // CHECK: store i128 [[INT_VAL]], i128* [[INT_LD_TEMP:%.+]], align 16
+ // CHECK: [[RET_VAL:%.+]] = load x86_fp80* [[LD_TEMP]], align 16
+ // CHECK: ret x86_fp80 [[RET_VAL]]
+ // CHECK32: [[ADDR:%.+]] = load x86_fp80** %{{.+}}, align 4
+ // CHECK32: [[VOID_ADDR:%.+]] = bitcast x86_fp80* [[ADDR]] to i8*
+ // CHECK32: [[VOID_LD_TEMP:%.+]] = bitcast x86_fp80* [[LD_TEMP:%.+]] to i8*
+ // CHECK32: call void @__atomic_load(i32 12, i8* [[VOID_ADDR]], i8* [[VOID_LD_TEMP]], i32 5)
+ // CHECK32: [[RET_VAL:%.+]] = load x86_fp80* [[LD_TEMP]], align 4
+ // CHECK32: ret x86_fp80 [[RET_VAL]]
+
+ return *addr;
+}
diff --git a/test/CodeGen/x86_32-inline-asm.c b/test/CodeGen/x86_32-inline-asm.c
index 473f78ebcae6..c1fba0eee942 100644
--- a/test/CodeGen/x86_32-inline-asm.c
+++ b/test/CodeGen/x86_32-inline-asm.c
@@ -1,5 +1,9 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -target-feature +avx -verify %s
+
// <rdar://problem/12415959>
+// rdar://problem/11846140
+// rdar://problem/17476970
typedef unsigned int u_int32_t;
typedef u_int32_t uint32_t;
@@ -7,6 +11,14 @@ typedef u_int32_t uint32_t;
typedef unsigned long long u_int64_t;
typedef u_int64_t uint64_t;
+typedef float __m128 __attribute__ ((vector_size (16)));
+typedef float __m256 __attribute__ ((vector_size (32)));
+typedef float __m512 __attribute__ ((vector_size (64)));
+
+__m128 val128;
+__m256 val256;
+__m512 val512;
+
int func1() {
// Error out if size is > 32-bits.
uint32_t msr = 0x8b;
@@ -21,4 +33,40 @@ int func1() {
unsigned char data;
unsigned int port;
__asm__ volatile("outb %0, %w1" : : "a" (data), "Nd" (port)); // No error expected.
+
+ __asm__ volatile("outb %0, %w1" : : "R" (val), "Nd" (port)); // expected-error {{invalid input size for constraint 'R'}}
+ __asm__ volatile("outb %0, %w1" : : "q" (val), "Nd" (port)); // expected-error {{invalid input size for constraint 'q'}}
+ __asm__ volatile("outb %0, %w1" : : "Q" (val), "Nd" (port)); // expected-error {{invalid input size for constraint 'Q'}}
+ __asm__ volatile("outb %0, %w1" : : "b" (val), "Nd" (port)); // expected-error {{invalid input size for constraint 'b'}}
+ __asm__ volatile("outb %0, %w1" : : "c" (val), "Nd" (port)); // expected-error {{invalid input size for constraint 'c'}}
+ __asm__ volatile("outb %0, %w1" : : "d" (val), "Nd" (port)); // expected-error {{invalid input size for constraint 'd'}}
+ __asm__ volatile("outb %0, %w1" : : "S" (val), "Nd" (port)); // expected-error {{invalid input size for constraint 'S'}}
+ __asm__ volatile("outb %0, %w1" : : "D" (val), "Nd" (port)); // expected-error {{invalid input size for constraint 'D'}}
+ __asm__ volatile("foo1 %0" : : "A" (val128)); // expected-error {{invalid input size for constraint 'A'}}
+ __asm__ volatile("foo1 %0" : : "f" (val256)); // expected-error {{invalid input size for constraint 'f'}}
+ __asm__ volatile("foo1 %0" : : "t" (val256)); // expected-error {{invalid input size for constraint 't'}}
+ __asm__ volatile("foo1 %0" : : "u" (val256)); // expected-error {{invalid input size for constraint 'u'}}
+ __asm__ volatile("foo1 %0" : : "x" (val512)); // expected-error {{invalid input size for constraint 'x'}}
+
+ __asm__ volatile("foo1 %0" : "=R" (val)); // expected-error {{invalid output size for constraint '=R'}}
+ __asm__ volatile("foo1 %0" : "=q" (val)); // expected-error {{invalid output size for constraint '=q'}}
+ __asm__ volatile("foo1 %0" : "=Q" (val)); // expected-error {{invalid output size for constraint '=Q'}}
+ __asm__ volatile("foo1 %0" : "=a" (val)); // expected-error {{invalid output size for constraint '=a'}}
+ __asm__ volatile("foo1 %0" : "=b" (val)); // expected-error {{invalid output size for constraint '=b'}}
+ __asm__ volatile("foo1 %0" : "=c" (val)); // expected-error {{invalid output size for constraint '=c'}}
+ __asm__ volatile("foo1 %0" : "=d" (val)); // expected-error {{invalid output size for constraint '=d'}}
+ __asm__ volatile("foo1 %0" : "=S" (val)); // expected-error {{invalid output size for constraint '=S'}}
+ __asm__ volatile("foo1 %0" : "=D" (val)); // expected-error {{invalid output size for constraint '=D'}}
+ __asm__ volatile("foo1 %0" : "=A" (val128)); // expected-error {{invalid output size for constraint '=A'}}
+ __asm__ volatile("foo1 %0" : "=t" (val256)); // expected-error {{invalid output size for constraint '=t'}}
+ __asm__ volatile("foo1 %0" : "=u" (val256)); // expected-error {{invalid output size for constraint '=u'}}
+ __asm__ volatile("foo1 %0" : "=x" (val512)); // expected-error {{invalid output size for constraint '=x'}}
+
+#ifdef __AVX__
+ __asm__ volatile("foo1 %0" : : "x" (val256)); // No error.
+ __asm__ volatile("foo1 %0" : "=x" (val256)); // No error.
+#else
+ __asm__ volatile("foo1 %0" : : "x" (val256)); // expected-error {{invalid input size for constraint 'x'}}
+ __asm__ volatile("foo1 %0" : "=x" (val256)); // expected-error {{invalid output size for constraint '=x'}}
+#endif
}
diff --git a/test/CodeGen/x86_64-arguments-win32.c b/test/CodeGen/x86_64-arguments-win32.c
new file mode 100644
index 000000000000..5aea7fc62368
--- /dev/null
+++ b/test/CodeGen/x86_64-arguments-win32.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -w -triple x86_64-pc-win32 -emit-llvm -o - %s | FileCheck %s
+
+// To be ABI compatible with code generated by MSVC, there shouldn't be any
+// sign/zero extensions on types smaller than 64bit.
+
+// CHECK-LABEL: define void @f1(i8 %a)
+void f1(char a) {}
+
+// CHECK-LABEL: define void @f2(i8 %a)
+void f2(unsigned char a) {}
+
+// CHECK-LABEL: define void @f3(i16 %a)
+void f3(short a) {}
+
+// CHECK-LABEL: define void @f4(i16 %a)
+void f4(unsigned short a) {}
diff --git a/test/CodeGen/xcore-stringtype.c b/test/CodeGen/xcore-stringtype.c
index 25589d5b2b21..1297ca0bb733 100644
--- a/test/CodeGen/xcore-stringtype.c
+++ b/test/CodeGen/xcore-stringtype.c
@@ -5,19 +5,27 @@
// In the tests below, some types are not supported by the ABI (_Complex,
// variable length arrays) and will thus emit no meta data.
-// The 33 tests that do emit typestrings are gathered into '!xcore.typestrings'
+// The 38 tests that do emit typestrings are gathered into '!xcore.typestrings'
// Please see 'Tools Development Guide' section 2.16.2 for format details:
// <https://www.xmos.com/download/public/Tools-Development-Guide%28X9114A%29.pdf>
-// CHECK: !xcore.typestrings = !{!1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11,
-// CHECK: !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25,
-// CHECK: !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !38}
+// CHECK: !xcore.typestrings = !{
+// CHECK: !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}},
+// CHECK: !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}},
+// CHECK: !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}},
+// CHECK: !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}},
+// CHECK: !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}},
+// CHECK: !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}},
+// CHECK: !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}},
+// CHECK: !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}
+// CHECK-NOT: , !{{[0-9]+}}
+// CHECK: }
// test BuiltinType
-// CHECK: !1 = metadata !{void (i1, i8, i8, i8, i16, i16, i16, i32, i32, i32,
+// CHECK: !{{[0-9]+}} = !{void (i1, i8, i8, i8, i16, i16, i16, i32, i32, i32,
// CHECK: i32, i32, i32, i64, i64, i64, float, double, double)*
-// CHECK: @builtinType, metadata !"f{0}(b,uc,uc,sc,ss,us,ss,si,ui,si,sl,
+// CHECK: @builtinType, !"f{0}(b,uc,uc,sc,ss,us,ss,si,ui,si,sl,
// CHECK: ul,sl,sll,ull,sll,ft,d,ld)"}
void builtinType(_Bool B, char C, unsigned char UC, signed char SC, short S,
unsigned short US, signed short SS, int I, unsigned int UI,
@@ -28,14 +36,14 @@ double _Complex Complex; // not supported
// test FunctionType & Qualifiers
-// CHECK: !2 = metadata !{void ()* @gI, metadata !"f{0}()"}
-// CHECK: !3 = metadata !{void (...)* @eI, metadata !"f{0}()"}
-// CHECK: !4 = metadata !{void ()* @gV, metadata !"f{0}(0)"}
-// CHECK: !5 = metadata !{void ()* @eV, metadata !"f{0}(0)"}
-// CHECK: !6 = metadata !{void (i32, ...)* @gVA, metadata !"f{0}(si,va)"}
-// CHECK: !7 = metadata !{void (i32, ...)* @eVA, metadata !"f{0}(si,va)"}
-// CHECK: !8 = metadata !{i32* (i32*)* @gQ, metadata !"f{crv:p(cv:si)}(p(cv:si))"}
-// CHECK: !9 = metadata !{i32* (i32*)* @eQ, metadata !"f{crv:p(cv:si)}(p(cv:si))"}
+// CHECK: !{{[0-9]+}} = !{void ()* @gI, !"f{0}()"}
+// CHECK: !{{[0-9]+}} = !{void (...)* @eI, !"f{0}()"}
+// CHECK: !{{[0-9]+}} = !{void ()* @gV, !"f{0}(0)"}
+// CHECK: !{{[0-9]+}} = !{void ()* @eV, !"f{0}(0)"}
+// CHECK: !{{[0-9]+}} = !{void (i32, ...)* @gVA, !"f{0}(si,va)"}
+// CHECK: !{{[0-9]+}} = !{void (i32, ...)* @eVA, !"f{0}(si,va)"}
+// CHECK: !{{[0-9]+}} = !{i32* (i32*)* @gQ, !"f{crv:p(cv:si)}(p(cv:si))"}
+// CHECK: !{{[0-9]+}} = !{i32* (i32*)* @eQ, !"f{crv:p(cv:si)}(p(cv:si))"}
extern void eI();
void gI() {eI();};
extern void eV(void);
@@ -49,10 +57,10 @@ const volatile int* volatile restrict const
// test PointerType
-// CHECK: !10 = metadata !{i32* (i32*, i32* (i32*)*)*
-// CHECK: @pointerType, metadata !"f{p(si)}(p(si),p(f{p(si)}(p(si))))"}
-// CHECK: !11 = metadata !{i32** @EP, metadata !"p(si)"}
-// CHECK: !12 = metadata !{i32** @GP, metadata !"p(si)"}
+// CHECK: !{{[0-9]+}} = !{i32* (i32*, i32* (i32*)*)*
+// CHECK: @pointerType, !"f{p(si)}(p(si),p(f{p(si)}(p(si))))"}
+// CHECK: !{{[0-9]+}} = !{i32** @EP, !"p(si)"}
+// CHECK: !{{[0-9]+}} = !{i32** @GP, !"p(si)"}
extern int* EP;
int* GP;
int* pointerType(int *I, int * (*FP)(int *)) {
@@ -60,19 +68,19 @@ int* pointerType(int *I, int * (*FP)(int *)) {
}
// test ArrayType
-// CHECK: !13 = metadata !{[2 x i32]* (i32*, i32*, [2 x i32]*, [2 x i32]*, i32*)*
-// CHECK: @arrayType, metadata !"f{p(a(2:si))}(p(si),p(cv:si),p(a(2:si)),
+// CHECK: !{{[0-9]+}} = !{[2 x i32]* (i32*, i32*, [2 x i32]*, [2 x i32]*, i32*)*
+// CHECK: @arrayType, !"f{p(a(2:si))}(p(si),p(cv:si),p(a(2:si)),
// CHECK: p(a(2:si)),p(si))"}
-// CHECK: !14 = metadata !{[0 x i32]* @EA1, metadata !"a(*:cv:si)"}
-// CHECK: !15 = metadata !{[2 x i32]* @EA2, metadata !"a(2:si)"}
-// CHECK: !16 = metadata !{[0 x [2 x i32]]* @EA3, metadata !"a(*:a(2:si))"}
-// CHECK: !17 = metadata !{[3 x [2 x i32]]* @EA4, metadata !"a(3:a(2:si))"}
-// CHECK: !18 = metadata !{[2 x i32]* @GA1, metadata !"a(2:cv:si)"}
-// CHECK: !19 = metadata !{void ([2 x i32]*)* @arrayTypeVariable1,
-// CHECK: metadata !"f{0}(p(a(2:si)))"}
-// CHECK: !20 = metadata !{void (void ([2 x i32]*)*)* @arrayTypeVariable2,
-// CHECK: metadata !"f{0}(p(f{0}(p(a(2:si)))))"}
-// CHECK: !21 = metadata !{[3 x [2 x i32]]* @GA2, metadata !"a(3:a(2:si))"}
+// CHECK: !{{[0-9]+}} = !{[0 x i32]* @EA1, !"a(*:cv:si)"}
+// CHECK: !{{[0-9]+}} = !{[2 x i32]* @EA2, !"a(2:si)"}
+// CHECK: !{{[0-9]+}} = !{[0 x [2 x i32]]* @EA3, !"a(*:a(2:si))"}
+// CHECK: !{{[0-9]+}} = !{[3 x [2 x i32]]* @EA4, !"a(3:a(2:si))"}
+// CHECK: !{{[0-9]+}} = !{[2 x i32]* @GA1, !"a(2:cv:si)"}
+// CHECK: !{{[0-9]+}} = !{void ([2 x i32]*)* @arrayTypeVariable1,
+// CHECK: !"f{0}(p(a(2:si)))"}
+// CHECK: !{{[0-9]+}} = !{void (void ([2 x i32]*)*)* @arrayTypeVariable2,
+// CHECK: !"f{0}(p(f{0}(p(a(2:si)))))"}
+// CHECK: !{{[0-9]+}} = !{[3 x [2 x i32]]* @GA2, !"a(3:a(2:si))"}
extern int GA2[3][2];
extern const volatile int EA1[];
extern int EA2[2];
@@ -100,16 +108,16 @@ RetType* arrayType(int A1[], int const volatile A2[2], int A3[][2],
// test StructureType
-// CHECK: !22 = metadata !{void (%struct.S1*)* @structureType1, metadata
+// CHECK: !{{[0-9]+}} = !{void (%struct.S1*)* @structureType1,
// CHECK: !"f{0}(s(S1){m(ps2){p(s(S2){m(ps3){p(s(S3){m(s1){s(S1){}}})}})}})"}
-// CHECK: !23 = metadata !{void (%struct.S2*)* @structureType2, metadata
+// CHECK: !{{[0-9]+}} = !{void (%struct.S2*)* @structureType2,
// CHECK: !"f{0}(s(S2){m(ps3){p(s(S3){m(s1){s(S1){m(ps2){p(s(S2){})}}}})}})"}
-// CHECK: !24 = metadata !{void (%struct.S3*)* @structureType3, metadata
+// CHECK: !{{[0-9]+}} = !{void (%struct.S3*)* @structureType3,
// CHECK: !"f{0}(s(S3){m(s1){s(S1){m(ps2){p(s(S2){m(ps3){p(s(S3){})}})}}}})"}
-// CHECK: !25 = metadata !{void (%struct.S4*)* @structureType4, metadata
+// CHECK: !{{[0-9]+}} = !{void (%struct.S4*)* @structureType4,
// CHECK: !"f{0}(s(S4){m(s1){s(S1){m(ps2){p(s(S2){m(ps3){p(s(S3){m(s1){s(S1){}}})}})}}}})"}
-// CHECK: !26 = metadata !{%struct.anon* @StructAnon, metadata !"s(){m(A){si}}"}
-// CHECK: !27 = metadata !{i32 (%struct.SB*)* @structureTypeB, metadata
+// CHECK: !{{[0-9]+}} = !{%struct.anon* @StructAnon, !"s(){m(A){si}}"}
+// CHECK: !{{[0-9]+}} = !{i32 (%struct.SB*)* @structureTypeB,
// CHECK: !"f{si}(s(SB){m(){b(4:si)},m(){b(2:si)},m(N4){b(4:si)},
// CHECK: m(N2){b(2:si)},m(){b(4:ui)},m(){b(4:si)},m(){b(4:c:si)},
// CHECK: m(){b(4:c:si)},m(){b(4:cv:si)}})"}
@@ -130,16 +138,16 @@ int structureTypeB(struct SB sb){return StructAnon.A;}
// test UnionType
-// CHECK: !28 = metadata !{void (%union.U1*)* @unionType1, metadata
+// CHECK: !{{[0-9]+}} = !{void (%union.U1*)* @unionType1,
// CHECK: !"f{0}(u(U1){m(pu2){p(u(U2){m(pu3){p(u(U3){m(u1){u(U1){}}})}})}})"}
-// CHECK: !29 = metadata !{void (%union.U2*)* @unionType2, metadata
+// CHECK: !{{[0-9]+}} = !{void (%union.U2*)* @unionType2,
// CHECK: !"f{0}(u(U2){m(pu3){p(u(U3){m(u1){u(U1){m(pu2){p(u(U2){})}}}})}})"}
-// CHECK: !30 = metadata !{void (%union.U3*)* @unionType3, metadata
+// CHECK: !{{[0-9]+}} = !{void (%union.U3*)* @unionType3,
// CHECK: !"f{0}(u(U3){m(u1){u(U1){m(pu2){p(u(U2){m(pu3){p(u(U3){})}})}}}})"}
-// CHECK: !31 = metadata !{void (%union.U4*)* @unionType4, metadata
+// CHECK: !{{[0-9]+}} = !{void (%union.U4*)* @unionType4,
// CHECK: !"f{0}(u(U4){m(u1){u(U1){m(pu2){p(u(U2){m(pu3){p(u(U3){m(u1){u(U1){}}})}})}}}})"}
-// CHECK: !32 = metadata !{%union.anon* @UnionAnon, metadata !"u(){m(A){si}}"}
-// CHECK: !33 = metadata !{i32 (%union.UB*)* @unionTypeB, metadata
+// CHECK: !{{[0-9]+}} = !{%union.anon* @UnionAnon, !"u(){m(A){si}}"}
+// CHECK: !{{[0-9]+}} = !{i32 (%union.UB*)* @unionTypeB,
// CHECK: !"f{si}(u(UB){m(N2){b(2:si)},m(N4){b(4:si)},m(){b(2:si)},
// CHECK: m(){b(4:c:si)},m(){b(4:c:si)},m(){b(4:cv:si)},m(){b(4:si)},
// CHECK: m(){b(4:si)},m(){b(4:ui)}})"}
@@ -160,17 +168,17 @@ int unionTypeB(union UB ub) {return UnionAnon.A;}
// test EnumType
-// CHECK: !34 = metadata !{i32* @EnumAnon, metadata !"e(){m(EA){3}}"}
-// CHECK: !35 = metadata !{i32 (i32)* @enumType, metadata
+// CHECK: !{{[0-9]+}} = !{i32* @EnumAnon, !"e(){m(EA){3}}"}
+// CHECK: !{{[0-9]+}} = !{i32 (i32)* @enumType,
// CHECK: !"f{si}(e(E){m(A){7},m(B){6},m(C){5},m(D){0}})"}
enum E {D, C=5, B, A};
enum {EA=3} EnumAnon = EA;
int enumType(enum E e) {return EnumAnon;}
-// CHECK: !36 = metadata !{i32 ()* @testReDecl, metadata !"f{si}()"}
-// CHECK: !37 = metadata !{[10 x i32]* @After, metadata !"a(10:si)"}
-// CHECK: !38 = metadata !{[10 x i32]* @Before, metadata !"a(10:si)"}
+// CHECK: !{{[0-9]+}} = !{i32 ()* @testReDecl, !"f{si}()"}
+// CHECK: !{{[0-9]+}} = !{[10 x i32]* @After, !"a(10:si)"}
+// CHECK: !{{[0-9]+}} = !{[10 x i32]* @Before, !"a(10:si)"}
extern int After[];
extern int Before[10];
int testReDecl() {return After[0] + Before[0];}
diff --git a/test/CodeGenCUDA/launch-bounds.cu b/test/CodeGenCUDA/launch-bounds.cu
index ed4c2bfc8870..6f4102ea0076 100644
--- a/test/CodeGenCUDA/launch-bounds.cu
+++ b/test/CodeGenCUDA/launch-bounds.cu
@@ -14,8 +14,8 @@ Kernel1()
}
}
-// CHECK: !{{[0-9]+}} = metadata !{void ()* @Kernel1, metadata !"maxntidx", i32 256}
-// CHECK: !{{[0-9]+}} = metadata !{void ()* @Kernel1, metadata !"minctasm", i32 2}
+// CHECK: !{{[0-9]+}} = !{void ()* @Kernel1, !"maxntidx", i32 256}
+// CHECK: !{{[0-9]+}} = !{void ()* @Kernel1, !"minctasm", i32 2}
// Test only max threads per block. Min cta per sm defaults to 0, and
// CodeGen doesn't output a zero value for minctasm.
@@ -27,4 +27,4 @@ Kernel2()
}
}
-// CHECK: !{{[0-9]+}} = metadata !{void ()* @Kernel2, metadata !"maxntidx", i32 256}
+// CHECK: !{{[0-9]+}} = !{void ()* @Kernel2, !"maxntidx", i32 256}
diff --git a/test/CodeGenCUDA/ptx-kernels.cu b/test/CodeGenCUDA/ptx-kernels.cu
index 11b92b587606..658b3488fc18 100644
--- a/test/CodeGenCUDA/ptx-kernels.cu
+++ b/test/CodeGenCUDA/ptx-kernels.cu
@@ -13,4 +13,4 @@ __global__ void global_function() {
device_function();
}
-// CHECK: !{{[0-9]+}} = metadata !{void ()* @global_function, metadata !"kernel", i32 1}
+// CHECK: !{{[0-9]+}} = !{void ()* @global_function, !"kernel", i32 1}
diff --git a/test/CodeGenCXX/2010-07-23-DeclLoc.cpp b/test/CodeGenCXX/2010-07-23-DeclLoc.cpp
index 4c689029b8a8..56c364cb485f 100644
--- a/test/CodeGenCXX/2010-07-23-DeclLoc.cpp
+++ b/test/CodeGenCXX/2010-07-23-DeclLoc.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s
// Require the template function declaration refer to the correct filename.
// First, locate the function decl in metadata, and pluck out the file handle:
-// CHECK: metadata [[filehandle:![0-9]+]], {{[^,]*}}, {{.*extract_dwarf_data_from_header.*extract_dwarf_data_from_header.*extract_dwarf_data_from_header.*[^ ]+", }}
+// CHECK: !"0x2e\00extract_dwarf_data_from_header{{[^"]+}}", [[filehandle:![0-9]+]]
// Second: Require that filehandle refer to the correct filename:
// CHECK: [[filehandle]] = {{.*}}decl_should_be_here.hpp"
typedef long unsigned int __darwin_size_t;
diff --git a/test/CodeGenCXX/PR20038.cpp b/test/CodeGenCXX/PR20038.cpp
index c24685d696b6..0936dfc64904 100644
--- a/test/CodeGenCXX/PR20038.cpp
+++ b/test/CodeGenCXX/PR20038.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple %itanium_abi_triple -g -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -g -mllvm -no-discriminators -emit-llvm %s -o - | FileCheck %s
struct C {
~C();
@@ -8,9 +8,7 @@ extern bool b;
// CHECK: call {{.*}}, !dbg [[DTOR_CALL2_LOC:![0-9]*]]
// CHECK: [[FUN1:.*]] = {{.*}}; [ DW_TAG_subprogram ] {{.*}} [def] [fun1]
// CHECK: [[FUN2:.*]] = {{.*}}; [ DW_TAG_subprogram ] {{.*}} [def] [fun2]
-// CHECK: [[DTOR_CALL1_LOC]] = metadata !{i32 [[@LINE+2]], i32 0, metadata [[FUN1_BLOCK:.*]], null}
-// CHECK: [[FUN1_BLOCK]] = metadata !{{{[^,]*}}, {{[^,]*}}, metadata [[FUN1]],
+// CHECK: [[DTOR_CALL1_LOC]] = !MDLocation(line: [[@LINE+1]], scope: [[FUN1]])
void fun1() { b && (C(), 1); }
-// CHECK: [[DTOR_CALL2_LOC]] = metadata !{i32 [[@LINE+2]], i32 0, metadata [[FUN2_BLOCK1:.*]], null}
-// CHECK: [[FUN2_BLOCK1]] = metadata !{{{[^,]*}}, {{[^,]*}}, metadata [[FUN2]],
+// CHECK: [[DTOR_CALL2_LOC]] = !MDLocation(line: [[@LINE+1]], scope: [[FUN2]])
bool fun2() { return (C(), b) && 0; }
diff --git a/test/CodeGenCXX/align-avx-complete-objects.cpp b/test/CodeGenCXX/align-avx-complete-objects.cpp
new file mode 100644
index 000000000000..25f4ef1099ac
--- /dev/null
+++ b/test/CodeGenCXX/align-avx-complete-objects.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -x c++ %s -O0 -triple=x86_64-apple-darwin -target-feature +avx2 -fmax-type-align=16 -emit-llvm -o - -Werror | FileCheck %s
+// rdar://16254558
+
+typedef float AVX2Float __attribute__((__vector_size__(32)));
+
+
+volatile float TestAlign(void)
+{
+ volatile AVX2Float *p = new AVX2Float;
+ *p = *p;
+ AVX2Float r = *p;
+ return r[0];
+}
+
+// CHECK: [[R:%.*]] = alloca <8 x float>, align 32
+// CHECK-NEXT: [[CALL:%.*]] = call noalias i8* @_Znwm(i64 32)
+// CHECK-NEXT: [[ZERO:%.*]] = bitcast i8* [[CALL]] to <8 x float>*
+// CHECK-NEXT: store <8 x float>* [[ZERO]], <8 x float>** [[P:%.*]], align 8
+// CHECK-NEXT: [[ONE:%.*]] = load <8 x float>** [[P]], align 8
+// CHECK-NEXT: [[TWO:%.*]] = load volatile <8 x float>* [[ONE]], align 16
+// CHECK-NEXT: [[THREE:%.*]] = load <8 x float>** [[P]], align 8
+// CHECK-NEXT: store volatile <8 x float> [[TWO]], <8 x float>* [[THREE]], align 16
+// CHECK-NEXT: [[FOUR:%.*]] = load <8 x float>** [[P]], align 8
+// CHECK-NEXT: [[FIVE:%.*]] = load volatile <8 x float>* [[FOUR]], align 16
+// CHECK-NEXT: store <8 x float> [[FIVE]], <8 x float>* [[R]], align 32
+// CHECK-NEXT: [[SIX:%.*]] = load <8 x float>* [[R]], align 32
+// CHECK-NEXT: [[VECEXT:%.*]] = extractelement <8 x float> [[SIX]], i32 0
+// CHECK-NEXT: ret float [[VECEXT]]
+
+typedef float AVX2Float_Explicitly_aligned __attribute__((__vector_size__(32))) __attribute__((aligned (32)));
+
+typedef AVX2Float_Explicitly_aligned AVX2Float_indirect;
+
+typedef AVX2Float_indirect AVX2Float_use_existing_align;
+
+volatile float TestAlign2(void)
+{
+ volatile AVX2Float_use_existing_align *p = new AVX2Float_use_existing_align;
+ *p = *p;
+ AVX2Float_use_existing_align r = *p;
+ return r[0];
+}
+
+// CHECK: [[R:%.*]] = alloca <8 x float>, align 32
+// CHECK-NEXT: [[CALL:%.*]] = call noalias i8* @_Znwm(i64 32)
+// CHECK-NEXT: [[ZERO:%.*]] = bitcast i8* [[CALL]] to <8 x float>*
+// CHECK-NEXT: store <8 x float>* [[ZERO]], <8 x float>** [[P:%.*]], align 8
+// CHECK-NEXT: [[ONE:%.*]] = load <8 x float>** [[P]], align 8
+// CHECK-NEXT: [[TWO:%.*]] = load volatile <8 x float>* [[ONE]], align 32
+// CHECK-NEXT: [[THREE:%.*]] = load <8 x float>** [[P]], align 8
+// CHECK-NEXT: store volatile <8 x float> [[TWO]], <8 x float>* [[THREE]], align 32
+// CHECK-NEXT: [[FOUR:%.*]] = load <8 x float>** [[P]], align 8
+// CHECK-NEXT: [[FIVE:%.*]] = load volatile <8 x float>* [[FOUR]], align 32
+// CHECK-NEXT: store <8 x float> [[FIVE]], <8 x float>* [[R]], align 32
+// CHECK-NEXT: [[SIX:%.*]] = load <8 x float>* [[R]], align 32
+// CHECK-NEXT: [[VECEXT:%.*]] = extractelement <8 x float> [[SIX]], i32 0
+// CHECK-NEXT: ret float [[VECEXT]]
diff --git a/test/CodeGenCXX/atomicinit.cpp b/test/CodeGenCXX/atomicinit.cpp
index f453194468dd..982396e177ab 100644
--- a/test/CodeGenCXX/atomicinit.cpp
+++ b/test/CodeGenCXX/atomicinit.cpp
@@ -1,9 +1,13 @@
// RUN: %clang_cc1 %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 -std=c++11 | FileCheck %s
-// CHECK-DAG: @_ZN7PR180978constant1aE = global {{.*}} { i16 1, i8 6, i8 undef }, align 4
-// CHECK-DAG: @_ZN7PR180978constant1bE = global {{.*}} { i16 2, i8 6, i8 undef }, align 4
-// CHECK-DAG: @_ZN7PR180978constant1cE = global {{.*}} { i16 3, i8 6, i8 undef }, align 4
-// CHECK-DAG: @_ZN7PR180978constant1yE = global {{.*}} { {{.*}} { i16 4, i8 6, i8 undef }, i32 5 }, align 4
+// CHECK-DAG: @PR22043 = global i32 0, align 4
+typedef _Atomic(int) AtomicInt;
+AtomicInt PR22043 = AtomicInt();
+
+// CHECK-DAG: @_ZN7PR180978constant1aE = global { i16, i8 } { i16 1, i8 6 }, align 4
+// CHECK-DAG: @_ZN7PR180978constant1bE = global { i16, i8 } { i16 2, i8 6 }, align 4
+// CHECK-DAG: @_ZN7PR180978constant1cE = global { i16, i8 } { i16 3, i8 6 }, align 4
+// CHECK-DAG: @_ZN7PR180978constant1yE = global { { i16, i8 }, i32 } { { i16, i8 } { i16 4, i8 6 }, i32 5 }, align 4
struct A {
_Atomic(int) i;
diff --git a/test/CodeGenCXX/attr-used.cpp b/test/CodeGenCXX/attr-used.cpp
index 861734667357..d2a73f7d33e6 100644
--- a/test/CodeGenCXX/attr-used.cpp
+++ b/test/CodeGenCXX/attr-used.cpp
@@ -2,16 +2,16 @@
// <rdar://problem/8684363>: clang++ not respecting __attribute__((used)) on destructors
struct X0 {
- // CHECK: define linkonce_odr {{.*}} @_ZN2X0C1Ev
+ // CHECK-DAG: define linkonce_odr {{.*}} @_ZN2X0C1Ev
__attribute__((used)) X0() {}
- // CHECK: define linkonce_odr {{.*}} @_ZN2X0D1Ev
+ // CHECK-DAG: define linkonce_odr {{.*}} @_ZN2X0D1Ev
__attribute__((used)) ~X0() {}
};
// PR19743: not emitting __attribute__((used)) inline methods in nested classes.
struct X1 {
struct Nested {
- // CHECK: define linkonce_odr {{.*}} @_ZN2X16Nested1fEv
+ // CHECK-DAG: define linkonce_odr {{.*}} @_ZN2X16Nested1fEv
void __attribute__((used)) f() {}
};
};
@@ -22,6 +22,6 @@ struct X2 {
void __attribute__((used)) bar() { foo(); }
void foo() { }
- // CHECK: define linkonce_odr {{.*}} @_ZN2X23barEv
- // CHECK: define linkonce_odr {{.*}} @_ZN2X23fooEv
+ // CHECK-DAG: define linkonce_odr {{.*}} @_ZN2X23barEv
+ // CHECK-DAG: define linkonce_odr {{.*}} @_ZN2X23fooEv
};
diff --git a/test/CodeGenCXX/call-with-static-chain.cpp b/test/CodeGenCXX/call-with-static-chain.cpp
new file mode 100644
index 000000000000..7cf929189f2c
--- /dev/null
+++ b/test/CodeGenCXX/call-with-static-chain.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK32 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK64 %s
+
+struct A {
+ long x, y;
+};
+
+struct B {
+ long x, y, z, w;
+};
+
+extern "C" {
+
+int f1(A, A, A, A);
+B f2(void);
+_Complex float f3(void);
+A &f4();
+
+}
+
+void test() {
+ A a;
+
+ // CHECK32: call i32 bitcast (i32 (%struct.A*, %struct.A*, %struct.A*, %struct.A*)* @f1 to i32 (i8*, %struct.A*, %struct.A*, %struct.A*, %struct.A*)*)(i8* nest bitcast (i32 (%struct.A*, %struct.A*, %struct.A*, %struct.A*)* @f1 to i8*)
+ // CHECK64: call i32 bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i32 (i8*, i64, i64, i64, i64, i64, i64, %struct.A*)*)(i8* nest bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i8*)
+ __builtin_call_with_static_chain(f1(a, a, a, a), f1);
+
+ // CHECK32: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*))
+ // CHECK64: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*))
+ __builtin_call_with_static_chain(f2(), f2);
+
+ // CHECK32: call i64 bitcast (i64 ()* @f3 to i64 (i8*)*)(i8* nest bitcast (i64 ()* @f3 to i8*))
+ // CHECK64: call <2 x float> bitcast (<2 x float> ()* @f3 to <2 x float> (i8*)*)(i8* nest bitcast (<2 x float> ()* @f3 to i8*))
+ __builtin_call_with_static_chain(f3(), f3);
+
+ // CHECK32: call dereferenceable(8) %struct.A* bitcast (%struct.A* ()* @f4 to %struct.A* (i8*)*)(i8* nest bitcast (%struct.A* ()* @f4 to i8*))
+ // CHECK64: call dereferenceable(16) %struct.A* bitcast (%struct.A* ()* @f4 to %struct.A* (i8*)*)(i8* nest bitcast (%struct.A* ()* @f4 to i8*))
+ __builtin_call_with_static_chain(f4(), f4);
+}
diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp
index 333855d0ba61..4120d0fead4d 100644
--- a/test/CodeGenCXX/catch-undef-behavior.cpp
+++ b/test/CodeGenCXX/catch-undef-behavior.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -std=c++11 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,array-bounds,function -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
-// RUN: %clang_cc1 -std=c++11 -fsanitize=vptr,address -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-ASAN
-// RUN: %clang_cc1 -std=c++11 -fsanitize=vptr -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=DOWNCAST-NULL
+// RUN: %clang_cc1 -std=c++11 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,array-bounds,function -fsanitize-recover=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,array-bounds,function -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fsanitize=vptr,address -fsanitize-recover=vptr,address -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-ASAN
+// RUN: %clang_cc1 -std=c++11 -fsanitize=vptr -fsanitize-recover=vptr -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=DOWNCAST-NULL
struct S {
double d;
@@ -221,11 +221,14 @@ void bad_downcast_pointer(S *p) {
void bad_downcast_reference(S &p) {
// CHECK: %[[E1:.*]] = icmp ne {{.*}}, null
// CHECK-NOT: br i1
+
// CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(
// CHECK: %[[E2:.*]] = icmp uge i64 %[[SIZE]], 24
- // CHECK: %[[E12:.*]] = and i1 %[[E1]], %[[E2]]
+
// CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
// CHECK: %[[E3:.*]] = icmp eq i64 %[[MISALIGN]], 0
+
+ // CHECK: %[[E12:.*]] = and i1 %[[E1]], %[[E2]]
// CHECK: %[[E123:.*]] = and i1 %[[E12]], %[[E3]]
// CHECK: br i1 %[[E123]],
@@ -382,11 +385,11 @@ void downcast_reference(B &b) {
// CHECK-NEXT: [[MASKED:%[0-9]*]] = and i64 [[C_INT]], 15
// CHECK-NEXT: [[TEST:%[0-9]*]] = icmp eq i64 [[MASKED]], 0
// AND the alignment test with the objectsize test.
- // CHECK-NEXT: [[AND:%[0-9]*]] = and i1 {{.*}}, [[TEST]]
+ // CHECK: [[AND:%[0-9]*]] = and i1 {{.*}}, [[TEST]]
// CHECK-NEXT: br i1 [[AND]]
}
-// CHECK-LABEL: @_Z22indirect_function_callPFviE({{.*}} prefix <{ i32, i8* }> <{ i32 1413876459, i8* bitcast ({ i8*, i8* }* @_ZTIFvPFviEE to i8*) }>
+// CHECK-LABEL: @_Z22indirect_function_callPFviE({{.*}} prologue <{ i32, i8* }> <{ i32 1413876459, i8* bitcast ({ i8*, i8* }* @_ZTIFvPFviEE to i8*) }>
void indirect_function_call(void (*p)(int)) {
// CHECK: [[PTR:%[0-9]*]] = bitcast void (i32)* {{.*}} to <{ i32, i8* }>*
@@ -404,6 +407,40 @@ void indirect_function_call(void (*p)(int)) {
p(42);
}
+namespace UpcastPointerTest {
+struct S {};
+struct T : S { double d; };
+struct V : virtual S {};
+
+// CHECK-LABEL: upcast_pointer
+S* upcast_pointer(T* t) {
+ // Check for null pointer
+ // CHECK: %[[NONNULL:.*]] = icmp ne {{.*}}, null
+ // CHECK: br i1 %[[NONNULL]]
+
+ // Check alignment
+ // CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
+ // CHECK: icmp eq i64 %[[MISALIGN]], 0
+
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ return t;
+}
+
+V getV();
+
+// CHECK-LABEL: upcast_to_vbase
+void upcast_to_vbase() {
+ // No need to check for null here, as we have a temporary here.
+
+ // CHECK-NOT: br i1
+
+ // CHECK: call i64 @llvm.objectsize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss
+ const S& s = getV();
+}
+}
+
namespace CopyValueRepresentation {
// CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S3aSERKS0_
// CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value
diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp
index d7d84a86abad..610dbc5feaaf 100644
--- a/test/CodeGenCXX/class-layout.cpp
+++ b/test/CodeGenCXX/class-layout.cpp
@@ -14,7 +14,7 @@ namespace Test2 {
namespace Test3 {
// C should have a vtable pointer.
- // CHECK: %"struct.Test3::A" = type { i32 (...)**, i32 }
+ // CHECK: %"struct.Test3::A" = type <{ i32 (...)**, i32, [4 x i8] }>
struct A { virtual void f(); int a; } *a;
}
diff --git a/test/CodeGenCXX/compound-literals.cpp b/test/CodeGenCXX/compound-literals.cpp
index f1d88027c4fa..e7710939bd2d 100644
--- a/test/CodeGenCXX/compound-literals.cpp
+++ b/test/CodeGenCXX/compound-literals.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple armv7-none-eabi -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple armv7-none-eabi -emit-llvm -o - %s | FileCheck %s
struct X {
X();
@@ -42,3 +42,16 @@ struct Z { int i[3]; };
int *p = (Z){ {1, 2, 3} }.i;
// CHECK: define {{.*}}__cxx_global_var_init()
// CHECK: store i32* getelementptr inbounds (%struct.Z* @.compoundliteral, i32 0, i32 0, i32 0), i32** @p
+
+
+int *PR21912_1 = (int []){};
+// CHECK-LABEL: define {{.*}}__cxx_global_var_init1()
+// CHECK: store i32* getelementptr inbounds ([0 x i32]* @.compoundliteral2, i32 0, i32 0), i32** @PR21912_1
+
+union PR21912Ty {
+ long long l;
+ double d;
+};
+union PR21912Ty *PR21912_2 = (union PR21912Ty[]){{.d = 2.0}, {.l = 3}};
+// CHECK-LABEL: define {{.*}}__cxx_global_var_init3()
+// CHECK: store %union.PR21912Ty* getelementptr inbounds ([2 x %union.PR21912Ty]* bitcast (<{ { double }, %union.PR21912Ty }>* @.compoundliteral4 to [2 x %union.PR21912Ty]*), i32 0, i32 0), %union.PR21912Ty** @PR21912_2
diff --git a/test/CodeGenCXX/constructor-destructor-return-this.cpp b/test/CodeGenCXX/constructor-destructor-return-this.cpp
index ce6ddd29f644..dcd20fe87d6f 100644
--- a/test/CodeGenCXX/constructor-destructor-return-this.cpp
+++ b/test/CodeGenCXX/constructor-destructor-return-this.cpp
@@ -10,7 +10,7 @@
class A {
public:
A();
- ~A();
+ virtual ~A();
private:
int x_;
@@ -19,7 +19,7 @@ private:
class B : public A {
public:
B(int *i);
- ~B();
+ virtual ~B();
private:
int *i_;
@@ -44,7 +44,7 @@ B::~B() { }
// CHECKIOS5-LABEL: define %class.B* @_ZN1BD1Ev(%class.B* %this)
// CHECKMS-LABEL: define x86_thiscallcc %class.B* @"\01??0B@@QAE@PAH@Z"(%class.B* returned %this, i32* %i)
-// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1B@@QAE@XZ"(%class.B* %this)
+// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1B@@UAE@XZ"(%class.B* %this)
class C : public A, public B {
public:
@@ -61,19 +61,25 @@ C::~C() { }
// CHECKGEN-LABEL: define void @_ZN1CC1EPiPc(%class.C* %this, i32* %i, i8* %c)
// CHECKGEN-LABEL: define void @_ZN1CD2Ev(%class.C* %this)
// CHECKGEN-LABEL: define void @_ZN1CD1Ev(%class.C* %this)
+// CHECKGEN-LABEL: define void @_ZThn8_N1CD1Ev(%class.C* %this)
// CHECKGEN-LABEL: define void @_ZN1CD0Ev(%class.C* %this)
+// CHECKGEN-LABEL: define void @_ZThn8_N1CD0Ev(%class.C* %this)
// CHECKARM-LABEL: define %class.C* @_ZN1CC2EPiPc(%class.C* returned %this, i32* %i, i8* %c)
// CHECKARM-LABEL: define %class.C* @_ZN1CC1EPiPc(%class.C* returned %this, i32* %i, i8* %c)
// CHECKARM-LABEL: define %class.C* @_ZN1CD2Ev(%class.C* returned %this)
// CHECKARM-LABEL: define %class.C* @_ZN1CD1Ev(%class.C* returned %this)
+// CHECKARM-LABEL: define %class.C* @_ZThn8_N1CD1Ev(%class.C* %this)
// CHECKARM-LABEL: define void @_ZN1CD0Ev(%class.C* %this)
+// CHECKARM-LABEL: define void @_ZThn8_N1CD0Ev(%class.C* %this)
// CHECKIOS5-LABEL: define %class.C* @_ZN1CC2EPiPc(%class.C* %this, i32* %i, i8* %c)
// CHECKIOS5-LABEL: define %class.C* @_ZN1CC1EPiPc(%class.C* %this, i32* %i, i8* %c)
// CHECKIOS5-LABEL: define %class.C* @_ZN1CD2Ev(%class.C* %this)
// CHECKIOS5-LABEL: define %class.C* @_ZN1CD1Ev(%class.C* %this)
+// CHECKIOS5-LABEL: define %class.C* @_ZThn8_N1CD1Ev(%class.C* %this)
// CHECKIOS5-LABEL: define void @_ZN1CD0Ev(%class.C* %this)
+// CHECKIOS5-LABEL: define void @_ZThn8_N1CD0Ev(%class.C* %this)
// CHECKMS-LABEL: define x86_thiscallcc %class.C* @"\01??0C@@QAE@PAHPAD@Z"(%class.C* returned %this, i32* %i, i8* %c)
// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1C@@UAE@XZ"(%class.C* %this)
@@ -103,7 +109,7 @@ D::~D() { }
// CHECKIOS5-LABEL: define %class.D* @_ZN1DD1Ev(%class.D* %this)
// CHECKMS-LABEL: define x86_thiscallcc %class.D* @"\01??0D@@QAE@XZ"(%class.D* returned %this, i32 %is_most_derived)
-// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1D@@QAE@XZ"(%class.D* %this)
+// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1D@@UAE@XZ"(%class.D*)
class E {
public:
diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp
index a8f483e53ab5..9d029a3696b2 100644
--- a/test/CodeGenCXX/constructor-init.cpp
+++ b/test/CodeGenCXX/constructor-init.cpp
@@ -94,23 +94,23 @@ namespace InitVTable {
};
// CHECK-LABEL: define void @_ZN10InitVTable1BC2Ev(%"struct.InitVTable::B"* %this) unnamed_addr
- // CHECK: [[T0:%.*]] = bitcast [[B:%.*]]* [[THIS:%.*]] to i8***
- // CHECK-NEXT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2), i8*** [[T0]]
+ // CHECK: [[T0:%.*]] = bitcast [[B:%.*]]* [[THIS:%.*]] to i32 (...)***
+ // CHECK-NEXT: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2) to i32 (...)**), i32 (...)*** [[T0]]
// CHECK: [[VTBL:%.*]] = load i32 ([[B]]*)*** {{%.*}}
// CHECK-NEXT: [[FNP:%.*]] = getelementptr inbounds i32 ([[B]]*)** [[VTBL]], i64 0
// CHECK-NEXT: [[FN:%.*]] = load i32 ([[B]]*)** [[FNP]]
// CHECK-NEXT: [[ARG:%.*]] = call i32 [[FN]]([[B]]* [[THIS]])
// CHECK-NEXT: call void @_ZN10InitVTable1AC2Ei({{.*}}* {{%.*}}, i32 [[ARG]])
- // CHECK-NEXT: [[T0:%.*]] = bitcast [[B]]* [[THIS]] to i8***
- // CHECK-NEXT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2), i8*** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[B]]* [[THIS]] to i32 (...)***
+ // CHECK-NEXT: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2) to i32 (...)**), i32 (...)*** [[T0]]
// CHECK-NEXT: ret void
B::B() : A(foo()) {}
// CHECK-LABEL: define void @_ZN10InitVTable1BC2Ei(%"struct.InitVTable::B"* %this, i32 %x) unnamed_addr
// CHECK: [[ARG:%.*]] = add nsw i32 {{%.*}}, 5
// CHECK-NEXT: call void @_ZN10InitVTable1AC2Ei({{.*}}* {{%.*}}, i32 [[ARG]])
- // CHECK-NEXT: [[T0:%.*]] = bitcast [[B]]* {{%.*}} to i8***
- // CHECK-NEXT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2), i8*** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[B]]* {{%.*}} to i32 (...)***
+ // CHECK-NEXT: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2) to i32 (...)**), i32 (...)*** [[T0]]
// CHECK-NEXT: ret void
B::B(int x) : A(x + 5) {}
}
diff --git a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
index 4bb0fee25e51..8fdc4dff7feb 100644
--- a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
+++ b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
@@ -4,4 +4,4 @@ struct A { virtual void a(); };
A x(A& y) { return y; }
// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* {{.*}}%this, %struct.A* dereferenceable({{[0-9]+}})) unnamed_addr
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) to i32 (...)**)
diff --git a/test/CodeGenCXX/copy-constructor-synthesis.cpp b/test/CodeGenCXX/copy-constructor-synthesis.cpp
index 47f8e131d62e..abbb7d05351e 100644
--- a/test/CodeGenCXX/copy-constructor-synthesis.cpp
+++ b/test/CodeGenCXX/copy-constructor-synthesis.cpp
@@ -148,8 +148,8 @@ void f(B b1) {
// CHECK-LABEL: define linkonce_odr void @_ZN12rdar138169401AC2ERKS0_(
// CHECK: [[THIS:%.*]] = load [[A]]**
-// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[THIS]] to i8***
-// CHECK-NEXT: store i8** getelementptr inbounds ([4 x i8*]* @_ZTVN12rdar138169401AE, i64 0, i64 2), i8*** [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[THIS]] to i32 (...)***
+// CHECK-NEXT: store i32 (...)** bitcast (i8** getelementptr inbounds ([4 x i8*]* @_ZTVN12rdar138169401AE, i64 0, i64 2) to i32 (...)**), i32 (...)*** [[T0]]
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1
// CHECK-NEXT: [[OTHER:%.*]] = load [[A]]**
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* [[OTHER]], i32 0, i32 1
diff --git a/test/CodeGenCXX/coverage.cpp b/test/CodeGenCXX/coverage.cpp
index 88f74098efa8..3931b0c6ffb3 100644
--- a/test/CodeGenCXX/coverage.cpp
+++ b/test/CodeGenCXX/coverage.cpp
@@ -3,5 +3,5 @@
extern "C" void test_name1() {}
void test_name2() {}
-// CHECK: metadata !"test_name1", metadata !"test_name1", metadata !"",{{.*}}DW_TAG_subprogram
-// CHECK: metadata !"test_name2", metadata !"test_name2", metadata !"_Z10test_name2v",{{.*}}DW_TAG_subprogram
+// CHECK: !"0x2e\00test_name1\00test_name1\00\00{{[^,]+}}", {{.*}} DW_TAG_subprogram
+// CHECK: !"0x2e\00test_name2\00test_name2\00_Z10test_name2v\00{{[^,]+}}", {{.*}} DW_TAG_subprogram
diff --git a/test/CodeGenCXX/crash.cpp b/test/CodeGenCXX/crash.cpp
index 073542dd15b0..e1577a3abe37 100644
--- a/test/CodeGenCXX/crash.cpp
+++ b/test/CodeGenCXX/crash.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only
+// RUN: %clang_cc1 -emit-obj -o %t -gline-tables-only -std=c++11 %s
// CHECK that we don't crash.
// PR11676's example is ill-formed:
@@ -33,3 +34,13 @@ template <class ELFT> void finalizeDefaultAtomValues() {
void f() { finalizeDefaultAtomValues<int>(); }
}
+
+namespace PR22096 {
+template <class> struct c {
+ c();
+ template <class U> __attribute__((__always_inline__)) c(c<U>) {}
+};
+struct {
+ c<double> v = c<int>();
+} o;
+}
diff --git a/test/CodeGenCXX/ctor-dtor-alias.cpp b/test/CodeGenCXX/ctor-dtor-alias.cpp
index d869a2bfd5d9..bd60cb88bb25 100644
--- a/test/CodeGenCXX/ctor-dtor-alias.cpp
+++ b/test/CodeGenCXX/ctor-dtor-alias.cpp
@@ -1,20 +1,33 @@
-// RUN: %clang_cc1 %s -triple i686-linux -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck %s
// RUN: %clang_cc1 %s -triple i686-linux -emit-llvm -o - -mconstructor-aliases | FileCheck --check-prefix=NOOPT %s
-// RUN: %clang_cc1 -triple x86_64--netbsd -emit-llvm \
-// RUN: -mconstructor-aliases -O2 %s -o - | FileCheck --check-prefix=CHECK-RAUW %s
+// RUN: %clang_cc1 %s -triple i686-linux -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns > %t
+// RUN: FileCheck --check-prefix=CHECK1 --input-file=%t %s
+// RUN: FileCheck --check-prefix=CHECK2 --input-file=%t %s
+// RUN: FileCheck --check-prefix=CHECK3 --input-file=%t %s
+// RUN: FileCheck --check-prefix=CHECK4 --input-file=%t %s
+// RUN: FileCheck --check-prefix=CHECK5 --input-file=%t %s
+// RUN: FileCheck --check-prefix=CHECK6 --input-file=%t %s
+
+// RUN: %clang_cc1 %s -triple i686-pc-windows-gnu -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck --check-prefix=COFF %s
namespace test1 {
-// test that we don't produce an alias when the destructor is weak_odr. The
-// reason to avoid it that another TU might have no explicit template
-// instantiation definition or declaration, causing it to to output only
-// one of the destructors as linkonce_odr, producing a different comdat.
+// Test that we produce the apropriate comdats when creating aliases to
+// weak_odr constructors and destructors.
-// CHECK-DAG: define weak_odr void @_ZN5test16foobarIvEC2Ev
-// CHECK-DAG: define weak_odr void @_ZN5test16foobarIvEC1Ev
+// CHECK1: @_ZN5test16foobarIvEC1Ev = weak_odr alias void {{.*}} @_ZN5test16foobarIvEC2Ev
+// CHECK1: @_ZN5test16foobarIvED1Ev = weak_odr alias void (%"struct.test1::foobar"*)* @_ZN5test16foobarIvED2Ev
+// CHECK1: define weak_odr void @_ZN5test16foobarIvEC2Ev({{.*}} comdat($_ZN5test16foobarIvEC5Ev)
+// CHECK1: define weak_odr void @_ZN5test16foobarIvED2Ev({{.*}} comdat($_ZN5test16foobarIvED5Ev)
+// CHECK1: define weak_odr void @_ZN5test16foobarIvED0Ev({{.*}} comdat($_ZN5test16foobarIvED5Ev)
+// CHECK1-NOT: comdat
-template <typename T> struct foobar {
+// COFF doesn't support comdats with arbitrary names (C5/D5).
+// COFF-NOT: comdat
+
+template <typename T>
+struct foobar {
foobar() {}
+ virtual ~foobar() {}
};
template struct foobar<void>;
@@ -24,8 +37,9 @@ namespace test2 {
// test that when the destrucor is linkonce_odr we just replace every use of
// C1 with C2.
-// CHECK-DAG: define linkonce_odr void @_ZN5test26foobarIvEC2Ev(
-// CHECK-DAG: call void @_ZN5test26foobarIvEC2Ev
+// CHECK1: define internal void @__cxx_global_var_init()
+// CHECK1: call void @_ZN5test26foobarIvEC2Ev
+// CHECK1: define linkonce_odr void @_ZN5test26foobarIvEC2Ev(
void g();
template <typename T> struct foobar {
foobar() { g(); }
@@ -37,8 +51,9 @@ namespace test3 {
// test that instead of an internal alias we just use the other destructor
// directly.
-// CHECK-DAG: define internal void @_ZN5test312_GLOBAL__N_11AD2Ev(
-// CHECK-DAG: call i32 @__cxa_atexit{{.*}}_ZN5test312_GLOBAL__N_11AD2Ev
+// CHECK1: define internal void @__cxx_global_var_init1()
+// CHECK1: call i32 @__cxa_atexit{{.*}}_ZN5test312_GLOBAL__N_11AD2Ev
+// CHECK1: define internal void @_ZN5test312_GLOBAL__N_11AD2Ev(
namespace {
struct A {
~A() {}
@@ -55,13 +70,15 @@ namespace test4 {
// guarantee that they will be present in every TU. Instead, we just call
// A's destructor directly.
- // CHECK-DAG: define linkonce_odr void @_ZN5test41AD2Ev(
- // CHECK-DAG: call i32 @__cxa_atexit{{.*}}_ZN5test41AD2Ev
+ // CHECK1: define internal void @__cxx_global_var_init2()
+ // CHECK1: call i32 @__cxa_atexit{{.*}}_ZN5test41AD2Ev
+ // CHECK1: define linkonce_odr void @_ZN5test41AD2Ev(
// test that we don't do this optimization at -O0 so that the debugger can
// see both destructors.
- // NOOPT-DAG: call i32 @__cxa_atexit{{.*}}@_ZN5test41BD2Ev
- // NOOPT-DAG: define linkonce_odr void @_ZN5test41BD2Ev
+ // NOOPT: define internal void @__cxx_global_var_init2()
+ // NOOPT: call i32 @__cxa_atexit{{.*}}@_ZN5test41BD2Ev
+ // NOOPT: define linkonce_odr void @_ZN5test41BD2Ev
struct A {
virtual ~A() {}
};
@@ -74,8 +91,9 @@ namespace test4 {
namespace test5 {
// similar to test4, but with an internal B.
- // CHECK-DAG: define linkonce_odr void @_ZN5test51AD2Ev(
- // CHECK-DAG: call i32 @__cxa_atexit{{.*}}_ZN5test51AD2Ev
+ // CHECK2: define internal void @__cxx_global_var_init3()
+ // CHECK2: call i32 @__cxa_atexit{{.*}}_ZN5test51AD2Ev
+ // CHECK2: define linkonce_odr void @_ZN5test51AD2Ev(
struct A {
virtual ~A() {}
};
@@ -99,14 +117,15 @@ namespace test6 {
};
}
B X;
- // CHECK-DAG: call i32 @__cxa_atexit({{.*}}@_ZN5test61AD2Ev
+ // CHECK3: define internal void @__cxx_global_var_init4()
+ // CHECK3: call i32 @__cxa_atexit({{.*}}@_ZN5test61AD2Ev
}
namespace test7 {
// Test that we don't produce an alias from ~B to ~A<int> (or crash figuring
// out if we should).
// pr17875.
- // CHECK-DAG: define void @_ZN5test71BD2Ev
+ // CHECK3: define void @_ZN5test71BD2Ev
template <typename> struct A {
~A() {}
};
@@ -119,8 +138,9 @@ namespace test7 {
namespace test8 {
// Test that we replace ~zed with ~bar which is an alias to ~foo.
- // CHECK-DAG: call i32 @__cxa_atexit({{.*}}@_ZN5test83barD2Ev
- // CHECK-DAG: @_ZN5test83barD2Ev = alias {{.*}} @_ZN5test83fooD2Ev
+ // CHECK4: @_ZN5test83barD2Ev = alias {{.*}} @_ZN5test83fooD2Ev
+ // CHECK4: define internal void @__cxx_global_var_init5()
+ // CHECK4: call i32 @__cxa_atexit({{.*}}@_ZN5test83barD2Ev
struct foo {
~foo();
};
@@ -144,12 +164,12 @@ struct bar : public foo {};
void zed() {
// Test that we produce a call to bar's destructor. We used to call foo's, but
// it has a different calling conversion.
- // CHECK-DAG: call void @_ZN5test93barD2Ev
+ // CHECK4: call void @_ZN5test93barD2Ev
bar ptr;
}
}
-// CHECK-RAUW: @_ZTV1C = linkonce_odr unnamed_addr constant [4 x i8*] [{{[^@]*}}@_ZTI1C {{[^@]*}}@_ZN1CD2Ev {{[^@]*}}@_ZN1CD0Ev {{[^@]*}}]
+// CHECK5: @_ZTV1C = linkonce_odr unnamed_addr constant [4 x i8*] [{{[^@]*}}@_ZTI1C {{[^@]*}}@_ZN1CD2Ev {{[^@]*}}@_ZN1CD0Ev {{[^@]*}}]
// r194296 replaced C::~C with B::~B without emitting the later.
class A {
@@ -177,3 +197,38 @@ void
fn1() {
new C;
}
+
+namespace test10 {
+// Test that if a destructor is in a comdat, we don't try to emit is as an
+// alias to a base class destructor.
+struct bar {
+ ~bar();
+};
+bar::~bar() {
+}
+} // closing the namespace causes ~bar to be sent to CodeGen
+namespace test10 {
+template <typename T>
+struct foo : public bar {
+ ~foo();
+};
+template <typename T>
+foo<T>::~foo() {}
+template class foo<int>;
+// CHECK5: define weak_odr void @_ZN6test103fooIiED2Ev({{.*}} comdat($_ZN6test103fooIiED5Ev)
+}
+
+namespace test11 {
+// Test that when we don't have to worry about COMDATs we produce an alias
+// from complate to base and from base to base class base.
+struct bar {
+ ~bar();
+};
+bar::~bar() {}
+struct foo : public bar {
+ ~foo();
+};
+foo::~foo() {}
+// CHECK6: @_ZN6test113fooD2Ev = alias {{.*}} @_ZN6test113barD2Ev
+// CHECK6: @_ZN6test113fooD1Ev = alias {{.*}} @_ZN6test113fooD2Ev
+}
diff --git a/test/CodeGenCXX/ctor-globalopt.cpp b/test/CodeGenCXX/ctor-globalopt.cpp
new file mode 100644
index 000000000000..672fc9067527
--- /dev/null
+++ b/test/CodeGenCXX/ctor-globalopt.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s -O1 | FileCheck %s --check-prefix=O1
+// RUN: %clang_cc1 -triple %ms_abi_triple -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %ms_abi_triple -emit-llvm -o - %s -O1 | FileCheck %s --check-prefix=O1
+
+// Check that GlobalOpt can eliminate static constructors for simple implicit
+// constructors. This is a targetted integration test to make sure that LLVM's
+// optimizers are able to process Clang's IR. GlobalOpt in particular is
+// sensitive to the casts we emit.
+
+// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }]
+// CHECK: [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_ctor_globalopt.cpp, i8* null }]
+
+// CHECK-LABEL: define internal void @_GLOBAL__sub_I_ctor_globalopt.cpp()
+// CHECK: call void @
+// CHECK-NOT: call
+
+// O1: @llvm.global_ctors = appending global [0 x { i32, void ()*, i8* }] zeroinitializer
+
+struct A {
+ virtual void f();
+ int a;
+};
+struct B : virtual A {
+ virtual void g();
+ int b;
+};
+B b;
diff --git a/test/CodeGenCXX/cxx11-exception-spec.cpp b/test/CodeGenCXX/cxx11-exception-spec.cpp
index 3b1516b92536..3fb5c15c2ab5 100644
--- a/test/CodeGenCXX/cxx11-exception-spec.cpp
+++ b/test/CodeGenCXX/cxx11-exception-spec.cpp
@@ -22,9 +22,9 @@ template<> void S<short>::f() { h(); }
// CHECK: define {{.*}} @_ZN1SIA2_sE1fEv() [[NUW]]
template<> void S<short[2]>::f() noexcept { h(); }
-// CHECK: define {{.*}} @_Z1fIDsEvv() [[NONE]] {
+// CHECK: define {{.*}} @_Z1fIDsEvv() [[NONE]] comdat {
template void f<char16_t>();
-// CHECK: define {{.*}} @_Z1fIA2_DsEvv() [[NUW]] {
+// CHECK: define {{.*}} @_Z1fIA2_DsEvv() [[NUW]] comdat {
template void f<char16_t[2]>();
// CHECK: define {{.*}} @_ZN1SIDsE1fEv()
@@ -34,9 +34,9 @@ template void S<char16_t>::f();
template void S<char16_t[2]>::f();
void h() {
- // CHECK: define {{.*}} @_Z1fIiEvv() [[NUW]] {
+ // CHECK: define {{.*}} @_Z1fIiEvv() [[NUW]] comdat {
f<int>();
- // CHECK: define {{.*}} @_Z1fIA2_iEvv() [[NONE]] {
+ // CHECK: define {{.*}} @_Z1fIA2_iEvv() [[NONE]] comdat {
f<int[2]>();
// CHECK: define {{.*}} @_ZN1SIiE1fEv() [[NUW]]
@@ -45,9 +45,9 @@ void h() {
// CHECK-NOT: [[NUW]]
S<int[2]>::f();
- // CHECK: define {{.*}} @_Z1fIfEvv() [[NUW]] {
+ // CHECK: define {{.*}} @_Z1fIfEvv() [[NUW]] comdat {
void (*f1)() = &f<float>;
- // CHECK: define {{.*}} @_Z1fIdEvv() [[NONE]] {
+ // CHECK: define {{.*}} @_Z1fIdEvv() [[NONE]] comdat {
void (*f2)() = &f<double>;
// CHECK: define {{.*}} @_ZN1SIfE1fEv() [[NUW]]
@@ -56,9 +56,9 @@ void h() {
// CHECK-NOT: [[NUW]]
void (*f4)() = &S<double>::f;
- // CHECK: define {{.*}} @_Z1fIA4_cEvv() [[NUW]] {
+ // CHECK: define {{.*}} @_Z1fIA4_cEvv() [[NUW]] comdat {
(void)&f<char[4]>;
- // CHECK: define {{.*}} @_Z1fIcEvv() [[NONE]] {
+ // CHECK: define {{.*}} @_Z1fIcEvv() [[NONE]] comdat {
(void)&f<char>;
// CHECK: define {{.*}} @_ZN1SIA4_cE1fEv() [[NUW]]
@@ -122,3 +122,8 @@ void j() {
// CHECK: attributes [[NONE]] = { {{.*}} }
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
+
+namespace PR19190 {
+template <class T> struct DWFIterator { virtual void get() throw(int) = 0; };
+void foo(DWFIterator<int> *foo) { foo->get(); }
+}
diff --git a/test/CodeGenCXX/cxx11-special-members.cpp b/test/CodeGenCXX/cxx11-special-members.cpp
index 59461f9e2f4b..037e59a6408f 100644
--- a/test/CodeGenCXX/cxx11-special-members.cpp
+++ b/test/CodeGenCXX/cxx11-special-members.cpp
@@ -28,5 +28,19 @@ void f2(B &x, B &y) {
// CHECK: define {{.*}} @_ZN1BaSEOS_(
// CHECK: call {{.*}} @_ZN1AaSERKS_(
+// rdar://18309639 {
+template<int> struct C { C() = default; };
+struct D {
+ C<0> c;
+ D() { }
+};
+template struct C<0>; // was asserting
+void f3() {
+ C<0> a;
+ D b;
+}
+// CHECK: define {{.*}} @_ZN1CILi0EEC1Ev
+// CHECK: define {{.*}} @_ZN1DC1Ev
+
// CHECK: define {{.*}} @_ZN1BC2EOS_(
// CHECK: call {{.*}} @_ZN1AC1ERKS_(
diff --git a/test/CodeGenCXX/cxx11-thread-local.cpp b/test/CodeGenCXX/cxx11-thread-local.cpp
index a3690b352989..a6f010626cad 100644
--- a/test/CodeGenCXX/cxx11-thread-local.cpp
+++ b/test/CodeGenCXX/cxx11-thread-local.cpp
@@ -44,9 +44,9 @@ int e = V<int>::m;
// CHECK: @llvm.global_ctors = appending global {{.*}} @[[GLOBAL_INIT:[^ ]*]]
// CHECK: @_ZTH1a = alias void ()* @__tls_init
-// CHECK: @_ZTHL1d = alias internal void ()* @__tls_init
+// CHECK: @_ZTHL1d = internal alias void ()* @__tls_init
// CHECK: @_ZTHN1U1mE = alias void ()* @__tls_init
-// CHECK: @_ZTHN1VIiE1mE = alias linkonce_odr void ()* @__tls_init
+// CHECK: @_ZTHN1VIiE1mE = linkonce_odr alias void ()* @__tls_init
// Individual variable initialization functions:
diff --git a/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
index 8bdf8633d61e..098a4b945e04 100644
--- a/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
+++ b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
@@ -36,6 +36,17 @@ B y {};
B z { 1 };
// CHECK: @z = global {{.*}} { i32 1 }
+// Brace initialization should initialize the first field even though it is
+// unnamed.
+union C {
+ struct {
+ int C::*memptr;
+ };
+};
+
+C n{};
+// CHECK: @n = global %union.C { %struct.anon { i64 -1 } }, align 8
+
// Initialization of 'a':
// CHECK: store i32 0, i32* getelementptr inbounds ({{.*}} @a, i32 0, i32 0)
diff --git a/test/CodeGenCXX/cxx1y-variable-template-linkage.cpp b/test/CodeGenCXX/cxx1y-variable-template-linkage.cpp
new file mode 100644
index 000000000000..8c0b8c22096d
--- /dev/null
+++ b/test/CodeGenCXX/cxx1y-variable-template-linkage.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -std=c++1y -O1 -disable-llvm-optzns %s -o - | FileCheck %s -check-prefix=CHECKA -check-prefix=CHECK
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -std=c++1y -O1 -disable-llvm-optzns -fcxx-exceptions %s -o - | FileCheck %s -check-prefix=CHECKB -check-prefix=CHECK
+// expected-no-diagnostics
+
+// The variable template specialization x<Foo> generated in each file
+// should be 'internal global' and not 'linkonce_odr global'.
+
+template <typename T> int x = 42;
+
+// CHECK-DAG: @_Z1xIZL3foovE3FooE = internal global
+
+// CHECK-DAG: define internal dereferenceable(4) i32* @_ZL3foov(
+static int &foo() {
+ struct Foo { };
+
+ // CHECK-DAG: ret i32* @_Z1xIZL3foovE3FooE
+ return x<Foo>;
+}
+
+
+#if !__has_feature(cxx_exceptions) // File A
+// CHECKA-DAG: define dereferenceable(4) i32* @_Z3barv(
+int &bar() {
+ // CHECKA-DAG: call dereferenceable(4) i32* @_ZL3foov()
+ return foo();
+}
+
+#else // File B
+
+// CHECKB-DAG: declare dereferenceable(4) i32* @_Z3barv(
+int &bar();
+
+int main() {
+ // CHECKB-DAG: call dereferenceable(4) i32* @_Z3barv()
+ // CHECKB-DAG: call dereferenceable(4) i32* @_ZL3foov()
+ &bar() == &foo() ? throw 0 : (void)0; // Should not throw exception at runtime.
+}
+
+#endif // end of Files A and B
+
diff --git a/test/CodeGenCXX/cxx1z-fold-expression.cpp b/test/CodeGenCXX/cxx1z-fold-expression.cpp
new file mode 100644
index 000000000000..5dac66b497db
--- /dev/null
+++ b/test/CodeGenCXX/cxx1z-fold-expression.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -std=c++1z -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+
+template<int> struct A {};
+template<int ...N> void foldr(A<(N + ...)>);
+template<int ...N> void foldl(A<(... + N)>);
+template<int ...N> void foldr1(A<(N + ... + 1)>);
+template<int ...N> void foldl1(A<(1 + ... + N)>);
+void use() {
+ foldr<1, 2, 3>({});
+ foldl<1, 2, 3>({});
+ foldr1<1, 2, 3>({});
+ foldl1<1, 2, 3>({});
+ // CHECK-DAG: @_Z5foldrIJLi1ELi2ELi3EEEv1AIXfrplT_EE(
+ // CHECK-DAG: @_Z5foldlIJLi1ELi2ELi3EEEv1AIXflplT_EE(
+ // CHECK-DAG: @_Z6foldr1IJLi1ELi2ELi3EEEv1AIXfRplT_Li1EEE(
+ // CHECK-DAG: @_Z6foldl1IJLi1ELi2ELi3EEEv1AIXfLplLi1ET_EE(
+}
+
+template<int ...N> using Foldr = A<(N + ...)>;
+template<int ...N> using Foldl = A<(... + N)>;
+template<int ...N> using Foldr1 = A<(N + ... + 1)>;
+template<int ...N> using Foldl1 = A<(1 + ... + N)>;
+
+template<int ...A> struct Partial {
+ template<int ...B> void foldr(Foldr<A..., B..., A..., B...>);
+ template<int ...B> void foldl(Foldl<A..., B..., A..., B...>);
+ template<int ...B> void foldr1(Foldr1<A..., B..., A..., B...>);
+ template<int ...B> void foldl1(Foldl1<A..., B..., A..., B...>);
+};
+void use(Partial<1, 2> p) {
+ p.foldr<3, 4>({});
+ p.foldl<3, 4>({});
+ p.foldr1<3, 4>({});
+ p.foldl1<3, 4>({});
+ // CHECK-DAG: @_ZN7PartialIJLi1ELi2EEE5foldrIJLi3ELi4EEEEv1AIXplLi1EplLi2EfRplT_plLi1EplLi2EfrplT_EE(
+ // CHECK-DAG: @_ZN7PartialIJLi1ELi2EEE5foldlIJLi3ELi4EEEEv1AIXfLplplplfLplplLi1ELi2ET_Li1ELi2ET_EE
+ // CHECK-DAG: @_ZN7PartialIJLi1ELi2EEE6foldr1IJLi3ELi4EEEEv1AIXplLi1EplLi2EfRplT_plLi1EplLi2EfRplT_Li1EEE(
+ // CHECK-DAG: @_ZN7PartialIJLi1ELi2EEE6foldl1IJLi3ELi4EEEEv1AIXfLplplplfLplplplLi1ELi1ELi2ET_Li1ELi2ET_EE(
+}
+
+extern int n;
+template<int ...N> void f() {
+ (n = ... = N);
+}
+template void f<>();
diff --git a/test/CodeGenCXX/debug-info-access.cpp b/test/CodeGenCXX/debug-info-access.cpp
new file mode 100644
index 000000000000..d6dfd87013dd
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-access.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple %itanium_abi_triple %s -o - | FileCheck %s
+// Test the various accessibility flags in the debug info.
+struct A {
+ // CHECK-DAG: [ DW_TAG_subprogram ] [line [[@LINE+1]]] [pub_default]
+ void pub_default();
+ // CHECK-DAG: [ DW_TAG_member ] [pub_default_static] [line [[@LINE+1]]{{.*}}offset 0] [static]
+ static int pub_default_static;
+};
+
+// CHECK: [ DW_TAG_inheritance ] {{.*}} [public] [from {{.*}}A]
+class B : public A {
+public:
+ // CHECK-DAG: [ DW_TAG_subprogram ] [line [[@LINE+1]]] [public] [pub]
+ void pub();
+ // CHECK-DAG: [ DW_TAG_member ] [public_static] [line [[@LINE+1]]{{.*}} [public] [static]
+ static int public_static;
+protected:
+ // CHECK: [ DW_TAG_subprogram ] [line [[@LINE+1]]] [protected] [prot]
+ void prot();
+private:
+ // CHECK: [ DW_TAG_subprogram ] [line [[@LINE+1]]] [priv_default]
+ void priv_default();
+};
+
+union U {
+ // CHECK-DAG: [ DW_TAG_subprogram ] [line [[@LINE+1]]] [union_pub_default]
+ void union_pub_default();
+private:
+ // CHECK-DAG: [ DW_TAG_member ] [union_priv] [line [[@LINE+1]]{{.*}} [private]
+ int union_priv;
+};
+
+
+// CHECK: {{.*}}\00256\00{{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [free]
+void free() {}
+
+A a;
+B b;
+U u;
diff --git a/test/CodeGenCXX/debug-info-alias.cpp b/test/CodeGenCXX/debug-info-alias.cpp
index fb18ac5da006..dd4b00b7de62 100644
--- a/test/CodeGenCXX/debug-info-alias.cpp
+++ b/test/CodeGenCXX/debug-info-alias.cpp
@@ -13,15 +13,15 @@ bar
= foo<T*>;
}
-// CHECK: metadata [[BINT:![0-9]*]], i32 0, i32 1, {{.*}} ; [ DW_TAG_variable ] [bi]
+// CHECK: [[BINT:![0-9]*]], {{[^,]+, [^,]+}}} ; [ DW_TAG_variable ] [bi]
// CHECK: [[BINT]] = {{.*}} ; [ DW_TAG_typedef ] [bar<int>] [line 42
x::bar<int> bi;
-// CHECK: metadata [[BFLOAT:![0-9]*]], i32 0, i32 1, {{.*}} ; [ DW_TAG_variable ] [bf]
+// CHECK: [[BFLOAT:![0-9]*]], {{[^,]+, [^,]+}}} ; [ DW_TAG_variable ] [bf]
// CHECK: [[BFLOAT]] = {{.*}} ; [ DW_TAG_typedef ] [bar<float>] [line 42
x::bar<float> bf;
using
-// CHECK: metadata [[NARF:![0-9]*]], i32 0, i32 1, {{.*}} ; [ DW_TAG_variable ] [n]
+// CHECK: [[NARF:![0-9]*]], {{[^,]+, [^,]+}}} ; [ DW_TAG_variable ] [n]
# 142
narf // CHECK: [[NARF]] = {{.*}} ; [ DW_TAG_typedef ] [narf] [line 142
= int;
diff --git a/test/CodeGenCXX/debug-info-artificial-arg.cpp b/test/CodeGenCXX/debug-info-artificial-arg.cpp
index 84f496f54c37..9eb3c6f0e98d 100644
--- a/test/CodeGenCXX/debug-info-artificial-arg.cpp
+++ b/test/CodeGenCXX/debug-info-artificial-arg.cpp
@@ -22,8 +22,8 @@ int main(int argc, char **argv) {
A reallyA (500);
}
-// CHECK: ![[CLASSTYPE:.*]] = {{.*}}, metadata !"_ZTS1A"} ; [ DW_TAG_class_type ] [A]
+// CHECK: ![[CLASSTYPE:.*]] = {{.*}}, !"_ZTS1A"} ; [ DW_TAG_class_type ] [A]
// CHECK: ![[ARTARG:.*]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from _ZTS1A]
-// CHECK: metadata !"_ZTS1A", {{.*}} ; [ DW_TAG_subprogram ] [line 12] [A]
-// CHECK: metadata [[FUNCTYPE:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
-// CHECK: [[FUNCTYPE]] = metadata !{null, metadata ![[ARTARG]], metadata !{{.*}}, metadata !{{.*}}}
+// CHECK: !"_ZTS1A", {{.*}} ; [ DW_TAG_subprogram ] [line 12] [public] [A]
+// CHECK: [[FUNCTYPE:![0-9]*]], null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[FUNCTYPE]] = !{null, ![[ARTARG]], !{{.*}}, !{{.*}}}
diff --git a/test/CodeGenCXX/debug-info-class.cpp b/test/CodeGenCXX/debug-info-class.cpp
index 34add0432c49..55d56531609f 100644
--- a/test/CodeGenCXX/debug-info-class.cpp
+++ b/test/CodeGenCXX/debug-info-class.cpp
@@ -94,33 +94,29 @@ int main(int argc, char **argv) {
// CHECK: DW_TAG_class_type ] [bar]
// CHECK: DW_TAG_union_type ] [baz]
// CHECK: DW_TAG_class_type ] [B] {{.*}} [def]
-// CHECK: metadata !"_vptr$B", {{.*}}, i32 64, metadata !{{.*}}} ; [ DW_TAG_member ]
+// CHECK: !"0xd\00_vptr$B\00{{.*}}\0064", {{.*}} ; [ DW_TAG_member ]
-// CHECK: [[C:![0-9]*]] = {{.*}} metadata [[C_MEM:![0-9]*]], i32 0, metadata !"_ZTS1C", null, metadata !"_ZTS1C"} ; [ DW_TAG_structure_type ] [C] {{.*}} [def]
-// CHECK: [[C_MEM]] = metadata !{metadata [[C_VPTR:![0-9]*]], metadata [[C_S:![0-9]*]], metadata [[C_DTOR:![0-9]*]]}
+// CHECK: [[C:![0-9]*]] = {{.*}} [[C_MEM:![0-9]*]], !"_ZTS1C", null, !"_ZTS1C"} ; [ DW_TAG_structure_type ] [C] {{.*}} [def]
+// CHECK: [[C_MEM]] = !{[[C_VPTR:![0-9]*]], [[C_S:![0-9]*]], [[C_DTOR:![0-9]*]]}
// CHECK: [[C_VPTR]] = {{.*}} ; [ DW_TAG_member ] [_vptr$C] {{.*}} [artificial]
// CHECK: [[C_S]] = {{.*}} ; [ DW_TAG_member ] [s] {{.*}} [static] [from int]
// CHECK: [[C_DTOR]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [~C]
-// CHECK: null, i32 0, null, null, metadata !"_ZTS1D"} ; [ DW_TAG_structure_type ] [D] {{.*}} [decl]
-// CHECK: null, i32 0, null, null, metadata !"_ZTS1E"} ; [ DW_TAG_structure_type ] [E] {{.*}} [decl]
-// CHECK: [[F:![0-9]*]] = {{.*}} null, i32 0, null, null, metadata !"_ZTS1F"} ; [ DW_TAG_structure_type ] [F] {{.*}} [decl]
+// CHECK: null, null, null, !"_ZTS1D"} ; [ DW_TAG_structure_type ] [D] {{.*}} [decl]
+// CHECK: null, null, null, !"_ZTS1E"} ; [ DW_TAG_structure_type ] [E] {{.*}} [decl]
+// CHECK: [[F:![0-9]*]] = {{.*}} null, null, null, !"_ZTS1F"} ; [ DW_TAG_structure_type ] [F] {{.*}} [decl]
-// CHECK: null, i32 0, null, null, metadata !"_ZTS1G"} ; [ DW_TAG_structure_type ] [G] {{.*}} [decl]
-// CHECK: metadata [[G_INNER_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTSN1G5innerE"} ; [ DW_TAG_structure_type ] [inner] [line 50, {{.*}} [def]
-// CHECK: [[G_INNER_MEM]] = metadata !{metadata [[G_INNER_I:![0-9]*]]}
+// CHECK: null, null, null, !"_ZTS1G"} ; [ DW_TAG_structure_type ] [G] {{.*}} [decl]
+// CHECK: [[G_INNER_MEM:![0-9]*]], null, null, !"_ZTSN1G5innerE"} ; [ DW_TAG_structure_type ] [inner] [line 50, {{.*}} [def]
+// CHECK: [[G_INNER_MEM]] = !{[[G_INNER_I:![0-9]*]]}
// CHECK: [[G_INNER_I]] = {{.*}} ; [ DW_TAG_member ] [j] {{.*}} [from int]
// CHECK: ; [ DW_TAG_structure_type ] [A]
// CHECK: HdrSize
// CHECK: ; [ DW_TAG_structure_type ] [I] {{.*}} [def]
//
-// CHECK: metadata !"_ZTS1D", {{.*}}, metadata [[D_FUNC_DECL:![0-9]*]], metadata {{![0-9]*}}, i32 {{[0-9]*}}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
-// CHECK: [[D_FUNC_DECL]] = {{.*}}, metadata !"_ZTS1D", {{.*}}, i32 0, null, i32 {{[0-9]*}}} ; [ DW_TAG_subprogram ] {{.*}} [func]
+// CHECK: !"_ZTS1D", {{.*}}, [[D_FUNC_DECL:![0-9]*]], {{![0-9]*}}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
+// CHECK: [[D_FUNC_DECL]] = !{!"0x2e\00func\00{{.*}}\000\00{{[0-9]+}}"{{.*}}, !"_ZTS1D", {{.*}}, null} ; [ DW_TAG_subprogram ] {{.*}} [func]
-// CHECK: [[F_I_DEF:![0-9]*]] = {{.*}}, metadata [[F_I:![0-9]*]]} ; [ DW_TAG_variable ] [i]
-
-// CHECK: [[F_I]] = {{.*}}, metadata !"_ZTS1F", {{.*}} ; [ DW_TAG_member ] [i]
-
-// CHECK: ![[EXCEPTLOC]] = metadata !{i32 84,
-// CHECK: ![[RETLOC]] = metadata !{i32 83,
+// CHECK: ![[EXCEPTLOC]] = !MDLocation(line: 84,
+// CHECK: ![[RETLOC]] = !MDLocation(line: 83,
diff --git a/test/CodeGenCXX/debug-info-cxx1y.cpp b/test/CodeGenCXX/debug-info-cxx1y.cpp
index 3cb7e45e6985..261f9653461d 100644
--- a/test/CodeGenCXX/debug-info-cxx1y.cpp
+++ b/test/CodeGenCXX/debug-info-cxx1y.cpp
@@ -1,7 +1,20 @@
-// RUN: not %clang_cc1 -emit-llvm-only -std=c++1y -g %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm-only -std=c++14 -emit-llvm -g %s -o - | FileCheck %s
+
+// CHECK: [[EMPTY:![0-9]*]] = !{}
+// CHECK: \00foo\00{{.*}}, [[EMPTY]], {{.*}}} ; [ DW_TAG_structure_type ]
+// FIXME: The context of this definition should be the CU/file scope, not the class.
+// CHECK: !"_ZTS3foo", [[SUBROUTINE_TYPE:![0-9]*]], {{.*}}, [[FUNC_DECL:![0-9]*]], {{![0-9]*}}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
+// CHECK: [[SUBROUTINE_TYPE]] = {{.*}}, [[TYPE_LIST:![0-9]*]],
+// CHECK: [[TYPE_LIST]] = !{[[INT:![0-9]*]]}
+// CHECK: [[INT]] = {{.*}} ; [ DW_TAG_base_type ] [int]
+// CHECK: [[FUNC_DECL]] = {{.*}}, !"_ZTS3foo", [[SUBROUTINE_TYPE]], {{.*}}} ; [ DW_TAG_subprogram ] {{.*}} [func]
struct foo {
- auto func(); // CHECK: error: debug information for auto is not yet supported
+ static auto func();
};
foo f;
+
+auto foo::func() {
+ return 1;
+}
diff --git a/test/CodeGenCXX/debug-info-decl-nested.cpp b/test/CodeGenCXX/debug-info-decl-nested.cpp
index f79a8e9fe32d..95d32c400e18 100644
--- a/test/CodeGenCXX/debug-info-decl-nested.cpp
+++ b/test/CodeGenCXX/debug-info-decl-nested.cpp
@@ -17,17 +17,18 @@ class OuterClass
public:
InnerClass(); // Here createContextChain() generates a limited type for OuterClass.
} theInnerClass;
-// CHECK0: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [private] [OuterClass]
+// CHECK0: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [OuterClass]
OuterClass(const Foo *); // line 10
};
OuterClass::InnerClass OuterClass::theInnerClass; // This toplevel decl causes InnerClass to be generated.
-// CHECK0: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+1]]} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [OuterClass]
+// CHECK0: !"0x2e\00OuterClass\00{{.*}}\00[[@LINE+1]]"{{.*}}, ![[DECL]], {{![0-9]+}}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [OuterClass]
OuterClass::OuterClass(const Foo *meta) { } // line 13
+
class Foo1;
class OuterClass1
{
@@ -35,8 +36,8 @@ class OuterClass1
public:
InnerClass1();
} theInnerClass1;
-// CHECK1: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+2]]] [private] [Bar]
-// CHECK1: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+4]]} ; [ DW_TAG_subprogram ] [line [[@LINE+4]]] [def] [Bar]
+// CHECK1: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+2]]] [Bar]
+// CHECK1: !"0x2e\00Bar\00{{.*}}\00[[@LINE+4]]"{{.*}}, ![[DECL]], {{![0-9]+}}} ; [ DW_TAG_subprogram ] [line [[@LINE+4]]] [def] [Bar]
void Bar(const Foo1 *);
};
OuterClass1::InnerClass1 OuterClass1::theInnerClass1;
@@ -53,9 +54,9 @@ class OuterClass2
public:
InnerClass2();
} theInnerClass2;
-// CHECK2: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [private] [~OuterClass2]
+// CHECK2: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [~OuterClass2]
~OuterClass2(); // line 10
};
OuterClass2::InnerClass2 OuterClass2::theInnerClass2;
-// CHECK2: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+1]]} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [~OuterClass2]
+// CHECK2: !"0x2e\00~OuterClass2\00{{.*}}\00[[@LINE+1]]"{{.*}}, ![[DECL]], {{.*}}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [~OuterClass2]
OuterClass2::~OuterClass2() { }
diff --git a/test/CodeGenCXX/debug-info-enum-class.cpp b/test/CodeGenCXX/debug-info-enum-class.cpp
index f0b97ccd2c8e..28ffce046c09 100644
--- a/test/CodeGenCXX/debug-info-enum-class.cpp
+++ b/test/CodeGenCXX/debug-info-enum-class.cpp
@@ -29,10 +29,10 @@ namespace PR14029 {
namespace test2 {
// FIXME: this should just be a declaration under -fno-standalone-debug
-// CHECK: metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST2:![0-9]*]], {{.*}}, metadata [[TEST_ENUMS:![0-9]*]], {{[^,]*}}, null, null, metadata !"_ZTSN5test21EE"} ; [ DW_TAG_enumeration_type ] [E]
+// CHECK: !"0x4\00{{.*}}", {{[^,]*}}, [[TEST2:![0-9]*]], {{.*}}, [[TEST_ENUMS:![0-9]*]], null, null, !"_ZTSN5test21EE"} ; [ DW_TAG_enumeration_type ] [E]
// CHECK: [[TEST2]] = {{.*}} ; [ DW_TAG_namespace ] [test2]
-// CHECK: [[TEST_ENUMS]] = metadata !{metadata [[TEST_E:![0-9]*]]}
-// CHECK: [[TEST_E]] = {{.*}}, metadata !"e", i64 0} ; [ DW_TAG_enumerator ] [e :: 0]
+// CHECK: [[TEST_ENUMS]] = !{[[TEST_E:![0-9]*]]}
+// CHECK: [[TEST_E]] = !{!"0x28\00e\000"} ; [ DW_TAG_enumerator ] [e :: 0]
enum E : int;
void func(E *) {
}
@@ -41,7 +41,7 @@ enum E : int { e };
namespace test3 {
// FIXME: this should just be a declaration under -fno-standalone-debug
-// CHECK: metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST3:![0-9]*]], {{.*}}, metadata [[TEST_ENUMS]], {{[^,]*}}, null, null, metadata !"_ZTSN5test31EE"} ; [ DW_TAG_enumeration_type ] [E]
+// CHECK: !"0x4\00{{.*}}", {{[^,]*}}, [[TEST3:![0-9]*]], {{.*}}, [[TEST_ENUMS]], null, null, !"_ZTSN5test31EE"} ; [ DW_TAG_enumeration_type ] [E]
// CHECK: [[TEST3]] = {{.*}} ; [ DW_TAG_namespace ] [test3]
enum E : int { e };
void func(E *) {
@@ -49,7 +49,7 @@ void func(E *) {
}
namespace test4 {
-// CHECK: metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST4:![0-9]*]], {{.*}}, metadata [[TEST_ENUMS]], {{[^,]*}}, null, null, metadata !"_ZTSN5test41EE"} ; [ DW_TAG_enumeration_type ] [E]
+// CHECK: !"0x4\00{{.*}}", {{[^,]*}}, [[TEST4:![0-9]*]], {{.*}}, [[TEST_ENUMS]], null, null, !"_ZTSN5test41EE"} ; [ DW_TAG_enumeration_type ] [E]
// CHECK: [[TEST4]] = {{.*}} ; [ DW_TAG_namespace ] [test4]
enum E : int;
void f1(E *) {
@@ -62,7 +62,7 @@ void f2(E) {
// CHECK: ; [ DW_TAG_enumeration_type ] [D] [line 6, size 16, align 16, offset 0] [decl] [from ]
namespace test5 {
-// CHECK: metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST5:![0-9]*]], {{.*}}, null, {{[^,]*}}, null, null, metadata !"_ZTSN5test51EE"} ; [ DW_TAG_enumeration_type ] [E]
+// CHECK: !"0x4\00{{.*}}", {{[^,]*}}, [[TEST5:![0-9]*]], {{.*}}, null, null, null, !"_ZTSN5test51EE"} ; [ DW_TAG_enumeration_type ] [E]
// CHECK: [[TEST5]] = {{.*}} ; [ DW_TAG_namespace ] [test5]
enum E : int;
void f1(E *) {
diff --git a/test/CodeGenCXX/debug-info-enum.cpp b/test/CodeGenCXX/debug-info-enum.cpp
index 810c3ee7ae9b..954f6f62e497 100644
--- a/test/CodeGenCXX/debug-info-enum.cpp
+++ b/test/CodeGenCXX/debug-info-enum.cpp
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -g %s -o - | FileCheck %s
-// CHECK: [[ENUMS:![0-9]*]], {{[^,]*}}, {{[^,]*}}, {{[^,]*}}, {{[^,]*}}, {{[^,]*}}} ; [ DW_TAG_compile_unit ]
-// CHECK: [[ENUMS]] = metadata !{metadata [[E1:![0-9]*]], metadata [[E2:![0-9]*]], metadata [[E3:![0-9]*]]}
+// CHECK: !"0x11\00{{.*}}", {{[^,]*}}, [[ENUMS:![0-9]*]], {{.*}}} ; [ DW_TAG_compile_unit ]
+// CHECK: [[ENUMS]] = !{[[E1:![0-9]*]], [[E2:![0-9]*]], [[E3:![0-9]*]]}
namespace test1 {
-// CHECK: [[E1]] = metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST1:![0-9]*]], {{.*}}, metadata [[TEST1_ENUMS:![0-9]*]], {{[^,]*}}, null, null, metadata !"_ZTSN5test11eE"} ; [ DW_TAG_enumeration_type ] [e]
+// CHECK: [[E1]] = !{!"0x4\00{{.*}}", {{[^,]*}}, [[TEST1:![0-9]*]], {{.*}}, [[TEST1_ENUMS:![0-9]*]], null, null, !"_ZTSN5test11eE"} ; [ DW_TAG_enumeration_type ] [e]
// CHECK: [[TEST1]] = {{.*}} ; [ DW_TAG_namespace ] [test1]
-// CHECK: [[TEST1_ENUMS]] = metadata !{metadata [[TEST1_E:![0-9]*]]}
-// CHECK: [[TEST1_E]] = {{.*}}, metadata !"E", i64 0} ; [ DW_TAG_enumerator ] [E :: 0]
+// CHECK: [[TEST1_ENUMS]] = !{[[TEST1_E:![0-9]*]]}
+// CHECK: [[TEST1_E]] = !{!"0x28\00E\000"} ; [ DW_TAG_enumerator ] [E :: 0]
enum e { E };
void foo() {
int v = E;
@@ -16,7 +16,7 @@ void foo() {
namespace test2 {
// rdar://8195980
-// CHECK: [[E2]] = metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST2:![0-9]*]], {{.*}}, metadata [[TEST1_ENUMS]], {{[^,]*}}, null, null, metadata !"_ZTSN5test21eE"} ; [ DW_TAG_enumeration_type ] [e]
+// CHECK: [[E2]] = !{!"0x4\00{{.*}}", {{[^,]*}}, [[TEST2:![0-9]*]], {{.*}}, [[TEST1_ENUMS]], null, null, !"_ZTSN5test21eE"} ; [ DW_TAG_enumeration_type ] [e]
// CHECK: [[TEST2]] = {{.*}} ; [ DW_TAG_namespace ] [test2]
enum e { E };
bool func(int i) {
@@ -25,10 +25,10 @@ bool func(int i) {
}
namespace test3 {
-// CHECK: [[E3]] = metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST3:![0-9]*]], {{.*}}, metadata [[TEST3_ENUMS:![0-9]*]], {{[^,]*}}, null, null, metadata !"_ZTSN5test31eE"} ; [ DW_TAG_enumeration_type ] [e]
+// CHECK: [[E3]] = !{!"0x4\00{{.*}}", {{[^,]*}}, [[TEST3:![0-9]*]], {{.*}}, [[TEST3_ENUMS:![0-9]*]], null, null, !"_ZTSN5test31eE"} ; [ DW_TAG_enumeration_type ] [e]
// CHECK: [[TEST3]] = {{.*}} ; [ DW_TAG_namespace ] [test3]
-// CHECK: [[TEST3_ENUMS]] = metadata !{metadata [[TEST3_E:![0-9]*]]}
-// CHECK: [[TEST3_E]] = {{.*}}, metadata !"E", i64 -1} ; [ DW_TAG_enumerator ] [E :: -1]
+// CHECK: [[TEST3_ENUMS]] = !{[[TEST3_E:![0-9]*]]}
+// CHECK: [[TEST3_E]] = !{!"0x28\00E\00-1"} ; [ DW_TAG_enumerator ] [E :: -1]
enum e { E = -1 };
void func() {
e x;
diff --git a/test/CodeGenCXX/debug-info-flex-member.cpp b/test/CodeGenCXX/debug-info-flex-member.cpp
index 11329aa1e2b9..bc501c016847 100644
--- a/test/CodeGenCXX/debug-info-flex-member.cpp
+++ b/test/CodeGenCXX/debug-info-flex-member.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
-// CHECK: metadata !{i32 {{.*}}, i64 0, i64 -1} ; [ DW_TAG_subrange_type ]
+// CHECK: !"0x21\000\00-1"} ; [ DW_TAG_subrange_type ]
struct StructName {
int member[];
diff --git a/test/CodeGenCXX/debug-info-function-context.cpp b/test/CodeGenCXX/debug-info-function-context.cpp
index e65d3289f8b1..a6c5a115fc07 100644
--- a/test/CodeGenCXX/debug-info-function-context.cpp
+++ b/test/CodeGenCXX/debug-info-function-context.cpp
@@ -25,12 +25,12 @@ int global_namespace_variable = 1;
// functions that belong to the namespace have it as a context, and the global
// function has the file as a context.
-// CHECK: metadata !"_ZTS1C", metadata !"member_function"{{.*}} [ DW_TAG_subprogram ] [line 11] [def] [member_function]
+// CHECK: !"0x2e\00member_function\00{{.*}}", !{{[0-9]+}}, !"_ZTS1C"{{.*}} [ DW_TAG_subprogram ] [line 11] [def] [member_function]
-// CHECK: metadata !"_ZTS1C", metadata !"static_member_function"{{.*}} [ DW_TAG_subprogram ] [line 13] [def] [static_member_function]
+// CHECK: !"0x2e\00static_member_function\00{{.*}}", !{{[0-9]+}}, !"_ZTS1C"{{.*}} [ DW_TAG_subprogram ] [line 13] [def] [static_member_function]
-// CHECK: metadata [[FILE:![0-9]*]], metadata !"global_function"{{.*}} [ DW_TAG_subprogram ] [line 17] [def] [global_function]
+// CHECK: !"0x2e\00global_function\00{{[^,]+}}", !{{[0-9]+}}, [[FILE:![0-9]*]]{{.*}} [ DW_TAG_subprogram ] [line 17] [def] [global_function]
// CHECK: [[FILE]] = {{.*}} [ DW_TAG_file_type ]
-// CHECK: metadata [[NS:![0-9]*]], metadata !"global_namespace_function"{{.*}} [ DW_TAG_subprogram ] [line 20] [def] [global_namespace_function]
+// CHECK: !"0x2e\00global_namespace_function\00{{[^,]+}}", !{{[0-9]+}}, [[NS:![0-9]*]]{{.*}} [ DW_TAG_subprogram ] [line 20] [def] [global_namespace_function]
// CHECK: [[NS]] = {{.*}} [ DW_TAG_namespace ] [ns] [line 19]
diff --git a/test/CodeGenCXX/debug-info-global.cpp b/test/CodeGenCXX/debug-info-global.cpp
index 8dc30c892316..5fc61c7c4d45 100644
--- a/test/CodeGenCXX/debug-info-global.cpp
+++ b/test/CodeGenCXX/debug-info-global.cpp
@@ -10,10 +10,10 @@ int f1() {
return ns::cnst + ns::cnst;
}
-// CHECK: metadata [[GLOBALS:![0-9]*]], metadata {{![0-9]*}}, metadata !"{{.*}}", i32 {{[0-9]*}}} ; [ DW_TAG_compile_unit ]
+// CHECK: !"0x11\00{{.*}}"{{.*}}, [[GLOBALS:![0-9]*]], {{![0-9]*}}} ; [ DW_TAG_compile_unit ]
-// CHECK: [[GLOBALS]] = metadata !{metadata [[CNST:![0-9]*]]}
+// CHECK: [[GLOBALS]] = !{[[CNST:![0-9]*]]}
-// CHECK: [[CNST]] = {{.*}}, metadata [[NS:![0-9]*]], metadata !"cnst", {{.*}}; [ DW_TAG_variable ] [cnst]
+// CHECK: [[CNST]] = !{!"0x34\00cnst\00{{.*}}", [[NS:![0-9]*]], {{[^,]+, [^,]+, [^,]+, [^,]+}}} ; [ DW_TAG_variable ] [cnst]
// CHECK: [[NS]] = {{.*}}; [ DW_TAG_namespace ] [ns]
diff --git a/test/CodeGenCXX/debug-info-globalinit.cpp b/test/CodeGenCXX/debug-info-globalinit.cpp
index 30c8bfc680eb..efba958c9ed0 100644
--- a/test/CodeGenCXX/debug-info-globalinit.cpp
+++ b/test/CodeGenCXX/debug-info-globalinit.cpp
@@ -34,5 +34,5 @@ int main(void) {}
// CHECK-NOT: __cxx_global_var_init
// CHECK: store i32 %[[C2]], i32* @_ZL1k, align 4, !dbg
//
-// CHECK: ![[LINE]] = metadata !{i32 13, i32
-// CHECK: ![[LINE2]] = metadata !{i32 15, i32
+// CHECK: ![[LINE]] = !MDLocation(line: 13,
+// CHECK: ![[LINE2]] = !MDLocation(line: 15,
diff --git a/test/CodeGenCXX/debug-info-line-if.cpp b/test/CodeGenCXX/debug-info-line-if.cpp
index e14090f03f98..d0205af92bf4 100644
--- a/test/CodeGenCXX/debug-info-line-if.cpp
+++ b/test/CodeGenCXX/debug-info-line-if.cpp
@@ -1,20 +1,55 @@
// RUN: %clang_cc1 -g -std=c++11 -S -emit-llvm %s -o - | FileCheck %s
// PR19864
+extern int v[2];
+int a = 0, b = 0;
int main() {
- int v[] = {13, 21, 8, 3, 34, 1, 5, 2};
- int a = 0, b = 0;
- for (int x : v)
- if (x >= 3)
- ++b; // CHECK: add nsw{{.*}}, 1
- else if (x >= 0)
- ++a; // CHECK: add nsw{{.*}}, 1
- // The continuation block if the if statement should not share the
- // location of the ++a statement. Having it point to the end of
- // the condition is not ideal either, but it's less missleading.
-
- // CHECK: br label
- // CHECK: br label
- // CHECK: br label {{.*}}, !dbg ![[DBG:.*]]
- // CHECK: ![[DBG]] = metadata !{i32 [[@LINE-11]], i32 0, metadata !{{.*}}, null}
+#line 100
+ for (int x : v)
+ if (x)
+ ++b; // CHECK: add nsw{{.*}}, 1
+ else
+ ++a; // CHECK: add nsw{{.*}}, 1
+ // The continuation block if the if statement should not share the
+ // location of the ++a statement. The branch back to the start of the loop
+ // should be attributed to the loop header line.
+ // CHECK: br label
+ // CHECK: br label
+ // CHECK: br label {{.*}}, !dbg [[DBG1:!.*]]
+
+#line 200
+ while (a)
+ if (b)
+ ++b; // CHECK: add nsw{{.*}}, 1
+ else
+ ++a; // CHECK: add nsw{{.*}}, 1
+
+ // CHECK: br label
+ // CHECK: br label {{.*}}, !dbg [[DBG2:!.*]]
+
+#line 300
+ for (; a; )
+ if (b)
+ ++b; // CHECK: add nsw{{.*}}, 1
+ else
+ ++a; // CHECK: add nsw{{.*}}, 1
+
+ // CHECK: br label
+ // CHECK: br label {{.*}}, !dbg [[DBG3:!.*]]
+
+#line 400
+ int x[] = {1, 2};
+ for (int y : x)
+ if (b)
+ ++b; // CHECK: add nsw{{.*}}, 1
+ else
+ ++a; // CHECK: add nsw{{.*}}, 1
+
+ // CHECK: br label
+ // CHECK: br label {{.*}}, !dbg [[DBG4:!.*]]
+
+ // CHECK: [[DBG1]] = !MDLocation(line: 100, scope: !{{.*}})
+ // CHECK: [[DBG2]] = !MDLocation(line: 200, scope: !{{.*}})
+ // CHECK: [[DBG3]] = !MDLocation(line: 300, scope: !{{.*}})
+ // CHECK: [[DBG4]] = !MDLocation(line: 401, scope: !{{.*}})
}
diff --git a/test/CodeGenCXX/debug-info-line.cpp b/test/CodeGenCXX/debug-info-line.cpp
new file mode 100644
index 000000000000..a5cc6392b4fc
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-line.cpp
@@ -0,0 +1,187 @@
+// RUN: %clang_cc1 -gline-tables-only -std=c++11 -fexceptions -fcxx-exceptions -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -gline-tables-only -std=c++11 -fexceptions -fcxx-exceptions -S -emit-llvm %s -o - -triple i686-linux-gnu | FileCheck %s
+
+// XFAIL: win32
+
+int &src();
+int *sink();
+extern "C" __complex float complex_src();
+extern "C" __complex float *complex_sink();
+
+// CHECK-LABEL: define
+void f1() {
+#line 100
+ * // The store for the assignment should be attributed to the start of the
+ // assignment expression here, regardless of the location of subexpressions.
+ sink() = src();
+ // CHECK: store {{.*}}, !dbg [[DBG_F1:!.*]]
+}
+
+struct foo {
+ int i;
+ int &j;
+ __complex float k;
+ foo();
+};
+
+// CHECK-LABEL: define
+foo::foo()
+ :
+#line 200
+ i // CHECK: store i32 {{.*}} !dbg [[DBG_FOO_VALUE:!.*]]
+ (src()),
+ j // CHECK: store i32* {{.*}} !dbg [[DBG_FOO_REF:!.*]]
+ (src()),
+ k // CHECK: store float {{.*}} !dbg [[DBG_FOO_COMPLEX:!.*]]
+ (complex_src()) {
+}
+
+// CHECK-LABEL: define {{.*}}f2{{.*}}
+void f2() {
+#line 300
+ * // CHECK: store float {{.*}} !dbg [[DBG_F2:!.*]]
+ complex_sink() = complex_src();
+}
+
+// CHECK-LABEL: define
+void f3() {
+#line 400
+ * // CHECK: store float {{.*}} !dbg [[DBG_F3:!.*]]
+ complex_sink() += complex_src();
+}
+
+// CHECK-LABEL: define
+void f4() {
+#line 500
+ auto x // CHECK: store {{.*}} !dbg [[DBG_F4:!.*]]
+ = src();
+}
+
+// CHECK-LABEL: define
+void f5() {
+#line 600
+ auto x // CHECK: store float {{.*}} !dbg [[DBG_F5:!.*]]
+ = complex_src();
+}
+
+struct agg { int i; };
+agg agg_src();
+
+// CHECK-LABEL: define
+void f6() {
+ agg x;
+#line 700
+ x // CHECK: call void @llvm.memcpy{{.*}} !dbg [[DBG_F6:!.*]]
+ = agg_src();
+}
+
+// CHECK-LABEL: define
+void f7() {
+ int *src1();
+ int src2();
+#line 800
+ int x = ( // CHECK: load {{.*}} !dbg [[DBG_F7:!.*]]
+ src1())[src2()];
+}
+
+// CHECK-LABEL: define
+void f8() {
+ int src1[1];
+ int src2();
+#line 900
+ int x = ( // CHECK: load {{.*}} !dbg [[DBG_F8:!.*]]
+ src1)[src2()];
+}
+
+// CHECK-LABEL: define
+void f9(int i) {
+ int src1[1][i];
+ int src2();
+#line 1000
+ auto x = ( // CHECK: getelementptr {{.*}} !dbg [[DBG_F9:!.*]]
+ src1)[src2()];
+}
+
+inline void *operator new(decltype(sizeof(1)), void *p) noexcept { return p; }
+
+// CHECK-LABEL: define
+void f10() {
+ void *void_src();
+ ( // CHECK: icmp {{.*}} !dbg [[DBG_F10_ICMP:.*]]
+ // CHECK: store {{.*}} !dbg [[DBG_F10_STORE:!.*]]
+#line 1100
+ new (void_src()) int(src()));
+}
+
+// noexcept just to simplify the codegen a bit
+void fn() noexcept(true);
+
+struct bar {
+ bar();
+ // noexcept(false) to convolute the global dtor
+ ~bar() noexcept(false);
+};
+// global ctor cleanup
+// CHECK-LABEL: define
+// CHECK: invoke{{ }}
+// CHECK: invoke{{ }}
+// CHECK: to label {{.*}}, !dbg [[DBG_GLBL_CTOR_B:!.*]]
+
+// terminate caller
+// CHECK-LABEL: define
+
+// global dtor cleanup
+// CHECK-LABEL: define
+// CHECK: invoke{{ }}
+// CHECK: invoke{{ }}
+// CHECK: to label {{.*}}, !dbg [[DBG_GLBL_DTOR_B:!.*]]
+#line 1500
+bar b[1] = { //
+ (fn(), //
+ bar())};
+
+// CHECK-LABEL: define
+__complex double f11() {
+ __complex double f;
+// CHECK: store {{.*}} !dbg [[DBG_F11:!.*]]
+#line 1200
+ return f;
+}
+
+// CHECK-LABEL: define
+void f12() {
+ int f12_1();
+ void f12_2(int = f12_1());
+// CHECK: call {{(signext )?}}i32 {{.*}} !dbg [[DBG_F12:!.*]]
+#line 1300
+ f12_2();
+}
+
+// CHECK-LABEL: define
+void f13() {
+// CHECK: call {{.*}} !dbg [[DBG_F13:!.*]]
+#define F13_IMPL 1, src()
+ 1,
+#line 1400
+ F13_IMPL;
+}
+
+// CHECK: [[DBG_F1]] = !MDLocation(line: 100,
+// CHECK: [[DBG_FOO_VALUE]] = !MDLocation(line: 200,
+// CHECK: [[DBG_FOO_REF]] = !MDLocation(line: 202,
+// CHECK: [[DBG_FOO_COMPLEX]] = !MDLocation(line: 204,
+// CHECK: [[DBG_F2]] = !MDLocation(line: 300,
+// CHECK: [[DBG_F3]] = !MDLocation(line: 400,
+// CHECK: [[DBG_F4]] = !MDLocation(line: 500,
+// CHECK: [[DBG_F5]] = !MDLocation(line: 600,
+// CHECK: [[DBG_F6]] = !MDLocation(line: 700,
+// CHECK: [[DBG_F7]] = !MDLocation(line: 800,
+// CHECK: [[DBG_F8]] = !MDLocation(line: 900,
+// CHECK: [[DBG_F9]] = !MDLocation(line: 1000,
+// CHECK: [[DBG_F10_ICMP]] = !MDLocation(line: 1100,
+// CHECK: [[DBG_F10_STORE]] = !MDLocation(line: 1100,
+// CHECK: [[DBG_GLBL_CTOR_B]] = !MDLocation(line: 1500,
+// CHECK: [[DBG_GLBL_DTOR_B]] = !MDLocation(line: 1500,
+// CHECK: [[DBG_F11]] = !MDLocation(line: 1200,
+// CHECK: [[DBG_F12]] = !MDLocation(line: 1300,
+// CHECK: [[DBG_F13]] = !MDLocation(line: 1400,
diff --git a/test/CodeGenCXX/debug-info-method.cpp b/test/CodeGenCXX/debug-info-method.cpp
index 49b8dc47855d..bb69a6516507 100644
--- a/test/CodeGenCXX/debug-info-method.cpp
+++ b/test/CodeGenCXX/debug-info-method.cpp
@@ -1,14 +1,14 @@
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -g %s -o - | FileCheck %s
-// CHECK: metadata !"_ZTS1A"} ; [ DW_TAG_class_type ] [A]
-// CHECK: metadata !"_ZN1A3fooEiS_3$_0", {{.*}} [protected]
+// CHECK: !"_ZTS1A"} ; [ DW_TAG_class_type ] [A]
+// CHECK: !"{{.*}}\00_ZN1A3fooEiS_3$_0\00{{.*}}", {{.*}} [protected]
// CHECK: ![[THISTYPE:[0-9]+]] = {{.*}} ; [ DW_TAG_pointer_type ] {{.*}} [artificial] [from _ZTS1A]
-// CHECK: DW_TAG_ptr_to_member_type
-// CHECK: {{.*}}metadata ![[MEMFUNTYPE:[0-9]+]], metadata !{{.*}}} ; [ DW_TAG_ptr_to_member_type ] {{.*}} [from ]
-// CHECK: ![[MEMFUNTYPE]] = {{.*}}metadata ![[MEMFUNARGS:[0-9]+]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] {{.*}} [from ]
-// CHECK: ![[MEMFUNARGS]] = {{.*}}, metadata ![[THISTYPE]],
-// CHECK: ""{{.*}}DW_TAG_arg_variable
-// CHECK: ""{{.*}}DW_TAG_arg_variable
-// CHECK: ""{{.*}}DW_TAG_arg_variable
+// CHECK: [ DW_TAG_ptr_to_member_type ] [line {{[0-9]+}}, size {{[1-9][0-9]+}}, align
+// CHECK: {{.*}}![[MEMFUNTYPE:[0-9]+]], !{{.*}}} ; [ DW_TAG_ptr_to_member_type ] {{.*}} [from ]
+// CHECK: ![[MEMFUNTYPE]] = {{.*}}![[MEMFUNARGS:[0-9]+]], null, null, null} ; [ DW_TAG_subroutine_type ] {{.*}} [from ]
+// CHECK: ![[MEMFUNARGS]] = {{.*}}, ![[THISTYPE]],
+// CHECK: !"0x101\00\00{{.*}}"{{.*}} DW_TAG_arg_variable
+// CHECK: !"0x101\00\00{{.*}}"{{.*}} DW_TAG_arg_variable
+// CHECK: !"0x101\00\00{{.*}}"{{.*}} DW_TAG_arg_variable
union {
int a;
float b;
diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp
index a1284d2d2771..60d508bcb735 100644
--- a/test/CodeGenCXX/debug-info-namespace.cpp
+++ b/test/CodeGenCXX/debug-info-namespace.cpp
@@ -5,12 +5,16 @@
namespace A {
#line 1 "foo.cpp"
namespace B {
-int i;
-void f1() { }
+extern int i;
+int f1() { return 0; }
void f1(int) { }
struct foo;
struct bar { };
typedef bar baz;
+extern int var_decl;
+void func_decl(void);
+extern int var_fwd;
+void func_fwd(void);
}
}
namespace A {
@@ -19,7 +23,7 @@ using namespace B;
using namespace A;
namespace E = A;
-
+int B::i = f1();
int func(bool b) {
if (b) {
using namespace A::B;
@@ -33,51 +37,65 @@ int func(bool b) {
using B::baz;
namespace X = A;
namespace Y = X;
+ using B::var_decl;
+ using B::func_decl;
+ using B::var_fwd;
+ using B::func_fwd;
return i + X::B::i + Y::B::i;
}
namespace A {
using B::i;
+namespace B {
+int var_fwd = i;
+}
}
+void B::func_fwd() {}
// This should work even if 'i' and 'func' were declarations & not definitions,
// but it doesn't yet.
-// CHECK: [[CU:![0-9]*]] = {{.*}}[[MODULES:![0-9]*]], metadata !"", i32 1} ; [ DW_TAG_compile_unit ]
+// CHECK: [[CU:![0-9]*]] = !{!"0x11\00{{.*}}\001"{{.*}}, [[MODULES:![0-9]*]]} ; [ DW_TAG_compile_unit ]
// CHECK: [[FOO:![0-9]*]] {{.*}} ; [ DW_TAG_structure_type ] [foo] [line 5, size 0, align 0, offset 0] [decl] [from ]
-// CHECK: [[FOOCPP:![0-9]*]] = metadata !{metadata !"foo.cpp", {{.*}}
-// CHECK: [[NS:![0-9]*]] = {{.*}}, metadata [[FILE2:![0-9]*]], metadata [[CTXT:![0-9]*]], {{.*}} ; [ DW_TAG_namespace ] [B] [line 1]
-// CHECK: [[CTXT]] = {{.*}}, metadata [[FILE:![0-9]*]], null, {{.*}} ; [ DW_TAG_namespace ] [A] [line 5]
+// CHECK: [[FOOCPP:![0-9]*]] = !{!"foo.cpp", {{.*}}
+// CHECK: [[NS:![0-9]*]] = !{!"0x39\00B\001", [[FILE2:![0-9]*]], [[CTXT:![0-9]*]]} ; [ DW_TAG_namespace ] [B] [line 1]
+// CHECK: [[CTXT]] = !{!"0x39\00A\005", [[FILE:![0-9]*]], null} ; [ DW_TAG_namespace ] [A] [line 5]
// CHECK: [[FILE]] {{.*}}debug-info-namespace.cpp"
// CHECK: [[BAR:![0-9]*]] {{.*}} ; [ DW_TAG_structure_type ] [bar] [line 6, {{.*}}] [decl] [from ]
// CHECK: [[F1:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 4] [def] [f1]
-// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
// CHECK: [[FILE2]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp]
-// CHECK: [[I:![0-9]*]] = {{.*}}, metadata [[NS]], metadata !"i", {{.*}} ; [ DW_TAG_variable ] [i]
-// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]], metadata [[M5:![0-9]*]], metadata [[M6:![0-9]*]], metadata [[M7:![0-9]*]], metadata [[M8:![0-9]*]], metadata [[M9:![0-9]*]], metadata [[M10:![0-9]*]], metadata [[M11:![0-9]*]], metadata [[M12:![0-9]*]], metadata [[M13:![0-9]*]]}
-// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 11} ; [ DW_TAG_imported_module ]
-// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_module ]
-// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 15, metadata !"E"} ; [ DW_TAG_imported_declaration ]
-// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX2:![0-9]*]], metadata [[NS]], i32 19} ; [ DW_TAG_imported_module ]
-// CHECK: [[LEX2]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[LEX1:![0-9]+]], i32 {{[0-9]*}}, i32 0, i32 {{.*}}} ; [ DW_TAG_lexical_block ]
-// CHECK: [[LEX1]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 {{[0-9]*}}, i32 0, i32 {{.*}}} ; [ DW_TAG_lexical_block ]
-// CHECK: [[M5]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_module ]
-// CHECK: [[M6]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[FOO:!"_ZTSN1A1B3fooE"]], i32 23} ; [ DW_TAG_imported_declaration ]
-// CHECK: [[M7]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAR:!"_ZTSN1A1B3barE"]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
-// CHECK: [[M8]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[F1]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
-// CHECK: [[M9]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[I]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
-// CHECK: [[M10]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAZ:![0-9]*]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
-// CHECK: [[BAZ]] = metadata !{i32 {{[0-9]*}}, metadata [[FOOCPP]], metadata [[NS]], {{.*}}, metadata !"_ZTSN1A1B3barE"} ; [ DW_TAG_typedef ] [baz] {{.*}} [from _ZTSN1A1B3barE]
-// CHECK: [[M11]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 {{[0-9]*}}, metadata !"X"} ; [ DW_TAG_imported_declaration ]
-// CHECK: [[M12]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[M11]], i32 {{[0-9]*}}, metadata !"Y"} ; [ DW_TAG_imported_declaration ]
-// CHECK: [[M13]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[I]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
+// CHECK: [[FUNC_FWD:![0-9]*]] {{.*}} [ DW_TAG_subprogram ] [line 47] [def] [func_fwd]
+// CHECK: [[I:![0-9]*]] = !{!"0x34\00i\00{{.*}}", [[NS]], {{.*}} ; [ DW_TAG_variable ] [i]
+// CHECK: [[VAR_FWD:![0-9]*]] = !{!"0x34\00var_fwd\00{{.*}}", [[NS]], {{.*}}} ; [ DW_TAG_variable ] [var_fwd] [line 44] [def]
-// CHECK-GMLT: [[CU:![0-9]*]] = {{.*}}[[MODULES:![0-9]*]], metadata !"", i32 2} ; [ DW_TAG_compile_unit ]
-// CHECK-GMLT: [[MODULES]] = metadata !{}
+// CHECK: [[MODULES]] = !{[[M1:![0-9]*]], [[M2:![0-9]*]], [[M3:![0-9]*]], [[M4:![0-9]*]], [[M5:![0-9]*]], [[M6:![0-9]*]], [[M7:![0-9]*]], [[M8:![0-9]*]], [[M9:![0-9]*]], [[M10:![0-9]*]], [[M11:![0-9]*]], [[M12:![0-9]*]], [[M13:![0-9]*]], [[M14:![0-9]*]], [[M15:![0-9]*]], [[M16:![0-9]*]], [[M17:![0-9]*]]}
+// CHECK: [[M1]] = !{!"0x3a\0015\00", [[CTXT]], [[NS]]} ; [ DW_TAG_imported_module ]
+// CHECK: [[M2]] = !{!"0x3a\00{{[0-9]+}}\00", [[CU]], [[CTXT]]} ; [ DW_TAG_imported_module ]
+// CHECK: [[M3]] = !{!"0x8\0019\00E", [[CU]], [[CTXT]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M4]] = !{!"0x3a\0023\00", [[LEX2:![0-9]*]], [[NS]]} ; [ DW_TAG_imported_module ]
+// CHECK: [[LEX2]] = !{!"0xb\00{{[0-9]*}}\000\00{{.*}}", [[FILE2]], [[LEX1:![0-9]+]]} ; [ DW_TAG_lexical_block ]
+// CHECK: [[LEX1]] = !{!"0xb\00{{[0-9]*}}\000\00{{.*}}", [[FILE2]], [[FUNC]]} ; [ DW_TAG_lexical_block ]
+// CHECK: [[M5]] = !{!"0x3a\00{{[0-9]+}}\00", [[FUNC]], [[CTXT]]} ; [ DW_TAG_imported_module ]
+// CHECK: [[M6]] = !{!"0x8\0027\00", [[FUNC]], [[FOO:!"_ZTSN1A1B3fooE"]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M7]] = !{!"0x8\00{{[0-9]+}}\00", [[FUNC]], [[BAR:!"_ZTSN1A1B3barE"]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M8]] = !{!"0x8\00{{[0-9]+}}\00", [[FUNC]], [[F1]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M9]] = !{!"0x8\00{{[0-9]+}}\00", [[FUNC]], [[I]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M10]] = !{!"0x8\00{{[0-9]+}}\00", [[FUNC]], [[BAZ:![0-9]*]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[BAZ]] = !{!"0x16\00baz\00{{.*}}", [[FOOCPP]], [[NS]], !"_ZTSN1A1B3barE"} ; [ DW_TAG_typedef ] [baz] {{.*}} [from _ZTSN1A1B3barE]
+// CHECK: [[M11]] = !{!"0x8\00{{[0-9]+}}\00X", [[FUNC]], [[CTXT]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M12]] = !{!"0x8\00{{[0-9]+}}\00Y", [[FUNC]], [[M11]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M13]] = !{!"0x8\00{{[0-9]+}}\00", [[FUNC]], [[VAR_DECL:![0-9]*]]} ; [ DW_TAG_imported_declaration ]
+// CHECK [[VAR_DECL]] = !{!"0x34\00var_decl\00{{.*}}", [[NS]], {{.*}}} ; [ DW_TAG_variable ] [var_decl] [line 8]
+// CHECK: [[M14]] = !{!"0x8\00{{[0-9]+}}\00", [[FUNC]], [[FUNC_DECL:![0-9]*]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[FUNC_DECL]] = !{!"0x2e\00func_decl\00{{.*}}", [[FOOCPP]], [[NS]], {{.*}}} ; [ DW_TAG_subprogram ] [line 9] [scope 0] [func_decl]
+// CHECK: [[M15]] = !{!"0x8\00{{[0-9]+}}\00", [[FUNC]], [[VAR_FWD:![0-9]*]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M16]] = !{!"0x8\00{{[0-9]+}}\00", [[FUNC]], [[FUNC_FWD:![0-9]*]]} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M17]] = !{!"0x8\00{{[0-9]+}}\00", [[CTXT]], [[I]]} ; [ DW_TAG_imported_declaration ]
+// CHECK-GMLT: [[CU:![0-9]*]] = !{!"0x11\00{{.*}}\002"{{.*}}, [[MODULES:![0-9]*]]} ; [ DW_TAG_compile_unit ]
+// CHECK-GMLT: [[MODULES]] = !{}
// CHECK-NOLIMIT: ; [ DW_TAG_structure_type ] [bar] [line 6, {{.*}}] [def] [from ]
-// FIXME: It is confused on win32 to generate file entry when dosish filename is given.
-// REQUIRES: shell
// REQUIRES: shell-preserves-root
// REQUIRES: dw2
diff --git a/test/CodeGenCXX/debug-info-ptr-to-member-function.cpp b/test/CodeGenCXX/debug-info-ptr-to-member-function.cpp
new file mode 100644
index 000000000000..656e6f495880
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-ptr-to-member-function.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin -g -emit-llvm -o - | FileCheck %s
+
+struct T {
+ int method();
+};
+
+void foo(int (T::*method)()) {}
+
+// A pointer to a member function is a pair of function- and this-pointer.
+// CHECK: [ DW_TAG_ptr_to_member_type ] {{.*}} size 128
diff --git a/test/CodeGenCXX/debug-info-qualifiers.cpp b/test/CodeGenCXX/debug-info-qualifiers.cpp
index c6b935f9039a..2655bd9d726f 100644
--- a/test/CodeGenCXX/debug-info-qualifiers.cpp
+++ b/test/CodeGenCXX/debug-info-qualifiers.cpp
@@ -2,25 +2,25 @@
// Test (r)value and CVR qualifiers on C++11 non-static member functions.
class A {
public:
- // CHECK: i32 [[@LINE+2]], metadata ![[PLSR:[0-9]+]], {{.*}}[ DW_TAG_subprogram ] [line [[@LINE+2]]] [reference] [l]
+ // CHECK: !"0x2e\00l\00{{.*}}\00[[@LINE+2]]"{{, [^,]+, [^,]+}}, ![[PLSR:[0-9]+]], {{.*}}[ DW_TAG_subprogram ] [line [[@LINE+2]]] [public] [reference] [l]
// CHECK: ![[PLSR]] ={{.*}}[ DW_TAG_subroutine_type ]{{.*}}[reference]
void l() const &;
- // CHECK: ![[ARGS:[0-9]+]] = metadata !{null, metadata ![[THIS:[0-9]+]]}
- // CHECK: ![[THIS]] = {{.*}} metadata ![[CONST_A:.*]]} ; [ DW_TAG_pointer_type ]
+ // CHECK: ![[ARGS:[0-9]+]] = !{null, ![[THIS:[0-9]+]]}
+ // CHECK: ![[THIS]] = {{.*}} ![[CONST_A:.*]]} ; [ DW_TAG_pointer_type ]
// CHECK: ![[CONST_A]] = {{.*}} [ DW_TAG_const_type ]
- // CHECK: i32 [[@LINE+2]], metadata ![[PRSR:[0-9]+]], {{.*}}[ DW_TAG_subprogram ] [line [[@LINE+2]]] [rvalue reference] [r]
- // CHECK: ![[PRSR]] ={{.*}}metadata ![[ARGS]], i32 0, null, null, null}{{.*}}[ DW_TAG_subroutine_type ]{{.*}}[rvalue reference]
+ // CHECK: !"0x2e\00r\00{{.*}}\00[[@LINE+2]]"{{, [^,]+, [^,]+}}, ![[PRSR:[0-9]+]], {{.*}}[ DW_TAG_subprogram ] [line [[@LINE+2]]] [public] [rvalue reference] [r]
+ // CHECK: ![[PRSR]] ={{.*}}![[ARGS]], null, null, null}{{.*}}[ DW_TAG_subroutine_type ]{{.*}}[rvalue reference]
void r() const &&;
};
void g() {
A a;
// The type of pl is "void (A::*)() const &".
- // CHECK: metadata ![[PL:[0-9]+]], i32 0, i32 0} ; [ DW_TAG_auto_variable ] [pl] [line [[@LINE+2]]]
- // CHECK: metadata ![[PLSR]], metadata !"{{.*}}"} ; [ DW_TAG_ptr_to_member_type ]
+ // CHECK: ![[PL:[0-9]+]]} ; [ DW_TAG_auto_variable ] [pl] [line [[@LINE+2]]]
+ // CHECK: ![[PLSR]], !"{{.*}}"} ; [ DW_TAG_ptr_to_member_type ]
auto pl = &A::l;
- // CHECK: metadata ![[PR:[0-9]+]], i32 0, i32 0} ; [ DW_TAG_auto_variable ] [pr] [line [[@LINE+2]]]
- // CHECK: metadata ![[PRSR]], metadata !"{{.*}}"} ; [ DW_TAG_ptr_to_member_type ]
+ // CHECK: ![[PR:[0-9]+]]} ; [ DW_TAG_auto_variable ] [pr] [line [[@LINE+2]]]
+ // CHECK: ![[PRSR]], !"{{.*}}"} ; [ DW_TAG_ptr_to_member_type ]
auto pr = &A::r;
}
diff --git a/test/CodeGenCXX/debug-info-rvalue-ref.cpp b/test/CodeGenCXX/debug-info-rvalue-ref.cpp
index 142f587fc62d..36e4aa374244 100644
--- a/test/CodeGenCXX/debug-info-rvalue-ref.cpp
+++ b/test/CodeGenCXX/debug-info-rvalue-ref.cpp
@@ -8,4 +8,4 @@ void foo (int &&i)
printf("%d\n", i);
}
-// CHECK: metadata !{i32 {{.*}}, null, null, null, i32 0, i64 0, i64 0, i64 0, i32 0, metadata !{{.*}}} ; [ DW_TAG_rvalue_reference_type ]
+// CHECK: !"0x42\00\000\000\000\000\000", null, null, !{{.*}}} ; [ DW_TAG_rvalue_reference_type ]
diff --git a/test/CodeGenCXX/debug-info-scope.cpp b/test/CodeGenCXX/debug-info-scope.cpp
index 0447dc04d56b..e66588d699af 100644
--- a/test/CodeGenCXX/debug-info-scope.cpp
+++ b/test/CodeGenCXX/debug-info-scope.cpp
@@ -1,32 +1,55 @@
-// RUN: %clang_cc1 -g -emit-llvm %s -o -| FileCheck %s
+// RUN: %clang_cc1 -g -std=c++11 -emit-llvm %s -o -| FileCheck %s
//
// Two variables with the same name in subsequent if staments need to be in separate scopes.
//
// rdar://problem/14024005
-//
-int printf(const char*, ...);
+int src();
-char *return_char (int input)
-{
- if (input%2 == 0)
- return "I am even.\n";
- else
- return "I am odd.\n";
-}
+void f();
-int main2() {
-// CHECK: [ DW_TAG_auto_variable ] [ptr] [line [[@LINE+2]]]
-// CHECK: metadata !{i32 {{.*}}, metadata !{{.*}}, i32 [[@LINE+1]], {{.*}}} ; [ DW_TAG_lexical_block ]
- if (char *ptr = return_char(1)) {
- printf ("%s", ptr);
- }
-// CHECK: [ DW_TAG_auto_variable ] [ptr] [line [[@LINE+2]]]
-// CHECK: metadata !{i32 {{.*}}, metadata !{{.*}}, i32 [[@LINE+1]], {{.*}}} ; [ DW_TAG_lexical_block ]
- if (char *ptr = return_char(2)) {
- printf ("%s", ptr);
+void func() {
+ // CHECK: = !{!"0x100\00{{.*}}", [[IF1:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [i] [line [[@LINE+2]]]
+ // CHECK: [[IF1]] = !{!"0xb\00[[@LINE+1]]\00{{.*}}", !{{.*}}} ; [ DW_TAG_lexical_block ]
+ if (int i = src())
+ f();
+
+ // CHECK: = !{!"0x100\00{{.*}}", [[IF2:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [i] [line [[@LINE+2]]]
+ // CHECK: [[IF2]] = !{!"0xb\00[[@LINE+1]]\00{{.*}}", !{{.*}}} ; [ DW_TAG_lexical_block ]
+ if (int i = src()) {
+ f();
+ } else
+ f();
+
+ // CHECK: = !{!"0x100\00{{.*}}", [[FOR:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [i] [line [[@LINE+2]]]
+ // CHECK: [[FOR]] = !{!"0xb\00[[@LINE+1]]\00{{.*}}", !{{.*}}} ; [ DW_TAG_lexical_block ]
+ for (int i = 0;
+ // CHECK: = !{!"0x100\00{{.*}}", [[FOR_BODY:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [b] [line [[@LINE+6]]]
+ // The scope could be located at 'bool b', but LLVM drops line information for
+ // scopes anyway, so it's not terribly important.
+ // FIXME: change the debug info schema to not include locations of scopes,
+ // since they're not used.
+ // CHECK: [[FOR_BODY]] = !{!"0xb\00[[@LINE-6]]\00{{.*}}", !{{.*}}} ; [ DW_TAG_lexical_block ]
+ bool b = i != 10; ++i)
+ f();
+
+ // CHECK: = !{!"0x100\00{{.*}}", [[FOR:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [i] [line [[@LINE+2]]]
+ // CHECK: [[FOR]] = !{!"0xb\00[[@LINE+1]]\00{{.*}}", !{{.*}}} ; [ DW_TAG_lexical_block ]
+ for (int i = 0; i != 10; ++i) {
+ // FIXME: Do not include scopes that have only other scopes (and no variables
+ // or using declarations) as direct children, they just waste
+ // space/relocations/etc.
+ // CHECK: [[FOR_LOOP_INCLUDING_COND:!.*]] = !{!"0xb\00[[@LINE-4]]\00{{.*}}", !{{[0-9]+}}, [[FOR]]} ; [ DW_TAG_lexical_block ]
+ // CHECK: = !{!"0x100\00{{.*}}", [[FOR_COMPOUND:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [b] [line [[@LINE+2]]]
+ // CHECK: [[FOR_COMPOUND]] = !{!"0xb\00[[@LINE-6]]\00{{.*}}", !{{[0-9]+}}, [[FOR_LOOP_INCLUDING_COND]]} ; [ DW_TAG_lexical_block ]
+ bool b = i % 2;
}
- else printf ("%s", ptr);
- return 0;
+ int x[] = {1, 2};
+ // CHECK: = !{!"0x100\00{{.*}}", [[RANGE_FOR:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [__range] [line 0]
+ // CHECK: [[RANGE_FOR]] = !{!"0xb\00[[@LINE+1]]\00{{.*}}", !{{.*}}} ; [ DW_TAG_lexical_block ]
+ for (int i : x) {
+ // CHECK: = !{!"0x100\00{{.*}}", [[RANGE_FOR_BODY:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [i] [line [[@LINE-1]]]
+ // CHECK: [[RANGE_FOR_BODY]] = !{!"0xb\00[[@LINE-2]]\00{{.*}}", !{{[0-9]+}}, [[RANGE_FOR]]} ; [ DW_TAG_lexical_block ]
+ }
}
diff --git a/test/CodeGenCXX/debug-info-static-fns.cpp b/test/CodeGenCXX/debug-info-static-fns.cpp
index 136261cdbc0d..41b713cc0674 100644
--- a/test/CodeGenCXX/debug-info-static-fns.cpp
+++ b/test/CodeGenCXX/debug-info-static-fns.cpp
@@ -7,4 +7,4 @@ namespace A {
}
// Verify that a is present and mangled.
-// CHECK: metadata !"_ZN1AL1aEi", {{.*}}, i32 (i32)* @_ZN1AL1aEi, {{.*}} ; [ DW_TAG_subprogram ] [line 4] [local] [def] [a]
+// CHECK: !"0x2e\00a\00a\00_ZN1AL1aEi\00{{.*}}", {{.*}}, i32 (i32)* @_ZN1AL1aEi, {{.*}} ; [ DW_TAG_subprogram ] [line 4] [local] [def] [a]
diff --git a/test/CodeGenCXX/debug-info-static-member.cpp b/test/CodeGenCXX/debug-info-static-member.cpp
index 1ac235c50f8e..18fd6915189a 100644
--- a/test/CodeGenCXX/debug-info-static-member.cpp
+++ b/test/CodeGenCXX/debug-info-static-member.cpp
@@ -33,15 +33,72 @@ int main()
// why the definition of "a" comes before the declarations while
// "b" and "c" come after.
-// CHECK: metadata !"_ZTS1X"} ; [ DW_TAG_enumeration_type ] [X]
-// CHECK: metadata !"_ZTS1C"} ; [ DW_TAG_class_type ] [C]
-// CHECK: ![[DECL_A:[0-9]+]] = metadata {{.*}} [ DW_TAG_member ] [a] [line {{.*}}, size 0, align 0, offset 0] [private] [static]
-// CHECK: metadata !"const_a", {{.*}}, i1 true} ; [ DW_TAG_member ] [const_a] [line {{.*}}, size 0, align 0, offset 0] [private] [static]
-// CHECK: ![[DECL_B:[0-9]+]] {{.*}} metadata !"b", {{.*}} [ DW_TAG_member ] [b] [line {{.*}}, size 0, align 0, offset 0] [protected] [static]
-// CHECK: metadata !"const_b", {{.*}}, float 0x{{.*}}} ; [ DW_TAG_member ] [const_b] [line {{.*}}, size 0, align 0, offset 0] [protected] [static]
-// CHECK: ![[DECL_C:[0-9]+]] {{.*}} metadata !"c", {{.*}} [ DW_TAG_member ] [c] [line {{.*}}, size 0, align 0, offset 0] [static]
-// CHECK: metadata !"const_c", {{.*}} [ DW_TAG_member ] [const_c] [line {{.*}}, size 0, align 0, offset 0] [static]
-// CHECK: metadata !"x_a", {{.*}} [ DW_TAG_member ] [x_a] {{.*}} [static]
-// CHECK: metadata !"a", {{.*}} @_ZN1C1aE, metadata ![[DECL_A]]} ; [ DW_TAG_variable ] [a] {{.*}} [def]
-// CHECK: metadata !"b", {{.*}} @_ZN1C1bE, metadata ![[DECL_B]]} ; [ DW_TAG_variable ] [b] {{.*}} [def]
-// CHECK: metadata !"c", {{.*}} @_ZN1C1cE, metadata ![[DECL_C]]} ; [ DW_TAG_variable ] [c] {{.*}} [def]
+// CHECK: !"_ZTS1X"} ; [ DW_TAG_enumeration_type ] [X]
+// CHECK: !"_ZTS1C"} ; [ DW_TAG_class_type ] [C]
+// CHECK: ![[DECL_A:[0-9]+]] = {{.*}} [ DW_TAG_member ] [a] [line {{.*}}, size 0, align 0, offset 0] [static]
+// CHECK: !"0xd\00const_a\00{{.*}}", {{.*}}, i1 true} ; [ DW_TAG_member ] [const_a] [line {{.*}}, size 0, align 0, offset 0] [static]
+// CHECK: ![[DECL_B:[0-9]+]] = !{!"0xd\00b\00{{.*}}", {{.*}} [ DW_TAG_member ] [b] [line {{.*}}, size 0, align 0, offset 0] [protected] [static]
+// CHECK: !"0xd\00const_b\00{{.*}}", {{.*}}, float 0x{{.*}}} ; [ DW_TAG_member ] [const_b] [line {{.*}}, size 0, align 0, offset 0] [protected] [static]
+// CHECK: ![[DECL_C:[0-9]+]] = !{!"0xd\00c\00{{.*}}", {{.*}} [ DW_TAG_member ] [c] [line {{.*}}, size 0, align 0, offset 0] [public] [static]
+// CHECK: !"0xd\00const_c\00{{.*}}", {{.*}} [ DW_TAG_member ] [const_c] [line {{.*}}, size 0, align 0, offset 0] [public] [static]
+// CHECK: !"0xd\00x_a\00{{.*}}", {{.*}} [ DW_TAG_member ] [x_a] {{.*}} [public] [static]
+
+// CHECK: ; [ DW_TAG_structure_type ] [static_decl_templ<int>] {{.*}} [def]
+// CHECK: ; [ DW_TAG_member ] [static_decl_templ_var]
+
+// CHECK: [[NS_X:![0-9]+]] = {{.*}} ; [ DW_TAG_namespace ] [x]
+
+// Test this in an anonymous namespace to ensure the type is retained even when
+// it doesn't get automatically retained by the string type reference machinery.
+namespace {
+struct anon_static_decl_struct {
+ static const int anon_static_decl_var = 117;
+};
+}
+
+
+// CHECK: ; [ DW_TAG_structure_type ] [anon_static_decl_struct] {{.*}} [def]
+// CHECK: ; [ DW_TAG_member ] [anon_static_decl_var]
+
+int ref() {
+ return anon_static_decl_struct::anon_static_decl_var;
+}
+
+template<typename T>
+struct static_decl_templ {
+ static const int static_decl_templ_var = 7;
+};
+
+template<typename T>
+const int static_decl_templ<T>::static_decl_templ_var;
+
+int static_decl_templ_ref() {
+ return static_decl_templ<int>::static_decl_templ_var;
+}
+
+// CHECK: !"0x34\00a\00{{.*}}", null, {{.*}} @_ZN1C1aE, ![[DECL_A]]} ; [ DW_TAG_variable ] [a] {{.*}} [def]
+// CHECK: !"0x34\00b\00{{.*}}", null, {{.*}} @_ZN1C1bE, ![[DECL_B]]} ; [ DW_TAG_variable ] [b] {{.*}} [def]
+// CHECK: !"0x34\00c\00{{.*}}", null, {{.*}} @_ZN1C1cE, ![[DECL_C]]} ; [ DW_TAG_variable ] [c] {{.*}} [def]
+
+// CHECK-NOT: ; [ DW_TAG_variable ] [anon_static_decl_var]
+
+// Verify that even when a static member declaration is created lazily when
+// creating the definition, the declaration line is that of the canonical
+// declaration, not the definition. Also, since we look at the canonical
+// definition, we should also correctly emit the constant value (42) into the
+// debug info.
+struct V {
+ virtual ~V(); // cause the definition of 'V' to be omitted by no-standalone-debug optimization
+ static const int const_va = 42;
+};
+// CHECK: i32 42} ; [ DW_TAG_member ] [const_va] [line [[@LINE-2]],
+const int V::const_va;
+
+namespace x {
+struct y {
+ static int z;
+};
+int y::z;
+}
+
+// CHECK: !"0x34\00z\00{{.*}}", [[NS_X]], {{.*}} ; [ DW_TAG_variable ] [z] {{.*}} [def]
diff --git a/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp b/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp
index 506c0d535751..461303884b8d 100644
--- a/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp
+++ b/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp
@@ -91,3 +91,11 @@ struct j {
extern template class j<int>;
j<int> jj;
// CHECK: ; [ DW_TAG_structure_type ] [j<int, int>]
+
+template <typename T>
+struct k {
+};
+template <>
+struct k<int>;
+template struct k<int>;
+// CHECK-NOT: ; [ DW_TAG_structure_type ] [k<int>]
diff --git a/test/CodeGenCXX/debug-info-template-limit.cpp b/test/CodeGenCXX/debug-info-template-limit.cpp
index e1f23ada21ed..8e05c7f1c81d 100644
--- a/test/CodeGenCXX/debug-info-template-limit.cpp
+++ b/test/CodeGenCXX/debug-info-template-limit.cpp
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -emit-llvm -fno-standalone-debug -triple %itanium_abi_triple -g %s -o - | FileCheck %s
// Check that this pointer type is TC<int>
-// CHECK: ![[LINE:[0-9]+]] = {{.*}}"TC<int>", {{.*}} metadata !"_ZTS2TCIiE"} ; [ DW_TAG_class_type ]
-// CHECK: metadata !"_ZTS2TCIiE"} ; [ DW_TAG_pointer_type ]{{.*}}[from _ZTS2TCIiE]
+// CHECK: ![[LINE:[0-9]+]] = !{!"0x2\00TC<int>\00{{.*}}", {{.*}} !"_ZTS2TCIiE"} ; [ DW_TAG_class_type ]
+// CHECK: !"_ZTS2TCIiE"} ; [ DW_TAG_pointer_type ]{{.*}}[from _ZTS2TCIiE]
template<typename T>
class TC {
diff --git a/test/CodeGenCXX/debug-info-template-member.cpp b/test/CodeGenCXX/debug-info-template-member.cpp
index c9a3d9b9177c..300b6dbaccf6 100644
--- a/test/CodeGenCXX/debug-info-template-member.cpp
+++ b/test/CodeGenCXX/debug-info-template-member.cpp
@@ -16,29 +16,35 @@ inline int add3(int x) {
return MyClass().add<3>(x); // even though add<3> is ODR used, don't emit it since we don't codegen it
}
-// CHECK: [[FOO_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTS3foo"} ; [ DW_TAG_structure_type ] [foo]
-// CHECK: [[FOO_MEM]] = metadata !{metadata [[FOO_FUNC:![0-9]*]]}
-// CHECK: [[FOO_FUNC]] = {{.*}}, metadata !"_ZN3foo4funcEN5outerIS_E5innerE", i32 {{[0-9]*}}, metadata [[FOO_FUNC_TYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [func]
-// CHECK: [[FOO_FUNC_TYPE]] = {{.*}}, metadata [[FOO_FUNC_PARAMS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
-// CHECK: [[FOO_FUNC_PARAMS]] = metadata !{null, metadata !{{[0-9]*}}, metadata [[OUTER_FOO_INNER:![0-9]*]]}
-// CHECK: [[OUTER_FOO_INNER]] = {{.*}}, null, metadata !"[[OUTER_FOO_INNER_ID:.*]]"} ; [ DW_TAG_structure_type ] [inner]
-
-// CHECK: metadata [[VIRT_MEM:![0-9]*]], i32 0, metadata !"_ZTS4virtI4elemE", metadata [[VIRT_TEMP_PARAM:![0-9]*]], metadata !"_ZTS4virtI4elemE"} ; [ DW_TAG_structure_type ] [virt<elem>] {{.*}} [def]
-// CHECK: [[VIRT_TEMP_PARAM]] = metadata !{metadata [[VIRT_T:![0-9]*]]}
-// CHECK: [[VIRT_T]] = {{.*}}, metadata !"T", metadata !"_ZTS4elem", {{.*}} ; [ DW_TAG_template_type_parameter ]
-
-// CHECK: [[C:![0-9]*]] = {{.*}}, metadata [[C_MEM:![0-9]*]], i32 0, metadata !"_ZTS7MyClass", null, metadata !"_ZTS7MyClass"} ; [ DW_TAG_structure_type ] [MyClass]
-// CHECK: [[C_MEM]] = metadata !{metadata [[C_VPTR:![0-9]*]], metadata [[C_ADD:![0-9]*]], metadata [[C_FUNC:![0-9]*]], metadata [[C_CTOR:![0-9]*]]}
+// CHECK: [[FOO_MEM:![0-9]*]], null, null, !"_ZTS3foo"} ; [ DW_TAG_structure_type ] [foo]
+// CHECK: [[FOO_MEM]] = !{[[FOO_FUNC:![0-9]*]]}
+// CHECK: [[FOO_FUNC]] = !{!"0x2e\00func\00func\00_ZN3foo4funcEN5outerIS_E5innerE\00{{.*}}"{{, [^,]+, [^,]+}}, [[FOO_FUNC_TYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [func]
+// CHECK: [[FOO_FUNC_TYPE]] = {{.*}}, [[FOO_FUNC_PARAMS:![0-9]*]], null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[FOO_FUNC_PARAMS]] = !{null, !{{[0-9]*}}, !"[[OUTER_FOO_INNER_ID:.*]]"}
+// CHECK: !{{[0-9]*}} = {{.*}}, null, !"[[OUTER_FOO_INNER_ID]]"} ; [ DW_TAG_structure_type ] [inner]
+
+// CHECK: [[VIRT_MEM:![0-9]*]], !"_ZTS4virtI4elemE", [[VIRT_TEMP_PARAM:![0-9]*]], !"_ZTS4virtI4elemE"} ; [ DW_TAG_structure_type ] [virt<elem>] {{.*}} [def]
+// CHECK: [[VIRT_TEMP_PARAM]] = !{[[VIRT_T:![0-9]*]]}
+// CHECK: [[VIRT_T]] = !{!"0x2f\00T\000\000"{{, [^,]+}}, !"_ZTS4elem", {{.*}} ; [ DW_TAG_template_type_parameter ]
+
+// CHECK: [[C:![0-9]*]] = {{.*}}, [[C_MEM:![0-9]*]], !"_ZTS7MyClass", null, !"_ZTS7MyClass"} ; [ DW_TAG_structure_type ] [MyClass]
+// CHECK: [[C_MEM]] = !{[[C_VPTR:![0-9]*]], [[C_FUNC:![0-9]*]]}
// CHECK: [[C_VPTR]] = {{.*}} ; [ DW_TAG_member ] [_vptr$MyClass]
-// CHECK: [[C_ADD]] = {{.*}} ; [ DW_TAG_subprogram ] [line 4] [add<2>]
// CHECK: [[C_FUNC]] = {{.*}} ; [ DW_TAG_subprogram ] [line 7] [func]
-// CHECK: [[C_CTOR]] = {{.*}} ; [ DW_TAG_subprogram ] [line 0] [MyClass]
-// CHECK: [[ELEM:![0-9]*]] = {{.*}}, metadata [[ELEM_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTS4elem"} ; [ DW_TAG_structure_type ] [elem] {{.*}} [def]
-// CHECK: [[ELEM_MEM]] = metadata !{metadata [[ELEM_X:![0-9]*]]}
+// CHECK: [[ELEM:![0-9]*]] = {{.*}}, [[ELEM_MEM:![0-9]*]], null, null, !"_ZTS4elem"} ; [ DW_TAG_structure_type ] [elem] {{.*}} [def]
+// CHECK: [[ELEM_MEM]] = !{[[ELEM_X:![0-9]*]]}
// CHECK: [[ELEM_X]] = {{.*}} ; [ DW_TAG_member ] [x] {{.*}} [static] [from _ZTS4virtI4elemE]
+// Check that the member function template specialization and implicit special
+// members (the default ctor) refer to their class by scope, even though they
+// didn't appear in the class's member list (C_MEM). This prevents the functions
+// from being added to type units, while still appearing in the type
+// declaration/reference in the compile unit.
+// CHECK: !"_ZTS7MyClass", {{.*}} ; [ DW_TAG_subprogram ] [line 4] [add<2>]
+// CHECK: !"_ZTS7MyClass", {{.*}} ; [ DW_TAG_subprogram ] [line 0] [MyClass]
+
template<typename T>
struct outer {
struct inner {
@@ -59,7 +65,7 @@ inline void func() {
outer<foo>::inner x;
-// CHECK: metadata !"[[OUTER_FOO_INNER_ID]]", i32 {{[0-9]*}}, i32 {{[0-9]*}}, %"struct.outer<foo>::inner"* @x, {{.*}} ; [ DW_TAG_variable ] [x]
+// CHECK: !"0x34\00{{.*}}", {{.*}}, !"[[OUTER_FOO_INNER_ID]]", %"struct.outer<foo>::inner"* @x, {{.*}} ; [ DW_TAG_variable ] [x]
template <typename T>
struct virt {
diff --git a/test/CodeGenCXX/debug-info-template-partial-specialization.cpp b/test/CodeGenCXX/debug-info-template-partial-specialization.cpp
index cce84af4023c..6940c0fd3503 100644
--- a/test/CodeGenCXX/debug-info-template-partial-specialization.cpp
+++ b/test/CodeGenCXX/debug-info-template-partial-specialization.cpp
@@ -3,7 +3,7 @@ namespace __pointer_type_imp
{
template <class _Tp, class _Dp, bool > struct __pointer_type1 {};
- // CHECK: metadata ![[PARAMS:[0-9]+]], metadata !"_ZTSN18__pointer_type_imp15__pointer_type1I1C14default_deleteIS1_ELb0EEE"} ; [ DW_TAG_structure_type ] [__pointer_type1<C, default_delete<C>, false>] [line [[@LINE+1]], size 8, align 8, offset 0] [def] [from ]
+ // CHECK: ![[PARAMS:[0-9]+]], !"_ZTSN18__pointer_type_imp15__pointer_type1I1C14default_deleteIS1_ELb0EEE"} ; [ DW_TAG_structure_type ] [__pointer_type1<C, default_delete<C>, false>] [line [[@LINE+1]], size 8, align 8, offset 0] [def] [from ]
template <class _Tp, class _Dp> struct __pointer_type1<_Tp, _Dp, false>
{
typedef _Tp* type;
@@ -14,7 +14,7 @@ struct __pointer_type2
{
// Test that the bool template type parameter is emitted.
//
- // CHECK: ![[PARAMS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata ![[FALSE:[0-9]+]]}
+ // CHECK: ![[PARAMS]] = !{!{{.*}}, !{{.*}}, ![[FALSE:[0-9]+]]}
// CHECK: ![[FALSE]] = {{.*}} i8 0, {{.*}}} ; [ DW_TAG_template_value_parameter ]
typedef typename __pointer_type_imp::__pointer_type1<_Tp, _Dp, false>::type type;
};
diff --git a/test/CodeGenCXX/debug-info-template-quals.cpp b/test/CodeGenCXX/debug-info-template-quals.cpp
index 740f7bfa5ce5..15c096f5f94e 100644
--- a/test/CodeGenCXX/debug-info-template-quals.cpp
+++ b/test/CodeGenCXX/debug-info-template-quals.cpp
@@ -16,12 +16,12 @@ void foo (const char *c) {
}
// CHECK: [[BS:.*]] = {{.*}} ; [ DW_TAG_structure_type ] [basic_string<char>] [line 4, size 8, align 8, offset 0] [def] [from ]
-// CHECK: [[TYPE:![0-9]*]] = metadata !{i32 {{.*}}, metadata [[ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
-// CHECK: [[ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata [[P:![0-9]*]], metadata [[R:.*]]}
-// CHECK: [[P]] = {{.*}}, metadata [[CON:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
-// CHECK: [[CON]] = {{.*}}, metadata [[CH:![0-9]*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from char]
+// CHECK: [[TYPE:![0-9]*]] = !{!"0x15\00{{.*}}"{{.*}}, [[ARGS:.*]], null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[ARGS]] = !{!{{.*}}, !{{.*}}, [[P:![0-9]*]], [[R:.*]]}
+// CHECK: [[P]] = {{.*}}, [[CON:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
+// CHECK: [[CON]] = {{.*}}, [[CH:![0-9]*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from char]
// CHECK: [[CH]] = {{.*}} ; [ DW_TAG_base_type ] [char] [line 0, size 8, align 8, offset 0, enc DW_ATE_signed_char]
-// CHECK: [[R]] = {{.*}}, metadata [[CON2:![0-9]*]]} ; [ DW_TAG_reference_type ] [line 0, size 0, align 0, offset 0] [from ]
-// CHECK: [[CON2]] = {{.*}}, metadata !"_ZTS12basic_stringIcE"} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from _ZTS12basic_stringIcE]
-// CHECK: {{.*}} metadata [[TYPE]], {{.*}}, metadata !{{[0-9]*}}, metadata !{{[0-9]*}}, i32 8} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 8] [assign]
+// CHECK: [[R]] = {{.*}}, [[CON2:![0-9]*]]} ; [ DW_TAG_reference_type ] [line 0, size 0, align 0, offset 0] [from ]
+// CHECK: [[CON2]] = {{.*}}, !"_ZTS12basic_stringIcE"} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from _ZTS12basic_stringIcE]
+// CHECK: !"0x2e\00assign\00{{.*}}\008"{{, [^,]+, [^,]+}}, !8, {{.*}} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 8] [assign]
diff --git a/test/CodeGenCXX/debug-info-template.cpp b/test/CodeGenCXX/debug-info-template.cpp
index d071830eaf67..17b945018387 100644
--- a/test/CodeGenCXX/debug-info-template.cpp
+++ b/test/CodeGenCXX/debug-info-template.cpp
@@ -1,92 +1,106 @@
// RUN: %clang -S -emit-llvm -target x86_64-unknown_unknown -g %s -o - -std=c++11 | FileCheck %s
-// CHECK: {{.*}}, i1 false, metadata !"", i32 0, metadata !{{[0-9]]*}}, metadata [[RETAIN:![0-9]*]], {{.*}} ; [ DW_TAG_compile_unit ]
-// CHECK: [[EMPTY:![0-9]*]] = metadata !{}
-// CHECK: [[RETAIN]] = metadata !{metadata !{{[0-9]]*}}, metadata [[FOO:![0-9]*]],
+// CHECK: !"0x11\00{{.*}}"{{, [^,]+, [^,]+}}, [[RETAIN:![0-9]*]], {{.*}} ; [ DW_TAG_compile_unit ]
+// CHECK: [[EMPTY:![0-9]*]] = !{}
+// CHECK: [[RETAIN]] = !{!{{[0-9]]*}}, [[FOO:![0-9]*]],
-// CHECK: [[TC:![0-9]*]] = {{.*}}, metadata [[TCARGS:![0-9]*]], metadata !"{{.*}}"} ; [ DW_TAG_structure_type ] [TC<unsigned int, 2, &glb, &foo::e, &foo::f, &func, tmpl_impl, 1, 2, 3>]
-// CHECK: [[TCARGS]] = metadata !{metadata [[TCARG1:![0-9]*]], metadata [[TCARG2:![0-9]*]], metadata [[TCARG3:![0-9]*]], metadata [[TCARG4:![0-9]*]], metadata [[TCARG5:![0-9]*]], metadata [[TCARG6:![0-9]*]], metadata [[TCARG7:![0-9]*]], metadata [[TCARG8:![0-9]*]]}
+// CHECK: [[TC:![0-9]*]] = {{.*}}, [[TCARGS:![0-9]*]], !"{{.*}}"} ; [ DW_TAG_structure_type ] [TC<unsigned int, 2, &glb, &foo::e, &foo::f, &foo::g, 1, 2, 3>]
+// CHECK: [[TCARGS]] = !{[[TCARG1:![0-9]*]], [[TCARG2:![0-9]*]], [[TCARG3:![0-9]*]], [[TCARG4:![0-9]*]], [[TCARG5:![0-9]*]], [[TCARG6:![0-9]*]], [[TCARG7:![0-9]*]]}
//
// We seem to be missing file/line/col info on template value parameters -
// metadata supports it but it's not populated. GCC doesn't emit it either,
// perhaps we should just drop it from the metadata.
//
-// CHECK: [[TCARG1]] = {{.*}}metadata !"T", metadata [[UINT:![0-9]*]], {{.*}} ; [ DW_TAG_template_type_parameter ]
+// CHECK: [[TCARG1]] = !{!"0x2f\00T\000\000", null, [[UINT:![0-9]*]], null} ; [ DW_TAG_template_type_parameter ]
// CHECK: [[UINT:![0-9]*]] = {{.*}} ; [ DW_TAG_base_type ] [unsigned int]
-// CHECK: [[TCARG2]] = {{.*}}metadata !"", metadata [[UINT]], i32 2, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[TCARG3]] = {{.*}}metadata !"x", metadata [[INTPTR:![0-9]*]], i32* @glb, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[INTPTR]] = {{.*}}, metadata [[INT:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from int]
+// CHECK: [[TCARG2]] = !{!"0x30\00\00{{.*}}", {{[^,]+}}, [[UINT]], i32 2, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCARG3]] = !{!"0x30\00x\00{{.*}}", {{[^,]+}}, [[CINTPTR:![0-9]*]], i32* @glb, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[CINTPTR]] = {{.*}}, [[CINT:![0-9]*]]} ; [ DW_TAG_pointer_type ] {{.*}} [from ]
+// CHECK: [[CINT]] = {{.*}}, [[INT:![0-9]*]]} ; [ DW_TAG_const_type ] {{.*}} [from int]
// CHECK: [[INT]] = {{.*}} ; [ DW_TAG_base_type ] [int]
-// CHECK: [[TCARG4]] = {{.*}}metadata !"a", metadata [[MEMINTPTR:![0-9]*]], i64 8, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[MEMINTPTR]] = {{.*}}, metadata !"_ZTS3foo"} ; [ DW_TAG_ptr_to_member_type ] {{.*}}[from int]
+// CHECK: [[TCARG4]] = !{!"0x30\00a\00{{.*}}", {{[^,]+}}, [[MEMINTPTR:![0-9]*]], i64 8, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[MEMINTPTR]] = {{.*}}, !"_ZTS3foo"} ; [ DW_TAG_ptr_to_member_type ] {{.*}}[from int]
//
// Currently Clang emits the pointer-to-member-function value, but LLVM doesn't
// use it (GCC doesn't emit a value for pointers to member functions either - so
// it's not clear what, if any, format would be acceptable to GDB)
//
-// CHECK: [[TCARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR:![0-9]*]], { i64, i64 } { i64 ptrtoint (void (%struct.foo*)* @_ZN3foo1fEv to i64), i64 0 }, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[MEMFUNPTR]] = {{.*}}, metadata [[FTYPE:![0-9]*]], metadata !"_ZTS3foo"} ; [ DW_TAG_ptr_to_member_type ]
-// CHECK: [[FTYPE]] = {{.*}}, metadata [[FARGS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
-// CHECK: [[FARGS]] = metadata !{null, metadata [[FARG1:![0-9]*]]}
+// CHECK: [[TCARG5]] = !{!"0x30\00b\00{{.*}}", {{[^,]+}}, [[MEMFUNPTR:![0-9]*]], { i64, i64 } { i64 ptrtoint (void (%struct.foo*)* @_ZN3foo1fEv to i64), i64 0 }, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[MEMFUNPTR]] = {{.*}}, [[FTYPE:![0-9]*]], !"_ZTS3foo"} ; [ DW_TAG_ptr_to_member_type ]
+// CHECK: [[FTYPE]] = {{.*}}, [[FARGS:![0-9]*]], null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[FARGS]] = !{null, [[FARG1:![0-9]*]]}
// CHECK: [[FARG1]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from _ZTS3foo]
//
-// CHECK: [[TCARG6]] = {{.*}}metadata !"f", metadata [[FUNPTR:![0-9]*]], void ()* @_Z4funcv, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[FUNPTR]] = {{.*}}, metadata [[FUNTYPE:![0-9]*]]} ; [ DW_TAG_pointer_type ]
-// CHECK: [[FUNTYPE]] = {{.*}}, metadata [[FUNARGS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
-// CHECK: [[FUNARGS]] = metadata !{null}
-// CHECK: [[TCARG7]] = {{.*}}metadata !"tmpl", null, metadata !"tmpl_impl", {{.*}} ; [ DW_TAG_GNU_template_template_param ]
-// CHECK: [[TCARG8]] = {{.*}}metadata !"Is", null, metadata [[TCARG8_VALS:![0-9]*]], {{.*}} ; [ DW_TAG_GNU_template_parameter_pack ]
-// CHECK: [[TCARG8_VALS]] = metadata !{metadata [[TCARG8_1:![0-9]*]], metadata [[TCARG8_2:![0-9]*]], metadata [[TCARG8_3:![0-9]*]]}
-// CHECK: [[TCARG8_1]] = {{.*}}metadata !"", metadata [[INT]], i32 1, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[TCARG8_2]] = {{.*}}metadata !"", metadata [[INT]], i32 2, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[TCARG8_3]] = {{.*}}metadata !"", metadata [[INT]], i32 3, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCARG6]] = !{!"0x30\00f\00{{.*}}", {{[^,]+}}, [[FUNPTR:![0-9]*]], void ()* @_ZN3foo1gEv, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[FUNPTR]] = {{.*}}, [[FUNTYPE:![0-9]*]]} ; [ DW_TAG_pointer_type ]
+// CHECK: [[FUNTYPE]] = {{.*}}, [[FUNARGS:![0-9]*]], null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[FUNARGS]] = !{null}
+// CHECK: [[TCARG7]] = !{!"0x4107\00Is\000\000", null, null, [[TCARG7_VALS:![0-9]*]], null} ; [ DW_TAG_GNU_template_parameter_pack ]
+// CHECK: [[TCARG7_VALS]] = !{[[TCARG7_1:![0-9]*]], [[TCARG7_2:![0-9]*]], [[TCARG7_3:![0-9]*]]}
+// CHECK: [[TCARG7_1]] = !{!"0x30\00\00{{.*}}", {{[^,]+}}, [[INT]], i32 1, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCARG7_2]] = !{!"0x30\00\00{{.*}}", {{[^,]+}}, [[INT]], i32 2, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCARG7_3]] = !{!"0x30\00\00{{.*}}", {{[^,]+}}, [[INT]], i32 3, {{.*}} ; [ DW_TAG_template_value_parameter ]
//
// We could just emit a declaration of 'foo' here, rather than the entire
// definition (same goes for any time we emit a member (function or data)
// pointer type)
-// CHECK: [[FOO]] = {{.*}}, metadata !"_ZTS3foo"} ; [ DW_TAG_structure_type ] [foo]
-// CHECK: metadata !"f", metadata !"_ZN3foo1fEv", i32 {{[0-9]*}}, metadata [[FTYPE:![0-9]*]],
+// CHECK: [[FOO]] = {{.*}}, !"_ZTS3foo"} ; [ DW_TAG_structure_type ] [foo]
+// CHECK: !"0x2e\00f\00f\00_ZN3foo1fEv\00{{.*}}", [[FTYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ]
//
-
-// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"_ZTS2TCIjLj2EXadL_Z3glbEEXadL_ZN3foo1eEEEXadL_ZNS0_1fEvEEXadL_Z4funcvEE9tmpl_implJLi1ELi2ELi3EEE", {{.*}}, metadata !"[[TCNESTED:.*]]"} ; [ DW_TAG_structure_type ] [nested]
-// CHECK: metadata [[TCNARGS:![0-9]*]], metadata !"[[TCNT:.*]]"} ; [ DW_TAG_structure_type ] [TC<int, -3, nullptr, nullptr, nullptr, nullptr, tmpl_impl>]
-// CHECK: [[TCNARGS]] = metadata !{metadata [[TCNARG1:![0-9]*]], metadata [[TCNARG2:![0-9]*]], metadata [[TCNARG3:![0-9]*]], metadata [[TCNARG4:![0-9]*]], metadata [[TCNARG5:![0-9]*]], metadata [[TCNARG6:![0-9]*]], metadata [[TCARG7:![0-9]*]], metadata [[TCNARG8:![0-9]*]]}
-// CHECK: [[TCNARG1]] = {{.*}}metadata !"T", metadata [[INT]], {{.*}} ; [ DW_TAG_template_type_parameter ]
-// CHECK: [[TCNARG2]] = {{.*}}metadata !"", metadata [[INT]], i32 -3, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[TCNARG3]] = {{.*}}metadata !"x", metadata [[INTPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: !"0x13\00{{.*}}", !{{[0-9]*}}, !"_ZTS2TCIjLj2EXadL_Z3glbEEXadL_ZN3foo1eEEEXadL_ZNS0_1fEvEEXadL_ZNS0_1gEvEEJLi1ELi2ELi3EEE", {{.*}}, !"[[TCNESTED:.*]]"} ; [ DW_TAG_structure_type ] [nested]
+// CHECK: [[TCNARGS:![0-9]*]], !"[[TCNT:.*]]"} ; [ DW_TAG_structure_type ] [TC<int, -3, nullptr, nullptr, nullptr, nullptr>]
+// CHECK: [[TCNARGS]] = !{[[TCNARG1:![0-9]*]], [[TCNARG2:![0-9]*]], [[TCNARG3:![0-9]*]], [[TCNARG4:![0-9]*]], [[TCNARG5:![0-9]*]], [[TCNARG6:![0-9]*]], [[TCNARG7:![0-9]*]]}
+// CHECK: [[TCNARG1]] = !{!"0x2f\00T\000\000", null, [[INT]], null} ; [ DW_TAG_template_type_parameter ]
+// CHECK: [[TCNARG2]] = !{!"0x30\00\000\000", null, [[INT]], i32 -3, null} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCNARG3]] = !{!"0x30\00x\000\000", null, [[CINTPTR]], i8 0, null} ; [ DW_TAG_template_value_parameter ]
// The interesting null pointer: -1 for member data pointers (since they are
// just an offset in an object, they can be zero and non-null for the first
// member)
-// CHECK: [[TCNARG4]] = {{.*}}metadata !"a", metadata [[MEMINTPTR]], i64 -1, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCNARG4]] = !{!"0x30\00a\000\000", null, [[MEMINTPTR]], i64 -1, null} ; [ DW_TAG_template_value_parameter ]
//
// In some future iteration we could possibly emit the value of a null member
// function pointer as '{ i64, i64 } zeroinitializer' as it may be handled
// naturally from the LLVM CodeGen side once we decide how to handle non-null
// member function pointers. For now, it's simpler just to emit the 'i8 0'.
//
-// CHECK: [[TCNARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[TCNARG6]] = {{.*}}metadata !"f", metadata [[FUNPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[TCNARG8]] = {{.*}}metadata !"Is", null, metadata [[EMPTY]], {{.*}} ; [ DW_TAG_GNU_template_parameter_pack ]
-
-// CHECK: metadata [[PTOARGS:![0-9]*]], metadata !"{{.*}}"} ; [ DW_TAG_structure_type ] [PaddingAtEndTemplate<&PaddedObj>]
-// CHECK: [[PTOARGS]] = metadata !{metadata [[PTOARG1:![0-9]*]]}
-// CHECK: [[PTOARG1]] = {{.*}}metadata !"", metadata [[CONST_PADDINGATEND_PTR:![0-9]*]], { i32, i8, [3 x i8] }* @PaddedObj, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCNARG5]] = !{!"0x30\00b\000\000", null, [[MEMFUNPTR]], i8 0, null} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCNARG6]] = !{!"0x30\00f\000\000", null, [[FUNPTR]], i8 0, null} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCNARG7]] = !{!"0x4107\00Is\000\000", null, null, [[EMPTY]], null} ; [ DW_TAG_GNU_template_parameter_pack ]
+
+// FIXME: these parameters should probably be rendered as 'glb' rather than
+// '&glb', since they're references, not pointers.
+// CHECK: [[NNARGS:![0-9]*]], !"[[NNT:.*]]"} ; [ DW_TAG_structure_type ] [NN<tmpl_impl, &glb, &glb>]
+// CHECK: [[NNARGS]] = !{[[NNARG1:![0-9]*]], [[NNARG2:![0-9]*]], [[NNARG3:![0-9]*]]}
+// CHECK: [[NNARG1]] = !{!"0x4106\00tmpl\000\000", null, null, !"tmpl_impl", null} ; [ DW_TAG_GNU_template_template_param ]
+// CHECK: [[NNARG2]] = !{!"0x30\00lvr\00{{.*}}", {{[^,]+}}, [[INTLVR:![0-9]*]], i32* @glb, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[INTLVR]] = {{.*}}, [[INT]]} ; [ DW_TAG_reference_type ] {{.*}} [from int]
+// CHECK: [[NNARG3]] = !{!"0x30\00rvr\00{{.*}}", {{[^,]+}}, [[INTRVR:![0-9]*]], i32* @glb, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[INTRVR]] = {{.*}}, [[INT]]} ; [ DW_TAG_rvalue_reference_type ] {{.*}} [from int]
+
+// CHECK: [[PTOARGS:![0-9]*]], !"{{.*}}"} ; [ DW_TAG_structure_type ] [PaddingAtEndTemplate<&PaddedObj>]
+// CHECK: [[PTOARGS]] = !{[[PTOARG1:![0-9]*]]}
+// CHECK: [[PTOARG1]] = !{!"0x30\00\000\000", null, [[CONST_PADDINGATEND_PTR:![0-9]*]], %struct.PaddingAtEnd* @PaddedObj, null} ; [ DW_TAG_template_value_parameter ]
// CHECK: [[CONST_PADDINGATEND_PTR]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from _ZTS12PaddingAtEnd]
-// CHECK: metadata !"[[TCNESTED]]", i32 0, i32 1, %"struct.TC<unsigned int, 2, &glb, &foo::e, &foo::f, &func, tmpl_impl, 1, 2, 3>::nested"* @tci, null} ; [ DW_TAG_variable ] [tci]
+// CHECK: !"[[TCNESTED]]", %"struct.TC<unsigned int, 2, &glb, &foo::e, &foo::f, &foo::g, 1, 2, 3>::nested"* @tci, null} ; [ DW_TAG_variable ] [tci]
-// CHECK: metadata !"[[TCNT]]", i32 0, i32 1, %struct.TC* @tcn, null} ; [ DW_TAG_variable ] [tcn]
+// CHECK: !"[[TCNT]]", %struct.TC* @tcn, null} ; [ DW_TAG_variable ] [tcn]
+
+// CHECK: !"[[NNT]]", %struct.NN* @nn, null} ; [ DW_TAG_variable ] [nn]
struct foo {
char pad[8]; // make the member pointer to 'e' a bit more interesting (nonzero)
int e;
void f();
+ static void g();
};
-template<typename T, T, int *x, int foo::*a, void (foo::*b)(), void (*f)(), template<typename> class tmpl, int ...Is>
+typedef int foo::*foo_mem;
+
+template<typename T, T, const int *x, foo_mem a, void (foo::*b)(), void (*f)(), int ...Is>
struct TC {
struct nested {
};
@@ -95,12 +109,18 @@ struct TC {
int glb;
void func();
+TC<unsigned, 2, &glb, &foo::e, &foo::f, &foo::g, 1, 2, 3>::nested tci;
+TC<int, -3, nullptr, nullptr, nullptr, nullptr> tcn;
+
template<typename>
struct tmpl_impl {
};
-TC<unsigned, 2, &glb, &foo::e, &foo::f, &func, tmpl_impl, 1, 2, 3>::nested tci;
-TC<int, -3, nullptr, nullptr, nullptr, nullptr, tmpl_impl> tcn;
+template <template <typename> class tmpl, int &lvr, int &&rvr>
+struct NN {
+};
+
+NN<tmpl_impl, glb, glb> nn;
struct PaddingAtEnd {
int i;
@@ -109,7 +129,7 @@ struct PaddingAtEnd {
PaddingAtEnd PaddedObj = {};
-template <const PaddingAtEnd *>
+template <PaddingAtEnd *>
struct PaddingAtEndTemplate {
};
diff --git a/test/CodeGenCXX/debug-info-thunk.cpp b/test/CodeGenCXX/debug-info-thunk.cpp
index 1d6f1a77b49a..9f187901f7ec 100644
--- a/test/CodeGenCXX/debug-info-thunk.cpp
+++ b/test/CodeGenCXX/debug-info-thunk.cpp
@@ -14,4 +14,4 @@ struct C : A, B {
void C::f() { }
-// CHECK: metadata !"_ZThn{{4|8}}_N1C1fEv", i32 15, {{.*}} ; [ DW_TAG_subprogram ] [line 15] [def]{{$}}
+// CHECK: !"0x2e\00\00\00_ZThn{{[48]}}_N1C1fEv\0015\00{{.*}}", {{.*}} ; [ DW_TAG_subprogram ] [line 15] [def]{{$}}
diff --git a/test/CodeGenCXX/debug-info-union-template.cpp b/test/CodeGenCXX/debug-info-union-template.cpp
index 570520d03d9e..aa66e3f9de1a 100644
--- a/test/CodeGenCXX/debug-info-union-template.cpp
+++ b/test/CodeGenCXX/debug-info-union-template.cpp
@@ -10,6 +10,6 @@ namespace PR15637 {
Value<float> f;
}
-// CHECK: {{.*}}, metadata !"Value<float>", {{.*}}, null, metadata [[TTPARAM:.*]], metadata !"_ZTSN7PR156375ValueIfEE"} ; [ DW_TAG_union_type ] [Value<float>]
-// CHECK: [[TTPARAM]] = metadata !{metadata [[PARAMS:.*]]}
-// CHECK: [[PARAMS]] = metadata !{{{.*}}metadata !"T",{{.*}}} ; [ DW_TAG_template_type_parameter ]
+// CHECK: !"0x17\00Value<float>\00{{.*}}", {{.*}}, [[TTPARAM:![0-9]+]], !"_ZTSN7PR156375ValueIfEE"} ; [ DW_TAG_union_type ] [Value<float>]
+// CHECK: [[TTPARAM]] = !{[[PARAMS:.*]]}
+// CHECK: [[PARAMS]] = !{!"0x2f\00T\000\000", {{.*}} ; [ DW_TAG_template_type_parameter ]
diff --git a/test/CodeGenCXX/debug-info-uuid.cpp b/test/CodeGenCXX/debug-info-uuid.cpp
index 6137400de07c..b7e532ba2b31 100644
--- a/test/CodeGenCXX/debug-info-uuid.cpp
+++ b/test/CodeGenCXX/debug-info-uuid.cpp
@@ -1,14 +1,20 @@
// RUN: %clang_cc1 -emit-llvm -fms-extensions -triple=x86_64-pc-win32 -g %s -o - -std=c++11 | FileCheck %s
-// RUN: not %clang_cc1 -emit-llvm -fms-extensions -triple=x86_64-unknown-unknown -g %s -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=CHECK-ITANIUM
+// RUN: %clang_cc1 -emit-llvm -fms-extensions -triple=x86_64-unknown-unknown -g %s -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=CHECK-ITANIUM
-// CHECK: metadata [[TGIARGS:![0-9]*]], null} ; [ DW_TAG_structure_type ] [tmpl_guid<&__uuidof(uuid)>]
-// CHECK: [[TGIARGS]] = metadata !{metadata [[TGIARG1:![0-9]*]]}
-// CHECK: [[TGIARG1]] = {{.*}}metadata !"", metadata [[CONST_GUID_PTR:![0-9]*]], { i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab, {{.*}} ; [ DW_TAG_template_value_parameter ]
-// CHECK: [[CONST_GUID_PTR]] = {{.*}}, metadata [[CONST_GUID:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
-// CHECK: [[CONST_GUID]] = {{.*}}, metadata [[GUID:![0-9]*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from _GUID]
+// CHECK: [[TGIARGS:![0-9]*]], null} ; [ DW_TAG_structure_type ] [tmpl_guid<&__uuidof(uuid)>]
+// CHECK: [[TGIARGS]] = !{[[TGIARG1:![0-9]*]]}
+// CHECK: [[TGIARG1]] = !{!"0x30\00\00{{.*}}", {{[^,]+}}, [[CONST_GUID_PTR:![0-9]*]], { i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[CONST_GUID_PTR]] = {{.*}}, [[CONST_GUID:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
+// CHECK: [[CONST_GUID]] = {{.*}}, [[GUID:![0-9]*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from _GUID]
// CHECK: [[GUID]] = {{.*}} ; [ DW_TAG_structure_type ] [_GUID]
-// CHECK-ITANIUM: error: cannot yet mangle expression type CXXUuidofExpr
+// CHECK: [[TGI2ARGS:![0-9]*]], null} ; [ DW_TAG_structure_type ] [tmpl_guid2<__uuidof(uuid)>]
+// CHECK: [[TGI2ARGS]] = !{[[TGI2ARG1:![0-9]*]]}
+// CHECK: [[TGI2ARG1]] = !{!"0x30\00\00{{.*}}", {{[^,]+}}, [[CONST_GUID_REF:![0-9]*]], { i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[CONST_GUID_REF]] = {{.*}}, [[CONST_GUID:![0-9]*]]} ; [ DW_TAG_reference_type ] [line 0, size 0, align 0, offset 0] [from ]
+
+// CHECK-ITANIUM: !"_ZTS9tmpl_guidIXadu8__uuidoft4uuidEE"} ; [ DW_TAG_structure_type ] [tmpl_guid<&__uuidof(uuid)>]
+// CHECK-ITANIUM: !"_ZTS10tmpl_guid2IXu8__uuidoft4uuidEE"} ; [ DW_TAG_structure_type ] [tmpl_guid2<__uuidof(uuid)>]
struct _GUID;
template <const _GUID *>
@@ -17,3 +23,7 @@ struct tmpl_guid {
struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ab}")) uuid;
tmpl_guid<&__uuidof(uuid)> tgi;
+
+template <const _GUID &>
+struct tmpl_guid2 {};
+tmpl_guid2<__uuidof(uuid)> tgi2;
diff --git a/test/CodeGenCXX/debug-info-varargs.cpp b/test/CodeGenCXX/debug-info-varargs.cpp
index cc92477dbb92..25e8f350b055 100644
--- a/test/CodeGenCXX/debug-info-varargs.cpp
+++ b/test/CodeGenCXX/debug-info-varargs.cpp
@@ -2,21 +2,21 @@
struct A
{
- // CHECK-DAG: ", i32 [[@LINE+1]], metadata ![[ATY:[0-9]+]]{{.*}}[ DW_TAG_subprogram ]{{.*}}[a]
+ // CHECK-DAG: !"0x2e\00a\00a\00_ZN1A1aEiz\00[[@LINE+1]]\00{{[^,]*}}"{{, [^,]+, [^,]+}}, ![[ATY:[0-9]+]]{{.*}}[ DW_TAG_subprogram ]{{.*}}[a]
void a(int c, ...) {}
- // CHECK: ![[ATY]] ={{.*}} metadata ![[AARGS:[0-9]+]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
- // CHECK: ![[AARGS]] = {{.*}} metadata ![[UNSPEC:[0-9]+]]}
- // CHECK: ![[UNSPEC]] = {{.*}} [ DW_TAG_unspecified_parameters ]
+ // CHECK: ![[ATY]] ={{.*}} ![[AARGS:[0-9]+]], null, null, null} ; [ DW_TAG_subroutine_type ]
+ // We no longer use an explicit unspecified parameter. Instead we use a trailing null to mean the function is variadic.
+ // CHECK: ![[AARGS]] = !{null, !{{[0-9]+}}, !{{[0-9]+}}, null}
};
- // CHECK: ", i32 [[@LINE+1]], metadata ![[BTY:[0-9]+]]{{.*}}[ DW_TAG_subprogram ]{{.*}}[b]
+ // CHECK: !"0x2e\00b\00b\00_Z1biz\00[[@LINE+1]]\00{{[^,]*}}"{{, [^,]+, [^,]+}}, ![[BTY:[0-9]+]]{{.*}}[ DW_TAG_subprogram ]{{.*}}[b]
void b(int c, ...) {
- // CHECK: ![[BTY]] ={{.*}} metadata ![[BARGS:[0-9]+]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ]
- // CHECK: ![[BARGS]] = {{.*}} metadata ![[UNSPEC:[0-9]+]]}
+ // CHECK: ![[BTY]] ={{.*}} ![[BARGS:[0-9]+]], null, null, null} ; [ DW_TAG_subroutine_type ]
+ // CHECK: ![[BARGS]] = !{null, !{{[0-9]+}}, null}
A a;
- // CHECK: metadata ![[PST:[0-9]+]], i32 0, i32 0} ; [ DW_TAG_auto_variable ] [fptr] [line [[@LINE+1]]]
+ // CHECK: !"0x100\00fptr\00[[@LINE+1]]\000"{{, [^,]+, [^,]+}}, ![[PST:[0-9]+]]} ; [ DW_TAG_auto_variable ] [fptr] [line [[@LINE+1]]]
void (*fptr)(int, ...) = b;
- // CHECK: ![[PST]] ={{.*}} metadata ![[BTY]]} ; [ DW_TAG_pointer_type ]
+ // CHECK: ![[PST]] ={{.*}} ![[BTY]]} ; [ DW_TAG_pointer_type ]
}
diff --git a/test/CodeGenCXX/debug-info-wchar.cpp b/test/CodeGenCXX/debug-info-wchar.cpp
index 6f5384966b99..5b5fdccce14e 100644
--- a/test/CodeGenCXX/debug-info-wchar.cpp
+++ b/test/CodeGenCXX/debug-info-wchar.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -g %s -o -| FileCheck %s
void foo() {
-// CHECK: metadata !"wchar_t",
+// CHECK: !"0x24\00wchar_t\00{{.*}}", null, null} ; [ DW_TAG_base_type ] [wchar_t]
const wchar_t w = L'x';
}
diff --git a/test/CodeGenCXX/debug-info-windows-dtor.cpp b/test/CodeGenCXX/debug-info-windows-dtor.cpp
new file mode 100644
index 000000000000..a94f2b06ee72
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-windows-dtor.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple i386-unknown-windows-msvc -std=c++11 -emit-llvm -gline-tables-only %s -o - | FileCheck %s
+
+struct A {
+ virtual ~A() {}
+};
+
+struct B {
+ virtual ~B() {}
+};
+
+template<typename T>
+struct AB: A, B {
+};
+
+template struct AB<int>;
+
+// CHECK-LABEL: define {{.*}}@"\01??_E?$AB@H@@W3AEPAXI@Z"
+// CHECK: call {{.*}}@"\01??_G?$AB@H@@UAEPAXI@Z"({{.*}}) #{{[0-9]*}}, !dbg [[THUNK_LOC:![0-9]*]]
+// CHECK-LABEL: define
+
+// CHECK: [[THUNK_VEC_DEL_DTOR:![0-9]*]] = {{.*}} @"\01??_E?$AB@H@@W3AEPAXI@Z", {{.*}}; [ DW_TAG_subprogram ]
+// CHECK: [[THUNK_LOC]] = !MDLocation(line: 15, scope: [[THUNK_VEC_DEL_DTOR]])
diff --git a/test/CodeGenCXX/debug-info-zero-length-arrays.cpp b/test/CodeGenCXX/debug-info-zero-length-arrays.cpp
index 101796509da3..f1ba636729bc 100644
--- a/test/CodeGenCXX/debug-info-zero-length-arrays.cpp
+++ b/test/CodeGenCXX/debug-info-zero-length-arrays.cpp
@@ -6,7 +6,7 @@ class A {
};
A a;
-// CHECK: metadata [[ARRAY_TYPE:![0-9]*]]} ; [ DW_TAG_member ] [x]
-// CHECK: metadata [[ELEM_TYPE:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_array_type ] [line 0, size 0, align 32, offset 0] [from int]
-// CHECK: [[ELEM_TYPE]] = metadata !{metadata [[SUBRANGE:.*]]}
-// CHECK: [[SUBRANGE]] = metadata !{i32 786465, i64 0, i64 -1} ; [ DW_TAG_subrange_type ] [unbounded]
+// CHECK: [[ARRAY_TYPE:![0-9]*]]} ; [ DW_TAG_member ] [x]
+// CHECK: !"0x1\00\000\000\0032\000\000\000", null, null, {{![0-9]+}}, [[ELEM_TYPE:![0-9]+]], null, null, null} ; [ DW_TAG_array_type ] [line 0, size 0, align 32, offset 0] [from int]
+// CHECK: [[ELEM_TYPE]] = !{[[SUBRANGE:.*]]}
+// CHECK: [[SUBRANGE]] = !{!"0x21\000\00-1"} ; [ DW_TAG_subrange_type ] [unbounded]
diff --git a/test/CodeGenCXX/debug-info.cpp b/test/CodeGenCXX/debug-info.cpp
index 7c89dfc04ce1..f4d1f00137d6 100644
--- a/test/CodeGenCXX/debug-info.cpp
+++ b/test/CodeGenCXX/debug-info.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -emit-llvm -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i686-pc-windows-msvc -emit-llvm -g %s -o - | FileCheck %s --check-prefix=MSVC
+
template<typename T> struct Identity {
typedef T Type;
};
@@ -43,14 +45,25 @@ namespace VirtualDtor {
}
namespace VirtualBase {
- struct A { };
- struct B : virtual A { };
+ struct A { int a; };
+ struct B : virtual A { int b; };
void f() {
B b;
}
}
+// MSVC: [[VBASE_B:![0-9]+]] = distinct !{!"0x13\00B\00{{[0-9]+}}\0096\0032\000\000\000", {{.*}}, null, [[VBASE_B_DEF:![0-9]+]], {{.*}}} ; [ DW_TAG_structure_type ] [B] [line 49, size 96, align 32, offset 0] [def] [from ]
+// MSVC: [[VBASE_B_DEF]] = !{[[VBASE_A_IN_B:![0-9]+]],
+//
+// Look for the vbtable offset of A, which should be 4.
+// MSVC: [[VBASE_A_IN_B]] = !{!"0x1c\00\000\000\000\004\0032", null, [[VBASE_B]], !{{[0-9]*}}} ; [ DW_TAG_inheritance ] [line 0, size 0, align 0, offset 4] [from A]
+
+// CHECK: !"0x13\00B\00{{[0-9]+}}\00128\0064\000\000\000", {{.*}}, null, [[VBASE_B_DEF:![0-9]+]], {{.*}}} ; [ DW_TAG_structure_type ] [B] [line 49, size 128, align 64, offset 0] [def] [from ]
+// CHECK: [[VBASE_B_DEF]] = !{[[VBASE_A_IN_B:![0-9]+]],
+//
+// Look for the vtable offset offset, which should be -24.
+// CHECK: [[VBASE_A_IN_B]] = !{!"0x1c\00\000\000\000\0024\0032", null, !"_ZTSN11VirtualBase1BE", !"_ZTSN11VirtualBase1AE"} ; [ DW_TAG_inheritance ] [line 0, size 0, align 0, offset 24] [from _ZTSN11VirtualBase1AE]
namespace b5249287 {
template <typename T> class A {
struct B;
@@ -72,15 +85,15 @@ foo func(foo f) {
return f; // reference 'f' for now because otherwise we hit another bug
}
-// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata [[PR14763:![0-9]*]], {{.*}}, metadata !"[[FOO:.*]]"} ; [ DW_TAG_structure_type ] [foo]
+// CHECK: !"0x13\00{{.*}}", !{{[0-9]*}}, [[PR14763:![0-9]*]], {{.*}}, !"[[FOO:.*]]"} ; [ DW_TAG_structure_type ] [foo]
// CHECK: [[PR14763]] = {{.*}} ; [ DW_TAG_namespace ] [pr14763]
// CHECK: [[INCTYPE:![0-9]*]] = {{.*}} ; [ DW_TAG_structure_type ] [incomplete]{{.*}} [decl]
-// CHECK: metadata [[A_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTSN7pr162141aE"} ; [ DW_TAG_structure_type ] [a]
-// CHECK: [[A_MEM]] = metadata !{metadata [[A_I:![0-9]*]]}
+// CHECK: [[A_MEM:![0-9]*]], null, null, !"_ZTSN7pr162141aE"} ; [ DW_TAG_structure_type ] [a]
+// CHECK: [[A_MEM]] = !{[[A_I:![0-9]*]]}
// CHECK: [[A_I]] = {{.*}} ; [ DW_TAG_member ] [i] {{.*}} [from int]
// CHECK: ; [ DW_TAG_structure_type ] [b] {{.*}}[decl]
-// CHECK: [[FUNC:![0-9]*]] = {{.*}} metadata !"_ZN7pr147634funcENS_3fooE", i32 {{[0-9]*}}, metadata [[FUNC_TYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
+// CHECK: [[FUNC:![0-9]*]] = !{!"0x2e\00func\00func\00_ZN7pr147634funcENS_3fooE\00{{.*}}"{{, [^,]+, [^,]+}}, [[FUNC_TYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
}
void foo() {
@@ -93,13 +106,13 @@ void foo() {
namespace pr9608 { // also pr9600
struct incomplete;
incomplete (*x)[3];
-// CHECK: metadata [[INCARRAYPTR:![0-9]*]], i32 0, i32 1, [3 x i8]** @_ZN6pr96081xE, null} ; [ DW_TAG_variable ] [x]
-// CHECK: [[INCARRAYPTR]] = {{.*}}metadata [[INCARRAY:![0-9]*]]} ; [ DW_TAG_pointer_type ]
-// CHECK: [[INCARRAY]] = {{.*}}metadata !"_ZTSN6pr960810incompleteE", metadata {{![0-9]*}}, i32 0, null, null, null} ; [ DW_TAG_array_type ] [line 0, size 0, align 0, offset 0] [from _ZTSN6pr960810incompleteE]
+// CHECK: [[INCARRAYPTR:![0-9]*]], [3 x i8]** @_ZN6pr96081xE, null} ; [ DW_TAG_variable ] [x]
+// CHECK: [[INCARRAYPTR]] = {{.*}}[[INCARRAY:![0-9]*]]} ; [ DW_TAG_pointer_type ]
+// CHECK: [[INCARRAY]] = !{!"0x1\00\000\000\000\000\000\000", null, null, !"_ZTSN6pr960810incompleteE", {{![0-9]+}}, null, null, null} ; [ DW_TAG_array_type ] [line 0, size 0, align 0, offset 0] [from _ZTSN6pr960810incompleteE]
}
// For some reason function arguments ended up down here
-// CHECK: = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], {{.*}}, metadata !"[[FOO]]", i32 8192, i32 0} ; [ DW_TAG_arg_variable ] [f]
+// CHECK: = !{!"0x101\00f\00{{.*}}\008192", [[FUNC]], {{![0-9]+}}, !"[[FOO]]"} ; [ DW_TAG_arg_variable ] [f]
// CHECK: ; [ DW_TAG_auto_variable ] [c]
diff --git a/test/CodeGenCXX/debug-lambda-expressions.cpp b/test/CodeGenCXX/debug-lambda-expressions.cpp
index 0b087360f9d5..feafcff064c8 100644
--- a/test/CodeGenCXX/debug-lambda-expressions.cpp
+++ b/test/CodeGenCXX/debug-lambda-expressions.cpp
@@ -30,38 +30,38 @@ int d(int x) { D y[10]; return [x,y] { return y[x].x; }(); }
// CHECK: [[D_FUNC:.*]] = {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE:.*]]] [def] [d]
// Back to D. -- 24
-// CHECK: [[LAM_D:.*]] = {{.*}}, metadata [[D_FUNC]], {{.*}}, metadata [[LAM_D_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[D_LINE]],
-// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]]}
-// CHECK: [[CAP_D_X]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_member ] [x] [line [[D_LINE]],
-// CHECK: [[CAP_D_Y]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_member ] [y] [line [[D_LINE]],
-// CHECK: [[CON_LAM_D]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE]]] [operator()]
+// CHECK: [[LAM_D:.*]] = {{.*}}, [[D_FUNC]], {{.*}}, [[LAM_D_ARGS:.*]], null, null, null} ; [ DW_TAG_class_type ] [line [[D_LINE]],
+// CHECK: [[LAM_D_ARGS]] = !{[[CAP_D_X:.*]], [[CAP_D_Y:.*]], [[CON_LAM_D:.*]]}
+// CHECK: [[CAP_D_X]] = {{.*}}, [[LAM_D]], {{.*}} [ DW_TAG_member ] [x] [line [[D_LINE]],
+// CHECK: [[CAP_D_Y]] = {{.*}}, [[LAM_D]], {{.*}} [ DW_TAG_member ] [y] [line [[D_LINE]],
+// CHECK: [[CON_LAM_D]] = {{.*}}, [[LAM_D]], {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE]]] [public] [operator()]
// Back to C. -- 55
-// CHECK: [[LAM_C:.*]] = {{.*}}, metadata [[C_FUNC]], {{.*}}, metadata [[LAM_C_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[C_LINE]],
-// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]]}
+// CHECK: [[LAM_C:.*]] = {{.*}}, [[C_FUNC]], {{.*}}, [[LAM_C_ARGS:.*]], null, null, null} ; [ DW_TAG_class_type ] [line [[C_LINE]],
+// CHECK: [[LAM_C_ARGS]] = !{[[CAP_C:.*]], [[CON_LAM_C:.*]]}
// Ignoring the member type for now.
-// CHECK: [[CAP_C]] = {{.*}}, metadata [[LAM_C]], {{.*}}} ; [ DW_TAG_member ] [x] [line [[C_LINE]],
-// CHECK: [[CON_LAM_C]] = {{.*}}, metadata [[LAM_C]], {{.*}} [ DW_TAG_subprogram ] [line [[C_LINE]]] [operator()]
+// CHECK: [[CAP_C]] = {{.*}}, [[LAM_C]], {{.*}}} ; [ DW_TAG_member ] [x] [line [[C_LINE]],
+// CHECK: [[CON_LAM_C]] = {{.*}}, [[LAM_C]], {{.*}} [ DW_TAG_subprogram ] [line [[C_LINE]]] [public] [operator()]
// Back to B. -- 67
-// CHECK: [[LAM_B:.*]] = {{.*}}, metadata [[B_FUNC]], {{.*}}, metadata [[LAM_B_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[B_LINE]],
-// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]]}
-// CHECK: [[CAP_B]] = {{.*}}, metadata [[LAM_B]], {{.*}}} ; [ DW_TAG_member ] [x] [line [[B_LINE]],
-// CHECK: [[CON_LAM_B]] = {{.*}}, metadata [[LAM_B]], {{.*}} [ DW_TAG_subprogram ] [line [[B_LINE]]] [operator()]
+// CHECK: [[LAM_B:.*]] = {{.*}}, [[B_FUNC]], {{.*}}, [[LAM_B_ARGS:.*]], null, null, null} ; [ DW_TAG_class_type ] [line [[B_LINE]],
+// CHECK: [[LAM_B_ARGS]] = !{[[CAP_B:.*]], [[CON_LAM_B:.*]]}
+// CHECK: [[CAP_B]] = {{.*}}, [[LAM_B]], {{.*}}} ; [ DW_TAG_member ] [x] [line [[B_LINE]],
+// CHECK: [[CON_LAM_B]] = {{.*}}, [[LAM_B]], {{.*}} [ DW_TAG_subprogram ] [line [[B_LINE]]] [public] [operator()]
// Back to A. -- 78
-// CHECK: [[LAM_A:.*]] = {{.*}}, metadata [[A_FUNC]], {{.*}}, metadata [[LAM_A_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[A_LINE]],
-// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]]}
-// CHECK: [[CON_LAM_A]] = {{.*}}, metadata [[LAM_A]], {{.*}} [ DW_TAG_subprogram ] [line [[A_LINE]]] [operator()]
+// CHECK: [[LAM_A:.*]] = {{.*}}, [[A_FUNC]], {{.*}}, [[LAM_A_ARGS:.*]], null, null, null} ; [ DW_TAG_class_type ] [line [[A_LINE]],
+// CHECK: [[LAM_A_ARGS]] = !{[[CON_LAM_A:.*]]}
+// CHECK: [[CON_LAM_A]] = {{.*}}, [[LAM_A]], {{.*}} [ DW_TAG_subprogram ] [line [[A_LINE]]] [public] [operator()]
// CVAR:
-// CHECK: {{.*}} metadata [[CVAR_T:![0-9]*]], {{.*}} ; [ DW_TAG_variable ] [cvar] [line [[CVAR_LINE:[0-9]*]]]
-// CHECK: [[CVAR_T]] = {{.*}}, metadata ![[CVAR_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[CVAR_LINE]],
-// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}}
+// CHECK: {{.*}} [[CVAR_T:![0-9]*]], {{.*}} ; [ DW_TAG_variable ] [cvar] [line [[CVAR_LINE:[0-9]*]]]
+// CHECK: [[CVAR_T]] = {{.*}}, ![[CVAR_ARGS:.*]], null, null, null} ; [ DW_TAG_class_type ] [line [[CVAR_LINE]],
+// CHECK: [[CVAR_ARGS]] = !{!{{.*}}}
// VAR:
-// CHECK: {{.*}} metadata [[VAR_T:![0-9]*]], {{.*}} ; [ DW_TAG_variable ] [var] [line [[VAR_LINE:[0-9]*]]]
-// CHECK: [[VAR_T]] = {{.*}}, metadata [[VAR_ARGS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[VAR_LINE]],
-// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}}
+// CHECK: {{.*}} [[VAR_T:![0-9]*]], {{.*}} ; [ DW_TAG_variable ] [var] [line [[VAR_LINE:[0-9]*]]]
+// CHECK: [[VAR_T]] = {{.*}}, [[VAR_ARGS:![0-9]*]], null, null, null} ; [ DW_TAG_class_type ] [line [[VAR_LINE]],
+// CHECK: [[VAR_ARGS]] = !{!{{.*}}}
diff --git a/test/CodeGenCXX/debug-lambda-this.cpp b/test/CodeGenCXX/debug-lambda-this.cpp
index e7155e76a1cc..87a317db5e16 100644
--- a/test/CodeGenCXX/debug-lambda-this.cpp
+++ b/test/CodeGenCXX/debug-lambda-this.cpp
@@ -12,4 +12,4 @@ int D::d(int x) {
}();
}
-// CHECK: {{.*}} [ DW_TAG_member ] [this] [line 11, size 64, align 64, offset 0] [private] [from ]
+// CHECK: {{.*}} [ DW_TAG_member ] [this] [line 11, size 64, align 64, offset 0] [from ]
diff --git a/test/CodeGenCXX/destructor-debug-info.cpp b/test/CodeGenCXX/destructor-debug-info.cpp
index f2e2a39bd6b6..a8abfded2c22 100644
--- a/test/CodeGenCXX/destructor-debug-info.cpp
+++ b/test/CodeGenCXX/destructor-debug-info.cpp
@@ -19,4 +19,4 @@ void foo() {
}
}
// Check there is a line number entry for line 19 where b1 is destructed.
-// CHECK: i32 19, i32 0, metadata
+// CHECK: !MDLocation(line: 19,
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index 5c430480bc28..bc9a683be5d4 100644
--- a/test/CodeGenCXX/destructors.cpp
+++ b/test/CodeGenCXX/destructors.cpp
@@ -1,21 +1,13 @@
-// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fcxx-exceptions -fexceptions -O1 -disable-llvm-optzns | FileCheck %s
-
-// CHECK-DAG: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
-// CHECK-DAG: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// CHECK-DAG: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// CHECK-DAG: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// CHECK-DAG: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
-
-// WIN32-DAG: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
-// WIN32-DAG: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// WIN32-DAG: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// WIN32-DAG: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// WIN32-DAG: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
-
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fcxx-exceptions -fexceptions -O1 -disable-llvm-optzns > %t
+// RUN: FileCheck --check-prefix=CHECK1 --input-file=%t %s
+// RUN: FileCheck --check-prefix=CHECK2 --input-file=%t %s
+// RUN: FileCheck --check-prefix=CHECK3 --input-file=%t %s
+// RUN: FileCheck --check-prefix=CHECK4 --input-file=%t %s
+// RUN: FileCheck --check-prefix=CHECK5 --input-file=%t %s
struct A {
int a;
-
+
~A();
};
@@ -29,7 +21,7 @@ B::~B() { }
// Field with non-trivial destructor
struct C {
A a;
-
+
~C();
};
@@ -43,11 +35,11 @@ namespace PR7526 {
struct allocator_derived : allocator { };
- // CHECK-LABEL: define void @_ZN6PR75263fooEv()
- // CHECK: call void {{.*}} @_ZN6PR75269allocatorD2Ev
+ // CHECK1-LABEL: define void @_ZN6PR75263fooEv()
+ // CHECK1: call void {{.*}} @_ZN6PR75269allocatorD2Ev
- // CHECK-LABEL: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR7526::allocator"* %this) unnamed_addr
- // CHECK: call void @__cxa_call_unexpected
+ // CHECK1-LABEL: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR7526::allocator"* %this) unnamed_addr
+ // CHECK1: call void @__cxa_call_unexpected
allocator::~allocator() throw() { foo(); }
void foo() {
@@ -68,12 +60,12 @@ namespace PR5529 {
struct A {
~A();
};
-
+
A::~A() { }
struct B : A {
virtual ~B();
};
-
+
B::~B() {}
}
@@ -96,11 +88,12 @@ namespace test0 {
// complete destructor alias tested above
-// CHECK-LABEL: define void @_ZN5test01AD2Ev(%"struct.test0::A"* %this) unnamed_addr
-// CHECK: invoke void @_ZN5test06MemberD1Ev
-// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
-// CHECK: invoke void @_ZN5test04BaseD2Ev
-// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
+// CHECK2-LABEL: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
+// CHECK2-LABEL: define void @_ZN5test01AD2Ev(%"struct.test0::A"* %this) unnamed_addr
+// CHECK2: invoke void @_ZN5test06MemberD1Ev
+// CHECK2: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
+// CHECK2: invoke void @_ZN5test04BaseD2Ev
+// CHECK2: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
struct B : Base, virtual VBase {
Member M;
@@ -109,19 +102,19 @@ namespace test0 {
B::~B() try { } catch (int i) {}
// It will suppress the delegation optimization here, though.
-// CHECK-LABEL: define void @_ZN5test01BD2Ev(%"struct.test0::B"* %this, i8** %vtt) unnamed_addr
-// CHECK: invoke void @_ZN5test06MemberD1Ev
-// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
-// CHECK: invoke void @_ZN5test04BaseD2Ev
-// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
-
-// CHECK-LABEL: define void @_ZN5test01BD1Ev(%"struct.test0::B"* %this) unnamed_addr
-// CHECK: invoke void @_ZN5test06MemberD1Ev
-// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
-// CHECK: invoke void @_ZN5test04BaseD2Ev
-// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
-// CHECK: invoke void @_ZN5test05VBaseD2Ev
-// CHECK: unwind label [[VBASE_UNWIND:%[a-zA-Z0-9.]+]]
+// CHECK2-LABEL: define void @_ZN5test01BD2Ev(%"struct.test0::B"* %this, i8** %vtt) unnamed_addr
+// CHECK2: invoke void @_ZN5test06MemberD1Ev
+// CHECK2: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
+// CHECK2: invoke void @_ZN5test04BaseD2Ev
+// CHECK2: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
+
+// CHECK2-LABEL: define void @_ZN5test01BD1Ev(%"struct.test0::B"* %this) unnamed_addr
+// CHECK2: invoke void @_ZN5test06MemberD1Ev
+// CHECK2: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
+// CHECK2: invoke void @_ZN5test04BaseD2Ev
+// CHECK2: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
+// CHECK2: invoke void @_ZN5test05VBaseD2Ev
+// CHECK2: unwind label [[VBASE_UNWIND:%[a-zA-Z0-9.]+]]
}
// Test base-class aliasing.
@@ -136,33 +129,37 @@ namespace test1 {
A::~A() { delete m; }
struct M : A { ~M(); };
- M::~M() {} // alias tested above
+ M::~M() {}
+ // CHECK3: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
struct N : A, Empty { ~N(); };
- N::~N() {} // alias tested above
+ N::~N() {}
+ // CHECK3: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev
struct O : Empty, A { ~O(); };
- O::~O() {} // alias tested above
+ O::~O() {}
+ // CHECK3: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
struct P : NonEmpty, A { ~P(); };
- P::~P() {} // CHECK-LABEL: define void @_ZN5test11PD2Ev(%"struct.test1::P"* %this) unnamed_addr
+ P::~P() {} // CHECK3-LABEL: define void @_ZN5test11PD2Ev(%"struct.test1::P"* %this) unnamed_addr
struct Q : A, B { ~Q(); };
- Q::~Q() {} // CHECK-LABEL: define void @_ZN5test11QD2Ev(%"struct.test1::Q"* %this) unnamed_addr
+ Q::~Q() {} // CHECK3-LABEL: define void @_ZN5test11QD2Ev(%"struct.test1::Q"* %this) unnamed_addr
struct R : A { ~R(); };
- R::~R() { A a; } // CHECK-LABEL: define void @_ZN5test11RD2Ev(%"struct.test1::R"* %this) unnamed_addr
+ R::~R() { A a; } // CHECK3-LABEL: define void @_ZN5test11RD2Ev(%"struct.test1::R"* %this) unnamed_addr
struct S : A { ~S(); int x; };
- S::~S() {} // alias tested above
+ S::~S() {}
+ // CHECK4: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
struct T : A { ~T(); B x; };
- T::~T() {} // CHECK-LABEL: define void @_ZN5test11TD2Ev(%"struct.test1::T"* %this) unnamed_addr
+ T::~T() {} // CHECK4-LABEL: define void @_ZN5test11TD2Ev(%"struct.test1::T"* %this) unnamed_addr
// The VTT parameter prevents this. We could still make this work
// for calling conventions that are safe against extra parameters.
struct U : A, virtual B { ~U(); };
- U::~U() {} // CHECK-LABEL: define void @_ZN5test11UD2Ev(%"struct.test1::U"* %this, i8** %vtt) unnamed_addr
+ U::~U() {} // CHECK4-LABEL: define void @_ZN5test11UD2Ev(%"struct.test1::U"* %this, i8** %vtt) unnamed_addr
}
// PR6471
@@ -171,8 +168,8 @@ namespace test2 {
struct B : A { ~B(); };
B::~B() {}
- // CHECK-LABEL: define void @_ZN5test21BD2Ev(%"struct.test2::B"* %this) unnamed_addr
- // CHECK: call void @_ZN5test21AD2Ev
+ // CHECK4-LABEL: define void @_ZN5test21BD2Ev(%"struct.test2::B"* %this) unnamed_addr
+ // CHECK4: call void @_ZN5test21AD2Ev
}
// PR7142
@@ -187,14 +184,63 @@ namespace test3 {
void test() {
new D; // Force emission of D's vtable
}
+
+ // CHECK4-LABEL: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::(anonymous namespace)::D"* %this) unnamed_addr
+ // CHECK4: invoke void {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
+ // CHECK4: call void @_ZdlPv({{.*}}) [[NUW:#[0-9]+]]
+ // CHECK4: ret void
+ // CHECK4: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK4-NEXT: cleanup
+ // CHECK4: call void @_ZdlPv({{.*}}) [[NUW]]
+ // CHECK4: resume { i8*, i32 }
+
+ // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD1Ev(
+ // CHECK4: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK4: call void {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
+ // CHECK4: ret void
+
+ // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD0Ev(
+ // CHECK4: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK4: call void @_ZN5test312_GLOBAL__N_11DD0Ev(
+ // CHECK4: ret void
+
+ // CHECK4-LABEL: declare void @_ZN5test31BD2Ev(
+ // CHECK4-LABEL: declare void @_ZN5test31AD2Ev(
+
+ // CHECK4-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(%"struct.test3::(anonymous namespace)::C"* %this) unnamed_addr
+ // CHECK4: invoke void @_ZN5test31BD2Ev(
+ // CHECK4: call void @_ZN5test31AD2Ev(
+ // CHECK4: ret void
+
+
+ // CHECK4-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::(anonymous namespace)::C"* %this) unnamed_addr
+ // CHECK4: invoke void @_ZN5test312_GLOBAL__N_11CD2Ev(
+ // CHECK4: call void @_ZdlPv({{.*}}) [[NUW]]
+ // CHECK4: ret void
+ // CHECK4: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK4-NEXT: cleanup
+ // CHECK4: call void @_ZdlPv({{.*}}) [[NUW]]
+ // CHECK4: resume { i8*, i32 }
+
+ // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
+ // CHECK4: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD2Ev(
+ // CHECK4: ret void
+
+ // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev(
+ // CHECK4: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD0Ev(
+ // CHECK4: ret void
+
+ // CHECK4: attributes [[NUW]] = {{[{].*}} nounwind {{.*[}]}}
}
namespace test4 {
struct A { ~A(); };
- // CHECK-LABEL: define void @_ZN5test43fooEv()
- // CHECK: call void @_ZN5test41AD1Ev
- // CHECK: ret void
+ // CHECK5-LABEL: define void @_ZN5test43fooEv()
+ // CHECK5: call void @_ZN5test41AD1Ev
+ // CHECK5: ret void
void foo() {
{
A a;
@@ -205,20 +251,20 @@ namespace test4 {
return;
}
- // CHECK-LABEL: define void @_ZN5test43barEi(
- // CHECK: [[X:%.*]] = alloca i32
- // CHECK-NEXT: [[A:%.*]] = alloca
- // CHECK: br label
- // CHECK: [[TMP:%.*]] = load i32* [[X]]
- // CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP]], 0
- // CHECK-NEXT: br i1
- // CHECK: call void @_ZN5test41AD1Ev(
- // CHECK: br label
- // CHECK: [[TMP:%.*]] = load i32* [[X]]
- // CHECK: [[TMP2:%.*]] = add nsw i32 [[TMP]], -1
- // CHECK: store i32 [[TMP2]], i32* [[X]]
- // CHECK: br label
- // CHECK: ret void
+ // CHECK5-LABEL: define void @_ZN5test43barEi(
+ // CHECK5: [[X:%.*]] = alloca i32
+ // CHECK5-NEXT: [[A:%.*]] = alloca
+ // CHECK5: br label
+ // CHECK5: [[TMP:%.*]] = load i32* [[X]]
+ // CHECK5-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP]], 0
+ // CHECK5-NEXT: br i1
+ // CHECK5: call void @_ZN5test41AD1Ev(
+ // CHECK5: br label
+ // CHECK5: [[TMP:%.*]] = load i32* [[X]]
+ // CHECK5: [[TMP2:%.*]] = add nsw i32 [[TMP]], -1
+ // CHECK5: store i32 [[TMP2]], i32* [[X]]
+ // CHECK5: br label
+ // CHECK5: ret void
void bar(int x) {
for (A a; x; ) {
x--;
@@ -230,27 +276,27 @@ namespace test4 {
namespace test5 {
struct A { ~A(); };
- // CHECK-LABEL: define void @_ZN5test53fooEv()
- // CHECK: [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align
- // CHECK-NEXT: [[EXN:%.*]] = alloca i8*
- // CHECK-NEXT: [[SEL:%.*]] = alloca i32
- // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x [[A]]]* [[ELEMS]], i32 0, i32 0
- // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 5
- // CHECK-NEXT: br label
- // CHECK: [[POST:%.*]] = phi [[A]]* [ [[END]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
- // CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]]* [[POST]], i64 -1
- // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[ELT]])
- // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ELT]], [[BEGIN]]
- // CHECK-NEXT: br i1 [[T0]],
- // CHECK: ret void
+ // CHECK5-LABEL: define void @_ZN5test53fooEv()
+ // CHECK5: [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align
+ // CHECK5-NEXT: [[EXN:%.*]] = alloca i8*
+ // CHECK5-NEXT: [[SEL:%.*]] = alloca i32
+ // CHECK5-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x [[A]]]* [[ELEMS]], i32 0, i32 0
+ // CHECK5-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 5
+ // CHECK5-NEXT: br label
+ // CHECK5: [[POST:%.*]] = phi [[A]]* [ [[END]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
+ // CHECK5-NEXT: [[ELT]] = getelementptr inbounds [[A]]* [[POST]], i64 -1
+ // CHECK5-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[ELT]])
+ // CHECK5: [[T0:%.*]] = icmp eq [[A]]* [[ELT]], [[BEGIN]]
+ // CHECK5-NEXT: br i1 [[T0]],
+ // CHECK5: ret void
// lpad
- // CHECK: [[EMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[ELT]]
- // CHECK-NEXT: br i1 [[EMPTY]]
- // CHECK: [[AFTER:%.*]] = phi [[A]]* [ [[ELT]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
- // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1
- // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[CUR]])
- // CHECK: [[DONE:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]]
- // CHECK-NEXT: br i1 [[DONE]],
+ // CHECK5: [[EMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[ELT]]
+ // CHECK5-NEXT: br i1 [[EMPTY]]
+ // CHECK5: [[AFTER:%.*]] = phi [[A]]* [ [[ELT]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
+ // CHECK5-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1
+ // CHECK5-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[CUR]])
+ // CHECK5: [[DONE:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]]
+ // CHECK5-NEXT: br i1 [[DONE]],
void foo() {
A elems[5];
}
@@ -269,37 +315,37 @@ namespace test6 {
};
C::C() { opaque(); }
- // CHECK-LABEL: define void @_ZN5test61CC1Ev(%"struct.test6::C"* %this) unnamed_addr
- // CHECK: call void @_ZN5test61BILj2EEC2Ev
- // CHECK: invoke void @_ZN5test61BILj3EEC2Ev
- // CHECK: invoke void @_ZN5test61BILj0EEC2Ev
- // CHECK: invoke void @_ZN5test61BILj1EEC2Ev
- // CHECK: invoke void @_ZN5test66opaqueEv
- // CHECK: ret void
+ // CHECK5-LABEL: define void @_ZN5test61CC1Ev(%"struct.test6::C"* %this) unnamed_addr
+ // CHECK5: call void @_ZN5test61BILj2EEC2Ev
+ // CHECK5: invoke void @_ZN5test61BILj3EEC2Ev
+ // CHECK5: invoke void @_ZN5test61BILj0EEC2Ev
+ // CHECK5: invoke void @_ZN5test61BILj1EEC2Ev
+ // CHECK5: invoke void @_ZN5test66opaqueEv
+ // CHECK5: ret void
// FIXME: way too much EH cleanup code follows
C::~C() { opaque(); }
- // CHECK-LABEL: define void @_ZN5test61CD2Ev(%"struct.test6::C"* %this, i8** %vtt) unnamed_addr
- // CHECK: invoke void @_ZN5test66opaqueEv
- // CHECK: invoke void @_ZN5test61AD1Ev
- // CHECK: invoke void @_ZN5test61AD1Ev
- // CHECK: invoke void @_ZN5test61AD1Ev
- // CHECK: invoke void @_ZN5test61BILj1EED2Ev
- // CHECK: call void @_ZN5test61BILj0EED2Ev
- // CHECK: ret void
- // CHECK: invoke void @_ZN5test61AD1Ev
- // CHECK: invoke void @_ZN5test61AD1Ev
- // CHECK: invoke void @_ZN5test61AD1Ev
- // CHECK: invoke void @_ZN5test61BILj1EED2Ev
- // CHECK: invoke void @_ZN5test61BILj0EED2Ev
-
- // CHECK-LABEL: define void @_ZN5test61CD1Ev(%"struct.test6::C"* %this) unnamed_addr
- // CHECK: invoke void @_ZN5test61CD2Ev
- // CHECK: invoke void @_ZN5test61BILj3EED2Ev
- // CHECK: call void @_ZN5test61BILj2EED2Ev
- // CHECK: ret void
- // CHECK: invoke void @_ZN5test61BILj3EED2Ev
- // CHECK: invoke void @_ZN5test61BILj2EED2Ev
+ // CHECK5-LABEL: define void @_ZN5test61CD2Ev(%"struct.test6::C"* %this, i8** %vtt) unnamed_addr
+ // CHECK5: invoke void @_ZN5test66opaqueEv
+ // CHECK5: invoke void @_ZN5test61AD1Ev
+ // CHECK5: invoke void @_ZN5test61AD1Ev
+ // CHECK5: invoke void @_ZN5test61AD1Ev
+ // CHECK5: invoke void @_ZN5test61BILj1EED2Ev
+ // CHECK5: call void @_ZN5test61BILj0EED2Ev
+ // CHECK5: ret void
+ // CHECK5: invoke void @_ZN5test61AD1Ev
+ // CHECK5: invoke void @_ZN5test61AD1Ev
+ // CHECK5: invoke void @_ZN5test61AD1Ev
+ // CHECK5: invoke void @_ZN5test61BILj1EED2Ev
+ // CHECK5: invoke void @_ZN5test61BILj0EED2Ev
+
+ // CHECK5-LABEL: define void @_ZN5test61CD1Ev(%"struct.test6::C"* %this) unnamed_addr
+ // CHECK5: invoke void @_ZN5test61CD2Ev
+ // CHECK5: invoke void @_ZN5test61BILj3EED2Ev
+ // CHECK5: call void @_ZN5test61BILj2EED2Ev
+ // CHECK5: ret void
+ // CHECK5: invoke void @_ZN5test61BILj3EED2Ev
+ // CHECK5: invoke void @_ZN5test61BILj2EED2Ev
}
// PR 9197
@@ -315,9 +361,9 @@ namespace test7 {
};
// Verify that this doesn't get emitted as an alias
- // CHECK-LABEL: define void @_ZN5test71BD2Ev(
- // CHECK: invoke void @_ZN5test71DD1Ev(
- // CHECK: call void @_ZN5test71AD2Ev(
+ // CHECK5-LABEL: define void @_ZN5test71BD2Ev(
+ // CHECK5: invoke void @_ZN5test71DD1Ev(
+ // CHECK5: call void @_ZN5test71AD2Ev(
B::~B() {}
}
@@ -335,16 +381,16 @@ namespace test8 {
l: die();
}
- // CHECK-LABEL: define void @_ZN5test84testEv()
- // CHECK: [[X:%.*]] = alloca [[A:%.*]], align 1
- // CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]], align 1
- // CHECK: call void @_ZN5test81AC1Ev([[A]]* [[X]])
- // CHECK-NEXT: br label
- // CHECK: invoke void @_ZN5test81AC1Ev([[A]]* [[Y]])
- // CHECK: invoke void @_ZN5test81AD1Ev([[A]]* [[Y]])
- // CHECK-NOT: switch
- // CHECK: invoke void @_ZN5test83dieEv()
- // CHECK: unreachable
+ // CHECK5-LABEL: define void @_ZN5test84testEv()
+ // CHECK5: [[X:%.*]] = alloca [[A:%.*]], align 1
+ // CHECK5-NEXT: [[Y:%.*]] = alloca [[A:%.*]], align 1
+ // CHECK5: call void @_ZN5test81AC1Ev([[A]]* [[X]])
+ // CHECK5-NEXT: br label
+ // CHECK5: invoke void @_ZN5test81AC1Ev([[A]]* [[Y]])
+ // CHECK5: invoke void @_ZN5test81AD1Ev([[A]]* [[Y]])
+ // CHECK5-NOT: switch
+ // CHECK5: invoke void @_ZN5test83dieEv()
+ // CHECK5: unreachable
}
// PR12710
@@ -359,8 +405,8 @@ namespace test9 {
f1<int>();
f2();
}
- // CHECK: call void @_ZN5test97ArgTypeD1Ev(%"struct.test9::ArgType"* %
- // CHECK: call void @_ZN5test92f2Ev()
+ // CHECK5: call void @_ZN5test97ArgTypeD1Ev(%"struct.test9::ArgType"* %
+ // CHECK5: call void @_ZN5test92f2Ev()
}
namespace test10 {
@@ -371,60 +417,10 @@ namespace test10 {
};
template <class DataType> class opt : public Option {};
template class opt<int>;
- // CHECK-LABEL: define zeroext i1 @_ZN6test1016handleOccurrenceEv(
+ // CHECK5-LABEL: define zeroext i1 @_ZN6test1016handleOccurrenceEv(
bool handleOccurrence() {
- // CHECK: call void @_ZN6test106OptionD2Ev(
+ // CHECK5: call void @_ZN6test106OptionD2Ev(
Option x;
return true;
}
}
-
-// Checks from test3:
-
- // CHECK-LABEL: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::(anonymous namespace)::D"* %this) unnamed_addr
- // CHECK: invoke void {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
- // CHECK: call void @_ZdlPv({{.*}}) [[NUW:#[0-9]+]]
- // CHECK: ret void
- // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
- // CHECK-NEXT: cleanup
- // CHECK: call void @_ZdlPv({{.*}}) [[NUW]]
- // CHECK: resume { i8*, i32 }
-
- // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD1Ev(
- // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
- // CHECK: call void {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
- // CHECK: ret void
-
- // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD0Ev(
- // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
- // CHECK: call void @_ZN5test312_GLOBAL__N_11DD0Ev(
- // CHECK: ret void
-
- // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
- // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
- // CHECK: call void @_ZN5test312_GLOBAL__N_11CD2Ev(
- // CHECK: ret void
-
- // CHECK-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(%"struct.test3::(anonymous namespace)::C"* %this) unnamed_addr
- // CHECK: invoke void @_ZN5test31BD2Ev(
- // CHECK: call void @_ZN5test31AD2Ev(
- // CHECK: ret void
-
- // CHECK: declare void @_ZN5test31BD2Ev(
- // CHECK: declare void @_ZN5test31AD2Ev(
-
- // CHECK-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::(anonymous namespace)::C"* %this) unnamed_addr
- // CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD2Ev(
- // CHECK: call void @_ZdlPv({{.*}}) [[NUW]]
- // CHECK: ret void
- // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
- // CHECK-NEXT: cleanup
- // CHECK: call void @_ZdlPv({{.*}}) [[NUW]]
- // CHECK: resume { i8*, i32 }
-
- // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev(
- // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
- // CHECK: call void @_ZN5test312_GLOBAL__N_11CD0Ev(
- // CHECK: ret void
-
- // CHECK: attributes [[NUW]] = {{[{].*}} nounwind {{.*[}]}}
diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
index 11026e8df3e7..193ee5f80406 100644
--- a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
+++ b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
@@ -53,26 +53,32 @@ namespace Test3 {
namespace Test4 {
struct A {
virtual void f();
+ virtual int operator-();
};
struct B final : A {
virtual void f();
+ virtual int operator-();
};
// CHECK-LABEL: define void @_ZN5Test41fEPNS_1BE
void f(B* d) {
// CHECK: call void @_ZN5Test41B1fEv
static_cast<A*>(d)->f();
+ // CHECK: call i32 @_ZN5Test41BngEv
+ -static_cast<A&>(*d);
}
}
namespace Test5 {
struct A {
virtual void f();
+ virtual int operator-();
};
struct B : A {
virtual void f();
+ virtual int operator-();
};
struct C final : B {
@@ -87,6 +93,15 @@ namespace Test5 {
// CHECK-NEXT: call void %[[FUNC]]
static_cast<A*>(d)->f();
}
+ // CHECK-LABEL: define void @_ZN5Test53fopEPNS_1CE
+ void fop(C* d) {
+ // FIXME: It should be possible to devirtualize this case, but that is
+ // not implemented yet.
+ // CHECK: getelementptr
+ // CHECK-NEXT: %[[FUNC:.*]] = load
+ // CHECK-NEXT: call i32 %[[FUNC]]
+ -static_cast<A&>(*d);
+ }
}
namespace Test6 {
@@ -165,6 +180,9 @@ namespace Test9 {
virtual A *f() {
return 0;
}
+ virtual A *operator-() {
+ return 0;
+ }
};
struct RC final : public RA {
virtual C *f() {
@@ -173,15 +191,37 @@ namespace Test9 {
x->b = 2;
return x;
}
+ virtual C *operator-() {
+ C *x = new C();
+ x->a = 1;
+ x->b = 2;
+ return x;
+ }
};
// CHECK: define {{.*}} @_ZN5Test91fEPNS_2RCE
A *f(RC *x) {
// FIXME: It should be possible to devirtualize this case, but that is
// not implemented yet.
- // CHECK: getelementptr
- // CHECK-NEXT: %[[FUNC:.*]] = load
- // CHECK-NEXT: bitcast
+ // CHECK: load
+ // CHECK: bitcast
+ // CHECK: [[F_PTR_RA:%.+]] = bitcast
+ // CHECK: [[VTABLE:%.+]] = load {{.+}} [[F_PTR_RA]]
+ // CHECK: [[VFN:%.+]] = getelementptr inbounds {{.+}} [[VTABLE]], i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[FUNC:.*]] = load {{.+}} [[VFN]]
// CHECK-NEXT: = call {{.*}} %[[FUNC]]
return static_cast<RA*>(x)->f();
}
+ // CHECK: define {{.*}} @_ZN5Test93fopEPNS_2RCE
+ A *fop(RC *x) {
+ // FIXME: It should be possible to devirtualize this case, but that is
+ // not implemented yet.
+ // CHECK: load
+ // CHECK: bitcast
+ // CHECK: [[F_PTR_RA:%.+]] = bitcast
+ // CHECK: [[VTABLE:%.+]] = load {{.+}} [[F_PTR_RA]]
+ // CHECK: [[VFN:%.+]] = getelementptr inbounds {{.+}} [[VTABLE]], i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[FUNC:.*]] = load {{.+}} [[VFN]]
+ // CHECK-NEXT: = call {{.*}} %[[FUNC]]
+ return -static_cast<RA&>(*x);
+ }
}
diff --git a/test/CodeGenCXX/dllexport-alias.cpp b/test/CodeGenCXX/dllexport-alias.cpp
new file mode 100644
index 000000000000..479595d05751
--- /dev/null
+++ b/test/CodeGenCXX/dllexport-alias.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -mconstructor-aliases %s -S -emit-llvm -o - | FileCheck %s
+
+// This test assumes that the C1 constructor will be aliased to the C2
+// constructor, and the D1 destructor to the D2. It then checks that the aliases
+// are dllexport'ed.
+
+class __declspec(dllexport) A {
+public:
+ A();
+ ~A();
+};
+
+A::A() {}
+
+A::~A() {}
+
+// CHECK: @_ZN1AC1Ev = dllexport alias void (%class.A*)* @_ZN1AC2Ev
+// CHECK: @_ZN1AD1Ev = dllexport alias void (%class.A*)* @_ZN1AD2Ev
diff --git a/test/CodeGenCXX/dllexport-members.cpp b/test/CodeGenCXX/dllexport-members.cpp
index d913c09ec7be..5b2af1e04bd7 100644
--- a/test/CodeGenCXX/dllexport-members.cpp
+++ b/test/CodeGenCXX/dllexport-members.cpp
@@ -110,9 +110,9 @@ public:
// MSC-DAG: @"\01?StaticField@ExportMembers@@2HA" = dllexport global i32 1, align 4
// MSC-DAG: @"\01?StaticConstField@ExportMembers@@2HB" = dllexport constant i32 1, align 4
- // MSC-DAG: @"\01?StaticConstFieldEqualInit@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, align 4
- // MSC-DAG: @"\01?StaticConstFieldBraceInit@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, align 4
- // MSC-DAG: @"\01?ConstexprField@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, align 4
+ // MSC-DAG: @"\01?StaticConstFieldEqualInit@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
+ // MSC-DAG: @"\01?StaticConstFieldBraceInit@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
+ // MSC-DAG: @"\01?ConstexprField@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
// GNU-DAG: @_ZN13ExportMembers11StaticFieldE = dllexport global i32 1, align 4
// GNU-DAG: @_ZN13ExportMembers16StaticConstFieldE = dllexport constant i32 1, align 4
// GNU-DAG: @_ZN13ExportMembers25StaticConstFieldEqualInitE = dllexport constant i32 1, align 4
@@ -233,9 +233,9 @@ public:
// MSC-DAG: @"\01?StaticField@Nested@ExportMembers@@2HA" = dllexport global i32 1, align 4
// MSC-DAG: @"\01?StaticConstField@Nested@ExportMembers@@2HB" = dllexport constant i32 1, align 4
- // MSC-DAG: @"\01?StaticConstFieldEqualInit@Nested@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, align 4
- // MSC-DAG: @"\01?StaticConstFieldBraceInit@Nested@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, align 4
- // MSC-DAG: @"\01?ConstexprField@Nested@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, align 4
+ // MSC-DAG: @"\01?StaticConstFieldEqualInit@Nested@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
+ // MSC-DAG: @"\01?StaticConstFieldBraceInit@Nested@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
+ // MSC-DAG: @"\01?ConstexprField@Nested@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
// GNU-DAG: @_ZN13ExportMembers6Nested11StaticFieldE = dllexport global i32 1, align 4
// GNU-DAG: @_ZN13ExportMembers6Nested16StaticConstFieldE = dllexport constant i32 1, align 4
// GNU-DAG: @_ZN13ExportMembers6Nested25StaticConstFieldEqualInitE = dllexport constant i32 1, align 4
@@ -599,21 +599,21 @@ template<typename T> const int MemVarTmpl::StaticVar;
template<typename T> const int MemVarTmpl::ExportedStaticVar;
// Export implicit instantiation of an exported member variable template.
-// MSC-DAG: @"\01??$ExportedStaticVar@UImplicitInst_Exported@@@MemVarTmpl@@2HB" = weak_odr dllexport constant i32 1, align 4
-// GNU-DAG: @_ZN10MemVarTmpl17ExportedStaticVarI21ImplicitInst_ExportedEE = weak_odr dllexport constant i32 1, align 4
+// MSC-DAG: @"\01??$ExportedStaticVar@UImplicitInst_Exported@@@MemVarTmpl@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
+// GNU-DAG: @_ZN10MemVarTmpl17ExportedStaticVarI21ImplicitInst_ExportedEE = weak_odr dllexport constant i32 1, comdat, align 4
int useMemVarTmpl() { return MemVarTmpl::ExportedStaticVar<ImplicitInst_Exported>; }
// Export explicit instantiation declaration of an exported member variable
// template.
-// MSC-DAG: @"\01??$ExportedStaticVar@UExplicitDecl_Exported@@@MemVarTmpl@@2HB" = weak_odr dllexport constant i32 1, align 4
-// GNU-DAG: @_ZN10MemVarTmpl17ExportedStaticVarI21ExplicitDecl_ExportedEE = weak_odr dllexport constant i32 1, align 4
+// MSC-DAG: @"\01??$ExportedStaticVar@UExplicitDecl_Exported@@@MemVarTmpl@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
+// GNU-DAG: @_ZN10MemVarTmpl17ExportedStaticVarI21ExplicitDecl_ExportedEE = weak_odr dllexport constant i32 1, comdat, align 4
extern template const int MemVarTmpl::ExportedStaticVar<ExplicitDecl_Exported>;
template const int MemVarTmpl::ExportedStaticVar<ExplicitDecl_Exported>;
// Export explicit instantiation definition of an exported member variable
// template.
-// MSC-DAG: @"\01??$ExportedStaticVar@UExplicitInst_Exported@@@MemVarTmpl@@2HB" = weak_odr dllexport constant i32 1, align 4
-// GNU-DAG: @_ZN10MemVarTmpl17ExportedStaticVarI21ExplicitInst_ExportedEE = weak_odr dllexport constant i32 1, align 4
+// MSC-DAG: @"\01??$ExportedStaticVar@UExplicitInst_Exported@@@MemVarTmpl@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
+// GNU-DAG: @_ZN10MemVarTmpl17ExportedStaticVarI21ExplicitInst_ExportedEE = weak_odr dllexport constant i32 1, comdat, align 4
template const int MemVarTmpl::ExportedStaticVar<ExplicitInst_Exported>;
// Export specialization of an exported member variable template.
@@ -630,15 +630,15 @@ template<> const int MemVarTmpl::ExportedStaticVar<ExplicitSpec_NotExported> = 1
// Export explicit instantiation declaration of a non-exported member variable
// template.
-// MSC-DAG: @"\01??$StaticVar@UExplicitDecl_Exported@@@MemVarTmpl@@2HB" = weak_odr dllexport constant i32 1, align 4
-// GNU-DAG: @_ZN10MemVarTmpl9StaticVarI21ExplicitDecl_ExportedEE = weak_odr dllexport constant i32 1, align 4
+// MSC-DAG: @"\01??$StaticVar@UExplicitDecl_Exported@@@MemVarTmpl@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
+// GNU-DAG: @_ZN10MemVarTmpl9StaticVarI21ExplicitDecl_ExportedEE = weak_odr dllexport constant i32 1, comdat, align 4
extern template __declspec(dllexport) const int MemVarTmpl::StaticVar<ExplicitDecl_Exported>;
template __declspec(dllexport) const int MemVarTmpl::StaticVar<ExplicitDecl_Exported>;
// Export explicit instantiation definition of a non-exported member variable
// template.
-// MSC-DAG: @"\01??$StaticVar@UExplicitInst_Exported@@@MemVarTmpl@@2HB" = weak_odr dllexport constant i32 1, align 4
-// GNU-DAG: @_ZN10MemVarTmpl9StaticVarI21ExplicitInst_ExportedEE = weak_odr dllexport constant i32 1, align 4
+// MSC-DAG: @"\01??$StaticVar@UExplicitInst_Exported@@@MemVarTmpl@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4
+// GNU-DAG: @_ZN10MemVarTmpl9StaticVarI21ExplicitInst_ExportedEE = weak_odr dllexport constant i32 1, comdat, align 4
template __declspec(dllexport) const int MemVarTmpl::StaticVar<ExplicitInst_Exported>;
// Export specialization of a non-exported member variable template.
diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp
index 5097abf0c094..93bd1f5fe99c 100644
--- a/test/CodeGenCXX/dllexport.cpp
+++ b/test/CodeGenCXX/dllexport.cpp
@@ -1,9 +1,7 @@
-// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=MSC --check-prefix=M32 %s
-// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=MSC --check-prefix=M64 %s
-// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G32 %s
-// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G64 %s
-
-// RUN: %clang_cc1 -triple i686-pc-win32 -O1 -mconstructor-aliases -std=c++1y -emit-llvm -o - %s | FileCheck %s --check-prefix=MSC --check-prefix=M32
+// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++1y -O1 -mconstructor-aliases -disable-llvm-optzns -o - %s -w | FileCheck --check-prefix=MSC --check-prefix=M32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c++1y -O0 -o - %s -w | FileCheck --check-prefix=MSC --check-prefix=M64 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s -w | FileCheck --check-prefix=GNU --check-prefix=G32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s -w | FileCheck --check-prefix=GNU --check-prefix=G64 %s
// Helper structs to make templates more expressive.
struct ImplicitInst_Exported {};
@@ -77,8 +75,8 @@ namespace ns { __declspec(dllexport) int ExternalGlobal; }
__declspec(dllexport) auto ExternalAutoTypeGlobal = External();
int f();
-// MSC-DAG: @"\01?x@?0??nonInlineStaticLocalsFunc@@YAHXZ@4HA" = internal {{(unnamed_addr )*}}global i32 0
-// MSC-DAG: @"\01?$S1@?0??nonInlineStaticLocalsFunc@@YAHXZ@4IA" = internal {{(unnamed_addr )*}}global i32 0
+// MSC-DAG: @"\01?x@?1??nonInlineStaticLocalsFunc@@YAHXZ@4HA" = internal {{(unnamed_addr )*}}global i32 0
+// MSC-DAG: @"\01?$S1@?1??nonInlineStaticLocalsFunc@@YAHXZ@4IA" = internal {{(unnamed_addr )*}}global i32 0
int __declspec(dllexport) nonInlineStaticLocalsFunc() {
static int x = f();
return x++;
@@ -112,43 +110,43 @@ template<typename T> __declspec(dllexport) int VarTmplImplicitDef;
USEVAR(VarTmplImplicitDef<ImplicitInst_Exported>)
// Export definition.
-// MSC-DAG: @"\01??$VarTmplInit1@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_Z12VarTmplInit1I21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$VarTmplInit1@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_Z12VarTmplInit1I21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, comdat, align 4
template<typename T> __declspec(dllexport) int VarTmplInit1 = 1;
INSTVAR(VarTmplInit1<ExplicitInst_Exported>)
-// MSC-DAG: @"\01??$VarTmplInit2@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_Z12VarTmplInit2I21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$VarTmplInit2@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_Z12VarTmplInit2I21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, comdat, align 4
template<typename T> int __declspec(dllexport) VarTmplInit2 = 1;
INSTVAR(VarTmplInit2<ExplicitInst_Exported>)
// Declare, then export definition.
-// MSC-DAG: @"\01??$VarTmplDeclInit@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_Z15VarTmplDeclInitI21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$VarTmplDeclInit@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_Z15VarTmplDeclInitI21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, comdat, align 4
template<typename T> __declspec(dllexport) extern int VarTmplDeclInit;
template<typename T> int VarTmplDeclInit = 1;
INSTVAR(VarTmplDeclInit<ExplicitInst_Exported>)
// Redeclarations
-// MSC-DAG: @"\01??$VarTmplRedecl1@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_Z14VarTmplRedecl1I21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$VarTmplRedecl1@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_Z14VarTmplRedecl1I21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, comdat, align 4
template<typename T> __declspec(dllexport) extern int VarTmplRedecl1;
template<typename T> __declspec(dllexport) int VarTmplRedecl1 = 1;
INSTVAR(VarTmplRedecl1<ExplicitInst_Exported>)
-// MSC-DAG: @"\01??$VarTmplRedecl2@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_Z14VarTmplRedecl2I21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$VarTmplRedecl2@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_Z14VarTmplRedecl2I21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, comdat, align 4
template<typename T> __declspec(dllexport) extern int VarTmplRedecl2;
template<typename T> int VarTmplRedecl2 = 1;
INSTVAR(VarTmplRedecl2<ExplicitInst_Exported>)
-// MSC-DAG: @"\01??$ExternalVarTmpl@UExplicitInst_Exported@@@ns@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_ZN2ns15ExternalVarTmplI21ExplicitInst_ExportedEE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$ExternalVarTmpl@UExplicitInst_Exported@@@ns@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_ZN2ns15ExternalVarTmplI21ExplicitInst_ExportedEE = weak_odr dllexport global i32 1, comdat, align 4
namespace ns { template<typename T> __declspec(dllexport) int ExternalVarTmpl = 1; }
INSTVAR(ns::ExternalVarTmpl<ExplicitInst_Exported>)
-// MSC-DAG: @"\01??$ExternalAutoTypeVarTmpl@UExplicitInst_Exported@@@@3UExternal@@A" = weak_odr dllexport global %struct.External zeroinitializer, align 4
-// GNU-DAG: @_Z23ExternalAutoTypeVarTmplI21ExplicitInst_ExportedE = weak_odr dllexport global %struct.External zeroinitializer, align 4
+// MSC-DAG: @"\01??$ExternalAutoTypeVarTmpl@UExplicitInst_Exported@@@@3UExternal@@A" = weak_odr dllexport global %struct.External zeroinitializer, comdat, align 4
+// GNU-DAG: @_Z23ExternalAutoTypeVarTmplI21ExplicitInst_ExportedE = weak_odr dllexport global %struct.External zeroinitializer, comdat, align 4
template<typename T> __declspec(dllexport) auto ExternalAutoTypeVarTmpl = External();
template External ExternalAutoTypeVarTmpl<ExplicitInst_Exported>;
@@ -157,19 +155,19 @@ template<typename T> int VarTmpl = 1;
template<typename T> __declspec(dllexport) int ExportedVarTmpl = 1;
// Export implicit instantiation of an exported variable template.
-// MSC-DAG: @"\01??$ExportedVarTmpl@UImplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_Z15ExportedVarTmplI21ImplicitInst_ExportedE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$ExportedVarTmpl@UImplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_Z15ExportedVarTmplI21ImplicitInst_ExportedE = weak_odr dllexport global i32 1, comdat, align 4
USEVAR(ExportedVarTmpl<ImplicitInst_Exported>)
// Export explicit instantiation declaration of an exported variable template.
-// MSC-DAG: @"\01??$ExportedVarTmpl@UImplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_Z15ExportedVarTmplI21ExplicitDecl_ExportedE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$ExportedVarTmpl@UImplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_Z15ExportedVarTmplI21ExplicitDecl_ExportedE = weak_odr dllexport global i32 1, comdat, align 4
extern template int ExportedVarTmpl<ExplicitDecl_Exported>;
template int ExportedVarTmpl<ExplicitDecl_Exported>;
// Export explicit instantiation definition of an exported variable template.
-// MSC-DAG: @"\01??$ExportedVarTmpl@UImplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_Z15ExportedVarTmplI21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$ExportedVarTmpl@UImplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_Z15ExportedVarTmplI21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, comdat, align 4
template __declspec(dllexport) int ExportedVarTmpl<ExplicitInst_Exported>;
// Export specialization of an exported variable template.
@@ -189,14 +187,14 @@ template<> int ExportedVarTmpl<ExplicitSpec_NotExported>;
// Export explicit instantiation declaration of a non-exported variable template.
-// MSC-DAG: @"\01??$VarTmpl@UExplicitDecl_Exported@@@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_Z7VarTmplI21ExplicitDecl_ExportedE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$VarTmpl@UExplicitDecl_Exported@@@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_Z7VarTmplI21ExplicitDecl_ExportedE = weak_odr dllexport global i32 1, comdat, align 4
extern template __declspec(dllexport) int VarTmpl<ExplicitDecl_Exported>;
template __declspec(dllexport) int VarTmpl<ExplicitDecl_Exported>;
// Export explicit instantiation definition of a non-exported variable template.
-// MSC-DAG: @"\01??$VarTmpl@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, align 4
-// GNU-DAG: @_Z7VarTmplI21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, align 4
+// MSC-DAG: @"\01??$VarTmpl@UExplicitInst_Exported@@@@3HA" = weak_odr dllexport global i32 1, comdat, align 4
+// GNU-DAG: @_Z7VarTmplI21ExplicitInst_ExportedE = weak_odr dllexport global i32 1, comdat, align 4
template __declspec(dllexport) int VarTmpl<ExplicitInst_Exported>;
// Export specialization of a non-exported variable template.
@@ -509,11 +507,9 @@ USEVAR(T::b)
int T::c;
template <typename T> struct __declspec(dllexport) U { void foo() {} };
-// The U<int> specialization below must cause the following to be emitted:
-// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?foo@?$U@H@@QAEXXZ"
-// M32-DAG: define weak_odr dllexport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.U* @"\01??4?$U@H@@QAEAAU0@ABU0@@Z"
struct __declspec(dllexport) V : public U<int> { };
-
+// U<int>'s assignment operator is emitted.
+// M32-DAG: define weak_odr dllexport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.U* @"\01??4?$U@H@@QAEAAU0@ABU0@@Z"
struct __declspec(dllexport) W { virtual void foo() {} };
// Default ctor:
@@ -521,7 +517,7 @@ struct __declspec(dllexport) W { virtual void foo() {} };
// Copy ctor:
// M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.W* @"\01??0W@@QAE@ABU0@@Z"
// vftable:
-// M32-DAG: [[W_VTABLE:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4W@@6B@" to i8*), i8* bitcast (void (%struct.W*)* @"\01?foo@W@@UAEXXZ" to i8*)], comdat $"\01??_7W@@6B@"
+// M32-DAG: [[W_VTABLE:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4W@@6B@" to i8*), i8* bitcast (void (%struct.W*)* @"\01?foo@W@@UAEXXZ" to i8*)], comdat($"\01??_7W@@6B@")
// M32-DAG: @"\01??_7W@@6B@" = dllexport unnamed_addr alias getelementptr inbounds ([2 x i8*]* [[W_VTABLE]], i32 0, i32 1)
// G32-DAG: @_ZTV1W = weak_odr dllexport unnamed_addr constant [3 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1W to i8*), i8* bitcast (void (%struct.W*)* @_ZN1W3fooEv to i8*)]
@@ -538,19 +534,20 @@ struct __declspec(dllexport) Y {
struct __declspec(dllexport) Z { virtual ~Z() {} };
// The scalar deleting dtor does not get exported:
-// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01??_GZ@@UAEPAXI@Z"
+// M32-DAG: define linkonce_odr x86_thiscallcc i8* @"\01??_GZ@@UAEPAXI@Z"
// The user-defined dtor does get exported:
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??1Z@@UAE@XZ"
-namespace DontUseDtorAlias {
+namespace UseDtorAlias {
struct __declspec(dllexport) A { ~A(); };
struct __declspec(dllexport) B : A { ~B(); };
A::~A() { }
B::~B() { }
- // Emit a real definition of B's constructor; don't alias it to A's.
- // M32-DAG: define dllexport x86_thiscallcc void @"\01??1B@DontUseDtorAlias@@QAE@XZ"
+ // Emit a alias definition of B's constructor.
+ // M32-DAG: @"\01??1B@UseDtorAlias@@QAE@XZ" = dllexport alias {{.*}} @"\01??1A@UseDtorAlias@@QAE@XZ"
+
}
struct __declspec(dllexport) DefaultedCtorsDtors {
@@ -581,106 +578,155 @@ USEMEMFUNC(PartiallySpecializedClassTemplate<void*>, f);
// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?f@?$PartiallySpecializedClassTemplate@PAX@@QAEXXZ"
// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN33PartiallySpecializedClassTemplateIPvE1fEv
+// Attributes on explicit specializations are honored.
template <typename T> struct ExplicitlySpecializedClassTemplate {};
template <> struct __declspec(dllexport) ExplicitlySpecializedClassTemplate<void*> { void f() {} };
USEMEMFUNC(ExplicitlySpecializedClassTemplate<void*>, f);
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$ExplicitlySpecializedClassTemplate@PAX@@QAEXXZ"
// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN34ExplicitlySpecializedClassTemplateIPvE1fEv
+// MS inherits DLL attributes to partial specializations.
+template <typename T> struct __declspec(dllexport) PartiallySpecializedExportedClassTemplate {};
+template <typename T> struct PartiallySpecializedExportedClassTemplate<T*> { void f() {} };
+USEMEMFUNC(PartiallySpecializedExportedClassTemplate<void*>, f);
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$PartiallySpecializedExportedClassTemplate@PAX@@QAEXXZ"
+// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN41PartiallySpecializedExportedClassTemplateIPvE1fEv
+
+// MS ignores DLL attributes on partial specializations; inheritance still works though.
+template <typename T> struct __declspec(dllexport) PartiallySpecializedExportedClassTemplate2 {};
+template <typename T> struct __declspec(dllimport) PartiallySpecializedExportedClassTemplate2<T*> { void f(); };
+template <typename T> void PartiallySpecializedExportedClassTemplate2<T*>::f() {}
+USEMEMFUNC(PartiallySpecializedExportedClassTemplate2<void*>, f);
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$PartiallySpecializedExportedClassTemplate2@PAX@@QAEXXZ"
+// G32-DAG: declare dllimport x86_thiscallcc void @_ZN42PartiallySpecializedExportedClassTemplate2IPvE1fEv
+
+// Attributes on the instantiation take precedence over attributes on the template.
+template <typename T> struct __declspec(dllimport) ExplicitlyInstantiatedWithDifferentAttr { void f() {} };
+template struct __declspec(dllexport) ExplicitlyInstantiatedWithDifferentAttr<int>;
+USEMEMFUNC(ExplicitlyInstantiatedWithDifferentAttr<int>, f);
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$ExplicitlyInstantiatedWithDifferentAttr@H@@QAEXXZ"
+
+// Don't create weak dllexport aliases. (PR21373)
+struct NonExportedBaseClass {
+ virtual ~NonExportedBaseClass();
+};
+NonExportedBaseClass::~NonExportedBaseClass() {}
+
+struct __declspec(dllexport) ExportedDerivedClass : NonExportedBaseClass {};
+// M32-DAG: weak_odr dllexport x86_thiscallcc void @"\01??1ExportedDerivedClass@@UAE@XZ"
+
+// Do not assert about generating code for constexpr functions twice during explicit instantiation (PR21718).
+template <typename T> struct ExplicitInstConstexprMembers {
+ // Copy assignment operator
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc dereferenceable(1) %struct.ExplicitInstConstexprMembers* @"\01??4?$ExplicitInstConstexprMembers@X@@QAEAAU0@ABU0@@Z"
+
+ constexpr ExplicitInstConstexprMembers() {}
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.ExplicitInstConstexprMembers* @"\01??0?$ExplicitInstConstexprMembers@X@@QAE@XZ"
+
+ ExplicitInstConstexprMembers(const ExplicitInstConstexprMembers&) = default;
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.ExplicitInstConstexprMembers* @"\01??0?$ExplicitInstConstexprMembers@X@@QAE@ABU0@@Z"
+
+ constexpr int f() const { return 42; }
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc i32 @"\01?f@?$ExplicitInstConstexprMembers@X@@QBEHXZ"
+};
+template struct __declspec(dllexport) ExplicitInstConstexprMembers<void>;
+
//===----------------------------------------------------------------------===//
// Classes with template base classes
//===----------------------------------------------------------------------===//
template <typename T> struct ClassTemplate { void func() {} };
template <typename T> struct __declspec(dllexport) ExportedClassTemplate { void func() {} };
-template <typename T> struct __declspec(dllimport) ImportedClassTemplate { void func() {} };
+template <typename T> struct __declspec(dllimport) ImportedClassTemplate { void func(); };
+template <typename T> void ImportedClassTemplate<T>::func() {}
template <typename T> struct ExplicitlySpecializedTemplate { void func() {} };
template <> struct ExplicitlySpecializedTemplate<int> { void func() {} };
template <typename T> struct ExplicitlyExportSpecializedTemplate { void func() {} };
template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate<int> { void func() {} };
-template <typename T> struct ExplicitlyImportSpecializedTemplate { void func() {} };
-template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func() {} };
+template <typename T> struct ExplicitlyImportSpecializedTemplate { void func(); };
+template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func(); };
template <typename T> struct ExplicitlyInstantiatedTemplate { void func() {} };
template struct ExplicitlyInstantiatedTemplate<int>;
template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} };
template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>;
-template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func() {} };
+template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func(); };
template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>;
// MS: ClassTemplate<int> gets exported.
struct __declspec(dllexport) DerivedFromTemplate : public ClassTemplate<int> {};
-USEMEMFUNC(ClassTemplate<int>, func)
+USEMEMFUNC(DerivedFromTemplate, func)
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ClassTemplate@H@@QAEXXZ"
// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIiE4funcEv
// ExportedTemplate is explicitly exported.
struct __declspec(dllexport) DerivedFromExportedTemplate : public ExportedClassTemplate<int> {};
+USEMEMFUNC(DerivedFromExportedTemplate, func)
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExportedClassTemplate@H@@QAEXXZ"
// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN21ExportedClassTemplateIiE4funcEv
// ImportedClassTemplate is explicitly imported.
struct __declspec(dllexport) DerivedFromImportedTemplate : public ImportedClassTemplate<int> {};
-USEMEMFUNC(ImportedClassTemplate<int>, func)
+USEMEMFUNC(DerivedFromImportedTemplate, func)
// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ImportedClassTemplate@H@@QAEXXZ"
// G32-DAG: declare dllimport x86_thiscallcc void @_ZN21ImportedClassTemplateIiE4funcEv
// Base class already instantiated without dll attribute.
struct DerivedFromTemplateD : public ClassTemplate<double> {};
struct __declspec(dllexport) DerivedFromTemplateD2 : public ClassTemplate<double> {};
-USEMEMFUNC(ClassTemplate<double>, func)
+USEMEMFUNC(DerivedFromTemplateD2, func)
// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?func@?$ClassTemplate@N@@QAEXXZ"
// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIdE4funcEv
// MS: Base class already instantiated with different dll attribute.
struct __declspec(dllimport) DerivedFromTemplateB : public ClassTemplate<bool> {};
struct __declspec(dllexport) DerivedFromTemplateB2 : public ClassTemplate<bool> {};
-USEMEMFUNC(ClassTemplate<bool>, func)
+USEMEMFUNC(DerivedFromTemplateB2, func)
// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ClassTemplate@_N@@QAEXXZ"
// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIbE4funcEv
// Base class already specialized without dll attribute.
struct __declspec(dllexport) DerivedFromExplicitlySpecializedTemplate : public ExplicitlySpecializedTemplate<int> {};
-USEMEMFUNC(ExplicitlySpecializedTemplate<int>, func)
+USEMEMFUNC(DerivedFromExplicitlySpecializedTemplate, func)
// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?func@?$ExplicitlySpecializedTemplate@H@@QAEXXZ"
// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN29ExplicitlySpecializedTemplateIiE4funcEv
// Base class alredy specialized with export attribute.
struct __declspec(dllexport) DerivedFromExplicitlyExportSpecializedTemplate : public ExplicitlyExportSpecializedTemplate<int> {};
-USEMEMFUNC(ExplicitlyExportSpecializedTemplate<int>, func)
+USEMEMFUNC(DerivedFromExplicitlyExportSpecializedTemplate, func)
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExplicitlyExportSpecializedTemplate@H@@QAEXXZ"
// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN35ExplicitlyExportSpecializedTemplateIiE4funcEv
// Base class already specialized with import attribute.
struct __declspec(dllexport) DerivedFromExplicitlyImportSpecializedTemplate : public ExplicitlyImportSpecializedTemplate<int> {};
-USEMEMFUNC(ExplicitlyImportSpecializedTemplate<int>, func)
-// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportSpecializedTemplate@H@@QAEXXZ"
-// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN35ExplicitlyImportSpecializedTemplateIiE4funcEv
+USEMEMFUNC(DerivedFromExplicitlyImportSpecializedTemplate, func)
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportSpecializedTemplate@H@@QAEXXZ"
+// G32-DAG: declare dllimport x86_thiscallcc void @_ZN35ExplicitlyImportSpecializedTemplateIiE4funcEv
// Base class already instantiated without dll attribute.
struct __declspec(dllexport) DerivedFromExplicitlyInstantiatedTemplate : public ExplicitlyInstantiatedTemplate<int> {};
-USEMEMFUNC(ExplicitlyInstantiatedTemplate<int>, func)
+USEMEMFUNC(DerivedFromExplicitlyInstantiatedTemplate, func)
// M32-DAG: define weak_odr x86_thiscallcc void @"\01?func@?$ExplicitlyInstantiatedTemplate@H@@QAEXXZ"
// G32-DAG: define weak_odr x86_thiscallcc void @_ZN30ExplicitlyInstantiatedTemplateIiE4funcEv
// Base class already instantiated with export attribute.
struct __declspec(dllexport) DerivedFromExplicitlyExportInstantiatedTemplate : public ExplicitlyExportInstantiatedTemplate<int> {};
-USEMEMFUNC(ExplicitlyExportInstantiatedTemplate<int>, func)
+USEMEMFUNC(DerivedFromExplicitlyExportInstantiatedTemplate, func)
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExplicitlyExportInstantiatedTemplate@H@@QAEXXZ"
// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN36ExplicitlyExportInstantiatedTemplateIiE4funcEv
// Base class already instantiated with import attribute.
struct __declspec(dllexport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate<int> {};
-USEMEMFUNC(ExplicitlyImportInstantiatedTemplate<int>, func)
-// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportInstantiatedTemplate@H@@QAEXXZ"
-// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN36ExplicitlyImportInstantiatedTemplateIiE4funcEv
+USEMEMFUNC(DerivedFromExplicitlyImportInstantiatedTemplate, func)
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportInstantiatedTemplate@H@@QAEXXZ"
+// G32-DAG: declare dllimport x86_thiscallcc void @_ZN36ExplicitlyImportInstantiatedTemplateIiE4funcEv
// MS: A dll attribute propagates through multiple levels of instantiation.
template <typename T> struct TopClass { void func() {} };
template <typename T> struct MiddleClass : public TopClass<T> { };
struct __declspec(dllexport) BottomClass : public MiddleClass<int> { };
-USEMEMFUNC(TopClass<int>, func)
+USEMEMFUNC(BottomClass, func)
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$TopClass@H@@QAEXXZ"
// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN8TopClassIiE4funcEv
diff --git a/test/CodeGenCXX/dllimport-members.cpp b/test/CodeGenCXX/dllimport-members.cpp
index 6656b92b0022..e88b7e97c3e7 100644
--- a/test/CodeGenCXX/dllimport-members.cpp
+++ b/test/CodeGenCXX/dllimport-members.cpp
@@ -63,64 +63,64 @@ struct ForceNonTrivial {
struct ImportMembers {
struct Nested;
- // M32-DAG: define x86_thiscallcc void @"\01?normalDef@ImportMembers@@QAEXXZ"(%struct.ImportMembers* %this)
- // M64-DAG: define void @"\01?normalDef@ImportMembers@@QEAAXXZ"(%struct.ImportMembers* %this)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalDecl@ImportMembers@@QAEXXZ"(%struct.ImportMembers*)
- // M64-DAG: declare dllimport void @"\01?normalDecl@ImportMembers@@QEAAXXZ"(%struct.ImportMembers*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInclass@ImportMembers@@QAEXXZ"(%struct.ImportMembers*)
- // M64-DAG: declare dllimport void @"\01?normalInclass@ImportMembers@@QEAAXXZ"(%struct.ImportMembers*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInlineDef@ImportMembers@@QAEXXZ"(%struct.ImportMembers*)
- // M64-DAG: declare dllimport void @"\01?normalInlineDef@ImportMembers@@QEAAXXZ"(%struct.ImportMembers*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInlineDecl@ImportMembers@@QAEXXZ"(%struct.ImportMembers*)
- // M64-DAG: declare dllimport void @"\01?normalInlineDecl@ImportMembers@@QEAAXXZ"(%struct.ImportMembers*)
- // G32-DAG: define x86_thiscallcc void @_ZN13ImportMembers9normalDefEv(%struct.ImportMembers* %this)
- // G64-DAG: define void @_ZN13ImportMembers9normalDefEv(%struct.ImportMembers* %this)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers10normalDeclEv(%struct.ImportMembers*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers10normalDeclEv(%struct.ImportMembers*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers13normalInclassEv(%struct.ImportMembers*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers13normalInclassEv(%struct.ImportMembers*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers15normalInlineDefEv(%struct.ImportMembers*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers15normalInlineDefEv(%struct.ImportMembers*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers16normalInlineDeclEv(%struct.ImportMembers*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers16normalInlineDeclEv(%struct.ImportMembers*)
+ // M32-DAG: define x86_thiscallcc void @"\01?normalDef@ImportMembers@@QAEXXZ"(%struct.ImportMembers* %this)
+ // M64-DAG: define void @"\01?normalDef@ImportMembers@@QEAAXXZ"(%struct.ImportMembers* %this)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalDecl@ImportMembers@@QAEXXZ"(%struct.ImportMembers*)
+ // M64-DAG: declare dllimport void @"\01?normalDecl@ImportMembers@@QEAAXXZ"(%struct.ImportMembers*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInclass@ImportMembers@@QAEXXZ"(%struct.ImportMembers*)
+ // M64-DAG: declare dllimport void @"\01?normalInclass@ImportMembers@@QEAAXXZ"(%struct.ImportMembers*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInlineDef@ImportMembers@@QAEXXZ"(%struct.ImportMembers*)
+ // M64-DAG: declare dllimport void @"\01?normalInlineDef@ImportMembers@@QEAAXXZ"(%struct.ImportMembers*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInlineDecl@ImportMembers@@QAEXXZ"(%struct.ImportMembers*)
+ // M64-DAG: declare dllimport void @"\01?normalInlineDecl@ImportMembers@@QEAAXXZ"(%struct.ImportMembers*)
+ // G32-DAG: define x86_thiscallcc void @_ZN13ImportMembers9normalDefEv(%struct.ImportMembers* %this)
+ // G64-DAG: define void @_ZN13ImportMembers9normalDefEv(%struct.ImportMembers* %this)
+ // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers10normalDeclEv(%struct.ImportMembers*)
+ // G64-DAG: declare dllimport void @_ZN13ImportMembers10normalDeclEv(%struct.ImportMembers*)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers13normalInclassEv(%struct.ImportMembers* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers13normalInclassEv(%struct.ImportMembers* %this)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers15normalInlineDefEv(%struct.ImportMembers* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers15normalInlineDefEv(%struct.ImportMembers* %this)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers16normalInlineDeclEv(%struct.ImportMembers* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers16normalInlineDeclEv(%struct.ImportMembers* %this)
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?normalInclass@ImportMembers@@QAEXXZ"(
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?normalInlineDef@ImportMembers@@QAEXXZ"(
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?normalInlineDecl@ImportMembers@@QAEXXZ"(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers13normalInclassEv(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers15normalInlineDefEv(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers16normalInlineDeclEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers13normalInclassEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers15normalInlineDefEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers16normalInlineDeclEv(
__declspec(dllimport) void normalDef(); // dllimport ignored
__declspec(dllimport) void normalDecl();
__declspec(dllimport) void normalInclass() {}
__declspec(dllimport) void normalInlineDef();
__declspec(dllimport) inline void normalInlineDecl();
- // M32-DAG: define x86_thiscallcc void @"\01?virtualDef@ImportMembers@@UAEXXZ"(%struct.ImportMembers* %this)
- // M64-DAG: define void @"\01?virtualDef@ImportMembers@@UEAAXXZ"(%struct.ImportMembers* %this)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualDecl@ImportMembers@@UAEXXZ"(%struct.ImportMembers*)
- // M64-DAG: declare dllimport void @"\01?virtualDecl@ImportMembers@@UEAAXXZ"(%struct.ImportMembers*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInclass@ImportMembers@@UAEXXZ"(%struct.ImportMembers*)
- // M64-DAG: declare dllimport void @"\01?virtualInclass@ImportMembers@@UEAAXXZ"(%struct.ImportMembers*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInlineDef@ImportMembers@@UAEXXZ"(%struct.ImportMembers*)
- // M64-DAG: declare dllimport void @"\01?virtualInlineDef@ImportMembers@@UEAAXXZ"(%struct.ImportMembers*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInlineDecl@ImportMembers@@UAEXXZ"(%struct.ImportMembers*)
- // M64-DAG: declare dllimport void @"\01?virtualInlineDecl@ImportMembers@@UEAAXXZ"(%struct.ImportMembers*)
- // G32-DAG: define x86_thiscallcc void @_ZN13ImportMembers10virtualDefEv(%struct.ImportMembers* %this)
- // G64-DAG: define void @_ZN13ImportMembers10virtualDefEv(%struct.ImportMembers* %this)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers11virtualDeclEv(%struct.ImportMembers*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers11virtualDeclEv(%struct.ImportMembers*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers14virtualInclassEv(%struct.ImportMembers*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers14virtualInclassEv(%struct.ImportMembers*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers16virtualInlineDefEv(%struct.ImportMembers*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers16virtualInlineDefEv(%struct.ImportMembers*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers17virtualInlineDeclEv(%struct.ImportMembers*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers17virtualInlineDeclEv(%struct.ImportMembers*)
+ // M32-DAG: define x86_thiscallcc void @"\01?virtualDef@ImportMembers@@UAEXXZ"(%struct.ImportMembers* %this)
+ // M64-DAG: define void @"\01?virtualDef@ImportMembers@@UEAAXXZ"(%struct.ImportMembers* %this)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualDecl@ImportMembers@@UAEXXZ"(%struct.ImportMembers*)
+ // M64-DAG: declare dllimport void @"\01?virtualDecl@ImportMembers@@UEAAXXZ"(%struct.ImportMembers*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInclass@ImportMembers@@UAEXXZ"(%struct.ImportMembers*)
+ // M64-DAG: declare dllimport void @"\01?virtualInclass@ImportMembers@@UEAAXXZ"(%struct.ImportMembers*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInlineDef@ImportMembers@@UAEXXZ"(%struct.ImportMembers*)
+ // M64-DAG: declare dllimport void @"\01?virtualInlineDef@ImportMembers@@UEAAXXZ"(%struct.ImportMembers*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInlineDecl@ImportMembers@@UAEXXZ"(%struct.ImportMembers*)
+ // M64-DAG: declare dllimport void @"\01?virtualInlineDecl@ImportMembers@@UEAAXXZ"(%struct.ImportMembers*)
+ // G32-DAG: define x86_thiscallcc void @_ZN13ImportMembers10virtualDefEv(%struct.ImportMembers* %this)
+ // G64-DAG: define void @_ZN13ImportMembers10virtualDefEv(%struct.ImportMembers* %this)
+ // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers11virtualDeclEv(%struct.ImportMembers*)
+ // G64-DAG: declare dllimport void @_ZN13ImportMembers11virtualDeclEv(%struct.ImportMembers*)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers14virtualInclassEv(%struct.ImportMembers* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers14virtualInclassEv(%struct.ImportMembers* %this)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers16virtualInlineDefEv(%struct.ImportMembers* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers16virtualInlineDefEv(%struct.ImportMembers* %this)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers17virtualInlineDeclEv(%struct.ImportMembers* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers17virtualInlineDeclEv(%struct.ImportMembers* %this)
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?virtualInclass@ImportMembers@@UAEXXZ"(
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?virtualInlineDef@ImportMembers@@UAEXXZ"(
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?virtualInlineDecl@ImportMembers@@UAEXXZ"(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers14virtualInclassEv(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers16virtualInlineDefEv(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers17virtualInlineDeclEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers14virtualInclassEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers16virtualInlineDefEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers17virtualInlineDeclEv(
__declspec(dllimport) virtual void virtualDef(); // dllimport ignored
__declspec(dllimport) virtual void virtualDecl();
__declspec(dllimport) virtual void virtualInclass() {}
@@ -134,15 +134,15 @@ struct ImportMembers {
// MSC-DAG: declare dllimport void @"\01?staticInlineDecl@ImportMembers@@SAXXZ"()
// GNU-DAG: define void @_ZN13ImportMembers9staticDefEv()
// GNU-DAG: declare dllimport void @_ZN13ImportMembers10staticDeclEv()
- // GNU-DAG: declare dllimport void @_ZN13ImportMembers13staticInclassEv()
- // GNU-DAG: declare dllimport void @_ZN13ImportMembers15staticInlineDefEv()
- // GNU-DAG: declare dllimport void @_ZN13ImportMembers16staticInlineDeclEv()
+ // GNU-DAG: define linkonce_odr void @_ZN13ImportMembers13staticInclassEv()
+ // GNU-DAG: define linkonce_odr void @_ZN13ImportMembers15staticInlineDefEv()
+ // GNU-DAG: define linkonce_odr void @_ZN13ImportMembers16staticInlineDeclEv()
// MO1-DAG: define available_externally dllimport void @"\01?staticInclass@ImportMembers@@SAXXZ"()
// MO1-DAG: define available_externally dllimport void @"\01?staticInlineDef@ImportMembers@@SAXXZ"()
// MO1-DAG: define available_externally dllimport void @"\01?staticInlineDecl@ImportMembers@@SAXXZ"()
- // GO1-DAG: define available_externally dllimport void @_ZN13ImportMembers13staticInclassEv()
- // GO1-DAG: define available_externally dllimport void @_ZN13ImportMembers15staticInlineDefEv()
- // GO1-DAG: define available_externally dllimport void @_ZN13ImportMembers16staticInlineDeclEv()
+ // GO1-DAG: define linkonce_odr void @_ZN13ImportMembers13staticInclassEv()
+ // GO1-DAG: define linkonce_odr void @_ZN13ImportMembers15staticInlineDefEv()
+ // GO1-DAG: define linkonce_odr void @_ZN13ImportMembers16staticInlineDeclEv()
__declspec(dllimport) static void staticDef(); // dllimport ignored
__declspec(dllimport) static void staticDecl();
__declspec(dllimport) static void staticInclass() {}
@@ -235,65 +235,65 @@ USEMV(ImportMembers, ConstexprField)
// Import individual members of a nested class.
struct ImportMembers::Nested {
- // M32-DAG: define x86_thiscallcc void @"\01?normalDef@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"* %this)
- // M64-DAG: define void @"\01?normalDef@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"* %this)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalDecl@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"*)
- // M64-DAG: declare dllimport void @"\01?normalDecl@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInclass@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"*)
- // M64-DAG: declare dllimport void @"\01?normalInclass@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInlineDef@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"*)
- // M64-DAG: declare dllimport void @"\01?normalInlineDef@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInlineDecl@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"*)
- // M64-DAG: declare dllimport void @"\01?normalInlineDecl@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"*)
- // G32-DAG: define x86_thiscallcc void @_ZN13ImportMembers6Nested9normalDefEv(%"struct.ImportMembers::Nested"* %this)
- // G64-DAG: define void @_ZN13ImportMembers6Nested9normalDefEv(%"struct.ImportMembers::Nested"* %this)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested10normalDeclEv(%"struct.ImportMembers::Nested"*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers6Nested10normalDeclEv(%"struct.ImportMembers::Nested"*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested13normalInclassEv(%"struct.ImportMembers::Nested"*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers6Nested13normalInclassEv(%"struct.ImportMembers::Nested"*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested15normalInlineDefEv(%"struct.ImportMembers::Nested"*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers6Nested15normalInlineDefEv(%"struct.ImportMembers::Nested"*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested16normalInlineDeclEv(%"struct.ImportMembers::Nested"*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers6Nested16normalInlineDeclEv(%"struct.ImportMembers::Nested"*)
+ // M32-DAG: define x86_thiscallcc void @"\01?normalDef@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"* %this)
+ // M64-DAG: define void @"\01?normalDef@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"* %this)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalDecl@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"*)
+ // M64-DAG: declare dllimport void @"\01?normalDecl@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInclass@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"*)
+ // M64-DAG: declare dllimport void @"\01?normalInclass@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInlineDef@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"*)
+ // M64-DAG: declare dllimport void @"\01?normalInlineDef@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?normalInlineDecl@Nested@ImportMembers@@QAEXXZ"(%"struct.ImportMembers::Nested"*)
+ // M64-DAG: declare dllimport void @"\01?normalInlineDecl@Nested@ImportMembers@@QEAAXXZ"(%"struct.ImportMembers::Nested"*)
+ // G32-DAG: define x86_thiscallcc void @_ZN13ImportMembers6Nested9normalDefEv(%"struct.ImportMembers::Nested"* %this)
+ // G64-DAG: define void @_ZN13ImportMembers6Nested9normalDefEv(%"struct.ImportMembers::Nested"* %this)
+ // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested10normalDeclEv(%"struct.ImportMembers::Nested"*)
+ // G64-DAG: declare dllimport void @_ZN13ImportMembers6Nested10normalDeclEv(%"struct.ImportMembers::Nested"*)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested13normalInclassEv(%"struct.ImportMembers::Nested"* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested13normalInclassEv(%"struct.ImportMembers::Nested"* %this)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested15normalInlineDefEv(%"struct.ImportMembers::Nested"* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested15normalInlineDefEv(%"struct.ImportMembers::Nested"* %this)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested16normalInlineDeclEv(%"struct.ImportMembers::Nested"* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested16normalInlineDeclEv(%"struct.ImportMembers::Nested"* %this)
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?normalInclass@Nested@ImportMembers@@QAEXXZ"(
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?normalInlineDef@Nested@ImportMembers@@QAEXXZ"(
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?normalInlineDecl@Nested@ImportMembers@@QAEXXZ"(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested13normalInclassEv(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested15normalInlineDefEv(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested16normalInlineDeclEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested13normalInclassEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested15normalInlineDefEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested16normalInlineDeclEv(
__declspec(dllimport) void normalDef(); // dllimport ignored
__declspec(dllimport) void normalDecl();
__declspec(dllimport) void normalInclass() {}
__declspec(dllimport) void normalInlineDef();
__declspec(dllimport) inline void normalInlineDecl();
- // M32-DAG: define x86_thiscallcc void @"\01?virtualDef@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"* %this)
- // M64-DAG: define void @"\01?virtualDef@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"* %this)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualDecl@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"*)
- // M64-DAG: declare dllimport void @"\01?virtualDecl@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInclass@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"*)
- // M64-DAG: declare dllimport void @"\01?virtualInclass@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInlineDef@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"*)
- // M64-DAG: declare dllimport void @"\01?virtualInlineDef@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"*)
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInlineDecl@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"*)
- // M64-DAG: declare dllimport void @"\01?virtualInlineDecl@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"*)
- // G32-DAG: define x86_thiscallcc void @_ZN13ImportMembers6Nested10virtualDefEv(%"struct.ImportMembers::Nested"* %this)
- // G64-DAG: define void @_ZN13ImportMembers6Nested10virtualDefEv(%"struct.ImportMembers::Nested"* %this)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested11virtualDeclEv(%"struct.ImportMembers::Nested"*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers6Nested11virtualDeclEv(%"struct.ImportMembers::Nested"*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested14virtualInclassEv(%"struct.ImportMembers::Nested"*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers6Nested14virtualInclassEv(%"struct.ImportMembers::Nested"*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested16virtualInlineDefEv(%"struct.ImportMembers::Nested"*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers6Nested16virtualInlineDefEv(%"struct.ImportMembers::Nested"*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested17virtualInlineDeclEv(%"struct.ImportMembers::Nested"*)
- // G64-DAG: declare dllimport void @_ZN13ImportMembers6Nested17virtualInlineDeclEv(%"struct.ImportMembers::Nested"*)
+ // M32-DAG: define x86_thiscallcc void @"\01?virtualDef@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"* %this)
+ // M64-DAG: define void @"\01?virtualDef@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"* %this)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualDecl@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"*)
+ // M64-DAG: declare dllimport void @"\01?virtualDecl@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInclass@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"*)
+ // M64-DAG: declare dllimport void @"\01?virtualInclass@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInlineDef@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"*)
+ // M64-DAG: declare dllimport void @"\01?virtualInlineDef@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01?virtualInlineDecl@Nested@ImportMembers@@UAEXXZ"(%"struct.ImportMembers::Nested"*)
+ // M64-DAG: declare dllimport void @"\01?virtualInlineDecl@Nested@ImportMembers@@UEAAXXZ"(%"struct.ImportMembers::Nested"*)
+ // G32-DAG: define x86_thiscallcc void @_ZN13ImportMembers6Nested10virtualDefEv(%"struct.ImportMembers::Nested"* %this)
+ // G64-DAG: define void @_ZN13ImportMembers6Nested10virtualDefEv(%"struct.ImportMembers::Nested"* %this)
+ // G32-DAG: declare dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested11virtualDeclEv(%"struct.ImportMembers::Nested"*)
+ // G64-DAG: declare dllimport void @_ZN13ImportMembers6Nested11virtualDeclEv(%"struct.ImportMembers::Nested"*)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested14virtualInclassEv(%"struct.ImportMembers::Nested"* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested14virtualInclassEv(%"struct.ImportMembers::Nested"* %this)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested16virtualInlineDefEv(%"struct.ImportMembers::Nested"* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested16virtualInlineDefEv(%"struct.ImportMembers::Nested"* %this)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested17virtualInlineDeclEv(%"struct.ImportMembers::Nested"* %this)
+ // G64-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested17virtualInlineDeclEv(%"struct.ImportMembers::Nested"* %this)
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?virtualInclass@Nested@ImportMembers@@UAEXXZ"(
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?virtualInlineDef@Nested@ImportMembers@@UAEXXZ"(
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?virtualInlineDecl@Nested@ImportMembers@@UAEXXZ"(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested14virtualInclassEv(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested16virtualInlineDefEv(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN13ImportMembers6Nested17virtualInlineDeclEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested14virtualInclassEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested16virtualInlineDefEv(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ImportMembers6Nested17virtualInlineDeclEv(
__declspec(dllimport) virtual void virtualDef(); // dllimport ignored
__declspec(dllimport) virtual void virtualDecl();
__declspec(dllimport) virtual void virtualInclass() {}
@@ -307,15 +307,15 @@ struct ImportMembers::Nested {
// MSC-DAG: declare dllimport void @"\01?staticInlineDecl@Nested@ImportMembers@@SAXXZ"()
// GNU-DAG: define void @_ZN13ImportMembers6Nested9staticDefEv()
// GNU-DAG: declare dllimport void @_ZN13ImportMembers6Nested10staticDeclEv()
- // GNU-DAG: declare dllimport void @_ZN13ImportMembers6Nested13staticInclassEv()
- // GNU-DAG: declare dllimport void @_ZN13ImportMembers6Nested15staticInlineDefEv()
- // GNU-DAG: declare dllimport void @_ZN13ImportMembers6Nested16staticInlineDeclEv()
+ // GNU-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested13staticInclassEv()
+ // GNU-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested15staticInlineDefEv()
+ // GNU-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested16staticInlineDeclEv()
// MO1-DAG: define available_externally dllimport void @"\01?staticInclass@Nested@ImportMembers@@SAXXZ"()
// MO1-DAG: define available_externally dllimport void @"\01?staticInlineDef@Nested@ImportMembers@@SAXXZ"()
// MO1-DAG: define available_externally dllimport void @"\01?staticInlineDecl@Nested@ImportMembers@@SAXXZ"()
- // GO1-DAG: define available_externally dllimport void @_ZN13ImportMembers6Nested13staticInclassEv()
- // GO1-DAG: define available_externally dllimport void @_ZN13ImportMembers6Nested15staticInlineDefEv()
- // GO1-DAG: define available_externally dllimport void @_ZN13ImportMembers6Nested16staticInlineDeclEv()
+ // GO1-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested13staticInclassEv()
+ // GO1-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested15staticInlineDefEv()
+ // GO1-DAG: define linkonce_odr void @_ZN13ImportMembers6Nested16staticInlineDeclEv()
__declspec(dllimport) static void staticDef(); // dllimport ignored
__declspec(dllimport) static void staticDecl();
__declspec(dllimport) static void staticInclass() {}
@@ -449,52 +449,52 @@ USESPECIALS(ImportSpecials)
// Export inline special member functions.
struct ImportInlineSpecials {
- // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QAE@XZ"(%struct.ImportInlineSpecials* returned)
- // M64-DAG: declare dllimport %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QEAA@XZ"(%struct.ImportInlineSpecials* returned)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN20ImportInlineSpecialsC1Ev(%struct.ImportInlineSpecials*)
- // G64-DAG: declare dllimport void @_ZN20ImportInlineSpecialsC1Ev(%struct.ImportInlineSpecials*)
+ // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QAE@XZ"(%struct.ImportInlineSpecials* returned)
+ // M64-DAG: declare dllimport %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QEAA@XZ"(%struct.ImportInlineSpecials* returned)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN20ImportInlineSpecialsC1Ev(%struct.ImportInlineSpecials* %this)
+ // G64-DAG: define linkonce_odr void @_ZN20ImportInlineSpecialsC1Ev(%struct.ImportInlineSpecials* %this)
// MO1-DAG: define available_externally dllimport x86_thiscallcc %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QAE@XZ"(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN20ImportInlineSpecialsC1Ev(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN20ImportInlineSpecialsC1Ev(
__declspec(dllimport) ImportInlineSpecials() {}
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01??1ImportInlineSpecials@@QAE@XZ"(%struct.ImportInlineSpecials*)
- // M64-DAG: declare dllimport void @"\01??1ImportInlineSpecials@@QEAA@XZ"(%struct.ImportInlineSpecials*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN20ImportInlineSpecialsD1Ev(%struct.ImportInlineSpecials*)
- // G64-DAG: declare dllimport void @_ZN20ImportInlineSpecialsD1Ev(%struct.ImportInlineSpecials*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01??1ImportInlineSpecials@@QAE@XZ"(%struct.ImportInlineSpecials*)
+ // M64-DAG: declare dllimport void @"\01??1ImportInlineSpecials@@QEAA@XZ"(%struct.ImportInlineSpecials*)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN20ImportInlineSpecialsD1Ev(%struct.ImportInlineSpecials* %this)
+ // G64-DAG: define linkonce_odr void @_ZN20ImportInlineSpecialsD1Ev(%struct.ImportInlineSpecials* %this)
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01??1ImportInlineSpecials@@QAE@XZ"(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN20ImportInlineSpecialsD1Ev(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN20ImportInlineSpecialsD1Ev(
__declspec(dllimport) ~ImportInlineSpecials() {}
- // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QAE@ABU0@@Z"(%struct.ImportInlineSpecials* returned, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // M64-DAG: declare dllimport %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QEAA@AEBU0@@Z"(%struct.ImportInlineSpecials* returned, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN20ImportInlineSpecialsC1ERKS_(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // G64-DAG: declare dllimport void @_ZN20ImportInlineSpecialsC1ERKS_(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QAE@ABU0@@Z"(%struct.ImportInlineSpecials* returned, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // M64-DAG: declare dllimport %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QEAA@AEBU0@@Z"(%struct.ImportInlineSpecials* returned, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN20ImportInlineSpecialsC1ERKS_(%struct.ImportInlineSpecials* %this, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // G64-DAG: define linkonce_odr void @_ZN20ImportInlineSpecialsC1ERKS_(%struct.ImportInlineSpecials* %this, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
// MO1-DAG: define available_externally dllimport x86_thiscallcc %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QAE@ABU0@@Z"(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN20ImportInlineSpecialsC1ERKS_(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN20ImportInlineSpecialsC1ERKS_(
__declspec(dllimport) inline ImportInlineSpecials(const ImportInlineSpecials&);
- // M32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @"\01??4ImportInlineSpecials@@QAEAAU0@ABU0@@Z"(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // M64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @"\01??4ImportInlineSpecials@@QEAAAEAU0@AEBU0@@Z"(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // G32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSERKS_(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // G64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSERKS_(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // M32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @"\01??4ImportInlineSpecials@@QAEAAU0@ABU0@@Z"(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // M64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @"\01??4ImportInlineSpecials@@QEAAAEAU0@AEBU0@@Z"(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // G32-DAG: define linkonce_odr x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSERKS_(%struct.ImportInlineSpecials* %this, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // G64-DAG: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSERKS_(%struct.ImportInlineSpecials* %this, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
// MO1-DAG: define available_externally dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @"\01??4ImportInlineSpecials@@QAEAAU0@ABU0@@Z"(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSERKS_(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSERKS_(
__declspec(dllimport) ImportInlineSpecials& operator=(const ImportInlineSpecials&);
- // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QAE@$$QAU0@@Z"(%struct.ImportInlineSpecials* returned, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // M64-DAG: declare dllimport %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QEAA@$$QEAU0@@Z"(%struct.ImportInlineSpecials* returned, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN20ImportInlineSpecialsC1EOS_(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // G64-DAG: declare dllimport void @_ZN20ImportInlineSpecialsC1EOS_(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QAE@$$QAU0@@Z"(%struct.ImportInlineSpecials* returned, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // M64-DAG: declare dllimport %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QEAA@$$QEAU0@@Z"(%struct.ImportInlineSpecials* returned, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN20ImportInlineSpecialsC1EOS_(%struct.ImportInlineSpecials* %this, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // G64-DAG: define linkonce_odr void @_ZN20ImportInlineSpecialsC1EOS_(%struct.ImportInlineSpecials* %this, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
// MO1-DAG: define available_externally dllimport x86_thiscallcc %struct.ImportInlineSpecials* @"\01??0ImportInlineSpecials@@QAE@$$QAU0@@Z"(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN20ImportInlineSpecialsC1EOS_(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN20ImportInlineSpecialsC1EOS_(
__declspec(dllimport) ImportInlineSpecials(ImportInlineSpecials&&) {}
- // M32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @"\01??4ImportInlineSpecials@@QAEAAU0@$$QAU0@@Z"(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // M64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @"\01??4ImportInlineSpecials@@QEAAAEAU0@$$QEAU0@@Z"(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // G32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSEOS_(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
- // G64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSEOS_(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // M32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @"\01??4ImportInlineSpecials@@QAEAAU0@$$QAU0@@Z"(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // M64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @"\01??4ImportInlineSpecials@@QEAAAEAU0@$$QEAU0@@Z"(%struct.ImportInlineSpecials*, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // G32-DAG: define linkonce_odr x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSEOS_(%struct.ImportInlineSpecials* %this, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
+ // G64-DAG: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSEOS_(%struct.ImportInlineSpecials* %this, %struct.ImportInlineSpecials* dereferenceable({{[0-9]+}}))
// MO1-DAG: define available_externally dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @"\01??4ImportInlineSpecials@@QAEAAU0@$$QAU0@@Z"(
- // GO1-DAG: define available_externally dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSEOS_(
+ // GO1-DAG: define linkonce_odr x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportInlineSpecials* @_ZN20ImportInlineSpecialsaSEOS_(
__declspec(dllimport) ImportInlineSpecials& operator=(ImportInlineSpecials&&) { return *this; }
};
ImportInlineSpecials::ImportInlineSpecials(const ImportInlineSpecials&) {}
@@ -504,52 +504,52 @@ USESPECIALS(ImportInlineSpecials)
// Import defaulted member functions.
struct ImportDefaulted {
- // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QAE@XZ"(%struct.ImportDefaulted* returned)
- // M64-DAG: declare dllimport %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QEAA@XZ"(%struct.ImportDefaulted* returned)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN15ImportDefaultedC1Ev(%struct.ImportDefaulted*)
- // G64-DAG: declare dllimport void @_ZN15ImportDefaultedC1Ev(%struct.ImportDefaulted*)
+ // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QAE@XZ"(%struct.ImportDefaulted* returned)
+ // M64-DAG: declare dllimport %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QEAA@XZ"(%struct.ImportDefaulted* returned)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN15ImportDefaultedC1Ev(%struct.ImportDefaulted* %this)
+ // G64-DAG: define linkonce_odr void @_ZN15ImportDefaultedC1Ev(%struct.ImportDefaulted* %this)
// MO1-DAG: define available_externally dllimport x86_thiscallcc %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QAE@XZ"(%struct.ImportDefaulted* returned %this)
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN15ImportDefaultedC1Ev(%struct.ImportDefaulted* %this)
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN15ImportDefaultedC1Ev(%struct.ImportDefaulted* %this)
__declspec(dllimport) ImportDefaulted() = default;
- // M32-DAG: declare dllimport x86_thiscallcc void @"\01??1ImportDefaulted@@QAE@XZ"(%struct.ImportDefaulted*)
- // M64-DAG: declare dllimport void @"\01??1ImportDefaulted@@QEAA@XZ"(%struct.ImportDefaulted*)
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted*)
- // G64-DAG: declare dllimport void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted*)
+ // M32-DAG: declare dllimport x86_thiscallcc void @"\01??1ImportDefaulted@@QAE@XZ"(%struct.ImportDefaulted*)
+ // M64-DAG: declare dllimport void @"\01??1ImportDefaulted@@QEAA@XZ"(%struct.ImportDefaulted*)
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted* %this)
+ // G64-DAG: define linkonce_odr void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted* %this)
// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01??1ImportDefaulted@@QAE@XZ"(%struct.ImportDefaulted* %this)
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted* %this)
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN15ImportDefaultedD1Ev(%struct.ImportDefaulted* %this)
__declspec(dllimport) ~ImportDefaulted() = default;
- // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QAE@ABU0@@Z"(%struct.ImportDefaulted* returned, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // M64-DAG: declare dllimport %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QEAA@AEBU0@@Z"(%struct.ImportDefaulted* returned, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN15ImportDefaultedC1ERKS_(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // G64-DAG: declare dllimport void @_ZN15ImportDefaultedC1ERKS_(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QAE@ABU0@@Z"(%struct.ImportDefaulted* returned, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // M64-DAG: declare dllimport %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QEAA@AEBU0@@Z"(%struct.ImportDefaulted* returned, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN15ImportDefaultedC1ERKS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // G64-DAG: define linkonce_odr void @_ZN15ImportDefaultedC1ERKS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
// MO1-DAG: define available_externally dllimport x86_thiscallcc %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QAE@ABU0@@Z"(%struct.ImportDefaulted* returned %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN15ImportDefaultedC1ERKS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN15ImportDefaultedC1ERKS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
__declspec(dllimport) ImportDefaulted(const ImportDefaulted&) = default;
- // M32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @"\01??4ImportDefaulted@@QAEAAU0@ABU0@@Z"(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // M64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @"\01??4ImportDefaulted@@QEAAAEAU0@AEBU0@@Z"(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // G32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSERKS_(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // G64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSERKS_(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // M32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @"\01??4ImportDefaulted@@QAEAAU0@ABU0@@Z"(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // M64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @"\01??4ImportDefaulted@@QEAAAEAU0@AEBU0@@Z"(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // G32-DAG: define linkonce_odr x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSERKS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // G64-DAG: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSERKS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
// MO1-DAG: define available_externally dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @"\01??4ImportDefaulted@@QAEAAU0@ABU0@@Z"(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // GO1-DAG: define available_externally dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSERKS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // GO1-DAG: define linkonce_odr x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSERKS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
__declspec(dllimport) ImportDefaulted& operator=(const ImportDefaulted&) = default;
- // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QAE@$$QAU0@@Z"(%struct.ImportDefaulted* returned, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // M64-DAG: declare dllimport %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QEAA@$$QEAU0@@Z"(%struct.ImportDefaulted* returned, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // G32-DAG: declare dllimport x86_thiscallcc void @_ZN15ImportDefaultedC1EOS_(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // G64-DAG: declare dllimport void @_ZN15ImportDefaultedC1EOS_(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // M32-DAG: declare dllimport x86_thiscallcc %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QAE@$$QAU0@@Z"(%struct.ImportDefaulted* returned, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // M64-DAG: declare dllimport %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QEAA@$$QEAU0@@Z"(%struct.ImportDefaulted* returned, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN15ImportDefaultedC1EOS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // G64-DAG: define linkonce_odr void @_ZN15ImportDefaultedC1EOS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
// MO1-DAG: define available_externally dllimport x86_thiscallcc %struct.ImportDefaulted* @"\01??0ImportDefaulted@@QAE@$$QAU0@@Z"(%struct.ImportDefaulted* returned %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // GO1-DAG: define available_externally dllimport x86_thiscallcc void @_ZN15ImportDefaultedC1EOS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // GO1-DAG: define linkonce_odr x86_thiscallcc void @_ZN15ImportDefaultedC1EOS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
__declspec(dllimport) ImportDefaulted(ImportDefaulted&&) = default;
- // M32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @"\01??4ImportDefaulted@@QAEAAU0@$$QAU0@@Z"(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // M64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @"\01??4ImportDefaulted@@QEAAAEAU0@$$QEAU0@@Z"(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // G32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSEOS_(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // G64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSEOS_(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // M32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @"\01??4ImportDefaulted@@QAEAAU0@$$QAU0@@Z"(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // M64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @"\01??4ImportDefaulted@@QEAAAEAU0@$$QEAU0@@Z"(%struct.ImportDefaulted*, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // G32-DAG: define linkonce_odr x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSEOS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // G64-DAG: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSEOS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
// MO1-DAG: define available_externally dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @"\01??4ImportDefaulted@@QAEAAU0@$$QAU0@@Z"(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
- // GO1-DAG: define available_externally dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSEOS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
+ // GO1-DAG: define linkonce_odr x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaulted* @_ZN15ImportDefaultedaSEOS_(%struct.ImportDefaulted* %this, %struct.ImportDefaulted* dereferenceable({{[0-9]+}}))
__declspec(dllimport) ImportDefaulted& operator=(ImportDefaulted&&) = default;
ForceNonTrivial v; // ensure special members are non-trivial
@@ -569,28 +569,30 @@ struct ImportDefaultedDefs {
__declspec(dllimport) ImportDefaultedDefs& operator=(ImportDefaultedDefs&&);
};
+#ifdef MSABI
+// For MinGW, the function will not be dllimport, and we cannot add the attribute now.
// M32-DAG: declare dllimport x86_thiscallcc %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QAE@XZ"(%struct.ImportDefaultedDefs* returned)
// M64-DAG: declare dllimport %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QEAA@XZ"(%struct.ImportDefaultedDefs* returned)
-// G32-DAG: declare dllimport x86_thiscallcc void @_ZN19ImportDefaultedDefsC1Ev(%struct.ImportDefaultedDefs*)
-// G64-DAG: declare dllimport void @_ZN19ImportDefaultedDefsC1Ev(%struct.ImportDefaultedDefs*)
__declspec(dllimport) ImportDefaultedDefs::ImportDefaultedDefs() = default;
+#endif
+#ifdef MSABI
+// For MinGW, the function will not be dllimport, and we cannot add the attribute now.
// M32-DAG: declare dllimport x86_thiscallcc void @"\01??1ImportDefaultedDefs@@QAE@XZ"(%struct.ImportDefaultedDefs*)
// M64-DAG: declare dllimport void @"\01??1ImportDefaultedDefs@@QEAA@XZ"(%struct.ImportDefaultedDefs*)
-// G32-DAG: declare dllimport x86_thiscallcc void @_ZN19ImportDefaultedDefsD1Ev(%struct.ImportDefaultedDefs*)
-// G64-DAG: declare dllimport void @_ZN19ImportDefaultedDefsD1Ev(%struct.ImportDefaultedDefs*)
__declspec(dllimport) ImportDefaultedDefs::~ImportDefaultedDefs() = default;
+#endif
-// M32-DAG: declare dllimport x86_thiscallcc %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QAE@ABU0@@Z"(%struct.ImportDefaultedDefs* returned, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
-// M64-DAG: declare dllimport %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QEAA@AEBU0@@Z"(%struct.ImportDefaultedDefs* returned, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
-// G32-DAG: declare dllimport x86_thiscallcc void @_ZN19ImportDefaultedDefsC1ERKS_(%struct.ImportDefaultedDefs*, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
-// G64-DAG: declare dllimport void @_ZN19ImportDefaultedDefsC1ERKS_(%struct.ImportDefaultedDefs*, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
+// M32-DAG: declare dllimport x86_thiscallcc %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QAE@ABU0@@Z"(%struct.ImportDefaultedDefs* returned, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
+// M64-DAG: declare dllimport %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QEAA@AEBU0@@Z"(%struct.ImportDefaultedDefs* returned, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
+// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN19ImportDefaultedDefsC1ERKS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
+// G64-DAG: define linkonce_odr void @_ZN19ImportDefaultedDefsC1ERKS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
inline ImportDefaultedDefs::ImportDefaultedDefs(const ImportDefaultedDefs&) = default;
-// M32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @"\01??4ImportDefaultedDefs@@QAEAAU0@ABU0@@Z"(%struct.ImportDefaultedDefs*, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
-// M64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @"\01??4ImportDefaultedDefs@@QEAAAEAU0@AEBU0@@Z"(%struct.ImportDefaultedDefs*, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
-// G32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @_ZN19ImportDefaultedDefsaSERKS_(%struct.ImportDefaultedDefs*, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
-// G64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @_ZN19ImportDefaultedDefsaSERKS_(%struct.ImportDefaultedDefs*, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
+// M32-DAG: declare dllimport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @"\01??4ImportDefaultedDefs@@QAEAAU0@ABU0@@Z"(%struct.ImportDefaultedDefs*, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
+// M64-DAG: declare dllimport dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @"\01??4ImportDefaultedDefs@@QEAAAEAU0@AEBU0@@Z"(%struct.ImportDefaultedDefs*, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
+// G32-DAG: define linkonce_odr x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @_ZN19ImportDefaultedDefsaSERKS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
+// G64-DAG: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.ImportDefaultedDefs* @_ZN19ImportDefaultedDefsaSERKS_(%struct.ImportDefaultedDefs* %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
inline ImportDefaultedDefs& ImportDefaultedDefs::operator=(const ImportDefaultedDefs&) = default;
// M32-DAG: define x86_thiscallcc %struct.ImportDefaultedDefs* @"\01??0ImportDefaultedDefs@@QAE@$$QAU0@@Z"(%struct.ImportDefaultedDefs* returned %this, %struct.ImportDefaultedDefs* dereferenceable({{[0-9]+}}))
@@ -655,14 +657,14 @@ struct MemFunTmpl {
};
// Import implicit instantiation of an imported member function template.
-// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$importedNormal@UImplicitInst_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
-// M64-DAG: declare dllimport void @"\01??$importedNormal@UImplicitInst_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
-// G32-DAG: declare dllimport x86_thiscallcc void @_ZN10MemFunTmpl14importedNormalI21ImplicitInst_ImportedEEvv(%struct.MemFunTmpl*)
-// G64-DAG: declare dllimport void @_ZN10MemFunTmpl14importedNormalI21ImplicitInst_ImportedEEvv(%struct.MemFunTmpl*)
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$importedNormal@UImplicitInst_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
+// M64-DAG: declare dllimport void @"\01??$importedNormal@UImplicitInst_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
+// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN10MemFunTmpl14importedNormalI21ImplicitInst_ImportedEEvv(%struct.MemFunTmpl* %this)
+// G64-DAG: define linkonce_odr void @_ZN10MemFunTmpl14importedNormalI21ImplicitInst_ImportedEEvv(%struct.MemFunTmpl* %this)
USEMF(MemFunTmpl, importedNormal<ImplicitInst_Imported>)
// MSC-DAG: declare dllimport void @"\01??$importedStatic@UImplicitInst_Imported@@@MemFunTmpl@@SAXXZ"()
-// GNU-DAG: declare dllimport void @_ZN10MemFunTmpl14importedStaticI21ImplicitInst_ImportedEEvv()
+// GNU-DAG: define linkonce_odr void @_ZN10MemFunTmpl14importedStaticI21ImplicitInst_ImportedEEvv()
USE(MemFunTmpl::importedStatic<ImplicitInst_Imported>)
@@ -670,13 +672,13 @@ USE(MemFunTmpl::importedStatic<ImplicitInst_Imported>)
// template.
// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$importedNormal@UExplicitDecl_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
// M64-DAG: declare dllimport void @"\01??$importedNormal@UExplicitDecl_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
-// G32-DAG: declare dllimport x86_thiscallcc void @_ZN10MemFunTmpl14importedNormalI21ExplicitDecl_ImportedEEvv(%struct.MemFunTmpl*)
-// G64-DAG: declare dllimport void @_ZN10MemFunTmpl14importedNormalI21ExplicitDecl_ImportedEEvv(%struct.MemFunTmpl*)
+// G32-DAG: declare x86_thiscallcc void @_ZN10MemFunTmpl14importedNormalI21ExplicitDecl_ImportedEEvv(%struct.MemFunTmpl*)
+// G64-DAG: declare void @_ZN10MemFunTmpl14importedNormalI21ExplicitDecl_ImportedEEvv(%struct.MemFunTmpl*)
extern template void MemFunTmpl::importedNormal<ExplicitDecl_Imported>();
USEMF(MemFunTmpl, importedNormal<ExplicitDecl_Imported>)
// MSC-DAG: declare dllimport void @"\01??$importedStatic@UExplicitDecl_Imported@@@MemFunTmpl@@SAXXZ"()
-// GNU-DAG: declare dllimport void @_ZN10MemFunTmpl14importedStaticI21ExplicitDecl_ImportedEEvv()
+// GNU-DAG: declare void @_ZN10MemFunTmpl14importedStaticI21ExplicitDecl_ImportedEEvv()
extern template void MemFunTmpl::importedStatic<ExplicitDecl_Imported>();
USE(MemFunTmpl::importedStatic<ExplicitDecl_Imported>)
@@ -685,13 +687,13 @@ USE(MemFunTmpl::importedStatic<ExplicitDecl_Imported>)
// template.
// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$importedNormal@UExplicitInst_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
// M64-DAG: declare dllimport void @"\01??$importedNormal@UExplicitInst_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
-// G32-DAG: declare dllimport x86_thiscallcc void @_ZN10MemFunTmpl14importedNormalI21ExplicitInst_ImportedEEvv(%struct.MemFunTmpl*)
-// G64-DAG: declare dllimport void @_ZN10MemFunTmpl14importedNormalI21ExplicitInst_ImportedEEvv(%struct.MemFunTmpl*)
+// G32-DAG: define weak_odr x86_thiscallcc void @_ZN10MemFunTmpl14importedNormalI21ExplicitInst_ImportedEEvv(%struct.MemFunTmpl* %this)
+// G64-DAG: define weak_odr void @_ZN10MemFunTmpl14importedNormalI21ExplicitInst_ImportedEEvv(%struct.MemFunTmpl* %this)
template void MemFunTmpl::importedNormal<ExplicitInst_Imported>();
USEMF(MemFunTmpl, importedNormal<ExplicitInst_Imported>)
// MSC-DAG: declare dllimport void @"\01??$importedStatic@UExplicitInst_Imported@@@MemFunTmpl@@SAXXZ"()
-// GNU-DAG: declare dllimport void @_ZN10MemFunTmpl14importedStaticI21ExplicitInst_ImportedEEvv()
+// GNU-DAG: define weak_odr void @_ZN10MemFunTmpl14importedStaticI21ExplicitInst_ImportedEEvv()
template void MemFunTmpl::importedStatic<ExplicitInst_Imported>();
USE(MemFunTmpl::importedStatic<ExplicitInst_Imported>)
@@ -711,10 +713,10 @@ USEMF(MemFunTmpl, importedNormal<ExplicitSpec_Imported>)
//USEMF(MemFunTmpl, importedNormal<ExplicitSpec_Def_Imported>)
#endif
-// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$importedNormal@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
-// M64-DAG: declare dllimport void @"\01??$importedNormal@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
-// G32-DAG: declare dllimport x86_thiscallcc void @_ZN10MemFunTmpl14importedNormalI31ExplicitSpec_InlineDef_ImportedEEvv(%struct.MemFunTmpl*)
-// G64-DAG: declare dllimport void @_ZN10MemFunTmpl14importedNormalI31ExplicitSpec_InlineDef_ImportedEEvv(%struct.MemFunTmpl*)
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$importedNormal@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
+// M64-DAG: declare dllimport void @"\01??$importedNormal@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
+// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN10MemFunTmpl14importedNormalI31ExplicitSpec_InlineDef_ImportedEEvv(%struct.MemFunTmpl* %this)
+// G64-DAG: define linkonce_odr void @_ZN10MemFunTmpl14importedNormalI31ExplicitSpec_InlineDef_ImportedEEvv(%struct.MemFunTmpl* %this)
template<> __declspec(dllimport) inline void MemFunTmpl::importedNormal<ExplicitSpec_InlineDef_Imported>() {}
USEMF(MemFunTmpl, importedNormal<ExplicitSpec_InlineDef_Imported>)
@@ -731,7 +733,7 @@ USE(MemFunTmpl::importedStatic<ExplicitSpec_Imported>)
#endif
// MSC-DAG: declare dllimport void @"\01??$importedStatic@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@SAXXZ"()
-// GNU-DAG: declare dllimport void @_ZN10MemFunTmpl14importedStaticI31ExplicitSpec_InlineDef_ImportedEEvv()
+// GNU-DAG: define linkonce_odr void @_ZN10MemFunTmpl14importedStaticI31ExplicitSpec_InlineDef_ImportedEEvv()
template<> __declspec(dllimport) inline void MemFunTmpl::importedStatic<ExplicitSpec_InlineDef_Imported>() {}
USE(MemFunTmpl::importedStatic<ExplicitSpec_InlineDef_Imported>)
@@ -755,13 +757,13 @@ USE(MemFunTmpl::importedStatic<ExplicitSpec_NotImported>)
// template.
// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$normalDef@UExplicitDecl_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
// M64-DAG: declare dllimport void @"\01??$normalDef@UExplicitDecl_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
-// G32-DAG: declare dllimport x86_thiscallcc void @_ZN10MemFunTmpl9normalDefI21ExplicitDecl_ImportedEEvv(%struct.MemFunTmpl*)
-// G64-DAG: declare dllimport void @_ZN10MemFunTmpl9normalDefI21ExplicitDecl_ImportedEEvv(%struct.MemFunTmpl*)
+// G32-DAG: declare x86_thiscallcc void @_ZN10MemFunTmpl9normalDefI21ExplicitDecl_ImportedEEvv(%struct.MemFunTmpl*)
+// G64-DAG: declare void @_ZN10MemFunTmpl9normalDefI21ExplicitDecl_ImportedEEvv(%struct.MemFunTmpl*)
extern template __declspec(dllimport) void MemFunTmpl::normalDef<ExplicitDecl_Imported>();
USEMF(MemFunTmpl, normalDef<ExplicitDecl_Imported>)
// MSC-DAG: declare dllimport void @"\01??$staticDef@UExplicitDecl_Imported@@@MemFunTmpl@@SAXXZ"()
-// GNU-DAG: declare dllimport void @_ZN10MemFunTmpl9staticDefI21ExplicitDecl_ImportedEEvv()
+// GNU-DAG: declare void @_ZN10MemFunTmpl9staticDefI21ExplicitDecl_ImportedEEvv()
extern template __declspec(dllimport) void MemFunTmpl::staticDef<ExplicitDecl_Imported>();
USE(MemFunTmpl::staticDef<ExplicitDecl_Imported>)
@@ -770,13 +772,13 @@ USE(MemFunTmpl::staticDef<ExplicitDecl_Imported>)
// template.
// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$normalDef@UExplicitInst_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
// M64-DAG: declare dllimport void @"\01??$normalDef@UExplicitInst_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
-// G32-DAG: declare dllimport x86_thiscallcc void @_ZN10MemFunTmpl9normalDefI21ExplicitInst_ImportedEEvv(%struct.MemFunTmpl*)
-// G64-DAG: declare dllimport void @_ZN10MemFunTmpl9normalDefI21ExplicitInst_ImportedEEvv(%struct.MemFunTmpl*)
+// G32-DAG: define weak_odr x86_thiscallcc void @_ZN10MemFunTmpl9normalDefI21ExplicitInst_ImportedEEvv(%struct.MemFunTmpl* %this)
+// G64-DAG: define weak_odr void @_ZN10MemFunTmpl9normalDefI21ExplicitInst_ImportedEEvv(%struct.MemFunTmpl* %this)
template __declspec(dllimport) void MemFunTmpl::normalDef<ExplicitInst_Imported>();
USEMF(MemFunTmpl, normalDef<ExplicitInst_Imported>)
// MSC-DAG: declare dllimport void @"\01??$staticDef@UExplicitInst_Imported@@@MemFunTmpl@@SAXXZ"()
-// GNU-DAG: declare dllimport void @_ZN10MemFunTmpl9staticDefI21ExplicitInst_ImportedEEvv()
+// GNU-DAG: define weak_odr void @_ZN10MemFunTmpl9staticDefI21ExplicitInst_ImportedEEvv()
template __declspec(dllimport) void MemFunTmpl::staticDef<ExplicitInst_Imported>();
USE(MemFunTmpl::staticDef<ExplicitInst_Imported>)
@@ -796,10 +798,10 @@ USEMF(MemFunTmpl, normalDef<ExplicitSpec_Imported>)
//USEMF(MemFunTmpl, normalDef<ExplicitSpec_Def_Imported>)
#endif
-// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$normalDef@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
-// M64-DAG: declare dllimport void @"\01??$normalDef@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
-// G32-DAG: declare dllimport x86_thiscallcc void @_ZN10MemFunTmpl9normalDefI31ExplicitSpec_InlineDef_ImportedEEvv(%struct.MemFunTmpl*)
-// G64-DAG: declare dllimport void @_ZN10MemFunTmpl9normalDefI31ExplicitSpec_InlineDef_ImportedEEvv(%struct.MemFunTmpl*)
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$normalDef@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
+// M64-DAG: declare dllimport void @"\01??$normalDef@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
+// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN10MemFunTmpl9normalDefI31ExplicitSpec_InlineDef_ImportedEEvv(%struct.MemFunTmpl* %this)
+// G64-DAG: define linkonce_odr void @_ZN10MemFunTmpl9normalDefI31ExplicitSpec_InlineDef_ImportedEEvv(%struct.MemFunTmpl* %this)
template<> __declspec(dllimport) inline void MemFunTmpl::normalDef<ExplicitSpec_InlineDef_Imported>() {}
USEMF(MemFunTmpl, normalDef<ExplicitSpec_InlineDef_Imported>)
@@ -816,7 +818,7 @@ USE(MemFunTmpl::staticDef<ExplicitSpec_Imported>)
#endif
// MSC-DAG: declare dllimport void @"\01??$staticDef@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@SAXXZ"()
-// GNU-DAG: declare dllimport void @_ZN10MemFunTmpl9staticDefI31ExplicitSpec_InlineDef_ImportedEEvv()
+// GNU-DAG: define linkonce_odr void @_ZN10MemFunTmpl9staticDefI31ExplicitSpec_InlineDef_ImportedEEvv()
template<> __declspec(dllimport) inline void MemFunTmpl::staticDef<ExplicitSpec_InlineDef_Imported>() {}
USE(MemFunTmpl::staticDef<ExplicitSpec_InlineDef_Imported>)
diff --git a/test/CodeGenCXX/dllimport-rtti.cpp b/test/CodeGenCXX/dllimport-rtti.cpp
index 7ed7dadfe402..b5a5d543d6e2 100644
--- a/test/CodeGenCXX/dllimport-rtti.cpp
+++ b/test/CodeGenCXX/dllimport-rtti.cpp
@@ -1,13 +1,17 @@
-// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++1y -O1 -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++1y -O1 -disable-llvm-optzns -o - %s | FileCheck %s --check-prefix=MSVC
+// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c++1y -O1 -disable-llvm-optzns -o - %s | FileCheck %s --check-prefix=GNU
struct __declspec(dllimport) S {
- virtual void f();
+ virtual void f() {}
} s;
-// CHECK-DAG: @"\01??_7S@@6B@" = available_externally dllimport
-// CHECK-DAG: @"\01??_R0?AUS@@@8" = linkonce_odr
-// CHECK-DAG: @"\01??_R1A@?0A@EA@S@@8" = linkonce_odr
-// CHECK-DAG: @"\01??_R2S@@8" = linkonce_odr
-// CHECK-DAG: @"\01??_R3S@@8" = linkonce_odr
+// MSVC-DAG: @"\01??_7S@@6B@" = available_externally dllimport
+// MSVC-DAG: @"\01??_R0?AUS@@@8" = linkonce_odr
+// MSVC-DAG: @"\01??_R1A@?0A@EA@S@@8" = linkonce_odr
+// MSVC-DAG: @"\01??_R2S@@8" = linkonce_odr
+// MSVC-DAG: @"\01??_R3S@@8" = linkonce_odr
+
+// GNU-DAG: @_ZTV1S = available_externally dllimport
+// GNU-DAG: @_ZTI1S = external dllimport
struct U : S {
} u;
diff --git a/test/CodeGenCXX/dllimport.cpp b/test/CodeGenCXX/dllimport.cpp
index 59f8f6361619..e5b9f64dcca6 100644
--- a/test/CodeGenCXX/dllimport.cpp
+++ b/test/CodeGenCXX/dllimport.cpp
@@ -1,13 +1,13 @@
-// RUN: %clang_cc1 -triple i686-windows-msvc -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC --check-prefix=M32 %s
-// RUN: %clang_cc1 -triple x86_64-windows-msvc -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC --check-prefix=M64 %s
-// RUN: %clang_cc1 -triple i686-windows-gnu -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G32 %s
-// RUN: %clang_cc1 -triple x86_64-windows-gnu -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G64 %s
-// RUN: %clang_cc1 -triple i686-windows-msvc -fno-rtti -emit-llvm -std=c++1y -O1 -o - %s -DMSABI | FileCheck --check-prefix=MO1 %s
-// RUN: %clang_cc1 -triple i686-windows-gnu -fno-rtti -emit-llvm -std=c++1y -O1 -o - %s | FileCheck --check-prefix=GO1 %s
+// RUN: %clang_cc1 -triple i686-windows-msvc -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -DMSABI -w | FileCheck --check-prefix=MSC --check-prefix=M32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -DMSABI -w | FileCheck --check-prefix=MSC --check-prefix=M64 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -w | FileCheck --check-prefix=GNU --check-prefix=G32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -w | FileCheck --check-prefix=GNU --check-prefix=G64 %s
+// RUN: %clang_cc1 -triple i686-windows-msvc -fno-rtti -emit-llvm -std=c++1y -O1 -o - %s -DMSABI -w | FileCheck --check-prefix=MO1 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -fno-rtti -emit-llvm -std=c++1y -O1 -o - %s -w | FileCheck --check-prefix=GO1 %s
// CHECK-NOT doesn't play nice with CHECK-DAG, so use separate run lines.
-// RUN: %clang_cc1 -triple i686-windows-msvc -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC2 %s
-// RUN: %clang_cc1 -triple i686-windows-gnu -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU2 %s
+// RUN: %clang_cc1 -triple i686-windows-msvc -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -DMSABI -w | FileCheck --check-prefix=MSC2 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -w | FileCheck --check-prefix=GNU2 %s
// Helper structs to make templates more expressive.
struct ImplicitInst_Imported {};
@@ -95,7 +95,7 @@ inline int __declspec(dllimport) inlineStaticLocalsFunc() {
USE(inlineStaticLocalsFunc);
// The address of a dllimport global cannot be used in constant initialization.
-// M32-DAG: @"\01?arr@?0??initializationFunc@@YAPAHXZ@4QBQAHB" = internal global [1 x i32*] zeroinitializer
+// M32-DAG: @"\01?arr@?1??initializationFunc@@YAPAHXZ@4QBQAHB" = internal global [1 x i32*] zeroinitializer
// GNU-DAG: @_ZZ18initializationFuncvE3arr = internal global [1 x i32*] zeroinitializer
int *initializationFunc() {
static int *const arr[] = {&ExternGlobalDecl};
@@ -214,36 +214,36 @@ USE(externC)
// Import inline function.
// MSC-DAG: declare dllimport void @"\01?inlineFunc@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z10inlineFuncv()
+// GNU-DAG: define linkonce_odr void @_Z10inlineFuncv()
// MO1-DAG: define available_externally dllimport void @"\01?inlineFunc@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z10inlineFuncv()
+// GO1-DAG: define linkonce_odr void @_Z10inlineFuncv()
__declspec(dllimport) inline void inlineFunc() {}
USE(inlineFunc)
// MSC-DAG: declare dllimport void @"\01?inlineDecl@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z10inlineDeclv()
+// GNU-DAG: define linkonce_odr void @_Z10inlineDeclv()
// MO1-DAG: define available_externally dllimport void @"\01?inlineDecl@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z10inlineDeclv()
+// GO1-DAG: define linkonce_odr void @_Z10inlineDeclv()
__declspec(dllimport) inline void inlineDecl();
void inlineDecl() {}
USE(inlineDecl)
// MSC-DAG: declare dllimport void @"\01?inlineDef@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z9inlineDefv()
+// GNU-DAG: define linkonce_odr void @_Z9inlineDefv()
// MO1-DAG: define available_externally dllimport void @"\01?inlineDef@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z9inlineDefv()
+// GO1-DAG: define linkonce_odr void @_Z9inlineDefv()
__declspec(dllimport) void inlineDef();
inline void inlineDef() {}
USE(inlineDef)
// inline attributes
// MSC-DAG: declare dllimport void @"\01?noinline@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z8noinlinev()
+// GNU-DAG: define linkonce_odr void @_Z8noinlinev()
__declspec(dllimport) __attribute__((noinline)) inline void noinline() {}
USE(noinline)
// MSC2-NOT: @"\01?alwaysInline@@YAXXZ"()
-// GNU2-NOT: @_Z12alwaysInlinev()
+// GNU-DAG: define linkonce_odr void @_Z12alwaysInlinev() {{.*}} comdat {
__declspec(dllimport) __attribute__((always_inline)) inline void alwaysInline() {}
USE(alwaysInline)
@@ -276,6 +276,11 @@ USE(redecl3)
// GNU-DAG: declare void @_Z7friend2v()
// MSC-DAG: define void @"\01?friend3@@YAXXZ"()
// GNU-DAG: define void @_Z7friend3v()
+// MSC-DAG: declare void @"\01?friend4@@YAXXZ"()
+// GNU-DAG: declare void @_Z7friend4v()
+// MSC-DAG: declare dllimport void @"\01?friend5@@YAXXZ"()
+// GNU-DAG: declare dllimport void @_Z7friend5v()
+
struct FuncFriend {
friend __declspec(dllimport) void friend1();
friend __declspec(dllimport) void friend2();
@@ -284,9 +289,18 @@ struct FuncFriend {
__declspec(dllimport) void friend1();
void friend2(); // dllimport ignored
void friend3() {} // dllimport ignored
+
+__declspec(dllimport) void friend4();
+__declspec(dllimport) void friend5();
+struct FuncFriendRedecl {
+ friend void friend4(); // dllimport ignored
+ friend void ::friend5();
+};
USE(friend1)
USE(friend2)
USE(friend3)
+USE(friend4)
+USE(friend5)
// Implicit declarations can be redeclared with dllimport.
// MSC-DAG: declare dllimport noalias i8* @"\01??2@{{YAPAXI|YAPEAX_K}}@Z"(
@@ -315,31 +329,31 @@ USE(funcTmplDecl<ImplicitInst_Imported>)
// Import inline function template.
// MSC-DAG: declare dllimport void @"\01??$inlineFuncTmpl1@UImplicitInst_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z15inlineFuncTmpl1I21ImplicitInst_ImportedEvv()
+// GNU-DAG: define linkonce_odr void @_Z15inlineFuncTmpl1I21ImplicitInst_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$inlineFuncTmpl1@UImplicitInst_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z15inlineFuncTmpl1I21ImplicitInst_ImportedEvv()
+// GO1-DAG: define linkonce_odr void @_Z15inlineFuncTmpl1I21ImplicitInst_ImportedEvv()
template<typename T> __declspec(dllimport) inline void inlineFuncTmpl1() {}
USE(inlineFuncTmpl1<ImplicitInst_Imported>)
// MSC-DAG: declare dllimport void @"\01??$inlineFuncTmpl2@UImplicitInst_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z15inlineFuncTmpl2I21ImplicitInst_ImportedEvv()
+// GNU-DAG: define linkonce_odr void @_Z15inlineFuncTmpl2I21ImplicitInst_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$inlineFuncTmpl2@UImplicitInst_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z15inlineFuncTmpl2I21ImplicitInst_ImportedEvv()
+// GO1-DAG: define linkonce_odr void @_Z15inlineFuncTmpl2I21ImplicitInst_ImportedEvv()
template<typename T> inline void __attribute__((dllimport)) inlineFuncTmpl2() {}
USE(inlineFuncTmpl2<ImplicitInst_Imported>)
// MSC-DAG: declare dllimport void @"\01??$inlineFuncTmplDecl@UImplicitInst_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z18inlineFuncTmplDeclI21ImplicitInst_ImportedEvv()
+// GNU-DAG: define linkonce_odr void @_Z18inlineFuncTmplDeclI21ImplicitInst_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$inlineFuncTmplDecl@UImplicitInst_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z18inlineFuncTmplDeclI21ImplicitInst_ImportedEvv()
+// GO1-DAG: define linkonce_odr void @_Z18inlineFuncTmplDeclI21ImplicitInst_ImportedEvv()
template<typename T> __declspec(dllimport) inline void inlineFuncTmplDecl();
template<typename T> void inlineFuncTmplDecl() {}
USE(inlineFuncTmplDecl<ImplicitInst_Imported>)
// MSC-DAG: declare dllimport void @"\01??$inlineFuncTmplDef@UImplicitInst_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z17inlineFuncTmplDefI21ImplicitInst_ImportedEvv()
+// GNU-DAG: define linkonce_odr void @_Z17inlineFuncTmplDefI21ImplicitInst_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$inlineFuncTmplDef@UImplicitInst_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z17inlineFuncTmplDefI21ImplicitInst_ImportedEvv()
+// GO1-DAG: define linkonce_odr void @_Z17inlineFuncTmplDefI21ImplicitInst_ImportedEvv()
template<typename T> __declspec(dllimport) void inlineFuncTmplDef();
template<typename T> inline void inlineFuncTmplDef() {}
USE(inlineFuncTmplDef<ImplicitInst_Imported>)
@@ -373,7 +387,7 @@ USE(funcTmplRedecl3<ImplicitInst_NotImported>)
// MSC-DAG: define linkonce_odr void @"\01??$funcTmplFriend3@UImplicitInst_NotImported@@@@YAXXZ"()
// GNU-DAG: define linkonce_odr void @_Z15funcTmplFriend3I24ImplicitInst_NotImportedEvv()
// MSC-DAG: declare dllimport void @"\01??$funcTmplFriend4@UImplicitInst_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z15funcTmplFriend4I21ImplicitInst_ImportedEvv()
+// GNU-DAG: define linkonce_odr void @_Z15funcTmplFriend4I21ImplicitInst_ImportedEvv()
struct FuncTmplFriend {
template<typename T> friend __declspec(dllimport) void funcTmplFriend1();
template<typename T> friend __declspec(dllimport) void funcTmplFriend2();
@@ -406,24 +420,24 @@ template<typename T> __declspec(dllimport) inline void importedFuncTmpl() {}
USE(importedFuncTmplDecl<ImplicitInst_Imported>)
// MSC-DAG: declare dllimport void @"\01??$importedFuncTmpl@UImplicitInst_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z16importedFuncTmplI21ImplicitInst_ImportedEvv()
+// GNU-DAG: define linkonce_odr void @_Z16importedFuncTmplI21ImplicitInst_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$importedFuncTmpl@UImplicitInst_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z16importedFuncTmplI21ImplicitInst_ImportedEvv()
+// GO1-DAG: define linkonce_odr void @_Z16importedFuncTmplI21ImplicitInst_ImportedEvv()
USE(importedFuncTmpl<ImplicitInst_Imported>)
// Import explicit instantiation declaration of an imported function template.
// MSC-DAG: declare dllimport void @"\01??$importedFuncTmpl@UExplicitDecl_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z16importedFuncTmplI21ExplicitDecl_ImportedEvv()
+// GNU-DAG: declare void @_Z16importedFuncTmplI21ExplicitDecl_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$importedFuncTmpl@UExplicitDecl_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z16importedFuncTmplI21ExplicitDecl_ImportedEvv()
+// GO1-DAG: define available_externally void @_Z16importedFuncTmplI21ExplicitDecl_ImportedEvv()
extern template void importedFuncTmpl<ExplicitDecl_Imported>();
USE(importedFuncTmpl<ExplicitDecl_Imported>)
// Import explicit instantiation definition of an imported function template.
// MSC-DAG: declare dllimport void @"\01??$importedFuncTmpl@UExplicitInst_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z16importedFuncTmplI21ExplicitInst_ImportedEvv()
+// GNU-DAG: define weak_odr void @_Z16importedFuncTmplI21ExplicitInst_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$importedFuncTmpl@UExplicitInst_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z16importedFuncTmplI21ExplicitInst_ImportedEvv()
+// GO1-DAG: define weak_odr void @_Z16importedFuncTmplI21ExplicitInst_ImportedEvv()
template void importedFuncTmpl<ExplicitInst_Imported>();
USE(importedFuncTmpl<ExplicitInst_Imported>)
@@ -442,9 +456,9 @@ USE(importedFuncTmplDecl<ExplicitSpec_Imported>)
#endif
// MSC-DAG: declare dllimport void @"\01??$importedFuncTmplDecl@UExplicitSpec_InlineDef_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z20importedFuncTmplDeclI31ExplicitSpec_InlineDef_ImportedEvv()
+// GNU-DAG: define linkonce_odr void @_Z20importedFuncTmplDeclI31ExplicitSpec_InlineDef_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$importedFuncTmplDecl@UExplicitSpec_InlineDef_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z20importedFuncTmplDeclI31ExplicitSpec_InlineDef_ImportedEvv()
+// GO1-DAG: define linkonce_odr void @_Z20importedFuncTmplDeclI31ExplicitSpec_InlineDef_ImportedEvv()
template<> __declspec(dllimport) inline void importedFuncTmplDecl<ExplicitSpec_InlineDef_Imported>() {}
USE(importedFuncTmplDecl<ExplicitSpec_InlineDef_Imported>)
@@ -462,9 +476,9 @@ USE(importedFuncTmpl<ExplicitSpec_Imported>)
#endif
// MSC-DAG: declare dllimport void @"\01??$importedFuncTmpl@UExplicitSpec_InlineDef_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z16importedFuncTmplI31ExplicitSpec_InlineDef_ImportedEvv()
+// GNU-DAG: define linkonce_odr void @_Z16importedFuncTmplI31ExplicitSpec_InlineDef_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$importedFuncTmpl@UExplicitSpec_InlineDef_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z16importedFuncTmplI31ExplicitSpec_InlineDef_ImportedEvv()
+// GO1-DAG: define linkonce_odr void @_Z16importedFuncTmplI31ExplicitSpec_InlineDef_ImportedEvv()
template<> __declspec(dllimport) inline void importedFuncTmpl<ExplicitSpec_InlineDef_Imported>() {}
USE(importedFuncTmpl<ExplicitSpec_InlineDef_Imported>)
@@ -481,9 +495,9 @@ USE(importedFuncTmpl<ExplicitSpec_NotImported>)
// MSC-DAG: declare dllimport void @"\01??$funcTmpl@UExplicitDecl_Imported@@@@YAXXZ"()
// MSC-DAG: declare dllimport void @"\01??$inlineFuncTmpl@UExplicitDecl_Imported@@@@YAXXZ"()
// GNU-DAG: declare dllimport void @_Z8funcTmplI21ExplicitDecl_ImportedEvv()
-// GNU-DAG: declare dllimport void @_Z14inlineFuncTmplI21ExplicitDecl_ImportedEvv()
+// GNU-DAG: declare void @_Z14inlineFuncTmplI21ExplicitDecl_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$inlineFuncTmpl@UExplicitDecl_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z14inlineFuncTmplI21ExplicitDecl_ImportedEvv()
+// GO1-DAG: define available_externally void @_Z14inlineFuncTmplI21ExplicitDecl_ImportedEvv()
extern template __declspec(dllimport) void funcTmpl<ExplicitDecl_Imported>();
extern template __declspec(dllimport) void inlineFuncTmpl<ExplicitDecl_Imported>();
USE(funcTmpl<ExplicitDecl_Imported>)
@@ -494,11 +508,11 @@ USE(inlineFuncTmpl<ExplicitDecl_Imported>)
// MSC-DAG: declare dllimport void @"\01??$funcTmpl@UExplicitInst_Imported@@@@YAXXZ"()
// MSC-DAG: declare dllimport void @"\01??$inlineFuncTmpl@UExplicitInst_Imported@@@@YAXXZ"()
// GNU-DAG: declare dllimport void @_Z8funcTmplI21ExplicitInst_ImportedEvv()
-// GNU-DAG: declare dllimport void @_Z14inlineFuncTmplI21ExplicitInst_ImportedEvv()
+// GNU-DAG: define weak_odr void @_Z14inlineFuncTmplI21ExplicitInst_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$funcTmpl@UExplicitInst_Imported@@@@YAXXZ"()
// MO1-DAG: define available_externally dllimport void @"\01??$inlineFuncTmpl@UExplicitInst_Imported@@@@YAXXZ"()
// GO1-DAG: define available_externally dllimport void @_Z8funcTmplI21ExplicitInst_ImportedEvv()
-// GO1-DAG: define available_externally dllimport void @_Z14inlineFuncTmplI21ExplicitInst_ImportedEvv()
+// GO1-DAG: define weak_odr void @_Z14inlineFuncTmplI21ExplicitInst_ImportedEvv()
template __declspec(dllimport) void funcTmpl<ExplicitInst_Imported>();
template __declspec(dllimport) void inlineFuncTmpl<ExplicitInst_Imported>();
USE(funcTmpl<ExplicitInst_Imported>)
@@ -519,9 +533,9 @@ USE(funcTmpl<ExplicitSpec_Imported>)
#endif
// MSC-DAG: declare dllimport void @"\01??$funcTmpl@UExplicitSpec_InlineDef_Imported@@@@YAXXZ"()
-// GNU-DAG: declare dllimport void @_Z8funcTmplI31ExplicitSpec_InlineDef_ImportedEvv()
+// GNU-DAG: define linkonce_odr void @_Z8funcTmplI31ExplicitSpec_InlineDef_ImportedEvv()
// MO1-DAG: define available_externally dllimport void @"\01??$funcTmpl@UExplicitSpec_InlineDef_Imported@@@@YAXXZ"()
-// GO1-DAG: define available_externally dllimport void @_Z8funcTmplI31ExplicitSpec_InlineDef_ImportedEvv()
+// GO1-DAG: define linkonce_odr void @_Z8funcTmplI31ExplicitSpec_InlineDef_ImportedEvv()
template<> __declspec(dllimport) inline void funcTmpl<ExplicitSpec_InlineDef_Imported>() {}
USE(funcTmpl<ExplicitSpec_InlineDef_Imported>)
@@ -658,18 +672,56 @@ namespace PR19933 {
// MSC-DAG: @"\01?y@?$D@$0CK@@PR19933@@2HA" = available_externally dllimport global i32 0
}
+namespace PR21355 {
+ struct __declspec(dllimport) S {
+ virtual ~S();
+ };
+ S::~S() {}
+
+ // S::~S is a key function, so we would ordinarily emit a strong definition for
+ // the vtable. However, S is imported, so the vtable should be too.
+
+ // GNU-DAG: @_ZTVN7PR213551SE = available_externally dllimport unnamed_addr constant [4 x i8*]
+}
+
+namespace PR21366 {
+ struct __declspec(dllimport) S {
+ void outOfLineMethod();
+ void inlineMethod() {}
+ inline void anotherInlineMethod();
+ void outOfClassInlineMethod();
+ };
+ void S::anotherInlineMethod() {}
+ inline void S::outOfClassInlineMethod() {}
+}
+
// MS ignores DLL attributes on partial specializations.
template <typename T> struct PartiallySpecializedClassTemplate {};
-template <typename T> struct __declspec(dllimport) PartiallySpecializedClassTemplate<T*> { void f() {} };
+template <typename T> struct __declspec(dllimport) PartiallySpecializedClassTemplate<T*> { void f(); };
USEMEMFUNC(PartiallySpecializedClassTemplate<void*>, f);
-// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?f@?$PartiallySpecializedClassTemplate@PAX@@QAEXXZ"
-// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN33PartiallySpecializedClassTemplateIPvE1fEv
+// M32-DAG: declare x86_thiscallcc void @"\01?f@?$PartiallySpecializedClassTemplate@PAX@@QAEXXZ"
+// G32-DAG: declare dllimport x86_thiscallcc void @_ZN33PartiallySpecializedClassTemplateIPvE1fEv
+// Attributes on explicit specializations are honored.
template <typename T> struct ExplicitlySpecializedClassTemplate {};
-template <> struct __declspec(dllimport) ExplicitlySpecializedClassTemplate<void*> { void f() {} };
+template <> struct __declspec(dllimport) ExplicitlySpecializedClassTemplate<void*> { void f(); };
USEMEMFUNC(ExplicitlySpecializedClassTemplate<void*>, f);
-// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?f@?$ExplicitlySpecializedClassTemplate@PAX@@QAEXXZ"
-// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN34ExplicitlySpecializedClassTemplateIPvE1fEv
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01?f@?$ExplicitlySpecializedClassTemplate@PAX@@QAEXXZ"
+// G32-DAG: declare dllimport x86_thiscallcc void @_ZN34ExplicitlySpecializedClassTemplateIPvE1fEv
+
+// MS inherits DLL attributes to partial specializations.
+template <typename T> struct __declspec(dllimport) PartiallySpecializedImportedClassTemplate {};
+template <typename T> struct PartiallySpecializedImportedClassTemplate<T*> { void f() {} };
+USEMEMFUNC(PartiallySpecializedImportedClassTemplate<void*>, f);
+// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?f@?$PartiallySpecializedImportedClassTemplate@PAX@@QAEXXZ"
+// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN41PartiallySpecializedImportedClassTemplateIPvE1fEv
+
+// Attributes on the instantiation take precedence over attributes on the template.
+template <typename T> struct __declspec(dllexport) ExplicitlyInstantiatedWithDifferentAttr { void f() {} };
+template struct __declspec(dllimport) ExplicitlyInstantiatedWithDifferentAttr<int>;
+USEMEMFUNC(ExplicitlyInstantiatedWithDifferentAttr<int>, f);
+// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?f@?$ExplicitlyInstantiatedWithDifferentAttr@H@@QAEXXZ"
+
//===----------------------------------------------------------------------===//
// Classes with template base classes
@@ -677,20 +729,20 @@ USEMEMFUNC(ExplicitlySpecializedClassTemplate<void*>, f);
template <typename T> struct ClassTemplate { void func() {} };
template <typename T> struct __declspec(dllexport) ExportedClassTemplate { void func() {} };
-template <typename T> struct __declspec(dllimport) ImportedClassTemplate { void func() {} };
+template <typename T> struct __declspec(dllimport) ImportedClassTemplate { void func(); };
template <typename T> struct ExplicitlySpecializedTemplate { void func() {} };
template <> struct ExplicitlySpecializedTemplate<int> { void func() {} };
template <typename T> struct ExplicitlyExportSpecializedTemplate { void func() {} };
template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate<int> { void func() {} };
template <typename T> struct ExplicitlyImportSpecializedTemplate { void func() {} };
-template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func() {} };
+template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func(); };
template <typename T> struct ExplicitlyInstantiatedTemplate { void func() {} };
template struct ExplicitlyInstantiatedTemplate<int>;
template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} };
template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>;
-template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func() {} };
+template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func(); };
template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>;
@@ -703,7 +755,7 @@ USEMEMFUNC(ClassTemplate<int>, func)
// ImportedTemplate is explicitly imported.
struct __declspec(dllimport) DerivedFromImportedTemplate : public ImportedClassTemplate<int> {};
USEMEMFUNC(ImportedClassTemplate<int>, func)
-// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ImportedClassTemplate@H@@QAEXXZ"
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ImportedClassTemplate@H@@QAEXXZ"
// G32-DAG: declare dllimport x86_thiscallcc void @_ZN21ImportedClassTemplateIiE4funcEv
// ExportedTemplate is explicitly exported.
@@ -741,8 +793,8 @@ USEMEMFUNC(ExplicitlyExportSpecializedTemplate<int>, func)
// Base class already specialized with import attribute.
struct __declspec(dllimport) DerivedFromExplicitlyImportSpecializedTemplate : public ExplicitlyImportSpecializedTemplate<int> {};
USEMEMFUNC(ExplicitlyImportSpecializedTemplate<int>, func)
-// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportSpecializedTemplate@H@@QAEXXZ"
-// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN35ExplicitlyImportSpecializedTemplateIiE4funcEv
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportSpecializedTemplate@H@@QAEXXZ"
+// G32-DAG: declare dllimport x86_thiscallcc void @_ZN35ExplicitlyImportSpecializedTemplateIiE4funcEv
// Base class already instantiated without dll attribute.
struct __declspec(dllimport) DerivedFromExplicitlyInstantiatedTemplate : public ExplicitlyInstantiatedTemplate<int> {};
@@ -759,8 +811,8 @@ USEMEMFUNC(ExplicitlyExportInstantiatedTemplate<int>, func)
// Base class already instantiated with import attribute.
struct __declspec(dllimport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate<int> {};
USEMEMFUNC(ExplicitlyImportInstantiatedTemplate<int>, func)
-// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportInstantiatedTemplate@H@@QAEXXZ"
-// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN36ExplicitlyImportInstantiatedTemplateIiE4funcEv
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportInstantiatedTemplate@H@@QAEXXZ"
+// G32-DAG: declare dllimport x86_thiscallcc void @_ZN36ExplicitlyImportInstantiatedTemplateIiE4funcEv
// MS: A dll attribute propagates through multiple levels of instantiation.
template <typename T> struct TopClass { void func() {} };
diff --git a/test/CodeGenCXX/duplicate-mangled-name.cpp b/test/CodeGenCXX/duplicate-mangled-name.cpp
index 65bfa22ac621..e57012e8c414 100644
--- a/test/CodeGenCXX/duplicate-mangled-name.cpp
+++ b/test/CodeGenCXX/duplicate-mangled-name.cpp
@@ -4,7 +4,7 @@
class MyClass {
static void meth();
};
-void MyClass::meth() { }
+void MyClass::meth() { } // expected-note {{previous}}
extern "C" {
void _ZN7MyClass4methEv() { } // expected-error {{definition with same mangled name as another definition}}
}
diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp
index 5bd06784cfab..6076444c25b0 100644
--- a/test/CodeGenCXX/explicit-instantiation.cpp
+++ b/test/CodeGenCXX/explicit-instantiation.cpp
@@ -90,6 +90,19 @@ namespace LateInstantiation {
// CHECK-OPT: define available_externally i32 @_ZN17LateInstantiation1fIiEEiv(
}
+namespace PR21718 {
+// The linkage of a used constexpr member function can change from linkonce_odr
+// to weak_odr after explicit instantiation without errors about defining the
+// same function twice.
+template <typename T>
+struct S {
+// CHECK-LABEL: define weak_odr i32 @_ZN7PR217181SIiE1fEv
+ __attribute__((used)) constexpr int f() { return 0; }
+};
+int g() { return S<int>().f(); }
+template struct S<int>;
+}
+
// Check that we emit definitions from explicit instantiations even when they
// occur prior to the definition itself.
template <typename T> struct S {
diff --git a/test/CodeGenCXX/extern-c.cpp b/test/CodeGenCXX/extern-c.cpp
index fefb216ea1c0..7852644d2b74 100644
--- a/test/CodeGenCXX/extern-c.cpp
+++ b/test/CodeGenCXX/extern-c.cpp
@@ -59,10 +59,10 @@ extern "C" {
// CHECK-NOT: @unused
// CHECK-NOT: @duplicate_internal
- // CHECK: @internal_var = alias internal i32* @_Z12internal_var
+ // CHECK: @internal_var = internal alias i32* @_Z12internal_var
// CHECK-NOT: @unused
// CHECK-NOT: @duplicate_internal
- // CHECK: @internal_fn = alias internal i32 ()* @_Z11internal_fnv
+ // CHECK: @internal_fn = internal alias i32 ()* @_Z11internal_fnv
// CHECK-NOT: @unused
// CHECK-NOT: @duplicate_internal
}
diff --git a/test/CodeGenCXX/field-access-debug-info.cpp b/test/CodeGenCXX/field-access-debug-info.cpp
index aed4ee5f3a77..2b5b53dcbd84 100644
--- a/test/CodeGenCXX/field-access-debug-info.cpp
+++ b/test/CodeGenCXX/field-access-debug-info.cpp
@@ -1,7 +1,7 @@
// RUN: %clang -g -S -emit-llvm %s -o - | FileCheck %s
-// CHECK: [ DW_TAG_member ] [p] [{{[^]]*}}] [from int]
-// CHECK: [ DW_TAG_member ] [pr] [{{[^]]*}}] [private] [from int]
+// CHECK: [ DW_TAG_member ] [p] [{{[^]]*}}] [public] [from int]
+// CHECK: [ DW_TAG_member ] [pr] [{{[^]]*}}] [from int]
class A {
public:
diff --git a/test/CodeGenCXX/funcsig.cpp b/test/CodeGenCXX/funcsig.cpp
index 684a796c1905..2a6e641aec9c 100644
--- a/test/CodeGenCXX/funcsig.cpp
+++ b/test/CodeGenCXX/funcsig.cpp
@@ -8,7 +8,7 @@ extern "C" int printf(const char *, ...);
void freeFunc(int *, char) {
printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
}
-// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __cdecl freeFunc(int *, char)\00"
+// CHECK: @"\01??_C@_0CD@KLGMNNL@void?5__cdecl?5freeFunc?$CIint?5?$CK?0?5cha@" = linkonce_odr unnamed_addr constant [{{.*}} x i8] c"void __cdecl freeFunc(int *, char)\00"
struct TopLevelClass {
void topLevelMethod(int *, char);
@@ -16,7 +16,7 @@ struct TopLevelClass {
void TopLevelClass::topLevelMethod(int *, char) {
printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
}
-// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __thiscall TopLevelClass::topLevelMethod(int *, char)\00"
+// CHECK: @"\01??_C@_0DL@OBHNMDP@void?5__thiscall?5TopLevelClass?3?3t@" = linkonce_odr unnamed_addr constant [{{.*}} x i8] c"void __thiscall TopLevelClass::topLevelMethod(int *, char)\00"
namespace NS {
struct NamespacedClass {
@@ -25,5 +25,5 @@ struct NamespacedClass {
void NamespacedClass::namespacedMethod(int *, char) {
printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
}
-// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __thiscall NS::NamespacedClass::namespacedMethod(int *, char)\00"
+// CHECK: @"\01??_C@_0ED@PFDKIEBA@void?5__thiscall?5NS?3?3NamespacedCl@" = linkonce_odr unnamed_addr constant [{{.*}} x i8] c"void __thiscall NS::NamespacedClass::namespacedMethod(int *, char)\00"
}
diff --git a/test/CodeGenCXX/function-template-specialization.cpp b/test/CodeGenCXX/function-template-specialization.cpp
index eb099df14d00..7728f3dc7462 100644
--- a/test/CodeGenCXX/function-template-specialization.cpp
+++ b/test/CodeGenCXX/function-template-specialization.cpp
@@ -1,4 +1,8 @@
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple %s -o - | FileCheck %s
+
+// CHECK-DAG: _ZZN7PR219047GetDataIiEERKibE1i = internal global i32 4
+// CHECK-DAG: _ZZN7PR219047GetDataIiEERKibE1i_0 = internal global i32 2
+
template<typename T, typename U>
T* next(T* ptr, const U& diff);
@@ -24,3 +28,18 @@ void test2(int *iptr, double *dptr, int diff) {
// CHECK: _Z4nextIdiEPT_S1_RKT0_
dptr = next(dptr, diff);
}
+
+namespace PR21904 {
+template <typename>
+const int &GetData(bool);
+
+template <>
+const int &GetData<int>(bool b) {
+ static int i = 4;
+ if (b) {
+ static int i = 2;
+ return i;
+ }
+ return i;
+}
+}
diff --git a/test/CodeGenCXX/globalinit-loc.cpp b/test/CodeGenCXX/globalinit-loc.cpp
index eb39aec94d48..583f9c75fa53 100644
--- a/test/CodeGenCXX/globalinit-loc.cpp
+++ b/test/CodeGenCXX/globalinit-loc.cpp
@@ -6,8 +6,8 @@
//
// CHECK: define internal void @_GLOBAL__sub_I_globalinit_loc.cpp
// CHECK: !dbg ![[DBG:.*]]
-// CHECK: "_GLOBAL__sub_I_globalinit_loc.cpp", i32 0, {{.*}}, i32 0} ; [ DW_TAG_subprogram ] [line 0] [local] [def]
-// CHECK: ![[DBG]] = metadata !{i32 0, i32 0,
+// CHECK: !"0x2e\00\00\00_GLOBAL__sub_I_globalinit_loc.cpp\000\00{{.*}}\000", {{.*}} ; [ DW_TAG_subprogram ] [line 0] [local] [def]
+// CHECK: ![[DBG]] = !MDLocation(line: 0,
# 99 "someheader.h"
class A {
public:
diff --git a/test/CodeGenCXX/homogeneous-aggregates.cpp b/test/CodeGenCXX/homogeneous-aggregates.cpp
new file mode 100644
index 000000000000..94813f357884
--- /dev/null
+++ b/test/CodeGenCXX/homogeneous-aggregates.cpp
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC
+// RUN: %clang_cc1 -mfloat-abi hard -triple armv7-unknown-linux-gnueabi -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM32
+// RUN: %clang_cc1 -mfloat-abi hard -triple aarch64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM64
+// RUN: %clang_cc1 -mfloat-abi hard -triple x86_64-unknown-windows-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=X64
+
+#if defined(__x86_64__)
+#define CC __attribute__((vectorcall))
+#else
+#define CC
+#endif
+
+// Test that C++ classes are correctly classified as homogeneous aggregates.
+
+struct Base1 {
+ int x;
+};
+struct Base2 {
+ double x;
+};
+struct Base3 {
+ double x;
+};
+struct D1 : Base1 { // non-homogeneous aggregate
+ double y, z;
+};
+struct D2 : Base2 { // homogeneous aggregate
+ double y, z;
+};
+struct D3 : Base1, Base2 { // non-homogeneous aggregate
+ double y, z;
+};
+struct D4 : Base2, Base3 { // homogeneous aggregate
+ double y, z;
+};
+
+struct I1 : Base2 {};
+struct I2 : Base2 {};
+struct I3 : Base2 {};
+struct D5 : I1, I2, I3 {}; // homogeneous aggregate
+
+// PPC: define void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, [3 x i64] %x.coerce)
+// ARM32: define arm_aapcs_vfpcc void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, [3 x i64] %x.coerce)
+// ARM64: define void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, %struct.D1* %x)
+// X64: define x86_vectorcallcc void @"\01_Z7func_D12D1@@24"(%struct.D1* noalias sret %agg.result, %struct.D1* %x)
+D1 CC func_D1(D1 x) { return x; }
+
+// PPC: define [3 x double] @_Z7func_D22D2([3 x double] %x.coerce)
+// ARM32: define arm_aapcs_vfpcc %struct.D2 @_Z7func_D22D2(%struct.D2 %x.coerce)
+// ARM64: define %struct.D2 @_Z7func_D22D2([3 x double] %x.coerce)
+// X64: define x86_vectorcallcc %struct.D2 @"\01_Z7func_D22D2@@24"(double %x.0, double %x.1, double %x.2)
+D2 CC func_D2(D2 x) { return x; }
+
+// PPC: define void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, [4 x i64] %x.coerce)
+// ARM32: define arm_aapcs_vfpcc void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, [4 x i64] %x.coerce)
+// ARM64: define void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, %struct.D3* %x)
+D3 CC func_D3(D3 x) { return x; }
+
+// PPC: define [4 x double] @_Z7func_D42D4([4 x double] %x.coerce)
+// ARM32: define arm_aapcs_vfpcc %struct.D4 @_Z7func_D42D4(%struct.D4 %x.coerce)
+// ARM64: define %struct.D4 @_Z7func_D42D4([4 x double] %x.coerce)
+D4 CC func_D4(D4 x) { return x; }
+
+D5 CC func_D5(D5 x) { return x; }
+// PPC: define [3 x double] @_Z7func_D52D5([3 x double] %x.coerce)
+// ARM32: define arm_aapcs_vfpcc %struct.D5 @_Z7func_D52D5(%struct.D5 %x.coerce)
+
+// The C++ multiple inheritance expansion case is a little more complicated, so
+// do some extra checking.
+//
+// ARM64-LABEL: define %struct.D5 @_Z7func_D52D5([3 x double] %x.coerce)
+// ARM64: bitcast %struct.D5* %{{.*}} to [3 x double]*
+// ARM64: store [3 x double] %x.coerce, [3 x double]*
+
+void call_D5(D5 *p) {
+ func_D5(*p);
+}
+
+// Check the call site.
+//
+// ARM64-LABEL: define void @_Z7call_D5P2D5(%struct.D5* %p)
+// ARM64: load [3 x double]*
+// ARM64: call %struct.D5 @_Z7func_D52D5([3 x double] %{{.*}})
+
+struct Empty { };
+struct Float1 { float x; };
+struct Float2 { float y; };
+struct HVAWithEmptyBase : Float1, Empty, Float2 { float z; };
+
+// PPC: define void @_Z15with_empty_base16HVAWithEmptyBase([3 x float] %a.coerce)
+// ARM64: define void @_Z15with_empty_base16HVAWithEmptyBase([3 x float] %a.coerce)
+// ARM32: define arm_aapcs_vfpcc void @_Z15with_empty_base16HVAWithEmptyBase(%struct.HVAWithEmptyBase %a.coerce)
+void CC with_empty_base(HVAWithEmptyBase a) {}
+
+// FIXME: MSVC doesn't consider this an HVA becuase of the empty base.
+// X64: define x86_vectorcallcc void @"\01_Z15with_empty_base16HVAWithEmptyBase@@16"(float %a.0, float %a.1, float %a.2)
+
+struct HVAWithEmptyBitField : Float1, Float2 {
+ int : 0; // Takes no space.
+ float z;
+};
+
+// PPC: define void @_Z19with_empty_bitfield20HVAWithEmptyBitField([3 x float] %a.coerce)
+// ARM64: define void @_Z19with_empty_bitfield20HVAWithEmptyBitField([3 x float] %a.coerce)
+// ARM32: define arm_aapcs_vfpcc void @_Z19with_empty_bitfield20HVAWithEmptyBitField(%struct.HVAWithEmptyBitField %a.coerce)
+// X64: define x86_vectorcallcc void @"\01_Z19with_empty_bitfield20HVAWithEmptyBitField@@16"(float %a.0, float %a.1, float %a.2)
+void CC with_empty_bitfield(HVAWithEmptyBitField a) {}
diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp
index 2f9a4f2d4f55..49b9efbdaba2 100644
--- a/test/CodeGenCXX/lambda-expressions.cpp
+++ b/test/CodeGenCXX/lambda-expressions.cpp
@@ -81,7 +81,7 @@ int g() {
};
// PR14773
-// CHECK: [[ARRVAL:%[0-9a-zA-Z]*]] = load i32* getelementptr inbounds ([0 x i32]* bitcast (<{}>* @_ZZ14staticarrayrefvE5array to [0 x i32]*), i32 0, i64 0), align 4
+// CHECK: [[ARRVAL:%[0-9a-zA-Z]*]] = load i32* getelementptr inbounds ([0 x i32]* @_ZZ14staticarrayrefvE5array, i32 0, i64 0), align 4
// CHECK-NEXT: store i32 [[ARRVAL]]
void staticarrayref(){
static int array[] = {};
@@ -91,9 +91,17 @@ void staticarrayref(){
}();
}
-// CHECK: define internal void @"_ZZ1hvEN3$_88__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} {
+// CHECK-LABEL: define internal i32* @"_ZZ11PR22071_funvENK3$_8clEv"
+// CHECK: ret i32* @PR22071_var
+int PR22071_var;
+int *PR22071_fun() {
+ constexpr int &y = PR22071_var;
+ return [&] { return &y; }();
+}
+
+// CHECK: define internal void @"_ZZ1hvEN3$_98__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} {
// CHECK-NOT: =
-// CHECK: call void @"_ZZ1hvENK3$_8clEv"(%struct.A* sret %agg.result,
+// CHECK: call void @"_ZZ1hvENK3$_9clEv"(%struct.A* sret %agg.result,
// CHECK-NEXT: ret void
struct A { ~A(); };
void h() {
diff --git a/test/CodeGenCXX/linetable-cleanup.cpp b/test/CodeGenCXX/linetable-cleanup.cpp
index ce7f2c674ba5..3a6aa88d9464 100644
--- a/test/CodeGenCXX/linetable-cleanup.cpp
+++ b/test/CodeGenCXX/linetable-cleanup.cpp
@@ -24,15 +24,15 @@ int foo()
C c;
c.i = 42;
// This breakpoint should be at/before the cleanup code.
- // CHECK: ![[CLEANUP]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[CLEANUP]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
return 0;
- // CHECK: ![[RET]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RET]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
}
void bar()
{
if (!foo())
- // CHECK: {{.*}} = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: {{.*}} = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
return;
if (foo()) {
@@ -40,21 +40,21 @@ void bar()
c.i = foo();
}
// Clang creates only a single ret instruction. Make sure it is at a useful line.
- // CHECK: ![[RETBAR]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RETBAR]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
}
void baz()
{
if (!foo())
- // CHECK: ![[SCOPE1:.*]] = metadata !{{{.*}}, i32 [[@LINE-1]], {{.*}}} ; [ DW_TAG_lexical_block ]
- // CHECK: {{.*}} = metadata !{i32 [[@LINE+1]], i32 0, metadata ![[SCOPE1]], null}
+ // CHECK: ![[SCOPE1:.*]] = !{!"0xb\00[[@LINE-1]]\00{{.*}}", {{.*}} ; [ DW_TAG_lexical_block ]
+ // CHECK: {{.*}} = !MDLocation(line: [[@LINE+1]], scope: ![[SCOPE1]])
return;
if (foo()) {
// no cleanup
- // CHECK: {{.*}} = metadata !{i32 [[@LINE+2]], i32 0, metadata ![[SCOPE2:.*]], null}
- // CHECK: ![[SCOPE2]] = metadata !{{{.*}}, i32 [[@LINE-3]], {{.*}}} ; [ DW_TAG_lexical_block ]
+ // CHECK: {{.*}} = !MDLocation(line: [[@LINE+2]], scope: ![[SCOPE2:.*]])
+ // CHECK: ![[SCOPE2]] = !{!"0xb\00[[@LINE-3]]\00{{.*}}", {{.*}} ; [ DW_TAG_lexical_block ]
return;
}
- // CHECK: ![[RETBAZ]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RETBAZ]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
}
diff --git a/test/CodeGenCXX/linetable-eh.cpp b/test/CodeGenCXX/linetable-eh.cpp
index 14a5067cf3ea..6d9b3a968ca6 100644
--- a/test/CodeGenCXX/linetable-eh.cpp
+++ b/test/CodeGenCXX/linetable-eh.cpp
@@ -4,18 +4,18 @@
// entries for the code that triggered it.
// CHECK: call void @llvm.dbg.declare
-// CHECK: call void @llvm.dbg.declare(metadata !{{{.*}}}, metadata ![[CURRENT_ADDR:.*]]), !dbg ![[DBG1:.*]]
+// CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[CURRENT_ADDR:.*]], metadata !{{.*}}), !dbg ![[DBG1:.*]]
// CHECK: unwind label %{{.*}}, !dbg ![[DBG1]]
// CHECK: store i64 %{{.*}}, i64* %current_address, align 8, !dbg ![[DBG4:.*]]
-// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{{{.*}}}, metadata ![[FOUND_IT:.*]]), !dbg ![[DBG2:.*]]
+// CHECK-NEXT: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[FOUND_IT:.*]], metadata !{{.*}}), !dbg ![[DBG2:.*]]
// CHECK: = landingpad
// CHECK-NEXT: cleanup, !dbg ![[DBG3:.*]]
// CHECK-DAG: ![[CURRENT_ADDR]] = {{.*}} [current_address]
// CHECK-DAG: ![[FOUND_IT]] = {{.*}} [found_it]
-// CHECK-DAG: ![[DBG1]] = metadata !{i32 256,
-// CHECK-DAG: ![[DBG2]] = metadata !{i32 257,
-// CHECK-DAG: ![[DBG3]] = metadata !{i32 268,
-// CHECK-DAG: ![[DBG4]] = metadata !{i32 256,
+// CHECK-DAG: ![[DBG1]] = !MDLocation(line: 256,
+// CHECK-DAG: ![[DBG2]] = !MDLocation(line: 257,
+// CHECK-DAG: ![[DBG3]] = !MDLocation(line: 268,
+// CHECK-DAG: ![[DBG4]] = !MDLocation(line: 256,
typedef unsigned long long uint64_t;
template<class _Tp> class shared_ptr {
public:
diff --git a/test/CodeGenCXX/linetable-fnbegin.cpp b/test/CodeGenCXX/linetable-fnbegin.cpp
index ce46306fed0d..b0a03f7c2067 100644
--- a/test/CodeGenCXX/linetable-fnbegin.cpp
+++ b/test/CodeGenCXX/linetable-fnbegin.cpp
@@ -4,10 +4,10 @@
// CHECK: define{{.*}}bar
// CHECK-NOT: define
// CHECK: ret {{.*}}, !dbg [[DBG:.*]]
-// CHECK: [[HPP:.*]] = metadata !{metadata !"./template.hpp",
-// CHECK: [[SP:.*]] = metadata !{i32 786478, metadata [[HPP]],{{.*}}[ DW_TAG_subprogram ] [line 22] [def] [bar]
+// CHECK: [[HPP:.*]] = !{!"./template.hpp",
+// CHECK: [[SP:.*]] = !{!"0x2e\00{{.*}}", [[HPP]],{{.*}}[ DW_TAG_subprogram ] [line 22] [def] [bar]
// We shouldn't need a lexical block for this function.
-// CHECK: [[DBG]] = metadata !{i32 23, i32 0, metadata [[SP]], null}
+// CHECK: [[DBG]] = !MDLocation(line: 23, scope: [[SP]])
# 1 "./template.h" 1
diff --git a/test/CodeGenCXX/lpad-linetable.cpp b/test/CodeGenCXX/lpad-linetable.cpp
index dba2ad63b2dd..c81191b9fedd 100644
--- a/test/CodeGenCXX/lpad-linetable.cpp
+++ b/test/CodeGenCXX/lpad-linetable.cpp
@@ -4,7 +4,7 @@
// CHECK: ret i32
// CHECK: landingpad {{.*}}
// CHECK-NEXT: !dbg ![[LPAD:[0-9]+]]
-// CHECK: ![[LPAD]] = metadata !{i32 24, i32 0, metadata !{{.*}}, null}
+// CHECK: ![[LPAD]] = !MDLocation(line: 24, scope: !{{.*}})
# 1 "/usr/include/c++/4.2.1/vector" 1 3
typedef long unsigned int __darwin_size_t;
diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp
index e935f51a46b2..ee7f24466b00 100644
--- a/test/CodeGenCXX/mangle-exprs.cpp
+++ b/test/CodeGenCXX/mangle-exprs.cpp
@@ -56,6 +56,18 @@ namespace Casts {
void static_(typename enable_if< O <= static_cast<unsigned>(4) >::type* = 0) {
}
+ template <unsigned O, typename T>
+ void reinterpret_(typename enable_if<O <= sizeof(reinterpret_cast<T *>(0))>::type * = 0) {
+ }
+
+ template <typename T, T *p>
+ void const_(typename enable_if<0 <= sizeof(const_cast<T *>(p))>::type * = 0) {
+ }
+
+ template <typename T, T *p>
+ void dynamic_(typename enable_if<0 <= sizeof(dynamic_cast<T *>(p))>::type * = 0) {
+ }
+
template< typename T >
void auto_(decltype(new auto(T()))) {
}
@@ -64,11 +76,12 @@ namespace Casts {
void scalar_(decltype(T(), int())) {
}
- // FIXME: Test const_cast, reinterpret_cast, dynamic_cast, which are
- // a bit harder to use in template arguments.
template <unsigned N> struct T {};
template <int N> T<N> f() { return T<N>(); }
+
+ extern int i;
+ extern struct S {} s;
// CHECK-LABEL: define weak_odr void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE
template void implicit<4>(void*);
@@ -76,8 +89,14 @@ namespace Casts {
template void cstyle<4>(void*);
// CHECK-LABEL: define weak_odr void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
template void functional<4>(void*);
- // CHECK-LABEL: define weak_odr void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_scjLi4EEvE4typeE
template void static_<4>(void*);
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts12reinterpret_ILj4EiEEvPN9enable_ifIXleT_szrcPT0_Li0EEvE4typeE
+ template void reinterpret_<4, int>(void*);
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts6const_IiXadL_ZNS_1iEEEEEvPN9enable_ifIXleLi0EszccPT_T0_EvE4typeE
+ template void const_<int, &i>(void*);
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts8dynamic_INS_1SEXadL_ZNS_1sEEEEEvPN9enable_ifIXleLi0EszdcPT_T0_EvE4typeE
+ template void dynamic_<struct S, &s>(void*);
// CHECK-LABEL: define weak_odr void @_ZN5Casts1fILi6EEENS_1TIXT_EEEv
template T<6> f<6>();
@@ -198,3 +217,79 @@ namespace test5 {
template void a<int>(decltype(noexcept(int())));
// CHECK: void @_ZN5test51aIiEEvDTnxcvT__EE(
}
+
+namespace test6 {
+ struct X {
+ int i;
+ };
+
+ struct Y {
+ union {
+ int i;
+ };
+ };
+
+ struct Z {
+ union {
+ X ua;
+ Y ub;
+ };
+
+ struct {
+ X s;
+ };
+
+ union {
+ union {
+ struct {
+ struct {
+ X uuss;
+ };
+ };
+ };
+ };
+ };
+
+ Z z, *zp;
+
+ template<typename T>
+ void f1(decltype(T(z.ua.i))) {}
+ template void f1<int>(int);
+ // CHECK-LABEL: define weak_odr void @_ZN5test62f1IiEEvDTcvT_dtdtL_ZNS_1zEE2ua1iE
+
+ template<typename T>
+ void f2(decltype(T(z.ub.i))) {}
+ template void f2<int>(int);
+ // CHECK-LABEL: define weak_odr void @_ZN5test62f2IiEEvDTcvT_dtdtL_ZNS_1zEE2ub1iE
+
+ template<typename T>
+ void f3(decltype(T(z.s.i))) {}
+ template void f3<int>(int);
+ // CHECK-LABEL: define weak_odr void @_ZN5test62f3IiEEvDTcvT_dtdtL_ZNS_1zEE1s1iE
+
+ template<typename T>
+ void f4(decltype(T(z.uuss.i))) {}
+ template void f4<int>(int);
+ // CHECK-LABEL: define weak_odr void @_ZN5test62f4IiEEvDTcvT_dtdtL_ZNS_1zEE4uuss1iE
+
+ template<typename T>
+ void f5(decltype(T(zp->ua.i))) {}
+ template void f5<int>(int);
+ // CHECK-LABEL: define weak_odr void @_ZN5test62f5IiEEvDTcvT_dtptL_ZNS_2zpEE2ua1iE
+
+ template<typename T>
+ void f6(decltype(T(zp->ub.i))) {}
+ template void f6<int>(int);
+ // CHECK-LABEL: define weak_odr void @_ZN5test62f6IiEEvDTcvT_dtptL_ZNS_2zpEE2ub1iE
+
+ template<typename T>
+ void f7(decltype(T(zp->s.i))) {}
+ template void f7<int>(int);
+ // CHECK-LABEL: define weak_odr void @_ZN5test62f7IiEEvDTcvT_dtptL_ZNS_2zpEE1s1iE
+
+ template<typename T>
+ void f8(decltype(T(zp->uuss.i))) {}
+ template void f8<int>(int);
+ // CHECK-LABEL: define weak_odr void @_ZN5test62f8IiEEvDTcvT_dtptL_ZNS_2zpEE4uuss1iE
+}
+
diff --git a/test/CodeGenCXX/mangle-literal-suffix.cpp b/test/CodeGenCXX/mangle-literal-suffix.cpp
new file mode 100644
index 000000000000..ab557d5a1bfa
--- /dev/null
+++ b/test/CodeGenCXX/mangle-literal-suffix.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple mips-none-none -emit-llvm -o - %s | FileCheck %s
+
+template <class T> void g3(char (&buffer)[sizeof(T() + 5.0)]) {}
+template void g3<int>(char (&)[sizeof(double)]);
+// CHECK: _Z2g3IiEvRAszplcvT__ELd4014000000000000E_c
+
+template <class T> void g4(char (&buffer)[sizeof(T() + 5.0L)]) {}
+template void g4<int>(char (&)[sizeof(long double)]);
+// CHECK: _Z2g4IiEvRAszplcvT__ELe4014000000000000E_c
+
+template <class T> void g5(char (&buffer)[sizeof(T() + 5)]) {}
+template void g5<int>(char (&)[sizeof(int)]);
+// CHECK: _Z2g5IiEvRAszplcvT__ELi5E_c
+
+template <class T> void g6(char (&buffer)[sizeof(T() + 5L)]) {}
+template void g6<int>(char (&)[sizeof(long int)]);
+// CHECK: _Z2g6IiEvRAszplcvT__ELl5E_c
diff --git a/test/CodeGenCXX/mangle-local-anonymous-unions.cpp b/test/CodeGenCXX/mangle-local-anonymous-unions.cpp
new file mode 100644
index 000000000000..9187c1a5a27a
--- /dev/null
+++ b/test/CodeGenCXX/mangle-local-anonymous-unions.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple %itanium_abi_triple -o - | FileCheck %s
+
+// CHECK-DAG: @_ZZ2f0vE1a
+// CHECK-DAG: @_ZZ2f0vE1c
+// CHECK-DAG: @_ZZ2f0vE1e_0
+inline int f0() {
+ static union {
+ int a;
+ long int b;
+ };
+
+ static union {
+ int c;
+ double d;
+ };
+
+ if (0) {
+ static union {
+ int e;
+ int f;
+ };
+ }
+ static union {
+ int e;
+ int f;
+ };
+
+ return a+c;
+}
+
+inline void nop() {
+ static union {
+ union {
+ };
+ };
+}
+
+int f1 (int a, int c) {
+ nop();
+ return a+c+f0();
+}
+
diff --git a/test/CodeGenCXX/mangle-ms-cxx11.cpp b/test/CodeGenCXX/mangle-ms-cxx11.cpp
index 373d2b7b957f..fe7121ef24dc 100644
--- a/test/CodeGenCXX/mangle-ms-cxx11.cpp
+++ b/test/CodeGenCXX/mangle-ms-cxx11.cpp
@@ -1,8 +1,67 @@
// RUN: %clang_cc1 -std=c++11 -fms-extensions -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s
+namespace FTypeWithQuals {
+template <typename T>
+struct S {};
+
+using A = int () const;
+S<A> a;
+// CHECK-DAG: @"\01?a@FTypeWithQuals@@3U?$S@$$A8@@BAHXZ@1@A"
+
+using B = int () volatile;
+S<B> b;
+// CHECK-DAG: @"\01?b@FTypeWithQuals@@3U?$S@$$A8@@CAHXZ@1@A"
+
+using C = int () __restrict;
+S<C> c;
+// CHECK-DAG: @"\01?c@FTypeWithQuals@@3U?$S@$$A8@@IAAHXZ@1@A"
+
+using D = int () const &;
+S<D> d;
+// CHECK-DAG: @"\01?d@FTypeWithQuals@@3U?$S@$$A8@@GBAHXZ@1@A"
+
+using E = int () volatile &;
+S<E> e;
+// CHECK-DAG: @"\01?e@FTypeWithQuals@@3U?$S@$$A8@@GCAHXZ@1@A"
+
+using F = int () __restrict &;
+S<F> f;
+// CHECK-DAG: @"\01?f@FTypeWithQuals@@3U?$S@$$A8@@IGAAHXZ@1@A"
+
+using G = int () const &&;
+S<G> g;
+// CHECK-DAG: @"\01?g@FTypeWithQuals@@3U?$S@$$A8@@HBAHXZ@1@A"
+
+using H = int () volatile &&;
+S<H> h;
+// CHECK-DAG: @"\01?h@FTypeWithQuals@@3U?$S@$$A8@@HCAHXZ@1@A"
+
+using I = int () __restrict &&;
+S<I> i;
+// CHECK-DAG: @"\01?i@FTypeWithQuals@@3U?$S@$$A8@@IHAAHXZ@1@A"
+
+using J = int ();
+S<J> j;
+// CHECK-DAG: @"\01?j@FTypeWithQuals@@3U?$S@$$A6AHXZ@1@A"
+
+using K = int () &;
+S<K> k;
+// CHECK-DAG: @"\01?k@FTypeWithQuals@@3U?$S@$$A8@@GAAHXZ@1@A"
+
+using L = int () &&;
+S<L> l;
+// CHECK-DAG: @"\01?l@FTypeWithQuals@@3U?$S@$$A8@@HAAHXZ@1@A"
+}
+
// CHECK: "\01?DeducedType@@3HA"
auto DeducedType = 30;
+// CHECK-DAG: @"\01?Char16Var@@3_SA"
+char16_t Char16Var;
+
+// CHECK-DAG: @"\01?Char32Var@@3_UA"
+char32_t Char32Var;
+
// CHECK: "\01?LRef@@YAXAAH@Z"
void LRef(int& a) { }
@@ -98,7 +157,7 @@ namespace PR18022 {
struct { } a;
decltype(a) fun(decltype(a) x, decltype(a)) { return x; }
-// CHECK-DAG: ?fun@PR18022@@YA?AU<unnamed-type-a>@1@U21@0@Z
+// CHECK-DAG: @"\01?fun@PR18022@@YA?AU<unnamed-type-a>@1@U21@0@Z"
}
@@ -106,17 +165,32 @@ inline int define_lambda() {
static auto lambda = [] { static int local; ++local; return local; };
// First, we have the static local variable of type "<lambda_1>" inside of
// "define_lambda".
-// CHECK-DAG: ?lambda@?1??define_lambda@@YAHXZ@4V<lambda_1>@@A
+// CHECK-DAG: @"\01?lambda@?1??define_lambda@@YAHXZ@4V<lambda_1>@?1@YAHXZ@A"
// Next, we have the "operator()" for "<lambda_1>" which is inside of
// "define_lambda".
-// CHECK-DAG: ??R<lambda_1>@?define_lambda@@YAHXZ@QBEHXZ
+// CHECK-DAG: @"\01??R<lambda_1>@?define_lambda@@YAHXZ@QBEHXZ"
// Finally, we have the local which is inside of "<lambda_1>" which is inside of
// "define_lambda". Hooray.
-// CHECK-DAG: ?local@?2???R<lambda_1>@?define_lambda@@YAHXZ@QBEHXZ@4HA
+// CHECK-DAG: @"\01?local@?2???R<lambda_1>@?define_lambda@@YAHXZ@QBEHXZ@4HA"
return lambda();
}
+template <typename T>
+void use_lambda_arg(T) {}
+
+inline void call_with_lambda_arg1() {
+ use_lambda_arg([]{});
+ // CHECK-DAG: @"\01??$use_lambda_arg@V<lambda_1>@?call_with_lambda_arg1@@YAXXZ@@@YAXV<lambda_1>@?call_with_lambda_arg1@@YAXXZ@@Z"
+}
+
+inline void call_with_lambda_arg2() {
+ use_lambda_arg([]{});
+ // CHECK-DAG: @"\01??$use_lambda_arg@V<lambda_1>@?call_with_lambda_arg2@@YAXXZ@@@YAXV<lambda_1>@?call_with_lambda_arg2@@YAXXZ@@Z"
+}
+
int call_lambda() {
+ call_with_lambda_arg1();
+ call_with_lambda_arg2();
return define_lambda();
}
@@ -139,3 +213,29 @@ void templ_fun_with_pack() {}
template void templ_fun_with_pack<>();
// CHECK-DAG: @"\01??$templ_fun_with_pack@$S@@YAXXZ"
+
+template <typename...>
+void templ_fun_with_ty_pack() {}
+
+template void templ_fun_with_ty_pack<>();
+// CHECK-DAG: @"\01??$templ_fun_with_ty_pack@$$V@@YAXXZ"
+
+template <template <class> class...>
+void templ_fun_with_templ_templ_pack() {}
+
+template void templ_fun_with_templ_templ_pack<>();
+// CHECK-DAG: @"\01??$templ_fun_with_templ_templ_pack@$$V@@YAXXZ"
+
+namespace PR20047 {
+template <typename T>
+struct A {};
+
+template <typename T>
+using AliasA = A<T>;
+
+template <template <typename> class>
+void f() {}
+
+template void f<AliasA>();
+// CHECK-DAG: @"\01??$f@$$YAliasA@PR20047@@@PR20047@@YAXXZ"
+}
diff --git a/test/CodeGenCXX/mangle-ms-cxx14.cpp b/test/CodeGenCXX/mangle-ms-cxx14.cpp
index 03995611d252..c06efe2edee9 100644
--- a/test/CodeGenCXX/mangle-ms-cxx14.cpp
+++ b/test/CodeGenCXX/mangle-ms-cxx14.cpp
@@ -13,7 +13,7 @@ auto FunctionWithLocalType() {
return LocalType{};
}
-// CHECK: "\01?ValueFromFunctionWithLocalType@@3ULocalType@?0??FunctionWithLocalType@@YA?A?<auto>@@XZ@A"
+// CHECK: "\01?ValueFromFunctionWithLocalType@@3ULocalType@?1??FunctionWithLocalType@@YA?A?<auto>@@XZ@A"
auto ValueFromFunctionWithLocalType = FunctionWithLocalType();
// CHECK: "\01??R<lambda_0>@@QBE?A?<auto>@@XZ"
@@ -22,7 +22,7 @@ auto LambdaWithLocalType = [] {
return LocalType{};
};
-// CHECK: "\01?ValueFromLambdaWithLocalType@@3ULocalType@?0???R<lambda_0>@@QBE?A?<auto>@@XZ@A"
+// CHECK: "\01?ValueFromLambdaWithLocalType@@3ULocalType@?1???R<lambda_0>@@QBE?A?<auto>@@XZ@A"
auto ValueFromLambdaWithLocalType = LambdaWithLocalType();
template <typename T>
diff --git a/test/CodeGenCXX/mangle-ms-string-literals.cpp b/test/CodeGenCXX/mangle-ms-string-literals.cpp
index a77a04f71e0a..e5ebc086e148 100644
--- a/test/CodeGenCXX/mangle-ms-string-literals.cpp
+++ b/test/CodeGenCXX/mangle-ms-string-literals.cpp
@@ -719,3 +719,9 @@ const wchar_t *LongWideString = L"012345678901234567890123456789ABCDEF";
// CHECK: @"\01??_C@_1EK@KFPEBLPK@?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AAA?$AAB@"
const wchar_t *UnicodeLiteral = L"\ud7ff";
// CHECK: @"\01??_C@_13IIHIAFKH@?W?$PP?$AA?$AA@"
+const char *U8Literal = u8"hi";
+// CHECK: @"\01??_C@_02PCEFGMJL@hi?$AA@"
+const char16_t *U16Literal = u"hi";
+// CHECK: @"\01??_C@_05OMLEGLOC@h?$AAi?$AA?$AA?$AA@"
+const char32_t *U32Literal = U"hi";
+// CHECK: @"\01??_C@_0M@GFNAJIPG@h?$AA?$AA?$AAi?$AA?$AA?$AA?$AA?$AA?$AA?$AA@"
diff --git a/test/CodeGenCXX/mangle-ms-templates.cpp b/test/CodeGenCXX/mangle-ms-templates.cpp
index 31fda2046c4b..46ab251af14f 100644
--- a/test/CodeGenCXX/mangle-ms-templates.cpp
+++ b/test/CodeGenCXX/mangle-ms-templates.cpp
@@ -24,6 +24,12 @@ class IntTemplate {
IntTemplate() {}
};
+template<unsigned param>
+class UnsignedIntTemplate {
+public:
+ UnsignedIntTemplate() {}
+};
+
template<long long param>
class LongLongTemplate {
public:
@@ -133,6 +139,10 @@ void template_mangling() {
IntTemplate<-11> neg_11;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0?L@@@QAE@XZ"
// X64: call {{.*}} @"\01??0?$IntTemplate@$0?L@@@QEAA@XZ"
+
+ UnsignedIntTemplate<4294967295> ffffffff;
+// CHECK: call {{.*}} @"\01??0?$UnsignedIntTemplate@$0PPPPPPPP@@@QAE@XZ"
+// X64: call {{.*}} @"\01??0?$UnsignedIntTemplate@$0PPPPPPPP@@@QEAA@XZ"
LongLongTemplate<-9223372036854775807LL-1LL> int64_min;
// CHECK: call {{.*}} @"\01??0?$LongLongTemplate@$0?IAAAAAAAAAAAAAAA@@@QAE@XZ"
diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp
index 3285c98546ec..662278b3034f 100644
--- a/test/CodeGenCXX/mangle-ms.cpp
+++ b/test/CodeGenCXX/mangle-ms.cpp
@@ -117,6 +117,19 @@ const volatile char foo2::*k;
int (foo2::*l)(int);
// CHECK-DAG: @"\01?l@@3P8foo@@AEHH@ZQ1@"
+// Ensure typedef CV qualifiers are mangled correctly
+typedef const int cInt;
+typedef volatile int vInt;
+typedef const volatile int cvInt;
+
+extern cInt g_cInt = 1;
+vInt g_vInt = 2;
+cvInt g_cvInt = 3;
+
+// CHECK-DAG: @"\01?g_cInt@@3HB"
+// CHECK-DAG: @"\01?g_vInt@@3HC"
+// CHECK-DAG: @"\01?g_cvInt@@3HD"
+
// Static functions are mangled, too.
// Also make sure calling conventions, arglists, and throw specs work.
static void __stdcall alpha(float a, double b) throw() {}
@@ -365,3 +378,5 @@ void TypedefNewDelete::operator delete[](void *) { }
// CHECK-DAG: ??3TypedefNewDelete@@SAXPAX@Z
// CHECK-DAG: ??_VTypedefNewDelete@@SAXPAX@Z
+void __vectorcall vector_func() { }
+// CHECK-DAG: @"\01?vector_func@@YQXXZ"
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index 9bdac7f17289..9af0d9da9976 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -991,3 +991,25 @@ namespace test48 {
template void f<S>(S::u *);
// CHECK-LABEL: define weak_odr void @_ZN6test481fINS_1SEEEvPTuNT_1uE(%"union.test48::S::u"*)
}
+
+namespace test49 {
+ template <int>
+ struct S {};
+
+ template <template <int> class T>
+ T<3> fin(T<3>);
+
+ auto v = fin<S>;
+ // CHECK-LABEL: declare void @_ZN6test493finINS_1SEEET_ILi3EES3_()
+}
+
+namespace test50 {
+ template <int>
+ struct S {};
+
+ template <template <int> class T>
+ T<3> fin(T<4>);
+
+ auto v = fin<S>;
+ // CHECK-LABEL: declare void @_ZN6test503finINS_1SEEET_ILi3EES2_ILi4EE()
+}
diff --git a/test/CodeGenCXX/merge-functions.cpp b/test/CodeGenCXX/merge-functions.cpp
new file mode 100644
index 000000000000..2137f19c409c
--- /dev/null
+++ b/test/CodeGenCXX/merge-functions.cpp
@@ -0,0 +1,14 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O1 -fmerge-functions -emit-llvm -o - -x c++ < %s | FileCheck %s
+
+// Basic functionality test. Function merging doesn't kick in on functions that
+// are too simple.
+
+struct A {
+ virtual int f(int x, int *p) { return x ? *p : 1; }
+ virtual int g(int x, int *p) { return x ? *p : 1; }
+} a;
+
+// CHECK: define {{.*}} @_ZN1A1gEiPi
+// CHECK-NEXT: tail call i32 @_ZN1A1fEiPi
+// CHECK-NEXT: ret
diff --git a/test/CodeGenCXX/microsoft-abi-byval-sret.cpp b/test/CodeGenCXX/microsoft-abi-byval-sret.cpp
index 985b1ce62e92..a34a2455c36f 100644
--- a/test/CodeGenCXX/microsoft-abi-byval-sret.cpp
+++ b/test/CodeGenCXX/microsoft-abi-byval-sret.cpp
@@ -5,25 +5,66 @@ struct A {
A(const A &o) : a(o.a) {}
~A() {}
int a;
+};
+
+struct B {
A foo(A o);
+ A __cdecl bar(A o);
+ A __stdcall baz(A o);
+ A __fastcall qux(A o);
};
-A A::foo(A x) {
- A y(*this);
- y.a += x.a;
- return y;
+A B::foo(A x) {
+ return x;
}
-// CHECK-LABEL: define x86_thiscallcc %struct.A* @"\01?foo@A@@QAE?AU1@U1@@Z"
-// CHECK: (%struct.A* %this, <{ %struct.A*, %struct.A }>* inalloca)
+// CHECK-LABEL: define x86_thiscallcc %struct.A* @"\01?foo@B@@QAE?AUA@@U2@@Z"
+// CHECK: (%struct.B* %this, <{ %struct.A*, %struct.A }>* inalloca)
// CHECK: getelementptr inbounds <{ %struct.A*, %struct.A }>* %{{.*}}, i32 0, i32 0
// CHECK: load %struct.A**
// CHECK: ret %struct.A*
+A B::bar(A x) {
+ return x;
+}
+
+// CHECK-LABEL: define %struct.A* @"\01?bar@B@@QAA?AUA@@U2@@Z"
+// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca)
+// CHECK: getelementptr inbounds <{ %struct.B*, %struct.A*, %struct.A }>* %{{.*}}, i32 0, i32 1
+// CHECK: load %struct.A**
+// CHECK: ret %struct.A*
+
+A B::baz(A x) {
+ return x;
+}
+
+// CHECK-LABEL: define x86_stdcallcc %struct.A* @"\01?baz@B@@QAG?AUA@@U2@@Z"
+// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca)
+// CHECK: getelementptr inbounds <{ %struct.B*, %struct.A*, %struct.A }>* %{{.*}}, i32 0, i32 1
+// CHECK: load %struct.A**
+// CHECK: ret %struct.A*
+
+A B::qux(A x) {
+ return x;
+}
+
+// CHECK-LABEL: define x86_fastcallcc void @"\01?qux@B@@QAI?AUA@@U2@@Z"
+// CHECK: (%struct.B* inreg %this, %struct.A* inreg noalias sret %agg.result, <{ %struct.A }>* inalloca)
+// CHECK: ret void
+
int main() {
- A x;
- A y = x.foo(x);
+ B b;
+ A a = b.foo(A());
+ a = b.bar(a);
+ a = b.baz(a);
+ a = b.qux(a);
}
-// CHECK: call x86_thiscallcc %struct.A* @"\01?foo@A@@QAE?AU1@U1@@Z"
-// CHECK: (%struct.A* %{{[^,]*}}, <{ %struct.A*, %struct.A }>* inalloca %{{[^,]*}})
+// CHECK: call x86_thiscallcc %struct.A* @"\01?foo@B@@QAE?AUA@@U2@@Z"
+// CHECK: (%struct.B* %{{[^,]*}}, <{ %struct.A*, %struct.A }>* inalloca %{{[^,]*}})
+// CHECK: call %struct.A* @"\01?bar@B@@QAA?AUA@@U2@@Z"
+// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca %{{[^,]*}})
+// CHECK: call x86_stdcallcc %struct.A* @"\01?baz@B@@QAG?AUA@@U2@@Z"
+// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca %{{[^,]*}})
+// CHECK: call x86_fastcallcc void @"\01?qux@B@@QAI?AUA@@U2@@Z"
+// CHECK: (%struct.B* inreg %{{[^,]*}}, %struct.A* inreg sret %{{.*}}, <{ %struct.A }>* inalloca %{{[^,]*}})
diff --git a/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp b/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp
new file mode 100644
index 000000000000..9bcfb9c184e5
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 %s -fno-rtti -triple=i686-pc-win32 -emit-llvm -o - | FileCheck --check-prefix=CHECK32 %s
+// RUN: %clang_cc1 %s -fno-rtti -triple=x86_64-pc-win32 -emit-llvm -o - | FileCheck --check-prefix=CHECK64 %s
+
+namespace byval_thunk {
+struct Agg {
+ Agg();
+ Agg(const Agg &);
+ ~Agg();
+ int x;
+};
+
+struct A { virtual void foo(Agg x); };
+struct B { virtual void foo(Agg x); };
+struct C : A, B { C(); virtual void foo(Agg x); };
+C::C() {} // force emission
+
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01?foo@C@byval_thunk@@W3AEXUAgg@2@@Z"
+// CHECK32: (%"struct.byval_thunk::C"* %this, <{ %"struct.byval_thunk::Agg" }>* inalloca)
+// CHECK32: getelementptr i8* %{{.*}}, i32 -4
+// CHECK32: musttail call x86_thiscallcc void @"\01?foo@C@byval_thunk@@UAEXUAgg@2@@Z"
+// CHECK32: (%"struct.byval_thunk::C"* %{{.*}}, <{ %"struct.byval_thunk::Agg" }>* inalloca %0)
+// CHECK32-NEXT: ret void
+
+// CHECK64-LABEL: define linkonce_odr void @"\01?foo@C@byval_thunk@@W7EAAXUAgg@2@@Z"
+// CHECK64: (%"struct.byval_thunk::C"* %this, %"struct.byval_thunk::Agg"* %x)
+// CHECK64: getelementptr i8* %{{.*}}, i32 -8
+// CHECK64: call void @"\01?foo@C@byval_thunk@@UEAAXUAgg@2@@Z"
+// CHECK64: (%"struct.byval_thunk::C"* %{{.*}}, %"struct.byval_thunk::Agg"* %x)
+// CHECK64-NOT: call
+// CHECK64: ret void
+}
+
+namespace stdcall_thunk {
+struct Agg {
+ Agg();
+ Agg(const Agg &);
+ ~Agg();
+ int x;
+};
+
+struct A { virtual void __stdcall foo(Agg x); };
+struct B { virtual void __stdcall foo(Agg x); };
+struct C : A, B { C(); virtual void __stdcall foo(Agg x); };
+C::C() {} // force emission
+
+// CHECK32-LABEL: define linkonce_odr x86_stdcallcc void @"\01?foo@C@stdcall_thunk@@W3AGXUAgg@2@@Z"
+// CHECK32: (<{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* inalloca)
+// CHECK32: %[[this_slot:[^ ]*]] = getelementptr inbounds <{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* %0, i32 0, i32 0
+// CHECK32: load %"struct.stdcall_thunk::C"** %[[this_slot]]
+// CHECK32: getelementptr i8* %{{.*}}, i32 -4
+// CHECK32: store %"struct.stdcall_thunk::C"* %{{.*}}, %"struct.stdcall_thunk::C"** %[[this_slot]]
+// CHECK32: musttail call x86_stdcallcc void @"\01?foo@C@stdcall_thunk@@UAGXUAgg@2@@Z"
+// CHECK32: (<{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* inalloca %0)
+// CHECK32-NEXT: ret void
+
+// CHECK64-LABEL: define linkonce_odr void @"\01?foo@C@stdcall_thunk@@W7EAAXUAgg@2@@Z"
+// CHECK64: (%"struct.stdcall_thunk::C"* %this, %"struct.stdcall_thunk::Agg"* %x)
+// CHECK64: getelementptr i8* %{{.*}}, i32 -8
+// CHECK64: call void @"\01?foo@C@stdcall_thunk@@UEAAXUAgg@2@@Z"
+// CHECK64: (%"struct.stdcall_thunk::C"* %{{.*}}, %"struct.stdcall_thunk::Agg"* %x)
+// CHECK64-NOT: call
+// CHECK64: ret void
+}
+
+namespace sret_thunk {
+struct Agg {
+ Agg();
+ Agg(const Agg &);
+ ~Agg();
+ int x;
+};
+
+struct A { virtual Agg __cdecl foo(Agg x); };
+struct B { virtual Agg __cdecl foo(Agg x); };
+struct C : A, B { C(); virtual Agg __cdecl foo(Agg x); };
+C::C() {} // force emission
+
+// CHECK32-LABEL: define linkonce_odr %"struct.sret_thunk::Agg"* @"\01?foo@C@sret_thunk@@W3AA?AUAgg@2@U32@@Z"
+// CHECK32: (<{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* inalloca)
+// CHECK32: %[[this_slot:[^ ]*]] = getelementptr inbounds <{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* %0, i32 0, i32 0
+// CHECK32: load %"struct.sret_thunk::C"** %[[this_slot]]
+// CHECK32: getelementptr i8* %{{.*}}, i32 -4
+// CHECK32: store %"struct.sret_thunk::C"* %{{.*}}, %"struct.sret_thunk::C"** %[[this_slot]]
+// CHECK32: %[[rv:[^ ]*]] = musttail call %"struct.sret_thunk::Agg"* @"\01?foo@C@sret_thunk@@UAA?AUAgg@2@U32@@Z"
+// CHECK32: (<{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* inalloca %0)
+// CHECK32-NEXT: ret %"struct.sret_thunk::Agg"* %[[rv]]
+
+// CHECK64-LABEL: define linkonce_odr void @"\01?foo@C@sret_thunk@@W7EAA?AUAgg@2@U32@@Z"
+// CHECK64: (%"struct.sret_thunk::C"* %this, %"struct.sret_thunk::Agg"* noalias sret %agg.result, %"struct.sret_thunk::Agg"* %x)
+// CHECK64: getelementptr i8* %{{.*}}, i32 -8
+// CHECK64: call void @"\01?foo@C@sret_thunk@@UEAA?AUAgg@2@U32@@Z"
+// CHECK64: (%"struct.sret_thunk::C"* %{{.*}}, %"struct.sret_thunk::Agg"* sret %agg.result, %"struct.sret_thunk::Agg"* %x)
+// CHECK64-NOT: call
+// CHECK64: ret void
+}
+
+#if 0
+// FIXME: When we extend LLVM IR to allow forwarding of varargs through musttail
+// calls, use this test.
+namespace variadic_thunk {
+struct Agg {
+ Agg();
+ Agg(const Agg &);
+ ~Agg();
+ int x;
+};
+
+struct A { virtual void foo(Agg x, ...); };
+struct B { virtual void foo(Agg x, ...); };
+struct C : A, B { C(); virtual void foo(Agg x, ...); };
+C::C() {} // force emission
+}
+#endif
diff --git a/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp b/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
index 225407b7fa9c..f2e9da7cca1f 100644
--- a/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
+++ b/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
@@ -20,11 +20,10 @@ T* test1(V* x) { return &dynamic_cast<T&>(*x); }
T* test2(A* x) { return &dynamic_cast<T&>(*x); }
// CHECK-LABEL: define %struct.T* @"\01?test2@@YAPAUT@@PAUA@@@Z"(%struct.A* %x)
// CHECK: [[CAST:%.*]] = bitcast %struct.A* %x to i8*
-// CHECK-NEXT: [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**
-// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
-// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
-// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
-// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST]], align 4
+// CHECK-NEXT: [[VBPTRPTR:%.*]] = getelementptr inbounds %struct.A* %x, i32 0, i32 0
+// CHECK-NEXT: [[VBTBL:%.*]] = load i32** [[VBPTRPTR]], align 4
+// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i32* [[VBTBL]], i32 1
+// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFP]], align 4
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32 [[VBOFFS]]
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[VBOFFS]], i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUT@@@8" to i8*), i32 1)
// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*
@@ -34,11 +33,10 @@ T* test3(B* x) { return &dynamic_cast<T&>(*x); }
// CHECK-LABEL: define %struct.T* @"\01?test3@@YAPAUT@@PAUB@@@Z"(%struct.B* %x)
// CHECK: [[VOIDP:%.*]] = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
// CHECK-NEXT: [[VBPTR:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 4
-// CHECK-NEXT: [[BITCAST:%.*]] = bitcast i8* [[VBPTR:%.*]] to i8**
-// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
-// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
-// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
-// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST]], align 4
+// CHECK-NEXT: [[VBPTRPTR:%.*]] = bitcast i8* [[VBPTR:%.*]] to i32**
+// CHECK-NEXT: [[VBTBL:%.*]] = load i32** [[VBPTRPTR]], align 4
+// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i32* [[VBTBL]], i32 1
+// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFP]], align 4
// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 [[DELTA]]
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[DELTA]], i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUT@@@8" to i8*), i32 1)
@@ -57,11 +55,10 @@ T* test5(A* x) { return dynamic_cast<T*>(x); }
// CHECK: [[CHECK:%.*]] = icmp eq %struct.A* %x, null
// CHECK-NEXT: br i1 [[CHECK]]
// CHECK: [[VOIDP:%.*]] = bitcast %struct.A* %x to i8*
-// CHECK-NEXT: [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**
-// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
-// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
-// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
-// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
+// CHECK-NEXT: [[VBPTRPTR:%.*]] = getelementptr inbounds %struct.A* %x, i32 0, i32 0
+// CHECK-NEXT: [[VBTBL:%.*]] = load i32** [[VBPTRPTR]], align 4
+// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i32* [[VBTBL]], i32 1
+// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFP]], align 4
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 [[VBOFFS]]
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[VBOFFS]], i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUT@@@8" to i8*), i32 0)
// CHECK-NEXT: [[RES:%.*]] = bitcast i8* [[CALL]] to %struct.T*
@@ -75,11 +72,10 @@ T* test6(B* x) { return dynamic_cast<T*>(x); }
// CHECK-NEXT: br i1 [[CHECK]]
// CHECK: [[CAST:%.*]] = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
// CHECK-NEXT: [[VBPTR:%.*]] = getelementptr inbounds i8* [[CAST]], i32 4
-// CHECK-NEXT: [[BITCAST:%.*]] = bitcast i8* [[VBPTR]] to i8**
-// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
-// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
-// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
-// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
+// CHECK-NEXT: [[VBPTRPTR:%.*]] = bitcast i8* [[VBPTR]] to i32**
+// CHECK-NEXT: [[VBTBL:%.*]] = load i32** [[VBPTRPTR]], align 4
+// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i32* [[VBTBL]], i32 1
+// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFP]], align 4
// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32 [[DELTA]]
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[DELTA]], i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUT@@@8" to i8*), i32 0)
@@ -99,11 +95,10 @@ void* test8(A* x) { return dynamic_cast<void*>(x); }
// CHECK: [[CHECK:%.*]] = icmp eq %struct.A* %x, null
// CHECK-NEXT: br i1 [[CHECK]]
// CHECK: [[VOIDP:%.*]] = bitcast %struct.A* %x to i8*
-// CHECK-NEXT: [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**
-// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
-// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
-// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
-// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
+// CHECK-NEXT: [[VBPTRPTR:%.*]] = getelementptr inbounds %struct.A* %x, i32 0, i32 0
+// CHECK-NEXT: [[VBTBL:%.*]] = load i32** [[VBPTRPTR]], align 4
+// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i32* [[VBTBL]], i32 1
+// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFP]], align 4
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 [[VBOFFS]]
// CHECK-NEXT: [[RES:%.*]] = tail call i8* @__RTCastToVoid(i8* [[ADJ]])
// CHECK-NEXT: br label
@@ -116,11 +111,10 @@ void* test9(B* x) { return dynamic_cast<void*>(x); }
// CHECK-NEXT: br i1 [[CHECK]]
// CHECK: [[CAST:%.*]] = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
// CHECK-NEXT: [[VBPTR:%.*]] = getelementptr inbounds i8* [[CAST]], i32 4
-// CHECK-NEXT: [[BITCAST:%.*]] = bitcast i8* [[VBPTR]] to i8**
-// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
-// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
-// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
-// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
+// CHECK-NEXT: [[VBPTRPTR:%.*]] = bitcast i8* [[VBPTR]] to i32**
+// CHECK-NEXT: [[VBTBL:%.*]] = load i32** [[VBPTRPTR]], align 4
+// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i32* [[VBTBL]], i32 1
+// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFP]], align 4
// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32 [[DELTA]]
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTCastToVoid(i8* [[ADJ]])
diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
index 18e8c827eebe..719cb70679f4 100755
--- a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -1,9 +1,29 @@
-// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck %s
-// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 -fms-extensions | FileCheck %s -check-prefix=X64
-// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -fms-extensions -verify
-// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -DMEMFUN -fms-extensions -verify
-// FIXME: Test x86_64 member pointers when codegen no longer asserts on records
-// with virtual bases.
+// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 -fms-extensions | FileCheck %s -check-prefix=X64
+// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -fms-extensions -verify
+// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -DMEMFUN -fms-extensions -verify
+
+namespace PR20947 {
+struct A;
+int A::**a = nullptr;
+// CHECK: %[[opaque0:.*]] = type opaque
+// CHECK: %[[opaque1:.*]] = type opaque
+// CHECK: @"\01?a@PR20947@@3PAPQA@1@HA" = global %[[opaque0]]* null, align 4
+
+struct B;
+int B::*&b = b;
+// CHECK: @"\01?b@PR20947@@3AAPQB@1@HA" = global %[[opaque1]]* null, align 4
+}
+
+namespace PR20017 {
+template <typename T>
+struct A {
+ int T::*m_fn1() { return nullptr; }
+};
+struct B;
+auto a = &A<B>::m_fn1;
+// CHECK-DAG: @"\01?a@PR20017@@3P8?$A@UB@PR20017@@@1@AEPQB@1@HXZQ21@" = global i8* bitcast ({ i32, i32, i32 } ({{.*}}*)* @"\01?m_fn1@?$A@UB@PR20017@@@PR20017@@QAEPQB@2@HXZ" to i8*), align 4
+}
#ifndef INCOMPLETE_VIRTUAL
struct B1 {
@@ -265,11 +285,11 @@ int loadDataMemberPointerVirtual(Virtual *o, int Virtual::*memptr) {
// CHECK: %[[memptr1:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 1
// CHECK: %[[v6:.*]] = bitcast %{{.*}}* %[[o]] to i8*
// CHECK: %[[vbptr:.*]] = getelementptr inbounds i8* %[[v6]], i32 0
-// CHECK: %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8**
-// CHECK: %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]]
-// CHECK: %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr1]]
-// CHECK: %[[v8:.*]] = bitcast i8* %[[v7]] to i32*
-// CHECK: %[[vbase_offs:.*]] = load i32* %[[v8]]
+// CHECK: %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i32**
+// CHECK: %[[vbtable:.*]] = load i32** %[[vbptr_a:.*]]
+// CHECK: %[[memptr1_shr:.*]] = ashr exact i32 %[[memptr1]], 2
+// CHECK: %[[v7:.*]] = getelementptr inbounds i32* %[[vbtable]], i32 %[[memptr1_shr]]
+// CHECK: %[[vbase_offs:.*]] = load i32* %[[v7]]
// CHECK: %[[v10:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]]
// CHECK: %[[offset:.*]] = getelementptr inbounds i8* %[[v10]], i32 %[[memptr0]]
// CHECK: %[[v11:.*]] = bitcast i8* %[[offset]] to i32*
@@ -299,11 +319,11 @@ int loadDataMemberPointerUnspecified(Unspecified *o, int Unspecified::*memptr) {
//
// CHECK: [[vadjust]]
// CHECK: %[[vbptr:.*]] = getelementptr inbounds i8* %[[base]], i32 %[[memptr1]]
-// CHECK: %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8**
-// CHECK: %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]]
-// CHECK: %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr2]]
-// CHECK: %[[v8:.*]] = bitcast i8* %[[v7]] to i32*
-// CHECK: %[[vbase_offs:.*]] = load i32* %[[v8]]
+// CHECK: %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i32**
+// CHECK: %[[vbtable:.*]] = load i32** %[[vbptr_a:.*]]
+// CHECK: %[[memptr2_shr:.*]] = ashr exact i32 %[[memptr2]], 2
+// CHECK: %[[v7:.*]] = getelementptr inbounds i32* %[[vbtable]], i32 %[[memptr2_shr]]
+// CHECK: %[[vbase_offs:.*]] = load i32* %[[v7]]
// CHECK: %[[base_adj:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]]
//
// CHECK: [[skip]]
@@ -350,11 +370,11 @@ void callMemberPointerVirtualBase(Virtual *o, void (Virtual::*memptr)()) {
// CHECK: %[[memptr1:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 1
// CHECK: %[[memptr2:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 2
// CHECK: %[[vbptr:.*]] = getelementptr inbounds i8* %{{.*}}, i32 0
-// CHECK: %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8**
-// CHECK: %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]]
-// CHECK: %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr2]]
-// CHECK: %[[v8:.*]] = bitcast i8* %[[v7]] to i32*
-// CHECK: %[[vbase_offs:.*]] = load i32* %[[v8]]
+// CHECK: %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i32**
+// CHECK: %[[vbtable:.*]] = load i32** %[[vbptr_a:.*]]
+// CHECK: %[[memptr2_shr:.*]] = ashr exact i32 %[[memptr2]], 2
+// CHECK: %[[v7:.*]] = getelementptr inbounds i32* %[[vbtable]], i32 %[[memptr2_shr]]
+// CHECK: %[[vbase_offs:.*]] = load i32* %[[v7]]
// CHECK: %[[v10:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]]
// CHECK: %[[this_adjusted:.*]] = getelementptr inbounds i8* %[[v10]], i32 %[[memptr1]]
// CHECK: %[[fptr:.*]] = bitcast i8* %[[memptr0]] to void ({{.*}})
@@ -595,15 +615,15 @@ void (C::*getmp())() {
return &C::g;
}
// CHECK-LABEL: define i64 @"\01?getmp@Test4@@YAP8C@1@AEXXZXZ"()
-// CHECK: store { i8*, i32 } { i8* bitcast (void (i8*)* @"\01??_9C@Test4@@$BA@AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}
+// CHECK: store { i8*, i32 } { i8* bitcast (void (%"struct.Test4::C"*, ...)* @"\01??_9C@Test4@@$BA@AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}
//
-// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@Test4@@$BA@AE"(i8*)
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@Test4@@$BA@AE"(%"struct.Test4::C"* %this, ...)
// CHECK-NOT: getelementptr
-// CHECK: load void (i8*)*** %{{.*}}
-// CHECK: getelementptr inbounds void (i8*)** %{{.*}}, i64 0
+// CHECK: load void (%"struct.Test4::C"*, ...)*** %{{.*}}
+// CHECK: getelementptr inbounds void (%"struct.Test4::C"*, ...)** %{{.*}}, i64 0
// CHECK-NOT: getelementptr
-// CHECK: call x86_thiscallcc void %
+// CHECK: musttail call x86_thiscallcc void (%"struct.Test4::C"*, ...)* %
}
@@ -630,6 +650,34 @@ void test() { void (B::*a)() = &B::f; }
// CHECK: store i8* bitcast (void (%"struct.pr20007_kw::A"*)* @"\01?f@A@pr20007_kw@@QAEXXZ" to i8*)
}
+namespace pr20007_pragma {
+struct A {
+ void f();
+ void f(int);
+};
+struct B : public A {};
+void test() { (void)(void (B::*)()) &B::f; }
+#pragma pointers_to_members(full_generality, virtual_inheritance)
+static_assert(sizeof(int B::*) == 4, "");
+static_assert(sizeof(int A::*) == 4, "");
+#pragma pointers_to_members(best_case)
+// CHECK-LABEL: define void @"\01?test@pr20007_pragma@@YAXXZ"
+}
+
+namespace pr20007_pragma2 {
+struct A {
+};
+struct B : public A {
+ void f();
+};
+void test() { (void)&B::f; }
+#pragma pointers_to_members(full_generality, virtual_inheritance)
+static_assert(sizeof(int B::*) == 4, "");
+static_assert(sizeof(int A::*) == 12, "");
+#pragma pointers_to_members(best_case)
+// CHECK-LABEL: define void @"\01?test@pr20007_pragma2@@YAXXZ"
+}
+
namespace pr19987 {
template <typename T>
struct S {
diff --git a/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp
index b1c1482eff6f..b5293e0d7989 100644
--- a/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp
@@ -150,35 +150,35 @@ void emit_ctors() {
Left l;
// CHECK: define {{.*}} @"\01??0Left@@QAE@XZ"
// CHECK-NOT: getelementptr
- // CHECK: store [1 x i8*]* @"\01??_7Left@@6B@"
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7Left@@6B@" to i32 (...)**)
// CHECK: ret
Right r;
// CHECK: define {{.*}} @"\01??0Right@@QAE@XZ"
// CHECK-NOT: getelementptr
- // CHECK: store [1 x i8*]* @"\01??_7Right@@6B@"
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7Right@@6B@" to i32 (...)**)
// CHECK: ret
ChildOverride co;
// CHECK: define {{.*}} @"\01??0ChildOverride@@QAE@XZ"
// CHECK: %[[THIS:.*]] = load %struct.ChildOverride**
- // CHECK: %[[VFPTR:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to [1 x i8*]**
- // CHECK: store [1 x i8*]* @"\01??_7ChildOverride@@6BLeft@@@", [1 x i8*]** %[[VFPTR]]
+ // CHECK: %[[VFPTR:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i32 (...)***
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7ChildOverride@@6BLeft@@@" to i32 (...)**), i32 (...)*** %[[VFPTR]]
// CHECK: %[[THIS_i8:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8*
// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 4
- // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [1 x i8*]**
- // CHECK: store [1 x i8*]* @"\01??_7ChildOverride@@6BRight@@@", [1 x i8*]** %[[VFPTR]]
+ // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to i32 (...)***
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7ChildOverride@@6BRight@@@" to i32 (...)**), i32 (...)*** %[[VFPTR]]
// CHECK: ret
GrandchildOverride gc;
// CHECK: define {{.*}} @"\01??0GrandchildOverride@@QAE@XZ"
// CHECK: %[[THIS:.*]] = load %struct.GrandchildOverride**
- // CHECK: %[[VFPTR:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to [1 x i8*]**
- // CHECK: store [1 x i8*]* @"\01??_7GrandchildOverride@@6BLeft@@@", [1 x i8*]** %[[VFPTR]]
+ // CHECK: %[[VFPTR:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to i32 (...)***
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7GrandchildOverride@@6BLeft@@@" to i32 (...)**), i32 (...)*** %[[VFPTR]]
// CHECK: %[[THIS_i8:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to i8*
// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 4
- // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [1 x i8*]**
- // CHECK: store [1 x i8*]* @"\01??_7GrandchildOverride@@6BRight@@@", [1 x i8*]** %[[VFPTR]]
+ // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to i32 (...)***
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7GrandchildOverride@@6BRight@@@" to i32 (...)**), i32 (...)*** %[[VFPTR]]
// CHECK: ret
}
diff --git a/test/CodeGenCXX/microsoft-abi-nontrivial-covariant-thunk.cpp b/test/CodeGenCXX/microsoft-abi-nontrivial-covariant-thunk.cpp
index d305dd83271f..cb8b5224d65b 100644
--- a/test/CodeGenCXX/microsoft-abi-nontrivial-covariant-thunk.cpp
+++ b/test/CodeGenCXX/microsoft-abi-nontrivial-covariant-thunk.cpp
@@ -18,7 +18,7 @@ struct B {
struct C : A, B {
C();
int c;
- virtual C *clone(A); // expected-error {{cannot compile this non-trivial argument copy for thunk yet}}
+ virtual C *clone(A); // expected-error {{cannot compile this non-trivial argument copy for return-adjusting thunk yet}}
};
B::B() {} // force emission
C::C() {} // force emission
diff --git a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
index 5f74c54c1c45..76d7e9e19192 100644
--- a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
@@ -1,9 +1,12 @@
// RUN: %clang_cc1 -fms-extensions -emit-llvm %s -o - -mconstructor-aliases -triple=i386-pc-win32 | FileCheck %s
-// CHECK: @llvm.global_ctors = appending global [2 x { i32, void ()*, i8* }]
-// CHECK: [{ i32, void ()*, i8* } { i32 65535, void ()* @"\01??__Efoo@?$B@H@@2VA@@A@YAXXZ",
-// CHECK: i8* bitcast (%class.A* @"\01?foo@?$B@H@@2VA@@A" to i8*) },
-// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp, i8* null }]
+// CHECK: @llvm.global_ctors = appending global [5 x { i32, void ()*, i8* }] [
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"\01??__Eselectany1@@YAXXZ", i8* getelementptr inbounds (%struct.S* @"\01?selectany1@@3US@@A", i32 0, i32 0) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"\01??__Eselectany2@@YAXXZ", i8* getelementptr inbounds (%struct.S* @"\01?selectany2@@3US@@A", i32 0, i32 0) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"\01??__Es@?$ExportedTemplate@H@@2US@@A@YAXXZ", i8* getelementptr inbounds (%struct.S* @"\01?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"\01??__Efoo@?$B@H@@2VA@@A@YAXXZ", i8* bitcast (%class.A* @"\01?foo@?$B@H@@2VA@@A" to i8*) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp, i8* null }
+// CHECK: ]
struct S {
S();
@@ -21,8 +24,8 @@ S s;
// CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ"
// CHECK: ret void
-// These globals should use distinct guard variables, and not different bits of
-// the same global.
+// These globals should have initializers comdat associative with the global.
+// See @llvm.global_ctors above.
__declspec(selectany) S selectany1;
__declspec(selectany) S selectany2;
// CHECK: define linkonce_odr void @"\01??__Eselectany1@@YAXXZ"()
@@ -34,12 +37,23 @@ __declspec(selectany) S selectany2;
// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"
// CHECK: ret void
+// The implicitly instantiated static data member should have initializer
+// comdat associative with the global.
+template <typename T> struct __declspec(dllexport) ExportedTemplate {
+ static S s;
+};
+template <typename T> S ExportedTemplate<T>::s;
+void useExportedTemplate(ExportedTemplate<int> x) {
+ (void)x.s;
+}
+
void StaticLocal() {
static S TheS;
}
+
// CHECK-LABEL: define void @"\01?StaticLocal@@YAXXZ"()
-// CHECK: load i32* @"\01?$S1@?0??StaticLocal@@YAXXZ@4IA"
-// CHECK: store i32 {{.*}}, i32* @"\01?$S1@?0??StaticLocal@@YAXXZ@4IA"
+// CHECK: load i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA"
+// CHECK: store i32 {{.*}}, i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA"
// CHECK: ret
void MultipleStatics() {
@@ -80,7 +94,7 @@ void MultipleStatics() {
static S S35;
}
// CHECK-LABEL: define void @"\01?MultipleStatics@@YAXXZ"()
-// CHECK: load i32* @"\01?$S1@?0??MultipleStatics@@YAXXZ@4IA"
+// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA"
// CHECK: and i32 {{.*}}, 1
// CHECK: and i32 {{.*}}, 2
// CHECK: and i32 {{.*}}, 4
@@ -88,7 +102,7 @@ void MultipleStatics() {
// CHECK: and i32 {{.*}}, 16
// ...
// CHECK: and i32 {{.*}}, -2147483648
-// CHECK: load i32* @"\01?$S1@?0??MultipleStatics@@YAXXZ@4IA1"
+// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA1"
// CHECK: and i32 {{.*}}, 1
// CHECK: and i32 {{.*}}, 2
// CHECK: and i32 {{.*}}, 4
diff --git a/test/CodeGenCXX/microsoft-abi-structors-delayed-template.cpp b/test/CodeGenCXX/microsoft-abi-structors-delayed-template.cpp
new file mode 100644
index 000000000000..f9e188033ca4
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-structors-delayed-template.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -fdelayed-template-parsing -std=c++11 -o - -triple=i386-pc-win32 %s > %t
+// RUN: FileCheck %s < %t
+
+// PR20671
+namespace vtable_referenced_from_template {
+struct ImplicitCtor {
+ virtual ~ImplicitCtor();
+};
+template <class T> void foo(T t) { new ImplicitCtor; }
+void bar() { foo(0); }
+// CHECK: store {{.*}} @"\01??_7ImplicitCtor@vtable_referenced_from_template@@6B@"
+}
diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp
index 7d3992b9940b..01d72e0aed57 100644
--- a/test/CodeGenCXX/microsoft-abi-structors.cpp
+++ b/test/CodeGenCXX/microsoft-abi-structors.cpp
@@ -46,8 +46,9 @@ B::B() {
struct C {
virtual ~C() {
-// DTORS: define linkonce_odr x86_thiscallcc void @"\01??_GC@basic@@UAEPAXI@Z"(%"struct.basic::C"* %this, i32 %should_call_delete)
+// DTORS: define linkonce_odr x86_thiscallcc i8* @"\01??_GC@basic@@UAEPAXI@Z"(%"struct.basic::C"* %this, i32 %should_call_delete)
// DTORS: store i32 %should_call_delete, i32* %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 4
+// DTORS: store i8* %{{.*}}, i8** %[[RETVAL:[0-9a-z._]+]]
// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32* %[[SHOULD_DELETE_VAR]]
// DTORS: call x86_thiscallcc void @"\01??1C@basic@@UAE@XZ"(%"struct.basic::C"* %[[THIS:[0-9a-z]+]])
// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i32 %[[SHOULD_DELETE_VALUE]], 0
@@ -59,7 +60,8 @@ struct C {
// DTORS-NEXT: br label %[[CONTINUE_LABEL]]
//
// DTORS: [[CONTINUE_LABEL]]
-// DTORS-NEXT: ret void
+// DTORS-NEXT: %[[RET:.*]] = load i8** %[[RETVAL]]
+// DTORS-NEXT: ret i8* %[[RET]]
// Check that we do the mangling correctly on x64.
// DTORS-X64: @"\01??_GC@basic@@UEAAPEAXI@Z"
@@ -73,19 +75,19 @@ void C::foo() {}
void check_vftable_offset() {
C c;
// The vftable pointer should point at the beginning of the vftable.
-// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %"struct.basic::C"* {{.*}} to [2 x i8*]**
-// CHECK: store [2 x i8*]* @"\01??_7C@basic@@6B@", [2 x i8*]** [[THIS_PTR]]
+// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %"struct.basic::C"* {{.*}} to i32 (...)***
+// CHECK: store i32 (...)** bitcast ([2 x i8*]* @"\01??_7C@basic@@6B@" to i32 (...)**), i32 (...)*** [[THIS_PTR]]
}
void call_complete_dtor(C *obj_ptr) {
// CHECK: define void @"\01?call_complete_dtor@basic@@YAXPAUC@1@@Z"(%"struct.basic::C"* %obj_ptr)
obj_ptr->~C();
// CHECK: %[[OBJ_PTR_VALUE:.*]] = load %"struct.basic::C"** %{{.*}}, align 4
-// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i32)***
-// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
-// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
-// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i32)** %[[PVDTOR]]
-// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 0)
+// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to i8* (%"struct.basic::C"*, i32)***
+// CHECK-NEXT: %[[VTABLE:.*]] = load i8* (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
+// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds i8* (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
+// CHECK-NEXT: %[[VDTOR:.*]] = load i8* (%"struct.basic::C"*, i32)** %[[PVDTOR]]
+// CHECK-NEXT: call x86_thiscallcc i8* %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 0)
// CHECK-NEXT: ret void
}
@@ -96,11 +98,27 @@ void call_deleting_dtor(C *obj_ptr) {
// CHECK: br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]
// CHECK: [[DELETE_NOTNULL]]
-// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i32)***
-// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
-// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
-// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i32)** %[[PVDTOR]]
-// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 1)
+// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to i8* (%"struct.basic::C"*, i32)***
+// CHECK-NEXT: %[[VTABLE:.*]] = load i8* (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
+// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds i8* (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
+// CHECK-NEXT: %[[VDTOR:.*]] = load i8* (%"struct.basic::C"*, i32)** %[[PVDTOR]]
+// CHECK-NEXT: call x86_thiscallcc i8* %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 1)
+// CHECK: ret void
+}
+
+void call_deleting_dtor_and_global_delete(C *obj_ptr) {
+// CHECK: define void @"\01?call_deleting_dtor_and_global_delete@basic@@YAXPAUC@1@@Z"(%"struct.basic::C"* %obj_ptr)
+ ::delete obj_ptr;
+// CHECK: %[[OBJ_PTR_VALUE:.*]] = load %"struct.basic::C"** %{{.*}}, align 4
+// CHECK: br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]
+
+// CHECK: [[DELETE_NOTNULL]]
+// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to i8* (%"struct.basic::C"*, i32)***
+// CHECK-NEXT: %[[VTABLE:.*]] = load i8* (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
+// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds i8* (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
+// CHECK-NEXT: %[[VDTOR:.*]] = load i8* (%"struct.basic::C"*, i32)** %[[PVDTOR]]
+// CHECK-NEXT: %[[CALL:.*]] = call x86_thiscallcc i8* %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 0)
+// CHECK-NEXT: call void @"\01??3@YAXPAX@Z"(i8* %[[CALL]])
// CHECK: ret void
}
@@ -153,13 +171,13 @@ C::~C() {
void foo() {
C c;
}
-// DTORS2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_EC@dtor_in_second_nvbase@@W3AEPAXI@Z"
+// DTORS2-LABEL: define linkonce_odr x86_thiscallcc i8* @"\01??_EC@dtor_in_second_nvbase@@W3AEPAXI@Z"
// DTORS2: (%"struct.dtor_in_second_nvbase::C"* %this, i32 %should_call_delete)
// Do an adjustment from B* to C*.
// DTORS2: getelementptr i8* %{{.*}}, i32 -4
// DTORS2: bitcast i8* %{{.*}} to %"struct.dtor_in_second_nvbase::C"*
-// DTORS2: call x86_thiscallcc void @"\01??_GC@dtor_in_second_nvbase@@UAEPAXI@Z"
-// DTORS2: ret void
+// DTORS2: %[[CALL:.*]] = call x86_thiscallcc i8* @"\01??_GC@dtor_in_second_nvbase@@UAEPAXI@Z"
+// DTORS2: ret i8* %[[CALL]]
}
@@ -229,8 +247,8 @@ C::C() {
// CHECK: [[INIT_VBASES]]
// CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::C"* %{{.*}} to i8*
// CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
- // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to [2 x i32]**
- // CHECK-NEXT: store [2 x i32]* @"\01??_8C@constructors@@7B@", [2 x i32]** %[[vbptr]]
+ // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i32**
+ // CHECK-NEXT: store i32* getelementptr inbounds ([2 x i32]* @"\01??_8C@constructors@@7B@", i32 0, i32 0), i32** %[[vbptr]]
// CHECK-NEXT: bitcast %"struct.constructors::C"* %{{.*}} to i8*
// CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4
// CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"*
@@ -264,8 +282,8 @@ D::D() {
// CHECK: [[INIT_VBASES]]
// CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::D"* %{{.*}} to i8*
// CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
- // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to [2 x i32]**
- // CHECK-NEXT: store [2 x i32]* @"\01??_8D@constructors@@7B@", [2 x i32]** %[[vbptr]]
+ // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i32**
+ // CHECK-NEXT: store i32* getelementptr inbounds ([2 x i32]* @"\01??_8D@constructors@@7B@", i32 0, i32 0), i32** %[[vbptr]]
// CHECK-NEXT: bitcast %"struct.constructors::D"* %{{.*}} to i8*
// CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4
// CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"*
@@ -291,11 +309,11 @@ E::E() {
// CHECK: [[INIT_VBASES]]
// CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::E"* %{{.*}} to i8*
// CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
- // CHECK-NEXT: %[[vbptr_E:.*]] = bitcast i8* %[[offs]] to [3 x i32]**
- // CHECK-NEXT: store [3 x i32]* @"\01??_8E@constructors@@7B01@@", [3 x i32]** %[[vbptr_E]]
+ // CHECK-NEXT: %[[vbptr_E:.*]] = bitcast i8* %[[offs]] to i32**
+ // CHECK-NEXT: store i32* getelementptr inbounds ([3 x i32]* @"\01??_8E@constructors@@7B01@@", i32 0, i32 0), i32** %[[vbptr_E]]
// CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 4
- // CHECK-NEXT: %[[vbptr_C:.*]] = bitcast i8* %[[offs]] to [2 x i32]**
- // CHECK-NEXT: store [2 x i32]* @"\01??_8E@constructors@@7BC@1@@", [2 x i32]** %[[vbptr_C]]
+ // CHECK-NEXT: %[[vbptr_C:.*]] = bitcast i8* %[[offs]] to i32**
+ // CHECK-NEXT: store i32* getelementptr inbounds ([2 x i32]* @"\01??_8E@constructors@@7BC@1@@", i32 0, i32 0), i32** %[[vbptr_C]]
// CHECK-NEXT: bitcast %"struct.constructors::E"* %{{.*}} to i8*
// CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4
// CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"*
@@ -436,7 +454,7 @@ struct A {
void *getA() {
return (void*)new A();
}
-// CHECK: define internal x86_thiscallcc void @"\01??_GA@?A@@UAEPAXI@Z"
+// CHECK: define internal x86_thiscallcc i8* @"\01??_GA@?A@@UAEPAXI@Z"
// CHECK: (%"struct.(anonymous namespace)::A"* %this, i32 %should_call_delete)
// CHECK: define internal x86_thiscallcc void @"\01??1A@?A@@UAE@XZ"
// CHECK: (%"struct.(anonymous namespace)::A"* %this)
diff --git a/test/CodeGenCXX/microsoft-abi-thunks.cpp b/test/CodeGenCXX/microsoft-abi-thunks.cpp
index c755b300067d..843bc89b0d0d 100644
--- a/test/CodeGenCXX/microsoft-abi-thunks.cpp
+++ b/test/CodeGenCXX/microsoft-abi-thunks.cpp
@@ -61,10 +61,10 @@ struct C : A, B {
C::C() {} // Emits vftable and forces thunk generation.
-// CODEGEN-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete)
+// CODEGEN-LABEL: define linkonce_odr x86_thiscallcc i8* @"\01??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete)
// CODEGEN: getelementptr i8* {{.*}}, i32 -4
// FIXME: should actually call _EC, not _GC.
-// CODEGEN: call x86_thiscallcc void @"\01??_GC@@UAEPAXI@Z"
+// CODEGEN: call x86_thiscallcc i8* @"\01??_GC@@UAEPAXI@Z"
// CODEGEN: ret
// CODEGEN-LABEL: define linkonce_odr x86_thiscallcc void @"\01?public_f@C@@W3AEXXZ"(%struct.C*
@@ -128,10 +128,9 @@ I::I() {} // Emits vftable and forces thunk generation.
// CODEGEN: %[[ORIG_RET:.*]] = call x86_thiscallcc %struct.F* @"\01?goo@I@@UAEPAUF@@XZ"
// CODEGEN: %[[ORIG_RET_i8:.*]] = bitcast %struct.F* %[[ORIG_RET]] to i8*
// CODEGEN: %[[VBPTR_i8:.*]] = getelementptr inbounds i8* %[[ORIG_RET_i8]], i32 4
-// CODEGEN: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i8**
-// CODEGEN: %[[VBTABLE:.*]] = load i8** %[[VBPTR]]
-// CODEGEN: %[[VBASE_OFFSET_PTR_i8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 8
-// CODEGEN: %[[VBASE_OFFSET_PTR:.*]] = bitcast i8* %[[VBASE_OFFSET_PTR_i8]] to i32*
+// CODEGEN: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i32**
+// CODEGEN: %[[VBTABLE:.*]] = load i32** %[[VBPTR]]
+// CODEGEN: %[[VBASE_OFFSET_PTR:.*]] = getelementptr inbounds i32* %[[VBTABLE]], i32 2
// CODEGEN: %[[VBASE_OFFSET:.*]] = load i32* %[[VBASE_OFFSET_PTR]]
// CODEGEN: %[[RES_i8:.*]] = getelementptr inbounds i8* %[[VBPTR_i8]], i32 %[[VBASE_OFFSET]]
// CODEGEN: %[[RES:.*]] = bitcast i8* %[[RES_i8]] to %struct.F*
diff --git a/test/CodeGenCXX/microsoft-abi-typeid.cpp b/test/CodeGenCXX/microsoft-abi-typeid.cpp
index 4ee004d51d21..1beb2118126a 100644
--- a/test/CodeGenCXX/microsoft-abi-typeid.cpp
+++ b/test/CodeGenCXX/microsoft-abi-typeid.cpp
@@ -31,11 +31,10 @@ const std::type_info* test3_typeid() { return &typeid(*fn()); }
// CHECK: tail call i8* @__RTtypeid(i8* null)
// CHECK-NEXT: unreachable
// CHECK: [[THIS:%.*]] = bitcast %struct.A* [[CALL]] to i8*
-// CHECK-NEXT: [[VBTBLP:%.*]] = bitcast %struct.A* [[CALL]] to i8**
-// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[VBTBLP]], align 4
-// CHECK-NEXT: [[VBSLOT:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
-// CHECK-NEXT: [[VBITCST:%.*]] = bitcast i8* [[VBSLOT]] to i32*
-// CHECK-NEXT: [[VBASE_OFFS:%.*]] = load i32* [[VBITCST]], align 4
+// CHECK-NEXT: [[VBTBLP:%.*]] = getelementptr inbounds %struct.A* [[CALL]], i32 0, i32 0
+// CHECK-NEXT: [[VBTBL:%.*]] = load i32** [[VBTBLP]], align 4
+// CHECK-NEXT: [[VBSLOT:%.*]] = getelementptr inbounds i32* [[VBTBL]], i32 1
+// CHECK-NEXT: [[VBASE_OFFS:%.*]] = load i32* [[VBSLOT]], align 4
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[THIS]], i32 [[VBASE_OFFS]]
// CHECK-NEXT: [[RT:%.*]] = tail call i8* @__RTtypeid(i8* [[ADJ]])
// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[RT]] to %struct.type_info*
diff --git a/test/CodeGenCXX/microsoft-abi-vftables.cpp b/test/CodeGenCXX/microsoft-abi-vftables.cpp
index 825aba010f12..14bd6c388b01 100644
--- a/test/CodeGenCXX/microsoft-abi-vftables.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vftables.cpp
@@ -9,7 +9,7 @@ struct S {
virtual ~S();
} s;
-// RTTI-DAG: [[VTABLE_S:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast ({{.*}} @"\01??_R4S@@6B@" to i8*), i8* bitcast ({{.*}} @"\01??_GS@@UAEPAXI@Z" to i8*)], comdat $"\01??_7S@@6B@"
+// RTTI-DAG: [[VTABLE_S:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast ({{.*}} @"\01??_R4S@@6B@" to i8*), i8* bitcast ({{.*}} @"\01??_GS@@UAEPAXI@Z" to i8*)], comdat($"\01??_7S@@6B@")
// RTTI-DAG: @"\01??_7S@@6B@" = unnamed_addr alias getelementptr inbounds ([2 x i8*]* [[VTABLE_S]], i32 0, i32 1)
// NO-RTTI-DAG: @"\01??_7S@@6B@" = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast ({{.*}} @"\01??_GS@@UAEPAXI@Z" to i8*)]
@@ -26,7 +26,7 @@ struct __declspec(dllexport) V {
virtual ~V();
} v;
-// RTTI-DAG: [[VTABLE_V:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast ({{.*}} @"\01??_R4V@@6B@" to i8*), i8* bitcast ({{.*}} @"\01??_GV@@UAEPAXI@Z" to i8*)], comdat $"\01??_7V@@6B@"
+// RTTI-DAG: [[VTABLE_V:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast ({{.*}} @"\01??_R4V@@6B@" to i8*), i8* bitcast ({{.*}} @"\01??_GV@@UAEPAXI@Z" to i8*)], comdat($"\01??_7V@@6B@")
// RTTI-DAG: @"\01??_7V@@6B@" = dllexport unnamed_addr alias getelementptr inbounds ([2 x i8*]* [[VTABLE_V]], i32 0, i32 1)
// NO-RTTI-DAG: @"\01??_7V@@6B@" = weak_odr dllexport unnamed_addr constant [1 x i8*] [i8* bitcast ({{.*}} @"\01??_GV@@UAEPAXI@Z" to i8*)]
@@ -36,7 +36,7 @@ struct W {
virtual ~W();
} w;
}
-// RTTI-DAG: [[VTABLE_W:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast ({{.*}} @"\01??_R4W@?A@@6B@" to i8*), i8* bitcast ({{.*}} @"\01??_GW@?A@@UAEPAXI@Z" to i8*)], comdat $"\01??_7W@?A@@6B@"
-// RTTI-DAG: @"\01??_7W@?A@@6B@" = unnamed_addr alias internal getelementptr inbounds ([2 x i8*]* @1, i32 0, i32 1)
+// RTTI-DAG: [[VTABLE_W:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast ({{.*}} @"\01??_R4W@?A@@6B@" to i8*), i8* bitcast ({{.*}} @"\01??_GW@?A@@UAEPAXI@Z" to i8*)], comdat($"\01??_7W@?A@@6B@")
+// RTTI-DAG: @"\01??_7W@?A@@6B@" = internal unnamed_addr alias getelementptr inbounds ([2 x i8*]* @1, i32 0, i32 1)
// NO-RTTI-DAG: @"\01??_7W@?A@@6B@" = internal unnamed_addr constant [1 x i8*] [i8* bitcast ({{.*}} @"\01??_GW@?A@@UAEPAXI@Z" to i8*)]
diff --git a/test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp b/test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp
index a6fcdea749ab..26eb01205cf6 100644
--- a/test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp
+++ b/test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp
@@ -72,10 +72,9 @@ G::G() {} // Forces vftable emission.
// CHECK: %[[VTORDISP_NEG:.*]] = sub i32 0, %[[VTORDISP]]
// CHECK: %[[VTORDISP_ADJUSTED_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 %[[VTORDISP_NEG]]
// CHECK: %[[VBPTR_i8:.*]] = getelementptr inbounds i8* %[[VTORDISP_ADJUSTED_i8]], i32 -16
-// CHECK: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i8**
-// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR]]
-// CHECK: %[[VBOFFSET_PTR_i8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 12
-// CHECK: %[[VBOFFSET_PTR:.*]] = bitcast i8* %[[VBOFFSET_PTR_i8]] to i32*
+// CHECK: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i32**
+// CHECK: %[[VBTABLE:.*]] = load i32** %[[VBPTR]]
+// CHECK: %[[VBOFFSET_PTR:.*]] = getelementptr inbounds i32* %[[VBTABLE]], i32 3
// CHECK: %[[VBASE_OFFSET:.*]] = load i32* %[[VBOFFSET_PTR]]
// CHECK: %[[VBASE:.*]] = getelementptr inbounds i8* %[[VBPTR_i8]], i32 %[[VBASE_OFFSET]]
// CHECK: %[[ARG_i8:.*]] = getelementptr i8* %[[VBASE]], i32 8
diff --git a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
index 2f0fffee696f..7a00a731f5fa 100644
--- a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
@@ -32,8 +32,8 @@ B::B() {
// ...
// CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %{{.*}}
- // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [3 x i8*]**
- // CHECK: store [3 x i8*]* @"\01??_7B@@6B@", [3 x i8*]** %[[VFPTR]]
+ // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to i32 (...)***
+ // CHECK: store i32 (...)** bitcast ([3 x i8*]* @"\01??_7B@@6B@" to i32 (...)**), i32 (...)*** %[[VFPTR]]
// Initialize vtorDisp:
// CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
@@ -65,8 +65,8 @@ B::~B() {
// ...
// CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %{{.*}}
- // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [3 x i8*]**
- // CHECK: store [3 x i8*]* @"\01??_7B@@6B@", [3 x i8*]** %[[VFPTR]]
+ // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to i32 (...)***
+ // CHECK: store i32 (...)** bitcast ([3 x i8*]* @"\01??_7B@@6B@" to i32 (...)**), i32 (...)*** %[[VFPTR]]
// Initialize vtorDisp:
// CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
@@ -96,7 +96,7 @@ B::~B() {
// CHECK2: call x86_thiscallcc void @"\01??1VBase@@UAE@XZ"(%struct.VBase* %[[VBASE]])
// CHECK2: ret
- // CHECK2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_GB@@UAEPAXI@Z"
+ // CHECK2-LABEL: define linkonce_odr x86_thiscallcc i8* @"\01??_GB@@UAEPAXI@Z"
// CHECK2: %[[THIS_PARAM_i8:.*]] = bitcast %struct.B* {{.*}} to i8*
// CHECK2: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[THIS_PARAM_i8:.*]], i32 -8
// CHECK2: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B*
@@ -122,10 +122,9 @@ void B::foo() {
// CHECK: %[[THIS:.*]] = load %struct.B** %[[THIS_ADDR]]
// CHECK: %[[THIS8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS8]], i32 0
-// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
-// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
-// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
-// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i32**
+// CHECK: %[[VBTABLE:.*]] = load i32** %[[VBPTR8]]
+// CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32* %[[VBTABLE]], i32 1
// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
// CHECK: %[[THIS8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
@@ -147,10 +146,9 @@ void call_vbase_bar(B *obj) {
//
// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
-// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
-// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
-// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
-// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i32**
+// CHECK: %[[VBTABLE:.*]] = load i32** %[[VBPTR8]]
+// CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32* %[[VBTABLE]], i32 1
// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
@@ -161,10 +159,9 @@ void call_vbase_bar(B *obj) {
//
// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
-// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
-// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
-// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
-// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i32**
+// CHECK: %[[VBTABLE:.*]] = load i32** %[[VBPTR8]]
+// CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32* %[[VBTABLE]], i32 1
// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
// CHECK: %[[VBASE:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
@@ -181,30 +178,28 @@ void delete_B(B *obj) {
delete obj;
// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
-// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
-// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
-// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
-// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i32**
+// CHECK: %[[VBTABLE:.*]] = load i32** %[[VBPTR8]]
+// CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32* %[[VBTABLE]], i32 1
// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
-// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (%struct.B*, i32)***
-// CHECK: %[[VFTABLE:.*]] = load void (%struct.B*, i32)*** %[[VFPTR]]
-// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.B*, i32)** %[[VFTABLE]], i64 0
-// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.B*, i32)** %[[VFUN]]
+// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to i8* (%struct.B*, i32)***
+// CHECK: %[[VFTABLE:.*]] = load i8* (%struct.B*, i32)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds i8* (%struct.B*, i32)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load i8* (%struct.B*, i32)** %[[VFUN]]
//
// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
-// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
-// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
-// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
-// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i32**
+// CHECK: %[[VBTABLE:.*]] = load i32** %[[VBPTR8]]
+// CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32* %[[VBTABLE]], i32 1
// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
// CHECK: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.B*
//
-// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.B* %[[VBASE]], i32 1)
+// CHECK: call x86_thiscallcc i8* %[[VFUN_VALUE]](%struct.B* %[[VBASE]], i32 1)
// CHECK: ret void
}
@@ -250,9 +245,9 @@ struct D : virtual A, virtual B, virtual C {
D::D() {
// CHECK-LABEL: define x86_thiscallcc %"struct.multiple_vbases::D"* @"\01??0D@multiple_vbases@@QAE@XZ"
// Just make sure we emit 3 vtordisps after initializing vfptrs.
- // CHECK: store [1 x i8*]* @"\01??_7D@multiple_vbases@@6BA@1@@", [1 x i8*]** %{{.*}}
- // CHECK: store [1 x i8*]* @"\01??_7D@multiple_vbases@@6BB@1@@", [1 x i8*]** %{{.*}}
- // CHECK: store [1 x i8*]* @"\01??_7D@multiple_vbases@@6BC@1@@", [1 x i8*]** %{{.*}}
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7D@multiple_vbases@@6BA@1@@" to i32 (...)**), i32 (...)*** %{{.*}}
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7D@multiple_vbases@@6BB@1@@" to i32 (...)**), i32 (...)*** %{{.*}}
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7D@multiple_vbases@@6BC@1@@" to i32 (...)**), i32 (...)*** %{{.*}}
// ...
// CHECK: store i32 %{{.*}}, i32* %{{.*}}
// CHECK: store i32 %{{.*}}, i32* %{{.*}}
@@ -401,8 +396,8 @@ C::~C() {
// In this case "this" points to the most derived class, so no GEPs needed.
// CHECK-NOT: getelementptr
// CHECK-NOT: bitcast
- // CHECK: %[[VFPTR_i8:.*]] = bitcast %"struct.test4::C"* %{{.*}} to [1 x i8*]**
- // CHECK: store [1 x i8*]* @"\01??_7C@test4@@6BB@1@@", [1 x i8*]** %[[VFPTR_i8]]
+ // CHECK: %[[VFPTR_i8:.*]] = bitcast %"struct.test4::C"* %{{.*}} to i32 (...)***
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7C@test4@@6BB@1@@" to i32 (...)**), i32 (...)*** %[[VFPTR_i8]]
foo(this);
// CHECK: ret
@@ -412,11 +407,11 @@ void destroy(C *obj) {
// CHECK-LABEL: define void @"\01?destroy@test4@@YAXPAUC@1@@Z"(%"struct.test4::C"* %obj)
delete obj;
- // CHECK: %[[VPTR:.*]] = bitcast %"struct.test4::C"* %[[OBJ:.*]] to void (%"struct.test4::C"*, i32)***
- // CHECK: %[[VFTABLE:.*]] = load void (%"struct.test4::C"*, i32)*** %[[VPTR]]
- // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds void (%"struct.test4::C"*, i32)** %[[VFTABLE]], i64 0
- // CHECK: %[[VFUN:.*]] = load void (%"struct.test4::C"*, i32)** %[[VFTENTRY]]
- // CHECK: call x86_thiscallcc void %[[VFUN]](%"struct.test4::C"* %[[OBJ]], i32 1)
+ // CHECK: %[[VPTR:.*]] = bitcast %"struct.test4::C"* %[[OBJ:.*]] to i8* (%"struct.test4::C"*, i32)***
+ // CHECK: %[[VFTABLE:.*]] = load i8* (%"struct.test4::C"*, i32)*** %[[VPTR]]
+ // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds i8* (%"struct.test4::C"*, i32)** %[[VFTABLE]], i64 0
+ // CHECK: %[[VFUN:.*]] = load i8* (%"struct.test4::C"*, i32)** %[[VFTENTRY]]
+ // CHECK: call x86_thiscallcc i8* %[[VFUN]](%"struct.test4::C"* %[[OBJ]], i32 1)
// CHECK: ret
}
@@ -436,8 +431,8 @@ E::~E() {
// In this case "this" points to the most derived class, so no GEPs needed.
// CHECK-NOT: getelementptr
// CHECK-NOT: bitcast
- // CHECK: %[[VFPTR_i8:.*]] = bitcast %"struct.test4::E"* %{{.*}} to [1 x i8*]**
- // CHECK: store [1 x i8*]* @"\01??_7E@test4@@6BD@1@@", [1 x i8*]** %[[VFPTR_i8]]
+ // CHECK: %[[VFPTR_i8:.*]] = bitcast %"struct.test4::E"* %{{.*}} to i32 (...)***
+ // CHECK: store i32 (...)** bitcast ([1 x i8*]* @"\01??_7E@test4@@6BD@1@@" to i32 (...)**), i32 (...)*** %[[VFPTR_i8]]
foo(this);
}
@@ -447,15 +442,15 @@ void destroy(E *obj) {
// CHECK-NOT: getelementptr
// CHECK: %[[OBJ_i8:.*]] = bitcast %"struct.test4::E"* %[[OBJ:.*]] to i8*
// CHECK: %[[B_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 4
- // CHECK: %[[VPTR:.*]] = bitcast i8* %[[B_i8]] to void (%"struct.test4::E"*, i32)***
- // CHECK: %[[VFTABLE:.*]] = load void (%"struct.test4::E"*, i32)*** %[[VPTR]]
- // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds void (%"struct.test4::E"*, i32)** %[[VFTABLE]], i64 0
- // CHECK: %[[VFUN:.*]] = load void (%"struct.test4::E"*, i32)** %[[VFTENTRY]]
+ // CHECK: %[[VPTR:.*]] = bitcast i8* %[[B_i8]] to i8* (%"struct.test4::E"*, i32)***
+ // CHECK: %[[VFTABLE:.*]] = load i8* (%"struct.test4::E"*, i32)*** %[[VPTR]]
+ // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds i8* (%"struct.test4::E"*, i32)** %[[VFTABLE]], i64 0
+ // CHECK: %[[VFUN:.*]] = load i8* (%"struct.test4::E"*, i32)** %[[VFTENTRY]]
// CHECK: %[[OBJ_i8:.*]] = bitcast %"struct.test4::E"* %[[OBJ]] to i8*
// CHECK: %[[B_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 4
// FIXME: in fact, the call should take i8* and the bitcast is redundant.
// CHECK: %[[B_as_E:.*]] = bitcast i8* %[[B_i8]] to %"struct.test4::E"*
- // CHECK: call x86_thiscallcc void %[[VFUN]](%"struct.test4::E"* %[[B_as_E]], i32 1)
+ // CHECK: call x86_thiscallcc i8* %[[VFUN]](%"struct.test4::E"* %[[B_as_E]], i32 1)
delete obj;
}
diff --git a/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
index 974953c01444..b5db7c7881b5 100644
--- a/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
@@ -45,92 +45,95 @@ void f() {
// CHECK32-LABEL: define void @"\01?f@@YAXXZ"()
-// CHECK32: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AE" to i8*), i8** %ptr
-// CHECK32: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2
-// CHECK32: store i8* bitcast (void (%struct.C*, %struct.S*, i32)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3
-// CHECK32: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*)* @"\01??_9D@?A@@$BA@AE" to i8*), i8** %ptr4
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BA@AE" to i8*), i8** %ptr
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3
+// CHECK32: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*, ...)* @"\01??_9D@?A@@$BA@AE" to i8*), i8** %ptr4
// CHECK32: }
//
// CHECK64-LABEL: define void @"\01?f@@YAXXZ"()
-// CHECK64: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AA" to i8*), i8** %ptr
-// CHECK64: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2
-// CHECK64: store i8* bitcast (void (%struct.C*, %struct.S*, i32)* @"\01??_9C@@$BBA@AA" to i8*), i8** %ptr3
-// CHECK64: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*)* @"\01??_9D@?A@@$BA@AA" to i8*), i8** %ptr
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BA@AA" to i8*), i8** %ptr
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BBA@AA" to i8*), i8** %ptr3
+// CHECK64: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*, ...)* @"\01??_9D@?A@@$BA@AA" to i8*), i8** %ptr
// CHECK64: }
}
// Thunk for calling the 1st virtual function in C with no parameters.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BA@AE"(%struct.C* %this) unnamed_addr
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]]
-// CHECK32: musttail call x86_thiscallcc void [[CALLEE]](%struct.C* %{{.*}})
-// CHECK32: ret void
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BA@AE"(%struct.C* %this, ...)
+// CHECK32-NOT: unnamed_addr
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 0
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA@AA"(%struct.C* %this) unnamed_addr
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]]
-// CHECK64: musttail call void [[CALLEE]](%struct.C* %{{.*}})
-// CHECK64: ret void
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA@AA"(%struct.C* %this, ...)
+// CHECK64-NOT: unnamed_addr
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 0
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
// CHECK64: }
// Thunk for calling the 2nd virtual function in C, taking int and double as parameters, returning int.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc i32 @"\01??_9C@@$B3AE"(%struct.C* %this, i32, double) unnamed_addr
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1
-// CHECK32: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]]
-// CHECK32: [[CALL:%.*]] = musttail call x86_thiscallcc i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}})
-// CHECK32: ret i32 [[CALL]]
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B3AE"(%struct.C* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 1
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define linkonce_odr i32 @"\01??_9C@@$B7AA"(%struct.C* %this, i32, double) unnamed_addr
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1
-// CHECK64: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]]
-// CHECK64: [[CALL:%.*]] = musttail call i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}})
-// CHECK64: ret i32 [[CALL]]
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$B7AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 1
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
// CHECK64: }
// Thunk for calling the 3rd virtual function in C, taking an int parameter, returning a struct.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.C* %this, %struct.S* noalias sret %agg.result, i32) unnamed_addr
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, i32)** %{{.*}}, i64 2
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, i32)** [[VPTR]]
-// CHECK32: musttail call x86_thiscallcc void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, i32 %{{.*}})
-// CHECK32: ret void
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.C* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 2
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA@AA"(%struct.C* %this, %struct.S* noalias sret %agg.result, i32) unnamed_addr
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, i32)** %{{.*}}, i64 2
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, i32)** [[VPTR]]
-// CHECK64: musttail call void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, i32 %{{.*}})
-// CHECK64: ret void
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA@AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 2
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
// CHECK64: }
// Thunk for calling the virtual function in internal class D.
-// CHECK32-LABEL: define internal x86_thiscallcc void @"\01??_9D@?A@@$BA@AE"(%"struct.(anonymous namespace)::D"* %this) unnamed_addr
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*)** %{{.*}}, i64 0
-// CHECK32: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*)** [[VPTR]]
-// CHECK32: musttail call x86_thiscallcc void [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}})
-// CHECK32: ret void
+// CHECK32-LABEL: define internal x86_thiscallcc void @"\01??_9D@?A@@$BA@AE"(%"struct.(anonymous namespace)::D"* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*, ...)** %{{.*}}, i64 0
+// CHECK32: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%"struct.(anonymous namespace)::D"*, ...)* [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA@AA"(%"struct.(anonymous namespace)::D"* %this) unnamed_addr
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*)** %{{.*}}, i64 0
-// CHECK64: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*)** [[VPTR]]
-// CHECK64: musttail call void [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}})
-// CHECK64: ret void
+// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA@AA"(%"struct.(anonymous namespace)::D"* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*, ...)** %{{.*}}, i64 0
+// CHECK64: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%"struct.(anonymous namespace)::D"*, ...)* [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
// CHECK64: }
-// Thunk for calling the fourth virtual function in C, taking a struct parameter and returning a struct.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc %struct.S* @"\01??_9C@@$BM@AE"(%struct.C* %this, <{ %struct.S*, %struct.U }>* inalloca) unnamed_addr
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds %struct.S* (%struct.C*, <{ %struct.S*, %struct.U }>*)** %{{.*}}, i64 3
-// CHECK32: [[CALLEE:%.*]] = load %struct.S* (%struct.C*, <{ %struct.S*, %struct.U }>*)** [[VPTR]]
-// CHECK32: [[CALL:%.*]] = musttail call x86_thiscallcc %struct.S* [[CALLEE]](%struct.C* %this, <{ %struct.S*, %struct.U }>* inalloca %{{.*}})
-// CHECK32: ret %struct.S* [[CALL]]
+// Thunk for calling the fourth virtual function in C, taking a struct parameter
+// and returning a struct.
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BM@AE"(%struct.C* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 3
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBI@AA"(%struct.C* %this, %struct.S* noalias sret %agg.result, %struct.U*) unnamed_addr
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, %struct.U*)** %{{.*}}, i64 3
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, %struct.U*)** [[VPTR]]
-// CHECK64: musttail call void [[CALLEE]](%struct.C* %this, %struct.S* sret %agg.result, %struct.U* %{{.*}})
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBI@AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 3
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK64: ret void
// CHECK64: }
diff --git a/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp b/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp
new file mode 100644
index 000000000000..35ff4f3bebef
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -triple=i386-pc-win32 %s -o - | FileCheck %s
+
+// In each test case, we have two member pointers whose thunks have the same
+// vtable offset and same mangling, but their prototypes conflict. The
+// arguments and return type may differ. Therefore, we have to bitcast the
+// function prototype. Unfortunately, if the return types differ, LLVM's
+// optimizers can get upset.
+
+namespace num_params {
+struct A { virtual void a(int); };
+struct B { virtual void b(int, int); };
+struct C : A, B {
+ virtual void a(int);
+ virtual void b(int, int);
+};
+void f(C *c) {
+ (c->*(&C::a))(0);
+ (c->*(&C::b))(0, 0);
+}
+}
+
+// CHECK-LABEL: define void @"\01?f@num_params@@YAXPAUC@1@@Z"(%"struct.num_params::C"* %c)
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.num_params::C"*, ...)* @"\01??_9C@num_params@@$BA@AE" to void (%"struct.num_params::C"*, i32)*)(%"struct.num_params::C"* %{{.*}}, i32 0)
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.num_params::C"*, ...)* @"\01??_9C@num_params@@$BA@AE" to void (%"struct.num_params::C"*, i32, i32)*)(%"struct.num_params::C"* %{{.*}}, i32 0, i32 0)
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@num_params@@$BA@AE"(%"struct.num_params::C"* %this, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.num_params::C"*, ...)* %{{.*}}(%"struct.num_params::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
+
+namespace i64_return {
+struct A { virtual int a(); };
+struct B { virtual long long b(); };
+struct C : A, B {
+ virtual int a();
+ virtual long long b();
+};
+long long f(C *c) {
+ int x = (c->*(&C::a))();
+ long long y = (c->*(&C::b))();
+ return x + y;
+}
+}
+
+// CHECK-LABEL: define i64 @"\01?f@i64_return@@YA_JPAUC@1@@Z"(%"struct.i64_return::C"* %c)
+// CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.i64_return::C"*, ...)* @"\01??_9C@i64_return@@$BA@AE" to i32 (%"struct.i64_return::C"*)*)(%"struct.i64_return::C"* %{{.*}})
+// CHECK: call x86_thiscallcc i64 bitcast (void (%"struct.i64_return::C"*, ...)* @"\01??_9C@i64_return@@$BA@AE" to i64 (%"struct.i64_return::C"*)*)(%"struct.i64_return::C"* %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@i64_return@@$BA@AE"(%"struct.i64_return::C"* %this, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.i64_return::C"*, ...)* %{{.*}}(%"struct.i64_return::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
+
+namespace sret {
+struct Big { int big[32]; };
+struct A { virtual int a(); };
+struct B { virtual Big b(); };
+struct C : A, B {
+ virtual int a();
+ virtual Big b();
+};
+void f(C *c) {
+ (c->*(&C::a))();
+ Big b((c->*(&C::b))());
+}
+}
+
+// CHECK-LABEL: define void @"\01?f@sret@@YAXPAUC@1@@Z"(%"struct.sret::C"* %c)
+// CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.sret::C"*, ...)* @"\01??_9C@sret@@$BA@AE" to i32 (%"struct.sret::C"*)*)(%"struct.sret::C"* %{{.*}})
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.sret::C"*, ...)* @"\01??_9C@sret@@$BA@AE" to void (%"struct.sret::C"*, %"struct.sret::Big"*)*)(%"struct.sret::C"* %{{.*}}, %"struct.sret::Big"* sret %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@sret@@$BA@AE"(%"struct.sret::C"* %this, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.sret::C"*, ...)* %{{.*}}(%"struct.sret::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
+
+namespace cdecl_inalloca {
+// Fairly evil, since now we end up doing an inalloca-style call through a
+// thunk that doesn't use inalloca. Hopefully the stacks line up?
+struct Big {
+ Big();
+ ~Big();
+ int big[32];
+};
+struct A { virtual void __cdecl a(); };
+struct B { virtual void __cdecl b(Big); };
+struct C : A, B {
+ virtual void __cdecl a();
+ virtual void __cdecl b(Big);
+};
+void f(C *c) {
+ Big b;
+ (c->*(&C::a))();
+ ((c->*(&C::b))(b));
+}
+}
+
+// CHECK-LABEL: define void @"\01?f@cdecl_inalloca@@YAXPAUC@1@@Z"(%"struct.cdecl_inalloca::C"* %c)
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"\01??_9C@cdecl_inalloca@@$BA@AE" to void (%"struct.cdecl_inalloca::C"*)*)(%"struct.cdecl_inalloca::C"* %{{.*}})
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"\01??_9C@cdecl_inalloca@@$BA@AE" to void (<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>*)*)(<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>* inalloca %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr void @"\01??_9C@cdecl_inalloca@@$BA@AE"(%"struct.cdecl_inalloca::C"* %this, ...)
+// CHECK: musttail call void (%"struct.cdecl_inalloca::C"*, ...)* %{{.*}}(%"struct.cdecl_inalloca::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp b/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp
new file mode 100644
index 000000000000..6d42b8504abf
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fms-extensions -triple i686-pc-windows-msvc %s -emit-llvm-only -verify
+
+// We reject this because LLVM doesn't forward the second regparm through the
+// thunk.
+
+struct A {
+ virtual void __fastcall f(int a, int b); // expected-error {{cannot compile this pointer to fastcall virtual member function yet}}
+};
+void (__fastcall A::*doit())(int, int) {
+ return &A::f;
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp
index 2d0bf6362296..232c0d9c4dd8 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp
@@ -295,3 +295,70 @@ struct X : E {
void build_vftable(X *obj) { obj->foo(); }
}
+
+namespace test7 {
+struct A {
+ virtual A *f() = 0;
+};
+struct B {
+ virtual void g();
+};
+struct C : B, A {
+ virtual void g();
+ virtual C *f() = 0;
+ // CHECK-LABEL: VFTable for 'test7::B' in 'test7::C' (1 entry).
+ // CHECK-NEXT: 0 | void test7::C::g()
+
+ // CHECK-LABEL: VFTable for 'test7::A' in 'test7::C' (2 entries).
+ // CHECK-NEXT: 0 | test7::C *test7::C::f() [pure]
+ // CHECK-NEXT: 1 | test7::C *test7::C::f() [pure]
+
+ // No return adjusting thunks needed for pure virtual methods.
+ // CHECK-NOT: Thunks for 'test7::C *test7::C::f()'
+};
+
+void build_vftable(C *obj) { obj->g(); }
+}
+
+namespace pr20444 {
+struct A {
+ virtual A* f();
+};
+struct B {
+ virtual B* f();
+};
+struct C : A, B {
+ virtual C* f();
+ // CHECK-LABEL: VFTable for 'pr20444::A' in 'pr20444::C' (1 entry).
+ // CHECK-NEXT: 0 | pr20444::C *pr20444::C::f()
+
+ // CHECK-LABEL: VFTable for 'pr20444::B' in 'pr20444::C' (2 entries).
+ // CHECK-NEXT: 0 | pr20444::C *pr20444::C::f()
+ // CHECK-NEXT: [return adjustment (to type 'struct pr20444::B *'): 4 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+ // CHECK-NEXT: 1 | pr20444::C *pr20444::C::f()
+ // CHECK-NEXT: [return adjustment (to type 'struct pr20444::C *'): 0 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+};
+
+void build_vftable(C *obj) { obj->f(); }
+
+struct D : C {
+ virtual D* f();
+ // CHECK-LABEL: VFTable for 'pr20444::A' in 'pr20444::C' in 'pr20444::D' (1 entry).
+ // CHECK-NEXT: 0 | pr20444::D *pr20444::D::f()
+
+ // CHECK-LABEL: VFTable for 'pr20444::B' in 'pr20444::C' in 'pr20444::D' (3 entries).
+ // CHECK-NEXT: 0 | pr20444::D *pr20444::D::f()
+ // CHECK-NEXT: [return adjustment (to type 'struct pr20444::B *'): 4 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+ // CHECK-NEXT: 1 | pr20444::D *pr20444::D::f()
+ // CHECK-NEXT: [return adjustment (to type 'struct pr20444::C *'): 0 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+ // CHECK-NEXT: 2 | pr20444::D *pr20444::D::f()
+ // CHECK-NEXT: [return adjustment (to type 'struct pr20444::D *'): 0 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+};
+
+void build_vftable(D *obj) { obj->f(); }
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp
index 957980aa95ec..d71f40a5ecc6 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
// RUN: FileCheck %s < %t
-// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
+// RUN: FileCheck --check-prefix=BITCODE %s < %t.ll
namespace test1 {
struct A {
@@ -29,8 +29,8 @@ struct X : A, B {
// CHECK-LABEL: VFTable indices for 'test1::X' (1 entry).
// CHECK-NEXT: 0 | void test1::X::g()
- // MANGLING-DAG: @"\01??_7X@test1@@6BA@1@@"
- // MANGLING-DAG: @"\01??_7X@test1@@6BB@1@@"
+ // BITCODE-DAG: @"\01??_7X@test1@@6BA@1@@"
+ // BITCODE-DAG: @"\01??_7X@test1@@6BB@1@@"
virtual void g();
} x;
@@ -71,9 +71,9 @@ struct X : A, B, C {
// CHECK-NEXT: via vfptr at offset 4
// CHECK-NEXT: 0 | void test2::X::g()
- // MANGLING-DAG: @"\01??_7X@test2@@6BA@1@@"
- // MANGLING-DAG: @"\01??_7X@test2@@6BB@1@@"
- // MANGLING-DAG: @"\01??_7X@test2@@6BC@1@@"
+ // BITCODE-DAG: @"\01??_7X@test2@@6BA@1@@"
+ // BITCODE-DAG: @"\01??_7X@test2@@6BB@1@@"
+ // BITCODE-DAG: @"\01??_7X@test2@@6BC@1@@"
virtual void g();
} x;
@@ -138,3 +138,42 @@ struct X: C, D {
void build_vftable(X *obj) { obj->g(); }
}
+
+namespace test4 {
+struct A {
+ virtual void foo();
+};
+struct B {
+ virtual int filler();
+ virtual int operator-();
+ virtual int bar();
+};
+struct C : public A, public B {
+ virtual int filler();
+ virtual int operator-();
+ virtual int bar();
+};
+
+// BITCODE-LABEL: define {{.*}}\01?ffun@test4@@YAXAAUC@1@@Z
+void ffun(C &c) {
+ // BITCODE: load
+ // BITCODE: bitcast
+ // BITCODE: bitcast
+ // BITCODE: [[THIS1:%.+]] = bitcast %"struct.test4::C"* {{.*}} to i8*
+ // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8* [[THIS1]], i32 4
+ // BITCODE-NEXT: call x86_thiscallcc {{.*}}(i8* [[THIS2]])
+ c.bar();
+}
+
+// BITCODE-LABEL: define {{.*}}\01?fop@test4@@YAXAAUC@1@@Z
+void fop(C &c) {
+ // BITCODE: load
+ // BITCODE: bitcast
+ // BITCODE: bitcast
+ // BITCODE: [[THIS1:%.+]] = bitcast %"struct.test4::C"* {{.*}} to i8*
+ // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8* [[THIS1]], i32 4
+ // BITCODE-NEXT: call x86_thiscallcc {{.*}}(i8* [[THIS2]])
+ -c;
+}
+
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-return-thunks.cpp b/test/CodeGenCXX/microsoft-abi-vtables-return-thunks.cpp
index a4a21106c685..072cb956035f 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-return-thunks.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-return-thunks.cpp
@@ -104,3 +104,27 @@ K::K() {}
// GLOBALS-LABEL: @"\01??_7K@test2@@6B@" = linkonce_odr unnamed_addr constant [3 x i8*]
}
+
+namespace pr20479 {
+struct A {
+ virtual A *f();
+};
+
+struct B : virtual A {
+ virtual B *f();
+};
+
+struct C : virtual A, B {
+// VFTABLES-LABEL: VFTable for 'pr20479::A' in 'pr20479::B' in 'pr20479::C' (2 entries).
+// VFTABLES-NEXT: 0 | pr20479::B *pr20479::B::f()
+// VFTABLES-NEXT: [return adjustment (to type 'struct pr20479::A *'): vbase #1, 0 non-virtual]
+// VFTABLES-NEXT: 1 | pr20479::B *pr20479::B::f()
+ C();
+};
+
+C::C() {}
+
+// GLOBALS-LABEL: @"\01??_7C@pr20479@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*]
+// GLOBALS: @"\01?f@B@pr20479@@QAEPAUA@2@XZ"
+// GLOBALS: @"\01?f@B@pr20479@@UAEPAU12@XZ"
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
index d453f5c55aed..baed35145f98 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
@@ -289,3 +289,13 @@ struct R : Q {
R r;
void use(R *obj) { obj->foo(42l); }
+
+struct S {
+ // CHECK-LABEL: VFTable for 'S' (1 entry).
+ // CHECK-NEXT: 0 | void S::f() [deleted]
+ virtual void f() = delete;
+ S();
+ // EMITS-VFTABLE-DAG: @"\01??_7S@@6B@" = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast (void ()* @_purecall to i8*)]
+};
+
+S::S() {}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp
index f63808a89873..1f6d4202154a 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp
@@ -32,8 +32,8 @@ struct V4 : Z, V1, V2 {
void use_somewhere_else(void*);
namespace simple {
-// In case of a single-layer virtual inheritance, the "this" adjustment is done
-// staically:
+// In case of a single-layer virtual inheritance, the "this" adjustment for a
+// virtual method is done staically:
// struct A {
// virtual void f(); // Expects "(A*)this" in ECX
// };
@@ -48,9 +48,9 @@ namespace simple {
// current class layout and the most derived class layout are different.
// This is done using vtordisp thunks.
//
-// A simple vtordisp{A,B} thunk for Method@Class is something like:
-// sub ecx, [ecx+A] // apply the vtordisp adjustment
-// sub ecx, B // apply the subobject adjustment, if needed.
+// A simple vtordisp{x,y} thunk for Method@Class is something like:
+// sub ecx, [ecx+x] // apply the vtordisp adjustment
+// sub ecx, y // apply the subobject adjustment, if needed.
// jmp Method@Class
struct A : virtual V1 {
@@ -227,12 +227,12 @@ namespace extended {
// In this case, we should use the extended form of vtordisp thunks, called
// vtordispex thunks.
//
-// vtordispex{A,B,C,D} thunk for Method@Class is something like:
-// sub ecx, [ecx+C] // apply the vtordisp adjustment
-// sub ecx, A // jump to the vbtable of the most derived class
+// vtordispex{x,y,z,w} thunk for Method@Class is something like:
+// sub ecx, [ecx+z] // apply the vtordisp adjustment
+// sub ecx, x // jump to the vbptr of the most derived class
// mov eax, [ecx] // load the vbtable address
-// add ecx, [eax+B] // lookup the final overrider's vbase offset
-// add ecx, D // apphy the subobject offset if needed
+// add ecx, [eax+y] // lookup the final overrider's vbase offset
+// add ecx, w // apphy the subobject offset if needed
// jmp Method@Class
struct A : virtual simple::A {
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
index 4ce4e9c2e17e..65d6a9d90e6d 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t
+// RUN: %clang_cc1 -std=c++11 -fms-extensions -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t
// RUN: FileCheck %s < %t
// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
@@ -764,3 +764,46 @@ struct W : B, Y {
W::W() {}
}
+
+namespace Test13 {
+struct A {
+ virtual void f();
+};
+struct __declspec(dllexport) B : virtual A {
+ virtual void f() = 0;
+ // MANGLING-DAG: @"\01??_7B@Test13@@6B@" = weak_odr dllexport unnamed_addr constant [1 x i8*] [i8* bitcast (void ()* @_purecall to i8*)]
+};
+}
+
+namespace pr21031_1 {
+// This ordering of base specifiers regressed in r202425.
+struct A { virtual void f(void); };
+struct B : virtual A { virtual void g(void); };
+struct C : virtual A, B { C(); };
+C::C() {}
+
+// CHECK-LABEL: VFTable for 'pr21031_1::A' in 'pr21031_1::B' in 'pr21031_1::C' (1 entry)
+// CHECK-NEXT: 0 | void pr21031_1::A::f()
+
+// CHECK-LABEL: VFTable for 'pr21031_1::B' in 'pr21031_1::C' (1 entry)
+// CHECK-NEXT: 0 | void pr21031_1::B::g()
+
+// MANGLING-DAG: @"\01??_7C@pr21031_1@@6BB@1@@" = {{.*}} constant [1 x i8*]
+// MANGLING-DAG: @"\01??_7C@pr21031_1@@6B@" = {{.*}} constant [1 x i8*]
+}
+
+namespace pr21031_2 {
+struct A { virtual void f(void); };
+struct B : virtual A { virtual void g(void); };
+struct C : B, virtual A { C(); };
+C::C() {}
+
+// CHECK-LABEL: VFTable for 'pr21031_2::B' in 'pr21031_2::C' (1 entry)
+// CHECK-NEXT: 0 | void pr21031_2::B::g()
+
+// CHECK-LABEL: VFTable for 'pr21031_2::A' in 'pr21031_2::B' in 'pr21031_2::C' (1 entry)
+// CHECK-NEXT: 0 | void pr21031_2::A::f()
+
+// MANGLING-DAG: @"\01??_7C@pr21031_2@@6BA@1@@" = {{.*}} constant [1 x i8*]
+// MANGLING-DAG: @"\01??_7C@pr21031_2@@6BB@1@@" = {{.*}} constant [1 x i8*]
+}
diff --git a/test/CodeGenCXX/microsoft-interface.cpp b/test/CodeGenCXX/microsoft-interface.cpp
index c030d1d0b3b5..ec558a408178 100644
--- a/test/CodeGenCXX/microsoft-interface.cpp
+++ b/test/CodeGenCXX/microsoft-interface.cpp
@@ -34,7 +34,7 @@ int fn() {
// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @_ZN1SC2Ev(%struct.S* %this)
// CHECK: call x86_thiscallcc void @_ZN1IC2Ev(%__interface.I* %{{[.0-9A-Z_a-z]+}})
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1S, i64 0, i64 2), i8*** %{{[.0-9A-Z_a-z]+}}
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTV1S, i64 0, i64 2) to i32 (...)**), i32 (...)*** %{{[.0-9A-Z_a-z]+}}
// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @_ZN1IC2Ev(%__interface.I* %this)
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1I, i64 0, i64 2), i8*** %{{[.0-9A-Z_a-z]+}}
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTV1I, i64 0, i64 2) to i32 (...)**), i32 (...)*** %{{[.0-9A-Z_a-z]+}}
diff --git a/test/CodeGenCXX/microsoft-no-rtti-data.cpp b/test/CodeGenCXX/microsoft-no-rtti-data.cpp
index d4002c28b1a2..fded4c91e4f1 100644
--- a/test/CodeGenCXX/microsoft-no-rtti-data.cpp
+++ b/test/CodeGenCXX/microsoft-no-rtti-data.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 %s -fno-rtti-data -triple=i386-pc-win32 -o - -emit-llvm | FileCheck %s
// vftable shouldn't have RTTI data in it.
+// CHECK-NOT: @"\01??_R4S@@6B@"
// CHECK: @"\01??_7S@@6B@" = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast ({{.*}} @"\01??_GS@@UAEPAXI@Z" to i8*)]
struct type_info;
diff --git a/test/CodeGenCXX/microsoft-uuidof-mangling.cpp b/test/CodeGenCXX/microsoft-uuidof-mangling.cpp
new file mode 100644
index 000000000000..9019aa8c9217
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-uuidof-mangling.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-unknown-unknown -fms-extensions | FileCheck %s
+// rdar://17784718
+
+typedef struct _GUID
+{
+ unsigned int Data1;
+ unsigned short Data2;
+ unsigned short Data3;
+ unsigned char Data4[ 8 ];
+} GUID;
+
+
+template < typename T, const GUID & T_iid = __uuidof(T)>
+class UUIDTest
+{
+public:
+ UUIDTest() { }
+};
+
+struct __declspec(uuid("EAFA1952-66F8-438B-8FBA-AF1BBAE42191")) TestStruct
+{
+ int foo;
+};
+
+template <class T> void test_uuidofType(void *arg[sizeof(__uuidof(T))] = 0) {}
+
+template <class T> void test_uuidofExpr(void *arg[sizeof(__uuidof(T::member))] = 0) {}
+
+struct HasMember { typedef TestStruct member; };
+
+int main(int argc, const char * argv[])
+{
+
+ UUIDTest<TestStruct> uuidof_test;
+ test_uuidofType<TestStruct>();
+ test_uuidofExpr<HasMember>();
+ return 0;
+}
+
+// CHECK: define i32 @main
+// CHECK: call void @_ZN8UUIDTestI10TestStructXu8__uuidoftS0_EEC1Ev
+// CHECK: call void @_Z15test_uuidofTypeI10TestStructEvPPv(i8** null)
+// CHECK: call void @_Z15test_uuidofExprI9HasMemberEvPPv(i8** null)
+
+// CHECK: define linkonce_odr void @_ZN8UUIDTestI10TestStructXu8__uuidoftS0_EEC1Ev
+// CHECK: define linkonce_odr void @_Z15test_uuidofTypeI10TestStructEvPPv
+// CHECK: define linkonce_odr void @_Z15test_uuidofExprI9HasMemberEvPPv
+// CHECK: define linkonce_odr void @_ZN8UUIDTestI10TestStructXu8__uuidoftS0_EEC2Ev
diff --git a/test/CodeGenCXX/mingw-w64-seh-exceptions.cpp b/test/CodeGenCXX/mingw-w64-seh-exceptions.cpp
new file mode 100644
index 000000000000..bacddb2936f4
--- /dev/null
+++ b/test/CodeGenCXX/mingw-w64-seh-exceptions.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -fexceptions -emit-llvm -triple x86_64-w64-windows-gnu -o - | FileCheck %s --check-prefix=X64
+// RUN: %clang_cc1 %s -fexceptions -emit-llvm -triple i686-w64-windows-gnu -o - | FileCheck %s --check-prefix=X86
+
+extern "C" void foo();
+extern "C" void bar();
+
+struct Cleanup {
+ ~Cleanup() {
+ bar();
+ }
+};
+
+extern "C" void test() {
+ Cleanup x;
+ foo();
+}
+
+// X64: define void @test()
+// X64: invoke void @foo()
+// X64: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_seh0 to i8*)
+
+// X86: define void @test()
+// X86: invoke void @foo()
+// X86: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
diff --git a/test/CodeGenCXX/ms-inline-asm-return.cpp b/test/CodeGenCXX/ms-inline-asm-return.cpp
new file mode 100644
index 000000000000..26fc426e5fc2
--- /dev/null
+++ b/test/CodeGenCXX/ms-inline-asm-return.cpp
@@ -0,0 +1,100 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 %s -triple i686-pc-windows-msvc -emit-llvm -o - -fasm-blocks | FileCheck %s
+
+// Check that we take EAX or EAX:EDX and return it from these functions for MSVC
+// compatibility.
+
+extern "C" {
+
+long long f_i64() {
+ __asm {
+ mov eax, 1
+ mov edx, 1
+ }
+}
+// CHECK-LABEL: define i64 @f_i64()
+// CHECK: %[[r:[^ ]*]] = call i64 asm sideeffect inteldialect "mov eax, $$1\0A\09mov edx, $$1", "=A,~{eax},{{.*}}"
+// CHECK: ret i64 %[[r]]
+
+int f_i32() {
+ __asm {
+ mov eax, 1
+ mov edx, 1
+ }
+}
+// CHECK-LABEL: define i32 @f_i32()
+// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, $$1\0A\09mov edx, $$1", "={eax},~{eax},{{.*}}"
+// CHECK: ret i32 %[[r]]
+
+short f_i16() {
+ __asm {
+ mov eax, 1
+ mov edx, 1
+ }
+}
+// CHECK-LABEL: define signext i16 @f_i16()
+// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, $$1\0A\09mov edx, $$1", "={eax},~{eax},{{.*}}"
+// CHECK: %[[r_i16:[^ ]*]] = trunc i32 %[[r]] to i16
+// CHECK: ret i16 %[[r_i16]]
+
+char f_i8() {
+ __asm {
+ mov eax, 1
+ mov edx, 1
+ }
+}
+// CHECK-LABEL: define signext i8 @f_i8()
+// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, $$1\0A\09mov edx, $$1", "={eax},~{eax},{{.*}}"
+// CHECK: %[[r_i8:[^ ]*]] = trunc i32 %[[r]] to i8
+// CHECK: ret i8 %[[r_i8]]
+
+bool f_i1() {
+ __asm {
+ mov eax, 1
+ mov edx, 1
+ }
+}
+// CHECK-LABEL: define zeroext i1 @f_i1()
+// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, $$1\0A\09mov edx, $$1", "={eax},~{eax},{{.*}}"
+// CHECK: %[[r_i8:[^ ]*]] = trunc i32 %[[r]] to i8
+// CHECK: store i8 %[[r_i8]], i8* %{{.*}}
+// CHECK: %[[r_i1:[^ ]*]] = load i1* %{{.*}}
+// CHECK: ret i1 %[[r_i1]]
+
+struct FourChars {
+ char a, b, c, d;
+};
+FourChars f_s4() {
+ __asm {
+ mov eax, 0x01010101
+ }
+}
+// CHECK-LABEL: define i32 @f_s4()
+// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, $$0x01010101", "={eax},~{eax},{{.*}}"
+// CHECK: store i32 %[[r]], i32* %{{.*}}
+// CHECK: %[[r_i32:[^ ]*]] = load i32* %{{.*}}
+// CHECK: ret i32 %[[r_i32]]
+
+struct EightChars {
+ char a, b, c, d, e, f, g, h;
+};
+EightChars f_s8() {
+ __asm {
+ mov eax, 0x01010101
+ mov edx, 0x01010101
+ }
+}
+// CHECK-LABEL: define i64 @f_s8()
+// CHECK: %[[r:[^ ]*]] = call i64 asm sideeffect inteldialect "mov eax, $$0x01010101\0A\09mov edx, $$0x01010101", "=A,~{eax},{{.*}}"
+// CHECK: store i64 %[[r]], i64* %{{.*}}
+// CHECK: %[[r_i64:[^ ]*]] = load i64* %{{.*}}
+// CHECK: ret i64 %[[r_i64]]
+
+} // extern "C"
+
+int main() {
+ __asm xor eax, eax
+}
+// CHECK-LABEL: define i32 @main()
+// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "xor eax, eax", "={eax},{{.*}}"
+// CHECK: ret i32 %[[r]]
diff --git a/test/CodeGenCXX/ms-integer-static-data-members-exported.cpp b/test/CodeGenCXX/ms-integer-static-data-members-exported.cpp
index 3f868f36ff66..78bb3a2b1afa 100644
--- a/test/CodeGenCXX/ms-integer-static-data-members-exported.cpp
+++ b/test/CodeGenCXX/ms-integer-static-data-members-exported.cpp
@@ -17,6 +17,6 @@ struct __declspec(dllexport) S {
};
};
-// CHECK: @"\01?x@S@@2FB" = weak_odr dllexport constant i16 42, align 2
-// CHECK: @"\01?y@S@@2W4Enum@@B" = weak_odr dllexport constant i32 2, align 4
+// CHECK: @"\01?x@S@@2FB" = weak_odr dllexport constant i16 42, comdat, align 2
+// CHECK: @"\01?y@S@@2W4Enum@@B" = weak_odr dllexport constant i32 2, comdat, align 4
// CHECK-NOT: NonExported
diff --git a/test/CodeGenCXX/ms-integer-static-data-members.cpp b/test/CodeGenCXX/ms-integer-static-data-members.cpp
index b02b679d71a1..4965f7319187 100644
--- a/test/CodeGenCXX/ms-integer-static-data-members.cpp
+++ b/test/CodeGenCXX/ms-integer-static-data-members.cpp
@@ -26,7 +26,7 @@ const int S::x = 5;
// Inline initialization.
-// CHECK-INLINE: @"\01?x@S@@2HB" = linkonce_odr constant i32 5, align 4
+// CHECK-INLINE: @"\01?x@S@@2HB" = linkonce_odr constant i32 5, comdat, align 4
// Out-of-line initialization.
// CHECK-OUTOFLINE: @"\01?x@S@@2HB" = constant i32 5, align 4
diff --git a/test/CodeGenCXX/ms-thread_local.cpp b/test/CodeGenCXX/ms-thread_local.cpp
new file mode 100644
index 000000000000..c29473fd6fca
--- /dev/null
+++ b/test/CodeGenCXX/ms-thread_local.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 %s -std=c++1y -triple=i686-pc-win32 -emit-llvm -o - | FileCheck %s
+
+struct A {
+ A();
+ ~A();
+};
+
+// CHECK-DAG: $"\01??$a@X@@3UA@@A" = comdat any
+// CHECK-DAG: @"\01??$a@X@@3UA@@A" = linkonce_odr thread_local global %struct.A zeroinitializer, comdat, align 1
+// CHECK-DAG: @"\01??__E?$a@X@@YAXXZ$initializer$" = internal constant void ()* @"\01??__E?$a@X@@YAXXZ", section ".CRT$XDU", comdat($"\01??$a@X@@3UA@@A")
+template <typename T>
+thread_local A a = A();
+
+// CHECK-DAG: @"\01?b@@3UA@@A" = thread_local global %struct.A zeroinitializer, align 1
+// CHECK-DAG: @"__tls_init$initializer$" = internal constant void ()* @__tls_init, section ".CRT$XDU"
+thread_local A b;
+
+// CHECK-LABEL: define internal void @__tls_init()
+// CHECK: call void @"\01??__Eb@@YAXXZ"
+
+thread_local A &c = b;
+thread_local A &d = c;
+
+A f() {
+ (void)a<void>;
+ (void)b;
+ return c;
+}
diff --git a/test/CodeGenCXX/nrvo-noreturn.cc b/test/CodeGenCXX/nrvo-noreturn.cpp
index a8259cab5f30..a8259cab5f30 100644
--- a/test/CodeGenCXX/nrvo-noreturn.cc
+++ b/test/CodeGenCXX/nrvo-noreturn.cpp
diff --git a/test/CodeGenCXX/optnone-def-decl.cpp b/test/CodeGenCXX/optnone-def-decl.cpp
new file mode 100644
index 000000000000..ab6eb3f32e11
--- /dev/null
+++ b/test/CodeGenCXX/optnone-def-decl.cpp
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 %s -triple %itanium_abi_triple -fms-extensions -emit-llvm -o - | FileCheck %s
+
+// Test optnone on both function declarations and function definitions.
+// Verify also that we don't generate invalid IR functions with
+// both alwaysinline and noinline. (optnone implies noinline and wins
+// over alwaysinline, in all cases.)
+
+// Test optnone on extern declaration only.
+extern int decl_only(int a) __attribute__((optnone));
+
+// This function should be marked 'optnone'.
+int decl_only(int a) {
+ return a + a + a + a;
+}
+
+// CHECK: define {{.*}} @_Z9decl_onlyi({{.*}}) [[OPTNONE:#[0-9]+]]
+
+// Test optnone on definition but not extern declaration.
+extern int def_only(int a);
+
+__attribute__((optnone))
+int def_only(int a) {
+ return a + a + a + a;
+}
+
+// Function def_only is a optnone function and therefore it should not be
+// inlined inside 'user_of_def_only'.
+int user_of_def_only() {
+ return def_only(5);
+}
+
+// CHECK: define {{.*}} @_Z8def_onlyi({{.*}}) [[OPTNONE]]
+// CHECK: define {{.*}} @_Z16user_of_def_onlyv() [[NORMAL:#[0-9]+]]
+
+// Test optnone on both definition and declaration.
+extern int def_and_decl(int a) __attribute__((optnone));
+
+__attribute__((optnone))
+int def_and_decl(int a) {
+ return a + a + a + a;
+}
+
+// CHECK: define {{.*}} @_Z12def_and_decli({{.*}}) [[OPTNONE]]
+
+// Check that optnone wins over always_inline.
+
+// Test optnone on definition and always_inline on declaration.
+extern int always_inline_function(int a) __attribute__((always_inline));
+
+__attribute__((optnone))
+extern int always_inline_function(int a) {
+ return a + a + a + a;
+}
+// CHECK: define {{.*}} @_Z22always_inline_functioni({{.*}}) [[OPTNONE]]
+
+int user_of_always_inline_function() {
+ return always_inline_function(4);
+}
+
+// CHECK: define {{.*}} @_Z30user_of_always_inline_functionv() [[NORMAL]]
+
+// Test optnone on declaration and always_inline on definition.
+extern int optnone_function(int a) __attribute__((optnone));
+
+__attribute__((always_inline))
+int optnone_function(int a) {
+ return a + a + a + a;
+}
+// CHECK: define {{.*}} @_Z16optnone_functioni({{.*}}) [[OPTNONE]]
+
+int user_of_optnone_function() {
+ return optnone_function(4);
+}
+
+// CHECK: define {{.*}} @_Z24user_of_optnone_functionv() [[NORMAL]]
+
+// Test the combination of optnone with forceinline (optnone wins).
+extern __forceinline int forceinline_optnone_function(int a, int b);
+
+__attribute__((optnone))
+extern int forceinline_optnone_function(int a, int b) {
+ return a + b;
+}
+
+int user_of_forceinline_optnone_function() {
+ return forceinline_optnone_function(4,5);
+}
+
+// CHECK: @_Z36user_of_forceinline_optnone_functionv() [[NORMAL]]
+// CHECK: @_Z28forceinline_optnone_functionii({{.*}}) [[OPTNONE]]
+
+// CHECK: attributes [[OPTNONE]] = { noinline nounwind optnone {{.*}} }
+// CHECK: attributes [[NORMAL]] = { nounwind {{.*}} }
+
diff --git a/test/CodeGenCXX/pod-member-memcpys.cpp b/test/CodeGenCXX/pod-member-memcpys.cpp
index 31d774c5345e..a3ee990bf319 100644
--- a/test/CodeGenCXX/pod-member-memcpys.cpp
+++ b/test/CodeGenCXX/pod-member-memcpys.cpp
@@ -67,6 +67,13 @@ struct BitfieldMember2 {
NonPOD np;
};
+struct BitfieldMember3 {
+ virtual void f();
+ int : 8;
+ int x : 1;
+ int y;
+};
+
struct InnerClassMember {
struct {
int a, b, c, d;
@@ -174,6 +181,7 @@ CALL_AO(PackedMembers)
CALL_CC(PackedMembers)
CALL_CC(BitfieldMember2)
+CALL_CC(BitfieldMember3)
CALL_CC(ReferenceMember)
CALL_CC(InnerClassMember)
CALL_CC(BitfieldMember)
@@ -243,6 +251,11 @@ CALL_CC(Basic)
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}})
// CHECK: ret void
+// BitfieldMember3 copy-constructor:
+// CHECK-LABEL: define linkonce_odr void @_ZN15BitfieldMember3C2ERKS_(%struct.BitfieldMember3* %this, %struct.BitfieldMember3* dereferenceable({{[0-9]+}}))
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 8, i32 8, i1 false)
+// CHECK: ret void
+
// BitfieldMember2 copy-constructor:
// CHECK-2-LABEL: define linkonce_odr void @_ZN15BitfieldMember2C2ERKS_(%struct.BitfieldMember2* %this, %struct.BitfieldMember2* dereferenceable({{[0-9]+}}))
// CHECK-2: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4, i1 false)
diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp
index 745cf18fce21..0b99fea8fc57 100644
--- a/test/CodeGenCXX/pointers-to-data-members.cpp
+++ b/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -55,7 +55,7 @@ namespace ZeroInit {
};
struct C : A, B { int j; };
- // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.ZeroInit::A"] [%"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0 }, align 8
+ // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} <{ %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.ZeroInit::A"] [%"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0, [4 x i8] zeroinitializer }>, align 8
C c;
}
@@ -255,4 +255,26 @@ namespace PR13097 {
// CHECK: call void @_ZN7PR130971XC1ERKS0_
}
+namespace PR21089 {
+struct A {
+ bool : 1;
+ int A::*x;
+ bool y;
+ A();
+};
+struct B : A {
+};
+B b;
+// CHECK-GLOBAL: @_ZN7PR210891bE = global %"struct.PR21089::B" { %"struct.PR21089::A.base" <{ i8 0, [7 x i8] zeroinitializer, i64 -1, i8 0 }>, [7 x i8] zeroinitializer }, align 8
+}
+
+namespace PR21282 {
+union U {
+ int U::*x;
+ long y[2];
+};
+U u;
+// CHECK-GLOBAL: @_ZN7PR212821uE = global %"union.PR21282::U" { i64 -1, [8 x i8] zeroinitializer }, align 8
+}
+
// CHECK-O3: attributes [[NUW]] = { nounwind readnone{{.*}} }
diff --git a/test/CodeGenCXX/pr12251.cpp b/test/CodeGenCXX/pr12251.cpp
index bb1c82dc8153..5b1ef9a31d24 100644
--- a/test/CodeGenCXX/pr12251.cpp
+++ b/test/CodeGenCXX/pr12251.cpp
@@ -18,14 +18,14 @@ e1 g1(e1 *x) {
return *x;
}
// CHECK-LABEL: define i32 @_Z2g1P2e1
-// CHECK: load i32* %x, align 4, !range [[RANGE_i32_0_1:![^ ]*]]
+// CHECK: ret i32 0
enum e2 { e2_a = 0 };
e2 g2(e2 *x) {
return *x;
}
// CHECK-LABEL: define i32 @_Z2g2P2e2
-// CHECK: load i32* %x, align 4, !range [[RANGE_i32_0_1]]
+// CHECK: ret i32 0
enum e3 { e3_a = 16 };
e3 g3(e3 *x) {
@@ -136,11 +136,10 @@ e16 g16(e16 *x) {
// CHECK: ret
-// CHECK: [[RANGE_i8_0_2]] = metadata !{i8 0, i8 2}
-// CHECK: [[RANGE_i32_0_1]] = metadata !{i32 0, i32 1}
-// CHECK: [[RANGE_i32_0_32]] = metadata !{i32 0, i32 32}
-// CHECK: [[RANGE_i32_m16_16]] = metadata !{i32 -16, i32 16}
-// CHECK: [[RANGE_i32_m32_32]] = metadata !{i32 -32, i32 32}
-// CHECK: [[RANGE_i32_m1_1]] = metadata !{i32 -1, i32 1}
-// CHECK: [[RANGE_i32_m64_64]] = metadata !{i32 -64, i32 64}
-// CHECK: [[RANGE_i64_0_2pow33]] = metadata !{i64 0, i64 8589934592}
+// CHECK: [[RANGE_i8_0_2]] = !{i8 0, i8 2}
+// CHECK: [[RANGE_i32_0_32]] = !{i32 0, i32 32}
+// CHECK: [[RANGE_i32_m16_16]] = !{i32 -16, i32 16}
+// CHECK: [[RANGE_i32_m32_32]] = !{i32 -32, i32 32}
+// CHECK: [[RANGE_i32_m1_1]] = !{i32 -1, i32 1}
+// CHECK: [[RANGE_i32_m64_64]] = !{i32 -64, i32 64}
+// CHECK: [[RANGE_i64_0_2pow33]] = !{i64 0, i64 8589934592}
diff --git a/test/CodeGenCXX/pr18635.cpp b/test/CodeGenCXX/pr18635.cpp
new file mode 100644
index 000000000000..94b5e4599956
--- /dev/null
+++ b/test/CodeGenCXX/pr18635.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm -std=c++11 -triple x86_64-pc-linux-gnu -o- %s | FileCheck %s
+
+// Global @x:
+// CHECK: [[X_GLOBAL:@[^ ]+]]{{.*}}thread_local global
+
+// returned somewhere in TLS wrapper:
+// CHECK: ret{{.*}}[[X_GLOBAL]]
+
+template <typename T> class unique_ptr {
+ template <typename F, typename S> struct pair {
+ F first;
+ S second;
+ };
+ pair<T *, int> data;
+public:
+ constexpr unique_ptr() noexcept : data() {}
+ explicit unique_ptr(T *p) noexcept : data() {}
+};
+
+thread_local unique_ptr<int> x;
+int main() { x = unique_ptr<int>(new int(5)); }
+
diff --git a/test/CodeGenCXX/pr18962.cpp b/test/CodeGenCXX/pr18962.cpp
index ab537b4928e3..9e6ef169cd10 100644
--- a/test/CodeGenCXX/pr18962.cpp
+++ b/test/CodeGenCXX/pr18962.cpp
@@ -26,7 +26,7 @@ fn2(C *) {
// We end up using an opaque type for 'append' to avoid circular references.
// CHECK: %class.A = type { {}* }
-// CHECK: %class.C = type { %class.D*, %class.B }
+// CHECK: %class.C = type <{ %class.D*, %class.B, [3 x i8] }>
// CHECK: %class.D = type { %class.C.base, [3 x i8] }
// CHECK: %class.C.base = type <{ %class.D*, %class.B }>
// CHECK: %class.B = type { i8 }
diff --git a/test/CodeGenCXX/pr20719.cpp b/test/CodeGenCXX/pr20719.cpp
new file mode 100644
index 000000000000..208d11135847
--- /dev/null
+++ b/test/CodeGenCXX/pr20719.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++11 -o - %s | FileCheck %s
+
+// Make sure that we emit H's constructor twice: once with the first lambda
+// inside of 'lep' and again with the second lambda inside of 'lep'.
+// CHECK-DAG: @"\01??0?$H@V<lambda_1>@??$lep@X@@YAXXZ@@@QAE@XZ"
+// CHECK-DAG: @"\01??0?$H@V<lambda_2>@??$lep@X@@YAXXZ@@@QAE@XZ"
+
+template <typename>
+struct H {
+ H() {}
+};
+
+template <typename Fx>
+int K_void(const Fx &) {
+ H<Fx> callee;
+ return 0;
+}
+template <typename Fx>
+int K_int(const Fx &) {
+ H<Fx> callee;
+ return 0;
+}
+
+struct pair {
+ pair(int, int);
+};
+
+struct E1;
+
+template <typename>
+void lep() {
+ pair x(K_void([] {}), K_int([] {}));
+}
+
+auto z = lep<void>;
diff --git a/test/CodeGenCXX/pr20897.cpp b/test/CodeGenCXX/pr20897.cpp
new file mode 100644
index 000000000000..49d669bd7eab
--- /dev/null
+++ b/test/CodeGenCXX/pr20897.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++1y -O0 -o - %s | FileCheck %s
+struct Base {};
+
+// __declspec(dllexport) causes us to export the implicit constructor.
+struct __declspec(dllexport) Derived : virtual Base {
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc %struct.Derived* @"\01??0Derived@@QAE@ABU0@@Z"
+// CHECK: %[[this:.*]] = load %struct.Derived** {{.*}}
+// CHECK-NEXT: store %struct.Derived* %[[this]], %struct.Derived** %[[retval:.*]]
+// CHECK: %[[dest_a_gep:.*]] = getelementptr inbounds %struct.Derived* %[[this]], i32 0, i32 1
+// CHECK-NEXT: %[[src_load:.*]] = load %struct.Derived** {{.*}}
+// CHECK-NEXT: %[[src_a_gep:.*]] = getelementptr inbounds %struct.Derived* %[[src_load:.*]], i32 0, i32 1
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[dest_a_gep]], i8* %[[src_a_gep]], i64 1, i32 4, i1 false)
+// CHECK-NEXT: %[[dest_this:.*]] = load %struct.Derived** %[[retval]]
+// CHECK-NEXT: ret %struct.Derived* %[[dest_this]]
+ bool a : 1;
+ bool b : 1;
+};
+
+// __declspec(dllexport) causes us to export the implicit copy constructor.
+struct __declspec(dllexport) Derived2 : virtual Base {
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc %struct.Derived2* @"\01??0Derived2@@QAE@ABU0@@Z"
+// CHECK: %[[this:.*]] = load %struct.Derived2** {{.*}}
+// CHECK-NEXT: store %struct.Derived2* %[[this]], %struct.Derived2** %[[retval:.*]]
+// CHECK: %[[dest_a_gep:.*]] = getelementptr inbounds %struct.Derived2* %[[this]], i32 0, i32 1
+// CHECK-NEXT: %[[src_load:.*]] = load %struct.Derived2** {{.*}}
+// CHECK-NEXT: %[[src_a_gep:.*]] = getelementptr inbounds %struct.Derived2* %[[src_load:.*]], i32 0, i32 1
+// CHECK-NEXT: %[[dest_a_bitcast:.*]] = bitcast [1 x i32]* %[[dest_a_gep]] to i8*
+// CHECK-NEXT: %[[src_a_bitcast:.*]] = bitcast [1 x i32]* %[[src_a_gep]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %[[dest_a_bitcast]], i8* %[[src_a_bitcast]], i32 4, i32 4, i1 false)
+// CHECK-NEXT: %[[dest_this:.*]] = load %struct.Derived2** %[[retval]]
+// CHECK-NEXT: ret %struct.Derived2* %[[dest_this]]
+ int Array[1];
+};
diff --git a/test/CodeGenCXX/pr21989.cpp b/test/CodeGenCXX/pr21989.cpp
new file mode 100644
index 000000000000..0b9bccbe925b
--- /dev/null
+++ b/test/CodeGenCXX/pr21989.cpp
@@ -0,0 +1,9 @@
+// REQUIRES: asserts
+// RUN: not %clang_cc1 -emit-llvm -triple %itanium_abi_triple -o - %s 2>&1 | FileCheck %s
+
+struct {
+ void __attribute__((used)) f() {}
+};
+// CHECK: 2 errors generated.
+
+// Emit the errors, but don't assert.
diff --git a/test/CodeGenCXX/pragma-init_seg.cpp b/test/CodeGenCXX/pragma-init_seg.cpp
index 3f9ff217e6b6..cc4d01875309 100644
--- a/test/CodeGenCXX/pragma-init_seg.cpp
+++ b/test/CodeGenCXX/pragma-init_seg.cpp
@@ -35,24 +35,24 @@ int x = f();
namespace selectany_init {
int __declspec(selectany) x = f();
-// CHECK: @"\01?x@selectany_init@@3HA" = weak_odr global i32 0, comdat $"\01?x@selectany_init@@3HA", align 4
-// CHECK: @__cxx_init_fn_ptr3 = private constant void ()* @"\01??__Ex@selectany_init@@YAXXZ", section ".asdf", comdat $"\01?x@selectany_init@@3HA"
+// CHECK: @"\01?x@selectany_init@@3HA" = weak_odr global i32 0, comdat, align 4
+// CHECK: @__cxx_init_fn_ptr3 = private constant void ()* @"\01??__Ex@selectany_init@@YAXXZ", section ".asdf", comdat($"\01?x@selectany_init@@3HA")
}
namespace explicit_template_instantiation {
template <typename T> struct A { static const int x; };
template <typename T> const int A<T>::x = f();
template struct A<int>;
-// CHECK: @"\01?x@?$A@H@explicit_template_instantiation@@2HB" = weak_odr global i32 0, comdat $"\01?x@?$A@H@explicit_template_instantiation@@2HB", align 4
-// CHECK: @__cxx_init_fn_ptr4 = private constant void ()* @"\01??__Ex@?$A@H@explicit_template_instantiation@@2HB@YAXXZ", section ".asdf", comdat $"\01?x@?$A@H@explicit_template_instantiation@@2HB"
+// CHECK: @"\01?x@?$A@H@explicit_template_instantiation@@2HB" = weak_odr global i32 0, comdat, align 4
+// CHECK: @__cxx_init_fn_ptr4 = private constant void ()* @"\01??__Ex@?$A@H@explicit_template_instantiation@@2HB@YAXXZ", section ".asdf", comdat($"\01?x@?$A@H@explicit_template_instantiation@@2HB")
}
namespace implicit_template_instantiation {
template <typename T> struct A { static const int x; };
template <typename T> const int A<T>::x = f();
int g() { return A<int>::x; }
-// CHECK: @"\01?x@?$A@H@implicit_template_instantiation@@2HB" = linkonce_odr global i32 0, comdat $"\01?x@?$A@H@implicit_template_instantiation@@2HB", align 4
-// CHECK: @__cxx_init_fn_ptr5 = private constant void ()* @"\01??__Ex@?$A@H@implicit_template_instantiation@@2HB@YAXXZ", section ".asdf", comdat $"\01?x@?$A@H@implicit_template_instantiation@@2HB"
+// CHECK: @"\01?x@?$A@H@implicit_template_instantiation@@2HB" = linkonce_odr global i32 0, comdat, align 4
+// CHECK: @__cxx_init_fn_ptr5 = private constant void ()* @"\01??__Ex@?$A@H@implicit_template_instantiation@@2HB@YAXXZ", section ".asdf", comdat($"\01?x@?$A@H@implicit_template_instantiation@@2HB")
}
// ... and here's where we emitted user level ctors.
diff --git a/test/CodeGenCXX/predefined-expr-cxx14.cpp b/test/CodeGenCXX/predefined-expr-cxx14.cpp
new file mode 100644
index 000000000000..1f035757dea9
--- /dev/null
+++ b/test/CodeGenCXX/predefined-expr-cxx14.cpp
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -std=c++14 %s -triple %itanium_abi_triple -fblocks -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -x c++ -std=c++14 -triple %itanium_abi_triple -fblocks -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -triple %itanium_abi_triple -std=c++14 -fblocks -include-pch %t %s -emit-llvm -o - | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+
+// CHECK-DAG: @__func__._ZN13ClassTemplateIiE21classTemplateFunctionERi = private unnamed_addr constant [22 x i8] c"classTemplateFunction\00"
+// CHECK-DAG: @__PRETTY_FUNCTION__._ZN13ClassTemplateIiE21classTemplateFunctionERi = private unnamed_addr constant [69 x i8] c"const auto &ClassTemplate<int>::classTemplateFunction(T &) [T = int]\00"
+
+// CHECK-DAG: @__func__._ZN24ClassInTopLevelNamespace16functionTemplateIiEERDaRT_ = private unnamed_addr constant [17 x i8] c"functionTemplate\00"
+// CHECK-DAG: @__PRETTY_FUNCTION__._ZN24ClassInTopLevelNamespace16functionTemplateIiEERDaRT_ = private unnamed_addr constant [64 x i8] c"auto &ClassInTopLevelNamespace::functionTemplate(T &) [T = int]\00"
+
+// CHECK-DAG: @__func__._ZN24ClassInTopLevelNamespace16variadicFunctionEPiz = private unnamed_addr constant [17 x i8] c"variadicFunction\00"
+// CHECK-DAG: @__PRETTY_FUNCTION__._ZN24ClassInTopLevelNamespace16variadicFunctionEPiz = private unnamed_addr constant [70 x i8] c"decltype(auto) ClassInTopLevelNamespace::variadicFunction(int *, ...)\00"
+
+// CHECK-DAG: @__func__._ZN24ClassInTopLevelNamespace25topLevelNamespaceFunctionEv = private unnamed_addr constant [26 x i8] c"topLevelNamespaceFunction\00"
+// CHECK-DAG: @__PRETTY_FUNCTION__._ZN24ClassInTopLevelNamespace25topLevelNamespaceFunctionEv = private unnamed_addr constant [60 x i8] c"auto *ClassInTopLevelNamespace::topLevelNamespaceFunction()\00"
+
+// CHECK-DAG: @__func__.___ZN16ClassBlockConstrD2Ev_block_invoke = private unnamed_addr constant [41 x i8] c"___ZN16ClassBlockConstrD2Ev_block_invoke\00"
+// CHECK-DAG: @__func__.___ZN16ClassBlockConstrC2Ev_block_invoke = private unnamed_addr constant [41 x i8] c"___ZN16ClassBlockConstrC2Ev_block_invoke\00"
+
+int printf(const char * _Format, ...);
+
+class ClassInTopLevelNamespace {
+public:
+ auto *topLevelNamespaceFunction() {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ return static_cast<int *>(nullptr);
+ }
+
+ decltype(auto) variadicFunction(int *a, ...) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ return a;
+ }
+
+ template<typename T>
+ auto &functionTemplate(T &t) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ return t;
+ }
+};
+
+template<typename T>
+class ClassTemplate {
+public:
+ const auto &classTemplateFunction(T &t) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ return t;
+ }
+};
+
+struct ClassBlockConstr {
+ const char *s;
+ ClassBlockConstr() {
+ const char * (^b)() = ^() {
+ return __func__;
+ };
+ s = b();
+ }
+ ~ClassBlockConstr() {
+ const char * (^b)() = ^() {
+ return __func__;
+ };
+ s = b();
+ }
+};
+
+template <class T>
+class FuncTemplate {
+ const char *Func;
+
+public:
+ FuncTemplate() : Func(__func__) {}
+ const char *getFunc() const { return Func; }
+};
+
+int
+main() {
+ int a;
+ ClassInTopLevelNamespace topLevelNamespace;
+ ClassBlockConstr classBlockConstr;
+ topLevelNamespace.topLevelNamespaceFunction();
+ topLevelNamespace.variadicFunction(&a);
+ topLevelNamespace.functionTemplate(a);
+
+ ClassTemplate<int> t;
+ t.classTemplateFunction(a);
+ return 0;
+}
+#else
+void Foo() {
+ FuncTemplate<int> FTi;
+ (void)FTi.getFunc();
+}
+#endif
+
diff --git a/test/CodeGenCXX/predefined-expr.cpp b/test/CodeGenCXX/predefined-expr.cpp
index f901467c4f4b..6bdc2cec4be8 100644
--- a/test/CodeGenCXX/predefined-expr.cpp
+++ b/test/CodeGenCXX/predefined-expr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fblocks %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
// CHECK: private unnamed_addr constant [15 x i8] c"externFunction\00"
// CHECK: private unnamed_addr constant [26 x i8] c"void NS::externFunction()\00"
@@ -537,3 +537,33 @@ int main() {
return 0;
}
+
+// rdar://19065361
+class XXX {
+ XXX();
+ ~XXX();
+};
+
+void XXLog(const char *functionName) { }
+
+typedef void (^notify_handler_t)(int token);
+
+typedef void (^dispatch_block_t)(void);
+
+void notify_register_dispatch(notify_handler_t handler);
+
+void _dispatch_once(dispatch_block_t block);
+
+XXX::XXX()
+{
+ _dispatch_once(^{ notify_register_dispatch( ^(int token) { XXLog(__FUNCTION__); });
+ });
+}
+// CHECK: define internal void @___ZN3XXXC2Ev_block_invoke_
+
+XXX::~XXX()
+{
+ _dispatch_once(^{ notify_register_dispatch( ^(int token) { XXLog(__FUNCTION__); });
+ });
+}
+// CHECK: define internal void @___ZN3XXXD2Ev_block_invoke_
diff --git a/test/CodeGenCXX/runtimecc.cpp b/test/CodeGenCXX/runtimecc.cpp
index 20448838f919..ad6dc85c360d 100644
--- a/test/CodeGenCXX/runtimecc.cpp
+++ b/test/CodeGenCXX/runtimecc.cpp
@@ -20,33 +20,33 @@ namespace test0 {
};
A global;
-// CHECK-LABEL: define internal arm_aapcscc void @__cxx_global_var_init()
-// CHECK: call arm_aapcscc [[A]]* @_ZN5test01AC1Ev([[A]]* @_ZN5test06globalE)
-// CHECK-NEXT: call arm_aapcscc i32 @__cxa_atexit(void (i8*)* bitcast ([[A]]* ([[A]]*)* @_ZN5test01AD1Ev to void (i8*)*), i8* bitcast ([[A]]* @_ZN5test06globalE to i8*), i8* @__dso_handle) [[NOUNWIND:#[0-9]+]]
+// CHECK-LABEL: define internal void @__cxx_global_var_init()
+// CHECK: call [[A]]* @_ZN5test01AC1Ev([[A]]* @_ZN5test06globalE)
+// CHECK-NEXT: call i32 @__cxa_atexit(void (i8*)* bitcast ([[A]]* ([[A]]*)* @_ZN5test01AD1Ev to void (i8*)*), i8* bitcast ([[A]]* @_ZN5test06globalE to i8*), i8* @__dso_handle) [[NOUNWIND:#[0-9]+]]
// CHECK-NEXT: ret void
}
-// CHECK: declare arm_aapcscc i32 @__cxa_atexit(void (i8*)*, i8*, i8*) [[NOUNWIND]]
+// CHECK: declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*) [[NOUNWIND]]
namespace test1 {
void test() {
throw 0;
}
-// CHECK-LABEL: define arm_aapcscc void @_ZN5test14testEv()
-// CHECK: [[T0:%.*]] = call arm_aapcscc i8* @__cxa_allocate_exception(i32 4) [[NOUNWIND]]
+// CHECK-LABEL: define void @_ZN5test14testEv()
+// CHECK: [[T0:%.*]] = call i8* @__cxa_allocate_exception(i32 4) [[NOUNWIND]]
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32*
// CHECK-NEXT: store i32 0, i32* [[T1]]
-// CHECK-NEXT: call arm_aapcscc void @__cxa_throw(i8* [[T0]], i8* bitcast (i8** @_ZTIi to i8*), i8* null) [[NORETURN:#[0-9]+]]
+// CHECK-NEXT: call void @__cxa_throw(i8* [[T0]], i8* bitcast (i8** @_ZTIi to i8*), i8* null) [[NORETURN:#[0-9]+]]
// CHECK-NEXT: unreachable
}
-// CHECK: declare arm_aapcscc i8* @__cxa_allocate_exception(i32)
+// CHECK: declare i8* @__cxa_allocate_exception(i32)
-// CHECK: declare arm_aapcscc void @__cxa_throw(i8*, i8*, i8*)
+// CHECK: declare void @__cxa_throw(i8*, i8*, i8*)
-// CHECK-LABEL: define internal arm_aapcscc void @_GLOBAL__sub_I_runtimecc.cpp()
-// CHECK: call arm_aapcscc void @__cxx_global_var_init()
+// CHECK-LABEL: define internal void @_GLOBAL__sub_I_runtimecc.cpp()
+// CHECK: call void @__cxx_global_var_init()
// CHECK: attributes [[NOUNWIND]] = { nounwind }
diff --git a/test/CodeGen/sections.c b/test/CodeGenCXX/sections.cpp
index 8d93fed480e1..f84f9d939c0b 100644
--- a/test/CodeGen/sections.c
+++ b/test/CodeGenCXX/sections.cpp
@@ -1,8 +1,7 @@
-// RUN: %clang_cc1 -emit-llvm -fms-extensions -xc++ -o - < %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-win32 -fms-extensions -o - %s | FileCheck %s
-#ifdef __cplusplus
extern "C" {
-#endif
+
#pragma const_seg(".my_const")
#pragma bss_seg(".my_bss")
int D = 1;
@@ -31,9 +30,26 @@ int i;
int TEST1;
#pragma bss_seg(pop)
int TEST2;
-#ifdef __cplusplus
+
+#pragma section("read_flag_section", read)
+// Even though they are not declared const, these become constant since they are
+// in a read-only section.
+__declspec(allocate("read_flag_section")) int unreferenced = 0;
+extern __declspec(allocate("read_flag_section")) int referenced = 42;
+int *user() { return &referenced; }
+
+#pragma section("no_section_attributes")
+// A pragma section with no section attributes is read/write.
+__declspec(allocate("no_section_attributes")) int implicitly_read_write = 42;
+
+#pragma section("long_section", long)
+// Pragma section ignores "long".
+__declspec(allocate("long_section")) long long_var = 42;
+
+#pragma section("short_section", short)
+// Pragma section ignores "short".
+__declspec(allocate("short_section")) short short_var = 42;
}
-#endif
//CHECK: @D = global i32 1
//CHECK: @a = global i32 1, section ".data"
@@ -47,5 +63,10 @@ int TEST2;
//CHECK: @i = global i32 0
//CHECK: @TEST1 = global i32 0
//CHECK: @TEST2 = global i32 0, section ".bss1"
+//CHECK: @unreferenced = constant i32 0, section "read_flag_section"
+//CHECK: @referenced = constant i32 42, section "read_flag_section"
+//CHECK: @implicitly_read_write = global i32 42, section "no_section_attributes"
+//CHECK: @long_var = global i32 42, section "long_section"
+//CHECK: @short_var = global i16 42, section "short_section"
//CHECK: define void @g()
//CHECK: define void @h() {{.*}} section ".my_code"
diff --git a/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp b/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
index 29926b91b795..6b500751d5d4 100644
--- a/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
+++ b/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
@@ -11,7 +11,7 @@ struct A {
};
// CHECK-LABEL: define void @_ZN5Test11AD2Ev
-// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test11AE, i64 0, i64 2), i8***
+// CHECK-NOT: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test11AE, i64 0, i64 2) to i32 (...)**), i32 (...)***
A::~A()
{
}
@@ -27,7 +27,7 @@ struct A {
};
// CHECK-LABEL: define void @_ZN5Test21AD2Ev
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test21AE, i64 0, i64 2), i8***
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test21AE, i64 0, i64 2) to i32 (...)**), i32 (...)***
A::~A() {
f();
}
@@ -50,7 +50,7 @@ struct A {
};
// CHECK-LABEL: define void @_ZN5Test31AD2Ev
-// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test31AE, i64 0, i64 2), i8***
+// CHECK-NOT: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test31AE, i64 0, i64 2) to i32 (...)**), i32 (...)***
A::~A() {
}
@@ -76,7 +76,7 @@ struct A {
};
// CHECK-LABEL: define void @_ZN5Test41AD2Ev
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test41AE, i64 0, i64 2), i8***
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test41AE, i64 0, i64 2) to i32 (...)**), i32 (...)***
A::~A()
{
}
@@ -100,7 +100,7 @@ struct A {
};
// CHECK-LABEL: define void @_ZN5Test51AD2Ev
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test51AE, i64 0, i64 2), i8***
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test51AE, i64 0, i64 2) to i32 (...)**), i32 (...)***
A::~A()
{
}
@@ -128,7 +128,7 @@ struct A {
};
// CHECK-LABEL: define void @_ZN5Test61AD2Ev
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test61AE, i64 0, i64 2), i8***
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test61AE, i64 0, i64 2) to i32 (...)**), i32 (...)***
A::~A()
{
}
@@ -154,7 +154,7 @@ struct A {
};
// CHECK-LABEL: define void @_ZN5Test71AD2Ev
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test71AE, i64 0, i64 2), i8***
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test71AE, i64 0, i64 2) to i32 (...)**), i32 (...)***
A::~A()
{
}
@@ -180,7 +180,7 @@ struct A {
};
// CHECK-LABEL: define void @_ZN5Test81AD2Ev
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test81AE, i64 0, i64 2), i8***
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test81AE, i64 0, i64 2) to i32 (...)**), i32 (...)***
A::~A()
{
}
diff --git a/test/CodeGenCXX/split-stacks.cpp b/test/CodeGenCXX/split-stacks.cpp
index 3e120344d6b6..76e1b79b8f1a 100644
--- a/test/CodeGenCXX/split-stacks.cpp
+++ b/test/CodeGenCXX/split-stacks.cpp
@@ -18,7 +18,7 @@ int nosplit() {
// CHECK-SEGSTK: define i32 @_Z3foov() [[SS:#[0-9]+]] {
// CHECK-SEGSTK: define i32 @_Z7nosplitv() [[NSS1:#[0-9]+]] {
-// CHECK-SEGSTK: define linkonce_odr i32 @_Z8tnosplitIiEiv() [[NSS2:#[0-9]+]] {
+// CHECK-SEGSTK: define linkonce_odr i32 @_Z8tnosplitIiEiv() [[NSS2:#[0-9]+]] comdat {
// CHECK-SEGSTK-NOT: [[NSS1]] = { {{.*}} "split-stack" {{.*}} }
// CHECK-SEGSTK-NOT: [[NSS2]] = { {{.*}} "split-stack" {{.*}} }
// CHECK-SEGSTK: [[SS]] = { {{.*}} "split-stack" {{.*}} }
@@ -27,7 +27,7 @@ int nosplit() {
// CHECK-NOSEGSTK: define i32 @_Z3foov() [[NSS0:#[0-9]+]] {
// CHECK-NOSEGSTK: define i32 @_Z7nosplitv() [[NSS1:#[0-9]+]] {
-// CHECK-NOSEGSTK: define linkonce_odr i32 @_Z8tnosplitIiEiv() [[NSS2:#[0-9]+]] {
+// CHECK-NOSEGSTK: define linkonce_odr i32 @_Z8tnosplitIiEiv() [[NSS2:#[0-9]+]] comdat {
// CHECK-NOSEGSTK-NOT: [[NSS1]] = { {{.*}} "split-stack" {{.*}} }
// CHECK-NOSEGSTK-NOT: [[NSS2]] = { {{.*}} "split-stack" {{.*}} }
// CHECK-NOSEGSTK-NOT: [[NSS3]] = { {{.*}} "split-stack" {{.*}} }
diff --git a/test/CodeGenCXX/static-data-member.cpp b/test/CodeGenCXX/static-data-member.cpp
index eea979494843..d41ac8fb3542 100644
--- a/test/CodeGenCXX/static-data-member.cpp
+++ b/test/CodeGenCXX/static-data-member.cpp
@@ -1,9 +1,13 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | \
+// RUN: FileCheck --check-prefix=MACHO %s
// CHECK: @_ZN5test11A1aE = constant i32 10, align 4
// CHECK: @_ZN5test212_GLOBAL__N_11AIiE1xE = internal global i32 0, align 4
-// CHECK: @_ZN5test31AIiE1xE = weak_odr global i32 0, align 4
-// CHECK: @_ZGVN5test31AIiE1xE = weak_odr global i64 0
+// CHECK: @_ZN5test31AIiE1xE = weak_odr global i32 0, comdat, align 4
+// CHECK: @_ZGVN5test31AIiE1xE = weak_odr global i64 0, comdat($_ZN5test31AIiE1xE)
+// MACHO: @_ZGVN5test31AIiE1xE = weak_odr global i64 0
+// MACHO-NOT: comdat
// CHECK: _ZN5test51U2k0E = global i32 0
// CHECK: _ZN5test51U2k1E = global i32 0
@@ -60,7 +64,9 @@ namespace test3 {
template <class T> int A<T>::x = foo();
template struct A<int>;
- // CHECK-LABEL: define internal void @__cxx_global_var_init1()
+ // CHECK-LABEL: define internal void @__cxx_global_var_init1() {{.*}} comdat($_ZN5test31AIiE1xE)
+ // MACHO-LABEL: define internal void @__cxx_global_var_init1()
+ // MACHO-NOT: comdat
// CHECK: [[GUARDBYTE:%.*]] = load i8* bitcast (i64* @_ZGVN5test31AIiE1xE to i8*)
// CHECK-NEXT: [[UNINITIALIZED:%.*]] = icmp eq i8 [[GUARDBYTE]], 0
// CHECK-NEXT: br i1 [[UNINITIALIZED]]
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
index d23ead47f385..66ff5b3fbabd 100644
--- a/test/CodeGenCXX/static-init.cpp
+++ b/test/CodeGenCXX/static-init.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-linuxs -emit-llvm -o - | FileCheck %s
// CHECK: @_ZZ1hvE1i = internal global i32 0, align 4
// CHECK: @base_req = global [4 x i8] c"foo\00", align 1
@@ -6,8 +6,9 @@
// CHECK: @_ZZN5test31BC1EvE1u = internal global { i8, [3 x i8] } { i8 97, [3 x i8] undef }, align 4
// CHECK: @_ZZN5test1L6getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 16
-// CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0
-// CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0
+
+// CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0, comdat, align
+// CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0, comdat{{$}}
struct A {
A();
@@ -34,6 +35,7 @@ void h() {
static const int i = a();
}
+// CHECK: define linkonce_odr void @_Z2h2v() {{.*}} comdat {
inline void h2() {
static int i = a();
}
diff --git a/test/CodeGenCXX/static-local-in-local-class.cpp b/test/CodeGenCXX/static-local-in-local-class.cpp
index ebf560ab9805..729b9376ae48 100644
--- a/test/CodeGenCXX/static-local-in-local-class.cpp
+++ b/test/CodeGenCXX/static-local-in-local-class.cpp
@@ -1,6 +1,13 @@
-// RUN: %clang_cc1 -emit-llvm -o %t %s
-// PR6769
+// RUN: %clang_cc1 -triple x86_64-linux -fblocks -emit-llvm -o - %s -std=c++1y | FileCheck %s
+// CHECK: @"_ZZNK3$_2clEvE1x" = internal global i32 42
+// CHECK: @_ZZ18static_local_labelPvE1q = linkonce_odr global i8* blockaddress(@_Z18static_local_labelPv, %{{.*}})
+// CHECK: @_ZZZL20block_deduced_returnvEUb_E1n = internal global i32 42
+// CHECK: @_ZZL14deduced_returnvE1n = internal global i32 42
+// CHECK: @"_ZZZNK17pr18020_constexpr3$_1clEvENKUlvE_clEvE2l2" =
+// CHECK: internal global i32* @"_ZZNK17pr18020_constexpr3$_1clEvE2l1"
+
+namespace pr6769 {
struct X {
static void f();
};
@@ -19,8 +26,9 @@ void X::f() {
}
(void)i;
}
+}
-// pr7101
+namespace pr7101 {
void foo() {
static int n = 0;
struct Helper {
@@ -30,4 +38,123 @@ void foo() {
};
Helper::Execute();
}
+}
+
+// These tests all break the assumption that the static var decl has to be
+// emitted before use of the var decl. This happens because we defer emission
+// of variables with internal linkage and no initialization side effects, such
+// as 'x'. Then we hit operator()() in 'f', and emit the callee before we emit
+// the arguments, so we emit the innermost function first.
+
+namespace pr18020_lambda {
+// Referring to l1 before emitting it used to crash.
+auto x = []() {
+ static int l1 = 0;
+ return [] { return l1; };
+};
+int f() { return x()(); }
+}
+
+// CHECK-LABEL: define internal i32 @"_ZZNK14pr18020_lambda3$_0clEvENKUlvE_clEv"
+// CHECK: load i32* @"_ZZNK14pr18020_lambda3$_0clEvE2l1"
+
+namespace pr18020_constexpr {
+// Taking the address of l1 in a constant expression used to crash.
+auto x = []() {
+ static int l1 = 0;
+ return [] {
+ static int *l2 = &l1;
+ return *l2;
+ };
+};
+int f() { return x()(); }
+}
+
+// CHECK-LABEL: define internal i32 @"_ZZNK17pr18020_constexpr3$_1clEvENKUlvE_clEv"
+// CHECK: load i32** @"_ZZZNK17pr18020_constexpr3$_1clEvENKUlvE_clEvE2l2"
+
+// Lambda-less reduction that references l1 before emitting it. This didn't
+// crash if you put it in a namespace.
+struct pr18020_class {
+ auto operator()() {
+ static int l1 = 0;
+ struct U {
+ int operator()() { return l1; }
+ };
+ return U();
+ }
+};
+static pr18020_class x;
+int pr18020_f() { return x()(); }
+
+// CHECK-LABEL: define linkonce_odr i32 @_ZZN13pr18020_classclEvEN1UclEv
+// CHECK: load i32* @_ZZN13pr18020_classclEvE2l1
+
+// In this test case, the function containing the static local will not be
+// emitted because it is unneeded. However, the operator call of the inner class
+// is called, and the static local is referenced and must be emitted.
+static auto deduced_return() {
+ static int n = 42;
+ struct S { int *operator()() { return &n; } };
+ return S();
+}
+extern "C" int call_deduced_return_operator() {
+ return *decltype(deduced_return())()();
+}
+
+// CHECK-LABEL: define i32 @call_deduced_return_operator()
+// CHECK: call i32* @_ZZL14deduced_returnvEN1SclEv(
+// CHECK: load i32* %
+// CHECK: ret i32 %
+
+// CHECK-LABEL: define internal i32* @_ZZL14deduced_returnvEN1SclEv(%struct.S* %this)
+// CHECK: ret i32* @_ZZL14deduced_returnvE1n
+
+static auto block_deduced_return() {
+ auto (^b)() = ^() {
+ static int n = 42;
+ struct S { int *operator()() { return &n; } };
+ return S();
+ };
+ return b();
+}
+extern "C" int call_block_deduced_return() {
+ return *decltype(block_deduced_return())()();
+}
+
+// CHECK-LABEL: define i32 @call_block_deduced_return()
+// CHECK: call i32* @_ZZZL20block_deduced_returnvEUb_EN1SclEv(
+// CHECK: load i32* %
+// CHECK: ret i32 %
+
+// CHECK-LABEL: define internal i32* @_ZZZL20block_deduced_returnvEUb_EN1SclEv(%struct.S.6* %this) #0 align 2 {
+// CHECK: ret i32* @_ZZZL20block_deduced_returnvEUb_E1n
+
+inline auto static_local_label(void *p) {
+ if (p)
+ goto *p;
+ static void *q = &&label;
+ struct S { static void *get() { return q; } };
+ return S();
+label:
+ __builtin_abort();
+}
+void *global_label = decltype(static_local_label(0))::get();
+
+// CHECK-LABEL: define linkonce_odr i8* @_ZZ18static_local_labelPvEN1S3getEv()
+// CHECK: %[[lbl:[^ ]*]] = load i8** @_ZZ18static_local_labelPvE1q
+// CHECK: ret i8* %[[lbl]]
+
+auto global_lambda = []() {
+ static int x = 42;
+ struct S { static int *get() { return &x; } };
+ return S();
+};
+extern "C" int use_global_lambda() {
+ return *decltype(global_lambda())::get();
+}
+// CHECK-LABEL: define i32 @use_global_lambda()
+// CHECK: call i32* @"_ZZNK3$_2clEvEN1S3getEv"()
+// CHECK-LABEL: define internal i32* @"_ZZNK3$_2clEvEN1S3getEv"()
+// CHECK: ret i32* @"_ZZNK3$_2clEvE1x"
diff --git a/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp b/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
index 98c09b84797d..20b409cbf996 100644
--- a/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
+++ b/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
@@ -1,25 +1,42 @@
-// RUN: %clang_cc1 %s -std=c++1y -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
-// CHECK: ; ModuleID
+// RUN: %clang_cc1 %s -std=c++1y -triple=x86_64-pc-linux -emit-llvm -o - | FileCheck --check-prefix=ELF --check-prefix=ALL %s
+// RUN: %clang_cc1 %s -std=c++1y -triple=x86_64-apple-darwin -emit-llvm -o - | FileCheck --check-prefix=MACHO --check-prefix=ALL %s
+
+// ALL: ; ModuleID
extern "C" int foo();
template<typename T> struct A { static int a; };
template<typename T> int A<T>::a = foo();
-// CHECK-NOT: @_ZN1AIcE1aE
+// ALLK-NOT: @_ZN1AIcE1aE
template<> int A<char>::a;
-// CHECK: @_ZN1AIbE1aE = global i32 10
+// ALL: @_ZN1AIbE1aE = global i32 10
template<> int A<bool>::a = 10;
-// CHECK: @llvm.global_ctors = appending global [7 x { i32, void ()*, i8* }]
-// CHECK: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* bitcast (i32* @_ZN1AIsE1aE to i8*) },
-// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered2:[^,]*]], i8* bitcast (i16* @_Z1xIsE to i8*) },
-// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered3:[^,]*]], i8* bitcast (i32* @_ZN2ns1aIiE1iE to i8*) },
-// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered4:[^,]*]], i8* bitcast (i32* @_ZN2ns1b1iIiEE to i8*) },
-// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered5:[^,]*]], i8* bitcast (i32* @_ZN1AIvE1aE to i8*) },
-// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered6:[^,]*]], i8* @_Z1xIcE },
-// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp, i8* null }]
+// ALL: @llvm.global_ctors = appending global [8 x { i32, void ()*, i8* }]
+
+// ELF: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* bitcast (i32* @_ZN1AIsE1aE to i8*) },
+// MACHO: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* null },
+
+// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered2:[^,]*]], i8* bitcast (i16* @_Z1xIsE to i8*) },
+// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered2:[^,]*]], i8* null },
+
+// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered3:[^,]*]], i8* bitcast (i32* @_ZN2ns1aIiE1iE to i8*) },
+// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered3:[^,]*]], i8* null },
+
+// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered4:[^,]*]], i8* bitcast (i32* @_ZN2ns1b1iIiEE to i8*) },
+// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered4:[^,]*]], i8* null },
+
+// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered5:[^,]*]], i8* bitcast (i32* @_ZN1AIvE1aE to i8*) },
+// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered5:[^,]*]], i8* null },
+
+// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered6:[^,]*]], i8* @_Z1xIcE },
+// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered6:[^,]*]], i8* null },
+
+// ALL: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered7:[^,]*]], i8* null },
+
+// ALL: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp, i8* null }]
template int A<short>::a; // Unordered
int b = foo();
@@ -52,45 +69,57 @@ struct b {
template<typename T> T b::i = foo();
template int b::i<int>;
}
-// CHECK: define internal void @[[unordered1]]
-// CHECK: call i32 @foo()
-// CHECK: store {{.*}} @_ZN1AIsE1aE
-// CHECK: ret
-
-// CHECK: define internal void @[[unordered2]]
-// CHECK: call i32 @foo()
-// CHECK: store {{.*}} @_Z1xIsE
-// CHECK: ret
-
-// CHECK: define internal void @[[unordered3]]
-// CHECK: call i32 @foo()
-// CHECK: store {{.*}} @_ZN2ns1aIiE1iE
-// CHECK: ret
-
-// CHECK: define internal void @[[unordered4]]
-// CHECK: call i32 @foo()
-// CHECK: store {{.*}} @_ZN2ns1b1iIiEE
-// CHECK: ret
-
-// CHECK: define internal void @[[unordered5]]
-// CHECK: call i32 @foo()
-// CHECK: store {{.*}} @_ZN1AIvE1aE
-// CHECK: ret
-
-// CHECK: define internal void @[[unordered6]]
-// CHECK: call i32 @foo()
-// CHECK: store {{.*}} @_Z1xIcE
-// CHECK: ret
-
-// CHECK: define internal void @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp()
+
+namespace {
+template<typename T> struct Internal { static int a; };
+template<typename T> int Internal<T>::a = foo();
+}
+int *use_internal_a = &Internal<int>::a;
+
+// ALL: define internal void @[[unordered1]](
+// ALL: call i32 @foo()
+// ALL: store {{.*}} @_ZN1AIsE1aE
+// ALL: ret
+
+// ALL: define internal void @[[unordered2]](
+// ALL: call i32 @foo()
+// ALL: store {{.*}} @_Z1xIsE
+// ALL: ret
+
+// ALL: define internal void @[[unordered3]](
+// ALL: call i32 @foo()
+// ALL: store {{.*}} @_ZN2ns1aIiE1iE
+// ALL: ret
+
+// ALL: define internal void @[[unordered4]](
+// ALL: call i32 @foo()
+// ALL: store {{.*}} @_ZN2ns1b1iIiEE
+// ALL: ret
+
+// ALL: define internal void @[[unordered5]](
+// ALL: call i32 @foo()
+// ALL: store {{.*}} @_ZN1AIvE1aE
+// ALL: ret
+
+// ALL: define internal void @[[unordered6]](
+// ALL: call i32 @foo()
+// ALL: store {{.*}} @_Z1xIcE
+// ALL: ret
+
+// ALL: define internal void @[[unordered7]](
+// ALL: call i32 @foo()
+// ALL: store {{.*}} @_ZN12_GLOBAL__N_18InternalIiE1aE
+// ALL: ret
+
+// ALL: define internal void @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp()
// We call unique stubs for every ordered dynamic initializer in the TU.
-// CHECK: call
-// CHECK: call
-// CHECK: call
-// CHECK: call
-// CHECK: call
-// CHECK: call
-// CHECK: call
-// CHECK: call
-// CHECK-NOT: call
-// CHECK: ret
+// ALL: call
+// ALL: call
+// ALL: call
+// ALL: call
+// ALL: call
+// ALL: call
+// ALL: call
+// ALL: call
+// ALL-NOT: call
+// ALL: ret
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index 7f5c7af03865..89677cb1e4e9 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -42,6 +42,13 @@ namespace PR20227 {
// CHECK: @_ZGRN7PR202271cE_ = private global
}
+namespace BraceInit {
+ typedef const int &CIR;
+ CIR x = CIR{3};
+ // CHECK: @_ZGRN9BraceInit1xE_ = private constant i32 3
+ // CHECK: @_ZN9BraceInit1xE = constant i32* @_ZGRN9BraceInit1xE_
+}
+
struct A {
A();
~A();
diff --git a/test/CodeGenCXX/try-catch.cpp b/test/CodeGenCXX/try-catch.cpp
index 89f229fee375..b50214ecdb97 100644
--- a/test/CodeGenCXX/try-catch.cpp
+++ b/test/CodeGenCXX/try-catch.cpp
@@ -11,3 +11,11 @@ void f() {
} catch (const X x) {
}
}
+
+void h() {
+ try {
+ throw "ABC";
+ // CHECK: @_ZTIPKc to i8
+ } catch (char const(&)[4]) {
+ }
+}
diff --git a/test/CodeGenCXX/unknown-anytype.cpp b/test/CodeGenCXX/unknown-anytype.cpp
index aacb8493ef3c..e6f887bea083 100644
--- a/test/CodeGenCXX/unknown-anytype.cpp
+++ b/test/CodeGenCXX/unknown-anytype.cpp
@@ -115,3 +115,11 @@ extern "C" __unknown_anytype test10_any(...);
void test10() {
(void) test10_any(), (void) test10_any();
}
+
+extern "C" __unknown_anytype malloc(...);
+void test11() {
+ void *s = (void*)malloc(12);
+ // COMMON: call i8* (i32, ...)* @malloc(i32 12)
+ void *d = (void*)malloc(435);
+ // COMMON: call i8* (i32, ...)* @malloc(i32 435)
+}
diff --git a/test/CodeGenCXX/vararg-non-pod-ms-compat.cpp b/test/CodeGenCXX/vararg-non-pod-ms-compat.cpp
new file mode 100644
index 000000000000..668fadf7b589
--- /dev/null
+++ b/test/CodeGenCXX/vararg-non-pod-ms-compat.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -Wno-error=non-pod-varargs -triple i686-pc-win32 -fms-compatibility -emit-llvm -o - %s | FileCheck %s -check-prefix=X86 -check-prefix=CHECK
+// RUN: %clang_cc1 -Wno-error=non-pod-varargs -triple x86_64-pc-win32 -fms-compatibility -emit-llvm -o - %s | FileCheck %s -check-prefix=X64 -check-prefix=CHECK
+
+struct X {
+ X();
+ ~X();
+ int data;
+};
+
+void vararg(...);
+
+void test(X x) {
+ // CHECK-LABEL: define void @"\01?test@@YAXUX@@@Z"
+
+ // X86: %[[argmem:[^ ]*]] = alloca inalloca <{ %struct.X }>
+ // X86: call void (<{ %struct.X }>*, ...)* bitcast (void (...)* @"\01?vararg@@YAXZZ" to void (<{ %struct.X }>*, ...)*)(<{ %struct.X }>* inalloca %[[argmem]])
+
+ // X64: alloca %struct.X
+
+ // X64: %[[agg:[^ ]*]] = alloca %struct.X
+ // X64: %[[valptr:[^ ]*]] = getelementptr %struct.X* %[[agg]], i32 0, i32 0
+ // X64: %[[val:[^ ]*]] = load i32* %[[valptr]]
+ // X64: call void (...)* @"\01?vararg@@YAXZZ"(i32 %[[val]])
+
+ // CHECK-NOT: llvm.trap
+ vararg(x);
+ // CHECK: ret void
+}
diff --git a/test/CodeGenCXX/virtual-base-cast.cpp b/test/CodeGenCXX/virtual-base-cast.cpp
index 6a4894b63b70..0dcf319d7dc2 100644
--- a/test/CodeGenCXX/virtual-base-cast.cpp
+++ b/test/CodeGenCXX/virtual-base-cast.cpp
@@ -20,11 +20,10 @@ A* a() { return x; }
// MSVC: @"\01?a@@YAPAUA@@XZ"() [[NUW:#[0-9]+]] {
// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0
-// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
-// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]]
-// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 4
-// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
-// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i32**
+// MSVC: %[[vbtable:.*]] = load i32** %[[vbptr]]
+// MSVC: %[[entry:.*]] = getelementptr inbounds i32* {{.*}}, i32 1
+// MSVC: %[[offset:.*]] = load i32* %[[entry]]
// MSVC: add nsw i32 0, %[[offset]]
// MSVC: }
@@ -38,11 +37,10 @@ B* b() { return x; }
// Same as 'a' except we use a different vbtable offset.
// MSVC: @"\01?b@@YAPAUB@@XZ"() [[NUW:#[0-9]+]] {
// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0
-// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
-// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]]
-// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 8
-// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
-// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i32**
+// MSVC: %[[vbtable:.*]] = load i32** %[[vbptr]]
+// MSVC: %[[entry:.*]] = getelementptr inbounds i32* {{.*}}, i32 2
+// MSVC: %[[offset:.*]] = load i32* %[[entry]]
// MSVC: add nsw i32 0, %[[offset]]
// MSVC: }
@@ -58,11 +56,10 @@ BB* c() { return x; }
// Same as 'a' except we use a different vbtable offset.
// MSVC: @"\01?c@@YAPAUBB@@XZ"() [[NUW:#[0-9]+]] {
// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0
-// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
-// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]]
-// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 16
-// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
-// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i32**
+// MSVC: %[[vbtable:.*]] = load i32** %[[vbptr]]
+// MSVC: %[[entry:.*]] = getelementptr inbounds i32* {{.*}}, i32 4
+// MSVC: %[[offset:.*]] = load i32* %[[entry]]
// MSVC: add nsw i32 0, %[[offset]]
// MSVC: }
@@ -78,11 +75,10 @@ BB* d() { return y; }
// final add.
// MSVC: @"\01?d@@YAPAUBB@@XZ"() [[NUW:#[0-9]+]] {
// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 4
-// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
-// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]]
-// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 16
-// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
-// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i32**
+// MSVC: %[[vbtable:.*]] = load i32** %[[vbptr]]
+// MSVC: %[[entry:.*]] = getelementptr inbounds i32* {{.*}}, i32 4
+// MSVC: %[[offset:.*]] = load i32* %[[entry]]
// MSVC: add nsw i32 4, %[[offset]]
// MSVC: }
diff --git a/test/CodeGenCXX/virtual-destructor-calls.cpp b/test/CodeGenCXX/virtual-destructor-calls.cpp
index 3e7fa8293af8..f0e3dc58b641 100644
--- a/test/CodeGenCXX/virtual-destructor-calls.cpp
+++ b/test/CodeGenCXX/virtual-destructor-calls.cpp
@@ -17,8 +17,8 @@ struct B : A {
// CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev
// (aliases from C)
-// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev
// CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev
+// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev
// Base dtor: actually calls A's base dtor.
// CHECK-LABEL: define void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr
diff --git a/test/CodeGenCXX/virtual-operator-call.cpp b/test/CodeGenCXX/virtual-operator-call.cpp
index 72d49c230093..727c8e140fd8 100644
--- a/test/CodeGenCXX/virtual-operator-call.cpp
+++ b/test/CodeGenCXX/virtual-operator-call.cpp
@@ -1,10 +1,13 @@
// RUN: %clang_cc1 %s -triple i386-unknown-unknown -emit-llvm -o - | FileCheck %s
struct A {
- virtual int operator-() = 0;
+ virtual int operator-();
};
-void f(A *a) {
+void f(A a, A *ap) {
+ // CHECK: call i32 @_ZN1AngEv(%struct.A* %a)
+ -a;
+
// CHECK: call i32 %
- -*a;
+ -*ap;
}
diff --git a/test/CodeGenCXX/vla-lambda-capturing.cpp b/test/CodeGenCXX/vla-lambda-capturing.cpp
new file mode 100644
index 000000000000..e8fd0a1fd3ab
--- /dev/null
+++ b/test/CodeGenCXX/vla-lambda-capturing.cpp
@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -emit-pch -o %t
+// RUN: %clang_cc1 %s -std=c++11 -include-pch %t -emit-llvm -o - | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+
+typedef __INTPTR_TYPE__ intptr_t;
+
+// CHECK-DAG: [[CAP_TYPE1:%.+]] = type { [[INTPTR_T:i.+]], [[INTPTR_T]]*, [[INTPTR_T]]* }
+// CHECK-DAG: [[CAP_TYPE2:%.+]] = type { [[INTPTR_T]], [[INTPTR_T]]* }
+// CHECK-DAG: [[CAP_TYPE3:%.+]] = type { [[INTPTR_T]]*, [[INTPTR_T]], [[INTPTR_T]], [[INTPTR_T]]*, [[INTPTR_T]]* }
+// CHECK-DAG: [[CAP_TYPE4:%.+]] = type { [[INTPTR_T]]*, [[INTPTR_T]], [[INTPTR_T]]*, [[INTPTR_T]], [[INTPTR_T]]* }
+
+// CHECK: define void [[G:@.+]](
+// CHECK: [[N_ADDR:%.+]] = alloca [[INTPTR_T]]
+// CHECK: store [[INTPTR_T]] %{{.+}}, [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[N_VAL:%.+]] = load [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[CAP_EXPR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0
+// CHECK: store [[INTPTR_T]] [[N_VAL]], [[INTPTR_T]]* [[CAP_EXPR_REF]]
+// CHECK: [[CAP_BUFFER_ADDR:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1
+// CHECK: store [[INTPTR_T]]* %{{.+}}, [[INTPTR_T]]** [[CAP_BUFFER_ADDR]]
+// CHECK: [[CAP_N_REF:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 2
+// CHECK: store [[INTPTR_T]]* [[N_ADDR]], [[INTPTR_T]]** [[CAP_N_REF]]
+// CHECK: call void [[G_LAMBDA:@.+]]([[CAP_TYPE1]]* [[CAP_ARG]])
+// CHECK: ret void
+void g(intptr_t n) {
+ intptr_t buffer[n];
+ [&buffer, &n]() {
+ __typeof(buffer) x;
+ }();
+}
+
+// CHECK: void [[G_LAMBDA]]([[CAP_TYPE1]]*
+// CHECK: [[THIS:%.+]] = load [[CAP_TYPE1]]**
+// CHECK: [[N_ADDR:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[THIS]], i{{.+}} 0, i{{.+}} 0
+// CHECK: [[N:%.+]] = load [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[BUFFER_ADDR:%.+]] = getelementptr inbounds [[CAP_TYPE1]]* [[THIS]], i{{.+}} 0, i{{.+}} 1
+// CHECK: [[BUFFER:%.+]] = load [[INTPTR_T]]** [[BUFFER_ADDR]]
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: alloca [[INTPTR_T]], [[INTPTR_T]] [[N]]
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+
+template <typename T>
+void f(T n, T m) {
+ intptr_t buffer[n + m];
+ [&buffer]() {
+ __typeof(buffer) x;
+ }();
+}
+
+template <typename T>
+intptr_t getSize(T);
+
+template <typename T>
+void b(intptr_t n, T arg) {
+ typedef intptr_t ArrTy[getSize(arg)];
+ ArrTy buffer2;
+ ArrTy buffer1[n + arg];
+ intptr_t a;
+ [&]() {
+ n = sizeof(buffer1[n]);
+ [&](){
+ n = sizeof(buffer2);
+ n = sizeof(buffer1);
+ }();
+ }();
+}
+
+// CHECK-LABEL: @main
+int main() {
+ // CHECK: call void [[G]]([[INTPTR_T]] [[INTPTR_T_ATTR:(signext )?]]1)
+ g((intptr_t)1);
+ // CHECK: call void [[F_INT:@.+]]([[INTPTR_T]] [[INTPTR_T_ATTR]]1, [[INTPTR_T]] [[INTPTR_T_ATTR]]2)
+ f((intptr_t)1, (intptr_t)2);
+ // CHECK: call void [[B_INT:@.+]]([[INTPTR_T]] [[INTPTR_T_ATTR]]12, [[INTPTR_T]] [[INTPTR_T_ATTR]]13)
+ b((intptr_t)12, (intptr_t)13);
+ // CHECK: ret i32 0
+ return 0;
+}
+
+// CHECK: void [[F_INT]]([[INTPTR_T]]
+// CHECK: [[SIZE:%.+]] = add
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: [[BUFFER_ADDR:%.+]] = alloca [[INTPTR_T]], [[INTPTR_T]] [[SIZE]]
+// CHECK: [[CAP_SIZE_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0
+// CHECK: store [[INTPTR_T]] [[SIZE]], [[INTPTR_T]]* [[CAP_SIZE_REF]]
+// CHECK: [[CAP_BUFFER_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1
+// CHECK: store [[INTPTR_T]]* [[BUFFER_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER_ADDR_REF]]
+// CHECK: call void [[F_INT_LAMBDA:@.+]]([[CAP_TYPE2]]* [[CAP_ARG]])
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+// CHECK: void [[B_INT]]([[INTPTR_T]]
+// CHECK: [[SIZE1:%.+]] = call [[INTPTR_T]]
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: [[BUFFER2_ADDR:%.+]] = alloca [[INTPTR_T]], [[INTPTR_T]] [[SIZE1]]
+// CHECK: [[SIZE2:%.+]] = add
+// CHECK: [[BUFFER1_ADDR:%.+]] = alloca [[INTPTR_T]], [[INTPTR_T]]
+// CHECK: [[CAP_N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 0
+// CHECK: store [[INTPTR_T]]* {{%.+}}, [[INTPTR_T]]** [[CAP_N_ADDR_REF]]
+// CHECK: [[CAP_SIZE2_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1
+// CHECK: store i{{[0-9]+}} [[SIZE2]], i{{[0-9]+}}* [[CAP_SIZE2_REF]]
+// CHECK: [[CAP_SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 2
+// CHECK: store i{{[0-9]+}} [[SIZE1]], i{{[0-9]+}}* [[CAP_SIZE1_REF]]
+// CHECK: [[CAP_BUFFER1_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 3
+// CHECK: store [[INTPTR_T]]* [[BUFFER1_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER1_ADDR_REF]]
+// CHECK: [[CAP_BUFFER2_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 4
+// CHECK: store [[INTPTR_T]]* [[BUFFER2_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER2_ADDR_REF]]
+// CHECK: call void [[B_INT_LAMBDA:@.+]]([[CAP_TYPE3]]* [[CAP_ARG]])
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+
+// CHECK: define {{.*}} void [[B_INT_LAMBDA]]([[CAP_TYPE3]]*
+// CHECK: [[SIZE2_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[SIZE2:%.+]] = load i{{[0-9]+}}* [[SIZE2_REF]]
+// CHECK: [[SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[SIZE1:%.+]] = load i{{[0-9]+}}* [[SIZE1_REF]]
+// CHECK: [[N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[N_ADDR:%.+]] = load [[INTPTR_T]]** [[N_ADDR_REF]]
+// CHECK: [[N:%.+]] = load [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[BUFFER1_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[BUFFER1_ADDR:%.+]] = load [[INTPTR_T]]** [[BUFFER1_ADDR_REF]]
+// CHECK: [[ELEM_OFFSET:%.+]] = mul {{.*}} i{{[0-9]+}} [[N]], [[SIZE1]]
+// CHECK: [[ELEM_ADDR:%.+]] = getelementptr inbounds [[INTPTR_T]]* [[BUFFER1_ADDR]], i{{[0-9]+}} [[ELEM_OFFSET]]
+// CHECK: [[SIZEOF:%.+]] = mul {{.*}} i{{[0-9]+}} {{[0-9]+}}, [[SIZE1]]
+// CHECK: [[N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[N_ADDR:%.+]] = load [[INTPTR_T]]** [[N_ADDR_REF]]
+// CHECK: store [[INTPTR_T]] {{%.+}}, [[INTPTR_T]]* [[N_ADDR]]
+// CHECK: [[N_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[CAP:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[N_ADDR_REF_ORIG:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[N_ADDR_ORIG:%.+]] = load [[INTPTR_T]]** [[N_ADDR_REF_ORIG]]
+// CHECK: store [[INTPTR_T]]* [[N_ADDR_ORIG]], [[INTPTR_T]]** [[N_ADDR_REF]]
+// CHECK: [[SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[CAP]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: store i{{[0-9]+}} [[SIZE1]], i{{[0-9]+}}* [[SIZE1_REF]]
+// CHECK: [[BUFFER2_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[CAP]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[BUFFER2_ADDR_REF_ORIG:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
+// CHECK: [[BUFFER2_ADDR_ORIG:%.+]] = load [[INTPTR_T]]** [[BUFFER2_ADDR_REF_ORIG]]
+// CHECK: store [[INTPTR_T]]* [[BUFFER2_ADDR_ORIG]], [[INTPTR_T]]** [[BUFFER2_ADDR_REF]]
+// CHECK: [[SIZE2_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[CAP]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: store i{{[0-9]+}} [[SIZE2]], i{{[0-9]+}}* [[SIZE2_REF]]
+// CHECK: [[BUFFER1_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[CAP]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
+// CHECK: [[BUFFER1_ADDR_REF_ORIG:%.+]] = getelementptr inbounds [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[BUFFER1_ADDR_ORIG:%.+]] = load [[INTPTR_T]]** [[BUFFER1_ADDR_REF_ORIG]]
+// CHECK: store [[INTPTR_T]]* [[BUFFER1_ADDR_ORIG]], [[INTPTR_T]]** [[BUFFER1_ADDR_REF]]
+// CHECK: call void [[B_INT_LAMBDA_LAMBDA:@.+]]([[CAP_TYPE4]]* [[CAP]])
+// CHECK: ret void
+
+// CHECK: define {{.*}} void [[B_INT_LAMBDA_LAMBDA]]([[CAP_TYPE4]]*
+// CHECK: [[SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[THIS:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[SIZE1:%.+]] = load i{{[0-9]+}}* [[SIZE1_REF]]
+// CHECK: [[SIZE2_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[SIZE2:%.+]] = load i{{[0-9]+}}* [[SIZE2_REF]]
+// CHECK: [[BUFFER2_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[BUFFER2_ADDR:%.+]] = load [[INTPTR_T]]** [[BUFFER2_ADDR_REF]]
+// CHECK: [[SIZEOF_BUFFER2:%.+]] = mul {{.*}} i{{[0-9]+}} {{[0-9]+}}, [[SIZE1]]
+// CHECK: [[BUFFER1_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
+// CHECK: [[BUFFER1_ADDR:%.+]] = load [[INTPTR_T]]** [[BUFFER1_ADDR_REF]]
+// CHECK: [[MUL:%.+]] = mul {{.*}} i{{[0-9]+}} [[SIZE2]], [[SIZE1]]
+// CHECK: mul {{.*}} i{{[0-9]+}} {{[0-9]+}}, [[MUL]]
+// CHECK: ret void
+
+// CHECK: void [[F_INT_LAMBDA]]([[CAP_TYPE2]]*
+// CHECK: [[THIS:%.+]] = load [[CAP_TYPE2]]**
+// CHECK: [[SIZE_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]]* [[THIS]], i{{.+}} 0, i{{.+}} 0
+// CHECK: [[SIZE:%.+]] = load [[INTPTR_T]]* [[SIZE_REF]]
+// CHECK: call i{{.+}}* @llvm.stacksave()
+// CHECK: alloca [[INTPTR_T]], [[INTPTR_T]] [[SIZE]]
+// CHECK: call void @llvm.stackrestore(
+// CHECK: ret void
+#endif
diff --git a/test/CodeGenCXX/vlt_to_reference.cpp b/test/CodeGenCXX/vlt_to_reference.cpp
new file mode 100644
index 000000000000..49d7f1aa975f
--- /dev/null
+++ b/test/CodeGenCXX/vlt_to_reference.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK-LABEL: @main
+
+struct dyn_array {
+ int size;
+ int data[];
+};
+
+int foo(dyn_array **&d) {
+ return (*d)->data[1];
+}
+
+int main()
+{
+ dyn_array **d;
+ return foo(d);
+
+ // CHECK: call {{.+}} @{{.+}}foo{{.+}}(
+ // CHECK: ret i{{[0-9]+}}
+}
+
diff --git a/test/CodeGenCXX/vtable-align.cpp b/test/CodeGenCXX/vtable-align.cpp
new file mode 100644
index 000000000000..f1f10c07df2d
--- /dev/null
+++ b/test/CodeGenCXX/vtable-align.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -triple=i386-apple-darwin10 -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-32
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-64
+
+struct A {
+ virtual void f();
+ virtual void g();
+ virtual void h();
+};
+
+void A::f() {}
+
+// CHECK-32: @_ZTV1A = unnamed_addr constant [5 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast (void (%struct.A*)* @_ZN1A1fEv to i8*), i8* bitcast (void (%struct.A*)* @_ZN1A1gEv to i8*), i8* bitcast (void (%struct.A*)* @_ZN1A1hEv to i8*)], align 4
+
+// CHECK-64: @_ZTV1A = unnamed_addr constant [5 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast (void (%struct.A*)* @_ZN1A1fEv to i8*), i8* bitcast (void (%struct.A*)* @_ZN1A1gEv to i8*), i8* bitcast (void (%struct.A*)* @_ZN1A1hEv to i8*)], align 8
diff --git a/test/CodeGenCXX/vtable-holder-self-reference.cpp b/test/CodeGenCXX/vtable-holder-self-reference.cpp
new file mode 100644
index 000000000000..05e6d71bae9c
--- /dev/null
+++ b/test/CodeGenCXX/vtable-holder-self-reference.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm -gdwarf-2 -x c++ -o - %s | FileCheck %s
+//
+// PR21941: crasher for self-referencing DW_TAG_structure_type node. If we get
+// rid of self-referenceing structure_types (PR21902), then it should be safe
+// to just kill this test.
+//
+// CHECK: ![[SELF:[0-9]+]] = distinct !{!"0x13\00B\00{{[^"]*}}", {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, ![[SELF]], {{[^}]+}}} ; [ DW_TAG_structure_type ] [B]
+
+void foo() {
+ struct V {
+ int vi;
+ };
+ struct B : virtual V {};
+ B b;
+}
diff --git a/test/CodeGenCXX/vtable-pointer-initialization.cpp b/test/CodeGenCXX/vtable-pointer-initialization.cpp
index 85e08d8f0f9b..835760d165c0 100644
--- a/test/CodeGenCXX/vtable-pointer-initialization.cpp
+++ b/test/CodeGenCXX/vtable-pointer-initialization.cpp
@@ -21,13 +21,13 @@ struct A : Base {
// CHECK-LABEL: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr
// CHECK: call void @_ZN4BaseC2Ev(
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) to i32 (...)**)
// CHECK: call void @_ZN5FieldC1Ev(
// CHECK: ret void
A::A() { }
// CHECK-LABEL: define void @_ZN1AD2Ev(%struct.A* %this) unnamed_addr
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) to i32 (...)**)
// CHECK: call void @_ZN5FieldD1Ev(
// CHECK: call void @_ZN4BaseD2Ev(
// CHECK: ret void
@@ -45,13 +45,13 @@ void f() { B b; }
// CHECK: call void @_ZN1BC2Ev(
// CHECK-LABEL: define linkonce_odr void @_ZN1BD1Ev(%struct.B* %this) unnamed_addr
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) to i32 (...)**)
// CHECK: call void @_ZN5FieldD1Ev(
// CHECK: call void @_ZN4BaseD2Ev(
// CHECK: ret void
// CHECK-LABEL: define linkonce_odr void @_ZN1BC2Ev(%struct.B* %this) unnamed_addr
// CHECK: call void @_ZN4BaseC2Ev(
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
+// CHECK: store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) to i32 (...)**)
// CHECK: call void @_ZN5FieldC1Ev
// CHECK: ret void
diff --git a/test/CodeGenCXX/x86_64-arguments-nacl-x32.cpp b/test/CodeGenCXX/x86_64-arguments-nacl-x32.cpp
new file mode 100644
index 000000000000..bb9bd888b20f
--- /dev/null
+++ b/test/CodeGenCXX/x86_64-arguments-nacl-x32.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-nacl -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnux32 -emit-llvm -o - %s | FileCheck %s
+
+struct test_struct {};
+typedef int test_struct::* test_struct_mdp;
+typedef int (test_struct::*test_struct_mfp)();
+
+// CHECK-LABEL: define i32 @{{.*}}f_mdp{{.*}}(i32 %a)
+test_struct_mdp f_mdp(test_struct_mdp a) { return a; }
+
+// CHECK-LABEL: define {{.*}} @{{.*}}f_mfp{{.*}}(i64 %a.coerce)
+test_struct_mfp f_mfp(test_struct_mfp a) { return a; }
+
+// A struct with <= 12 bytes before a member data pointer should still
+// be allowed in registers, since the member data pointer is only 4 bytes.
+// CHECK-LABEL: define void @{{.*}}f_struct_with_mdp{{.*}}(i64 %a.coerce0, i64 %a.coerce1)
+struct struct_with_mdp { char *a; char *b; char *c; test_struct_mdp d; };
+void f_struct_with_mdp(struct_with_mdp a) { (void)a; }
+
+struct struct_with_mdp_too_much {
+ char *a; char *b; char *c; char *d; test_struct_mdp e;
+};
+// CHECK-LABEL: define void @{{.*}}f_struct_with_mdp_too_much{{.*}}({{.*}} byval {{.*}} %a)
+void f_struct_with_mdp_too_much(struct_with_mdp_too_much a) {
+ (void)a;
+}
+
+// A struct with <= 8 bytes before a member function pointer should still
+// be allowed in registers, since the member function pointer is only 8 bytes.
+// CHECK-LABEL: define void @{{.*}}f_struct_with_mfp_0{{.*}}(i64 %a.coerce0, i32 %a.coerce1)
+struct struct_with_mfp_0 { char *a; test_struct_mfp b; };
+void f_struct_with_mfp_0(struct_with_mfp_0 a) { (void)a; }
+
+// CHECK-LABEL: define void @{{.*}}f_struct_with_mfp_1{{.*}}(i64 %a.coerce0, i64 %a.coerce1)
+struct struct_with_mfp_1 { char *a; char *b; test_struct_mfp c; };
+void f_struct_with_mfp_1(struct_with_mfp_1 a) { (void)a; }
+
+// CHECK-LABEL: define void @{{.*}}f_struct_with_mfp_too_much{{.*}}({{.*}} byval {{.*}} %a, i32 %x)
+struct struct_with_mfp_too_much {
+ char *a; char *b; char *c; test_struct_mfp d;
+};
+void f_struct_with_mfp_too_much(struct_with_mfp_too_much a, int x) {
+ (void)a;
+}
diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp
index 2172e0810d75..815ef6111a9a 100644
--- a/test/CodeGenCXX/x86_64-arguments.cpp
+++ b/test/CodeGenCXX/x86_64-arguments.cpp
@@ -32,6 +32,21 @@ typedef int (s4::*s4_mfp)();
s4_mdp f4_0(s4_mdp a) { return a; }
s4_mfp f4_1(s4_mfp a) { return a; }
+// A struct with <= one eightbyte before a member data pointer should still
+// be allowed in registers.
+// CHECK-LABEL: define void @{{.*}}f_struct_with_mdp{{.*}}(i8* %a.coerce0, i64 %a.coerce1)
+struct struct_with_mdp { char *a; s4_mdp b; };
+void f_struct_with_mdp(struct_with_mdp a) { (void)a; }
+
+// A struct with anything before a member function will be too big and
+// goes in memory.
+// CHECK-LABEL: define void @{{.*}}f_struct_with_mfp_0{{.*}}(%struct{{.*}} byval align 8 %a)
+struct struct_with_mfp_0 { char a; s4_mfp b; };
+void f_struct_with_mfp_0(struct_with_mfp_0 a) { (void)a; }
+
+// CHECK-LABEL: define void @{{.*}}f_struct_with_mfp_1{{.*}}(%struct{{.*}} byval align 8 %a)
+struct struct_with_mfp_1 { void *a; s4_mfp b; };
+void f_struct_with_mfp_1(struct_with_mfp_1 a) { (void)a; }
namespace PR7523 {
struct StringRef {
diff --git a/test/CodeGenObjC/2010-02-09-DbgSelf.m b/test/CodeGenObjC/2010-02-09-DbgSelf.m
index 9aebe3d619bc..d70b3d68e827 100644
--- a/test/CodeGenObjC/2010-02-09-DbgSelf.m
+++ b/test/CodeGenObjC/2010-02-09-DbgSelf.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -x objective-c -emit-llvm -g < %s | FileCheck %s
// Test to check that "self" argument is assigned a location.
-// CHECK: call void @llvm.dbg.declare(metadata !{%0** %{{[^}]+}}}, metadata [[SELF:![0-9]*]])
+// CHECK: call void @llvm.dbg.declare(metadata %0** %{{[^,]+}}, metadata [[SELF:![0-9]*]], metadata !{{.*}})
// CHECK: [[SELF]] = {{.*}} ; [ DW_TAG_arg_variable ] [self]
@interface Foo
diff --git a/test/CodeGenObjC/2010-02-15-Dbg-MethodStart.m b/test/CodeGenObjC/2010-02-15-Dbg-MethodStart.m
index 5186b20310a6..3fb98c54da26 100644
--- a/test/CodeGenObjC/2010-02-15-Dbg-MethodStart.m
+++ b/test/CodeGenObjC/2010-02-15-Dbg-MethodStart.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c -emit-llvm -g < %s | grep subprogram | grep "i32 9"
+// RUN: %clang_cc1 -x objective-c -emit-llvm -g < %s | FileCheck "%s"
// Test to check that subprogram start location.
@interface Foo
@@ -7,6 +7,7 @@
@implementation Foo
-(int) barMethod {
+// CHECK: [ DW_TAG_subprogram ] [line [[@LINE-1]]]
int i = 0;
int j = 1;
int k = 1;
diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m
index ec767d391fd6..46c5da0dd002 100644
--- a/test/CodeGenObjC/arc-foreach.m
+++ b/test/CodeGenObjC/arc-foreach.m
@@ -46,7 +46,7 @@ void test0(NSArray *array) {
// CHECK-LP64-NEXT: [[SAVED_ARRAY:%.*]] = bitcast i8* [[T2]] to [[ARRAY_T]]*
// Call the enumeration method.
-// CHECK-LP64-NEXT: [[T0:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-LP64-NEXT: [[T0:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
// CHECK-LP64-NEXT: [[SIZE:%.*]] = call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, [[STATE_T]]*, [16 x i8*]*, i64)*)(i8* [[T1]], i8* [[T0]], [[STATE_T]]* [[STATE]], [16 x i8*]* [[BUFFER]], i64 16)
@@ -69,7 +69,7 @@ void test0(NSArray *array) {
// CHECK-LP64: call void @use_block(
// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[D0]], i8* null)
-// CHECK-LP64: [[T0:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-LP64: [[T0:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
// CHECK-LP64-NEXT: [[SIZE:%.*]] = call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, [[STATE_T]]*, [16 x i8*]*, i64)*)(i8* [[T1]], i8* [[T0]], [[STATE_T]]* [[STATE]], [16 x i8*]* [[BUFFER]], i64 16)
@@ -135,7 +135,7 @@ void test2(Test2 *a) {
// CHECK-LP64-NEXT: [[COLL:%.*]] = bitcast i8* [[T2]] to [[ARRAY_T]]*
// Make sure it's not immediately released before starting the iteration.
-// CHECK-LP64-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-LP64-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[ARRAY_T]]* [[COLL]] to i8*
// CHECK-LP64-NEXT: @objc_msgSend
diff --git a/test/CodeGenObjC/arc-linetable-autorelease.m b/test/CodeGenObjC/arc-linetable-autorelease.m
index fa109154ce03..ab20f3e9baf4 100644
--- a/test/CodeGenObjC/arc-linetable-autorelease.m
+++ b/test/CodeGenObjC/arc-linetable-autorelease.m
@@ -32,8 +32,8 @@ NSRect NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h);
// CHECK: call void @objc_storeStrong{{.*}} !dbg ![[ARC:[0-9]+]]
// CHECK: call {{.*}} @objc_autoreleaseReturnValue{{.*}} !dbg ![[ARC]]
// CHECK: ret {{.*}} !dbg ![[ARC]]
- // CHECK: ![[RET]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RET]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
return path;
- // CHECK: ![[ARC]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[ARC]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
}
@end
diff --git a/test/CodeGenObjC/arc-linetable.m b/test/CodeGenObjC/arc-linetable.m
index 2d56ab3dfb55..656c34346879 100644
--- a/test/CodeGenObjC/arc-linetable.m
+++ b/test/CodeGenObjC/arc-linetable.m
@@ -57,52 +57,52 @@ typedef signed char BOOL;
// CHECK: ![[TESTNOSIDEEFFECT:.*]] = {{.*}}[ DW_TAG_subprogram ] [line [[@LINE+1]]] [local] [def] [-[AppDelegate testNoSideEffect:]]
- (int)testNoSideEffect:(NSString *)foo {
int x = 1;
- // CHECK: ![[ARC1]] = metadata !{i32 [[@LINE+1]], i32 0, metadata ![[TESTNOSIDEEFFECT]], null}
+ // CHECK: ![[ARC1]] = !MDLocation(line: [[@LINE+1]], scope: ![[TESTNOSIDEEFFECT]])
return 1; // Return expression
- // CHECK: ![[RET1]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RET1]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
} // Cleanup + Ret
- (int)testNoCleanup {
- // CHECK: ![[RET2]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RET2]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
return 1;
}
- (int)testSideEffect:(NSString *)foo {
- // CHECK: ![[MSG3]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[MSG3]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
return [self testNoSideEffect :foo];
- // CHECK: ![[RET3]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RET3]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
}
- (int)testMultiline:(NSString *)foo {
- // CHECK: ![[MSG4]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[MSG4]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
int r = [self testSideEffect :foo];
- // CHECK: ![[EXP4]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[EXP4]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
return r;
- // CHECK: ![[RET4]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RET4]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
}
- (void)testVoid:(NSString *)foo {
- // CHECK: ![[ARC5]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[ARC5]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
return;
- // CHECK: ![[RET5]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RET5]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
}
- (void)testVoidNoReturn:(NSString *)foo {
- // CHECK: ![[MSG6]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[MSG6]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
[self testVoid :foo];
- // CHECK: ![[RET6]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RET6]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
}
- (int)testNoCleanupSideEffect {
- // CHECK: ![[MSG7]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[MSG7]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
[self testVoid :@"foo"];
- // CHECK: ![[RET7]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+ // CHECK: ![[RET7]] = !MDLocation(line: [[@LINE+1]], scope: !{{.*}})
return 1;
}
- (void)testCleanupVoid:(BOOL)skip withDelegate: (AppDelegate *) delegate {
static BOOL skip_all;
- // CHECK: ![[SKIP1]] = metadata !{i32 [[@LINE+1]], i32 0,
+ // CHECK: ![[SKIP1]] = !MDLocation(line: [[@LINE+1]], scope:
if (!skip_all) {
if (!skip) {
return;
@@ -112,8 +112,8 @@ typedef signed char BOOL;
[delegate testVoid :s];
}
}
- // CHECK: ![[RET8]] = metadata !{i32 [[@LINE+2]], i32 0,
- // CHECK: ![[ARC8]] = metadata !{i32 [[@LINE+1]], i32 0,
+ // CHECK: ![[RET8]] = !MDLocation(line: [[@LINE+2]], scope:
+ // CHECK: ![[ARC8]] = !MDLocation(line: [[@LINE+1]], scope:
}
diff --git a/test/CodeGenObjC/arc-literals.m b/test/CodeGenObjC/arc-literals.m
index 19a5516dc7ca..abeb49f9dddf 100644
--- a/test/CodeGenObjC/arc-literals.m
+++ b/test/CodeGenObjC/arc-literals.m
@@ -50,8 +50,8 @@ void test_array(id a, id b) {
// CHECK-NEXT: [[V1:%.*]] = load i8** [[B]],
// CHECK-NEXT: store i8* [[V1]], i8** [[T0]]
- // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T:%.*]]** @"\01L_OBJC_CLASSLIST
- // CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+ // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T:%.*]]** @"OBJC_CLASSLIST
+ // CHECK-NEXT: [[SEL:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T1:%.*]] = bitcast [[CLASS_T]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = bitcast [2 x i8*]* [[OBJECTS]] to i8**
// CHECK-NEXT: [[T3:%.*]] = call i8* bitcast ({{.*@objc_msgSend.*}})(i8* [[T1]], i8* [[SEL]], i8** [[T2]], i64 2)
@@ -93,8 +93,8 @@ void test_dictionary(id k1, id o1, id k2, id o2) {
// CHECK-NEXT: store i8* [[V3]], i8** [[T0]]
// Constructing the dictionary
- // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T:%.*]]** @"\01L_OBJC_CLASSLIST
- // CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+ // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T:%.*]]** @"OBJC_CLASSLIST
+ // CHECK-NEXT: [[SEL:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T1:%.*]] = bitcast [[CLASS_T]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = bitcast [2 x i8*]* [[OBJECTS]] to i8**
// CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8*]* [[KEYS]] to i8**
@@ -127,7 +127,7 @@ void test_property(B *b) {
// CHECK: [[T0:%.*]] = getelementptr inbounds [1 x i8*]* [[OBJECTS:%.*]], i32 0, i32 0
// Invoke 'prop'
- // CHECK: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+ // CHECK: [[SEL:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T1:%.*]] = bitcast
// CHECK-NEXT: [[T2:%.*]] = call [[B:%.*]]* bitcast ({{.*}} @objc_msgSend to {{.*}})(i8* [[T1]], i8* [[SEL]])
// CHECK-NEXT: [[T3:%.*]] = bitcast [[B]]* [[T2]] to i8*
@@ -139,8 +139,8 @@ void test_property(B *b) {
// CHECK-NEXT: store i8* [[V1]], i8** [[T0]]
// Invoke arrayWithObjects:count:
- // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T]]** @"\01L_OBJC_CLASSLIST
- // CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+ // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T]]** @"OBJC_CLASSLIST
+ // CHECK-NEXT: [[SEL:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T1:%.*]] = bitcast [[CLASS_T]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = bitcast [1 x i8*]* [[OBJECTS]] to i8**
// CHECK-NEXT: [[T3:%.*]] = call i8* bitcast ({{.*}} @objc_msgSend to {{.*}}(i8* [[T1]], i8* [[SEL]], i8** [[T2]], i64 1)
diff --git a/test/CodeGenObjC/arc-loadweakretained-release.m b/test/CodeGenObjC/arc-loadweakretained-release.m
index a84719d606de..4db67a97de7b 100644
--- a/test/CodeGenObjC/arc-loadweakretained-release.m
+++ b/test/CodeGenObjC/arc-loadweakretained-release.m
@@ -30,7 +30,7 @@ int main (int argc, const char * argv[]) {
// CHECK: [[SIXTEEN:%.*]] = call i8* @objc_loadWeakRetained(i8** {{%.*}})
// CHECK-NEXT: [[SEVENTEEN:%.*]] = bitcast i8* [[SIXTEEN]] to {{%.*}}
-// CHECK-NEXT: [[EIGHTEEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_6"
+// CHECK-NEXT: [[EIGHTEEN:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_6
// CHECK-NEXT: [[NINETEEN:%.*]] = bitcast %0* [[SEVENTEEN]] to i8*
// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK-NEXT: [[TWENTY:%.*]] = bitcast %0* [[SEVENTEEN]] to i8*
diff --git a/test/CodeGenObjC/arc-precise-lifetime.m b/test/CodeGenObjC/arc-precise-lifetime.m
index e15d5d4835ce..ddbd7041cfd2 100644
--- a/test/CodeGenObjC/arc-precise-lifetime.m
+++ b/test/CodeGenObjC/arc-precise-lifetime.m
@@ -41,7 +41,7 @@ void test1a(void) {
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
- // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T4:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
// CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
// CHECK-NEXT: store i8* [[T6]], i8**
@@ -61,7 +61,7 @@ void test1b(void) {
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
// CHECK-NEXT: store [[TEST1]]* [[T3]]
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
- // CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T1:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
// CHECK-NEXT: store i8* [[T3]], i8**
@@ -84,7 +84,7 @@ void test1c(void) {
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
- // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T4:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
// CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
// CHECK-NEXT: store i8* [[T6]], i8**
@@ -106,7 +106,7 @@ void test1d(void) {
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease
// CHECK-NEXT: [[SIX:%.*]] = bitcast i8* [[T3]] to [[TEST1]]*
- // CHECK-NEXT: [[SEVEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[SEVEN:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[SIX]] to i8*
// CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]])
// CHECK-NEXT: store i8* [[CALL1]], i8**
diff --git a/test/CodeGenObjC/arc-property.m b/test/CodeGenObjC/arc-property.m
index 8398a1b60f0d..02cd50dbf286 100644
--- a/test/CodeGenObjC/arc-property.m
+++ b/test/CodeGenObjC/arc-property.m
@@ -101,13 +101,13 @@ void test3(Test3 *t) {
// CHECK-NEXT: [[X:%.*]] = alloca i8*,
// Property access.
// CHECK: [[T0:%.*]] = load [[TEST3]]** [[T]],
-// CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[SEL:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* bitcast ({{.*}} @objc_msgSend to {{.*}})(i8* [[T1]], i8* [[SEL]])
// CHECK-NEXT: store i8* [[T2]], i8** [[X]],
// Message send.
// CHECK-NEXT: [[T0:%.*]] = load [[TEST3]]** [[T]],
-// CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[SEL:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* bitcast ({{.*}} @objc_msgSend to {{.*}})(i8* [[T1]], i8* [[SEL]])
// CHECK-NEXT: [[T3:%.*]] = load i8** [[X]],
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
index 8fc68ca2ffa8..a83fe0f24be2 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -103,8 +103,8 @@ void test3_unelided() {
Test3 *x;
// Call to +alloc.
- // CHECK-NEXT: load {{.*}}* @"\01L_OBJC_CLASSLIST_REFERENCES_
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load {{.*}}* @"OBJC_CLASSLIST_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK-NEXT: bitcast
@@ -113,7 +113,7 @@ void test3_unelided() {
[Test3 alloc];
// CHECK-NEXT: [[T0:%.*]] = load [[TEST3]]** [[X]]
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
// CHECK-NEXT: [[COPY:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend {{.*}})(i8* [[T1]],
// CHECK-NEXT: call void @objc_release(i8* [[COPY]]) [[NUW:#[0-9]+]]
@@ -132,14 +132,14 @@ void test3() {
id x = [[Test3 alloc] initWith: 5];
// Call to +alloc.
- // CHECK-NEXT: load {{.*}}* @"\01L_OBJC_CLASSLIST_REFERENCES_
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load {{.*}}* @"OBJC_CLASSLIST_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK-NEXT: bitcast
// Call to -initWith: with elided retain of consumed argument.
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: [[INIT:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i32)*)(i8*
// CHECK-NEXT: bitcast
@@ -149,7 +149,7 @@ void test3() {
// Call to -copy.
// CHECK-NEXT: [[V:%.*]] = load i8** [[X]]
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[COPY:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend {{.*}})(i8* [[V]],
// Assignment to x.
@@ -169,14 +169,14 @@ void test3() {
// CHECK-LABEL: define i8* @test4()
id test4() {
// Call to +alloc.
- // CHECK: load {{.*}}* @"\01L_OBJC_CLASSLIST_REFERENCES_
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK: load {{.*}}* @"OBJC_CLASSLIST_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK-NEXT: [[ALLOC:%.*]] = bitcast
// Call to -initWith: with elided retain of consumed argument.
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[ALLOC:%.*]] = bitcast
// CHECK-NEXT: [[INIT:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i32)*)(i8* [[ALLOC]],
@@ -289,13 +289,13 @@ void test10() {
// CHECK-NEXT: [[Y:%.*]] = alloca i8*, align
// CHECK-NEXT: store [[TEST10]]* null, [[TEST10]]** [[X]]
// CHECK-NEXT: load [[TEST10]]** [[X]], align
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_{{[0-9]*}}"
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_{{[0-9]*}}
// CHECK-NEXT: bitcast
// CHECK-NEXT: [[T0:%.*]] = call [[TEST10]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST10]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
// CHECK-NEXT: [[V:%.*]] = bitcast i8* [[T2]] to [[TEST10]]*
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_{{[0-9]*}}"
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_{{[0-9]*}}
// CHECK-NEXT: bitcast
// CHECK-NEXT: [[T0:%.*]] = call [[TEST10]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST10]]* [[T0]] to i8*
@@ -412,11 +412,11 @@ void test13(void) {
// CHECK-NEXT: [[BASE2:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8*
// CHECK-NEXT: [[T0:%.*]] = getelementptr
// CHECK-NEXT: store i8* [[BASE2]], i8** [[T0]]
- // CHECK-NEXT: load {{%.*}}** @"\01L_OBJC_CLASSLIST_SUP_REFS_$_
+ // CHECK-NEXT: load {{%.*}}** @"OBJC_CLASSLIST_SUP_REFS_$_
// CHECK-NEXT: bitcast
// CHECK-NEXT: getelementptr
// CHECK-NEXT: store
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: call void bitcast (i8* ({{.*}})* @objc_msgSendSuper2 to void (
// CHECK-NEXT: ret void
}
@@ -675,7 +675,7 @@ static id _test29_allocator = 0;
// CHECK-NEXT: store [[TEST29]]* null, [[TEST29]]** [[SELF]]
// Actual message send.
-// CHECK-NEXT: [[T2:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-NEXT: [[T2:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T3:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
// CHECK-NEXT: [[CALL:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8*)*)(i8* [[T3]], i8* [[T2]], i8* [[T1]])
@@ -782,7 +782,7 @@ char *helper;
// Call.
// CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]]
-// CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-NEXT: [[T1:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST30]]* [[T0]] to i8*
// CHECK-NEXT: [[CALL:%.*]] = call [[TEST30_HELPER:%.*]]* bitcast {{.*}} @objc_msgSend {{.*}}(i8* [[T2]], i8* [[T1]])
@@ -868,7 +868,7 @@ void test33(Test33 *ptr) {
// CHECK-NEXT: load [[TEST33]]** [[PTR]]
// CHECK-NEXT: [[W0:%.*]] = load [[A_T]]** [[A]]
// CHECK-NEXT: store [[A_T]]* [[W0]], [[A_T]]** [[TEMP0]]
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP0]])
// CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[TEMP0]]
@@ -884,7 +884,7 @@ void test33(Test33 *ptr) {
// CHECK-NEXT: load [[TEST33]]** [[PTR]]
// CHECK-NEXT: [[W0:%.*]] = load [[A_T]]** [[A]]
// CHECK-NEXT: store [[A_T]]* [[W0]], [[A_T]]** [[TEMP1]]
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP1]])
// CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[TEMP1]]
@@ -898,19 +898,19 @@ void test33(Test33 *ptr) {
// CHECK-NEXT: call void @objc_release(i8* [[T5]])
// CHECK-NEXT: load [[TEST33]]** [[PTR]]
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[A]])
// CHECK-NEXT: load [[TEST33]]** [[PTR]]
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[A]])
// 'out'
// CHECK-NEXT: load [[TEST33]]** [[PTR]]
// CHECK-NEXT: store [[A_T]]* null, [[A_T]]** [[TEMP2]]
- // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP2]])
// CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[TEMP2]]
@@ -1270,16 +1270,16 @@ void test61(void) {
// CHECK-NEXT: [[T0:%.*]] = call i8* @test61_make()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
- // CHECK-NEXT: [[T2:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
- // CHECK-NEXT: [[T3:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T2:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T3:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T4:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8*)*)(i8* [[T1]], i8* [[T3]], i8* [[T2]])
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
[test61_make() performSelector: @selector(test61_void)];
// CHECK-NEXT: [[T0:%.*]] = call i8* @test61_make()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
- // CHECK-NEXT: [[T2:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
- // CHECK-NEXT: [[T3:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T2:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T3:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T4:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8*)*)(i8* [[T1]], i8* [[T3]], i8* [[T2]])
// CHECK-NEXT: [[T5:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T4]])
// CHECK-NEXT: store i8* [[T5]], i8** [[Y]]
@@ -1372,7 +1372,7 @@ void test66(void) {
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST66]]*
// CHECK-NEXT: [[T4:%.*]] = call i8* @test66_arg()
// CHECK-NEXT: [[T5:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T4]])
-// CHECK-NEXT: [[T6:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[T6:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T7:%.*]] = bitcast [[TEST66]]* [[T3]] to i8*
// CHECK-NEXT: [[SIX:%.*]] = icmp eq i8* [[T7]], null
// CHECK-NEXT: br i1 [[SIX]], label [[NULINIT:%.*]], label [[CALL:%.*]]
diff --git a/test/CodeGenObjC/arm-atomic-scalar-setter-getter.m b/test/CodeGenObjC/arm-atomic-scalar-setter-getter.m
index 535cbbb85c4f..6eb58906e639 100644
--- a/test/CodeGenObjC/arm-atomic-scalar-setter-getter.m
+++ b/test/CodeGenObjC/arm-atomic-scalar-setter-getter.m
@@ -8,6 +8,6 @@
@implementation I
@synthesize LONG_PROP;
@end
-// CHECK-ARM: call arm_aapcscc void @objc_copyStruct(i8* %{{.*}}, i8* %{{.*}}, i32 8, i1 zeroext true, i1 zeroext false)
-// CHECK-ARM: call arm_aapcscc void @objc_copyStruct(i8* %{{.*}}, i8* %{{.*}}, i32 8, i1 zeroext true, i1 zeroext false)
+// CHECK-ARM: call void @objc_copyStruct(i8* %{{.*}}, i8* %{{.*}}, i32 8, i1 zeroext true, i1 zeroext false)
+// CHECK-ARM: call void @objc_copyStruct(i8* %{{.*}}, i8* %{{.*}}, i32 8, i1 zeroext true, i1 zeroext false)
diff --git a/test/CodeGenObjC/block-byref-debuginfo.m b/test/CodeGenObjC/block-byref-debuginfo.m
index 88a8d8d50c1f..231767e99a66 100644
--- a/test/CodeGenObjC/block-byref-debuginfo.m
+++ b/test/CodeGenObjC/block-byref-debuginfo.m
@@ -3,7 +3,7 @@
// rdar://problem/14386148
// Test that the foo is aligned at an 8 byte boundary in the DWARF
// expression (256) that locates it inside of the byref descriptor:
-// CHECK: metadata !"foo", i32 0, i64 {{[0-9]+}}, i64 64, i64 256, i32 0, metadata
+// CHECK: [ DW_TAG_member ] [foo] [line 0, size {{[0-9]+}}, align 64, offset 256] [from Foo]
struct Foo {
unsigned char *data;
diff --git a/test/CodeGenObjC/block-over-align.m b/test/CodeGenObjC/block-over-align.m
new file mode 100644
index 000000000000..2747040ac031
--- /dev/null
+++ b/test/CodeGenObjC/block-over-align.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -emit-llvm -o /dev/null %s
+// rdar://17878679
+
+typedef struct
+{
+ int i;
+} GAXBackboardState __attribute__ ((aligned(32))); // minimum alignment is 32-byte boundary
+
+@interface GAXSpringboard @end
+
+@implementation GAXSpringboard
+{
+ GAXBackboardState _reflectedBackboardState;
+}
+
+- (void) MyMethod
+{
+ GAXBackboardState newBackboardState;
+ ^{
+ _reflectedBackboardState = newBackboardState;
+ return newBackboardState.i;
+ }();
+}
+@end
+
diff --git a/test/CodeGenObjC/boxing.m b/test/CodeGenObjC/boxing.m
index efd2b1600b36..33dc4e698f8b 100644
--- a/test/CodeGenObjC/boxing.m
+++ b/test/CodeGenObjC/boxing.m
@@ -53,18 +53,18 @@ typedef signed char BOOL;
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
@end
-// CHECK: [[WithIntMeth:@".*"]] = private global [15 x i8] c"numberWithInt:\00"
-// CHECK: [[WithIntSEL:@".*"]] = private externally_initialized global i8* getelementptr inbounds ([15 x i8]* [[WithIntMeth]]
-// CHECK: [[WithCharMeth:@".*"]] = private global [16 x i8] c"numberWithChar:\00"
-// CHECK: [[WithCharSEL:@".*"]] = private externally_initialized global i8* getelementptr inbounds ([16 x i8]* [[WithCharMeth]]
-// CHECK: [[WithBoolMeth:@".*"]] = private global [16 x i8] c"numberWithBool:\00"
-// CHECK: [[WithBoolSEL:@".*"]] = private externally_initialized global i8* getelementptr inbounds ([16 x i8]* [[WithBoolMeth]]
-// CHECK: [[WithIntegerMeth:@".*"]] = private global [19 x i8] c"numberWithInteger:\00"
-// CHECK: [[WithIntegerSEL:@".*"]] = private externally_initialized global i8* getelementptr inbounds ([19 x i8]* [[WithIntegerMeth]]
-// CHECK: [[WithUnsignedIntegerMeth:@".*"]] = private global [27 x i8] c"numberWithUnsignedInteger:\00"
-// CHECK: [[WithUnsignedIntegerSEL:@".*"]] = private externally_initialized global i8* getelementptr inbounds ([27 x i8]* [[WithUnsignedIntegerMeth]]
-// CHECK: [[stringWithUTF8StringMeth:@".*"]] = private global [22 x i8] c"stringWithUTF8String:\00"
-// CHECK: [[stringWithUTF8StringSEL:@".*"]] = private externally_initialized global i8* getelementptr inbounds ([22 x i8]* [[stringWithUTF8StringMeth]]
+// CHECK: [[WithIntMeth:@.*]] = private global [15 x i8] c"numberWithInt:\00"
+// CHECK: [[WithIntSEL:@.*]] = private externally_initialized global i8* getelementptr inbounds ([15 x i8]* [[WithIntMeth]]
+// CHECK: [[WithCharMeth:@.*]] = private global [16 x i8] c"numberWithChar:\00"
+// CHECK: [[WithCharSEL:@.*]] = private externally_initialized global i8* getelementptr inbounds ([16 x i8]* [[WithCharMeth]]
+// CHECK: [[WithBoolMeth:@.*]] = private global [16 x i8] c"numberWithBool:\00"
+// CHECK: [[WithBoolSEL:@.*]] = private externally_initialized global i8* getelementptr inbounds ([16 x i8]* [[WithBoolMeth]]
+// CHECK: [[WithIntegerMeth:@.*]] = private global [19 x i8] c"numberWithInteger:\00"
+// CHECK: [[WithIntegerSEL:@.*]] = private externally_initialized global i8* getelementptr inbounds ([19 x i8]* [[WithIntegerMeth]]
+// CHECK: [[WithUnsignedIntegerMeth:@.*]] = private global [27 x i8] c"numberWithUnsignedInteger:\00"
+// CHECK: [[WithUnsignedIntegerSEL:@.*]] = private externally_initialized global i8* getelementptr inbounds ([27 x i8]* [[WithUnsignedIntegerMeth]]
+// CHECK: [[stringWithUTF8StringMeth:@.*]] = private global [22 x i8] c"stringWithUTF8String:\00"
+// CHECK: [[stringWithUTF8StringSEL:@.*]] = private externally_initialized global i8* getelementptr inbounds ([22 x i8]* [[stringWithUTF8StringMeth]]
int main() {
// CHECK: load i8** [[WithIntSEL]]
diff --git a/test/CodeGenObjC/catch-lexical-block.m b/test/CodeGenObjC/catch-lexical-block.m
index 618d3a223229..d5aeee143bea 100644
--- a/test/CodeGenObjC/catch-lexical-block.m
+++ b/test/CodeGenObjC/catch-lexical-block.m
@@ -10,6 +10,6 @@ void f0() {
// We should have 3 lexical blocks here at the moment, including one
// for the catch block.
// CHECK: lexical_block
-// CHECK: lexical_block
// CHECK: auto_variable
// CHECK: lexical_block
+// CHECK: lexical_block
diff --git a/test/CodeGenObjC/category-super-class-meth.m b/test/CodeGenObjC/category-super-class-meth.m
index 5ba7adff8bbe..268f0b59711d 100644
--- a/test/CodeGenObjC/category-super-class-meth.m
+++ b/test/CodeGenObjC/category-super-class-meth.m
@@ -22,8 +22,8 @@
@end
// CHECK: define internal i8* @"\01+[Sub2(Category) copy]
-// CHECK: [[ONE:%.*]] = load %struct._class_t** @"\01L_OBJC_CLASSLIST_SUP_REFS_$_3"
+// CHECK: [[ONE:%.*]] = load %struct._class_t** @"OBJC_CLASSLIST_SUP_REFS_$_3"
// CHECK: [[TWO:%.*]] = bitcast %struct._class_t* [[ONE]] to i8*
// CHECK: [[THREE:%.*]] = getelementptr inbounds %struct._objc_super* [[OBJC_SUPER:%.*]], i32 0, i32 1
// CHECK: store i8* [[TWO]], i8** [[THREE]]
-// CHECK: [[FOUR:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_"
+// CHECK: [[FOUR:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
diff --git a/test/CodeGenObjC/debug-info-block-captured-self.m b/test/CodeGenObjC/debug-info-block-captured-self.m
index 183e91b6ec57..f0ca1af34c8f 100644
--- a/test/CodeGenObjC/debug-info-block-captured-self.m
+++ b/test/CodeGenObjC/debug-info-block-captured-self.m
@@ -55,15 +55,15 @@ typedef enum {
// CHECK-NEXT: %[[MEM2:.*]] = alloca i8*, align 8
// CHECK: store i8* [[BLOCK_DESC:%.*]], i8** %[[MEM1]], align 8
// CHECK: %[[TMP0:.*]] = load i8** %[[MEM1]]
-// CHECK: call void @llvm.dbg.value(metadata !{i8* %[[TMP0]]}, i64 0, metadata ![[BDMD:[0-9]+]])
-// CHECK: call void @llvm.dbg.declare(metadata !{i8* [[BLOCK_DESC]]}, metadata ![[BDMD:[0-9]+]])
+// CHECK: call void @llvm.dbg.value(metadata i8* %[[TMP0]], i64 0, metadata ![[BDMD:[0-9]+]], metadata !{{.*}})
+// CHECK: call void @llvm.dbg.declare(metadata i8* [[BLOCK_DESC]], metadata ![[BDMD:[0-9]+]], metadata !{{.*}})
// CHECK: %[[TMP1:.*]] = bitcast
// CHECK-NEXT: store
-// CHECK: call void @llvm.dbg.declare(metadata !{<{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** {{.*}}}, metadata ![[SELF:.*]])
+// CHECK: call void @llvm.dbg.declare(metadata <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** {{[^,]*}}, metadata ![[SELF:.*]], metadata !{{.*}})
// make sure we are still in the same function
// CHECK: define {{.*}}__copy_helper_block_
// Metadata
-// CHECK: ![[MAIN:.*]] = {{.*}}!"Main"{{.*}}DW_TAG_structure_type{{.*}}line 23
+// CHECK: ![[MAIN:.*]] = !{!"0x13\00Main\0023\00{{.*}}", {{.*}} ; [ DW_TAG_structure_type ] [Main] [line 23,
// CHECK: ![[PMAIN:.*]] = {{.*}}![[MAIN]]} ; [ DW_TAG_pointer_type ]{{.*}}from Main
-// CHECK: ![[BDMD]] = metadata {{.*}}.block_descriptor
+// CHECK: ![[BDMD]] = {{.*}}.block_descriptor
// CHECK: ![[SELF]] = {{.*}}![[PMAIN]]{{.*}}[ DW_TAG_auto_variable ] [self] [line 40]
diff --git a/test/CodeGenObjC/debug-info-block-type.m b/test/CodeGenObjC/debug-info-block-type.m
new file mode 100644
index 000000000000..ef92bf35152d
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-block-type.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm -fblocks -g -triple x86_64-apple-darwin14 -x objective-c < %s -o - | FileCheck %s
+#define nil ((void*) 0)
+typedef signed char BOOL;
+// CHECK: ![[BOOL:[0-9]+]] = {{.*}} [ DW_TAG_typedef ] [BOOL] [line [[@LINE-1]]
+// CHECK: ![[ID:[0-9]+]] = {{.*}} [ DW_TAG_typedef ] [id]
+
+typedef BOOL (^SomeKindOfPredicate)(id obj);
+// CHECK: ![[PTR:[0-9]+]]} ; [ DW_TAG_member ] [__FuncPtr]
+// CHECK: ![[PTR]] = {{.*}}, ![[FNTYPE:[0-9]+]]} ; [ DW_TAG_pointer_type ]
+// CHECK: ![[FNTYPE]] = {{.*}} ![[ARGS:[0-9]+]]{{.*}} ; [ DW_TAG_subroutine_type ]
+// CHECK: ![[ARGS]] = !{![[BOOL]], ![[ID]]}
+
+int main()
+{
+ SomeKindOfPredicate p = ^BOOL(id obj) { return obj != nil; };
+ // CHECK: ![[PTR]]} ; [ DW_TAG_member ] [__FuncPtr] [line [[@LINE-1]], size 64, align 64, offset 128]
+ return p(nil);
+}
diff --git a/test/CodeGenObjC/debug-info-blocks.m b/test/CodeGenObjC/debug-info-blocks.m
index d025ca87d560..f5f4437b7b59 100644
--- a/test/CodeGenObjC/debug-info-blocks.m
+++ b/test/CodeGenObjC/debug-info-blocks.m
@@ -7,8 +7,8 @@
// CHECK: define {{.*}}_block_invoke
// CHECK: %[[BLOCK:.*]] = bitcast i8* %.block_descriptor to <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>*, !dbg
// CHECK-NEXT: store <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[BLOCK]], <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA:.*]], align
-// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{<{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA]]}, metadata ![[SELF:[0-9]+]])
-// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{%1** %d}, metadata ![[D:[0-9]+]])
+// CHECK-NEXT: call void @llvm.dbg.declare(metadata <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA]], metadata ![[SELF:[0-9]+]], metadata !{{.*}})
+// CHECK-NEXT: call void @llvm.dbg.declare(metadata %1** %d, metadata ![[D:[0-9]+]], metadata !{{.*}})
// rdar://problem/14386148
// Test that we don't emit bogus line numbers for the helper functions.
@@ -22,10 +22,10 @@
// CHECK-NOT: ret
// CHECK: load {{.*}}, !dbg ![[DESTROY_LINE:[0-9]+]]
-// CHECK-DAG: [[DBG_LINE]] = metadata !{i32 0, i32 0, metadata ![[COPY_SP:[0-9]+]], null}
-// CHECK-DAG: [[COPY_LINE]] = metadata !{i32 0, i32 0, metadata ![[COPY_SP:[0-9]+]], null}
+// CHECK-DAG: [[DBG_LINE]] = !MDLocation(line: 0, scope: ![[COPY_SP:[0-9]+]])
+// CHECK-DAG: [[COPY_LINE]] = !MDLocation(line: 0, scope: ![[COPY_SP:[0-9]+]])
// CHECK-DAG: [[COPY_SP]] = {{.*}}[ DW_TAG_subprogram ]{{.*}}[__copy_helper_block_]
-// CHECK-DAG: [[DESTROY_LINE]] = metadata !{i32 0, i32 0, metadata ![[DESTROY_SP:[0-9]+]], null}
+// CHECK-DAG: [[DESTROY_LINE]] = !MDLocation(line: 0, scope: ![[DESTROY_SP:[0-9]+]])
// CHECK-DAG: [[DESTROY_SP]] = {{.*}}[ DW_TAG_subprogram ]{{.*}}[__destroy_helper_block_]
typedef unsigned int NSUInteger;
diff --git a/test/CodeGenObjC/debug-info-getter-name.m b/test/CodeGenObjC/debug-info-getter-name.m
index 70d99367cbf6..9e1e55f0f408 100644
--- a/test/CodeGenObjC/debug-info-getter-name.m
+++ b/test/CodeGenObjC/debug-info-getter-name.m
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target
// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10 -fexceptions -fobjc-exceptions -g %s -o - | FileCheck %s
-// CHECK: {{.*}}, metadata !"-[InstanceVariablesEverywhereButTheInterface someString]", {{.*}}} ; [ DW_TAG_subprogram ]
+// CHECK: !"0x2e\00-[InstanceVariablesEverywhereButTheInterface someString]\00{{.*}}", {{.*}} ; [ DW_TAG_subprogram ]
//rdar: //8498026
diff --git a/test/CodeGenObjC/debug-info-id-with-protocol.m b/test/CodeGenObjC/debug-info-id-with-protocol.m
index 7e96baffdeea..9233f6ccc859 100644
--- a/test/CodeGenObjC/debug-info-id-with-protocol.m
+++ b/test/CodeGenObjC/debug-info-id-with-protocol.m
@@ -36,6 +36,7 @@ int main()
}
}
// Verify that the debug type for both variables is 'id'.
-// CHECK: metadata !{i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata !"bad_carrier", null, i32 {{[0-9]+}}, metadata ![[IDTYPE:[0-9]+]], i32 0, i32 0} ; [ DW_TAG_arg_variable ] [bad_carrier] [line 0]
-// CHECK: metadata !{i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata !"good_carrier", null, i32 {{[0-9]+}}, metadata !{{.*}}[[IDTYPE]], i32 0, i32 0} ; [ DW_TAG_arg_variable ] [good_carrier] [line 0]
-// CHECK !{{.*}}[[IDTYPE]] = metadata !{i32 {{[0-9]+}}, null, metadata !"id", metadata !{{[0-9]+}}, i32 !{{[0-9]+}}, i64 0, i64 0, i64 0, i32 0, metadata !{{[0-9]+}}} ; [ DW_TAG_typedef ] [id]
+// CHECK: !"0x101\00bad_carrier\00{{[0-9]+}}\000", !{{[0-9]+}}, null, ![[IDTYPE:[0-9]+]]} ; [ DW_TAG_arg_variable ] [bad_carrier] [line 0]
+//
+// CHECK: !"0x101\00good_carrier\00{{[0-9]+}}\000", !{{[0-9]+}}, null, ![[IDTYPE]]} ; [ DW_TAG_arg_variable ] [good_carrier] [line 0]
+// CHECK !{{.*}}[[IDTYPE]] = !{!"0x16\00id\00{{[0-9]+}}\000\000\000\000", null, !{{[0-9]+}}, !{{[0-9]+}}} ; [ DW_TAG_typedef ] [id]
diff --git a/test/CodeGenObjC/debug-info-instancetype.m b/test/CodeGenObjC/debug-info-instancetype.m
index 1c155179a382..07fd5ca00b18 100644
--- a/test/CodeGenObjC/debug-info-instancetype.m
+++ b/test/CodeGenObjC/debug-info-instancetype.m
@@ -13,11 +13,11 @@
@implementation Foo
+(instancetype)defaultFoo {return 0;}
-// CHECK: ![[FOO:[0-9]+]] = metadata {{.*}}; [ DW_TAG_structure_type ] [Foo]
-// CHECK: metadata !"+[Foo defaultFoo]", metadata !"", i32 [[@LINE-2]], metadata ![[TYPE:[0-9]+]]
-// CHECK: ![[TYPE]] = {{.*}} metadata ![[RESULT:[0-9]+]], i32 {{.*}}, null, null, null} ; [ DW_TAG_subroutine_type ]
-// CHECK: ![[RESULT]] = metadata {{.*}}{metadata ![[FOOPTR:[0-9]+]],
-// CHECK: ![[FOOPTR]] = {{.*}}, metadata ![[FOO]]}{{.*}}[ DW_TAG_pointer_type ] {{.*}} [from Foo]
+// CHECK: ![[FOO:[0-9]+]] = {{.*}}; [ DW_TAG_structure_type ] [Foo]
+// CHECK: !"0x2e\00+[Foo defaultFoo]\00+[Foo defaultFoo]\00\00[[@LINE-2]]\00{{[^,]*}}"{{, [^,]+, [^,]+}}, ![[TYPE:[0-9]+]]
+// CHECK: ![[TYPE]] = {{.*}} ![[RESULT:[0-9]+]], null, null, null} ; [ DW_TAG_subroutine_type ]
+// CHECK: ![[RESULT]] = {{.*}}{![[FOOPTR:[0-9]+]],
+// CHECK: ![[FOOPTR]] = {{.*}}, ![[FOO]]}{{.*}}[ DW_TAG_pointer_type ] {{.*}} [from Foo]
@end
diff --git a/test/CodeGenObjC/debug-info-ivars-extension.m b/test/CodeGenObjC/debug-info-ivars-extension.m
index e43b598f70ca..9dd715225272 100644
--- a/test/CodeGenObjC/debug-info-ivars-extension.m
+++ b/test/CodeGenObjC/debug-info-ivars-extension.m
@@ -26,8 +26,8 @@ void gorf (I* pg) {
// CHECK: {{.*}} [ DW_TAG_structure_type ] [I]
// Check for "a".
-// CHECK: {{.*}} [ DW_TAG_member ] [a] [line 7, size 32, align 32, offset 0] [from int]
+// CHECK: {{.*}} [ DW_TAG_member ] [a] [line 7, size 32, align 32, offset 0] [public] [from int]
// Make sure we don't output the same type twice.
// CHECK-NOT: {{.*}} [ DW_TAG_structure_type ] [I]
// Check for "b".
-// CHECK: {{.*}} [ DW_TAG_member ] [b] [line 18, size 32, align 32, offset 0] [from int]
+// CHECK: {{.*}} [ DW_TAG_member ] [b] [line 18, size 32, align 32, offset 0] [public] [from int]
diff --git a/test/CodeGenObjC/debug-info-lifetime-crash.m b/test/CodeGenObjC/debug-info-lifetime-crash.m
index 81c7fbca1a80..e2e5d7e3b3b5 100644
--- a/test/CodeGenObjC/debug-info-lifetime-crash.m
+++ b/test/CodeGenObjC/debug-info-lifetime-crash.m
@@ -13,10 +13,10 @@
{
// The debug type for these two will be identical, because we do not
// actually emit the ownership qualifier.
- // CHECK-DAG: metadata !"weakSelf", metadata !{{[0-9]+}}, i32 [[@LINE+1]], metadata ![[SELFTY:[0-9]+]], i32 0, i32 0, {{.*}}} ; [ DW_TAG_auto_variable ] [weakSelf]
+ // CHECK-DAG: !"0x100\00weakSelf\00[[@LINE+1]]\000"{{, [^,]+, [^,]+}}, ![[SELFTY:[0-9]+]]} ; [ DW_TAG_auto_variable ] [weakSelf]
__attribute__((objc_ownership(weak))) __typeof(self) weakSelf = self;
Block = [^{
- // CHECK-DAG: metadata !"strongSelf", metadata !{{[0-9]+}}, i32 [[@LINE+1]], metadata ![[SELFTY]], i32 0, i32 0} ; [ DW_TAG_auto_variable ] [strongSelf]
+ // CHECK-DAG: !"0x100\00strongSelf\00[[@LINE+1]]\000"{{, [^,]+, [^,]+}}, ![[SELFTY]]} ; [ DW_TAG_auto_variable ] [strongSelf]
__attribute__((objc_ownership(strong))) __typeof(self) strongSelf = weakSelf;
} copy];
}
diff --git a/test/CodeGenObjC/debug-info-nested-blocks.m b/test/CodeGenObjC/debug-info-nested-blocks.m
new file mode 100644
index 000000000000..5c5958cf3096
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-nested-blocks.m
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -emit-llvm -gdwarf-2 -fblocks -o - -x objective-c %s| FileCheck %s
+// This code triggered a bug where a dbg.declare intrinsic ended up with the
+// wrong parent and subsequently failed the Verifier.
+void baz(id b);
+void fub(id block);
+int foo(void);
+void bar(void) {
+ fub(^() {
+ id a;
+ id b = [a bar:^(int e){}];
+ if (b) {
+ ^() {
+ if ((0 && foo()) ? 1 : 0) {
+ baz([a aMessage]);
+ }
+ };
+ }
+ });
+}
+
+// Verify that debug info for BlockPointerDbgLoc is emitted for the
+// innermost block.
+//
+// CHECK: define {{.*}}void @__bar_block_invoke_3(i8* %.block_descriptor)
+// CHECK: %[[BLOCKADDR:.*]] = alloca <{{.*}}>*, align
+// CHECK: call void @llvm.dbg.declare(metadata {{.*}}%[[BLOCKADDR]]
diff --git a/test/CodeGenObjC/debug-info-property-accessors.m b/test/CodeGenObjC/debug-info-property-accessors.m
index 4c7b98466a3e..0c7f03e6fb57 100644
--- a/test/CodeGenObjC/debug-info-property-accessors.m
+++ b/test/CodeGenObjC/debug-info-property-accessors.m
@@ -5,7 +5,7 @@
// Ensure we emit the names of explicit/renamed accessors even if they
// are defined later in the implementation section.
//
-// CHECK: metadata !{i32 {{.*}}, metadata !"blah", {{.*}} metadata !"isBlah", metadata !"", {{.*}}} ; [ DW_TAG_APPLE_property ] [blah]
+// CHECK: !"0x4200\00blah\00{{[0-9]+}}\00isBlah\00{{.*}}", {{.*}}} ; [ DW_TAG_APPLE_property ] [blah]
@class NSString;
extern void NSLog(NSString *format, ...);
diff --git a/test/CodeGenObjC/debug-info-property3.m b/test/CodeGenObjC/debug-info-property3.m
index f63e744066ec..a6d8daf083b0 100644
--- a/test/CodeGenObjC/debug-info-property3.m
+++ b/test/CodeGenObjC/debug-info-property3.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -S -emit-llvm -g %s -o - | FileCheck %s
-// CHECK: metadata !"p1", metadata !{{.*}}, i32 5, metadata !"", metadata !"", i32 2316, metadata !{{.*}}} ; [ DW_TAG_APPLE_property ]
+// CHECK: !"0x4200\00p1\005\00\00\002316", {{.*}}} ; [ DW_TAG_APPLE_property ]
@interface I1
@property int p1;
@end
diff --git a/test/CodeGenObjC/debug-info-self.m b/test/CodeGenObjC/debug-info-self.m
index 7a484d81481a..a6e9daff916a 100644
--- a/test/CodeGenObjC/debug-info-self.m
+++ b/test/CodeGenObjC/debug-info-self.m
@@ -14,6 +14,6 @@
}
@end
-// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR:.*]], metadata !"self", null, i32 16777216, metadata !{{.*}}, i32 1088, i32 0} ; [ DW_TAG_arg_variable ] [self] [line 0]
-// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR]], metadata !"_cmd", null, i32 33554432, metadata !{{.*}}, i32 64, i32 0} ; [ DW_TAG_arg_variable ] [_cmd] [line 0]
-// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR]], metadata !"myarg", metadata !{{.*}}, i32 50331659, metadata !{{.*}}, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [myarg] [line 11]
+// CHECK: !"0x101\00self\0016777216\001088", ![[CTOR:.*]], null, !{{.*}}} ; [ DW_TAG_arg_variable ] [self] [line 0]
+// CHECK: !"0x101\00_cmd\0033554432\0064", ![[CTOR]], null, !{{.*}}} ; [ DW_TAG_arg_variable ] [_cmd] [line 0]
+// CHECK: !"0x101\00myarg\0050331659\000", ![[CTOR]], !{{.*}}, !{{.*}}} ; [ DW_TAG_arg_variable ] [myarg] [line 11]
diff --git a/test/CodeGenObjC/debug-info-static-var.m b/test/CodeGenObjC/debug-info-static-var.m
index 2c10d597797f..6828983b0830 100644
--- a/test/CodeGenObjC/debug-info-static-var.m
+++ b/test/CodeGenObjC/debug-info-static-var.m
@@ -2,7 +2,7 @@
// Radar 8801045
// Do not emit AT_MIPS_linkage_name for static variable i
-// CHECK: metadata !"i", metadata !"i", metadata !""
+// CHECK: !"0x34\00i\00i\00\00{{.*}}"
@interface A {
}
diff --git a/test/CodeGenObjC/debug-info-synthesis.m b/test/CodeGenObjC/debug-info-synthesis.m
index 1bf7576d886f..55867b4068a2 100644
--- a/test/CodeGenObjC/debug-info-synthesis.m
+++ b/test/CodeGenObjC/debug-info-synthesis.m
@@ -31,4 +31,4 @@ int main(int argc, char *argv[]) {
}
// CHECK: ![[FILE:.*]] = {{.*}}[ DW_TAG_file_type ] [{{.*}}/foo.h]
-// CHECK: metadata ![[FILE]], {{.*}} ; [ DW_TAG_subprogram ] [line 8] [local] [def] [-[Foo dict]]
+// CHECK: ![[FILE]], {{.*}} ; [ DW_TAG_subprogram ] [line 8] [local] [def] [-[Foo dict]]
diff --git a/test/CodeGenObjC/debug-info-variadic-method.m b/test/CodeGenObjC/debug-info-variadic-method.m
new file mode 100644
index 000000000000..e895953ff6b6
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-variadic-method.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -o - -emit-llvm -g %s | FileCheck %s
+
+// This test verifies that variadic ObjC methods get the
+// DW_TAG_unspecified_parameter marker.
+
+@interface Foo
+- (void) Bar: (int) n, ...;
+@end
+
+@implementation Foo
+- (void) Bar: (int) n, ...
+{
+ // CHECK: ![[NUM:[^,]*]], null, null, null} ; [ DW_TAG_subroutine_type ]
+ // CHECK: ![[NUM]] = {{!{null, ![^,]*, ![^,]*, ![^,]*, null}}}
+}
+@end
diff --git a/test/CodeGenObjC/debug-property-synth.m b/test/CodeGenObjC/debug-property-synth.m
index 68fb956def80..14657249c00d 100644
--- a/test/CodeGenObjC/debug-property-synth.m
+++ b/test/CodeGenObjC/debug-property-synth.m
@@ -20,8 +20,8 @@
//
// CHECK: [ DW_TAG_subprogram ] [line [[@LINE+4]]] [local] [def] [-[I p1]]
// CHECK: [ DW_TAG_subprogram ] [line [[@LINE+3]]] [local] [def] [-[I setP1:]]
-// CHECK: ![[DBG1]] = metadata !{i32 [[@LINE+2]],
-// CHECK: ![[DBG2]] = metadata !{i32 [[@LINE+1]],
+// CHECK: ![[DBG1]] = !MDLocation(line: [[@LINE+2]],
+// CHECK: ![[DBG2]] = !MDLocation(line: [[@LINE+1]],
@property int p1;
@end
diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m
index 6f2423b66874..b61fbb32eaf1 100644
--- a/test/CodeGenObjC/encode-test.m
+++ b/test/CodeGenObjC/encode-test.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple i686-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o %t %s
// RUN: FileCheck < %t %s
//
-// CHECK: @"\01L_OBJC_METH_VAR_TYPE_34" = private global [16 x i8] c"v12@0:4[3[4@]]8\00"
+// CHECK: @OBJC_METH_VAR_TYPE_34 = private global [16 x i8] c"v12@0:4[3[4@]]8\00"
@class Int1;
diff --git a/test/CodeGenObjC/exceptions-asm-attribute.m b/test/CodeGenObjC/exceptions-asm-attribute.m
index eb369902a3c8..c5ef46724b5c 100644
--- a/test/CodeGenObjC/exceptions-asm-attribute.m
+++ b/test/CodeGenObjC/exceptions-asm-attribute.m
@@ -11,11 +11,11 @@
// CHECK-X86_64: @"OBJC_CLASS_$_MySecretNamespace.A" = global {{.*}}, section "__DATA, __objc_data", align 8
// CHECK-X86_64: @"OBJC_METACLASS_$_MySecretNamespace.A" = global {{.*}}, section "__DATA, __objc_data", align 8
-// CHECK-X86_64: @"\01L_OBJC_CLASS_NAME_" = {{.*}}, section "__TEXT,__objc_classname,cstring_literals", align 1
+// CHECK-X86_64: @OBJC_CLASS_NAME_ = {{.*}}, section "__TEXT,__objc_classname,cstring_literals", align 1
// CHECK-X86_64: @"OBJC_EHTYPE_$_MySecretNamespace.EH1" = weak global {{.*}}, section "__DATA,__datacoal_nt,coalesced", align 8
// CHECK-X86_64: @"OBJC_EHTYPE_$_MySecretNamespace.EH2" = external global
// CHECK-X86_64: @"OBJC_EHTYPE_$_MySecretNamespace.EH3" = global {{.*}}, section "__DATA,__objc_const", align 8
-// CHECK-X86_64: @"\01L_OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
+// CHECK-X86_64: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
// CHECK-X86_64: define internal void @"\01-[A im0]"
// CHECK-X86_64: define internal void @"\01-[A(Cat) im1]"
@@ -35,11 +35,11 @@
// CHECK-ARMV6: @"OBJC_CLASS_$_MySecretNamespace.A" = global {{.*}}, section "__DATA, __objc_data", align 4
// CHECK-ARMV6: @"OBJC_METACLASS_$_MySecretNamespace.A" = global {{.*}}, section "__DATA, __objc_data", align 4
-// CHECK-ARMV6: @"\01L_OBJC_CLASS_NAME_" = {{.*}}, section "__TEXT,__objc_classname,cstring_literals", align 1
+// CHECK-ARMV6: @OBJC_CLASS_NAME_ = {{.*}}, section "__TEXT,__objc_classname,cstring_literals", align 1
// CHECK-ARMV6: @"OBJC_EHTYPE_$_MySecretNamespace.EH1" = weak global {{.*}}, section "__DATA,__datacoal_nt,coalesced", align 4
// CHECK-ARMV6: @"OBJC_EHTYPE_$_MySecretNamespace.EH2" = external global
// CHECK-ARMV6: @"OBJC_EHTYPE_$_MySecretNamespace.EH3" = global {{.*}}, section "__DATA,__objc_const", align 4
-// CHECK-ARMV6: @"\01L_OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 4
+// CHECK-ARMV6: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 4
// CHECK-ARMV6: define internal void @"\01-[A im0]"
// CHECK-ARMV6: define internal void @"\01-[A(Cat) im1]"
diff --git a/test/CodeGenObjC/externally-initialized-selectors.m b/test/CodeGenObjC/externally-initialized-selectors.m
index 0b7c24eadd84..7dcd727e5724 100644
--- a/test/CodeGenObjC/externally-initialized-selectors.m
+++ b/test/CodeGenObjC/externally-initialized-selectors.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fobjc-runtime=macosx-fragile-10.5 -o - -emit-llvm %s | FileCheck %s
// RUN: %clang_cc1 -o - -emit-llvm %s | FileCheck %s
-// CHECK: @"\01L_OBJC_SELECTOR_REFERENCES_" = private externally_initialized global
+// CHECK: @OBJC_SELECTOR_REFERENCES_ = private externally_initialized global
void test(id x) {
[x doSomething];
diff --git a/test/CodeGenObjC/forward-protocol-metadata-symbols.m b/test/CodeGenObjC/forward-protocol-metadata-symbols.m
index 2b687d19f907..2e7ee63e0160 100644
--- a/test/CodeGenObjC/forward-protocol-metadata-symbols.m
+++ b/test/CodeGenObjC/forward-protocol-metadata-symbols.m
@@ -23,4 +23,4 @@ int main() {
// CHECK: @"\01l_OBJC_LABEL_PROTOCOL_$_P0" = weak hidden global
// CHECK: @"\01l_OBJC_PROTOCOL_REFERENCE_$_P0" = weak hidden global
-// CHECK: llvm.compiler.used = appending global [10 x i8*] {{[^"]*}}"\01L_OBJC_CLASS_NAME_"{{[^"]*}}"\01L_OBJC_METH_VAR_NAME_"{{[^"]*}}"\01L_OBJC_METH_VAR_TYPE_"{{[^"]*}}"\01l_OBJC_$_CLASS_METHODS_A"{{[^"]*}}"\01l_OBJC_CLASS_PROTOCOLS_$_A"{{[^"]*}}"\01L_OBJC_CLASS_NAME_1"{{[^"]*}}"\01l_OBJC_PROTOCOL_$_P0"{{[^"]*}}"\01l_OBJC_LABEL_PROTOCOL_$_P0"{{[^"]*}}"\01l_OBJC_PROTOCOL_REFERENCE_$_P0"{{[^"]*}}"\01L_OBJC_LABEL_CLASS_$"{{[^"]*}} section "llvm.metadata"
+// CHECK: llvm.compiler.used = appending global [10 x i8*] {{[^"]*}}OBJC_CLASS_NAME_{{[^"]*}}OBJC_METH_VAR_NAME_{{[^"]*}}OBJC_METH_VAR_TYPE_{{[^"]*}}"\01l_OBJC_$_CLASS_METHODS_A"{{[^"]*}}"\01l_OBJC_CLASS_PROTOCOLS_$_A"{{[^"]*}}OBJC_CLASS_NAME_1{{[^"]*}}"\01l_OBJC_PROTOCOL_$_P0"{{[^"]*}}"\01l_OBJC_LABEL_PROTOCOL_$_P0"{{[^"]*}}"\01l_OBJC_PROTOCOL_REFERENCE_$_P0"{{[^"]*}}"OBJC_LABEL_CLASS_$"{{[^"]*}} section "llvm.metadata"
diff --git a/test/CodeGenObjC/image-info.m b/test/CodeGenObjC/image-info.m
index 49f5d90808a9..43fb125a4cc6 100644
--- a/test/CodeGenObjC/image-info.m
+++ b/test/CodeGenObjC/image-info.m
@@ -5,13 +5,13 @@
// RUN: FileCheck --check-prefix CHECK-NONFRAGILE < %t %s
// CHECK-FRAGILE: !llvm.module.flags = !{{{.*}}}
-// CHECK-FRAGILE: !{{[0-9]+}} = metadata !{i32 1, metadata !"Objective-C Version", i32 1}
-// CHECK-FRAGILE-NEXT: !{{[0-9]+}} = metadata !{i32 1, metadata !"Objective-C Image Info Version", i32 0}
-// CHECK-FRAGILE-NEXT: !{{[0-9]+}} = metadata !{i32 1, metadata !"Objective-C Image Info Section", metadata !"__OBJC, __image_info,regular"}
-// CHECK-FRAGILE-NEXT: !{{[0-9]+}} = metadata !{i32 4, metadata !"Objective-C Garbage Collection", i32 0}
+// CHECK-FRAGILE: !{{[0-9]+}} = !{i32 1, !"Objective-C Version", i32 1}
+// CHECK-FRAGILE-NEXT: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0}
+// CHECK-FRAGILE-NEXT: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__OBJC, __image_info,regular"}
+// CHECK-FRAGILE-NEXT: !{{[0-9]+}} = !{i32 4, !"Objective-C Garbage Collection", i32 0}
// CHECK-NONFRAGILE: !llvm.module.flags = !{{{.*}}}
-// CHECK-NONFRAGILE: !{{[0-9]+}} = metadata !{i32 1, metadata !"Objective-C Version", i32 2}
-// CHECK-NONFRAGILE-NEXT: !{{[0-9]+}} = metadata !{i32 1, metadata !"Objective-C Image Info Version", i32 0}
-// CHECK-NONFRAGILE-NEXT: !{{[0-9]+}} = metadata !{i32 1, metadata !"Objective-C Image Info Section", metadata !"__DATA, __objc_imageinfo, regular, no_dead_strip"}
-// CHECK-NONFRAGILE-NEXT: !{{[0-9]+}} = metadata !{i32 4, metadata !"Objective-C Garbage Collection", i32 0}
+// CHECK-NONFRAGILE: !{{[0-9]+}} = !{i32 1, !"Objective-C Version", i32 2}
+// CHECK-NONFRAGILE-NEXT: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0}
+// CHECK-NONFRAGILE-NEXT: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA, __objc_imageinfo, regular, no_dead_strip"}
+// CHECK-NONFRAGILE-NEXT: !{{[0-9]+}} = !{i32 4, !"Objective-C Garbage Collection", i32 0}
diff --git a/test/CodeGenObjC/ivar-layout-64.m b/test/CodeGenObjC/ivar-layout-64.m
index 068d109321fc..0dfdbb960857 100644
--- a/test/CodeGenObjC/ivar-layout-64.m
+++ b/test/CodeGenObjC/ivar-layout-64.m
@@ -33,9 +33,9 @@ __weak B *f2;
@property int p3;
@end
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"C\00"
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"\11p\00"
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"!`\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"C\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"\11p\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"!`\00"
@implementation C
@@ -48,9 +48,9 @@ __weak B *f2;
@property (assign) __weak id p2;
@end
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"A\00"
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"\11q\10\00"
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"!q\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"A\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"\11q\10\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"!q\00"
@implementation A
@synthesize p0 = _p0;
@@ -62,9 +62,9 @@ __weak B *f2;
@property int p3;
@end
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"D\00"
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"\11p\00"
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"!`\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"D\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"\11p\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"!`\00"
@implementation D
@synthesize p3 = _p3;
@@ -89,8 +89,8 @@ typedef unsigned int FSCatalogInfoBitmap;
}
@end
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"NSFileLocationComponent\00"
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"\01\14\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"NSFileLocationComponent\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"\01\14\00"
@implementation NSFileLocationComponent @end
@@ -108,7 +108,7 @@ typedef unsigned int FSCatalogInfoBitmap;
}
@end
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"Foo\00"
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = private global {{.*}} c"\02\10\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"Foo\00"
+// CHECK: @OBJC_CLASS_NAME_{{.*}} = private global {{.*}} c"\02\10\00"
@implementation Foo @end
diff --git a/test/CodeGenObjC/mangle-blocks.m b/test/CodeGenObjC/mangle-blocks.m
new file mode 100644
index 000000000000..f0339c153084
--- /dev/null
+++ b/test/CodeGenObjC/mangle-blocks.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple i386-apple-ios -fblocks -emit-llvm -o - %s -Wno-objc-root-class \
+// RUN: | FileCheck %s
+
+void __assert_rtn(const char *, const char *, int, const char *);
+
+@interface Test
+- (void (^)(void)) mangle;
+@end
+
+@implementation Test
+- (void (^)(void)) mangle {
+ return ^() {
+ void (^b)(void) = ^() {
+ __assert_rtn(__func__, __FILE__, __LINE__, "mangle");
+ };
+ };
+}
+@end
+
+// CHECK: @"__func__.__14-[Test mangle]_block_invoke_2" = private unnamed_addr constant [34 x i8] c"__14-[Test mangle]_block_invoke_2\00", align 1
+// CHECK: @.str = private unnamed_addr constant {{.*}}, align 1
+// CHECK: @.str1 = private unnamed_addr constant [7 x i8] c"mangle\00", align 1
+
+// CHECK: define internal void @"__14-[Test mangle]_block_invoke"(i8* %.block_descriptor)
+
+// CHECK: define internal void @"__14-[Test mangle]_block_invoke_2"(i8* %.block_descriptor){{.*}}{
+// CHECK: call void @__assert_rtn(i8* getelementptr inbounds ([34 x i8]* @"__func__.__14-[Test mangle]_block_invoke_2", i32 0, i32 0), i8* getelementptr inbounds {{.*}}, i32 14, i8* getelementptr inbounds ([7 x i8]* @.str1, i32 0, i32 0))
+// CHECK: }
+
diff --git a/test/CodeGenObjC/metadata-symbols-32.m b/test/CodeGenObjC/metadata-symbols-32.m
index 61279e1dbed9..c75f6411e874 100644
--- a/test/CodeGenObjC/metadata-symbols-32.m
+++ b/test/CodeGenObjC/metadata-symbols-32.m
@@ -2,30 +2,30 @@
// CHECK: .lazy_reference .objc_class_name_J0
-// CHECK: @"\01L_OBJC_METH_VAR_NAME_{{[0-9]*}}" = private global {{.*}}section "__TEXT,__cstring,cstring_literals", align 1
-// CHECK: @"\01L_OBJC_METH_VAR_TYPE_{{[0-9]*}}" = private global {{.*}}section "__TEXT,__cstring,cstring_literals", align 1
+// CHECK: @OBJC_METH_VAR_NAME_{{[0-9]*}} = private global {{.*}}section "__TEXT,__cstring,cstring_literals", align 1
+// CHECK: @OBJC_METH_VAR_TYPE_{{[0-9]*}} = private global {{.*}}section "__TEXT,__cstring,cstring_literals", align 1
// CHECK: @"\01l_OBJC_PROTOCOLEXT_P" = private global
// CHECK-NOT: section
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{[0-9]*}}" = private global {{.*}}section "__TEXT,__cstring,cstring_literals", align 1
-// CHECK: @"\01L_OBJC_PROTOCOL_INSTANCE_METHODS_P" = private global {{.*}}section "__OBJC,__cat_inst_meth,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_PROTOCOL_CLASS_METHODS_P" = private global {{.*}}section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_PROTOCOL_P" = private global {{.*}}section "__OBJC,__protocol,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CLASS_PROTOCOLS_A" = private global {{.*}}section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CLASS_METHODS_A" = private global {{.*}}section "__OBJC,__cls_meth,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_METACLASS_A" = private global {{.*}}section "__OBJC,__meta_class,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_INSTANCE_VARIABLES_A" = private global {{.*}}section "__OBJC,__instance_vars,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_INSTANCE_METHODS_A" = private global {{.*}}section "__OBJC,__inst_meth,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_PROP_NAME_ATTR_{{[0-9]*}}" = private global {{.*}}section "__TEXT,__cstring,cstring_literals", align 1
+// CHECK: @OBJC_CLASS_NAME_{{[0-9]*}} = private global {{.*}}section "__TEXT,__cstring,cstring_literals", align 1
+// CHECK: @OBJC_PROTOCOL_INSTANCE_METHODS_P = private global {{.*}}section "__OBJC,__cat_inst_meth,regular,no_dead_strip", align 4
+// CHECK: @OBJC_PROTOCOL_CLASS_METHODS_P = private global {{.*}}section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4
+// CHECK: @OBJC_PROTOCOL_P = private global {{.*}}section "__OBJC,__protocol,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CLASS_PROTOCOLS_A = private global {{.*}}section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CLASS_METHODS_A = private global {{.*}}section "__OBJC,__cls_meth,regular,no_dead_strip", align 4
+// CHECK: @OBJC_METACLASS_A = private global {{.*}}section "__OBJC,__meta_class,regular,no_dead_strip", align 4
+// CHECK: @OBJC_INSTANCE_VARIABLES_A = private global {{.*}}section "__OBJC,__instance_vars,regular,no_dead_strip", align 4
+// CHECK: @OBJC_INSTANCE_METHODS_A = private global {{.*}}section "__OBJC,__inst_meth,regular,no_dead_strip", align 4
+// CHECK: @OBJC_PROP_NAME_ATTR_{{[0-9]*}} = private global {{.*}}section "__TEXT,__cstring,cstring_literals", align 1
// CHECK: @"\01l_OBJC_$_PROP_LIST_A" = private global {{.*}}section "__OBJC,__property,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CLASSEXT_A" = private global {{.*}}section "__OBJC,__class_ext,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CLASS_A" = private global {{.*}}section "__OBJC,__class,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CATEGORY_INSTANCE_METHODS_A_Cat" = private global {{.*}}section "__OBJC,__cat_inst_meth,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CATEGORY_CLASS_METHODS_A_Cat" = private global {{.*}}section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CATEGORY_A_Cat" = private global {{.*}}section "__OBJC,__category,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CLASS_REFERENCES_{{[0-9]*}}" = private global {{.*}}section "__OBJC,__cls_refs,literal_pointers,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_SELECTOR_REFERENCES_{{[0-9]*}}" = private externally_initialized global {{.*}}section "__OBJC,__message_refs,literal_pointers,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_SYMBOLS" = private global {{.*}}section "__OBJC,__symbols,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_MODULES" = private global {{.*}}section "__OBJC,__module_info,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CLASSEXT_A = private global {{.*}}section "__OBJC,__class_ext,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CLASS_A = private global {{.*}}section "__OBJC,__class,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CATEGORY_INSTANCE_METHODS_A_Cat = private global {{.*}}section "__OBJC,__cat_inst_meth,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CATEGORY_CLASS_METHODS_A_Cat = private global {{.*}}section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CATEGORY_A_Cat = private global {{.*}}section "__OBJC,__category,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CLASS_REFERENCES_{{[0-9]*}} = private global {{.*}}section "__OBJC,__cls_refs,literal_pointers,no_dead_strip", align 4
+// CHECK: @OBJC_SELECTOR_REFERENCES_{{[0-9]*}} = private externally_initialized global {{.*}}section "__OBJC,__message_refs,literal_pointers,no_dead_strip", align 4
+// CHECK: @OBJC_SYMBOLS = private global {{.*}}section "__OBJC,__symbols,regular,no_dead_strip", align 4
+// CHECK: @OBJC_MODULES = private global {{.*}}section "__OBJC,__module_info,regular,no_dead_strip", align 4
// Clang's Obj-C 32-bit doesn't emit ivars for the root class.
// CHECKX: @"\01L_OBJC_CLASS_VARIABLES_A" = private global {{.*}}section "__OBJC,__class_vars,regular,no_dead_strip", align 4
diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m
index 7b9609386900..8f598f41e551 100644
--- a/test/CodeGenObjC/metadata-symbols-64.m
+++ b/test/CodeGenObjC/metadata-symbols-64.m
@@ -5,9 +5,9 @@
// CHECK: @_objc_empty_vtable = external global
// CHECK: @"OBJC_CLASS_$_A" = global
// CHECK: @"OBJC_METACLASS_$_A" = global {{.*}} section "__DATA, __objc_data", align 8
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{[0-9]*}}" = private global {{.*}} section "__TEXT,__objc_classname,cstring_literals", align 1
-// CHECK: @"\01L_OBJC_METH_VAR_NAME_{{[0-9]*}}" = private global {{.*}} section "__TEXT,__objc_methname,cstring_literals", align 1
-// CHECK: @"\01L_OBJC_METH_VAR_TYPE_{{[0-9]*}}" = private global {{.*}} section "__TEXT,__objc_methtype,cstring_literals", align 1
+// CHECK: @OBJC_CLASS_NAME_{{[0-9]*}} = private global {{.*}} section "__TEXT,__objc_classname,cstring_literals", align 1
+// CHECK: @OBJC_METH_VAR_NAME_{{[0-9]*}} = private global {{.*}} section "__TEXT,__objc_methname,cstring_literals", align 1
+// CHECK: @OBJC_METH_VAR_TYPE_{{[0-9]*}} = private global {{.*}} section "__TEXT,__objc_methtype,cstring_literals", align 1
// CHECK: @"\01l_OBJC_$_CLASS_METHODS_A" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_P" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_PROTOCOL_CLASS_METHODS_P" = private global {{.*}} section "__DATA, __objc_const", align 8
@@ -17,20 +17,20 @@
// CHECK: @"\01l_OBJC_METACLASS_RO_$_A" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_INSTANCE_METHODS_A" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_INSTANCE_VARIABLES_A" = private global {{.*}} section "__DATA, __objc_const", align 8
-// CHECK: @"\01L_OBJC_PROP_NAME_ATTR_{{[0-9]*}}" = private global {{.*}} section "__TEXT,__cstring,cstring_literals", align 1
+// CHECK: @OBJC_PROP_NAME_ATTR_{{[0-9]*}} = private global {{.*}} section "__TEXT,__cstring,cstring_literals", align 1
// CHECK: @"\01l_OBJC_$_PROP_LIST_A" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_CLASS_RO_$_A" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_Cat" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_CATEGORY_CLASS_METHODS_A_$_Cat" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_CATEGORY_A_$_Cat" = private global {{.*}} section "__DATA, __objc_const", align 8
-// CHECK: @"\01L_OBJC_CLASSLIST_SUP_REFS_$_{{[0-9]*}}" = private global {{.*}} section "__DATA, __objc_superrefs, regular, no_dead_strip", align 8
-// CHECK: @"\01L_OBJC_SELECTOR_REFERENCES_" = private externally_initialized global {{.*}} section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
-// CHECK: @"\01L_OBJC_CLASSLIST_SUP_REFS_$_{{[0-9]*}}" = private global {{.*}} section "__DATA, __objc_superrefs, regular, no_dead_strip", align 8
+// CHECK: @"OBJC_CLASSLIST_SUP_REFS_$_{{[0-9]*}}" = private global {{.*}} section "__DATA, __objc_superrefs, regular, no_dead_strip", align 8
+// CHECK: @OBJC_SELECTOR_REFERENCES_ = private externally_initialized global {{.*}} section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
+// CHECK: @"OBJC_CLASSLIST_SUP_REFS_$_{{[0-9]*}}" = private global {{.*}} section "__DATA, __objc_superrefs, regular, no_dead_strip", align 8
// CHECK: @"OBJC_CLASS_$_B" = external global
-// CHECK: @"\01L_OBJC_CLASSLIST_REFERENCES_$_{{[0-9]*}}" = private global {{.*}} section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8
+// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_{{[0-9]*}}" = private global {{.*}} section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8
// CHECK: @"\01l_objc_msgSend_fixup_alloc" = weak hidden global {{.*}} section "__DATA, __objc_msgrefs, coalesced", align 16
-// CHECK: @"\01L_OBJC_LABEL_CLASS_$" = private global {{.*}} section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
-// CHECK: @"\01L_OBJC_LABEL_CATEGORY_$" = private global {{.*}} section "__DATA, __objc_catlist, regular, no_dead_strip", align 8
+// CHECK: @"OBJC_LABEL_CLASS_$" = private global {{.*}} section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
+// CHECK: @"OBJC_LABEL_CATEGORY_$" = private global {{.*}} section "__DATA, __objc_catlist, regular, no_dead_strip", align 8
// CHECK: @objc_msgSend_fpret(
// CHECK: @objc_msgSend_fixup(
diff --git a/test/CodeGenObjC/metadata_symbols.m b/test/CodeGenObjC/metadata_symbols.m
index 2b61c5d4bad3..2c44fb59bd2b 100644
--- a/test/CodeGenObjC/metadata_symbols.m
+++ b/test/CodeGenObjC/metadata_symbols.m
@@ -10,11 +10,11 @@
// CHECK-X86_64: @"OBJC_CLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 8
// CHECK-X86_64: @"OBJC_METACLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 8
-// CHECK-X86_64: @"\01L_OBJC_CLASS_NAME_" = {{.*}}, section "__TEXT,__objc_classname,cstring_literals", align 1
+// CHECK-X86_64: @OBJC_CLASS_NAME_ = {{.*}}, section "__TEXT,__objc_classname,cstring_literals", align 1
// CHECK-X86_64: @"OBJC_EHTYPE_$_EH1" = weak global {{.*}}, section "__DATA,__datacoal_nt,coalesced", align 8
// CHECK-X86_64: @"OBJC_EHTYPE_$_EH2" = external global
// CHECK-X86_64: @"OBJC_EHTYPE_$_EH3" = global {{.*}}, section "__DATA,__objc_const", align 8
-// CHECK-X86_64: @"\01L_OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
+// CHECK-X86_64: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
// CHECK-X86_64: define internal void @"\01-[A im0]"
// CHECK-X86_64: define internal void @"\01-[A(Cat) im1]"
@@ -34,11 +34,11 @@
// CHECK-ARMV6: @"OBJC_CLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 4
// CHECK-ARMV6: @"OBJC_METACLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 4
-// CHECK-ARMV6: @"\01L_OBJC_CLASS_NAME_" = {{.*}}, section "__TEXT,__objc_classname,cstring_literals", align 1
+// CHECK-ARMV6: @OBJC_CLASS_NAME_ = {{.*}}, section "__TEXT,__objc_classname,cstring_literals", align 1
// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH1" = weak global {{.*}}, section "__DATA,__datacoal_nt,coalesced", align 4
// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH2" = external global
// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH3" = global {{.*}}, section "__DATA,__objc_const", align 4
-// CHECK-ARMV6: @"\01L_OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 4
+// CHECK-ARMV6: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 4
// CHECK-ARMV6: define internal void @"\01-[A im0]"
// CHECK-ARMV6: define internal void @"\01-[A(Cat) im1]"
diff --git a/test/CodeGenObjC/non-lazy-classes.m b/test/CodeGenObjC/non-lazy-classes.m
index 760ddad068c5..400d3e9fdf94 100644
--- a/test/CodeGenObjC/non-lazy-classes.m
+++ b/test/CodeGenObjC/non-lazy-classes.m
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
-// RUN: grep '@".01L_OBJC_LABEL_NONLAZY_CLASS_$" = private global \[1 x .*\] .*@"OBJC_CLASS_$_A".*, section "__DATA, __objc_nlclslist, regular, no_dead_strip", align 8' %t
-// RUN: grep '@".01L_OBJC_LABEL_NONLAZY_CATEGORY_$" = private global \[1 x .*\] .*@".01l_OBJC_$_CATEGORY_A_$_Cat".*, section "__DATA, __objc_nlcatlist, regular, no_dead_strip", align 8' %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | \
+// RUN: FileCheck %s
+// CHECK: @"OBJC_LABEL_NONLAZY_CLASS_$" = private global [1 x {{.*}}] {{.*}}@"OBJC_CLASS_$_A"{{.*}}, section "__DATA, __objc_nlclslist, regular, no_dead_strip", align 8
+// CHECK: @"OBJC_LABEL_NONLAZY_CATEGORY_$" = private global [1 x {{.*}}] {{.*}}@"\01l_OBJC_$_CATEGORY_A_$_Cat"{{.*}}, section "__DATA, __objc_nlcatlist, regular, no_dead_strip", align 8
@interface A @end
@implementation A
diff --git a/test/CodeGenObjC/objc-align.m b/test/CodeGenObjC/objc-align.m
index 2b2133ea59b1..427633505872 100644
--- a/test/CodeGenObjC/objc-align.m
+++ b/test/CodeGenObjC/objc-align.m
@@ -1,33 +1,14 @@
// 32-bit
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o - %s | FileCheck %s
-// CHECK: @"\01L_OBJC_METACLASS_A" = private global {{.*}}, section "__OBJC,__meta_class,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CLASS_A" = private global {{.*}}, section "__OBJC,__class,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CATEGORY_A_Cat" = private global {{.*}}, section "__OBJC,__category,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_PROTOCOL_P" = private global {{.*}}, section "__OBJC,__protocol,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CLASS_PROTOCOLS_C" = private global {{.*}}, section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_METACLASS_C" = private global {{.*}}, section "__OBJC,__meta_class,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_CLASS_C" = private global {{.*}}, section "__OBJC,__class,regular,no_dead_strip", align 4
-// CHECK: @"\01L_OBJC_MODULES" = private global {{.*}}, section "__OBJC,__module_info,regular,no_dead_strip", align 4
-
-// 64-bit
-
-// RUNX: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s &&
-// RUNX: grep '@"OBJC_CLASS_$_A" = global' %t &&
-// RUNX: grep '@"OBJC_CLASS_$_C" = global' %t &&
-// RUNX: grep '@"OBJC_METACLASS_$_A" = global' %t &&
-// RUNX: grep '@"OBJC_METACLASS_$_C" = global' %t &&
-// RUNX: grep '@"\\01L_OBJC_CLASSLIST_REFERENCES_$_0" = private global .*, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8' %t &&
-// RUNX: grep '@"\\01L_OBJC_LABEL_CATEGORY_$" = private global .*, section "__DATA, __objc_catlist, regular, no_dead_strip", align 8' %t &&
-// RUNX: grep '@"\\01L_OBJC_LABEL_CLASS_$" = private global .*, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8' %t &&
-// RUNX: grep '@"\\01l_OBJC_$_CATEGORY_A_$_Cat" = private global .*, section "__DATA, __objc_const", align 8' %t &&
-// RUNX: grep '@"\\01l_OBJC_CLASS_PROTOCOLS_$_C" = private global .*, section "__DATA, __objc_const", align 8' %t &&
-// RUNX: grep '@"\\01l_OBJC_CLASS_RO_$_A" = private global .*, section "__DATA, __objc_const", align 8' %t &&
-// RUNX: grep '@"\\01l_OBJC_CLASS_RO_$_C" = private global .*, section "__DATA, __objc_const", align 8' %t &&
-// RUNX: grep '@"\\01l_OBJC_LABEL_PROTOCOL_$_P" = weak hidden global .*, section "__DATA, __objc_protolist, coalesced, no_dead_strip", align 8' %t &&
-// RUNX: grep '@"\\01l_OBJC_METACLASS_RO_$_A" = private global .*, section "__DATA, __objc_const", align 8' %t &&
-// RUNX: grep '@"\\01l_OBJC_METACLASS_RO_$_C" = private global .*, section "__DATA, __objc_const", align 8' %t &&
-// RUNX: grep '@"\\01l_OBJC_PROTOCOL_$_P" = weak hidden global .*, section "__DATA,__datacoal_nt,coalesced", align 8' %t &&
+// CHECK: @OBJC_METACLASS_A = private global {{.*}}, section "__OBJC,__meta_class,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CLASS_A = private global {{.*}}, section "__OBJC,__class,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CATEGORY_A_Cat = private global {{.*}}, section "__OBJC,__category,regular,no_dead_strip", align 4
+// CHECK: @OBJC_PROTOCOL_P = private global {{.*}}, section "__OBJC,__protocol,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CLASS_PROTOCOLS_C = private global {{.*}}, section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4
+// CHECK: @OBJC_METACLASS_C = private global {{.*}}, section "__OBJC,__meta_class,regular,no_dead_strip", align 4
+// CHECK: @OBJC_CLASS_C = private global {{.*}}, section "__OBJC,__class,regular,no_dead_strip", align 4
+// CHECK: @OBJC_MODULES = private global {{.*}}, section "__OBJC,__module_info,regular,no_dead_strip", align 4
@interface A @end
diff --git a/test/CodeGenObjC/objc-container-subscripting-1.m b/test/CodeGenObjC/objc-container-subscripting-1.m
index 91b7f468ea95..9ddfd39f63c4 100644
--- a/test/CodeGenObjC/objc-container-subscripting-1.m
+++ b/test/CodeGenObjC/objc-container-subscripting-1.m
@@ -19,7 +19,7 @@ int main() {
id oldObject = array[10];
// CHECK: [[ARR:%.*]] = load {{%.*}} [[array:%.*]], align 8
-// CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_"
+// CHECK-NEXT: [[SEL:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[ARRC:%.*]] = bitcast {{%.*}} [[ARR]] to i8*
// CHECK-NEXT: [[CALL:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i32)*)(i8* [[ARRC]], i8* [[SEL]], i32 10)
// CHECK-NEXT: store i8* [[CALL]], i8** [[OLDOBJ:%.*]], align 8
@@ -27,7 +27,7 @@ int main() {
val = (array[10] = oldObject);
// CHECK: [[THREE:%.*]] = load {{%.*}} [[array:%.*]], align 8
// CHECK-NEXT: [[FOUR:%.*]] = load i8** [[oldObject:%.*]], align 8
-// CHECK-NEXT: [[FIVE:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_2"
+// CHECK-NEXT: [[FIVE:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_2
// CHECK-NEXT: [[SIX:%.*]] = bitcast {{%.*}} [[THREE]] to i8*
// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*, i32)*)(i8* [[SIX]], i8* [[FIVE]], i8* [[FOUR]], i32 10)
// CHECK-NEXT: store i8* [[FOUR]], i8** [[val:%.*]]
@@ -38,7 +38,7 @@ int main() {
oldObject = dictionary[key];
// CHECK: [[SEVEN:%.*]] = load {{%.*}} [[DICTIONARY:%.*]], align 8
// CHECK-NEXT: [[EIGHT:%.*]] = load i8** [[KEY:%.*]], align 8
-// CHECK-NEXT: [[TEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_4"
+// CHECK-NEXT: [[TEN:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_4
// CHECK-NEXT: [[ELEVEN:%.*]] = bitcast {{%.*}} [[SEVEN]] to i8*
// CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8*)*)(i8* [[ELEVEN]], i8* [[TEN]], i8* [[EIGHT]])
// CHECK-NEXT: store i8* [[CALL1]], i8** [[oldObject:%.*]], align 8
@@ -48,7 +48,7 @@ int main() {
// CHECK: [[TWELVE:%.*]] = load {{%.*}} [[DICTIONARY]], align 8
// CHECK-NEXT: [[THIRTEEN:%.*]] = load i8** [[KEY]], align 8
// CHECK-NEXT: [[FOURTEEN:%.*]] = load i8** [[NEWOBJECT:%.*]], align 8
-// CHECK-NEXT: [[SIXTEEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_6"
+// CHECK-NEXT: [[SIXTEEN:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_6
// CHECK-NEXT: [[SEVENTEEN:%.*]] = bitcast {{%.*}} [[TWELVE]] to i8*
// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*, i8*)*)(i8* [[SEVENTEEN]], i8* [[SIXTEEN]], i8* [[FOURTEEN]], i8* [[THIRTEEN]])
// CHECK-NEXT: store i8* [[FOURTEEN]], i8** [[val:%.*]]
diff --git a/test/CodeGenObjC/objc-fixed-enum.m b/test/CodeGenObjC/objc-fixed-enum.m
index 55c2a7c1031e..eff317cdc513 100644
--- a/test/CodeGenObjC/objc-fixed-enum.m
+++ b/test/CodeGenObjC/objc-fixed-enum.m
@@ -34,13 +34,13 @@ typedef NSInteger Enum3;
int main() {
Enum0 e0 = Enum0One;
- // CHECK: call void @llvm.dbg.declare(metadata !{{.*}}, metadata ![[ENUM0:[0-9]+]])
+ // CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[ENUM0:[0-9]+]], metadata !{{.*}})
Enum1 e1 = Enum1One;
- // CHECK: call void @llvm.dbg.declare(metadata !{{.*}}, metadata ![[ENUM1:[0-9]+]])
+ // CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[ENUM1:[0-9]+]], metadata !{{.*}})
Enum2 e2 = Enum2One;
- // CHECK: call void @llvm.dbg.declare(metadata !{{.*}}, metadata ![[ENUM2:[0-9]+]])
+ // CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[ENUM2:[0-9]+]], metadata !{{.*}})
Enum3 e3 = Enum3One;
- // CHECK: call void @llvm.dbg.declare(metadata !{{.*}}, metadata ![[ENUM3:[0-9]+]])
+ // CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[ENUM3:[0-9]+]], metadata !{{.*}})
// -Werror and the following line ensures that these enums are not
// -treated as C++11 strongly typed enums.
@@ -51,14 +51,14 @@ int main() {
// CHECK: ![[ENUMERATOR3:[0-9]+]] = {{.*}}; [ DW_TAG_typedef ] [NSInteger] [line 6{{.*}}] [from long int]
// CHECK: ![[ENUMERATOR2:[0-9]+]] = {{.*}}; [ DW_TAG_enumeration_type ] [line 22{{.*}}] [from NSInteger]
-// CHECK: ![[ENUM0]] = metadata !{{{.*}}!"e0", metadata !{{[0-9]+}}, i32 {{[0-9]+}}, metadata ![[TYPE0:[0-9]+]]
-// CHECK: ![[TYPE0]] = metadata !{{{.*}}!"Enum0", {{.*}} metadata ![[ENUMERATOR0]]} ; [ DW_TAG_typedef ] [Enum0]
+// CHECK: ![[ENUM0]] = !{!"0x100\00e0\00{{[^,]*}}"{{, [^,]+, [^,]+}}, ![[TYPE0:[0-9]+]]} ; [ DW_TAG_auto_variable ]
+// CHECK: ![[TYPE0]] = !{!"0x16\00Enum0\00{{.*}}", {{.*}}, ![[ENUMERATOR0]]} ; [ DW_TAG_typedef ] [Enum0]
-// CHECK: ![[ENUM1]] = metadata !{{{.*}}!"e1", metadata !{{[0-9]+}}, i32 {{[0-9]+}}, metadata ![[TYPE1:[0-9]+]]
-// CHECK: ![[TYPE1]] = metadata !{{{.*}}!"Enum1", {{.*}} metadata ![[ENUMERATOR1]]} ; [ DW_TAG_typedef ] [Enum1]
+// CHECK: ![[ENUM1]] = !{!"0x100\00e1\00{{[^,]*}}"{{, [^,]+, [^,]+}}, ![[TYPE1:[0-9]+]]} ; [ DW_TAG_auto_variable ]
+// CHECK: ![[TYPE1]] = !{!"0x16\00Enum1\00{{.*}}", {{.*}}, ![[ENUMERATOR1]]} ; [ DW_TAG_typedef ] [Enum1]
-// CHECK: ![[ENUM2]] = metadata !{{{.*}}!"e2", metadata !{{[0-9]+}}, i32 {{[0-9]+}}, metadata ![[TYPE2:[0-9]+]]
-// CHECK: ![[TYPE2]] = metadata !{{{.*}}!"Enum2", {{.*}} metadata ![[ENUMERATOR2]]} ; [ DW_TAG_typedef ] [Enum2]
+// CHECK: ![[ENUM2]] = !{!"0x100\00e2\00{{[^,]*}}"{{, [^,]+, [^,]+}}, ![[TYPE2:[0-9]+]]} ; [ DW_TAG_auto_variable ]
+// CHECK: ![[TYPE2]] = !{!"0x16\00Enum2\00{{.*}}", {{.*}}, ![[ENUMERATOR2]]} ; [ DW_TAG_typedef ] [Enum2]
-// CHECK: ![[ENUM3]] = metadata !{{{.*}}!"e3", metadata !{{[0-9]+}}, i32 {{[0-9]+}}, metadata ![[TYPE3:[0-9]+]]
-// CHECK: ![[TYPE3]] = metadata !{{{.*}}!"Enum3", {{.*}} metadata ![[ENUMERATOR3]]} ; [ DW_TAG_typedef ] [Enum3]
+// CHECK: ![[ENUM3]] = !{!"0x100\00e3\00{{[^,]*}}"{{, [^,]+, [^,]+}}, ![[TYPE3:[0-9]+]]} ; [ DW_TAG_auto_variable ]
+// CHECK: ![[TYPE3]] = !{!"0x16\00Enum3\00{{.*}}", {{.*}}, ![[ENUMERATOR3]]} ; [ DW_TAG_typedef ] [Enum3]
diff --git a/test/CodeGenObjC/optimize-ivar-offset-load.m b/test/CodeGenObjC/optimize-ivar-offset-load.m
index d34ac137587f..29f70bea7a63 100644
--- a/test/CodeGenObjC/optimize-ivar-offset-load.m
+++ b/test/CodeGenObjC/optimize-ivar-offset-load.m
@@ -44,7 +44,7 @@ extern void foo(int);
}
}
@end
-// CHECK: [[ZERO:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 8, !invariant.load
+// CHECK: [[ZERO:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load
// CHECK: [[IVAR:%.*]] = load i64* @"OBJC_IVAR_$_SampleClass._value", align 8, !invariant.load
@interface Sample : SampleClass @end
@@ -59,6 +59,6 @@ extern void foo(int);
}
}
@end
-// CHECK: [[ZERO:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 8, !invariant.load
+// CHECK: [[ZERO:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load
// CHECK: [[IVAR:%.*]] = load i64* @"OBJC_IVAR_$_SampleClass._value", align 8, !invariant.load
diff --git a/test/CodeGenObjC/optimized-setter-ios-device.m b/test/CodeGenObjC/optimized-setter-ios-device.m
index 6fa322ab0f5f..ae8f34c081bf 100644
--- a/test/CodeGenObjC/optimized-setter-ios-device.m
+++ b/test/CodeGenObjC/optimized-setter-ios-device.m
@@ -26,8 +26,8 @@
@synthesize atomicPropertyCopy;
@end
-// CHECK: call arm_aapcscc void @objc_setProperty_nonatomic
-// CHECK: call arm_aapcscc void @objc_setProperty_nonatomic_copy
-// CHECK: call arm_aapcscc void @objc_setProperty_atomic
-// CHECK: call arm_aapcscc void @objc_setProperty_atomic_copy
+// CHECK: call void @objc_setProperty_nonatomic
+// CHECK: call void @objc_setProperty_nonatomic_copy
+// CHECK: call void @objc_setProperty_atomic
+// CHECK: call void @objc_setProperty_atomic_copy
diff --git a/test/CodeGenObjC/private-extern-selector-reference.m b/test/CodeGenObjC/private-extern-selector-reference.m
new file mode 100644
index 000000000000..c954d77027ce
--- /dev/null
+++ b/test/CodeGenObjC/private-extern-selector-reference.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple x86_64-apple-ios6.0.0 -emit-llvm -o - %s | FileCheck %s
+// rdar://18150301
+
+@interface Query
++ (void)_configureCI;
+@end
+
+__attribute__((visibility("default"))) __attribute__((availability(ios,introduced=7.0)))
+@interface ObserverQuery : Query @end
+
+@implementation ObserverQuery
++ (void)_configureCI {
+ [super _configureCI];
+}
+@end
+
+// CHECK: @"OBJC_METACLASS_$_ObserverQuery" = global %struct._class_t
+// CHECK: @OBJC_SELECTOR_REFERENCES_ = private externally_initialized global
diff --git a/test/CodeGenObjC/property-array-type.m b/test/CodeGenObjC/property-array-type.m
index 6600fd0f5965..84191ef6bfa5 100644
--- a/test/CodeGenObjC/property-array-type.m
+++ b/test/CodeGenObjC/property-array-type.m
@@ -26,5 +26,5 @@ typedef struct _GLKMatrix4 GLKMatrix4;
// CHECK: [[M:%.*]] = getelementptr inbounds %struct._GLKMatrix4* [[TMP:%.*]], i32 0, i32 0
// CHECK: [[ARRAYDECAY:%.*]] = getelementptr inbounds [16 x float]* [[M]], i32 0, i32 0
-// CHECK: [[SIX:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK: [[SIX:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, float*)*)(i8* [[SEVEN:%.*]], i8* [[SIX]], float* [[ARRAYDECAY]])
diff --git a/test/CodeGenObjC/property-type-mismatch.m b/test/CodeGenObjC/property-type-mismatch.m
index b920b45aef95..b5618cb513a8 100644
--- a/test/CodeGenObjC/property-type-mismatch.m
+++ b/test/CodeGenObjC/property-type-mismatch.m
@@ -13,5 +13,5 @@ void bar(Foo *x) {
// CHECK: [[C1:%.*]] = call float bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK: [[I:%.*]] = fadd float [[C1]], 1.000000e+00
// CHECK: [[CONV:%.*]] = fptosi float [[I]] to i32
-// CHECK: [[T3:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_2"
+// CHECK: [[T3:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_2
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m
index e156270f66fe..0f63a0fd14b0 100644
--- a/test/CodeGenObjC/property.m
+++ b/test/CodeGenObjC/property.m
@@ -136,33 +136,33 @@ void test7(Test7 *t) {
// CHECK: [[T:%.*]] = alloca [[TEST7]]*,
// CHECK-NEXT: store
// CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]** [[T]], align
-// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast
// CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32
// CHECK-NEXT: [[T4:%.*]] = and i32 [[T3]], 2
// CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8
-// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
// CHECK-NEXT: call void bitcast
// CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]** [[T]], align
-// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast
// CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32
// CHECK-NEXT: [[T4:%.*]] = or i32 [[T3]], 5
// CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8
-// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
// CHECK-NEXT: call void bitcast
// CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]** [[T]], align
-// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast
// CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32
// CHECK-NEXT: [[T4:%.*]] = xor i32 [[T3]], 8
// CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8
-// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
// CHECK-NEXT: call void bitcast
// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjC/reorder-synthesized-ivars.m b/test/CodeGenObjC/reorder-synthesized-ivars.m
index 8faafff2cdac..958d447b983c 100644
--- a/test/CodeGenObjC/reorder-synthesized-ivars.m
+++ b/test/CodeGenObjC/reorder-synthesized-ivars.m
@@ -38,21 +38,21 @@ typedef signed char BOOL;
}
@end
-// CHECK: @"{{.*}}" = private global [10 x i8] c"_boolean1
-// CHECK-NEXT: @"{{.*}}" = private global [10 x i8] c"_boolean2
-// CHECK-NEXT: @"{{.*}}" = private global [10 x i8] c"_boolean3
-// CHECK-NEXT: @"{{.*}}" = private global [10 x i8] c"_boolean4
-// CHECK-NEXT: @"{{.*}}" = private global [10 x i8] c"_boolean5
-// CHECK-NEXT: @"{{.*}}" = private global [10 x i8] c"_boolean6
-// CHECK-NEXT: @"{{.*}}" = private global [10 x i8] c"_boolean7
-// CHECK-NEXT: @"{{.*}}" = private global [10 x i8] c"_boolean8
-// CHECK-NEXT: @"{{.*}}" = private global [10 x i8] c"_boolean9
-// CHECK-NEXT: @"{{.*}}" = private global [9 x i8] c"_object1
-// CHECK-NEXT: @"{{.*}}" = private global [9 x i8] c"_object2
-// CHECK-NEXT: @"{{.*}}" = private global [9 x i8] c"_object3
-// CHECK-NEXT: @"{{.*}}" = private global [9 x i8] c"_object4
-// CHECK-NEXT: @"{{.*}}" = private global [9 x i8] c"_object5
-// CHECK-NEXT: @"{{.*}}" = private global [9 x i8] c"_object6
-// CHECK-NEXT: @"{{.*}}" = private global [9 x i8] c"_object7
-// CHECK-NEXT: @"{{.*}}" = private global [9 x i8] c"_object8
-// CHECK-NEXT: @"{{.*}}" = private global [9 x i8] c"_object9
+// CHECK: @{{.*}} = private global [10 x i8] c"_boolean1
+// CHECK-NEXT: @{{.*}} = private global [10 x i8] c"_boolean2
+// CHECK-NEXT: @{{.*}} = private global [10 x i8] c"_boolean3
+// CHECK-NEXT: @{{.*}} = private global [10 x i8] c"_boolean4
+// CHECK-NEXT: @{{.*}} = private global [10 x i8] c"_boolean5
+// CHECK-NEXT: @{{.*}} = private global [10 x i8] c"_boolean6
+// CHECK-NEXT: @{{.*}} = private global [10 x i8] c"_boolean7
+// CHECK-NEXT: @{{.*}} = private global [10 x i8] c"_boolean8
+// CHECK-NEXT: @{{.*}} = private global [10 x i8] c"_boolean9
+// CHECK-NEXT: @{{.*}} = private global [9 x i8] c"_object1
+// CHECK-NEXT: @{{.*}} = private global [9 x i8] c"_object2
+// CHECK-NEXT: @{{.*}} = private global [9 x i8] c"_object3
+// CHECK-NEXT: @{{.*}} = private global [9 x i8] c"_object4
+// CHECK-NEXT: @{{.*}} = private global [9 x i8] c"_object5
+// CHECK-NEXT: @{{.*}} = private global [9 x i8] c"_object6
+// CHECK-NEXT: @{{.*}} = private global [9 x i8] c"_object7
+// CHECK-NEXT: @{{.*}} = private global [9 x i8] c"_object8
+// CHECK-NEXT: @{{.*}} = private global [9 x i8] c"_object9
diff --git a/test/CodeGenObjC/selector-ref-invariance.m b/test/CodeGenObjC/selector-ref-invariance.m
index e356419de9e8..599bc3aa4c97 100644
--- a/test/CodeGenObjC/selector-ref-invariance.m
+++ b/test/CodeGenObjC/selector-ref-invariance.m
@@ -3,7 +3,7 @@
// rdar://6027699
void test(id x) {
-// CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", !invariant.load
+// CHECK: load i8** @OBJC_SELECTOR_REFERENCES_, !invariant.load
// CHECK: @objc_msgSend
[x foo];
}
diff --git a/test/CodeGenObjC/super-message-fragileabi.m b/test/CodeGenObjC/super-message-fragileabi.m
index b6c908624ef6..2c917d7fd6d0 100644
--- a/test/CodeGenObjC/super-message-fragileabi.m
+++ b/test/CodeGenObjC/super-message-fragileabi.m
@@ -24,7 +24,7 @@
{
;
}
-// CHECK: load %struct._objc_class** getelementptr inbounds (%struct._objc_class* @"\01L_OBJC_CLASS_BetterTable", i32 0, i32 1)
+// CHECK: load %struct._objc_class** getelementptr inbounds (%struct._objc_class* @OBJC_CLASS_BetterTable, i32 0, i32 1)
return self;
}
diff --git a/test/CodeGenObjC/tentative-cfconstantstring.m b/test/CodeGenObjC/tentative-cfconstantstring.m
index 714c1a402336..2b2601a54f8e 100644
--- a/test/CodeGenObjC/tentative-cfconstantstring.m
+++ b/test/CodeGenObjC/tentative-cfconstantstring.m
@@ -35,8 +35,8 @@ static inline void _inlineFunction() {
// CHECK: @_unnamed_cfstring_{{.*}} = private constant %struct.NSConstantString { i32* getelementptr inbounds ([24 x i32]* @__CFConstantStringClassReference, i32 0, i32 0)
// CHECK-LABEL: define internal void @_inlineFunction()
-// CHECK: [[ZERO:%.*]] = load %struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_
-// CHECK-NEXT: [[ONE:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_"
+// CHECK: [[ZERO:%.*]] = load %struct._class_t** @"OBJC_CLASSLIST_REFERENCES_
+// CHECK-NEXT: [[ONE:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[TWO:%.*]] = bitcast %struct._class_t* [[ZERO]] to i8*
// CHECK-NEXT: call void (i8*, i8*, [[T:%.*]]*, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, [[T:%.*]]*, ...)*)(i8* [[TWO]], i8* [[ONE]], [[T:%.*]]* bitcast (%struct.NSConstantString* @_unnamed_cfstring_{{.*}} to [[T:%.*]]*))
// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjC/undefined-protocol2.m b/test/CodeGenObjC/undefined-protocol2.m
new file mode 100644
index 000000000000..f171523b042c
--- /dev/null
+++ b/test/CodeGenObjC/undefined-protocol2.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s
+
+// Test that we produce a declaration for the protocol. It must be matched
+// by a definition in another TU, so external is the correct linkage
+// (not extern_weak).
+// CHECK: @"\01l_OBJC_PROTOCOL_$_p1" = external global
+
+@interface NSObject
+@end
+
+@protocol p1;
+
+@interface I1 : NSObject <p1>
+@end
+
+@implementation I1
+@end
diff --git a/test/CodeGenObjCXX/arc-cxx11-init-list.mm b/test/CodeGenObjCXX/arc-cxx11-init-list.mm
new file mode 100644
index 000000000000..da214dc38ad2
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-cxx11-init-list.mm
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -triple armv7-ios5.0 -std=c++11 -fobjc-arc -Os -emit-llvm -o - %s | FileCheck %s
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std {
+template <typename _Ep>
+class initializer_list {
+ const _Ep* __begin_;
+ size_t __size_;
+
+ initializer_list(const _Ep* __b, size_t __s);
+};
+}
+
+@interface I
++ (instancetype) new;
+@end
+
+void function(std::initializer_list<I *>);
+
+extern "C" void single() { function({ [I new] }); }
+
+// CHECK: [[INSTANCE:%.*]] = {{.*}} call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* {{.*}}, i8* {{.*}})
+// CHECK-NEXT: [[CAST:%.*]] = bitcast [{{[0-9]+}} x %0*]* %{{.*}} to i8**
+// CHECK-NEXT: store i8* [[INSTANCE]], i8** [[CAST]],
+// CHECK: call void @objc_release(i8* {{.*}})
+
+extern "C" void multiple() { function({ [I new], [I new] }); }
+
+// CHECK: [[INSTANCE:%.*]] = {{.*}} call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* {{.*}}, i8* {{.*}})
+// CHECK-NEXT: [[CAST:%.*]] = bitcast [{{[0-9]+}} x %0*]* %{{.*}} to i8**
+// CHECK-NEXT: store i8* [[INSTANCE]], i8** [[CAST]],
+// CHECK: call void @objc_release(i8* {{.*}})
+// CHECK-NEXT: icmp eq
+
+void external();
+
+extern "C" void extended() {
+ const auto && temporary = { [I new] };
+ external();
+}
+
+// CHECK: [[INSTANCE:%.*]] = {{.*}} call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* {{.*}}, i8* {{.*}})
+// CHECK-NEXT: [[CAST:%.*]] = bitcast [1 x %0*]* %{{.*}} to i8**
+// CHECK-NEXT: store i8* [[INSTANCE]], i8** [[CAST]],
+// CHECK: {{.*}} call void @_Z8externalv()
+// CHECK: {{.*}} call void @objc_release(i8* {{.*}})
+
+std::initializer_list<I *> il = { [I new] };
+
+// CHECK: [[POOL:%.*]] = {{.*}} call i8* @objc_autoreleasePoolPush()
+// CHECK: [[INSTANCE:%.*]] = {{.*}} call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* {{.*}}, i8* {{.*}})
+// CHECK-NEXT: store i8* [[INSTANCE]], i8** bitcast ([1 x %0*]* @_ZGR2il_ to i8**)
+// CHECK: {{.*}} call void @objc_autoreleasePoolPop(i8* [[POOL]])
+
diff --git a/test/CodeGenObjCXX/arc-cxx11-member-init.mm b/test/CodeGenObjCXX/arc-cxx11-member-init.mm
index 213e7a1b7b50..5129f9faca4d 100644
--- a/test/CodeGenObjCXX/arc-cxx11-member-init.mm
+++ b/test/CodeGenObjCXX/arc-cxx11-member-init.mm
@@ -23,10 +23,23 @@ class XClipboardDataSet
@end
// CHECK: [[mClipData:%.*]] = getelementptr inbounds %class.XClipboardDataSet*
-// CHECK: [[ZERO:%.*]] = load %struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_"
-// CHECK: [[ONE:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_"
+// CHECK: [[ZERO:%.*]] = load %struct._class_t** @"OBJC_CLASSLIST_REFERENCES_$_"
+// CHECK: [[ONE:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK: [[TWO:%.*]] = bitcast %struct._class_t* [[ZERO]] to i8*
// CHECK: [[CALL:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[TWO]], i8* [[ONE]])
// CHECK: [[THREE:%.*]] = bitcast i8* [[CALL]] to [[T:%.*]]*
// CHECK: store [[T]]* [[THREE]], [[T]]** [[mClipData]], align 8
+// rdar://18950072
+struct Butt { };
+
+__attribute__((objc_root_class))
+@interface Foo {
+ Butt x;
+ Butt y;
+ Butt z;
+}
+@end
+@implementation Foo
+@end
+// CHECK-NOT: define internal i8* @"\01-[Foo .cxx_construct
diff --git a/test/CodeGenObjCXX/arc-references.mm b/test/CodeGenObjCXX/arc-references.mm
index 10e7f64198db..0acb6d5659b0 100644
--- a/test/CodeGenObjCXX/arc-references.mm
+++ b/test/CodeGenObjCXX/arc-references.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
@interface A
@end
diff --git a/test/CodeGenObjCXX/arc.mm b/test/CodeGenObjCXX/arc.mm
index e31b0943b75e..6b42a4ca48e5 100644
--- a/test/CodeGenObjCXX/arc.mm
+++ b/test/CodeGenObjCXX/arc.mm
@@ -203,7 +203,7 @@ template void test37<Test37>(Test37 *a);
// CHECK-NEXT: [[COLL:%.*]] = bitcast i8* [[T2]] to [[NSARRAY]]*
// Make sure it's not immediately released before starting the iteration.
-// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
// CHECK-NEXT: @objc_msgSend
diff --git a/test/CodeGenObjCXX/block-id.mm b/test/CodeGenObjCXX/block-id.mm
new file mode 100644
index 000000000000..e324841b37f2
--- /dev/null
+++ b/test/CodeGenObjCXX/block-id.mm
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck %s
+
+// N.B. This test verifies that two blocks which are otherwise
+// indistinguishable receive distinct manglings.
+// We had a bug where the first two blocks in the global block map could
+// get the same unqualified-block mangling because the logic to handle
+// block-ids believed it was handling Itanium-style discriminators.
+
+template<typename T>
+int tf() {
+ return T::value;
+}
+int i1 = ^int {
+ struct S { enum { value = 1 };};
+ // CHECK-DAG: @_Z2tfIZUb_E1SEiv
+ return tf<S>();
+}();
+int i2 = ^int(int p1) {
+ struct S { enum { value = 2 };};
+ // CHECK-DAG: @_Z2tfIZUb0_E1SEiv
+ return tf<S>() + p1;
+}(1);
diff --git a/test/CodeGenObjCXX/debug-info-line.mm b/test/CodeGenObjCXX/debug-info-line.mm
new file mode 100644
index 000000000000..4c934f120708
--- /dev/null
+++ b/test/CodeGenObjCXX/debug-info-line.mm
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -gline-tables-only -fblocks -emit-llvm %s -o - | FileCheck %s
+
+void fn();
+
+struct foo {
+ ~foo();
+};
+
+void f1() {
+ ^{
+ foo f;
+ fn();
+ // CHECK: cleanup, !dbg [[DBG_F1:![0-9]*]]
+#line 100
+ }();
+}
+
+// CHECK-LABEL: define internal i8* @"\01-[TNSObject init]"
+@implementation TNSObject
+- (id)init
+{
+ foo f;
+ fn();
+ // CHECK: cleanup, !dbg [[DBG_TNSO:![0-9]*]]
+#line 200
+}
+@end
+
+// CHECK: [[DBG_F1]] = !MDLocation(line: 100,
+// CHECK: [[DBG_TNSO]] = !MDLocation(line: 200,
diff --git a/test/CodeGenObjCXX/destroy.mm b/test/CodeGenObjCXX/destroy.mm
new file mode 100644
index 000000000000..c53ac393de8f
--- /dev/null
+++ b/test/CodeGenObjCXX/destroy.mm
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -disable-llvm-optzns -o - %s | FileCheck %s
+// rdar://18249673
+
+@class MyObject;
+struct base {
+ ~base() = default;
+};
+struct derived : public base {
+ MyObject *myobject;
+};
+
+void test1() {
+ derived d1;
+}
+// CHECK-LABEL: define void @_Z5test1v()
+// CHECK: call void @_ZN7derivedC1Ev
+// CHECK: call void @_ZN7derivedD1Ev
+
+void test2() {
+ derived *d2 = new derived;
+ delete d2;
+}
+// CHECK-LABEL: define void @_Z5test2v()
+// CHECK: call void @_ZN7derivedC1Ev
+// CHECK: call void @_ZN7derivedD1Ev
+
+template <typename T>
+struct tderived : public base {
+ MyObject *myobject;
+};
+void test3() {
+ tderived<int> d1;
+}
+// CHECK-LABEL: define void @_Z5test3v()
+// CHECK: call void @_ZN8tderivedIiEC1Ev
+// CHECK: call void @_ZN8tderivedIiED1Ev
+
+void test4() {
+ tderived<int> *d2 = new tderived<int>;
+ delete d2;
+}
+// CHECK-LABEL: define void @_Z5test4v()
+// CHECK: call void @_ZN8tderivedIiEC1Ev
+// CHECK: call void @_ZN8tderivedIiED1Ev
+
+// CHECK-LABEL: define linkonce_odr void @_ZN8tderivedIiED2Ev
+// CHECK: call void @objc_storeStrong(i8** {{.*}}, i8* null)
+
+// CHECK-LABEL: define linkonce_odr void @_ZN7derivedD2Ev
+// CHECK: call void @objc_storeStrong(i8** {{.*}}, i8* null)
diff --git a/test/CodeGenObjCXX/externally-initialized-selectors.mm b/test/CodeGenObjCXX/externally-initialized-selectors.mm
index 0b7c24eadd84..7dcd727e5724 100644
--- a/test/CodeGenObjCXX/externally-initialized-selectors.mm
+++ b/test/CodeGenObjCXX/externally-initialized-selectors.mm
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fobjc-runtime=macosx-fragile-10.5 -o - -emit-llvm %s | FileCheck %s
// RUN: %clang_cc1 -o - -emit-llvm %s | FileCheck %s
-// CHECK: @"\01L_OBJC_SELECTOR_REFERENCES_" = private externally_initialized global
+// CHECK: @OBJC_SELECTOR_REFERENCES_ = private externally_initialized global
void test(id x) {
[x doSomething];
diff --git a/test/CodeGenObjCXX/lambda-expressions.mm b/test/CodeGenObjCXX/lambda-expressions.mm
index 435f805237c4..9129ff091ed3 100644
--- a/test/CodeGenObjCXX/lambda-expressions.mm
+++ b/test/CodeGenObjCXX/lambda-expressions.mm
@@ -4,8 +4,8 @@
typedef int (^fp)();
fp f() { auto x = []{ return 3; }; return x; }
-// MRC: @"\01L_OBJC_METH_VAR_NAME{{.*}}" = private global [5 x i8] c"copy\00"
-// MRC: @"\01L_OBJC_METH_VAR_NAME{{.*}}" = private global [12 x i8] c"autorelease\00"
+// MRC: @OBJC_METH_VAR_NAME{{.*}} = private global [5 x i8] c"copy\00"
+// MRC: @OBJC_METH_VAR_NAME{{.*}} = private global [12 x i8] c"autorelease\00"
// MRC-LABEL: define i32 ()* @_Z1fv(
// MRC-LABEL: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
// MRC: store i8* bitcast (i8** @_NSConcreteStackBlock to i8*)
diff --git a/test/CodeGenObjCXX/lvalue-reference-getter.mm b/test/CodeGenObjCXX/lvalue-reference-getter.mm
index 5205a7c378ba..87c132080aa3 100644
--- a/test/CodeGenObjCXX/lvalue-reference-getter.mm
+++ b/test/CodeGenObjCXX/lvalue-reference-getter.mm
@@ -23,6 +23,6 @@ static SetSection gSetSection;
// CHECK: [[SELF:%.*]] = alloca [[T6:%.*]]*, align
// CHECK: [[T0:%.*]] = load {{.*}}* [[SELF]], align
-// CHECK: [[T1:%.*]] = load {{.*}}* @"\01L_OBJC_SELECTOR_REFERENCES_"
+// CHECK: [[T1:%.*]] = load {{.*}}* @OBJC_SELECTOR_REFERENCES_
// CHECK: [[C:%.*]] = call dereferenceable({{[0-9]+}}) %struct.SetSection* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK: call dereferenceable({{[0-9]+}}) i32* @_ZN10SetSection2atEi(%struct.SetSection* [[C]]
diff --git a/test/CodeGenObjCXX/mangle-blocks.mm b/test/CodeGenObjCXX/mangle-blocks.mm
index 405e5282cda7..1f3f163adb4e 100644
--- a/test/CodeGenObjCXX/mangle-blocks.mm
+++ b/test/CodeGenObjCXX/mangle-blocks.mm
@@ -1,9 +1,8 @@
// RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck %s
-// CHECK: @_ZGVZZ3foovEUb_E5value = internal global i64 0
-// CHECK: @_ZZZN26externally_visible_statics1S3fooEiEd_Ub_E1k = linkonce_odr global i32 0
-// CHECK: @_ZZ26externally_visible_statics1S1xMUb_E1j = linkonce_odr global i32 0
-// CHECK: @_ZZZN26externally_visible_statics10inlinefuncEvEUb_E1i = linkonce_odr global i32 0
+// CHECK: @_ZZZN26externally_visible_statics1S3fooEiEd_Ub0_E1k = linkonce_odr global i32 0
+// CHECK: @_ZZ26externally_visible_statics1S1xMUb0_E1j = linkonce_odr global i32 0
+// CHECK: @_ZZZN26externally_visible_statics10inlinefuncEvEUb0_E1i = linkonce_odr global i32 0
int f();
@@ -27,7 +26,7 @@ int i = ^(int x) { return x;}(i);
- (void)method {
// CHECK: define internal signext i8 @"__11-[A method]_block_invoke"
(void)^(int x) {
- // CHECK: @"_ZZZ11-[A method]EUb0_E4name"
+ // CHECK: @"_ZZZ11-[A method]EUb1_E4name"
static const char *name = "hello";
return name[x];
};
@@ -45,7 +44,7 @@ namespace N {
// CHECK-LABEL: define internal signext i8 @___Z3fooi_block_invoke
void bar() {
(void)^(int x) {
- // CHECK: @_ZZZN1N3barEvEUb2_E4name
+ // CHECK: @_ZZZN1N3barEvEUb3_E4name
static const char *name = "hello";
return name[x];
};
@@ -57,7 +56,7 @@ class C {
};
C::C() {
(void)^(int x) {
- // CHECK: @_ZZZN1CC1EvEUb3_E5nameb
+ // CHECK: @_ZZZN1CC1EvEUb4_E5nameb
static const char *nameb = "hello";
return nameb[x];
};
diff --git a/test/CodeGenObjCXX/property-lvalue-capture.mm b/test/CodeGenObjCXX/property-lvalue-capture.mm
index 690ffa96b52a..1242246b24b2 100644
--- a/test/CodeGenObjCXX/property-lvalue-capture.mm
+++ b/test/CodeGenObjCXX/property-lvalue-capture.mm
@@ -24,10 +24,10 @@ typedef Quad2<double> Quad2d;
}
@end
-// CHECK: [[TWO:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", !invariant.load ![[MD_NUM:[0-9]+]]
+// CHECK: [[TWO:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_, !invariant.load ![[MD_NUM:[0-9]+]]
// CHECK: [[THREE:%.*]] = bitcast [[ONET:%.*]]* [[ONE:%.*]] to i8*
// CHECK: [[CALL:%.*]] = call nonnull %struct.Quad2* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %struct.Quad2* (i8*, i8*)*)(i8* [[THREE]], i8* [[TWO]])
-// CHECK: [[FOUR:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_2", !invariant.load ![[MD_NUM]]
+// CHECK: [[FOUR:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_2, !invariant.load ![[MD_NUM]]
// CHECK: [[FIVE:%.*]] = bitcast [[ONET]]* [[ZERO:%.*]] to i8*
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %struct.Quad2*)*)(i8* [[FIVE]], i8* [[FOUR]], %struct.Quad2* nonnull [[CALL]])
@@ -47,7 +47,7 @@ void test(C *c, const A &a) {
}
// CHECK: [[ONE1:%.*]] = load %struct.A** [[AADDR:%.*]], align 8
-// CHECK: [[TWO1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_5", !invariant.load ![[MD_NUM]]
+// CHECK: [[TWO1:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_5, !invariant.load ![[MD_NUM]]
// CHECK: [[THREE1:%.*]] = bitcast [[TWOT:%.*]]* [[ZERO1:%.*]] to i8*
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %struct.A*)*)(i8* [[THREE1]], i8* [[TWO1]], %struct.A* dereferenceable({{[0-9]+}}) [[ONE1]])
// CHECK: store %struct.A* [[ONE1]], %struct.A** [[RESULT:%.*]], align 8
diff --git a/test/CodeGenObjCXX/property-object-reference.mm b/test/CodeGenObjCXX/property-object-reference.mm
index ec311f1956a4..691e6fff8d84 100644
--- a/test/CodeGenObjCXX/property-object-reference.mm
+++ b/test/CodeGenObjCXX/property-object-reference.mm
@@ -25,11 +25,11 @@ static Foo gFoo;
@end
// CHECK: [[T0:%.*]] = load {{%.*}} [[S0:%.*]]
-// CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK: [[T2:%.*]] = bitcast {{%.*}} [[T0]] to i8*
// CHECK: @objc_msgSend
// CHECK: [[R0:%.*]] = load {{%.*}} [[U0:%.*]]
-// CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK: load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK: [[R2:%.*]] = bitcast {{%.*}} [[R0]] to i8*
// CHECK: @objc_msgSend
diff --git a/test/CodeGenObjCXX/property-objects.mm b/test/CodeGenObjCXX/property-objects.mm
index c79c280eddb1..73ed21dcb7d8 100644
--- a/test/CodeGenObjCXX/property-objects.mm
+++ b/test/CodeGenObjCXX/property-objects.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -g -o - | FileCheck %s
class S {
public:
@@ -35,6 +35,11 @@ struct CGRect {
// CHECK: call dereferenceable({{[0-9]+}}) %class.S* @_ZN1SaSERKS_
// CHECK-NEXT: ret void
+// Don't attach debug locations to the prologue instructions. These were
+// leaking over from the previous function emission by accident.
+// CHECK: define internal void @"\01-[I setBounds:]"
+// CHECK-NOT: !dbg
+// CHECK: call void @llvm.dbg.declare
- (void)setFrame:(CGRect)frameRect {}
- (CGRect)frame {return bounds;}
diff --git a/test/CodeGenObjCXX/subst-sel.mm b/test/CodeGenObjCXX/subst-sel.mm
new file mode 100644
index 000000000000..f4a2b840fe70
--- /dev/null
+++ b/test/CodeGenObjCXX/subst-sel.mm
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// CHECK: @_Z4bad1P8NSObjectP13objc_selectorP11objc_objectS4_
+void bad1(struct NSObject *, SEL, id, id) {}
diff --git a/test/CodeGenOpenCL/addr-space-struct-arg.cl b/test/CodeGenOpenCL/addr-space-struct-arg.cl
index f04923d39c58..d711f78d4ef0 100644
--- a/test/CodeGenOpenCL/addr-space-struct-arg.cl
+++ b/test/CodeGenOpenCL/addr-space-struct-arg.cl
@@ -1,23 +1,23 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -ffake-address-space-map -triple i686-pc-darwin | FileCheck %s
-
-typedef struct {
- int cells[9];
-} Mat3X3;
-
-typedef struct {
- int cells[16];
-} Mat4X4;
-
-Mat4X4 __attribute__((noinline)) foo(Mat3X3 in) {
- Mat4X4 out;
- return out;
-}
-
-kernel void ker(global Mat3X3 *in, global Mat4X4 *out) {
- out[0] = foo(in[1]);
-}
-
-// Expect two mem copies: one for the argument "in", and one for
-// the return value.
-// CHECK: call void @llvm.memcpy.p0i8.p1i8.i32(i8*
-// CHECK: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)*
+// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -ffake-address-space-map -triple i686-pc-darwin | FileCheck %s
+
+typedef struct {
+ int cells[9];
+} Mat3X3;
+
+typedef struct {
+ int cells[16];
+} Mat4X4;
+
+Mat4X4 __attribute__((noinline)) foo(Mat3X3 in) {
+ Mat4X4 out;
+ return out;
+}
+
+kernel void ker(global Mat3X3 *in, global Mat4X4 *out) {
+ out[0] = foo(in[1]);
+}
+
+// Expect two mem copies: one for the argument "in", and one for
+// the return value.
+// CHECK: call void @llvm.memcpy.p0i8.p1i8.i32(i8*
+// CHECK: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)*
diff --git a/test/CodeGenOpenCL/address-space-constant-initializers.cl b/test/CodeGenOpenCL/address-space-constant-initializers.cl
index ae8cedc1ca5b..079b0706f498 100644
--- a/test/CodeGenOpenCL/address-space-constant-initializers.cl
+++ b/test/CodeGenOpenCL/address-space-constant-initializers.cl
@@ -12,7 +12,7 @@ typedef struct {
} ConstantArrayPointerStruct;
// CHECK: %struct.ConstantArrayPointerStruct = type { float addrspace(3)* }
-// CHECK: addrspace(3) global %struct.ConstantArrayPointerStruct { float addrspace(3)* bitcast (i8 addrspace(3)* getelementptr (i8 addrspace(3)* bitcast (%struct.ArrayStruct addrspace(3)* @constant_array_struct to i8 addrspace(3)*), i64 4) to float addrspace(3)*) }
+// CHECK: addrspace(3) constant %struct.ConstantArrayPointerStruct { float addrspace(3)* bitcast (i8 addrspace(3)* getelementptr (i8 addrspace(3)* bitcast (%struct.ArrayStruct addrspace(3)* @constant_array_struct to i8 addrspace(3)*), i64 4) to float addrspace(3)*) }
// Bug 18567
__constant ConstantArrayPointerStruct constant_array_pointer_struct = {
&constant_array_struct.f
diff --git a/test/CodeGenOpenCL/address-spaces-conversions.cl b/test/CodeGenOpenCL/address-spaces-conversions.cl
new file mode 100644
index 000000000000..bc80f47f5f42
--- /dev/null
+++ b/test/CodeGenOpenCL/address-spaces-conversions.cl
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -ffake-address-space-map -cl-std=CL2.0 -emit-llvm -o - | FileCheck %s
+
+// test that we generate address space casts everywhere we need conversions of
+// pointers to different address spaces
+
+void test(global int *arg_glob, generic int *arg_gen) {
+ int var_priv;
+ arg_gen = arg_glob; // implicit cast global -> generic
+ // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)*
+ arg_gen = &var_priv; // implicit cast with obtaining adr, private -> generic
+ // CHECK: %{{[0-9]+}} = addrspacecast i32* %var_priv to i32 addrspace(4)*
+ arg_glob = (global int *)arg_gen; // explicit cast
+ // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(4)* %{{[0-9]+}} to i32 addrspace(1)*
+ global int *var_glob =
+ (global int *)arg_glob; // explicit cast in the same address space
+ // CHECK-NOT: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(1)*
+ var_priv = arg_gen - arg_glob; // arithmetic operation
+ // CHECK: %{{.*}} = ptrtoint i32 addrspace(4)* %{{.*}} to i64
+ // CHECK: %{{.*}} = ptrtoint i32 addrspace(1)* %{{.*}} to i64
+ var_priv = arg_gen > arg_glob; // comparison
+ // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)*
+}
diff --git a/test/CodeGenOpenCL/amdgpu-num-gpr-attr.cl b/test/CodeGenOpenCL/amdgpu-num-gpr-attr.cl
new file mode 100644
index 000000000000..35bdcead3128
--- /dev/null
+++ b/test/CodeGenOpenCL/amdgpu-num-gpr-attr.cl
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple amdgcn-- -target-cpu tahiti -O0 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O0 -emit-llvm -verify -o - %s | FileCheck -check-prefix=X86 %s
+
+// Make sure this is silently accepted on other targets.
+
+__attribute__((amdgpu_num_vgpr(64))) // expected-no-diagnostics
+kernel void test_num_vgpr64() {
+// CHECK: define void @test_num_vgpr64() [[ATTR_VGPR64:#[0-9]+]]
+}
+
+__attribute__((amdgpu_num_sgpr(32))) // expected-no-diagnostics
+kernel void test_num_sgpr32() {
+// CHECK: define void @test_num_sgpr32() [[ATTR_SGPR32:#[0-9]+]]
+}
+
+__attribute__((amdgpu_num_vgpr(64), amdgpu_num_sgpr(32))) // expected-no-diagnostics
+kernel void test_num_vgpr64_sgpr32() {
+// CHECK: define void @test_num_vgpr64_sgpr32() [[ATTR_VGPR64_SGPR32:#[0-9]+]]
+
+}
+
+__attribute__((amdgpu_num_sgpr(20), amdgpu_num_vgpr(40))) // expected-no-diagnostics
+kernel void test_num_sgpr20_vgpr40() {
+// CHECK: define void @test_num_sgpr20_vgpr40() [[ATTR_SGPR20_VGPR40:#[0-9]+]]
+}
+
+__attribute__((amdgpu_num_vgpr(0))) // expected-no-diagnostics
+kernel void test_num_vgpr0() {
+}
+
+__attribute__((amdgpu_num_sgpr(0))) // expected-no-diagnostics
+kernel void test_num_sgpr0() {
+}
+
+__attribute__((amdgpu_num_vgpr(0), amdgpu_num_sgpr(0))) // expected-no-diagnostics
+kernel void test_num_vgpr0_sgpr0() {
+}
+
+
+// X86-NOT: "amdgpu_num_vgpr"
+// X86-NOT: "amdgpu_num_sgpr"
+
+// CHECK-DAG-NOT: "amdgpu_num_vgpr"="0"
+// CHECK-DAG-NOT: "amdgpu_num_sgpr"="0"
+// CHECK-DAG: attributes [[ATTR_VGPR64]] = { nounwind "amdgpu_num_vgpr"="64"
+// CHECK-DAG: attributes [[ATTR_SGPR32]] = { nounwind "amdgpu_num_sgpr"="32"
+// CHECK-DAG: attributes [[ATTR_VGPR64_SGPR32]] = { nounwind "amdgpu_num_sgpr"="32" "amdgpu_num_vgpr"="64"
+// CHECK-DAG: attributes [[ATTR_SGPR20_VGPR40]] = { nounwind "amdgpu_num_sgpr"="20" "amdgpu_num_vgpr"="40"
diff --git a/test/CodeGenOpenCL/builtins-r600.cl b/test/CodeGenOpenCL/builtins-r600.cl
index cebeba185ea3..3e416b0323c2 100644
--- a/test/CodeGenOpenCL/builtins-r600.cl
+++ b/test/CodeGenOpenCL/builtins-r600.cl
@@ -1,5 +1,6 @@
// REQUIRES: r600-registered-target
// RUN: %clang_cc1 -triple r600-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
@@ -31,16 +32,16 @@ void test_div_scale_f32(global float* out, global int* flagout, float a, float b
// CHECK-LABEL: @test_div_fmas_f32
// CHECK: call float @llvm.AMDGPU.div.fmas.f32
-void test_div_fmas_f32(global float* out, float a, float b, float c)
+void test_div_fmas_f32(global float* out, float a, float b, float c, int d)
{
- *out = __builtin_amdgpu_div_fmasf(a, b, c);
+ *out = __builtin_amdgpu_div_fmasf(a, b, c, d);
}
// CHECK-LABEL: @test_div_fmas_f64
// CHECK: call double @llvm.AMDGPU.div.fmas.f64
-void test_div_fmas_f64(global double* out, double a, double b, double c)
+void test_div_fmas_f64(global double* out, double a, double b, double c, int d)
{
- *out = __builtin_amdgpu_div_fmas(a, b, c);
+ *out = __builtin_amdgpu_div_fmas(a, b, c, d);
}
// CHECK-LABEL: @test_div_fixup_f32
@@ -112,3 +113,31 @@ void test_rsq_clamped_f64(global double* out, double a)
{
*out = __builtin_amdgpu_rsq_clamped(a);
}
+
+// CHECK-LABEL: @test_ldexp_f32
+// CHECK: call float @llvm.AMDGPU.ldexp.f32
+void test_ldexp_f32(global float* out, float a, int b)
+{
+ *out = __builtin_amdgpu_ldexpf(a, b);
+}
+
+// CHECK-LABEL: @test_ldexp_f64
+// CHECK: call double @llvm.AMDGPU.ldexp.f64
+void test_ldexp_f64(global double* out, double a, int b)
+{
+ *out = __builtin_amdgpu_ldexp(a, b);
+}
+
+// CHECK-LABEL: @test_class_f32
+// CHECK: call i1 @llvm.AMDGPU.class.f32
+void test_class_f32(global float* out, float a, int b)
+{
+ *out = __builtin_amdgpu_classf(a, b);
+}
+
+// CHECK-LABEL: @test_class_f64
+// CHECK: call i1 @llvm.AMDGPU.class.f64
+void test_class_f64(global double* out, double a, int b)
+{
+ *out = __builtin_amdgpu_class(a, b);
+}
diff --git a/test/CodeGenOpenCL/const-str-array-decay.cl b/test/CodeGenOpenCL/const-str-array-decay.cl
new file mode 100644
index 000000000000..dbbe08989cb1
--- /dev/null
+++ b/test/CodeGenOpenCL/const-str-array-decay.cl
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -ffake-address-space-map | FileCheck %s
+
+int test_func(constant char* foo);
+
+kernel void str_array_decy() {
+ test_func("Test string literal");
+}
+
+// CHECK: i8 addrspace(3)* getelementptr inbounds ([20 x i8] addrspace(3)*
+// CHECK-NOT: addrspacecast
+
diff --git a/test/CodeGenOpenCL/constant-addr-space-globals.cl b/test/CodeGenOpenCL/constant-addr-space-globals.cl
new file mode 100644
index 000000000000..92fb9790b5fb
--- /dev/null
+++ b/test/CodeGenOpenCL/constant-addr-space-globals.cl
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -ffake-address-space-map -emit-llvm -o - | FileCheck %s
+
+// CHECK: @array = addrspace({{[0-9]+}}) constant
+__constant float array[2] = {0.0f, 1.0f};
+
+kernel void test(global float *out) {
+ *out = array[0];
+}
diff --git a/test/CodeGenOpenCL/denorms-are-zero.cl b/test/CodeGenOpenCL/denorms-are-zero.cl
new file mode 100644
index 000000000000..488004fa4fc3
--- /dev/null
+++ b/test/CodeGenOpenCL/denorms-are-zero.cl
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -S -cl-denorms-are-zero -o - %s 2>&1
+
+// This test just checks that the -cl-denorms-are-zero argument is accepted
+// by clang. This option is currently a no-op, which is allowed by the
+// OpenCL specification.
diff --git a/test/CodeGenOpenCL/fpmath.cl b/test/CodeGenOpenCL/fpmath.cl
index 704fcd739ac4..ef4da845529c 100644
--- a/test/CodeGenOpenCL/fpmath.cl
+++ b/test/CodeGenOpenCL/fpmath.cl
@@ -22,4 +22,4 @@ double dpscalardiv(double a, double b) {
return a / b;
}
-// CHECK: ![[MD]] = metadata !{float 2.500000e+00}
+// CHECK: ![[MD]] = !{float 2.500000e+00}
diff --git a/test/CodeGenOpenCL/kernel-arg-info.cl b/test/CodeGenOpenCL/kernel-arg-info.cl
index 9832604b0459..4bc191e1d75f 100644
--- a/test/CodeGenOpenCL/kernel-arg-info.cl
+++ b/test/CodeGenOpenCL/kernel-arg-info.cl
@@ -1,28 +1,55 @@
-// RUN: %clang_cc1 %s -cl-kernel-arg-info -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s
+// RUN: %clang_cc1 %s -cl-kernel-arg-info -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s -check-prefix ARGINFO
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s -check-prefix NO-ARGINFO
kernel void foo(__global int * restrict X, const int Y,
volatile int anotherArg, __constant float * restrict Z) {
*X = Y + anotherArg;
}
-// CHECK: metadata !{metadata !"kernel_arg_addr_space", i32 1, i32 0, i32 0, i32 2}
-// CHECK: metadata !{metadata !"kernel_arg_access_qual", metadata !"none", metadata !"none", metadata !"none", metadata !"none"}
-// CHECK: metadata !{metadata !"kernel_arg_type", metadata !"int*", metadata !"int", metadata !"int", metadata !"float*"}
-// CHECK: metadata !{metadata !"kernel_arg_type_qual", metadata !"restrict", metadata !"const", metadata !"volatile", metadata !"restrict const"}
-// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"X", metadata !"Y", metadata !"anotherArg", metadata !"Z"}
+// CHECK: !{!"kernel_arg_addr_space", i32 1, i32 0, i32 0, i32 2}
+// CHECK: !{!"kernel_arg_access_qual", !"none", !"none", !"none", !"none"}
+// CHECK: !{!"kernel_arg_type", !"int*", !"int", !"int", !"float*"}
+// CHECK: !{!"kernel_arg_base_type", !"int*", !"int", !"int", !"float*"}
+// CHECK: !{!"kernel_arg_type_qual", !"restrict", !"const", !"volatile", !"restrict const"}
+// ARGINFO: !{!"kernel_arg_name", !"X", !"Y", !"anotherArg", !"Z"}
+// NO-ARGINFO-NOT: !{!"kernel_arg_name", !"X", !"Y", !"anotherArg", !"Z"}
kernel void foo2(read_only image1d_t img1, image2d_t img2, write_only image2d_array_t img3) {
}
-// CHECK: metadata !{metadata !"kernel_arg_addr_space", i32 1, i32 1, i32 1}
-// CHECK: metadata !{metadata !"kernel_arg_access_qual", metadata !"read_only", metadata !"read_only", metadata !"write_only"}
-// CHECK: metadata !{metadata !"kernel_arg_type", metadata !"image1d_t", metadata !"image2d_t", metadata !"image2d_array_t"}
-// CHECK: metadata !{metadata !"kernel_arg_type_qual", metadata !"", metadata !"", metadata !""}
-// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"img1", metadata !"img2", metadata !"img3"}
+// CHECK: !{!"kernel_arg_addr_space", i32 1, i32 1, i32 1}
+// CHECK: !{!"kernel_arg_access_qual", !"read_only", !"read_only", !"write_only"}
+// CHECK: !{!"kernel_arg_type", !"image1d_t", !"image2d_t", !"image2d_array_t"}
+// CHECK: !{!"kernel_arg_base_type", !"image1d_t", !"image2d_t", !"image2d_array_t"}
+// CHECK: !{!"kernel_arg_type_qual", !"", !"", !""}
+// ARGINFO: !{!"kernel_arg_name", !"img1", !"img2", !"img3"}
+// NO-ARGINFO-NOT: !{!"kernel_arg_name", !"img1", !"img2", !"img3"}
kernel void foo3(__global half * X) {
}
-// CHECK: metadata !{metadata !"kernel_arg_addr_space", i32 1}
-// CHECK: metadata !{metadata !"kernel_arg_access_qual", metadata !"none"}
-// CHECK: metadata !{metadata !"kernel_arg_type", metadata !"half*"}
-// CHECK: metadata !{metadata !"kernel_arg_type_qual", metadata !""}
-// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"X"}
+// CHECK: !{!"kernel_arg_addr_space", i32 1}
+// CHECK: !{!"kernel_arg_access_qual", !"none"}
+// CHECK: !{!"kernel_arg_type", !"half*"}
+// CHECK: !{!"kernel_arg_base_type", !"half*"}
+// CHECK: !{!"kernel_arg_type_qual", !""}
+// ARGINFO: !{!"kernel_arg_name", !"X"}
+// NO-ARGINFO-NOT: !{!"kernel_arg_name", !"X"}
+
+typedef unsigned int myunsignedint;
+kernel void foo4(__global unsigned int * X, __global myunsignedint * Y) {
+}
+// CHECK: !{!"kernel_arg_addr_space", i32 1, i32 1}
+// CHECK: !{!"kernel_arg_access_qual", !"none", !"none"}
+// CHECK: !{!"kernel_arg_type", !"uint*", !"myunsignedint*"}
+// CHECK: !{!"kernel_arg_base_type", !"uint*", !"uint*"}
+// CHECK: !{!"kernel_arg_type_qual", !"", !""}
+// ARGINFO: !{!"kernel_arg_name", !"X", !"Y"}
+// NO-ARGINFO-NOT: !{!"kernel_arg_name", !"X", !"Y"}
+
+typedef image1d_t myImage;
+kernel void foo5(read_only myImage img1, write_only image1d_t img2) {
+}
+// CHECK: !{!"kernel_arg_access_qual", !"read_only", !"write_only"}
+// CHECK: !{!"kernel_arg_type", !"myImage", !"image1d_t"}
+// CHECK: !{!"kernel_arg_base_type", !"image1d_t", !"image1d_t"}
+// ARGINFO: !{!"kernel_arg_name", !"img1", !"img2"}
+// NO-ARGINFO-NOT: !{!"kernel_arg_name", !"img1", !"img2"}
diff --git a/test/CodeGenOpenCL/kernel-attributes.cl b/test/CodeGenOpenCL/kernel-attributes.cl
index 0825ffc0336f..8f22d611b820 100644
--- a/test/CodeGenOpenCL/kernel-attributes.cl
+++ b/test/CodeGenOpenCL/kernel-attributes.cl
@@ -8,9 +8,9 @@ kernel __attribute__((vec_type_hint(uint4))) __attribute__((work_group_size_hint
// CHECK: opencl.kernels = !{[[MDNODE0:![0-9]+]], [[MDNODE3:![0-9]+]]}
-// CHECK: [[MDNODE0]] = metadata !{void (i32)* @kernel1, metadata [[MDNODE1:![0-9]+]], metadata [[MDNODE2:![0-9]+]]}
-// CHECK: [[MDNODE1]] = metadata !{metadata !"vec_type_hint", i32 undef, i32 1}
-// CHECK: [[MDNODE2]] = metadata !{metadata !"reqd_work_group_size", i32 1, i32 2, i32 4}
-// CHECK: [[MDNODE3]] = metadata !{void (i32)* @kernel2, metadata [[MDNODE4:![0-9]+]], metadata [[MDNODE5:![0-9]+]]}
-// CHECK: [[MDNODE4]] = metadata !{metadata !"vec_type_hint", <4 x i32> undef, i32 0}
-// CHECK: [[MDNODE5]] = metadata !{metadata !"work_group_size_hint", i32 8, i32 16, i32 32}
+// CHECK: [[MDNODE0]] = !{void (i32)* @kernel1, {{.*}} [[MDNODE1:![0-9]+]], [[MDNODE2:![0-9]+]]}
+// CHECK: [[MDNODE1]] = !{!"vec_type_hint", i32 undef, i32 1}
+// CHECK: [[MDNODE2]] = !{!"reqd_work_group_size", i32 1, i32 2, i32 4}
+// CHECK: [[MDNODE3]] = !{void (i32)* @kernel2, {{.*}} [[MDNODE4:![0-9]+]], [[MDNODE5:![0-9]+]]}
+// CHECK: [[MDNODE4]] = !{!"vec_type_hint", <4 x i32> undef, i32 0}
+// CHECK: [[MDNODE5]] = !{!"work_group_size_hint", i32 8, i32 16, i32 32}
diff --git a/test/CodeGenOpenCL/kernel-metadata.cl b/test/CodeGenOpenCL/kernel-metadata.cl
index 3e10a119d044..ef3758fccaa0 100644
--- a/test/CodeGenOpenCL/kernel-metadata.cl
+++ b/test/CodeGenOpenCL/kernel-metadata.cl
@@ -7,4 +7,9 @@ __kernel void kernel_function() {
}
// CHECK: !opencl.kernels = !{!0}
-// CHECK: !0 = metadata !{void ()* @kernel_function}
+// CHECK: !0 = !{void ()* @kernel_function, !1, !2, !3, !4, !5}
+// CHECK: !1 = !{!"kernel_arg_addr_space"}
+// CHECK: !2 = !{!"kernel_arg_access_qual"}
+// CHECK: !3 = !{!"kernel_arg_type"}
+// CHECK: !4 = !{!"kernel_arg_base_type"}
+// CHECK: !5 = !{!"kernel_arg_type_qual"}
diff --git a/test/CodeGenOpenCL/local-initializer-undef.cl b/test/CodeGenOpenCL/local-initializer-undef.cl
new file mode 100644
index 000000000000..5d34f56b821d
--- /dev/null
+++ b/test/CodeGenOpenCL/local-initializer-undef.cl
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -O0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s
+
+typedef struct Foo {
+ int x;
+ float y;
+ float z;
+} Foo;
+
+// CHECK-DAG: @test.lds_int = internal addrspace(2) global i32 undef
+// CHECK-DAG: @test.lds_int_arr = internal addrspace(2) global [128 x i32] undef
+// CHECK-DAG: @test.lds_struct = internal addrspace(2) global %struct.Foo undef
+// CHECK-DAG: @test.lds_struct_arr = internal addrspace(2) global [64 x %struct.Foo] undef
+__kernel void test()
+{
+ __local int lds_int;
+ __local int lds_int_arr[128];
+ __local Foo lds_struct;
+ __local Foo lds_struct_arr[64];
+
+ lds_int = 1;
+ lds_int_arr[0] = 1;
+ lds_struct.x = 1;
+ lds_struct_arr[0].x = 1;
+}
diff --git a/test/CodeGenOpenCL/local.cl b/test/CodeGenOpenCL/local.cl
index 895c8fa2717d..f1031cdfd84e 100644
--- a/test/CodeGenOpenCL/local.cl
+++ b/test/CodeGenOpenCL/local.cl
@@ -1,9 +1,11 @@
// RUN: %clang_cc1 %s -ffake-address-space-map -faddress-space-map-mangling=no -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
+void func(local int*);
+
__kernel void foo(void) {
- // CHECK: @foo.i = internal unnamed_addr addrspace(2)
+ // CHECK: @foo.i = internal addrspace(2) global i32 undef
__local int i;
- ++i;
+ func(&i);
}
// CHECK-LABEL: define void @_Z3barPU7CLlocali
diff --git a/test/CodeGenOpenCL/opencl_types.cl b/test/CodeGenOpenCL/opencl_types.cl
index 7e99fc548ec5..71d1189e5f08 100644
--- a/test/CodeGenOpenCL/opencl_types.cl
+++ b/test/CodeGenOpenCL/opencl_types.cl
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -O0 | FileCheck %s
constant sampler_t glb_smp = 7;
-// CHECK: global i32 7
+// CHECK: constant i32 7
void fnc1(image1d_t img) {}
// CHECK: @fnc1(%opencl.image1d_t*
@@ -35,3 +35,6 @@ kernel void foo(image1d_t img) {
fnc4smp(glb_smp);
// CHECK: call void @fnc4smp(i32
}
+
+void __attribute__((overloadable)) bad1(image1d_t *b, image2d_t *c, image2d_t *d) {}
+// CHECK-LABEL: @{{_Z4bad1P11ocl_image1dP11ocl_image2dS2_|"\\01\?bad1@@YAXPE?APAUocl_image1d@@PE?APAUocl_image2d@@1@Z"}}
diff --git a/test/CodeGenOpenCL/ptx-calls.cl b/test/CodeGenOpenCL/ptx-calls.cl
index 00f2a0e4c042..bde00bc3d73a 100644
--- a/test/CodeGenOpenCL/ptx-calls.cl
+++ b/test/CodeGenOpenCL/ptx-calls.cl
@@ -9,5 +9,5 @@ __kernel void kernel_function() {
}
// CHECK-LABEL: define void @kernel_function()
// CHECK: call void @device_function()
-// CHECK: !{{[0-9]+}} = metadata !{void ()* @kernel_function, metadata !"kernel", i32 1}
+// CHECK: !{{[0-9]+}} = !{void ()* @kernel_function, !"kernel", i32 1}
diff --git a/test/CodeGenOpenCL/ptx-kernels.cl b/test/CodeGenOpenCL/ptx-kernels.cl
index 49d207f023c8..fc6de4f3d517 100644
--- a/test/CodeGenOpenCL/ptx-kernels.cl
+++ b/test/CodeGenOpenCL/ptx-kernels.cl
@@ -8,4 +8,4 @@ __kernel void kernel_function() {
}
// CHECK-LABEL: define void @kernel_function()
-// CHECK: !{{[0-9]+}} = metadata !{void ()* @kernel_function, metadata !"kernel", i32 1}
+// CHECK: !{{[0-9]+}} = !{void ()* @kernel_function, !"kernel", i32 1}
diff --git a/test/CodeGenOpenCL/relaxed-fpmath.cl b/test/CodeGenOpenCL/relaxed-fpmath.cl
new file mode 100644
index 000000000000..4222ea9c74b5
--- /dev/null
+++ b/test/CodeGenOpenCL/relaxed-fpmath.cl
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s -check-prefix=NORMAL
+// RUN: %clang_cc1 %s -emit-llvm -cl-fast-relaxed-math -o - | FileCheck %s -check-prefix=FAST
+// RUN: %clang_cc1 %s -emit-llvm -cl-finite-math-only -o - | FileCheck %s -check-prefix=FINITE
+// RUN: %clang_cc1 %s -emit-llvm -cl-unsafe-math-optimizations -o - | FileCheck %s -check-prefix=UNSAFE
+// RUN: %clang_cc1 %s -emit-llvm -cl-no-signed-zeros -o - | FileCheck %s -check-prefix=NOSZ
+
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+
+float spscalardiv(float a, float b) {
+ // CHECK: @spscalardiv(
+
+ // NORMAL: fdiv float
+ // FAST: fdiv fast float
+ // FINITE: fdiv nnan ninf float
+ // UNSAFE: fdiv nnan float
+ // NOSZ: fdiv nsz float
+ return a / b;
+}
+// CHECK: attributes
+
+// NORMAL: "no-infs-fp-math"="false"
+// NORMAL: "no-nans-fp-math"="false"
+// NORMAL: "unsafe-fp-math"="false"
+
+// FAST: "no-infs-fp-math"="true"
+// FAST: "no-nans-fp-math"="true"
+// FAST: "unsafe-fp-math"="true"
+
+// FINITE: "no-infs-fp-math"="true"
+// FINITE: "no-nans-fp-math"="true"
+// FINITE: "unsafe-fp-math"="false"
+
+// UNSAFE: "no-infs-fp-math"="false"
+// UNSAFE: "no-nans-fp-math"="true"
+// UNSAFE: "unsafe-fp-math"="true"
+
diff --git a/test/CodeGenOpenCL/str_literals.cl b/test/CodeGenOpenCL/str_literals.cl
index 43c90f83f6e7..092b6372a414 100644
--- a/test/CodeGenOpenCL/str_literals.cl
+++ b/test/CodeGenOpenCL/str_literals.cl
@@ -5,5 +5,5 @@ __constant char * __constant y = "hello world";
// CHECK: unnamed_addr addrspace(3) constant
// CHECK-NOT: addrspace(3) unnamed_addr constant
-// CHECK: @x = addrspace(3) global i8 addrspace(3)*
-// CHECK: @y = addrspace(3) global i8 addrspace(3)*
+// CHECK: @x = addrspace(3) constant i8 addrspace(3)*
+// CHECK: @y = addrspace(3) constant i8 addrspace(3)*
diff --git a/test/Coverage/html-diagnostics.c b/test/Coverage/html-diagnostics.c
index c7489f82dd7c..045943ae8b11 100644
--- a/test/Coverage/html-diagnostics.c
+++ b/test/Coverage/html-diagnostics.c
@@ -1,12 +1,9 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t %s
-// RUN: cat %t/*.html | FileCheck %s
+// RUN: find %t -name "*.html" -exec cat "{}" ";" | FileCheck %s
// REQUIRES: staticanalyzer
-// Because of the glob (*.html)
-// REQUIRES: shell
-
// CHECK: <h3>Annotated Source Code</h3>
// Without tweaking expr, the expr would hit to the line below
diff --git a/test/CoverageMapping/Inputs/code.h b/test/CoverageMapping/Inputs/code.h
new file mode 100644
index 000000000000..cd3cfb5d3fed
--- /dev/null
+++ b/test/CoverageMapping/Inputs/code.h
@@ -0,0 +1,11 @@
+x = x;
+if (x == 0) {
+ x = 1;
+} else {
+ x = 2;
+}
+if (true) {
+ x = x;
+} else {
+ x = x;
+}
diff --git a/test/CoverageMapping/Inputs/header1.h b/test/CoverageMapping/Inputs/header1.h
new file mode 100644
index 000000000000..d01e813b40b3
--- /dev/null
+++ b/test/CoverageMapping/Inputs/header1.h
@@ -0,0 +1,31 @@
+#ifndef HEADER1_H
+#define HEADER1_H
+
+inline void func(int i) {
+ int x = 0;
+ if (i == 0) {
+ x = 1;
+ } else {
+ x = 2;
+ }
+}
+static void static_func(int j) {
+ int x = 0;
+ if (j == x) {
+ x = !j;
+ } else {
+ x = 42;
+ }
+ j = x * j;
+}
+static void static_func2(int j) {
+ int x = 0;
+ if (j == x) {
+ x = !j;
+ } else {
+ x = 42;
+ }
+ j = x * j;
+}
+
+#endif // HEADER1_H
diff --git a/test/CoverageMapping/break.c b/test/CoverageMapping/break.c
new file mode 100644
index 000000000000..f5a0af5097bb
--- /dev/null
+++ b/test/CoverageMapping/break.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name break.c %s | FileCheck %s
+
+int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+28]]:2 = #0 (HasCodeBefore = 0)
+ int cnt = 0; // CHECK-NEXT: File 0, [[@LINE+1]]:9 -> [[@LINE+1]]:18 = #0 (HasCodeBefore = 0)
+ while(cnt < 100) { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+3]]:4 = #1 (HasCodeBefore = 0)
+ break;
+ ++cnt; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:10 = 0 (HasCodeBefore = 0)
+ } // CHECK-NEXT: File 0, [[@LINE+1]]:9 -> [[@LINE+1]]:18 = #0 (HasCodeBefore = 0)
+ while(cnt < 100) { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+6]]:4 = #2 (HasCodeBefore = 0)
+ {
+ break;
+ ++cnt; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE+2]]:10 = 0 (HasCodeBefore = 0)
+ }
+ ++cnt;
+ } // CHECK-NEXT: File 0, [[@LINE+1]]:9 -> [[@LINE+1]]:18 = ((#0 + #3) - #4) (HasCodeBefore = 0)
+ while(cnt < 100) { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+6]]:4 = #3 (HasCodeBefore = 0)
+ if(cnt == 0) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+3]]:6 = #4 (HasCodeBefore = 0)
+ break;
+ ++cnt; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:12 = 0 (HasCodeBefore = 0)
+ }
+ ++cnt; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:10 = (#3 - #4) (HasCodeBefore = 0)
+ } // CHECK-NEXT: File 0, [[@LINE+1]]:9 -> [[@LINE+1]]:18 = (#0 + #6) (HasCodeBefore = 0)
+ while(cnt < 100) { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+7]]:4 = #5 (HasCodeBefore = 0)
+ if(cnt == 0) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+5]]:10 = #6 (HasCodeBefore = 0)
+ ++cnt;
+ } else { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+2]]:6 = (#5 - #6) (HasCodeBefore = 0)
+ break;
+ }
+ ++cnt;
+ }
+}
diff --git a/test/CoverageMapping/builtinmacro.c b/test/CoverageMapping/builtinmacro.c
new file mode 100644
index 000000000000..a023abc62a40
--- /dev/null
+++ b/test/CoverageMapping/builtinmacro.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name builtinmacro.c %s | FileCheck %s
+
+// Test the coverage mapping generation for built-in macroes.
+
+// CHECK: filename
+const char *filename (const char *name) { // CHECK-NEXT: File 0, [[@LINE]]:41 -> [[@LINE+3]]:2 = #0 (HasCodeBefore = 0)
+ static const char this_file[] = __FILE__;
+ return this_file;
+}
+
+int main() { // CHECK-NEXT: main
+ filename(__FILE__ "test.c");
+ return 0;
+}
diff --git a/test/CoverageMapping/casts.c b/test/CoverageMapping/casts.c
new file mode 100644
index 000000000000..94c13dc13cb8
--- /dev/null
+++ b/test/CoverageMapping/casts.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name casts.c %s | FileCheck %s
+
+int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+4]]:2 = #0 (HasCodeBefore = 0)
+ // CHECK-NEXT: File 0, [[@LINE+1]]:41 -> [[@LINE+1]]:54 = #1 (HasCodeBefore = 0)
+ int window_size = (sizeof(int) <= 2 ? (unsigned)512 : 1024); // CHECK-NEXT: File 0, [[@LINE]]:57 -> [[@LINE]]:61 = (#0 - #1) (HasCodeBefore = 0)
+ return 0;
+}
+
+
+
+
diff --git a/test/CoverageMapping/classtemplate.cpp b/test/CoverageMapping/classtemplate.cpp
new file mode 100644
index 000000000000..6062266fd47d
--- /dev/null
+++ b/test/CoverageMapping/classtemplate.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name classtemplate.cpp %s > %tmapping
+// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-CONSTRUCTOR
+// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-GETTER
+// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-SETTER
+
+template<class TT>
+class Test {
+public:
+ enum BaseType {
+ A, C, G, T, Invalid
+ };
+ const static int BaseCount = 4;
+ double bases[BaseCount];
+
+ // CHECK-CONSTRUCTOR: _ZN4TestIjEC
+ Test() { } // CHECK-CONSTRUCTOR: File 0, [[@LINE]]:10 -> [[@LINE]]:13 = #0 (HasCodeBefore = 0)
+
+ // FIXME: It would be nice to emit no-coverage for get, but trying to do this
+ // runs afoul of cases like Test3::unmangleable below.
+ // FIXME-GETTER: _ZNK4TestIjE3get
+ double get(TT position) const { // FIXME-GETTER: File 0, [[@LINE]]:33 -> [[@LINE+2]]:4 = 0 (HasCodeBefore = 0)
+ return bases[position];
+ }
+ // CHECK-SETTER: _ZN4TestIjE3set
+ void set(TT position, double value) { // CHECK-SETTER: File 0, [[@LINE]]:39 -> [[@LINE+2]]:4 = #0 (HasCodeBefore = 0)
+ bases[position] = value;
+ }
+};
+
+class Test2 {
+ // CHECK-CONSTRUCTOR: _ZN5Test2C
+ Test2() { } // CHECK-CONSTRUCTOR: File 0, [[@LINE]]:11 -> [[@LINE]]:14 = 0 (HasCodeBefore = 0)
+ // CHECK-GETTER: _ZNK5Test23get
+ double get(unsigned position) const { // CHECK-GETTER: File 0, [[@LINE]]:39 -> [[@LINE+2]]:4 = 0 (HasCodeBefore = 0)
+ return 0.0;
+ }
+};
+
+// Test3::unmangleable can't be mangled, since there isn't a complete type for
+// the __is_final type trait expression. This would cause errors if we try to
+// emit a no-coverage mapping for the method.
+template <class T, bool = __is_final(T)> class UninstantiatedClassWithTraits {};
+template <class T> class Test3 {
+ void unmangleable(UninstantiatedClassWithTraits<T> x) {}
+};
+
+int main() {
+ Test<unsigned> t;
+ t.set(Test<unsigned>::A, 5.5);
+ t.set(Test<unsigned>::T, 5.6);
+ t.set(Test<unsigned>::G, 5.7);
+ t.set(Test<unsigned>::C, 5.8);
+ return 0;
+}
diff --git a/test/CoverageMapping/continue.c b/test/CoverageMapping/continue.c
new file mode 100644
index 000000000000..b56b164d4a3f
--- /dev/null
+++ b/test/CoverageMapping/continue.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name continue.c %s | FileCheck %s
+
+int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+21]]:2 = #0 (HasCodeBefore = 0)
+ int j = 0; // CHECK-NEXT: File 0, [[@LINE+2]]:18 -> [[@LINE+2]]:24 = (#0 + #1) (HasCodeBefore = 0)
+ // CHECK-NEXT: File 0, [[@LINE+1]]:26 -> [[@LINE+1]]:29 = #1 (HasCodeBefore = 0)
+ for(int i = 0; i < 20; ++i) { // CHECK-NEXT: File 0, [[@LINE]]:31 -> [[@LINE+17]]:4 = #1 (HasCodeBefore = 0)
+ if(i < 10) { // CHECK-NEXT: File 0, [[@LINE]]:16 -> [[@LINE+13]]:6 = #2 (HasCodeBefore = 0)
+ if(i < 5) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+3]]:8 = #3 (HasCodeBefore = 0)
+ continue;
+ j = 1; // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:14 = 0 (HasCodeBefore = 0)
+ } else { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+7]]:13 = (#2 - #3) (HasCodeBefore = 0)
+ j = 2;
+ }
+ j = 3;
+ if(i < 7) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+3]]:8 = #4 (HasCodeBefore = 0)
+ continue;
+ j = 4; // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:14 = 0 (HasCodeBefore = 0)
+ } else j = 5; // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+1]]:12 = ((#2 - #3) - #4) (HasCodeBefore = 0)
+ j = 6;
+ } else // CHECK-NEXT: File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:12 = (#1 - #2) (HasCodeBefore = 0)
+ j = 7;
+ j = 8; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:10 = ((#1 - #3) - #4) (HasCodeBefore = 0)
+ }
+}
diff --git a/test/CoverageMapping/header.cpp b/test/CoverageMapping/header.cpp
new file mode 100644
index 000000000000..c268191d2237
--- /dev/null
+++ b/test/CoverageMapping/header.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name tu1.cpp %s > %tmapping
+// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-FUNC
+// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-STATIC-FUNC
+// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-STATIC-FUNC2
+
+#include "Inputs/header1.h"
+
+int main() {
+ func(1);
+ static_func(2);
+}
+
+// CHECK-FUNC: func
+// CHECK-FUNC: File 0, 4:25 -> 11:2 = #0 (HasCodeBefore = 0)
+// CHECK-FUNC: File 0, 6:15 -> 8:4 = #1 (HasCodeBefore = 0)
+// CHECK-FUNC: File 0, 8:10 -> 10:4 = (#0 - #1) (HasCodeBefore = 0)
+// CHECK-FUNC: Expansion,File 1, 6:10 -> 6:28 = #0 (HasCodeBefore = 0, Expanded file = 0)
+
+// CHECK-STATIC-FUNC: static_func
+// CHECK-STATIC-FUNC: File 0, 12:32 -> 20:2 = #0 (HasCodeBefore = 0)
+// CHECK-STATIC-FUNC: File 0, 14:15 -> 16:4 = #1 (HasCodeBefore = 0)
+// CHECK-STATIC-FUNC: File 0, 16:10 -> 18:4 = (#0 - #1) (HasCodeBefore = 0)
+// CHECK-STATIC-FUNC: Expansion,File 1, 6:10 -> 6:28 = #0 (HasCodeBefore = 0, Expanded file = 0)
+
+// CHECK-STATIC-FUNC2: static_func2
+// CHECK-STATIC-FUNC2: File 0, 21:33 -> 29:2 = 0 (HasCodeBefore = 0)
+// CHECK-STATIC-FUNC2: Expansion,File 1, 6:10 -> 6:28 = 0 (HasCodeBefore = 0, Expanded file = 0)
diff --git a/test/CoverageMapping/if.c b/test/CoverageMapping/if.c
new file mode 100644
index 000000000000..4767b4039b3e
--- /dev/null
+++ b/test/CoverageMapping/if.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name if.c %s | FileCheck %s
+
+int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+21]]:2 = #0 (HasCodeBefore = 0)
+ int i = 0;
+ if(i == 0) i = 1; // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE]]:19 = #1 (HasCodeBefore = 0)
+ if(i == 1)
+ i = 2; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:10 = #2 (HasCodeBefore = 0)
+ if(i == 0) { i = 1; // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+2]]:4 = #3 (HasCodeBefore = 0)
+ i = 2;
+ }
+ if(i != 0) { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+2]]:4 = #4 (HasCodeBefore = 0)
+ i = 1;
+ } else { // CHECK-NEXT: File 0, [[@LINE]]:10 -> [[@LINE+2]]:4 = (#0 - #4) (HasCodeBefore = 0)
+ i = 3;
+ }
+
+ i = i == 0?
+ i + 1 : // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:14 = #5 (HasCodeBefore = 0)
+ i + 2; // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:14 = (#0 - #5) (HasCodeBefore = 0)
+ // CHECK-NEXT: File 0, [[@LINE+1]]:14 -> [[@LINE+1]]:20 = #6 (HasCodeBefore = 0)
+ i = i == 0?i + 12:i + 10; // CHECK-NEXT: File 0, [[@LINE]]:21 -> [[@LINE]]:27 = (#0 - #6) (HasCodeBefore = 0)
+
+ return 0;
+}
diff --git a/test/CoverageMapping/includehell.cpp b/test/CoverageMapping/includehell.cpp
new file mode 100644
index 000000000000..653f41464db0
--- /dev/null
+++ b/test/CoverageMapping/includehell.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name includehell.cpp %s | FileCheck %s
+
+int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+4]]:2 = #0 (HasCodeBefore = 0)
+ int x = 0;
+ #include "Inputs/code.h" // CHECK-NEXT: Expansion,File 0, [[@LINE]]:12 -> [[@LINE]]:27 = #0 (HasCodeBefore = 0, Expanded file = 1)
+ return 0;
+}
+// CHECK-NEXT: File 1, 1:1 -> 9:7 = #0 (HasCodeBefore = 0)
+// CHECK-NEXT: File 1, 2:13 -> 4:2 = #1 (HasCodeBefore = 0)
+// CHECK-NEXT: File 1, 4:8 -> 6:2 = (#0 - #1) (HasCodeBefore = 0)
+// CHECK-NEXT: File 1, 7:11 -> 9:2 = #2 (HasCodeBefore = 0)
+// CHECK-NEXT: File 1, 9:8 -> 11:2 = (#0 - #2) (HasCodeBefore = 0)
diff --git a/test/CoverageMapping/ir.c b/test/CoverageMapping/ir.c
new file mode 100644
index 000000000000..a1cb57020f9a
--- /dev/null
+++ b/test/CoverageMapping/ir.c
@@ -0,0 +1,12 @@
+// Check the data structures emitted by coverage mapping
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name ir.c %s -o - -emit-llvm -fprofile-instr-generate -fcoverage-mapping | FileCheck %s
+
+
+void foo(void) { }
+
+int main(void) {
+ foo();
+ return 0;
+}
+
+// CHECK: @__llvm_coverage_mapping = internal constant { i32, i32, i32, i32, [2 x { i8*, i32, i32, i64 }], [{{[0-9]+}} x i8] } { i32 2, i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 0, [2 x { i8*, i32, i32, i64 }] [{ i8*, i32, i32, i64 } { i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i32 3, i32 9, i64 {{[0-9]+}} }, { i8*, i32, i32, i64 } { i8* getelementptr inbounds ([4 x i8]* @__llvm_profile_name_main, i32 0, i32 0), i32 4, i32 9, i64 {{[0-9]+}} }]
diff --git a/test/CoverageMapping/label.cpp b/test/CoverageMapping/label.cpp
new file mode 100644
index 000000000000..d93626041bce
--- /dev/null
+++ b/test/CoverageMapping/label.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name label.cpp %s | FileCheck %s
+
+ // CHECK: func
+void func() { // CHECK-NEXT: File 0, [[@LINE]]:13 -> [[@LINE+18]]:2 = #0 (HasCodeBefore = 0)
+ int i = 0; // CHECK-NEXT: File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:20 = (#0 + #3) (HasCodeBefore = 0)
+ // CHECK-NEXT: File 0, [[@LINE+1]]:22 -> [[@LINE+1]]:25 = #3 (HasCodeBefore = 0)
+ for(i = 0; i < 10; ++i) { // CHECK-NEXT: File 0, [[@LINE]]:27 -> [[@LINE+10]]:4 = #1 (HasCodeBefore = 0)
+ if(i < 5) { // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+6]]:6 = #2 (HasCodeBefore = 0)
+ {
+ x: // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE+6]]:14 = #3 (HasCodeBefore = 0)
+ int j = 1;
+ }
+ int m = 2;
+ } else
+ goto x; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = (#1 - #2) (HasCodeBefore = 0)
+ int k = 3;
+ }
+ static int j = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:12 = ((#0 + #3) - #1) (HasCodeBefore = 0)
+ ++j;
+ if(j == 1)
+ goto x; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = #4 (HasCodeBefore = 0)
+}
+
+ // CHECK-NEXT: test1
+void test1(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> [[@LINE+7]]:2 = #0 (HasCodeBefore = 0)
+ if(x == 0)
+ goto a; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = #1 (HasCodeBefore = 0)
+ goto b; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:9 = (#0 - #1) (HasCodeBefore = 0)
+a: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE]]:2 = #2 (HasCodeBefore = 0)
+b: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+1]]:12 = #3 (HasCodeBefore = 0)
+ x = x + 1;
+}
+
+ // CHECK-NEXT: test2
+void test2(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> [[@LINE+8]]:2 = #0 (HasCodeBefore = 0)
+ if(x == 0)
+ goto a; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = #1 (HasCodeBefore = 0)
+ // CHECK-NEXT: File 0, [[@LINE+1]]:8 -> [[@LINE+1]]:17 = (#0 - #1) (HasCodeBefore = 0)
+ else if(x == 1) goto b; // CHECK-NEXT: File 0, [[@LINE]]:19 -> [[@LINE]]:25 = #2 (HasCodeBefore = 0)
+a: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE]]:2 = #3 (HasCodeBefore = 0)
+b: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+1]]:12 = #4 (HasCodeBefore = 0)
+ x = x + 1;
+}
+
+ // CHECK-NEXT: main
+int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+17]]:2 = #0 (HasCodeBefore = 0)
+ int j = 0;
+ for(int i = 0; i < 10; ++i) { // CHECK: File 0, [[@LINE]]:31 -> [[@LINE+11]]:4 = #1 (HasCodeBefore = 0)
+ a: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13 = #2 (HasCodeBefore = 0)
+ if(i < 3)
+ goto e; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #3 (HasCodeBefore = 0)
+ goto c; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = (#2 - #3) (HasCodeBefore = 0)
+ b: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #4 (HasCodeBefore = 0)
+ j = 2;
+ c: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #5 (HasCodeBefore = 0)
+ j = 1;
+ // CHECK-NEXT: File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:4 = #6 (HasCodeBefore = 0)
+ e: f: ; // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE]]:10 = #7 (HasCodeBefore = 0)
+ }
+ func(); // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:11 = ((#0 + #7) - #1) (HasCodeBefore = 0)
+ test1(0);
+ test2(2);
+}
diff --git a/test/CoverageMapping/logical.cpp b/test/CoverageMapping/logical.cpp
new file mode 100644
index 000000000000..0971c756b044
--- /dev/null
+++ b/test/CoverageMapping/logical.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name logical.cpp %s | FileCheck %s
+
+int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+10]]:2 = #0 (HasCodeBefore = 0)
+ bool bt = true;
+ bool bf = false;
+ bool a = bt && bf; // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE]]:20 = #1 (HasCodeBefore = 0)
+ a = bt &&
+ bf; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #2 (HasCodeBefore = 0)
+ a = bf || bt; // CHECK-NEXT: File 0, [[@LINE]]:13 -> [[@LINE]]:15 = #3 (HasCodeBefore = 0)
+ a = bf ||
+ bt; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #4 (HasCodeBefore = 0)
+ return 0;
+}
diff --git a/test/CoverageMapping/loopmacro.c b/test/CoverageMapping/loopmacro.c
new file mode 100644
index 000000000000..8480dbdc37e9
--- /dev/null
+++ b/test/CoverageMapping/loopmacro.c
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name loopmacro.c %s | FileCheck %s
+
+# define HASH_BITS 15
+#define MIN_MATCH 3
+#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
+#define WMASK 0xFFFF
+#define HASH_MASK 0xFFFF
+#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+#define INSERT_STRING(s, match_head) \
+ (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
+ prev[(s) & WMASK] = match_head = head[ins_h], \
+ head[ins_h] = (s))
+
+int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+12]]:2 = #0 (HasCodeBefore = 0)
+ int strstart = 0;
+ int hash_head = 2;
+ int prev_length = 5;
+ int ins_h = 1;
+ int prev[32] = { 0 };
+ int head[32] = { 0 };
+ int window[1024] = { 0 };
+ do { // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE+3]]:30 = (#0 + #1) (HasCodeBefore = 0)
+ strstart++;
+ INSERT_STRING(strstart, hash_head); // CHECK-NEXT: Expansion,File 0, [[@LINE]]:7 -> [[@LINE]]:20 = (#0 + #1) (HasCodeBefore = 0, Expanded file = 1)
+ } while (--prev_length != 0);
+}
+// CHECK-NEXT: File 0, 24:21 -> 24:29 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: File 0, 24:21 -> 24:29 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: File 0, 24:21 -> 24:29 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: File 0, 24:31 -> 24:40 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: File 1, 10:4 -> 12:23 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: Expansion,File 1, 10:5 -> 10:16 = (#0 + #1) (HasCodeBefore = 0, Expanded file = 2)
+// CHECK-NEXT: File 1, 10:17 -> 10:22 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: File 1, 10:17 -> 10:22 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: File 1, 10:24 -> 10:32 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: File 1, 10:33 -> 10:36 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: File 1, 10:46 -> 10:49 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: File 2, 8:26 -> 8:66 = (#0 + #1) (HasCodeBefore = 0)
+// CHECK-NEXT: Expansion,File 2, 8:38 -> 8:45 = (#0 + #1) (HasCodeBefore = 0, Expanded file = 3)
+// CHECK-NEXT: File 3, 5:18 -> 5:53 = (#0 + #1) (HasCodeBefore = 0)
diff --git a/test/CoverageMapping/loops.cpp b/test/CoverageMapping/loops.cpp
new file mode 100644
index 000000000000..81fad910d9e4
--- /dev/null
+++ b/test/CoverageMapping/loops.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -std=c++11 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name loops.cpp %s | FileCheck %s
+
+ // CHECK: rangedFor
+void rangedFor() { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+6]]:2 = #0 (HasCodeBefore = 0)
+ int arr[] = { 1, 2, 3, 4, 5 };
+ int sum = 0;
+ for(auto i : arr) { // CHECK-NEXT: File 0, [[@LINE]]:21 -> [[@LINE+2]]:4 = #1 (HasCodeBefore = 0)
+ sum += i;
+ }
+}
+
+ // CHECK-NEXT: main
+int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+24]]:2 = #0 (HasCodeBefore = 0)
+ // CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+1]]:24 = (#0 + #1) (HasCodeBefore = 0)
+ for(int i = 0; i < 10; ++i) // CHECK-NEXT: File 0, [[@LINE]]:26 -> [[@LINE]]:29 = #1 (HasCodeBefore = 0)
+ ; // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE]]:7 = #1 (HasCodeBefore = 0)
+ for(int i = 0;
+ i < 10; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = (#0 + #2) (HasCodeBefore = 0)
+ ++i) // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:10 = #2 (HasCodeBefore = 0)
+ { // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:4 = #2 (HasCodeBefore = 0)
+ int x = 0;
+ }
+ int j = 0; // CHECK-NEXT: File 0, [[@LINE+1]]:9 -> [[@LINE+1]]:14 = (#0 + #3) (HasCodeBefore = 0)
+ while(j < 5) ++j; // CHECK-NEXT: File 0, [[@LINE]]:16 -> [[@LINE]]:19 = #3 (HasCodeBefore = 0)
+ do { // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE+2]]:17 = (#0 + #4) (HasCodeBefore = 0)
+ ++j;
+ } while(j < 10);
+ j = 0;
+ while
+ (j < 5) // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:10 = (#0 + #5) (HasCodeBefore = 0)
+ ++j; // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE]]:9 = #5 (HasCodeBefore = 0)
+ do
+ ++j; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+1]]:15 = (#0 + #6) (HasCodeBefore = 0)
+ while(j < 10);
+ rangedFor();
+ return 0;
+}
diff --git a/test/CoverageMapping/macroception.c b/test/CoverageMapping/macroception.c
new file mode 100644
index 000000000000..edbd84a017d4
--- /dev/null
+++ b/test/CoverageMapping/macroception.c
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name macroception.c %s | FileCheck %s
+
+#define M2 {
+#define M1 M2
+#define M22 }
+#define M11 M22
+
+// CHECK-LABEL: main:
+int main() M1 // CHECK-NEXT: Expansion,File 0, [[@LINE]]:12 -> [[@LINE]]:14 = #0 (HasCodeBefore = 0, Expanded file = 2)
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = #0 (HasCodeBefore = 0)
+}
+// CHECK-NEXT: File 1, 3:12 -> 3:13 = #0 (HasCodeBefore = 0)
+// CHECK-NEXT: Expansion,File 2, 4:12 -> 4:14 = #0 (HasCodeBefore = 0, Expanded file = 1)
+
+
+// CHECK-LABEL: func2:
+void func2() { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+1]]:12 = #0 (HasCodeBefore = 0)
+ int x = 0;
+M11 // CHECK-NEXT: Expansion,File 0, [[@LINE]]:1 -> [[@LINE]]:4 = #0 (HasCodeBefore = 0, Expanded file = 2)
+// CHECK-NEXT: File 1, 5:13 -> 5:14 = #0 (HasCodeBefore = 0)
+// CHECK-NEXT: Expansion,File 2, 6:13 -> 6:16 = #0 (HasCodeBefore = 0, Expanded file = 1)
+
+// CHECK-LABEL: func3:
+void func3() M1 // CHECK-NEXT: Expansion,File 0, [[@LINE]]:14 -> [[@LINE]]:16 = #0 (HasCodeBefore = 0, Expanded file = 2)
+ int x = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:12 = #0 (HasCodeBefore = 0)
+M11 // CHECK-NEXT: Expansion,File 0, [[@LINE]]:1 -> [[@LINE]]:4 = #0 (HasCodeBefore = 0, Expanded file = 4)
+
+// CHECK-NEXT: File 1, 3:12 -> 3:13 = #0 (HasCodeBefore = 0)
+// CHECK-NEXT: Expansion,File 2, 4:12 -> 4:14 = #0 (HasCodeBefore = 0, Expanded file = 1)
+// CHECK-NEXT: File 3, 5:13 -> 5:14 = #0 (HasCodeBefore = 0)
+// CHECK-NEXT: Expansion,File 4, 6:13 -> 6:16 = #0 (HasCodeBefore = 0, Expanded file = 3)
+
+// CHECK-LABEL: func4:
+// CHECK-NEXT: File 0, 3:12 -> 3:13 = #0 (HasCodeBefore = 0)
+// CHECK-NEXT: Expansion,File 1, 4:12 -> 4:14 = #0 (HasCodeBefore = 0, Expanded file = 0)
+void func4() M1 M11
+// CHECK-NEXT: Expansion,File 2, [[@LINE-1]]:14 -> [[@LINE-1]]:16 = #0 (HasCodeBefore = 0, Expanded file = 1)
+// CHECK-NEXT: Expansion,File 2, [[@LINE-2]]:17 -> [[@LINE-2]]:20 = #0 (HasCodeBefore = 0, Expanded file = 4)
+// CHECK-NEXT: File 3, 5:13 -> 5:14 = #0 (HasCodeBefore = 0)
+// CHECK-NEXT: Expansion,File 4, 6:13 -> 6:16 = #0 (HasCodeBefore = 0, Expanded file = 3)
diff --git a/test/CoverageMapping/macroparams.c b/test/CoverageMapping/macroparams.c
new file mode 100644
index 000000000000..adf01ec09b8e
--- /dev/null
+++ b/test/CoverageMapping/macroparams.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name macroparams.c %s | FileCheck %s
+
+#define MACRO2(X2) (X2 + 2) // CHECK-DAG: File 2, [[@LINE]]:20 -> [[@LINE]]:28 = #0 (HasCodeBefore = 0)
+#define MACRO(X) MACRO2(x) // CHECK-DAG: File 1, [[@LINE]]:25 -> [[@LINE]]:26 = #0 (HasCodeBefore = 0)
+ // CHECK-DAG: Expansion,File 1, [[@LINE-1]]:18 -> [[@LINE-1]]:24 = #0 (HasCodeBefore = 0, Expanded file = 2)
+
+
+int main() { // CHECK-DAG: File 0, [[@LINE]]:12 -> [[@LINE+4]]:2 = #0 (HasCodeBefore = 0)
+ int x = 0;
+ MACRO(x); // CHECK-DAG: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:8 = #0 (HasCodeBefore = 0, Expanded file = 1)
+ return 0;
+}
diff --git a/test/CoverageMapping/macroparams2.c b/test/CoverageMapping/macroparams2.c
new file mode 100644
index 000000000000..0445370b0e13
--- /dev/null
+++ b/test/CoverageMapping/macroparams2.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name macroparams2.c %s | FileCheck %s
+
+// A test case for when the first macro parameter is used after the second
+// macro parameter.
+
+struct S {
+ int i, j;
+};
+
+#define MACRO(REFS, CALLS) (4 * (CALLS) < (REFS))
+
+int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+7]]:2 = #0 (HasCodeBefore = 0)
+ struct S arr[32] = { 0 }; // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:7 -> [[@LINE+2]]:12 = #0 (HasCodeBefore = 0, Expanded file = 1)
+ int n = 0; // CHECK-NEXT: File 0, [[@LINE+1]]:13 -> [[@LINE+1]]:21 = #0 (HasCodeBefore = 0)
+ if (MACRO(arr[n].j, arr[n].i)) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE]]:31 = #0 (HasCodeBefore = 0)
+ n = 1; // CHECK-NEXT: File 0, [[@LINE-1]]:34 -> [[@LINE+1]]:4 = #1 (HasCodeBefore = 0)
+ }
+ return n;
+} // CHECK-NEXT: File 1, [[@LINE-9]]:29 -> [[@LINE-9]]:51 = #0 (HasCodeBefore = 0
+
diff --git a/test/CoverageMapping/macros.c b/test/CoverageMapping/macros.c
new file mode 100644
index 000000000000..d3a0e6aab47b
--- /dev/null
+++ b/test/CoverageMapping/macros.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name macros.c %s | FileCheck %s
+
+void bar();
+#define MACRO return; bar()
+#define MACRO_2 bar()
+#define MACRO_1 return; MACRO_2
+
+ // CHECK: func
+void func() { // CHECK-NEXT: File 0, [[@LINE]]:13 -> [[@LINE+4]]:2 = #0 (HasCodeBefore = 0)
+ int i = 0;
+ MACRO; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:8 = #0 (HasCodeBefore = 0, Expanded file = 1)
+ i = 2; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:8 = 0 (HasCodeBefore = 0)
+}
+// CHECK-NEXT: File 1, 4:15 -> 4:21 = #0 (HasCodeBefore = 0)
+// CHECK-NEXT: File 1, 4:23 -> 4:28 = 0 (HasCodeBefore = 0)
+
+ // CHECK-NEXT: func2
+void func2() { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+4]]:2 = #0 (HasCodeBefore = 0)
+ int i = 0;
+ MACRO_1; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:10 = #0 (HasCodeBefore = 0, Expanded file = 1)
+ i = 2; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:8 = 0 (HasCodeBefore = 0)
+}
+// CHECK-NEXT: File 1, 6:17 -> 6:23 = #0 (HasCodeBefore = 0)
+// CHECK-NEXT: Expansion,File 1, 6:25 -> 6:32 = 0 (HasCodeBefore = 0, Expanded file = 2)
+// CHECK-NEXT: File 2, 5:17 -> 5:22 = 0 (HasCodeBefore = 0)
+
diff --git a/test/CoverageMapping/nestedclass.cpp b/test/CoverageMapping/nestedclass.cpp
new file mode 100644
index 000000000000..aca4abf1a7f0
--- /dev/null
+++ b/test/CoverageMapping/nestedclass.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name nestedclass.cpp %s > %tmapping
+// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-OUTER
+// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-INNER
+// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-INNERMOST
+
+struct Test { // CHECK-OUTER: emitTest
+ void emitTest() { // CHECK-OUTER: File 0, [[@LINE]]:19 -> [[@LINE+2]]:4 = #0 (HasCodeBefore = 0)
+ int i = 0;
+ }
+ struct Test2 { // CHECK-INNER: emitTest2
+ void emitTest2() { // CHECK-INNER: File 0, [[@LINE]]:22 -> [[@LINE+2]]:6 = #0 (HasCodeBefore = 0)
+ int i = 0;
+ }
+ struct Test3 { // CHECK-INNERMOST: emitTest3
+ static void emitTest3() { // CHECK-INNERMOST: File 0, [[@LINE]]:31 -> [[@LINE+2]]:8 = 0 (HasCodeBefore = 0)
+ int i = 0;
+ }
+ };
+ };
+};
+
+int main() {
+ Test t;
+ Test::Test2 t2;
+ t.emitTest();
+ t2.emitTest2();
+ return 0;
+}
diff --git a/test/CoverageMapping/objc.m b/test/CoverageMapping/objc.m
new file mode 100644
index 000000000000..b41ab94ccf26
--- /dev/null
+++ b/test/CoverageMapping/objc.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name objc.m -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck %s
+
+@interface A
+- (void)bork:(int)msg;
+@end
+
+ // CHECK: func
+void func(A *a) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+3]]:2 = #0 (HasCodeBefore = 0)
+ if (a)
+ [a bork: 20 ]; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:20 = #1 (HasCodeBefore = 0)
+}
+
+@interface NSArray
++ (NSArray*) arrayWithObjects: (id) first, ...;
+- (unsigned) count;
+@end
+
+ // CHECK: func2
+void func2(NSArray *array) { // CHECK-NEXT: File 0, [[@LINE]]:28 -> [[@LINE+10]]:2 = #0 (HasCodeBefore = 0)
+ int i = 0;
+ for (NSArray *x in array) { // CHECK-NEXT: File 0, [[@LINE]]:29 -> [[@LINE+6]]:4 = #1 (HasCodeBefore = 0)
+ if (x) { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+2]]:6 = #2 (HasCodeBefore = 0)
+ i = 1;
+ } else { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+2]]:6 = (#1 - #2) (HasCodeBefore = 0)
+ i = -1;
+ }
+ }
+ i = 0;
+}
diff --git a/test/CoverageMapping/preprocessor.c b/test/CoverageMapping/preprocessor.c
new file mode 100644
index 000000000000..a6edeb7c8241
--- /dev/null
+++ b/test/CoverageMapping/preprocessor.c
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name preprocessor.c %s | FileCheck %s
+
+ // CHECK: func
+void func() { // CHECK: File 0, [[@LINE]]:13 -> [[@LINE+5]]:2 = #0 (HasCodeBefore = 0)
+ int i = 0;
+#ifdef MACRO // CHECK-NEXT: Skipped,File 0, [[@LINE]]:2 -> [[@LINE+2]]:2 = 0 (HasCodeBefore = 0)
+ int x = i;
+#endif
+}
+
+#if 0
+ int g = 0;
+
+ void bar() { }
+#endif
+
+ // CHECK: main
+int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+19]]:2 = #0 (HasCodeBefore = 0)
+ int i = 0;
+#if 0 // CHECK-NEXT: Skipped,File 0, [[@LINE]]:2 -> [[@LINE+4]]:2 = 0 (HasCodeBefore = 0)
+ if(i == 0) {
+ i = 1;
+ }
+#endif
+
+#if 1
+ if(i == 0) { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+2]]:4 = #1 (HasCodeBefore = 0)
+ i = 1;
+ }
+#else // CHECK-NEXT: Skipped,File 0, [[@LINE]]:2 -> [[@LINE+5]]:2 = 0 (HasCodeBefore = 0)
+ if(i == 1) {
+ i = 0;
+ }
+}
+#endif
+ return 0;
+}
diff --git a/test/CoverageMapping/return.c b/test/CoverageMapping/return.c
new file mode 100644
index 000000000000..9c68759b2fc4
--- /dev/null
+++ b/test/CoverageMapping/return.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name return.c %s | FileCheck %s
+
+ // CHECK: func
+void func() { // CHECK: File 0, [[@LINE]]:13 -> [[@LINE+3]]:2 = #0 (HasCodeBefore = 0)
+ return;
+ int i = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:12 = 0 (HasCodeBefore = 0)
+}
+
+ // CHECK-NEXT: func2
+void func2() { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+13]]:2 = #0 (HasCodeBefore = 0)
+ // CHECK-NEXT: File 0, [[@LINE+2]]:18 -> [[@LINE+2]]:24 = ((#0 + #1) - #2) (HasCodeBefore = 0)
+ // CHECK-NEXT: File 0, [[@LINE+1]]:26 -> [[@LINE+1]]:29 = (#1 - #2) (HasCodeBefore = 0)
+ for(int i = 0; i < 10; ++i) { // CHECK-NEXT: File 0, [[@LINE]]:31 -> [[@LINE+9]]:4 = #1 (HasCodeBefore = 0)
+ if(i > 2) { // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+2]]:6 = #2 (HasCodeBefore = 0)
+ return;
+ } // CHECK-NEXT: File 0, [[@LINE+1]]:5 -> [[@LINE+3]]:11 = (#1 - #2) (HasCodeBefore = 0)
+ if(i == 3) { // CHECK-NEXT: File 0, [[@LINE]]:16 -> [[@LINE+2]]:6 = #3 (HasCodeBefore = 0)
+ int j = 1;
+ } else { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+2]]:6 = ((#1 - #2) - #3) (HasCodeBefore = 0)
+ int j = 2;
+ }
+ }
+}
+
+ // CHECK-NEXT: func3
+void func3(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> [[@LINE+9]]:2 = #0 (HasCodeBefore = 0)
+ if(x > 5) { // CHECK-NEXT: File 0, [[@LINE]]:13 -> [[@LINE+6]]:4 = #1 (HasCodeBefore = 0)
+ while(x >= 9) { // CHECK-NEXT: File 0, [[@LINE]]:11 -> [[@LINE]]:17 = #1 (HasCodeBefore = 0)
+ return; // CHECK-NEXT: File 0, [[@LINE-1]]:19 -> [[@LINE+2]]:6 = #2 (HasCodeBefore = 0)
+ --x; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:10 = 0 (HasCodeBefore = 0)
+ }
+ int i = 0; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:14 = (#1 - #2) (HasCodeBefore = 0)
+ }
+ int j = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:12 = (#0 - #2) (HasCodeBefore = 0)
+}
diff --git a/test/CoverageMapping/switch.c b/test/CoverageMapping/switch.c
new file mode 100644
index 000000000000..b6672258591a
--- /dev/null
+++ b/test/CoverageMapping/switch.c
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name switch.c %s | FileCheck %s
+ // CHECK: foo
+void foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+8]]:2 = #0 (HasCodeBefore = 0)
+ switch(i) {
+ case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:11 = #2 (HasCodeBefore = 0)
+ return;
+ case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #3 (HasCodeBefore = 0)
+ break;
+ } // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:12 = #1 (HasCodeBefore = 0)
+ int x = 0;
+}
+
+ // CHECK-NEXT: main
+int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+34]]:2 = #0 (HasCodeBefore = 0)
+ int i = 0;
+ switch(i) {
+ case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #2 (HasCodeBefore = 0)
+ i = 1;
+ break;
+ case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #3 (HasCodeBefore = 0)
+ i = 2;
+ break;
+ default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #4 (HasCodeBefore = 0)
+ break;
+ } // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:14 = #1 (HasCodeBefore = 0)
+ switch(i) {
+ case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #6 (HasCodeBefore = 0)
+ i = 1;
+ break;
+ case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #7 (HasCodeBefore = 0)
+ i = 2;
+ default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = (#7 + #8) (HasCodeBefore = 0)
+ break;
+ } // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:14 = #5 (HasCodeBefore = 0)
+
+
+ switch(i) {
+ case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:10 = #10 (HasCodeBefore = 0)
+ case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:11 = (#10 + #11) (HasCodeBefore = 0)
+ i = 11;
+ case 3: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:10 = ((#10 + #11) + #12) (HasCodeBefore = 0)
+ case 4: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:11 = (((#10 + #11) + #12) + #13) (HasCodeBefore = 0)
+ i = 99;
+ } // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:11 = #9 (HasCodeBefore = 0)
+
+ foo(1);
+ return 0;
+}
diff --git a/test/CoverageMapping/templates.cpp b/test/CoverageMapping/templates.cpp
new file mode 100644
index 000000000000..fcb92e1e9f57
--- /dev/null
+++ b/test/CoverageMapping/templates.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name templates.cpp %s | FileCheck %s
+
+template<typename T>
+void unused(T x) {
+ return;
+}
+
+template<typename T>
+int func(T x) { // CHECK: func
+ if(x) // CHECK: func
+ return 0;
+ else
+ return 1;
+ int j = 1;
+}
+
+int main() {
+ func<int>(0);
+ func<bool>(true);
+ return 0;
+}
diff --git a/test/CoverageMapping/test.c b/test/CoverageMapping/test.c
new file mode 100644
index 000000000000..594bcf68bc0f
--- /dev/null
+++ b/test/CoverageMapping/test.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name test.c %s | FileCheck %s
+
+void bar();
+static void static_func();
+
+ // CHECK: main
+int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+7]]:2 = #0 (HasCodeBefore = 0)
+ // CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+1]]:24 = (#0 + #1) (HasCodeBefore = 0)
+ for(int i = 0; i < 10; ++i) { // CHECK-NEXT: File 0, [[@LINE]]:26 -> [[@LINE]]:29 = #1 (HasCodeBefore = 0)
+ bar(); // CHECK-NEXT: File 0, [[@LINE-1]]:31 -> [[@LINE+1]]:4 = #1 (HasCodeBefore = 0)
+ }
+ static_func();
+ return 0;
+}
+
+ // CHECK-NEXT: foo
+void foo() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+4]]:2 = #0 (HasCodeBefore = 0)
+ if(1) { // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE+2]]:4 = #1 (HasCodeBefore = 0)
+ int i = 0;
+ }
+}
+
+ // CHECK-NEXT: bar
+void bar() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+1]]:2 = #0 (HasCodeBefore = 0)
+}
+
+ // CHECK-NEXT: static_func
+void static_func() { } // CHECK: File 0, [[@LINE]]:20 -> [[@LINE]]:23 = #0 (HasCodeBefore = 0)
+
+ // CHECK-NEXT: func
+static void func() { } // CHECK: File 0, [[@LINE]]:20 -> [[@LINE]]:23 = 0 (HasCodeBefore = 0)
diff --git a/test/CoverageMapping/trycatch.cpp b/test/CoverageMapping/trycatch.cpp
new file mode 100644
index 000000000000..a513845c28aa
--- /dev/null
+++ b/test/CoverageMapping/trycatch.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fexceptions -fcxx-exceptions -fprofile-instr-generate -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name trycatch.cpp %s | FileCheck %s
+
+class Error {
+};
+
+class ImportantError {
+};
+
+class Warning {
+};
+
+ // CHECK: func
+void func(int i) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+5]]:2 = #0 (HasCodeBefore = 0)
+ if(i % 2)
+ throw Error(); // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:16 = #1 (HasCodeBefore = 0)
+ else if(i == 8) // CHECK-NEXT: File 0, [[@LINE]]:8 -> [[@LINE]]:17 = (#0 - #1) (HasCodeBefore = 0)
+ throw ImportantError(); // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:25 = #2 (HasCodeBefore = 0)
+}
+
+ // CHECK-NEXT: main
+int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+13]]:2 = #0 (HasCodeBefore = 0)
+ int j = 0;
+ try {
+ func(j);
+ } catch(const Error &e) { // CHECK-NEXT: File 0, [[@LINE]]:27 -> [[@LINE+2]]:10 = #2 (HasCodeBefore = 0)
+ j = 1;
+ } catch(const ImportantError &e) { // CHECK-NEXT: File 0, [[@LINE]]:36 -> [[@LINE+3]]:8 = #3 (HasCodeBefore = 0)
+ j = 11;
+ }
+ catch(const Warning &w) { // CHECK-NEXT: File 0, [[@LINE]]:27 -> [[@LINE+2]]:4 = #4 (HasCodeBefore = 0)
+ j = 0;
+ }
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = #1 (HasCodeBefore = 0)
+}
diff --git a/test/Driver/B-opt.c b/test/Driver/B-opt.c
index 6759353174d0..318009413b1c 100644
--- a/test/Driver/B-opt.c
+++ b/test/Driver/B-opt.c
@@ -3,20 +3,20 @@
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
// RUN: -B %S/Inputs/B_opt_tree/dir1 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-TRIPLE %s
-// CHECK-B-OPT-TRIPLE: "{{.*}}/Inputs/B_opt_tree/dir1{{/|\\}}i386-unknown-linux-ld"
+// CHECK-B-OPT-TRIPLE: "{{.*}}/Inputs/B_opt_tree/dir1{{/|\\\\}}i386-unknown-linux-ld"
//
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
// RUN: -B %S/Inputs/B_opt_tree/dir2 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-DIR %s
-// CHECK-B-OPT-DIR: "{{.*}}/Inputs/B_opt_tree/dir2{{/|\\}}ld"
+// CHECK-B-OPT-DIR: "{{.*}}/Inputs/B_opt_tree/dir2{{/|\\\\}}ld"
//
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
// RUN: -B %S/Inputs/B_opt_tree/dir3/prefix- 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-PREFIX %s
-// CHECK-B-OPT-PREFIX: "{{.*}}/Inputs/B_opt_tree/dir3{{/|\\}}prefix-ld"
+// CHECK-B-OPT-PREFIX: "{{.*}}/Inputs/B_opt_tree/dir3{{/|\\\\}}prefix-ld"
//
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
// RUN: -B %S/Inputs/B_opt_tree/dir3/prefix- \
// RUN: -B %S/Inputs/B_opt_tree/dir2 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-MULT %s
-// CHECK-B-OPT-MULT: "{{.*}}/Inputs/B_opt_tree/dir3{{/|\\}}prefix-ld"
+// CHECK-B-OPT-MULT: "{{.*}}/Inputs/B_opt_tree/dir3{{/|\\\\}}prefix-ld"
diff --git a/test/Driver/Inputs/Windows/ARM/8.1/usr/bin/armv7-windows-itanium-ld b/test/Driver/Inputs/Windows/ARM/8.1/usr/bin/armv7-windows-itanium-ld
new file mode 100755
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/Windows/ARM/8.1/usr/bin/armv7-windows-itanium-ld
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/eabihf/crti.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/eabihf/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/eabihf/crti.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/powerpc/crti.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/powerpc/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/powerpc/crti.o
diff --git a/test/Driver/Inputs/cc1-response.txt b/test/Driver/Inputs/cc1-response.txt
new file mode 100644
index 000000000000..0236fdc6aa31
--- /dev/null
+++ b/test/Driver/Inputs/cc1-response.txt
@@ -0,0 +1,4 @@
+
+
+-cc1
+-triple i686-pc-windows-msvc
diff --git a/test/Driver/Inputs/gen-response.c b/test/Driver/Inputs/gen-response.c
new file mode 100644
index 000000000000..84ffb40dbece
--- /dev/null
+++ b/test/Driver/Inputs/gen-response.c
@@ -0,0 +1,8 @@
+#define M -DTEST
+#define M1 M M M M M M M M M M
+#define M2 M1 M1 M1 M1 M1 M1 M1 M1 M1 M1
+#define M3 M2 M2 M2 M2 M2 M2 M2 M2 M2 M2
+#define M4 M3 M3 M3 M3 M3 M3 M3 M3 M3 M3
+#define M5 M4 M4 M4 M4 M4 M4 M4 M4 M4 M4
+#define TEXT M5 M5 M5
+TEXT
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/el/.keep b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/el/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/el/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/nan2008/el/.keep b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/nan2008/el/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/nan2008/el/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/soft-float/el/.keep b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/soft-float/el/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/include-fixed/uclibc/soft-float/el/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/crtbegin.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/crtbegin.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/crtend.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/crtend.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/el/crtbegin.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/el/crtend.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/el/crtend.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/crtbegin.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/crtend.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/el/crtbegin.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/el/crtend.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/nan2008/el/crtend.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/crtbegin.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/crtbegin.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/crtend.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/crtend.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/el/crtbegin.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/el/crtend.o b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/lib/gcc/mips-linux-gnu/4.6.3/uclibc/soft-float/el/crtend.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/el/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/el/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/el/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/nan2008/el/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/nan2008/el/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/nan2008/el/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/soft-float/el/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/soft-float/el/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/lib/uclibc/soft-float/el/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/lib/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/lib/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/include/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/include/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/include/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crti.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/lib/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/lib/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/lib/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/lib/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/include/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/include/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/include/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crti.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/lib/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/lib/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/include/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/include/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/include/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/lib/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/lib/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/include/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/include/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/include/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crti.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/lib/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/lib/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/include/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/include/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/include/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crt1.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crti.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crtn.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/soft-float/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/include/.keep b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/include/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/include/.keep
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crt1.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crti.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crtn.o b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_cs_tree/mips-linux-gnu/libc/uclibc/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/el/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/nan2008/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/nan2008/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/nan2008/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/nan2008/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/nan2008/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/nan2008/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/sof/crtbegin.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/sof/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/sof/crtbegin.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/sof/crtend.o b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/sof/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/lib/gcc/mips-mti-linux-gnu/4.9.0/uclibc/sof/crtend.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/nan2008/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/nan2008/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/nan2008/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/sof/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/sof/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/sof/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/el/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/el/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/el/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/el/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/el/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/el/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/nan2008/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/nan2008/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/nan2008/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/sof/.keep b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/sof/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/mips-mti-linux-gnu/lib/uclibc/sof/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/include/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/include/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/include/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/include/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/include/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/include/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/include/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/include/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/include/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/el/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/include/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/include/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/include/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/nan2008/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/include/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/include/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/include/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/sof/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/include/bits/.keep b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/include/bits/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/include/bits/.keep
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crt1.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crti.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crti.o
diff --git a/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crtn.o b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/mips_fsf_tree/sysroot/uclibc/usr/lib/crtn.o
diff --git a/test/Driver/aarch64-cpus.c b/test/Driver/aarch64-cpus.c
index 68ad326d5edf..1627660d8130 100644
--- a/test/Driver/aarch64-cpus.c
+++ b/test/Driver/aarch64-cpus.c
@@ -7,7 +7,7 @@
// RUN: %clang -target arm64 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
// RUN: %clang -target arm64 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
-// RUN: %clang -target arm64_be -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
+
// ARM64-GENERIC: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64-apple-darwin -arch arm64 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-DARWIN %s
@@ -22,10 +22,8 @@
// RUN: %clang -target arm64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
-// RUN: %clang -target arm64_be -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
// RUN: %clang -target arm64 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
-// RUN: %clang -target arm64_be -mlittle-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
// ARM64-CA53: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a53"
// RUN: %clang -target aarch64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
@@ -38,10 +36,8 @@
// RUN: %clang -target arm64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
-// RUN: %clang -target arm64_be -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
// RUN: %clang -target arm64 -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
-// RUN: %clang -target arm64_be -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
// ARM64-CA57: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a57"
// RUN: %clang -target aarch64_be -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
@@ -49,11 +45,6 @@
// RUN: %clang -target aarch64_be -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
// GENERIC-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
-// RUN: %clang -target arm64_be -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC-BE %s
-// RUN: %clang -target arm64 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC-BE %s
-// RUN: %clang -target arm64_be -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC-BE %s
-// ARM64-GENERIC-BE: "-cc1"{{.*}} "-triple" "arm64_be{{.*}}" "-target-cpu" "generic"
-
// RUN: %clang -target aarch64_be -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
@@ -62,14 +53,6 @@
// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
// CA53-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a53"
-// RUN: %clang -target arm64_be -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-BE %s
-// RUN: %clang -target arm64 -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-BE %s
-// RUN: %clang -target arm64_be -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-BE %s
-// RUN: %clang -target arm64_be -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-BE %s
-// RUN: %clang -target arm64 -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-BE %s
-// RUN: %clang -target arm64_be -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-BE %s
-// ARM64-CA53-BE: "-cc1"{{.*}} "-triple" "arm64_be{{.*}}" "-target-cpu" "cortex-a53"
-
// RUN: %clang -target aarch64_be -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
@@ -78,14 +61,6 @@
// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
// CA57-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a57"
-// RUN: %clang -target arm64_be -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-BE %s
-// RUN: %clang -target arm64 -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-BE %s
-// RUN: %clang -target arm64_be -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-BE %s
-// RUN: %clang -target arm64_be -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-BE %s
-// RUN: %clang -target arm64 -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-BE %s
-// RUN: %clang -target arm64_be -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-BE %s
-// ARM64-CA57-BE: "-cc1"{{.*}} "-triple" "arm64_be{{.*}}" "-target-cpu" "cortex-a57"
-
// RUN: %clang -target aarch64 -mcpu=cortex-a57 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// MCPU-MTUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a53"
diff --git a/test/Driver/aarch64-fix-cortex-a53-835769.c b/test/Driver/aarch64-fix-cortex-a53-835769.c
new file mode 100644
index 000000000000..3fe918adec45
--- /dev/null
+++ b/test/Driver/aarch64-fix-cortex-a53-835769.c
@@ -0,0 +1,13 @@
+// RUN: %clang -target aarch64-linux-eabi %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-DEF %s
+// RUN: %clang -target aarch64-linux-eabi -mfix-cortex-a53-835769 %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-YES %s
+// RUN: %clang -target aarch64-linux-eabi -mno-fix-cortex-a53-835769 %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO %s
+
+// RUN: %clang -target aarch64-android-eabi %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-YES %s
+
+// CHECK-DEF-NOT: "-backend-option" "-aarch64-fix-cortex-a53-835769"
+// CHECK-YES: "-backend-option" "-aarch64-fix-cortex-a53-835769=1"
+// CHECK-NO: "-backend-option" "-aarch64-fix-cortex-a53-835769=0"
diff --git a/test/Driver/arm-abi.c b/test/Driver/arm-abi.c
new file mode 100644
index 000000000000..812a849110ec
--- /dev/null
+++ b/test/Driver/arm-abi.c
@@ -0,0 +1,53 @@
+// The default ABI is aapcs
+// RUN: %clang -target arm--- %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+// RUN: %clang -target armeb--- %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+// RUN: %clang -target thumb--- %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+// RUN: %clang -target thumbeb--- %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+
+// MachO targets default to apcs-gnu, except for m-class processors
+// RUN: %clang -target arm--darwin- -arch armv7s %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-APCS-GNU %s
+// RUN: %clang -target thumb--darwin- -arch armv7s %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-APCS-GNU %s
+// RUN: %clang -target thumb--darwin- -arch armv7m %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+
+// Windows targets default to AAPCS, regardless of environment
+// RUN: %clang -target arm--windows-gnueabi %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+
+// NetBSD defaults to apcs-gnu, but can also use aapcs
+// RUN: %clang -target arm--netbsd- %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-APCS-GNU %s
+// RUN: %clang -target arm--netbsd-eabi %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+// RUN: %clang -target arm--netbsd-eabihf %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+
+// Otherwise, ABI is celected based on environment
+// RUN: %clang -target arm---android %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS-LINUX %s
+// RUN: %clang -target arm---gnueabi %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS-LINUX %s
+// RUN: %clang -target arm---gnueabihf %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS-LINUX %s
+// RUN: %clang -target arm---eabi %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+// RUN: %clang -target arm---eabihf %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+
+// ABI can be overridden by the -mabi= option
+// RUN: %clang -target arm---eabi -mabi=apcs-gnu %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-APCS-GNU %s
+// RUN: %clang -target arm---gnueabi -mabi=aapcs %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+// RUN: %clang -target arm---eabi -mabi=aapcs-linux %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS-LINUX %s
+
+// CHECK-APCS-GNU: "-target-abi" "apcs-gnu"
+// CHECK-AAPCS: "-target-abi" "aapcs"
+// CHECK-AAPCS-LINUX: "-target-abi" "aapcs-linux"
diff --git a/test/Driver/arm-alignment.c b/test/Driver/arm-alignment.c
index 98046d7edf1d..3fe595143f7d 100644
--- a/test/Driver/arm-alignment.c
+++ b/test/Driver/arm-alignment.c
@@ -44,5 +44,17 @@
// RUN: %clang -target aarch64-none-gnueabi -munaligned-access -mstrict-align -### %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-ALIGNED-AARCH64 < %t %s
+// RUN: %clang -target aarch64-none-gnueabi -mkernel -mno-unaligned-access -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-ALIGNED-AARCH64 < %t %s
+
// CHECK-ALIGNED-ARM: "-backend-option" "-arm-strict-align"
// CHECK-ALIGNED-AARCH64: "-backend-option" "-aarch64-strict-align"
+
+// Make sure that v6M cores always trigger the unsupported aligned accesses error
+// for all supported architecture triples.
+// RUN: not %clang -c -target thumbv6m-none-gnueabi -mcpu=cortex-m0 -munaligned-access %s 2>&1 | \
+// RUN: FileCheck --check-prefix CHECK-UNALIGN-NOT-SUPPORTED %s
+// RUN: not %clang -c -target thumb-none-gnueabi -mcpu=cortex-m0 -munaligned-access %s 2>&1 | \
+// RUN: FileCheck --check-prefix CHECK-UNALIGN-NOT-SUPPORTED %s
+
+// CHECK-UNALIGN-NOT-SUPPORTED: error: the v6m sub-architecture does not support unaligned accesses
diff --git a/test/Driver/arm-cortex-cpus.c b/test/Driver/arm-cortex-cpus.c
index 224ba575dddd..b1f253341ef4 100644
--- a/test/Driver/arm-cortex-cpus.c
+++ b/test/Driver/arm-cortex-cpus.c
@@ -14,7 +14,7 @@
// CHECK-V5: "-cc1"{{.*}} "-triple" "armv5-{{.*}} "-target-cpu" "arm10tdmi"
// RUN: %clang -target armv5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V5-THUMB %s
-// RUN: %clang -target armv -march=armv5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V5-THUMB %s
+// RUN: %clang -target arm -march=armv5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V5-THUMB %s
// RUN: %clang -target armv5t -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V5-THUMB %s
// RUN: %clang -target arm -march=armv5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V5-THUMB %s
// CHECK-V5-THUMB: "-cc1"{{.*}} "-triple" "thumbv5-{{.*}} "-target-cpu" "arm10tdmi"
@@ -169,12 +169,14 @@
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a17 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a17 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// CHECK-CPUV7A: "-cc1"{{.*}} "-triple" "armv7-{{.*}}
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
@@ -183,12 +185,14 @@
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a9 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a12 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a15 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a17 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a17 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// CHECK-BE-CPUV7A: "-cc1"{{.*}} "-triple" "armebv7-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
@@ -197,12 +201,14 @@
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a17 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a17 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
// CHECK-CPUV7A-THUMB: "-cc1"{{.*}} "-triple" "thumbv7-{{.*}}
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
@@ -211,12 +217,14 @@
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a9 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a12 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a15 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a17 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a17 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
// CHECK-BE-CPUV7A-THUMB: "-cc1"{{.*}} "-triple" "thumbebv7-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m0 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6M %s
@@ -231,11 +239,15 @@
// CHECK-BE-CPUV7M: "-cc1"{{.*}} "-triple" "thumbebv7m-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7EM %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m7 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7EM %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m4 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7EM %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m7 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7EM %s
// CHECK-CPUV7EM: "-cc1"{{.*}} "-triple" "thumbv7em-{{.*}}
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-m4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7EM %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-m7 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7EM %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m4 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7EM %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m7 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7EM %s
// CHECK-BE-CPUV7EM: "-cc1"{{.*}} "-triple" "thumbebv7em-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
diff --git a/test/Driver/arm-fixed-r9.c b/test/Driver/arm-fixed-r9.c
index 0a95d8779780..2cec8b4c4fc8 100644
--- a/test/Driver/arm-fixed-r9.c
+++ b/test/Driver/arm-fixed-r9.c
@@ -1,4 +1,4 @@
-// RUN: %clang -target arm-none-gnueeabi -ffixed-r9 -### %s 2> %t
+// RUN: %clang -target arm-none-gnueabi -ffixed-r9 -### %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-FIXED-R9 < %t %s
// CHECK-FIXED-R9: "-backend-option" "-arm-reserve-r9"
diff --git a/test/Driver/arm-mfpu.c b/test/Driver/arm-mfpu.c
index 89c203542259..64d7d0bb630f 100644
--- a/test/Driver/arm-mfpu.c
+++ b/test/Driver/arm-mfpu.c
@@ -19,14 +19,6 @@
// CHECK-FPA: "-target-feature" "-vfp3"
// CHECK-FPA: "-target-feature" "-neon"
-// RUN: %clang -target arm-linux-eabi -mfpu=vfp3-d16 %s -### -o %t.o 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-VFP3-D16 %s
-// RUN: %clang -target arm-linux-eabi -mfpu=vfpv3-d16 %s -### -o %t.o 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-VFP3-D16 %s
-// CHECK-VFP3-D16: "-target-feature" "+vfp3"
-// CHECK-VFP3-D16: "-target-feature" "+d16"
-// CHECK-VFP3-D16: "-target-feature" "-neon"
-
// RUN: %clang -target arm-linux-eabi -mfpu=vfp %s -### -o %t.o 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-VFP %s
// CHECK-VFP: "-target-feature" "+vfp2"
@@ -39,6 +31,14 @@
// CHECK-VFP3: "-target-feature" "+vfp3"
// CHECK-VFP3: "-target-feature" "-neon"
+// RUN: %clang -target arm-linux-eabi -mfpu=vfp3-d16 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP3-D16 %s
+// RUN: %clang -target arm-linux-eabi -mfpu=vfpv3-d16 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP3-D16 %s
+// CHECK-VFP3-D16: "-target-feature" "+vfp3"
+// CHECK-VFP3-D16: "-target-feature" "+d16"
+// CHECK-VFP3-D16: "-target-feature" "-neon"
+
// RUN: %clang -target arm-linux-eabi -mfpu=vfp4 %s -### -o %t.o 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-VFP4 %s
// RUN: %clang -target arm-linux-eabi -mfpu=vfpv4 %s -### -o %t.o 2>&1 \
@@ -63,10 +63,39 @@
// CHECK-FP4-SP-D16: "-target-feature" "+fp-only-sp"
// CHECK-FP4-SP-D16: "-target-feature" "-neon"
+// RUN: %clang -target arm-linux-eabi -mfpu=fp5-sp-d16 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FP5-SP-D16 %s
+// RUN: %clang -target arm-linux-eabi -mfpu=fpv5-sp-d16 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FP5-SP-D16 %s
+// CHECK-FP5-SP-D16: "-target-feature" "+fp-armv8"
+// CHECK-FP5-SP-D16: "-target-feature" "+fp-only-sp"
+// CHECK-FP5-SP-D16: "-target-feature" "+d16"
+// CHECK-FP5-SP-D16: "-target-feature" "-neon"
+// CHECK-FP5-SP-D16: "-target-feature" "-crypto"
+
+// RUN: %clang -target arm-linux-eabi -mfpu=fp5-dp-d16 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FP5-DP-D16 %s
+// RUN: %clang -target arm-linux-eabi -mfpu=fpv5-dp-d16 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FP5-DP-D16 %s
+// CHECK-FP5-DP-D16: "-target-feature" "+fp-armv8"
+// CHECK-FP5-DP-D16: "-target-feature" "+d16"
+// CHECK-FP5-DP-D16: "-target-feature" "-neon"
+// CHECK-FP5-DP-D16: "-target-feature" "-crypto"
+
// RUN: %clang -target arm-linux-eabi -mfpu=neon %s -### -o %t.o 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NEON %s
// CHECK-NEON: "-target-feature" "+neon"
+// RUN: %clang -target arm-linux-eabi -mfpu=neon-vfpv3 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NEON-VFPV3 %s
+// CHECK-NEON-VFPV3: "-target-feature" "+vfp3"
+// CHECK-NEON-VFPV3: "-target-feature" "+neon"
+
+// RUN: %clang -target arm-linux-eabi -mfpu=neon-vfpv4 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NEON-VFPV4 %s
+// CHECK-NEON-VFPV4: "-target-feature" "+neon"
+// CHECK-NEON-VFPV4: "-target-feature" "+vfp4"
+
// RUN: %clang -target arm-linux-eabi -msoft-float %s -### -o %t.o 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-SOFT-FLOAT %s
// CHECK-SOFT-FLOAT: "-target-feature" "-neon"
diff --git a/test/Driver/ast.c b/test/Driver/ast.c
index 83dfcc37a9c8..c1d7b1a6d7b0 100644
--- a/test/Driver/ast.c
+++ b/test/Driver/ast.c
@@ -16,9 +16,10 @@
// COMPILE-AST-PHASES: 0: input,
// COMPILE-AST-PHASES: , ast
-// COMPILE-AST-PHASES: 1: compiler, {0}, assembler
-// COMPILE-AST-PHASES: 2: assembler, {1}, object
-// COMPILE-AST-PHASES-NOT: 3:
+// COMPILE-AST-PHASES: 1: compiler, {0}, ir
+// COMPILE-AST-PHASES: 2: backend, {1}, assembler
+// COMPILE-AST-PHASES: 3: assembler, {2}, object
+// COMPILE-AST-PHASES-NOT: 4:
// COMPILE-AST-PHASES: END
// FIXME: There is a problem with compiling AST's in that the input language is
diff --git a/test/Driver/biarch.c b/test/Driver/biarch.c
new file mode 100644
index 000000000000..1f0982e3c5d2
--- /dev/null
+++ b/test/Driver/biarch.c
@@ -0,0 +1,41 @@
+// RUN: %clang -target i386--netbsd -m32 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "i386--netbsd"' %t
+
+// RUN: %clang -target i386--netbsd -m64 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "x86_64--netbsd"' %t
+
+// RUN: %clang -target x86_64--netbsd -m32 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "i386--netbsd"' %t
+
+// RUN: %clang -target x86_64--netbsd -m64 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "x86_64--netbsd"' %t
+
+// RUN: %clang -target armv6--netbsd-eabihf -m32 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "armv6--netbsd-eabihf"' %t
+
+// RUN: %clang -target sparcv9--netbsd -m32 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "sparc--netbsd"' %t
+
+// RUN: %clang -target sparcv9--netbsd -m64 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "sparcv9--netbsd"' %t
+
+// RUN: %clang -target sparc64--netbsd -m64 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "sparc64--netbsd"' %t
+
+// RUN: %clang -target sparc--netbsd -m32 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "sparc--netbsd"' %t
+
+// RUN: %clang -target sparc--netbsd -m64 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "sparcv9--netbsd"' %t
+
+// RUN: %clang -target mips64--netbsd -m32 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "mips--netbsd"' %t
+
+// RUN: %clang -target mips64--netbsd -m64 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "mips64--netbsd"' %t
+
+// RUN: %clang -target mips--netbsd -m32 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "mips--netbsd"' %t
+
+// RUN: %clang -target mips--netbsd -m64 %s -### 2> %t
+// RUN: grep '"-cc1" "-triple" "mips64--netbsd"' %t
diff --git a/test/Driver/cc1-response-files.c b/test/Driver/cc1-response-files.c
new file mode 100644
index 000000000000..f47e6448a6ca
--- /dev/null
+++ b/test/Driver/cc1-response-files.c
@@ -0,0 +1,2 @@
+// RUN: %clang @%S/Inputs/cc1-response.txt -fsyntax-only -disable-llvm-optzns
+int main() {}
diff --git a/test/Driver/cl-inputs.c b/test/Driver/cl-inputs.c
index 029aeadaec42..b0265df52f05 100644
--- a/test/Driver/cl-inputs.c
+++ b/test/Driver/cl-inputs.c
@@ -34,6 +34,16 @@
// WARN: note: The last /TC or /TP option takes precedence over earlier instances
// WARN-NOT: note
+// RUN: env LIB=%S/Inputs/cl-libs %clang_cl /c /TP cl-test.lib -### 2>&1 | FileCheck -check-prefix=TPlib %s
+// TPlib: warning: cl-test.lib: 'linker' input unused
+// TPlib: warning: argument unused during compilation: '/TP'
+// TPlib-NOT: cl-test.lib
+
+// RUN: env LIB=%S/Inputs/cl-libs %clang_cl /c /TC cl-test.lib -### 2>&1 | FileCheck -check-prefix=TClib %s
+// TClib: warning: cl-test.lib: 'linker' input unused
+// TClib: warning: argument unused during compilation: '/TC'
+// TClib-NOT: cl-test.lib
+
// RUN: not %clang_cl - 2>&1 | FileCheck -check-prefix=STDIN %s
// STDIN: error: use /Tc or /Tp
diff --git a/test/Driver/cl-link-at-file.c b/test/Driver/cl-link-at-file.c
new file mode 100644
index 000000000000..f817ce523ad7
--- /dev/null
+++ b/test/Driver/cl-link-at-file.c
@@ -0,0 +1,22 @@
+// PR17239 - The /link option, when inside a response file, should only extend
+// until the end of the response file (and not the entire command line)
+
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// Note: %s must be preceded by -- or bound to another option, otherwise it may
+// be interpreted as a command-line option, e.g. on Mac where %s is commonly
+// under /Users.
+
+// RUN: echo /link bar.lib baz.lib > %t.args
+// RUN: touch %t.obj
+// RUN: %clang_cl -### @%t.args -- %t.obj 2>&1 | FileCheck %s -check-prefix=ARGS
+// If the "/link" option captures all remaining args beyond its response file,
+// it will also capture "--" and our input argument. In this case, Clang will
+// be clueless and will emit "argument unused" warnings. If PR17239 is properly
+// fixed, this should not happen because the "/link" option is restricted to
+// consume only remaining args in its response file.
+// ARGS-NOT: warning
+// ARGS-NOT: argument unused during compilation
+// Identify the linker command
+// ARGS: link.exe
diff --git a/test/Driver/cl-link.c b/test/Driver/cl-link.c
index f4717465d3ec..5bd200117967 100644
--- a/test/Driver/cl-link.c
+++ b/test/Driver/cl-link.c
@@ -19,6 +19,15 @@
// ASAN: "{{.*}}clang_rt.asan_cxx-i386.lib"
// ASAN: "{{.*}}cl-link{{.*}}.obj"
+// RUN: %clang_cl /MD /Tc%s -### -fsanitize=address 2>&1 | FileCheck --check-prefix=ASAN-MD %s
+// ASAN-MD: link.exe
+// ASAN-MD: "-debug"
+// ASAN-MD: "-incremental:no"
+// ASAN-MD: "{{.*}}clang_rt.asan_dynamic-i386.lib"
+// ASAN-MD: "{{.*}}clang_rt.asan_dynamic_runtime_thunk-i386.lib"
+// ASAN-MD: "-include:___asan_seh_interceptor"
+// ASAN-MD: "{{.*}}cl-link{{.*}}.obj"
+
// RUN: %clang_cl /LD -### /Tc%s 2>&1 | FileCheck --check-prefix=DLL %s
// RUN: %clang_cl /LDd -### /Tc%s 2>&1 | FileCheck --check-prefix=DLL %s
// DLL: link.exe
diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c
index 26cd7e9eb4c6..d9fcaf46692e 100644
--- a/test/Driver/cl-options.c
+++ b/test/Driver/cl-options.c
@@ -135,6 +135,12 @@
// RUN: %clang_cl /w -### -- %s 2>&1 | FileCheck -check-prefix=w %s
// w: -w
+// RUN: %clang_cl /Zp -### -- %s 2>&1 | FileCheck -check-prefix=ZP %s
+// ZP: -fpack-struct=1
+
+// RUN: %clang_cl /Zp2 -### -- %s 2>&1 | FileCheck -check-prefix=ZP2 %s
+// ZP2: -fpack-struct=2
+
// RUN: %clang_cl /Zs -### -- %s 2>&1 | FileCheck -check-prefix=Zs %s
// Zs: -fsyntax-only
@@ -166,8 +172,12 @@
// (/Zs is for syntax-only)
// RUN: %clang_cl /Zs \
// RUN: /analyze- \
+// RUN: /cgthreads4 \
+// RUN: /cgthreads8 \
+// RUN: /d2Zi+ \
// RUN: /errorReport:foo \
// RUN: /FS \
+// RUN: /Gd \
// RUN: /GF \
// RUN: /GS- \
// RUN: /kernel- \
@@ -178,14 +188,14 @@
// RUN: /sdl \
// RUN: /sdl- \
// RUN: /vmg \
+// RUN: /volatile:iso \
// RUN: /w12345 \
// RUN: /wd1234 \
-// RUN: /Zc:forScope \
-// RUN: /Zc:wchar_t \
-// RUN: /Zc:inline \
-// RUN: /Zc:rvalueCast \
+// RUN: /Zo \
+// RUN: /Zo- \
// RUN: -### -- %s 2>&1 | FileCheck -check-prefix=IGNORED %s
// IGNORED-NOT: argument unused during compilation
+// IGNORED-NOT: no such file or directory
// Ignored options and compile-only options are ignored for link jobs.
// RUN: touch %t.obj
@@ -204,7 +214,6 @@
// RUN: /AIfoo \
// RUN: /clr:pure \
// RUN: /docname \
-// RUN: /d2Zi+ \
// RUN: /EHsc \
// RUN: /F \
// RUN: /FA \
@@ -239,6 +248,7 @@
// RUN: /Gs1000 \
// RUN: /GT \
// RUN: /GX \
+// RUN: /Gv \
// RUN: /Gz \
// RUN: /GZ \
// RUN: /H \
@@ -257,7 +267,7 @@
// RUN: /Qvec-report:2 \
// RUN: /u \
// RUN: /V \
-// RUN: /volatile \
+// RUN: /volatile:ms \
// RUN: /wfoo \
// RUN: /WL \
// RUN: /Wp64 \
@@ -271,15 +281,11 @@
// RUN: /Yustdafx.h \
// RUN: /Z7 \
// RUN: /Za \
-// RUN: /Zc:auto \
-// RUN: /Zc:wchar_t- \
// RUN: /Ze \
// RUN: /Zg \
// RUN: /Zi \
// RUN: /ZI \
// RUN: /Zl \
-// RUN: /Zp \
-// RUN: /Zp1 \
// RUN: /ZW:nostdlib \
// RUN: -- %s 2>&1
diff --git a/test/Driver/cl-outputs.c b/test/Driver/cl-outputs.c
index 46502f6427d6..be1172f30fce 100644
--- a/test/Driver/cl-outputs.c
+++ b/test/Driver/cl-outputs.c
@@ -7,6 +7,9 @@
// RUN: %clang_cl /c -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULT %s
// DEFAULT: "-o" "cl-outputs.obj"
+// RUN: %clang_cl /Fo -### -- %s 2>&1 | FileCheck -check-prefix=FoEMPTY %s
+// FoEMPTY: "-o" "cl-outputs.obj"
+
// RUN: %clang_cl /Foa -### -- %s 2>&1 | FileCheck -check-prefix=FoNAME %s
// FoNAME: "-o" "a.obj"
@@ -25,15 +28,68 @@
// RUN: %clang_cl /Fo.. -### -- %s 2>&1 | FileCheck -check-prefix=FoCRAZY %s
// FoCRAZY: "-o" "..obj"
-// RUN: %clang_cl /Fo -### 2>&1 | FileCheck -check-prefix=FoMISSINGARG %s
-// FoMISSINGARG: error: argument to '/Fo' is missing (expected 1 value)
-
// RUN: %clang_cl /Foa.obj -### -- %s %s 2>&1 | FileCheck -check-prefix=CHECK-MULTIPLESOURCEERROR %s
// CHECK-MULTIPLESOURCEERROR: error: cannot specify '/Foa.obj' when compiling multiple source files
// RUN: %clang_cl /Fomydir/ -### -- %s %s 2>&1 | FileCheck -check-prefix=CHECK-MULTIPLESOURCEOK %s
// CHECK-MULTIPLESOURCEOK: "-o" "mydir{{[/\\]+}}cl-outputs.obj"
+// RUN: %clang_cl /Fo -### -- %s %s 2>&1 | FileCheck -check-prefix=CHECK-MULTIPLESOURCEOK2 %s
+// CHECK-MULTIPLESOURCEOK2: "-o" "cl-outputs.obj"
+// CHECK-MULTIPLESOURCEOK2: "-o" "cl-outputs.obj"
+
+// RUN: %clang_cl /c /oa -### -- %s 2>&1 | FileCheck -check-prefix=oNAME1 %s
+// oNAME1: "-o" "a.obj"
+
+// RUN: %clang_cl /c /o a -### -- %s 2>&1 | FileCheck -check-prefix=oNAME2 %s
+// oNAME2: "-o" "a.obj"
+
+// RUN: %clang_cl /c /oa.ext /ob.ext -### -- %s 2>&1 | FileCheck -check-prefix=oNAMEEXT1 %s
+// oNAMEEXT1: "-o" "b.ext"
+
+// RUN: %clang_cl /c /o a.ext /ob.ext -### -- %s 2>&1 | FileCheck -check-prefix=oNAMEEXT2 %s
+// oNAMEEXT2: "-o" "b.ext"
+
+// RUN: %clang_cl /c /ofoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=oDIR1 %s
+// oDIR1: "-o" "foo.dir{{[/\\]+}}cl-outputs.obj"
+
+// RUN: %clang_cl /c /o foo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=oDIR2 %s
+// oDIR2: "-o" "foo.dir{{[/\\]+}}cl-outputs.obj"
+
+// RUN: %clang_cl /c /ofoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=oDIRNAME1 %s
+// oDIRNAME1: "-o" "foo.dir{{[/\\]+}}a.obj"
+
+// RUN: %clang_cl /c /o foo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=oDIRNAME2 %s
+// oDIRNAME2: "-o" "foo.dir{{[/\\]+}}a.obj"
+
+// RUN: %clang_cl /c /ofoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=oDIRNAMEEXT1 %s
+// oDIRNAMEEXT1: "-o" "foo.dir{{[/\\]+}}a.ext"
+
+// RUN: %clang_cl /c /o foo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=oDIRNAMEEXT2 %s
+// oDIRNAMEEXT2: "-o" "foo.dir{{[/\\]+}}a.ext"
+
+// RUN: %clang_cl /c /o.. -### -- %s 2>&1 | FileCheck -check-prefix=oCRAZY1 %s
+// oCRAZY1: "-o" "..obj"
+
+// RUN: %clang_cl /c /o .. -### -- %s 2>&1 | FileCheck -check-prefix=oCRAZY2 %s
+// oCRAZY2: "-o" "..obj"
+
+// RUN: %clang_cl /c %s -### /o 2>&1 | FileCheck -check-prefix=oMISSINGARG %s
+// oMISSINGARG: error: argument to '/o' is missing (expected 1 value)
+
+// RUN: %clang_cl /c /omydir/ -### -- %s %s 2>&1 | FileCheck -check-prefix=CHECK-oMULTIPLESOURCEOK1 %s
+// CHECK-oMULTIPLESOURCEOK1: "-o" "mydir{{[/\\]+}}cl-outputs.obj"
+
+// RUN: %clang_cl /c /o mydir/ -### -- %s %s 2>&1 | FileCheck -check-prefix=CHECK-oMULTIPLESOURCEOK2 %s
+// CHECK-oMULTIPLESOURCEOK2: "-o" "mydir{{[/\\]+}}cl-outputs.obj"
+
+
+// RUN: %clang_cl /c /obar /Fofoo -### -- %s 2>&1 | FileCheck -check-prefix=FooRACE1 %s
+// FooRACE1: "-o" "foo.obj"
+
+// RUN: %clang_cl /c /Fofoo /obar -### -- %s 2>&1 | FileCheck -check-prefix=FooRACE2 %s
+// FooRACE2: "-o" "bar.obj"
+
// RUN: %clang_cl -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULTEXE %s
// DEFAULTEXE: cl-outputs.exe
@@ -46,6 +102,10 @@
// RUN: %clang_cl /Fefoo -### -- %s 2>&1 | FileCheck -check-prefix=FeNOEXT %s
// FeNOEXT: "-out:foo.exe"
+// RUN: %clang_cl /Fe -### -- %s 2>&1 | FileCheck -check-prefix=FeEMPTY %s
+// FeEMPTY-NOT: argument to '/Fe' is missing
+// FeEMPTY: "-out:cl-outputs.exe"
+
// RUN: %clang_cl /Fefoo /LD -### -- %s 2>&1 | FileCheck -check-prefix=FeNOEXTDLL %s
// RUN: %clang_cl /Fefoo /LDd -### -- %s 2>&1 | FileCheck -check-prefix=FeNOEXTDLL %s
// FeNOEXTDLL: "-out:foo.dll"
@@ -83,15 +143,83 @@
// FeDIRNAMEEXTDLL: "-out:foo.dir{{[/\\]+}}a.ext"
// FeDIRNAMEEXTDLL: "-implib:foo.dir{{[/\\]+}}a.lib"
-// RUN: %clang_cl /Fe -### 2>&1 | FileCheck -check-prefix=FeMISSINGARG %s
-// FeMISSINGARG: error: argument to '/Fe' is missing (expected 1 value)
-
// RUN: %clang_cl /Fefoo /Febar -### -- %s 2>&1 | FileCheck -check-prefix=FeOVERRIDE %s
// FeOVERRIDE: "-out:bar.exe"
+// RUN: %clang_cl /obar /Fefoo -### -- %s 2>&1 | FileCheck -check-prefix=FeoRACE1 %s
+// FeoRACE1: "-out:foo.exe"
+
+// RUN: %clang_cl /Fefoo /obar -### -- %s 2>&1 | FileCheck -check-prefix=FeoRACE2 %s
+// FeoRACE2: "-out:bar.exe"
+
+
+// RUN: %clang_cl /ofoo -### -- %s 2>&1 | FileCheck -check-prefix=FeoNOEXT1 %s
+// FeoNOEXT1: "-out:foo.exe"
+
+// RUN: %clang_cl /o foo -### -- %s 2>&1 | FileCheck -check-prefix=FeoNOEXT2 %s
+// FeoNOEXT2: "-out:foo.exe"
+
+// RUN: %clang_cl /o foo /LD -### -- %s 2>&1 | FileCheck -check-prefix=FeoNOEXTDLL %s
+// RUN: %clang_cl /ofoo /LDd -### -- %s 2>&1 | FileCheck -check-prefix=FeoNOEXTDLL %s
+// FeoNOEXTDLL: "-out:foo.dll"
+// FeoNOEXTDLL: "-implib:foo.lib"
+
+// RUN: %clang_cl /ofoo.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeoEXT1 %s
+// FeoEXT1: "-out:foo.ext"
+
+// RUN: %clang_cl /o foo.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeoEXT2 %s
+// FeoEXT2: "-out:foo.ext"
+
+// RUN: %clang_cl /LD /o foo.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeoEXTDLL %s
+// RUN: %clang_cl /LDd /ofoo.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeoEXTDLL %s
+// FeoEXTDLL: "-out:foo.ext"
+// FeoEXTDLL: "-implib:foo.lib"
+
+// RUN: %clang_cl /ofoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIR1 %s
+// FeoDIR1: "-out:foo.dir{{[/\\]+}}cl-outputs.exe"
+
+// RUN: %clang_cl /o foo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIR2 %s
+// FeoDIR2: "-out:foo.dir{{[/\\]+}}cl-outputs.exe"
+
+// RUN: %clang_cl /LD /o foo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIRDLL %s
+// RUN: %clang_cl /LDd /ofoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIRDLL %s
+// FeoDIRDLL: "-out:foo.dir{{[/\\]+}}cl-outputs.dll"
+// FeoDIRDLL: "-implib:foo.dir{{[/\\]+}}cl-outputs.lib"
+
+// RUN: %clang_cl /ofoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIRNAME1 %s
+// FeoDIRNAME1: "-out:foo.dir{{[/\\]+}}a.exe"
+
+// RUN: %clang_cl /o foo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIRNAME2 %s
+// FeoDIRNAME2: "-out:foo.dir{{[/\\]+}}a.exe"
+
+// RUN: %clang_cl /LD /o foo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIRNAMEDLL %s
+// RUN: %clang_cl /LDd /ofoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIRNAMEDLL %s
+// FeoDIRNAMEDLL: "-out:foo.dir{{[/\\]+}}a.dll"
+// FeoDIRNAMEDLL: "-implib:foo.dir{{[/\\]+}}a.lib"
+
+// RUN: %clang_cl /ofoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIRNAMEEXT1 %s
+// FeoDIRNAMEEXT1: "-out:foo.dir{{[/\\]+}}a.ext"
+
+// RUN: %clang_cl /o foo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIRNAMEEXT2 %s
+// FeoDIRNAMEEXT2: "-out:foo.dir{{[/\\]+}}a.ext"
+
+// RUN: %clang_cl /LD /o foo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIRNAMEEXTDLL %s
+// RUN: %clang_cl /LDd /ofoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeoDIRNAMEEXTDLL %s
+// FeoDIRNAMEEXTDLL: "-out:foo.dir{{[/\\]+}}a.ext"
+// FeoDIRNAMEEXTDLL: "-implib:foo.dir{{[/\\]+}}a.lib"
+
+// RUN: %clang_cl -### /o 2>&1 | FileCheck -check-prefix=FeoMISSINGARG %s
+// FeoMISSINGARG: error: argument to '/o' is missing (expected 1 value)
+
+// RUN: %clang_cl /ofoo /o bar -### -- %s 2>&1 | FileCheck -check-prefix=FeoOVERRIDE %s
+// FeoOVERRIDE: "-out:bar.exe"
+
+
// RUN: %clang_cl /FA -### -- %s 2>&1 | FileCheck -check-prefix=FA %s
// FA: "-o" "cl-outputs.asm"
+// RUN: %clang_cl /FA /Fa -### -- %s 2>&1 | FileCheck -check-prefix=FaEMPTY %s
+// FaEMPTY: "-o" "cl-outputs.asm"
// RUN: %clang_cl /FA /Fafoo -### -- %s 2>&1 | FileCheck -check-prefix=FaNAME %s
// RUN: %clang_cl /Fafoo -### -- %s 2>&1 | FileCheck -check-prefix=FaNAME %s
// FaNAME: "-o" "foo.asm"
@@ -105,6 +233,9 @@
// FaDIRNAMEEXT: "-o" "foo.dir{{[/\\]+}}a.ext"
// RUN: %clang_cl /Faa.asm -### -- %s %s 2>&1 | FileCheck -check-prefix=FaMULTIPLESOURCE %s
// FaMULTIPLESOURCE: error: cannot specify '/Faa.asm' when compiling multiple source files
+// RUN: %clang_cl /Fa -### -- %s %s 2>&1 | FileCheck -check-prefix=FaMULTIPLESOURCEOK %s
+// FaMULTIPLESOURCEOK: "-o" "cl-outputs.asm"
+// FaMULTIPLESOURCEOK: "-o" "cl-outputs.asm"
// RUN: %clang_cl /P -### -- %s 2>&1 | FileCheck -check-prefix=P %s
// P: "-E"
@@ -117,3 +248,28 @@
// RUN: %clang_cl /P /Fifoo.x -### -- %s 2>&1 | FileCheck -check-prefix=Fi2 %s
// Fi2: "-E"
// Fi2: "-o" "foo.x"
+
+// RUN: %clang_cl /P /ofoo -### -- %s 2>&1 | FileCheck -check-prefix=Fio1 %s
+// Fio1: "-E"
+// Fio1: "-o" "foo.i"
+
+// RUN: %clang_cl /P /o foo -### -- %s 2>&1 | FileCheck -check-prefix=Fio2 %s
+// Fio2: "-E"
+// Fio2: "-o" "foo.i"
+
+// RUN: %clang_cl /P /ofoo.x -### -- %s 2>&1 | FileCheck -check-prefix=Fio3 %s
+// Fio3: "-E"
+// Fio3: "-o" "foo.x"
+
+// RUN: %clang_cl /P /o foo.x -### -- %s 2>&1 | FileCheck -check-prefix=Fio4 %s
+// Fio4: "-E"
+// Fio4: "-o" "foo.x"
+
+
+// RUN: %clang_cl /P /obar.x /Fifoo.x -### -- %s 2>&1 | FileCheck -check-prefix=FioRACE1 %s
+// FioRACE1: "-E"
+// FioRACE1: "-o" "foo.x"
+
+// RUN: %clang_cl /P /Fifoo.x /obar.x -### -- %s 2>&1 | FileCheck -check-prefix=FioRACE2 %s
+// FioRACE2: "-E"
+// FioRACE2: "-o" "bar.x"
diff --git a/test/Driver/cl-zc.cpp b/test/Driver/cl-zc.cpp
new file mode 100644
index 000000000000..639095fded80
--- /dev/null
+++ b/test/Driver/cl-zc.cpp
@@ -0,0 +1,59 @@
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// Note: %s must be preceded by --, otherwise it may be interpreted as a
+// command-line option, e.g. on Mac where %s is commonly under /Users.
+
+// RUN: %clang_cl /c -### -- %s 2>&1 | FileCheck -check-prefix=TRIGRAPHS-DEFAULT %s
+// cc1 will disable trigraphs for -fms-compatibility as long as -ftrigraphs
+// isn't explicitly passed.
+// TRIGRAPHS-DEFAULT-NOT: "-ftrigraphs"
+
+// RUN: %clang_cl /c -### /Zc:trigraphs -- %s 2>&1 | FileCheck -check-prefix=TRIGRAPHS-ON %s
+// TRIGRAPHS-ON: "-ftrigraphs"
+
+// RUN: %clang_cl /c -### /Zc:trigraphs- -- %s 2>&1 | FileCheck -check-prefix=TRIGRAPHS-OFF %s
+// TRIGRAPHS-OFF: "-fno-trigraphs"
+
+// RUN: %clang_cl /c -### -- %s 2>&1 | FileCheck -check-prefix=STRICTSTRINGS-DEFAULT %s
+// STRICTSTRINGS-DEFAULT-NOT: -Werror=c++11-compat-deprecated-writable-strings
+// RUN: %clang_cl /c -### /Zc:strictStrings -- %s 2>&1 | FileCheck -check-prefix=STRICTSTRINGS-ON %s
+// STRICTSTRINGS-ON: -Werror=c++11-compat-deprecated-writable-strings
+// RUN: %clang_cl /c -### /Zc:strictStrings- -- %s 2>&1 | FileCheck -check-prefix=STRICTSTRINGS-OFF %s
+// STRICTSTRINGS-OFF: argument unused during compilation
+
+
+// RUN: %clang_cl /c -### /Zc:foobar -- %s 2>&1 | FileCheck -check-prefix=FOOBAR-ON %s
+// FOOBAR-ON: argument unused during compilation
+// RUN: %clang_cl /c -### /Zc:foobar- -- %s 2>&1 | FileCheck -check-prefix=FOOBAR-ON %s
+// FOOBAR-OFF: argument unused during compilation
+
+// These are ignored if enabled, and warn if disabled.
+
+// RUN: %clang_cl /c -### /Zc:forScope -- %s 2>&1 | FileCheck -check-prefix=FORSCOPE-ON %s
+// FORSCOPE-ON-NOT: argument unused during compilation
+// RUN: %clang_cl /c -### /Zc:forScope- -- %s 2>&1 | FileCheck -check-prefix=FORSCOPE-OFF %s
+// FORSCOPE-OFF: argument unused during compilation
+
+// RUN: %clang_cl /c -### /Zc:wchar_t -- %s 2>&1 | FileCheck -check-prefix=WCHAR_T-ON %s
+// WCHAR_T-ON-NOT: argument unused during compilation
+// RUN: %clang_cl /c -### /Zc:wchar_t- -- %s 2>&1 | FileCheck -check-prefix=WCHAR_T-OFF %s
+// WCHAR_T-OFF: argument unused during compilation
+
+// RUN: %clang_cl /c -### /Zc:auto -- %s 2>&1 | FileCheck -check-prefix=AUTO-ON %s
+// AUTO-ON-NOT: argument unused during compilation
+// RUN: %clang_cl /c -### /Zc:auto- -- %s 2>&1 | FileCheck -check-prefix=AUTO-OFF %s
+// AUTO-OFF: argument unused during compilation
+
+// RUN: %clang_cl /c -### /Zc:inline -- %s 2>&1 | FileCheck -check-prefix=INLINE-ON %s
+// INLINE-ON-NOT: argument unused during compilation
+// RUN: %clang_cl /c -### /Zc:inline- -- %s 2>&1 | FileCheck -check-prefix=INLINE-OFF %s
+// INLINE-OFF: argument unused during compilation
+
+
+// These never warn, but don't have an effect yet.
+
+// RUN: %clang_cl /c -### /Zc:rvalueCast -- %s 2>&1 | FileCheck -check-prefix=RVALUECAST-ON %s
+// RVALUECAST-ON-NOT: argument unused during compilation
+// RUN: %clang_cl /c -### /Zc:rvalueCast- -- %s 2>&1 | FileCheck -check-prefix=RVALUECAST-OFF %s
+// RVALUECAST-OFF: argument unused during compilation
diff --git a/test/Driver/clang-g-opts.c b/test/Driver/clang-g-opts.c
index a9566b7ee1d5..4a1e71908b9c 100644
--- a/test/Driver/clang-g-opts.c
+++ b/test/Driver/clang-g-opts.c
@@ -17,6 +17,8 @@
// RUN: | FileCheck --check-prefix=CHECK-WITH-G-DWARF2 %s
// RUN: %clang -### -S %s -g0 -g -target x86_64-pc-freebsd10.0 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-WITH-G-DWARF2 %s
+// RUN: %clang -### -S %s -g0 -g -target i386-pc-solaris 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-WITH-G-DWARF2 %s
// CHECK-WITHOUT-G-NOT: "-g"
// CHECK-WITH-G: "-g"
diff --git a/test/Driver/clang-s-opts.s b/test/Driver/clang-s-opts.s
new file mode 100644
index 000000000000..f29270882f0a
--- /dev/null
+++ b/test/Driver/clang-s-opts.s
@@ -0,0 +1,4 @@
+// RUN: %clang -### -c -flto -fno-lto %s 2>&1 | FileCheck %s
+// RUN: %clang -### -c -flto -fno-lto -fno-integrated-as %s 2>&1 | FileCheck %s
+
+// CHECK-NOT: argument unused during compilation
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
index 796da768769e..3ca9f2847523 100644
--- a/test/Driver/clang_f_opts.c
+++ b/test/Driver/clang_f_opts.c
@@ -59,6 +59,13 @@
// RUN: %clang -### -S -fauto-profile=%S/Inputs/file.prof %s 2>&1 | FileCheck -check-prefix=CHECK-AUTO-PROFILE %s
// CHECK-AUTO-PROFILE: "-fprofile-sample-use={{.*}}/file.prof"
+// RUN: %clang -### -S -fprofile-arcs %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-ARCS %s
+// RUN: %clang -### -S -fno-profile-arcs -fprofile-arcs %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-ARCS %s
+// RUN: %clang -### -S -fno-profile-arcs %s 2>&1 | FileCheck -check-prefix=CHECK-NO-PROFILE-ARCS %s
+// RUN: %clang -### -S -fprofile-arcs -fno-profile-arcs %s 2>&1 | FileCheck -check-prefix=CHECK-NO-PROFILE-ARCS %s
+// CHECK-PROFILE-ARCS: "-femit-coverage-data"
+// CHECK-NO-PROFILE-ARCS-NOT: "-femit-coverage-data"
+
// RUN: %clang -### -S -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
// RUN: %clang -### -S -fno-vectorize -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
// RUN: %clang -### -S -fno-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
@@ -132,6 +139,9 @@
// RUN: %clang -### -S -finput-charset=iso-8859-1 -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-CHARSET %s
// CHECK-INVALID-CHARSET: error: invalid value 'iso-8859-1' in '-finput-charset=iso-8859-1'
+// RUN: %clang -### -S -fexec-charset=iso-8859-1 -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-INPUT-CHARSET %s
+// CHECK-INVALID-INPUT-CHARSET: error: invalid value 'iso-8859-1' in '-fexec-charset=iso-8859-1'
+
// Test that we don't error on these.
// RUN: %clang -### -S -Werror \
// RUN: -falign-functions -falign-functions=2 -fno-align-functions \
@@ -144,6 +154,7 @@
// RUN: -fident -fno-ident \
// RUN: -fimplicit-templates -fno-implicit-templates \
// RUN: -finput-charset=UTF-8 \
+// RUN: -fexec-charset=UTF-8 \
// RUN: -fivopts -fno-ivopts \
// RUN: -fnon-call-exceptions -fno-non-call-exceptions \
// RUN: -fpermissive -fno-permissive \
@@ -166,6 +177,56 @@
// RUN: -fstrength-reduce -fno-strength-reduce \
// RUN: -finline-limit=1000 \
// RUN: -finline-limit \
+// RUN: -flto=1 \
+// RUN: -falign-labels \
+// RUN: -falign-labels=100 \
+// RUN: -falign-loops \
+// RUN: -falign-loops=100 \
+// RUN: -falign-jumps \
+// RUN: -falign-jumps=100 \
+// RUN: -fexcess-precision=100 \
+// RUN: -fbranch-count-reg \
+// RUN: -fcaller-saves \
+// RUN: -fno-default-inline -fdefault-inline \
+// RUN: -fgcse-after-reload \
+// RUN: -fgcse-las \
+// RUN: -fgcse-sm \
+// RUN: -fipa-cp \
+// RUN: -finline-functions-called-once \
+// RUN: -fmodulo-sched \
+// RUN: -fmodulo-sched-allow-regmoves \
+// RUN: -fpeel-loops \
+// RUN: -frename-registers \
+// RUN: -fschedule-insns2 \
+// RUN: -fsingle-precision-constant \
+// RUN: -ftree_loop_im \
+// RUN: -ftree_loop_ivcanon \
+// RUN: -ftree_loop_linear \
+// RUN: -funsafe-loop-optimizations \
+// RUN: -fuse-linker-plugin \
+// RUN: -fvect-cost-model \
+// RUN: -fvariable-expansion-in-unroller \
+// RUN: -fweb \
+// RUN: -fwhole-program \
+// RUN: -fno-tree-dce -ftree-dce \
+// RUN: -fno-tree-ter -ftree-ter \
+// RUN: -fno-tree-vrp -ftree-vrp \
+// RUN: -fno-delete-null-pointer-checks -fdelete-null-pointer-checks \
+// RUN: -fno-inline-small-functions -finline-small-functions \
+// RUN: -fno-fat-lto-objects -ffat-lto-objects \
+// RUN: -fno-merge-constants -fmerge-constants \
+// RUN: -fno-caller-saves -fcaller-saves \
+// RUN: -fno-reorder-blocks -freorder-blocks \
+// RUN: -fno-schedule-insns2 -fschedule-insns2 \
+// RUN: -fno-stack-check \
+// RUN: -fno-check-new -fcheck-new \
+// RUN: -ffriend-injection \
+// RUN: -fno-implement-inlines -fimplement-inlines \
+// RUN: -fstack-check \
+// RUN: -fforce-addr \
+// RUN: -malign-functions=100 \
+// RUN: -malign-loops=100 \
+// RUN: -malign-jumps=100 \
// RUN: %s 2>&1 | FileCheck --check-prefix=IGNORE %s
// IGNORE-NOT: error: unknown argument
@@ -177,6 +238,7 @@
// RUN: -fno-expensive-optimizations \
// RUN: -fno-defer-pop \
// RUN: -finline-functions \
+// RUN: -fkeep-inline-functions \
// RUN: -fno-keep-inline-functions \
// RUN: -freorder-blocks \
// RUN: -fprofile-dir=/rand/dir \
@@ -197,6 +259,48 @@
// RUN: -ftracer \
// RUN: -funroll-all-loops \
// RUN: -funswitch-loops \
+// RUN: -flto=1 \
+// RUN: -falign-labels \
+// RUN: -falign-labels=100 \
+// RUN: -falign-loops \
+// RUN: -falign-loops=100 \
+// RUN: -falign-jumps \
+// RUN: -falign-jumps=100 \
+// RUN: -fexcess-precision=100 \
+// RUN: -fbranch-count-reg \
+// RUN: -fcaller-saves \
+// RUN: -fno-default-inline \
+// RUN: -fgcse-after-reload \
+// RUN: -fgcse-las \
+// RUN: -fgcse-sm \
+// RUN: -fipa-cp \
+// RUN: -finline-functions-called-once \
+// RUN: -fmodulo-sched \
+// RUN: -fmodulo-sched-allow-regmoves \
+// RUN: -fpeel-loops \
+// RUN: -frename-registers \
+// RUN: -fschedule-insns2 \
+// RUN: -fsingle-precision-constant \
+// RUN: -ftree_loop_im \
+// RUN: -ftree_loop_ivcanon \
+// RUN: -ftree_loop_linear \
+// RUN: -funsafe-loop-optimizations \
+// RUN: -fuse-linker-plugin \
+// RUN: -fvect-cost-model \
+// RUN: -fvariable-expansion-in-unroller \
+// RUN: -fweb \
+// RUN: -fwhole-program \
+// RUN: -fcaller-saves \
+// RUN: -freorder-blocks \
+// RUN: -fdelete-null-pointer-checks \
+// RUN: -ffat-lto-objects \
+// RUN: -fmerge-constants \
+// RUN: -finline-small-functions \
+// RUN: -ftree-dce \
+// RUN: -ftree-ter \
+// RUN: -ftree-vrp \
+// RUN: -fno-devirtualize \
+// RUN: -fno-devirtualize-speculatively \
// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-WARNING %s
// CHECK-WARNING-DAG: optimization flag '-finline-limit=1000' is not supported
// CHECK-WARNING-DAG: optimization flag '-finline-limit' is not supported
@@ -204,6 +308,7 @@
// CHECK-WARNING-DAG: optimization flag '-fno-expensive-optimizations' is not supported
// CHECK-WARNING-DAG: optimization flag '-fno-defer-pop' is not supported
// CHECK-WARNING-DAG: optimization flag '-finline-functions' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fkeep-inline-functions' is not supported
// CHECK-WARNING-DAG: optimization flag '-fno-keep-inline-functions' is not supported
// CHECK-WARNING-DAG: optimization flag '-freorder-blocks' is not supported
// CHECK-WARNING-DAG: optimization flag '-fprofile-dir=/rand/dir' is not supported
@@ -224,12 +329,57 @@
// CHECK-WARNING-DAG: optimization flag '-ftracer' is not supported
// CHECK-WARNING-DAG: optimization flag '-funroll-all-loops' is not supported
// CHECK-WARNING-DAG: optimization flag '-funswitch-loops' is not supported
+// CHECK-WARNING-DAG: optimization flag '-flto=1' is not supported
+// CHECK-WARNING-DAG: optimization flag '-falign-labels' is not supported
+// CHECK-WARNING-DAG: optimization flag '-falign-labels=100' is not supported
+// CHECK-WARNING-DAG: optimization flag '-falign-loops' is not supported
+// CHECK-WARNING-DAG: optimization flag '-falign-loops=100' is not supported
+// CHECK-WARNING-DAG: optimization flag '-falign-jumps' is not supported
+// CHECK-WARNING-DAG: optimization flag '-falign-jumps=100' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fexcess-precision=100' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fbranch-count-reg' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fcaller-saves' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fno-default-inline' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fgcse-after-reload' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fgcse-las' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fgcse-sm' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fipa-cp' is not supported
+// CHECK-WARNING-DAG: optimization flag '-finline-functions-called-once' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fmodulo-sched' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fmodulo-sched-allow-regmoves' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fpeel-loops' is not supported
+// CHECK-WARNING-DAG: optimization flag '-frename-registers' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fschedule-insns2' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fsingle-precision-constant' is not supported
+// CHECK-WARNING-DAG: optimization flag '-ftree_loop_im' is not supported
+// CHECK-WARNING-DAG: optimization flag '-ftree_loop_ivcanon' is not supported
+// CHECK-WARNING-DAG: optimization flag '-ftree_loop_linear' is not supported
+// CHECK-WARNING-DAG: optimization flag '-funsafe-loop-optimizations' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fuse-linker-plugin' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fvect-cost-model' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fvariable-expansion-in-unroller' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fweb' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fwhole-program' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fcaller-saves' is not supported
+// CHECK-WARNING-DAG: optimization flag '-freorder-blocks' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fdelete-null-pointer-checks' is not supported
+// CHECK-WARNING-DAG: optimization flag '-ffat-lto-objects' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fmerge-constants' is not supported
+// CHECK-WARNING-DAG: optimization flag '-finline-small-functions' is not supported
+// CHECK-WARNING-DAG: optimization flag '-ftree-dce' is not supported
+// CHECK-WARNING-DAG: optimization flag '-ftree-ter' is not supported
+// CHECK-WARNING-DAG: optimization flag '-ftree-vrp' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fno-devirtualize' is not supported
+// CHECK-WARNING-DAG: optimization flag '-fno-devirtualize-speculatively' is not supported
// Test that we mute the warning on these
// RUN: %clang -### -finline-limit=1000 -Wno-invalid-command-line-argument \
// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-NO-WARNING1 %s
// RUN: %clang -### -finline-limit -Wno-invalid-command-line-argument \
// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-NO-WARNING2 %s
+// RUN: %clang -### -finline-limit \
+// RUN: -Winvalid-command-line-argument -Wno-ignored-optimization-argument \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-NO-WARNING2 %s
// CHECK-NO-WARNING1-NOT: optimization flag '-finline-limit=1000' is not supported
// CHECK-NO-WARNING2-NOT: optimization flag '-finline-limit' is not supported
diff --git a/test/Driver/constructors.c b/test/Driver/constructors.c
index a8b0942f01f4..cd14ed736a28 100644
--- a/test/Driver/constructors.c
+++ b/test/Driver/constructors.c
@@ -7,49 +7,58 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/fake_install_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -fno-use-init-array \
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/fake_install_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-NO-INIT-ARRAY %s
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -fno-use-init-array -fuse-init-array \
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/fake_install_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-NO-INIT-ARRAY %s
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -fuse-init-array \
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target arm-unknown-linux-androideabi \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target mipsel-unknown-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target i386-unknown-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target aarch64-none-linux-gnu \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
@@ -59,6 +68,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target arm64-none-linux-gnu \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
diff --git a/test/Driver/coverage_no_integrated_as.c b/test/Driver/coverage_no_integrated_as.c
new file mode 100644
index 000000000000..6f85b422d994
--- /dev/null
+++ b/test/Driver/coverage_no_integrated_as.c
@@ -0,0 +1,23 @@
+// REQUIRES: clang-driver
+// XFAIL: win32,win64
+
+// RUN: %clang -### -S -fprofile-arcs %s 2>&1 | FileCheck -check-prefix=CHECK-GCNO-DEFAULT-LOCATION %s
+// RUN: %clang -### -S -fprofile-arcs -no-integrated-as %s 2>&1 | FileCheck -check-prefix=CHECK-GCNO-DEFAULT-LOCATION %s
+// RUN: %clang -### -c -fprofile-arcs %s 2>&1 | FileCheck -check-prefix=CHECK-GCNO-DEFAULT-LOCATION %s
+// RUN: %clang -### -c -fprofile-arcs -no-integrated-as %s 2>&1 | FileCheck -check-prefix=CHECK-GCNO-DEFAULT-LOCATION %s
+
+// RUN: %clang -### -S -fprofile-arcs %s -o /foo/bar.o 2>&1 | FileCheck -check-prefix=CHECK-GCNO-LOCATION %s
+// RUN: %clang -### -S -fprofile-arcs -no-integrated-as %s -o /foo/bar.o 2>&1 | FileCheck -check-prefix=CHECK-GCNO-LOCATION %s
+// RUN: %clang -### -c -fprofile-arcs %s -o /foo/bar.o 2>&1 | FileCheck -check-prefix=CHECK-GCNO-LOCATION %s
+// RUN: %clang -### -c -fprofile-arcs -no-integrated-as %s -o /foo/bar.o 2>&1 | FileCheck -check-prefix=CHECK-GCNO-LOCATION %s
+
+// RUN: %clang -### -S -fprofile-arcs %s -o foo/bar.o 2>&1 | FileCheck -check-prefix=CHECK-GCNO-LOCATION-REL-PATH %s
+// RUN: %clang -### -S -fprofile-arcs -no-integrated-as %s -o foo/bar.o 2>&1 | FileCheck -check-prefix=CHECK-GCNO-LOCATION-REL-PATH %s
+// RUN: %clang -### -c -fprofile-arcs %s -o foo/bar.o 2>&1 | FileCheck -check-prefix=CHECK-GCNO-LOCATION-REL-PATH %s
+// RUN: %clang -### -c -fprofile-arcs -no-integrated-as %s -o foo/bar.o 2>&1 | FileCheck -check-prefix=CHECK-GCNO-LOCATION-REL-PATH %s
+
+
+// CHECK-GCNO-DEFAULT-LOCATION: "-coverage-file" "{{.*}}/coverage_no_integrated_as.c"
+// CHECK-GCNO-DEFAULT-LOCATION-NOT: "-coverage-file" "/tmp/{{.*}}/coverage_no_integrated_as.c"
+// CHECK-GCNO-LOCATION: "-coverage-file" "/foo/bar.o"
+// CHECK-GCNO-LOCATION-REL-PATH: "-coverage-file" "{{.*}}/foo/bar.o"
diff --git a/test/Driver/crash report spaces.c b/test/Driver/crash report spaces.c
new file mode 100644
index 000000000000..9bc4626b48b8
--- /dev/null
+++ b/test/Driver/crash report spaces.c
@@ -0,0 +1,18 @@
+// RUN: rm -rf "%t"
+// RUN: mkdir "%t"
+// RUN: not env TMPDIR="%t" TEMP="%t" TMP="%t" RC_DEBUG_OPTIONS=1 %clang -fsyntax-only "%s" 2>&1 | FileCheck "%s"
+// RUN: cat "%t/crash report spaces"-*.c | FileCheck --check-prefix=CHECKSRC "%s"
+// RUN: cat "%t/crash report spaces"-*.sh | FileCheck --check-prefix=CHECKSH "%s"
+// REQUIRES: crash-recovery
+
+// because of the glob (*.c, *.sh)
+// REQUIRES: shell
+
+#pragma clang __debug parser_crash
+// CHECK: Preprocessed source(s) and associated run script(s) are located at:
+// CHECK-NEXT: note: diagnostic msg: {{.*}}.c
+FOO
+// CHECKSRC: FOO
+// CHECKSH: "-cc1"
+// CHECKSH: "-main-file-name" "crash report spaces.c"
+// CHECKSH: "crash report spaces-{{[^ ]*}}.c"
diff --git a/test/Driver/crash-report-modules.m b/test/Driver/crash-report-modules.m
index d1c7832019cf..84b16044486b 100644
--- a/test/Driver/crash-report-modules.m
+++ b/test/Driver/crash-report-modules.m
@@ -25,8 +25,8 @@ const int x = MODULE_MACRO;
// CHECKSRC: @import simple;
// CHECKSRC: const int x = 10;
-// CHECKSH: -cc1
-// CHECKSH: -D "FOO=BAR"
-// CHECKSH-NOT: -fmodules-cache-path=/tmp/
-// CHECKSH: crash-report-modules-{{[^ ]*}}.m
-// CHECKSH: -ivfsoverlay crash-report-modules-{{[^ ]*}}.cache/vfs/vfs.yaml
+// CHECKSH: "-cc1"
+// CHECKSH: "-D" "FOO=BAR"
+// CHECKSH-NOT: "-fmodules-cache-path=/tmp/"
+// CHECKSH: "crash-report-modules-{{[^ ]*}}.m"
+// CHECKSH: "-ivfsoverlay" "crash-report-modules-{{[^ ]*}}.cache/vfs/vfs.yaml"
diff --git a/test/Driver/crash-report-null.test b/test/Driver/crash-report-null.test
new file mode 100644
index 000000000000..477dd28df3ed
--- /dev/null
+++ b/test/Driver/crash-report-null.test
@@ -0,0 +1,7 @@
+// RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH=1 %clang -fsyntax-only -x c /dev/null -lstdc++ 2>&1 | FileCheck %s
+
+// FIXME: Investigating. "fatal error: file 'nul' modified since it was first processed"
+// XFAIL: mingw32
+
+// CHECK: Preprocessed source(s) and associated run script(s) are located at:
+// CHECK-NEXT: note: diagnostic msg: {{.*}}null-{{.*}}.c
diff --git a/test/Driver/crash-report.c b/test/Driver/crash-report.c
index da1ff950fb9a..3370da88692f 100644
--- a/test/Driver/crash-report.c
+++ b/test/Driver/crash-report.c
@@ -13,27 +13,23 @@
// because of the glob (*.c, *.sh)
// REQUIRES: shell
-// RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH=1 %clang -fsyntax-only -x c /dev/null -lstdc++ 2>&1 | FileCheck %s
-
-// FIXME: Investigating. "fatal error: file 'nul' modified since it was first processed"
-// XFAIL: mingw32
-
#pragma clang __debug parser_crash
// CHECK: Preprocessed source(s) and associated run script(s) are located at:
-// CHECK-NEXT: note: diagnostic msg: {{.*}}.c
+// CHECK-NEXT: note: diagnostic msg: {{.*}}crash-report-{{.*}}.c
FOO
// CHECKSRC: FOO
-// CHECKSH: -cc1
-// CHECKSH: -D "FOO=BAR"
-// CHECKSH-NOT: -F/tmp/
-// CHECKSH-NOT: -I /tmp/
-// CHECKSH-NOT: -idirafter /tmp/
-// CHECKSH-NOT: -iquote /tmp/
-// CHECKSH-NOT: -isystem /tmp/
-// CHECKSH-NOT: -iprefix /the/prefix
-// CHECKSH-NOT: -iwithprefix /tmp/
-// CHECKSH-NOT: -iwithprefixbefore /tmp/
-// CHECKSH-NOT: -internal-isystem /tmp/
-// CHECKSH-NOT: -internal-externc-isystem /tmp/
-// CHECKSH-NOT: -dwarf-debug-flags
-// CHECKSH: crash-report-{{[^ ]*}}.c
+// CHECKSH: "-cc1"
+// CHECKSH: "-main-file-name" "crash-report.c"
+// CHECKSH: "-D" "FOO=BAR"
+// CHECKSH-NOT: "-F/tmp/"
+// CHECKSH-NOT: "-I" "/tmp/"
+// CHECKSH-NOT: "-idirafter" "/tmp/"
+// CHECKSH-NOT: "-iquote" "/tmp/"
+// CHECKSH-NOT: "-isystem" "/tmp/"
+// CHECKSH-NOT: "-iprefix" "/the/prefix"
+// CHECKSH-NOT: "-iwithprefix" "/tmp/"
+// CHECKSH-NOT: "-iwithprefixbefore" "/tmp/"
+// CHECKSH-NOT: "-internal-isystem" "/tmp/"
+// CHECKSH-NOT: "-internal-externc-isystem" "/tmp/"
+// CHECKSH-NOT: "-dwarf-debug-flags"
+// CHECKSH: "crash-report-{{[^ ]*}}.c"
diff --git a/test/Driver/cross-linux.c b/test/Driver/cross-linux.c
index ade8d8f62f33..3b1350489294 100644
--- a/test/Driver/cross-linux.c
+++ b/test/Driver/cross-linux.c
@@ -3,24 +3,24 @@
// RUN: --target=i386-unknown-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-I386 %s
// CHECK-I386: "-cc1" "-triple" "i386-unknown-linux-gnu"
-// CHECK-I386: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/../../../../i386-unknown-linux-gnu/bin{{/|\\}}as" "--32"
-// CHECK-I386: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/../../../../i386-unknown-linux-gnu/bin{{/|\\}}ld" {{.*}} "-m" "elf_i386"
+// CHECK-I386: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/../../../../i386-unknown-linux-gnu/bin{{/|\\\\}}as" "--32"
+// CHECK-I386: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/../../../../i386-unknown-linux-gnu/bin{{/|\\\\}}ld" {{.*}} "-m" "elf_i386"
//
// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
// RUN: --target=x86_64-unknown-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-X86-64 %s
// CHECK-X86-64: "-cc1" "-triple" "x86_64-unknown-linux-gnu"
-// CHECK-X86-64: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\}}as" "--64"
-// CHECK-X86-64: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\}}ld" {{.*}} "-m" "elf_x86_64"
+// CHECK-X86-64: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\\\}}as" "--64"
+// CHECK-X86-64: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\\\}}ld" {{.*}} "-m" "elf_x86_64"
//
// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
// RUN: --target=x86_64-unknown-linux-gnux32 \
// RUN: | FileCheck --check-prefix=CHECK-X32 %s
// CHECK-X32: "-cc1" "-triple" "x86_64-unknown-linux-gnux32"
-// CHECK-X32: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\}}as" "--x32"
-// CHECK-X32: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\}}ld" {{.*}} "-m" "elf32_x86_64"
+// CHECK-X32: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\\\}}as" "--x32"
+// CHECK-X32: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\\\}}ld" {{.*}} "-m" "elf32_x86_64"
//
// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
@@ -38,8 +38,8 @@
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-MULTI32-I386 %s
// CHECK-MULTI32-I386: "-cc1" "-triple" "i386-unknown-linux"
-// CHECK-MULTI32-I386: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}as" "--32"
-// CHECK-MULTI32-I386: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}ld"
+// CHECK-MULTI32-I386: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\\\}}as" "--32"
+// CHECK-MULTI32-I386: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\\\}}ld"
// CHECK-MULTI32-I386: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
// CHECK-MULTI32-I386: "-m" "elf_i386"
// CHECK-MULTI32-I386: "crti.o" "[[gcc_install:.*/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0]]{{/|\\\\}}crtbegin.o"
@@ -55,8 +55,8 @@
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-MULTI32-X86-64 %s
// CHECK-MULTI32-X86-64: "-cc1" "-triple" "x86_64-unknown-linux"
-// CHECK-MULTI32-X86-64: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}as" "--64"
-// CHECK-MULTI32-X86-64: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\}}ld"
+// CHECK-MULTI32-X86-64: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\\\}}as" "--64"
+// CHECK-MULTI32-X86-64: "{{.*}}/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/bin{{/|\\\\}}ld"
// CHECK-MULTI32-X86-64: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
// CHECK-MULTI32-X86-64: "-m" "elf_x86_64"
// CHECK-MULTI32-X86-64: "crti.o" "[[gcc_install:.*/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0]]/64{{/|\\\\}}crtbegin.o"
@@ -73,8 +73,8 @@
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-MULTI64-I386 %s
// CHECK-MULTI64-I386: "-cc1" "-triple" "i386-unknown-linux"
-// CHECK-MULTI64-I386: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}as" "--32"
-// CHECK-MULTI64-I386: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}ld"
+// CHECK-MULTI64-I386: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\\\}}as" "--32"
+// CHECK-MULTI64-I386: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\\\}}ld"
// CHECK-MULTI64-I386: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
// CHECK-MULTI64-I386: "-m" "elf_i386"
// CHECK-MULTI64-I386: "crti.o" "[[gcc_install:.*/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0]]/32{{/|\\\\}}crtbegin.o"
@@ -91,8 +91,8 @@
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-MULTI64-X86-64 %s
// CHECK-MULTI64-X86-64: "-cc1" "-triple" "x86_64-unknown-linux"
-// CHECK-MULTI64-X86-64: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}as" "--64"
-// CHECK-MULTI64-X86-64: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\}}ld"
+// CHECK-MULTI64-X86-64: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\\\}}as" "--64"
+// CHECK-MULTI64-X86-64: "{{.*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/bin{{/|\\\\}}ld"
// CHECK-MULTI64-X86-64: "--sysroot=[[sysroot:.*/Inputs/basic_linux_tree]]"
// CHECK-MULTI64-X86-64: "-m" "elf_x86_64"
// CHECK-MULTI64-X86-64: "crti.o" "[[gcc_install:.*/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0]]{{/|\\\\}}crtbegin.o"
diff --git a/test/Driver/darwin-arch-default.c b/test/Driver/darwin-arch-default.c
index 60bf61de8a34..e7e5e89ed085 100644
--- a/test/Driver/darwin-arch-default.c
+++ b/test/Driver/darwin-arch-default.c
@@ -2,6 +2,42 @@
//
// RUN: %clang -target powerpc-apple-darwin8 -### \
// RUN: -ccc-print-phases %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-POWERPC < %t %s
+// RUN: FileCheck --check-prefix=CHECK-BIND-PPC < %t %s
//
-// CHECK-POWERPC: bind-arch, "ppc"
+// CHECK-BIND-PPC: bind-arch, "ppc"
+//
+// RUN: %clang -target powerpc64-apple-darwin8 -### \
+// RUN: -ccc-print-phases %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-BIND-PPC64 < %t %s
+//
+// CHECK-BIND-PPC64: bind-arch, "ppc64"
+
+// Check that the correct arch name is passed to the external assembler
+//
+// RUN: %clang -target powerpc-apple-darwin8 -### \
+// RUN: -no-integrated-as -c %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-AS-PPC < %t %s
+//
+// CHECK-AS-PPC: {{as(.exe)?"}}
+// CHECK-AS-PPC: "-arch" "ppc"
+//
+// RUN: %clang -target powerpc64-apple-darwin8 -### \
+// RUN: -no-integrated-as -c %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-AS-PPC64 < %t %s
+//
+// CHECK-AS-PPC64: {{as(.exe)?"}}
+// CHECK-AS-PPC64: "-arch" "ppc64"
+
+// Check that the correct arch name is passed to the external linker
+//
+// RUN: %clang -target powerpc-apple-darwin8 -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-LD-PPC < %t %s
+//
+// CHECK-LD-PPC: {{ld(.exe)?"}}
+// CHECK-LD-PPC: "-arch" "ppc"
+//
+// RUN: %clang -target powerpc64-apple-darwin8 -### %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-LD-PPC64 < %t %s
+//
+// CHECK-LD-PPC64: {{ld(.exe)?"}}
+// CHECK-LD-PPC64: "-arch" "ppc64"
diff --git a/test/Driver/darwin-debug-flags.c b/test/Driver/darwin-debug-flags.c
index f98e9ce7bd8c..abe3f6953e32 100644
--- a/test/Driver/darwin-debug-flags.c
+++ b/test/Driver/darwin-debug-flags.c
@@ -1,11 +1,12 @@
-// RUN: env RC_DEBUG_OPTIONS=1 %clang -target i386-apple-darwin9 -g -Os %s -emit-llvm -S -o - | FileCheck %s
+// RUN: env RC_DEBUG_OPTIONS=1 %clang -target i386-apple-darwin9 -I "path with \spaces" -g -Os %s -emit-llvm -S -o - | FileCheck %s
// <rdar://problem/7256886>
// RUN: touch %t.s
// RUN: env RC_DEBUG_OPTIONS=1 %clang -### -target i386-apple-darwin9 -c -g %t.s 2>&1 | FileCheck -check-prefix=S %s
// <rdar://problem/12955296>
// RUN: %clang -### -target i386-apple-darwin9 -c -g %t.s 2>&1 | FileCheck -check-prefix=P %s
-// CHECK: !0 = metadata !{
+// CHECK: !0 = !{
+// CHECK: -I path\5C with\5C \5C\5Cspaces
// CHECK: -g -Os
// CHECK: -mmacosx-version-min=10.5.0
// CHECK: [ DW_TAG_compile_unit ]
@@ -15,3 +16,6 @@ int x;
// S: "-dwarf-debug-flags"
// P: "-dwarf-debug-producer"
+
+// This depends on shell quoting.
+// REQUIRES: shell
diff --git a/test/Driver/darwin-dsymutil.c b/test/Driver/darwin-dsymutil.c
index 59084a2c85ed..0e2c4907104e 100644
--- a/test/Driver/darwin-dsymutil.c
+++ b/test/Driver/darwin-dsymutil.c
@@ -6,13 +6,14 @@
//
// CHECK-MULTIARCH-ACTIONS: 0: input, "{{.*}}darwin-dsymutil.c", c
// CHECK-MULTIARCH-ACTIONS: 1: preprocessor, {0}, cpp-output
-// CHECK-MULTIARCH-ACTIONS: 2: compiler, {1}, assembler
-// CHECK-MULTIARCH-ACTIONS: 3: assembler, {2}, object
-// CHECK-MULTIARCH-ACTIONS: 4: linker, {3}, image
-// CHECK-MULTIARCH-ACTIONS: 5: bind-arch, "i386", {4}, image
-// CHECK-MULTIARCH-ACTIONS: 6: bind-arch, "x86_64", {4}, image
-// CHECK-MULTIARCH-ACTIONS: 7: lipo, {5, 6}, image
-// CHECK-MULTIARCH-ACTIONS: 8: dsymutil, {7}, dSYM
+// CHECK-MULTIARCH-ACTIONS: 2: compiler, {1}, ir
+// CHECK-MULTIARCH-ACTIONS: 3: backend, {2}, assembler
+// CHECK-MULTIARCH-ACTIONS: 4: assembler, {3}, object
+// CHECK-MULTIARCH-ACTIONS: 5: linker, {4}, image
+// CHECK-MULTIARCH-ACTIONS: 6: bind-arch, "i386", {5}, image
+// CHECK-MULTIARCH-ACTIONS: 7: bind-arch, "x86_64", {5}, image
+// CHECK-MULTIARCH-ACTIONS: 8: lipo, {6, 7}, image
+// CHECK-MULTIARCH-ACTIONS: 9: dsymutil, {8}, dSYM
//
// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -arch i386 -arch x86_64 %s -g 2> %t
diff --git a/test/Driver/darwin-ld-demangle.c b/test/Driver/darwin-ld-demangle.c
new file mode 100644
index 000000000000..1eef3c70322f
--- /dev/null
+++ b/test/Driver/darwin-ld-demangle.c
@@ -0,0 +1,8 @@
+// REQUIRES: system-darwin
+
+// On Darwin, -demangle is passed to the linker of HOST_LINK_VERSION
+// is high enough. It is assumed to be high enough on systems where
+// this test gets run.
+
+// RUN: %clang -### %s 2>&1 | FileCheck %s
+// CHECK: -demangle
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index 2da0d30b5008..d3d0f1da197b 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -17,6 +17,8 @@
// RUN: FileCheck -check-prefix=LINK_IPHONE_3_0 %s < %t.log
// LINK_IPHONE_3_0: {{ld(.exe)?"}}
+// LINK_IPHONE_3_0: -iphoneos_version_min
+// LINK_IPHONE_3_0: 3.0.0
// LINK_IPHONE_3_0-NOT: -lcrt1.3.1.o
// LINK_IPHONE_3_0: -lcrt1.o
// LINK_IPHONE_3_0: -lSystem
@@ -34,6 +36,8 @@
// RUN: FileCheck -check-prefix=LINK_IPHONE_3_1 %s < %t.log
// LINK_IPHONE_3_1: {{ld(.exe)?"}}
+// LINK_IPHONE_3_1: -iphoneos_version_min
+// LINK_IPHONE_3_1: 3.1.0
// LINK_IPHONE_3_1-NOT: -lcrt1.o
// LINK_IPHONE_3_1: -lcrt1.3.1.o
// LINK_IPHONE_3_1: -lSystem
@@ -51,6 +55,8 @@
// RUN: FileCheck -check-prefix=LINK_IOSSIM_3_0 %s < %t.log
// LINK_IOSSIM_3_0: {{ld(.exe)?"}}
+// LINK_IOSSIM_3_0: -ios_simulator_version_min
+// LINK_IOSSIM_3_0: 3.0.0
// LINK_IOSSIM_3_0-NOT: -lcrt1.o
// LINK_IOSSIM_3_0: -lSystem
// LINK_IOSSIM_3_0: {{ld(.exe)?"}}
@@ -187,10 +193,14 @@
// LINK_X86_64H_MULTIARCH: {{ld(.exe)?"}}
// LINK_X86_64H_MULTIARCH: "x86_64h"
-// Check that clang passes -iphoneos_version_min to the linker when building
-// for the iOS simulator but when -mios-simulator-version-min is not
-// explicitly specified (<rdar://problem/15959009>).
+// Check for the linker options to specify the iOS version when the
+// IPHONEOS_DEPLOYMENT_TARGET variable is used instead of the command-line
+// deployment target options.
// RUN: env IPHONEOS_DEPLOYMENT_TARGET=7.0 \
-// RUN: %clang -target i386-apple-darwin -### %t.o 2> %t.log
+// RUN: %clang -target arm64-apple-darwin -### %t.o 2> %t.log
// RUN: FileCheck -check-prefix=LINK_IPHONEOS_VERSION_MIN %s < %t.log
+// RUN: env IPHONEOS_DEPLOYMENT_TARGET=7.0 \
+// RUN: %clang -target i386-apple-darwin -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=LINK_IOS_SIMULATOR_VERSION_MIN %s < %t.log
// LINK_IPHONEOS_VERSION_MIN: -iphoneos_version_min
+// LINK_IOS_SIMULATOR_VERSION_MIN: -ios_simulator_version_min
diff --git a/test/Driver/darwin-max-type-align.c b/test/Driver/darwin-max-type-align.c
new file mode 100644
index 000000000000..6532f4aeeb91
--- /dev/null
+++ b/test/Driver/darwin-max-type-align.c
@@ -0,0 +1,15 @@
+// Check the -fmax-type-align=N flag
+// rdar://16254558
+//
+// RUN: %clang -no-canonical-prefixes -target x86_64-apple-macosx10.7.0 %s -o - -### 2>&1 | \
+// RUN: FileCheck -check-prefix=TEST0 %s
+// TEST0: -fmax-type-align=16
+// RUN: %clang -no-canonical-prefixes -fmax-type-align=32 -target x86_64-apple-macosx10.7.0 %s -o - -### 2>&1 | \
+// RUN: FileCheck -check-prefix=TEST1 %s
+// TEST1: -fmax-type-align=32
+// RUN: %clang -no-canonical-prefixes -fmax-type-align=32 -fno-max-type-align -target x86_64-apple-macosx10.7.0 %s -o - -### 2>&1 | \
+// RUN: FileCheck -check-prefix=TEST2 %s
+// TEST2-NOT: -fmax-type-align
+// RUN: %clang -no-canonical-prefixes -fno-max-type-align -target x86_64-apple-macosx10.7.0 %s -o - -### 2>&1 | \
+// RUN: FileCheck -check-prefix=TEST3 %s
+// TEST3-NOT: -fmax-type-align
diff --git a/test/Driver/darwin-sanitizer-ld.c b/test/Driver/darwin-sanitizer-ld.c
index 85cfb73c4a34..500fec4b2fcf 100644
--- a/test/Driver/darwin-sanitizer-ld.c
+++ b/test/Driver/darwin-sanitizer-ld.c
@@ -7,6 +7,8 @@
// CHECK-ASAN: "{{.*}}ld{{(.exe)?}}"
// CHECK-ASAN: stdc++
// CHECK-ASAN: libclang_rt.asan_osx_dynamic.dylib"
+// CHECK-ASAN: "-rpath" "@executable_path"
+// CHECK-ASAN: "-rpath" "{{.*}}lib{{.*}}darwin"
// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
// RUN: -fsanitize=address -mios-simulator-version-min=7.0 %s -o %t.o 2>&1 \
@@ -15,6 +17,8 @@
// CHECK-ASAN-IOSSIM: "{{.*}}ld{{(.exe)?}}"
// CHECK-ASAN-IOSSIM: lc++
// CHECK-ASAN-IOSSIM: libclang_rt.asan_iossim_dynamic.dylib"
+// CHECK-ASAN-IOSSIM: "-rpath" "@executable_path"
+// CHECK-ASAN-IOSSIM: "-rpath" "{{.*}}lib{{.*}}darwin"
// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
// RUN: -fPIC -shared -fsanitize=address %s -o %t.so 2>&1 \
@@ -22,7 +26,9 @@
// CHECK-DYN-ASAN: "{{.*}}ld{{(.exe)?}}"
// CHECK-DYN-ASAN: "-dylib"
-// CHECK-DYN-ASAN: libclang_rt.asan_osx_dynamic.dylib
+// CHECK-DYN-ASAN: libclang_rt.asan_osx_dynamic.dylib"
+// CHECK-DYN-ASAN: "-rpath" "@executable_path"
+// CHECK-DYN-ASAN: "-rpath" "{{.*}}lib{{.*}}darwin"
// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
// RUN: -fsanitize=undefined %s -o %t.o 2>&1 \
diff --git a/test/Driver/darwin-sdkroot.c b/test/Driver/darwin-sdkroot.c
index b727fa6bb0ce..58bc683320ff 100644
--- a/test/Driver/darwin-sdkroot.c
+++ b/test/Driver/darwin-sdkroot.c
@@ -33,3 +33,10 @@
//
// It doesn't make sense on msys bash.
// REQUIRES: shell-preserves-root
+//
+// This test will fail with MSYS env.exe, since it does not preserve root,
+// expanding / into C:/MINGW/MSYS/1.0. To see the problem, from cmd.exe run:
+//
+// env SDKROOT=/ cmd //c echo %SDKROOT%
+//
+// This test passes using env.exe from GnuWin32.
diff --git a/test/Driver/darwin-verify-debug.c b/test/Driver/darwin-verify-debug.c
index 4878c746e07e..ebbf89a4d636 100644
--- a/test/Driver/darwin-verify-debug.c
+++ b/test/Driver/darwin-verify-debug.c
@@ -1,13 +1,12 @@
// Check that we verify debug output properly with multiple -arch options.
//
-// REQUIRES: asserts
// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-phases \
// RUN: --verify-debug-info -arch i386 -arch x86_64 %s -g 2> %t
// RUN: FileCheck -check-prefix=CHECK-MULTIARCH-ACTIONS < %t %s
//
// CHECK-MULTIARCH-ACTIONS: 0: input, "{{.*}}darwin-verify-debug.c", c
-// CHECK-MULTIARCH-ACTIONS: 8: dsymutil, {7}, dSYM
-// CHECK-MULTIARCH-ACTIONS: 9: verify-debug-info, {8}, none
+// CHECK-MULTIARCH-ACTIONS: 9: dsymutil, {8}, dSYM
+// CHECK-MULTIARCH-ACTIONS: 10: verify-debug-info, {9}, none
//
// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: --verify-debug-info -arch i386 -arch x86_64 %s -g 2> %t
diff --git a/test/Driver/debug-options.c b/test/Driver/debug-options.c
index a8fadb36e74b..50461798efd0 100644
--- a/test/Driver/debug-options.c
+++ b/test/Driver/debug-options.c
@@ -33,6 +33,8 @@
// RUN: %clang -### -c -g -g0 %s 2>&1 | FileCheck -check-prefix=G_NO %s
// RUN: %clang -### -c -ggdb0 %s 2>&1 | FileCheck -check-prefix=G_NO %s
//
+// RUN: %clang -### -c -g1 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=GLTO_ONLY %s
// RUN: %clang -### -c -gmlt %s 2>&1 \
// RUN: | FileCheck -check-prefix=GLTO_ONLY %s
// RUN: %clang -### -c -gline-tables-only %s 2>&1 \
@@ -51,6 +53,8 @@
// RUN: | FileCheck -check-prefix=G_ONLY_DWARF2 %s
// RUN: %clang -### -c -gline-tables-only -g %s -target x86_64-pc-freebsd10.0 2>&1 \
// RUN: | FileCheck -check-prefix=G_ONLY_DWARF2 %s
+// RUN: %clang -### -c -gline-tables-only -g %s -target i386-pc-solaris 2>&1 \
+// RUN: | FileCheck -check-prefix=G_ONLY_DWARF2 %s
// RUN: %clang -### -c -gline-tables-only -g0 %s 2>&1 \
// RUN: | FileCheck -check-prefix=GLTO_NO %s
//
diff --git a/test/Driver/default-image-name.c b/test/Driver/default-image-name.c
new file mode 100644
index 000000000000..00cf7dfbd95d
--- /dev/null
+++ b/test/Driver/default-image-name.c
@@ -0,0 +1,7 @@
+// RUN: %clang -target i386-unknown-linux-gnu %s -### 2>&1 | FileCheck -check-prefix=LINUX %s
+// LINUX: a.out
+
+// RUN: %clang -target i686-pc-windows-msvc %s -### 2>&1 | FileCheck -check-prefix=WIN %s
+// RUN: %clang -target i686-pc-windows-gnu %s -### 2>&1 | FileCheck -check-prefix=WIN %s
+// RUN: %clang -target i686-windows-gnu %s -### 2>&1 | FileCheck -check-prefix=WIN %s
+// WIN: a.exe
diff --git a/test/Driver/env.c b/test/Driver/env.c
new file mode 100644
index 000000000000..f243fa641c76
--- /dev/null
+++ b/test/Driver/env.c
@@ -0,0 +1,28 @@
+// These tests try to ensure that the driver operates reasonably when run with
+// a strange environment. Unfortunately, it requires a normal shell and the
+// 'env' command.
+//
+// REQUIRES: shell
+// The PATH variable is heavily used when trying to find a linker.
+// RUN: env -i LC_ALL=C LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: --gcc-toolchain="" \
+// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
+//
+// RUN: env -i LC_ALL=C PATH="" LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: --gcc-toolchain="" \
+// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
+//
+// CHECK-LD-32-NOT: warning:
+// CHECK-LD-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-LD-32: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0{{/|\\\\}}crtbegin.o"
+// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0"
+// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/lib"
+// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../.."
+// CHECK-LD-32: "-L[[SYSROOT]]/lib"
+// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib"
diff --git a/test/Driver/fatal-warnings.c b/test/Driver/fatal-warnings.c
new file mode 100644
index 000000000000..6239b25e8917
--- /dev/null
+++ b/test/Driver/fatal-warnings.c
@@ -0,0 +1,8 @@
+// RUN: %clang -### %s -c -o tmp.o -target i686-pc-linux-gnu -integrated-as -Wa,--fatal-warnings 2>&1 | FileCheck %s
+// RUN: not %clang %s -c -o %t.o -target i686-pc-linux-gnu -integrated-as -Wa,--fatal-warnings 2>&1 %t.log
+// FileCheck --check-prefix=CHECK-AS %s -input-file %t.log
+
+// CHECK: "-cc1" {{.*}} "-massembler-fatal-warnings"
+// CHECK-AS: error: .warning argument must be a string
+
+__asm(".warning 1");
diff --git a/test/Driver/fortran.f95 b/test/Driver/fortran.f95
new file mode 100644
index 000000000000..9334cbec442a
--- /dev/null
+++ b/test/Driver/fortran.f95
@@ -0,0 +1,9 @@
+// Check that the clang driver can invoke gcc to compile Fortran.
+
+// RUN: %clang -target x86_64-unknown-linux-gnu -integrated-as -c %s -### 2>&1 \
+// RUN: | FileCheck %s
+// CHECK: gcc
+// CHECK: "-S"
+// CHECK: "-x" "f95"
+// CHECK: clang
+// CHECK: "-cc1as"
diff --git a/test/Driver/freebsd.c b/test/Driver/freebsd.c
index f0275d0156f7..a7448c11bfe6 100644
--- a/test/Driver/freebsd.c
+++ b/test/Driver/freebsd.c
@@ -1,4 +1,12 @@
// RUN: %clang -no-canonical-prefixes \
+// RUN: -target aarch64-pc-freebsd11 %s \
+// RUN: --sysroot=%S/Inputs/basic_freebsd64_tree -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ARM64 %s
+// CHECK-ARM64: "-cc1" "-triple" "aarch64-pc-freebsd11"
+// CHECK-ARM64: ld{{.*}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-ARM64: "--eh-frame-hdr" "-dynamic-linker" "{{.*}}ld-elf{{.*}}" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "-L[[SYSROOT]]/usr/lib" "{{.*}}.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "{{.*}}crtend.o" "{{.*}}crtn.o"
+//
+// RUN: %clang -no-canonical-prefixes \
// RUN: -target powerpc-pc-freebsd8 %s \
// RUN: --sysroot=%S/Inputs/basic_freebsd_tree -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PPC %s
@@ -120,11 +128,11 @@
// RUN: | FileCheck --check-prefix=CHECK-LTO %s
// CHECK-LTO: ld{{.*}}" "-plugin{{.*}}LLVMgold.so
-// RUN: %clang -target sparc-unknown-freebsd8 %s -### -fpic 2>&1 \
+// RUN: %clang -target sparc-unknown-freebsd8 %s -### -fpic -no-integrated-as 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-SPARC-PIE %s
// CHECK-SPARC-PIE: as{{.*}}" "-KPIC
-// RUN: %clang -mcpu=ultrasparc -target sparc64-unknown-freebsd8 %s -### 2>&1 \
+// RUN: %clang -mcpu=ultrasparc -target sparc64-unknown-freebsd8 %s -### -no-integrated-as 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-SPARC-CPU %s
// CHECK-SPARC-CPU: cc1{{.*}}" "-target-cpu" "ultrasparc"
// CHECK-SPARC-CPU: as{{.*}}" "-Av9a
diff --git a/test/Driver/freebsd.cc b/test/Driver/freebsd.cpp
index dea3267233cc..dea3267233cc 100644
--- a/test/Driver/freebsd.cc
+++ b/test/Driver/freebsd.cpp
diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c
index 57ea5a243fe4..1988503f677c 100644
--- a/test/Driver/fsanitize.c
+++ b/test/Driver/fsanitize.c
@@ -1,13 +1,13 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
// RUN: %clang -target x86_64-linux-gnu -fsanitize-undefined-trap-on-error -fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
-// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool),?){14}"}}
+// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){16}"}}
// CHECK-UNDEFINED-TRAP: "-fsanitize-undefined-trap-on-error"
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
-// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool),?){16}"}}
+// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-DARWIN
-// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool),?){15}"}}
+// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){17}"}}
// RUN: %clang -target x86_64-linux-gnu -fsanitize=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTEGER
// CHECK-INTEGER: "-fsanitize={{((signed-integer-overflow|unsigned-integer-overflow|integer-divide-by-zero|shift),?){4}"}}
@@ -15,8 +15,14 @@
// RUN: %clang -fsanitize=bounds -### -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=CHECK-BOUNDS
// CHECK-BOUNDS: "-fsanitize={{((array-bounds|local-bounds),?){2}"}}
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=all %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSANITIZE-ALL
+// CHECK-FSANITIZE-ALL: error: unsupported argument 'all' to option 'fsanitize='
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,undefined -fno-sanitize=all -fsanitize=thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FNO-SANITIZE-ALL
+// CHECK-FNO-SANITIZE-ALL: "-fsanitize=thread"
+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-sanitize=thread -fno-sanitize=float-cast-overflow,vptr,bool,enum %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
-// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|unreachable|return|vla-bound|alignment|null|object-size|array-bounds),?){12}"}}
+// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|unreachable|return|vla-bound|alignment|null|object-size|array-bounds|returns-nonnull-attribute|nonnull-attribute),?){14}"}}
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP-ON-ERROR-UNDEF
// CHECK-UNDEFINED-TRAP-ON-ERROR-UNDEF: '-fsanitize=undefined' not allowed with '-fsanitize-undefined-trap-on-error'
@@ -80,12 +86,40 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=3 -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACK-ORIGINS-3
// CHECK-TRACK-ORIGINS-3: error: invalid value '3' in '-fsanitize-memory-track-origins=3'
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-0
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-0
+// CHECK-SANITIZE-COVERAGE-0-NOT: fsanitize-coverage
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-1
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-coverage=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-1
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=leak -fsanitize-coverage=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-1
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-coverage=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-1
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=bool -fsanitize-coverage=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-1
+// CHECK-SANITIZE-COVERAGE-1: fsanitize-coverage=1
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-4
+// CHECK-SANITIZE-COVERAGE-4: fsanitize-coverage=4
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-5
+// CHECK-SANITIZE-COVERAGE-5: error: invalid value '5' in '-fsanitize-coverage=5'
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread -fsanitize-coverage=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-UNUSED
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=dataflow -fsanitize-coverage=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-UNUSED
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-UNUSED
+// CHECK-SANITIZE-COVERAGE-UNUSED: argument unused during compilation: '-fsanitize-coverage=1'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-field-padding=0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FIELD-PADDING-0
+// CHECK-ASAN-FIELD-PADDING-0-NOT: -fsanitize-address-field-padding
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-field-padding=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FIELD-PADDING-1
+// CHECK-ASAN-FIELD-PADDING-1: -fsanitize-address-field-padding=1
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-field-padding=2 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FIELD-PADDING-2
+// CHECK-ASAN-FIELD-PADDING-2: -fsanitize-address-field-padding=2
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-field-padding=3 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FIELD-PADDING-3
+// CHECK-ASAN-FIELD-PADDING-3: error: invalid value '3' in '-fsanitize-address-field-padding=3'
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-address-field-padding=2 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FIELD-PADDING-NO-ASAN
+// CHECK-ASAN-FIELD-PADDING-NO-ASAN: warning: argument unused during compilation: '-fsanitize-address-field-padding=2'
+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-sanitize=vptr -fsanitize=undefined,address %s -### 2>&1
// OK
// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-NO-PIE
-// CHECK-TSAN-NO-PIE: "-mrelocation-model" "pic" "-pic-level" "2" "-pie-level" "2"
-// CHECK-TSAN-NO-PIE: "-pie"
+// CHECK-TSAN-NO-PIE: "-mrelocation-model" "static"
// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MSAN-NO-PIE
// CHECK-MSAN-NO-PIE: "-mrelocation-model" "pic" "-pic-level" "2" "-pie-level" "2"
@@ -98,13 +132,22 @@
// RUN: %clang -target arm-linux-androideabi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ANDROID-NO-ASAN
// CHECK-ANDROID-NO-ASAN: "-mrelocation-model" "pic"
-// RUN: %clang -target x86_64-linux-gnu %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fno-sanitize-recover -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize-recover -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
-// CHECK-RECOVER-NOT: sanitize-recover
-// CHECK-NO-RECOVER: "-fno-sanitize-recover"
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=all -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=thread -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover -fsanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=object-size -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-RECOVER
+
+// CHECK-RECOVER: "-fsanitize-recover={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){16}"}}
+// CHECK-NO-RECOVER-NOT: sanitize-recover
+// CHECK-PARTIAL-RECOVER: "-fsanitize-recover=object-size"
+
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=address,foobar,object-size,unreachable -### 2>&1 | FileCheck %s --check-prefix=CHECK-DIAG-RECOVER
+// CHECK-DIAG-RECOVER: unsupported argument 'foobar' to option 'fsanitize-recover='
+// CHECK-DIAG-RECOVER: unsupported argument 'address,unreachable' to option 'fsanitize-recover='
// RUN: %clang -target x86_64-linux-gnu -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL
// CHECK-SANL: "-fsanitize=leak"
@@ -142,3 +185,21 @@
// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=function -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-UBSAN-DARWIN
// CHECK-FSAN-UBSAN-DARWIN: unsupported option '-fsanitize=function' for target 'x86_64-apple-darwin10'
+
+// RUN: %clang_cl -fsanitize=address -c -MDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
+// RUN: %clang_cl -fsanitize=address -c -MTd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
+// RUN: %clang_cl -fsanitize=address -c -LDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
+// RUN: %clang_cl -fsanitize=address -c -MD -MDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
+// RUN: %clang_cl -fsanitize=address -c -MT -MTd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
+// RUN: %clang_cl -fsanitize=address -c -LD -LDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
+// CHECK-ASAN-DEBUGRTL: error: invalid argument
+// CHECK-ASAN-DEBUGRTL: not allowed with '-fsanitize=address'
+// CHECK-ASAN-DEBUGRTL: note: AddressSanitizer doesn't support linking with debug runtime libraries yet
+
+// RUN: %clang_cl -fsanitize=address -c -MT -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-RELEASERTL
+// RUN: %clang_cl -fsanitize=address -c -MD -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-RELEASERTL
+// RUN: %clang_cl -fsanitize=address -c -LD -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-RELEASERTL
+// RUN: %clang_cl -fsanitize=address -c -MTd -MT -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-RELEASERTL
+// RUN: %clang_cl -fsanitize=address -c -MDd -MD -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-RELEASERTL
+// RUN: %clang_cl -fsanitize=address -c -LDd -LD -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-RELEASERTL
+// CHECK-ASAN-RELEASERTL-NOT: error: invalid argument
diff --git a/test/Driver/gcc-version-debug.c b/test/Driver/gcc-version-debug.c
index ff38c2805238..daa9606ef7a5 100644
--- a/test/Driver/gcc-version-debug.c
+++ b/test/Driver/gcc-version-debug.c
@@ -1,4 +1,5 @@
// RUN: %clang -v --target=i386-unknown-linux \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree 2>&1 | FileCheck %s
// CHECK: Found candidate GCC installation: {{.*}}Inputs{{.}}debian_multiarch_tree{{.}}usr{{.}}lib{{.}}gcc{{.}}i686-linux-gnu{{.}}4.5
diff --git a/test/Driver/gcc_forward.c b/test/Driver/gcc_forward.c
index 3bc413193f16..4892bd92ac69 100644
--- a/test/Driver/gcc_forward.c
+++ b/test/Driver/gcc_forward.c
@@ -11,10 +11,6 @@
//
// clang-cc1
// CHECK: "-Wall" "-Wdocumentation"
-// CHECK: "-o" "{{[^"]+}}.s"
-//
-// gnu-as
-// CHECK: as{{[^"]*}}"
// CHECK: "-o" "{{[^"]+}}.o"
//
// gcc-ld
diff --git a/test/Driver/hexagon-toolchain-elf.c b/test/Driver/hexagon-toolchain-elf.c
index 87c33c755fc7..984dc0439ddb 100644
--- a/test/Driver/hexagon-toolchain-elf.c
+++ b/test/Driver/hexagon-toolchain-elf.c
@@ -4,22 +4,24 @@
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK001 %s
// CHECK001: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK002 %s
// CHECK002: "-cc1" {{.*}} "-internal-isystem" "[[INSTALL_DIR:.*]]/Inputs/hexagon_tree/qc/bin/../../gnu{{/|\\\\}}hexagon/include/c++/4.4.0"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// -----------------------------------------------------------------------------
// Test -nostdinc, -nostdlibinc, -nostdinc++
@@ -27,6 +29,7 @@
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostdinc \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK003 %s
@@ -34,10 +37,11 @@
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostdlibinc \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK004 %s
@@ -45,10 +49,11 @@
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostdlibinc \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK005 %s
@@ -57,54 +62,59 @@
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostdinc++ \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK006 %s
// CHECK006: "-cc1"
// CHECK006-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
-// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// -----------------------------------------------------------------------------
// Test -march=<archname> -mcpu=<archname> -mv<number>
// -----------------------------------------------------------------------------
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -march=hexagonv3 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK007 %s
// CHECK007: "-cc1" {{.*}} "-target-cpu" "hexagonv3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv3"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -mcpu=hexagonv5 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK008 %s
// CHECK008: "-cc1" {{.*}} "-target-cpu" "hexagonv5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv5"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -mv2 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK009 %s
// CHECK009: "-cc1" {{.*}} "-target-cpu" "hexagonv2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv2"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK010 %s
// CHECK010: "-cc1" {{.*}} "-target-cpu" "hexagonv4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv4"
// RUN: not %clang -march=hexagonv2 -target hexagon-unknown-elf \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
@@ -131,11 +141,12 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK011 %s
// CHECK011: "-cc1"
-// CHECK011-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK011-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK011-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK011-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK011-NOT: "-static"
// CHECK011-NOT: "-shared"
// CHECK011: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -155,11 +166,12 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK012 %s
// CHECK012: "-cc1"
-// CHECK012-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK012-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK012-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK012-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK012-NOT: "-static"
// CHECK012-NOT: "-shared"
// CHECK012: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -180,12 +192,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -Lone -L two -L three \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK013 %s
// CHECK013: "-cc1"
-// CHECK013-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK013-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK013-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK013-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK013: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK013: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK013: "{{.*}}/hexagon/lib/v4/init.o"
@@ -204,12 +217,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -static \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK014 %s
// CHECK014: "-cc1"
-// CHECK014-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK014-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK014-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK014-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK014: "-static"
// CHECK014: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK014: "{{.*}}/hexagon/lib/v4/crt0.o"
@@ -225,12 +239,13 @@
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -shared \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK015 %s
// CHECK015: "-cc1"
-// CHECK015-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK015-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK015-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK015-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK015: "-shared" "-call_shared"
// CHECK015-NOT: crt0_standalone.o
// CHECK015-NOT: crt0.o
@@ -254,13 +269,14 @@
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -shared \
// RUN: -static \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK016 %s
// CHECK016: "-cc1"
-// CHECK016-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK016-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK016-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK016-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK016: "-shared" "-call_shared" "-static"
// CHECK016-NOT: crt0_standalone.o
// CHECK016-NOT: crt0.o
@@ -287,12 +303,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostdlib \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK017 %s
// CHECK017: "-cc1"
-// CHECK017-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK017-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK017-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK017-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK017-NOT: crt0_standalone.o
// CHECK017-NOT: crt0.o
// CHECK017-NOT: init.o
@@ -313,12 +330,13 @@
// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostartfiles \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK018 %s
// CHECK018: "-cc1"
-// CHECK018-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK018-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK018-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK018-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK018-NOT: crt0_standalone.o
// CHECK018-NOT: crt0.o
// CHECK018-NOT: init.o
@@ -339,12 +357,13 @@
// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nodefaultlibs \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK019 %s
// CHECK019: "-cc1"
-// CHECK019-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK019-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK019-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK019-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK019: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK019: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK019: "{{.*}}/hexagon/lib/v4/init.o"
@@ -368,12 +387,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -moslib=first -moslib=second \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK020 %s
// CHECK020: "-cc1"
-// CHECK020-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK020-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK020-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK020-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK020-NOT: "-static"
// CHECK020-NOT: "-shared"
// CHECK020-NOT: crt0_standalone.o
@@ -393,12 +413,13 @@
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -moslib=first -moslib=second -moslib=standalone\
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK021 %s
// CHECK021: "-cc1"
-// CHECK021-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK021-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK021-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK021-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK021-NOT: "-static"
// CHECK021-NOT: "-shared"
// CHECK021: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -421,6 +442,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clangxx -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -s \
// RUN: -Tbss 0xdead -Tdata 0xbeef -Ttext 0xcafe \
// RUN: -t \
@@ -429,8 +451,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK022 %s
// CHECK022: "-cc1"
-// CHECK022-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK022-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK022-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK022-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK022: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK022: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK022: "{{.*}}/hexagon/lib/v4/init.o"
@@ -453,27 +475,31 @@
// -----------------------------------------------------------------------------
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK023 %s
// CHECK023: "-cc1"
// CHECK023: "-mrelocation-model" "static"
-// CHECK023-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK023-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
// CHECK023-NOT: "-G{{[0-9]+}}"
-// CHECK023-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK023-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK023-NOT: "-G{{[0-9]+}}"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -fpic \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK024 %s
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -fPIC \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK024 %s
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -fPIC \
// RUN: -msmall-data-threshold=8 \
// RUN: %s 2>&1 \
@@ -482,32 +508,35 @@
// CHECK024-NOT: "-mrelocation-model" "static"
// CHECK024: "-pic-level" "{{[12]}}"
// CHECK024: "-mllvm" "-hexagon-small-data-threshold=0"
-// CHECK024-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK024-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
// CHECK024: "-G0"
-// CHECK024-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK024-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK024: "-G0"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -G=8 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK025 %s
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -G 8 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK025 %s
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -msmall-data-threshold=8 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK025 %s
// CHECK025: "-cc1"
// CHECK025: "-mrelocation-model" "static"
// CHECK025: "-mllvm" "-hexagon-small-data-threshold=8"
-// CHECK025-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK025-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
// CHECK025: "-G8"
-// CHECK025-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK025-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK025: "-G8"
// -----------------------------------------------------------------------------
@@ -515,22 +544,24 @@
// -----------------------------------------------------------------------------
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -pie \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK026 %s
// CHECK026: "-cc1"
-// CHECK026-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
-// CHECK026-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK026-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
+// CHECK026-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK026: "-pie"
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -pie -shared \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK027 %s
// CHECK027: "-cc1"
-// CHECK027-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
-// CHECK027-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK027-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
+// CHECK027-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK027-NOT: "-pie"
// -----------------------------------------------------------------------------
@@ -538,25 +569,27 @@
// -----------------------------------------------------------------------------
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK028 %s
// CHECK028: "-cc1"
// CHECK028: "-mqdsp6-compat"
// CHECK028: "-Wreturn-type"
-// CHECK028-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
-// CHECK028-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK028-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
+// CHECK028-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// -----------------------------------------------------------------------------
// Test Assembler related args
// -----------------------------------------------------------------------------
// RUN: %clang -### -target hexagon-unknown-elf \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -gdwarf-2 \
// RUN: -Wa,--noexecstack,--trap \
// RUN: -Xassembler --keep-locals \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK029 %s
// CHECK029: "-cc1"
-// CHECK029-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK029-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
// CHECK029: "--noexecstack" "--trap" "--keep-locals"
-// CHECK029-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK029-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
diff --git a/test/Driver/hexagon-toolchain.c b/test/Driver/hexagon-toolchain.c
index 88440f8d9d9b..391b78a13ea6 100644
--- a/test/Driver/hexagon-toolchain.c
+++ b/test/Driver/hexagon-toolchain.c
@@ -4,22 +4,24 @@
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK001 %s
// CHECK001: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK002 %s
// CHECK002: "-cc1" {{.*}} "-internal-isystem" "[[INSTALL_DIR:.*]]/Inputs/hexagon_tree/qc/bin/../../gnu{{/|\\\\}}hexagon/include/c++/4.4.0"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// -----------------------------------------------------------------------------
// Test -nostdinc, -nostdlibinc, -nostdinc++
@@ -27,6 +29,7 @@
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostdinc \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK003 %s
@@ -34,10 +37,11 @@
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostdlibinc \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK004 %s
@@ -45,10 +49,11 @@
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostdlibinc \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK005 %s
@@ -57,54 +62,59 @@
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostdinc++ \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK006 %s
// CHECK006: "-cc1"
// CHECK006-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
-// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
+// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
// -----------------------------------------------------------------------------
// Test -march=<archname> -mcpu=<archname> -mv<number>
// -----------------------------------------------------------------------------
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -march=hexagonv3 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK007 %s
// CHECK007: "-cc1" {{.*}} "-target-cpu" "hexagonv3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv3"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -mcpu=hexagonv5 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK008 %s
// CHECK008: "-cc1" {{.*}} "-target-cpu" "hexagonv5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv5"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -mv2 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK009 %s
// CHECK009: "-cc1" {{.*}} "-target-cpu" "hexagonv2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv2"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK010 %s
// CHECK010: "-cc1" {{.*}} "-target-cpu" "hexagonv4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"{{.*}} "-march=v4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-ld"{{.*}} "-mv4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv4"
// RUN: not %clang -march=hexagonv2 -target hexagon-unknown-linux \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
@@ -131,11 +141,12 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK011 %s
// CHECK011: "-cc1"
-// CHECK011-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK011-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK011-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK011-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK011-NOT: "-static"
// CHECK011-NOT: "-shared"
// CHECK011: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -155,11 +166,12 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK012 %s
// CHECK012: "-cc1"
-// CHECK012-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK012-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK012-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK012-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK012-NOT: "-static"
// CHECK012-NOT: "-shared"
// CHECK012: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -180,12 +192,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -Lone -L two -L three \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK013 %s
// CHECK013: "-cc1"
-// CHECK013-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK013-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK013-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK013-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK013: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK013: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK013: "{{.*}}/hexagon/lib/v4/init.o"
@@ -204,12 +217,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -static \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK014 %s
// CHECK014: "-cc1"
-// CHECK014-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK014-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK014-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK014-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK014: "-static"
// CHECK014: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK014: "{{.*}}/hexagon/lib/v4/crt0.o"
@@ -225,12 +239,13 @@
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -shared \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK015 %s
// CHECK015: "-cc1"
-// CHECK015-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK015-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK015-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK015-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK015: "-shared" "-call_shared"
// CHECK015-NOT: crt0_standalone.o
// CHECK015-NOT: crt0.o
@@ -254,13 +269,14 @@
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -shared \
// RUN: -static \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK016 %s
// CHECK016: "-cc1"
-// CHECK016-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK016-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK016-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK016-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK016: "-shared" "-call_shared" "-static"
// CHECK016-NOT: crt0_standalone.o
// CHECK016-NOT: crt0.o
@@ -287,12 +303,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostdlib \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK017 %s
// CHECK017: "-cc1"
-// CHECK017-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK017-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK017-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK017-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK017-NOT: crt0_standalone.o
// CHECK017-NOT: crt0.o
// CHECK017-NOT: init.o
@@ -313,12 +330,13 @@
// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nostartfiles \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK018 %s
// CHECK018: "-cc1"
-// CHECK018-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK018-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK018-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK018-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK018-NOT: crt0_standalone.o
// CHECK018-NOT: crt0.o
// CHECK018-NOT: init.o
@@ -339,12 +357,13 @@
// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -nodefaultlibs \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK019 %s
// CHECK019: "-cc1"
-// CHECK019-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK019-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK019-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK019-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK019: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK019: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK019: "{{.*}}/hexagon/lib/v4/init.o"
@@ -368,12 +387,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -moslib=first -moslib=second \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK020 %s
// CHECK020: "-cc1"
-// CHECK020-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK020-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK020-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK020-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK020-NOT: "-static"
// CHECK020-NOT: "-shared"
// CHECK020-NOT: crt0_standalone.o
@@ -393,12 +413,13 @@
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -moslib=first -moslib=second -moslib=standalone\
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK021 %s
// CHECK021: "-cc1"
-// CHECK021-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK021-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK021-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK021-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK021-NOT: "-static"
// CHECK021-NOT: "-shared"
// CHECK021: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
@@ -421,6 +442,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RUN: %clangxx -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -s \
// RUN: -Tbss 0xdead -Tdata 0xbeef -Ttext 0xcafe \
// RUN: -t \
@@ -429,8 +451,8 @@
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK022 %s
// CHECK022: "-cc1"
-// CHECK022-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"{{.*}}
-// CHECK022-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK022-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
+// CHECK022-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK022: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
// CHECK022: "{{.*}}/hexagon/lib/v4/crt0.o"
// CHECK022: "{{.*}}/hexagon/lib/v4/init.o"
@@ -453,27 +475,31 @@
// -----------------------------------------------------------------------------
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK023 %s
// CHECK023: "-cc1"
// CHECK023: "-mrelocation-model" "static"
-// CHECK023-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK023-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
// CHECK023-NOT: "-G{{[0-9]+}}"
-// CHECK023-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK023-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK023-NOT: "-G{{[0-9]+}}"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -fpic \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK024 %s
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -fPIC \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK024 %s
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -fPIC \
// RUN: -msmall-data-threshold=8 \
// RUN: %s 2>&1 \
@@ -482,32 +508,35 @@
// CHECK024-NOT: "-mrelocation-model" "static"
// CHECK024: "-pic-level" "{{[12]}}"
// CHECK024: "-mllvm" "-hexagon-small-data-threshold=0"
-// CHECK024-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK024-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
// CHECK024: "-G0"
-// CHECK024-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK024-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK024: "-G0"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -G=8 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK025 %s
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -G 8 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK025 %s
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -msmall-data-threshold=8 \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK025 %s
// CHECK025: "-cc1"
// CHECK025: "-mrelocation-model" "static"
// CHECK025: "-mllvm" "-hexagon-small-data-threshold=8"
-// CHECK025-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK025-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
// CHECK025: "-G8"
-// CHECK025-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK025-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK025: "-G8"
// -----------------------------------------------------------------------------
@@ -515,22 +544,24 @@
// -----------------------------------------------------------------------------
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -pie \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK026 %s
// CHECK026: "-cc1"
-// CHECK026-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
-// CHECK026-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK026-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
+// CHECK026-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK026: "-pie"
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -pie -shared \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK027 %s
// CHECK027: "-cc1"
-// CHECK027-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
-// CHECK027-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK027-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
+// CHECK027-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// CHECK027-NOT: "-pie"
// -----------------------------------------------------------------------------
@@ -538,25 +569,27 @@
// -----------------------------------------------------------------------------
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK028 %s
// CHECK028: "-cc1"
// CHECK028: "-mqdsp6-compat"
// CHECK028: "-Wreturn-type"
-// CHECK028-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
-// CHECK028-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK028-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
+// CHECK028-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
// -----------------------------------------------------------------------------
// Test Assembler related args
// -----------------------------------------------------------------------------
// RUN: %clang -### -target hexagon-unknown-linux \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: --gcc-toolchain="" \
// RUN: -gdwarf-2 \
// RUN: -Wa,--noexecstack,--trap \
// RUN: -Xassembler --keep-locals \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK029 %s
// CHECK029: "-cc1"
-// CHECK029-NEXT: "{{.*}}/bin{{/|\\}}hexagon-as"
+// CHECK029-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
// CHECK029: "--noexecstack" "--trap" "--keep-locals"
-// CHECK029-NEXT: "{{.*}}/bin{{/|\\}}hexagon-ld"
+// CHECK029-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
diff --git a/test/Driver/ident_md.c b/test/Driver/ident_md.c
index 7b2b2f6a7dee..0e664c2e1ea6 100644
--- a/test/Driver/ident_md.c
+++ b/test/Driver/ident_md.c
@@ -2,5 +2,5 @@
// Verify that clang version appears in the llvm.ident metadata.
// CHECK: !llvm.ident = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = metadata !{metadata !{{.*}}
+// CHECK: !{{[0-9]+}} = !{!{{.*}}
diff --git a/test/Driver/instrprof-ld.c b/test/Driver/instrprof-ld.c
index f70ae474d0db..f16fa8f0ed34 100644
--- a/test/Driver/instrprof-ld.c
+++ b/test/Driver/instrprof-ld.c
@@ -35,7 +35,7 @@
// RUN: | FileCheck --check-prefix=CHECK-LINUX-I386-SHARED %s
//
// CHECK-LINUX-I386-SHARED: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
-// CHECK-LINUX-I386-SHARED: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-pic-i386.a" {{.*}} "-lc"
+// CHECK-LINUX-I386-SHARED: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-i386.a" {{.*}} "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -shared \
@@ -45,7 +45,7 @@
// RUN: | FileCheck --check-prefix=CHECK-LINUX-X86-64-SHARED %s
//
// CHECK-LINUX-X86-64-SHARED: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
-// CHECK-LINUX-X86-64-SHARED: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-pic-x86_64.a" {{.*}} "-lc"
+// CHECK-LINUX-X86-64-SHARED: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-x86_64.a" {{.*}} "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -shared \
@@ -55,4 +55,4 @@
// RUN: | FileCheck --check-prefix=CHECK-FREEBSD-X86-64-SHARED %s
//
// CHECK-FREEBSD-X86-64-SHARED: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
-// CHECK-FREEBSD-X86-64-SHARED: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}freebsd{{/|\\\\}}libclang_rt.profile-pic-x86_64.a"
+// CHECK-FREEBSD-X86-64-SHARED: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}freebsd{{/|\\\\}}libclang_rt.profile-x86_64.a"
diff --git a/test/Driver/le32-unknown-nacl.cpp b/test/Driver/le32-unknown-nacl.cpp
index e029f667a192..379ddb6c63d8 100644
--- a/test/Driver/le32-unknown-nacl.cpp
+++ b/test/Driver/le32-unknown-nacl.cpp
@@ -4,9 +4,9 @@
// ECHO: {{.*}} "-cc1" {{.*}}le32-unknown-nacl.c
-// Check platform defines
-#include <stdarg.h>
-#include <stddef.h>
+typedef __builtin_va_list va_list;
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
extern "C" {
diff --git a/test/Driver/le64-unknown-unknown.cpp b/test/Driver/le64-unknown-unknown.cpp
new file mode 100644
index 000000000000..d0a58598ffe7
--- /dev/null
+++ b/test/Driver/le64-unknown-unknown.cpp
@@ -0,0 +1,137 @@
+// RUN: %clang -target le64-unknown-unknown -### %s -emit-llvm-only -c 2>&1 | FileCheck %s -check-prefix=ECHO
+// RUN: %clang -target le64-unknown-unknown %s -emit-llvm -S -c -o - | FileCheck %s
+
+// ECHO: {{.*}} "-cc1" {{.*}}le64-unknown-unknown.c
+
+typedef __builtin_va_list va_list;
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+extern "C" {
+
+// CHECK: @align_c = global i32 1
+int align_c = __alignof(char);
+
+// CHECK: @align_s = global i32 2
+int align_s = __alignof(short);
+
+// CHECK: @align_i = global i32 4
+int align_i = __alignof(int);
+
+// CHECK: @align_l = global i32 8
+int align_l = __alignof(long);
+
+// CHECK: @align_ll = global i32 8
+int align_ll = __alignof(long long);
+
+// CHECK: @align_p = global i32 8
+int align_p = __alignof(void*);
+
+// CHECK: @align_f = global i32 4
+int align_f = __alignof(float);
+
+// CHECK: @align_d = global i32 8
+int align_d = __alignof(double);
+
+// CHECK: @align_ld = global i32 8
+int align_ld = __alignof(long double);
+
+// CHECK: @align_vl = global i32 4
+int align_vl = __alignof(va_list);
+
+// CHECK: __LITTLE_ENDIAN__defined
+#ifdef __LITTLE_ENDIAN__
+void __LITTLE_ENDIAN__defined() {}
+#endif
+
+// CHECK: __le64defined
+#ifdef __le64
+void __le64defined() {}
+#endif
+
+// CHECK: __le64__defined
+#ifdef __le64__
+void __le64__defined() {}
+#endif
+
+// CHECK: unixdefined
+#ifdef unix
+void unixdefined() {}
+#endif
+
+// CHECK: __unixdefined
+#ifdef __unix
+void __unixdefined() {}
+#endif
+
+// CHECK: __unix__defined
+#ifdef __unix__
+void __unix__defined() {}
+#endif
+
+// CHECK: __ELF__defined
+#ifdef __ELF__
+void __ELF__defined() {}
+#endif
+
+// Check types
+
+// CHECK: signext i8 @check_char()
+char check_char() { return 0; }
+
+// CHECK: signext i16 @check_short()
+short check_short() { return 0; }
+
+// CHECK: i32 @check_int()
+int check_int() { return 0; }
+
+// CHECK: i64 @check_long()
+long check_long() { return 0; }
+
+// CHECK: i64 @check_longlong()
+long long check_longlong() { return 0; }
+
+// CHECK: zeroext i8 @check_uchar()
+unsigned char check_uchar() { return 0; }
+
+// CHECK: zeroext i16 @check_ushort()
+unsigned short check_ushort() { return 0; }
+
+// CHECK: i32 @check_uint()
+unsigned int check_uint() { return 0; }
+
+// CHECK: i64 @check_ulong()
+unsigned long check_ulong() { return 0; }
+
+// CHECK: i64 @check_ulonglong()
+unsigned long long check_ulonglong() { return 0; }
+
+// CHECK: i64 @check_size_t()
+size_t check_size_t() { return 0; }
+
+// CHECK: i64 @check_ptrdiff_t()
+ptrdiff_t check_ptrdiff_t() { return 0; }
+
+// CHECK: float @check_float()
+float check_float() { return 0; }
+
+// CHECK: double @check_double()
+double check_double() { return 0; }
+
+// CHECK: double @check_longdouble()
+long double check_longdouble() { return 0; }
+
+}
+
+template<int> void Switch();
+template<> void Switch<4>();
+template<> void Switch<8>();
+template<> void Switch<16>();
+
+void check_pointer_size() {
+ // CHECK: SwitchILi8
+ Switch<sizeof(void*)>();
+
+ // CHECK: SwitchILi16
+ Switch<sizeof(va_list)>();
+}
diff --git a/test/Driver/linux-header-search.cpp b/test/Driver/linux-header-search.cpp
index 309ece28db77..c62c4941f5ec 100644
--- a/test/Driver/linux-header-search.cpp
+++ b/test/Driver/linux-header-search.cpp
@@ -8,6 +8,7 @@
// RUN: -stdlib=libc++ \
// RUN: -ccc-install-dir %S/Inputs/basic_linux_tree/usr/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_libcxx_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-BASIC-LIBCXX-SYSROOT %s
// CHECK-BASIC-LIBCXX-SYSROOT: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-BASIC-LIBCXX-SYSROOT: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -18,6 +19,7 @@
// RUN: -stdlib=libc++ \
// RUN: -ccc-install-dir %S/Inputs/basic_linux_libcxx_tree/usr/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_libcxx_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-BASIC-LIBCXX-INSTALL %s
// CHECK-BASIC-LIBCXX-INSTALL: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-BASIC-LIBCXX-INSTALL: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -28,6 +30,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/ubuntu_11.04_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-11-04 %s
// CHECK-UBUNTU-11-04: "{{.*}}clang{{.*}}" "-cc1"
// CHECK-UBUNTU-11-04: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -42,6 +45,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target x86_64-unknown-linux-gnu \
// RUN: --sysroot=%S/Inputs/ubuntu_13.04_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-13-04 %s
// CHECK-UBUNTU-13-04: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-UBUNTU-13-04: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -57,6 +61,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target x86_64-unknown-linux-gnux32 \
// RUN: --sysroot=%S/Inputs/ubuntu_14.04_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-14-04 %s
// CHECK-UBUNTU-14-04: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-UBUNTU-14-04: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -72,6 +77,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target arm-linux-gnueabihf \
// RUN: --sysroot=%S/Inputs/ubuntu_13.04_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-13-04-CROSS %s
// CHECK-UBUNTU-13-04-CROSS: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-UBUNTU-13-04-CROSS: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -87,6 +93,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target x86_64-unknown-linux-gnu -m32 \
// RUN: --sysroot=%S/Inputs/ubuntu_13.04_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-13-04-M32 %s
// CHECK-UBUNTU-13-04-M32: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-UBUNTU-13-04-M32: "-triple" "i386-unknown-linux-gnu"
@@ -100,6 +107,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target x86_64-unknown-linux-gnu -m32 \
// RUN: --sysroot=%S/Inputs/ubuntu_14.04_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-14-04-M32 %s
// CHECK-UBUNTU-14-04-M32: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-UBUNTU-14-04-M32: "-triple" "i386-unknown-linux-gnu"
@@ -114,6 +122,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target x86_64-unknown-linux-gnu -m32 \
// RUN: --sysroot=%S/Inputs/ubuntu_14.04_multiarch_tree2 \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-14-04-I686 %s
// CHECK-UBUNTU-14-04-I686: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-UBUNTU-14-04-I686: "-triple" "i386-unknown-linux-gnu"
@@ -126,6 +135,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target powerpc64le-unknown-linux-gnu -m32 \
// RUN: --sysroot=%S/Inputs/ubuntu_14.04_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-14-04-PPC64LE %s
// CHECK-UBUNTU-14-04-PPC64LE: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-UBUNTU-14-04-PPC64LE: "-triple" "powerpc64le-unknown-linux-gnu"
@@ -141,6 +151,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target i686-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-X86 %s
// CHECK-DEBIAN-X86: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-DEBIAN-X86: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -155,6 +166,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target x86_64-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-X86-64 %s
// CHECK-DEBIAN-X86-64: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-DEBIAN-X86-64: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -169,6 +181,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target powerpc-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC %s
// CHECK-DEBIAN-PPC: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-DEBIAN-PPC: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -183,6 +196,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target powerpc64-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC64 %s
// CHECK-DEBIAN-PPC64: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-DEBIAN-PPC64: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -200,6 +214,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target x86_64-unknown-linux-gnu \
// RUN: --sysroot=%S/Inputs/gentoo_linux_gcc_4.6.2_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-GENTOO-4-6-2 %s
// CHECK-GENTOO-4-6-2: "{{.*}}clang{{.*}}" "-cc1"
// CHECK-GENTOO-4-6-2: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -213,6 +228,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target x86_64-unknown-linux-gnu \
// RUN: --sysroot=%S/Inputs/gentoo_linux_gcc_4.6.4_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-GENTOO-4-6-4 %s
// CHECK-GENTOO-4-6-4: "{{.*}}clang{{.*}}" "-cc1"
// CHECK-GENTOO-4-6-4: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -228,6 +244,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target mips64-unknown-linux-gnuabi64 \
// RUN: --sysroot=%S/Inputs/debian_6_mips64_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-MIPS64-GNUABI %s
// CHECK-MIPS64-GNUABI: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-MIPS64-GNUABI: "-isysroot" "[[SYSROOT:[^"]+]]"
@@ -244,6 +261,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target mips64el-unknown-linux-gnuabi64 \
// RUN: --sysroot=%S/Inputs/debian_6_mips64_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-MIPS64EL-GNUABI %s
// CHECK-MIPS64EL-GNUABI: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
// CHECK-MIPS64EL-GNUABI: "-isysroot" "[[SYSROOT:[^"]+]]"
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index 6a47d08274d2..1ce923b61ac3 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -3,6 +3,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i386-unknown-linux \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
// CHECK-LD-32-NOT: warning:
@@ -16,6 +17,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64 %s
// CHECK-LD-64-NOT: warning:
@@ -35,6 +37,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux-gnux32 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-X32 %s
// CHECK-LD-X32-NOT: warning:
@@ -48,6 +51,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: --rtlib=compiler-rt \
// RUN: | FileCheck --check-prefix=CHECK-LD-RT %s
@@ -68,6 +72,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: --rtlib=libgcc \
// RUN: | FileCheck --check-prefix=CHECK-LD-GCC %s
@@ -89,6 +94,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux \
// RUN: -static-libgcc \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC-LIBGCC %s
// CHECK-LD-64-STATIC-LIBGCC-NOT: warning:
@@ -109,6 +115,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux \
// RUN: -static \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC %s
// CHECK-LD-64-STATIC-NOT: warning:
@@ -129,11 +136,13 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux \
// RUN: -static-libgcc -static \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC %s
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i386-unknown-linux -m32 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-32-TO-32 %s
// CHECK-32-TO-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -150,6 +159,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i386-unknown-linux -m64 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-32-TO-64 %s
// CHECK-32-TO-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -167,6 +177,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux -m64 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-64-TO-64 %s
// CHECK-64-TO-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -183,6 +194,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux -m32 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-64-TO-32 %s
// CHECK-64-TO-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -200,6 +212,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux-gnux32 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-X32 %s
// CHECK-X32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -217,6 +230,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux -mx32 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-64-TO-X32 %s
// CHECK-64-TO-X32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -234,6 +248,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i386-unknown-linux -mx32 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-32-TO-X32 %s
// CHECK-32-TO-X32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -250,6 +265,41 @@
// CHECK-32-TO-X32: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=x86_64-unknown-linux-gnux32 -m64 \
+// RUN: --gcc-toolchain="" \
+// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-X32-TO-64 %s
+// CHECK-X32-TO-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-X32-TO-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0{{/|\\\\}}crtbegin.o"
+// CHECK-X32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
+// CHECK-X32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib/../lib64"
+// CHECK-X32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../lib64"
+// CHECK-X32-TO-64: "-L[[SYSROOT]]/lib/../lib64"
+// CHECK-X32-TO-64: "-L[[SYSROOT]]/usr/lib/../lib64"
+// CHECK-X32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
+// CHECK-X32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
+// CHECK-X32-TO-64: "-L[[SYSROOT]]/lib"
+// CHECK-X32-TO-64: "-L[[SYSROOT]]/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=x86_64-unknown-linux-gnux32 -m32 \
+// RUN: --gcc-toolchain="" \
+// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-X32-TO-32 %s
+// CHECK-X32-TO-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-X32-TO-32: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32{{/|\\\\}}crtbegin.o"
+// CHECK-X32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32"
+// CHECK-X32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib/../lib32"
+// CHECK-X32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../lib32"
+// CHECK-X32-TO-32: "-L[[SYSROOT]]/lib/../lib32"
+// CHECK-X32-TO-32: "-L[[SYSROOT]]/usr/lib/../lib32"
+// CHECK-X32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
+// CHECK-X32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
+// CHECK-X32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
+// CHECK-X32-TO-32: "-L[[SYSROOT]]/lib"
+// CHECK-X32-TO-32: "-L[[SYSROOT]]/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux -m32 \
// RUN: --gcc-toolchain=%S/Inputs/multilib_64bit_linux_tree/usr \
// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
@@ -266,6 +316,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/fake_install_tree/bin \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-INSTALL-DIR-32 %s
// CHECK-INSTALL-DIR-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -277,6 +328,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux -m64 \
// RUN: -ccc-install-dir %S/Inputs/fake_install_tree/bin \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-INSTALL-DIR-64 %s
// CHECK-INSTALL-DIR-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -288,6 +340,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing1/bin \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION1 %s
// CHECK-GCC-VERSION1: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -296,6 +349,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing2/bin \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION2 %s
// CHECK-GCC-VERSION2: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -304,6 +358,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing3/bin \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION3 %s
// CHECK-GCC-VERSION3: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -312,6 +367,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing4/bin \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION4 %s
// CHECK-GCC-VERSION4: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -324,6 +380,7 @@
// RUN: -target x86_64-unknown-linux-gnu \
// RUN: -stdlib=libc++ \
// RUN: -ccc-install-dir %S/Inputs/basic_linux_tree/usr/bin \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_libcxx_tree \
// RUN: | FileCheck --check-prefix=CHECK-BASIC-LIBCXX-SYSROOT %s
// CHECK-BASIC-LIBCXX-SYSROOT: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
@@ -335,6 +392,7 @@
// RUN: -target x86_64-unknown-linux-gnu \
// RUN: -stdlib=libc++ \
// RUN: -ccc-install-dir %S/Inputs/basic_linux_libcxx_tree/usr/bin \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_libcxx_tree \
// RUN: | FileCheck --check-prefix=CHECK-BASIC-LIBCXX-INSTALL %s
// CHECK-BASIC-LIBCXX-INSTALL: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
@@ -347,6 +405,7 @@
// Test a very broken version of multiarch that shipped in Ubuntu 11.04.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i386-unknown-linux \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/ubuntu_11.04_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-11-04 %s
// CHECK-UBUNTU-11-04: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -361,6 +420,7 @@
// Check multi arch support on Ubuntu 12.04 LTS.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-unknown-linux-gnueabihf \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/ubuntu_12.04_LTS_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-12-04-ARM-HF %s
// CHECK-UBUNTU-12-04-ARM-HF: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -378,6 +438,7 @@
// Check Ubuntu 13.10 on x86-64 targeting arm-linux-gnueabihf.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-gnueabihf \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/x86-64_ubuntu_13.10 \
// RUN: | FileCheck --check-prefix=CHECK-X86-64-UBUNTU-13-10-ARM-HF %s
// CHECK-X86-64-UBUNTU-13-10-ARM-HF: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -396,6 +457,7 @@
// Check Ubuntu 13.10 on x86-64 targeting arm-linux-gnueabi.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-gnueabi \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/x86-64_ubuntu_13.10 \
// RUN: | FileCheck --check-prefix=CHECK-X86-64-UBUNTU-13-10-ARM %s
// CHECK-X86-64-UBUNTU-13-10-ARM: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -414,6 +476,7 @@
// Check Ubuntu 14.04 on powerpc64le.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=powerpc64le-unknown-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/ubuntu_14.04_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-14-04-PPC64LE %s
// CHECK-UBUNTU-14-04-PPC64LE: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -432,6 +495,7 @@
// "/usr/lib/gcc/x86_64-linux-gnu/4.8/x32/crtend.o" "/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../libx32/crtn.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-unknown-linux-gnux32 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/ubuntu_14.04_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-14-04-X32 %s
// CHECK-UBUNTU-14-04-X32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -451,6 +515,7 @@
// Check fedora 18 on arm.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=armv7-unknown-linux-gnueabihf \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/fedora_18_tree \
// RUN: | FileCheck --check-prefix=CHECK-FEDORA-18-ARM-HF %s
// CHECK-FEDORA-18-ARM-HF: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -465,10 +530,12 @@
// Check Fedora 21 on AArch64.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm64-unknown-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/fedora_21_tree \
// RUN: | FileCheck --check-prefix=CHECK-FEDORA-21-AARCH64 %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=aarch64-unknown-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/fedora_21_tree \
// RUN: | FileCheck --check-prefix=CHECK-FEDORA-21-AARCH64 %s
// CHECK-FEDORA-21-AARCH64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -482,6 +549,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-unknown-linux-gnueabi \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/ubuntu_12.04_LTS_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-12-04-ARM %s
// CHECK-UBUNTU-12-04-ARM: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -499,6 +567,7 @@
// Test the setup that shipped in SUSE 10.3 on ppc64.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=powerpc64-suse-linux \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/suse_10.3_ppc64_tree \
// RUN: | FileCheck --check-prefix=CHECK-SUSE-10-3-PPC64 %s
// CHECK-SUSE-10-3-PPC64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -524,12 +593,47 @@
// CHECK-ARM-HF: "-dynamic-linker" "{{.*}}/lib/ld-linux-armhf.so.3"
//
// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: --target=powerpc64-linux-gnu \
+// RUN: | FileCheck --check-prefix=CHECK-PPC64 %s
+// CHECK-PPC64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PPC64: "-m" "elf64ppc"
+// CHECK-PPC64: "-dynamic-linker" "{{.*}}/lib64/ld64.so.1"
+//
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: --target=powerpc64-linux-gnu -mabi=elfv1 \
+// RUN: | FileCheck --check-prefix=CHECK-PPC64-ELFv1 %s
+// CHECK-PPC64-ELFv1: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PPC64-ELFv1: "-m" "elf64ppc"
+// CHECK-PPC64-ELFv1: "-dynamic-linker" "{{.*}}/lib64/ld64.so.1"
+//
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: --target=powerpc64-linux-gnu -mabi=elfv2 \
+// RUN: | FileCheck --check-prefix=CHECK-PPC64-ELFv2 %s
+// CHECK-PPC64-ELFv2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PPC64-ELFv2: "-m" "elf64ppc"
+// CHECK-PPC64-ELFv2: "-dynamic-linker" "{{.*}}/lib64/ld64.so.2"
+//
+// RUN: %clang %s -### -o %t.o 2>&1 \
// RUN: --target=powerpc64le-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-PPC64LE %s
// CHECK-PPC64LE: "{{.*}}ld{{(.exe)?}}"
// CHECK-PPC64LE: "-m" "elf64lppc"
// CHECK-PPC64LE: "-dynamic-linker" "{{.*}}/lib64/ld64.so.2"
//
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: --target=powerpc64le-linux-gnu -mabi=elfv1 \
+// RUN: | FileCheck --check-prefix=CHECK-PPC64LE-ELFv1 %s
+// CHECK-PPC64LE-ELFv1: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PPC64LE-ELFv1: "-m" "elf64lppc"
+// CHECK-PPC64LE-ELFv1: "-dynamic-linker" "{{.*}}/lib64/ld64.so.1"
+//
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: --target=powerpc64le-linux-gnu -mabi=elfv2 \
+// RUN: | FileCheck --check-prefix=CHECK-PPC64LE-ELFv2 %s
+// CHECK-PPC64LE-ELFv2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PPC64LE-ELFv2: "-m" "elf64lppc"
+// CHECK-PPC64LE-ELFv2: "-dynamic-linker" "{{.*}}/lib64/ld64.so.2"
+//
// Check that we do not pass --hash-style=gnu and --hash-style=both to linker
// and provide correct path to the dynamic linker and emulation mode when build
// for MIPS platforms.
@@ -633,6 +737,7 @@
// Thoroughly exercise the Debian multiarch environment.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i686-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-X86 %s
// CHECK-DEBIAN-X86: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -645,6 +750,7 @@
// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-X86-64 %s
// CHECK-DEBIAN-X86-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -657,6 +763,7 @@
// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=powerpc-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC %s
// CHECK-DEBIAN-PPC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -669,6 +776,7 @@
// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=powerpc64-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC64 %s
// CHECK-DEBIAN-PPC64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -681,6 +789,7 @@
// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS %s
// CHECK-DEBIAN-MIPS: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -693,6 +802,7 @@
// CHECK-DEBIAN-MIPS: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPSEL %s
// CHECK-DEBIAN-MIPSEL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -705,6 +815,7 @@
// CHECK-DEBIAN-MIPSEL: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS64 %s
// CHECK-DEBIAN-MIPS64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -716,6 +827,7 @@
// CHECK-DEBIAN-MIPS64: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS64EL %s
// CHECK-DEBIAN-MIPS64EL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -727,6 +839,7 @@
// CHECK-DEBIAN-MIPS64EL: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64-linux-gnu -mabi=n32 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS64-N32 %s
// CHECK-DEBIAN-MIPS64-N32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -738,6 +851,7 @@
// CHECK-DEBIAN-MIPS64-N32: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-gnu -mabi=n32 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS64EL-N32 %s
// CHECK-DEBIAN-MIPS64EL-N32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -751,34 +865,42 @@
// Test linker invocation on Android.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-androideabi \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=aarch64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i686-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// CHECK-ANDROID: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -791,16 +913,19 @@
// CHECK-ANDROID: "{{.*}}{{/|\\\\}}crtend_android.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-androideabi \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=aarch64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
@@ -811,21 +936,25 @@
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i686-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
@@ -840,6 +969,7 @@
// CHECK-ANDROID-SO: "{{.*}}{{/|\\\\}}crtend_so.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-androideabi \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
@@ -850,6 +980,7 @@
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=aarch64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
@@ -860,21 +991,25 @@
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i686-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=x86-linux-android \
+// RUN: --target=x86_64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
@@ -888,41 +1023,49 @@
// CHECK-ANDROID-STATIC: "{{.*}}{{/|\\\\}}crtend_android.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-androideabi \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=aarch64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i686-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
@@ -935,34 +1078,42 @@
// CHECK-ANDROID-PIE: "{{.*}}{{/|\\\\}}crtend_android.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-androideabi \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-32 %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-32 %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-32 %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=aarch64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-64 %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-64 %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-64 %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i686-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-32 %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-linux-android \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-64 %s
// CHECK-ANDROID-32: "-dynamic-linker" "/system/bin/linker"
@@ -971,18 +1122,22 @@
// Test that -pthread does not add -lpthread on Android.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-androideabi -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=aarch64-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm64-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
@@ -991,53 +1146,64 @@
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i686-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-androideabi -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=aarch64-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm64-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i686-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=x86_64-linux-android -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD %s
@@ -1045,6 +1211,7 @@
//
// RUN: %clang -no-canonical-prefixes %t.o -### -o %t 2>&1 \
// RUN: --target=arm-linux-androideabi -pthread \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PTHREAD-LINK %s
// CHECK-ANDROID-PTHREAD-LINK-NOT: argument unused during compilation: '-pthread'
@@ -1052,6 +1219,7 @@
// Check linker invocation on Debian 6 MIPS 32/64-bit.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_6_mips_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-ML-MIPSEL %s
// CHECK-DEBIAN-ML-MIPSEL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -1068,6 +1236,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-gnu \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_6_mips_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-ML-MIPS64EL %s
// CHECK-DEBIAN-ML-MIPS64EL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -1084,6 +1253,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-gnu -mabi=n32 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_6_mips_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-ML-MIPS64EL-N32 %s
// CHECK-DEBIAN-ML-MIPS64EL-N32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -1100,6 +1270,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64-linux-gnuabi64 -mabi=n64 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_6_mips64_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-ML-MIPS64-GNUABI %s
// CHECK-DEBIAN-ML-MIPS64-GNUABI: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -1119,6 +1290,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-gnuabi64 -mabi=n64 \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/debian_6_mips64_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-ML-MIPS64EL-GNUABI %s
// CHECK-DEBIAN-ML-MIPS64EL-GNUABI: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -1139,6 +1311,7 @@
// Test linker invocation for Freescale SDK (OpenEmbedded).
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=powerpc-fsl-linux \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/freescale_ppc_tree \
// RUN: | FileCheck --check-prefix=CHECK-FSL-PPC %s
// CHECK-FSL-PPC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -1148,6 +1321,7 @@
// CHECK-FSL-PPC: "-L[[SYSROOT]]/usr/lib"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=powerpc64-fsl-linux \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/freescale_ppc64_tree \
// RUN: | FileCheck --check-prefix=CHECK-FSL-PPC64 %s
// CHECK-FSL-PPC64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -1158,41 +1332,53 @@
//
// Check that crtfastmath.o is linked with -ffast-math and with -Ofast.
// RUN: %clang --target=x86_64-unknown-linux -### %s \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NOCRTFASTMATH %s
// RUN: %clang --target=x86_64-unknown-linux -### %s -ffast-math \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRTFASTMATH %s
// RUN: %clang --target=x86_64-unknown-linux -### %s -funsafe-math-optimizations\
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRTFASTMATH %s
// RUN: %clang --target=x86_64-unknown-linux -### %s -Ofast\
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRTFASTMATH %s
// RUN: %clang --target=x86_64-unknown-linux -### %s -Ofast -O3\
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NOCRTFASTMATH %s
// RUN: %clang --target=x86_64-unknown-linux -### %s -O3 -Ofast\
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRTFASTMATH %s
// RUN: %clang --target=x86_64-unknown-linux -### %s -ffast-math -fno-fast-math \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NOCRTFASTMATH %s
// RUN: %clang --target=x86_64-unknown-linux -### %s -Ofast -fno-fast-math \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRTFASTMATH %s
// RUN: %clang --target=x86_64-unknown-linux -### %s -Ofast -fno-unsafe-math-optimizations \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRTFASTMATH %s
// RUN: %clang --target=x86_64-unknown-linux -### %s -fno-fast-math -Ofast \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRTFASTMATH %s
// RUN: %clang --target=x86_64-unknown-linux -### %s -fno-unsafe-math-optimizations -Ofast \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRTFASTMATH %s
// We don't have crtfastmath.o in the i386 tree, use it to check that file
// detection works.
// RUN: %clang --target=i386-unknown-linux -### %s -ffast-math \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NOCRTFASTMATH %s
// CHECK-CRTFASTMATH: usr/lib/gcc/x86_64-unknown-linux/4.6.0{{/|\\\\}}crtfastmath.o
@@ -1200,12 +1386,14 @@
// Check that we link in gcrt1.o when compiling with -pg
// RUN: %clang -pg --target=x86_64-unknown-linux -### %s \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>& 1 \
// RUN: | FileCheck --check-prefix=CHECK-PG %s
// CHECK-PG: gcrt1.o
// GCC forwards -u to the linker.
// RUN: %clang -u asdf --target=x86_64-unknown-linux -### %s \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>& 1 \
// RUN: | FileCheck --check-prefix=CHECK-u %s
// CHECK-u: "-u" "asdf"
diff --git a/test/Driver/lto.c b/test/Driver/lto.c
index 91524bf78b1d..62300bd8fac1 100644
--- a/test/Driver/lto.c
+++ b/test/Driver/lto.c
@@ -1,19 +1,22 @@
// -flto causes a switch to llvm-bc object files.
// RUN: %clang -ccc-print-phases -c %s -flto 2> %t.log
-// RUN: grep '2: compiler, {1}, lto-bc' %t.log
+// RUN: grep '2: compiler, {1}, ir' %t.log
+// RUN: grep '3: backend, {2}, lto-bc' %t.log
// RUN: %clang -ccc-print-phases %s -flto 2> %t.log
// RUN: grep '0: input, ".*lto.c", c' %t.log
// RUN: grep '1: preprocessor, {0}, cpp-output' %t.log
-// RUN: grep '2: compiler, {1}, lto-bc' %t.log
-// RUN: grep '3: linker, {2}, image' %t.log
+// RUN: grep '2: compiler, {1}, ir' %t.log
+// RUN: grep '3: backend, {2}, lto-bc' %t.log
+// RUN: grep '4: linker, {3}, image' %t.log
// llvm-bc and llvm-ll outputs need to match regular suffixes
// (unfortunately).
// RUN: %clang %s -flto -save-temps -### 2> %t.log
// RUN: grep '"-o" ".*lto\.i" "-x" "c" ".*lto\.c"' %t.log
-// RUN: grep '"-o" ".*lto\.o" .*".*lto\.i"' %t.log
-// RUN: grep '".*a.out" .*".*lto\.o"' %t.log
+// RUN: grep '"-o" ".*lto\.bc" .*".*lto\.i"' %t.log
+// RUN: grep '"-o" ".*lto\.o" .*".*lto\.bc"' %t.log
+// RUN: grep '".*a\.\(out\|exe\)" .*".*lto\.o"' %t.log
// RUN: %clang %s -flto -S -### 2> %t.log
// RUN: grep '"-o" ".*lto\.s" "-x" "c" ".*lto\.c"' %t.log
diff --git a/test/Driver/mips-as.c b/test/Driver/mips-as.c
index ecbe7d668f96..12f184437417 100644
--- a/test/Driver/mips-as.c
+++ b/test/Driver/mips-as.c
@@ -51,7 +51,7 @@
// RUN: %clang -target mips64el-linux-gnu -mabi=64 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS64R2-EL-AS %s
-// MIPS64R2-EL-AS: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-KPIC" "-EL"
+// MIPS64R2-EL-AS: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-KPIC" "-EL"
//
// RUN: %clang -target mips-linux-gnu -march=mips32r2 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
@@ -61,7 +61,7 @@
// RUN: %clang -target mips64-linux-gnu -march=octeon -### \
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-OCTEON %s
-// MIPS-OCTEON: as{{(.exe)?}}" "-march" "octeon" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS-OCTEON: as{{(.exe)?}}" "-march" "octeon" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
//
// RUN: %clang -target mips-linux-gnu -mips1 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
@@ -106,17 +106,17 @@
// RUN: %clang -target mips64-linux-gnu -mips64 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64 %s
-// MIPS-ALIAS-64: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS-ALIAS-64: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
//
// RUN: %clang -target mips64-linux-gnu -mips64r2 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R2 %s
-// MIPS-ALIAS-64R2: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS-ALIAS-64R2: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
//
// RUN: %clang -target mips64-linux-gnu -mips64r6 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R6 %s
-// MIPS-ALIAS-64R6: as{{(.exe)?}}" "-march" "mips64r6" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS-ALIAS-64R6: as{{(.exe)?}}" "-march" "mips64r6" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
//
// RUN: %clang -target mips-linux-gnu -mno-mips16 -mips16 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
@@ -214,15 +214,15 @@
//
// RUN: %clang -target mips64-linux-gnu -### -no-integrated-as -c %s -mcpu=mips3 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS3-EB-AS %s
-// MIPS3-EB-AS: as{{(.exe)?}}" "-march" "mips3" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS3-EB-AS: as{{(.exe)?}}" "-march" "mips3" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
//
// RUN: %clang -target mips64-linux-gnu -### -no-integrated-as -c %s -mcpu=mips4 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS4-EB-AS %s
-// MIPS4-EB-AS: as{{(.exe)?}}" "-march" "mips4" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS4-EB-AS: as{{(.exe)?}}" "-march" "mips4" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
//
// RUN: %clang -target mips64-linux-gnu -### -no-integrated-as -c %s -mcpu=mips5 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS5-EB-AS %s
-// MIPS5-EB-AS: as{{(.exe)?}}" "-march" "mips5" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS5-EB-AS: as{{(.exe)?}}" "-march" "mips5" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
//
// RUN: %clang -target mips-linux-gnu -### -no-integrated-as -c %s -mcpu=mips32 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS32-EB-AS %s
@@ -236,11 +236,11 @@
//
// RUN: %clang -target mips64-linux-gnu -### -no-integrated-as -c %s -mcpu=mips64 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS64-EB-AS %s
-// MIPS64-EB-AS: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS64-EB-AS: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
//
// RUN: %clang -target mips64-linux-gnu -### -no-integrated-as -c %s -mcpu=mips64r6 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS64R6-EB-AS %s
-// MIPS64R6-EB-AS: as{{(.exe)?}}" "-march" "mips64r6" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS64R6-EB-AS: as{{(.exe)?}}" "-march" "mips64r6" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
//
// RUN: %clang -target mips-linux-gnu -### -no-integrated-as -msoft-float -mhard-float -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=HARDFLOAT --implicit-check-not=-msoft-float %s
diff --git a/test/Driver/mips-cs.cpp b/test/Driver/mips-cs.cpp
index ad031a935de3..62a90f0b9110 100644
--- a/test/Driver/mips-cs.cpp
+++ b/test/Driver/mips-cs.cpp
@@ -28,6 +28,35 @@
// CHECK-BE-HF-32: "[[TC]]{{/|\\\\}}crtend.o"
// CHECK-BE-HF-32: "[[TC]]/../../../../mips-linux-gnu/libc/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Big-endian, hard float, uclibc
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -muclibc \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-UC-HF-32 %s
+// CHECK-BE-UC-HF-32: "-internal-isystem"
+// CHECK-BE-UC-HF-32: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
+// CHECK-BE-UC-HF-32: "-internal-isystem"
+// CHECK-BE-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/mips-linux-gnu/uclibc"
+// CHECK-BE-UC-HF-32: "-internal-isystem"
+// CHECK-BE-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/backward"
+// CHECK-BE-UC-HF-32: "-internal-externc-isystem"
+// CHECK-BE-UC-HF-32: "[[TC]]/include"
+// CHECK-BE-UC-HF-32: "-internal-externc-isystem"
+// CHECK-BE-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/usr/include"
+// CHECK-BE-UC-HF-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-UC-HF-32: "--sysroot=[[TC]]/../../../../mips-linux-gnu/libc/uclibc"
+// CHECK-BE-UC-HF-32: "-dynamic-linker" "/lib/ld-uClibc.so.0"
+// CHECK-BE-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-UC-HF-32: "[[TC]]/uclibc{{/|\\\\}}crtbegin.o"
+// CHECK-BE-UC-HF-32: "-L[[TC]]/uclibc"
+// CHECK-BE-UC-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/uclibc"
+// CHECK-BE-UC-HF-32-NOT: "-L[[TC]]"
+// CHECK-BE-UC-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/lib/../lib"
+// CHECK-BE-UC-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/usr/lib/../lib"
+// CHECK-BE-UC-HF-32: "[[TC]]/uclibc{{/|\\\\}}crtend.o"
+// CHECK-BE-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Big-endian, hard float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips-linux-gnu -mips16 \
@@ -115,6 +144,35 @@
// CHECK-BE-HF-NAN: "[[TC]]/nan2008{{/|\\\\}}crtend.o"
// CHECK-BE-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/libc/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Big-endian, hard float, uclibc, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -muclibc -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-UC-HF-NAN %s
+// CHECK-BE-UC-HF-NAN: "-internal-isystem"
+// CHECK-BE-UC-HF-NAN: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
+// CHECK-BE-UC-HF-NAN: "-internal-isystem"
+// CHECK-BE-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/mips-linux-gnu/uclibc/nan2008"
+// CHECK-BE-UC-HF-NAN: "-internal-isystem"
+// CHECK-BE-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/backward"
+// CHECK-BE-UC-HF-NAN: "-internal-externc-isystem"
+// CHECK-BE-UC-HF-NAN: "[[TC]]/include"
+// CHECK-BE-UC-HF-NAN: "-internal-externc-isystem"
+// CHECK-BE-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/usr/include"
+// CHECK-BE-UC-HF-NAN: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-UC-HF-NAN: "--sysroot=[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008"
+// CHECK-BE-UC-HF-NAN: "-dynamic-linker" "/lib/ld-uClibc-mipsn8.so.0"
+// CHECK-BE-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-UC-HF-NAN: "[[TC]]/uclibc/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-UC-HF-NAN: "-L[[TC]]/uclibc/nan2008"
+// CHECK-BE-UC-HF-NAN: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/uclibc/nan2008"
+// CHECK-BE-UC-HF-NAN-NOT: "-L[[TC]]"
+// CHECK-BE-UC-HF-NAN: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/lib/../lib"
+// CHECK-BE-UC-HF-NAN: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/usr/lib/../lib"
+// CHECK-BE-UC-HF-NAN: "[[TC]]/uclibc/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Big-endian, soft float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips-linux-gnu -msoft-float \
@@ -144,6 +202,35 @@
// CHECK-BE-SF-32: "[[TC]]/soft-float{{/|\\\\}}crtend.o"
// CHECK-BE-SF-32: "[[TC]]/../../../../mips-linux-gnu/libc/soft-float/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Big-endian, soft float, uclibc
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -muclibc -msoft-float \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-UC-SF-32 %s
+// CHECK-BE-UC-SF-32: "-internal-isystem"
+// CHECK-BE-UC-SF-32: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
+// CHECK-BE-UC-SF-32: "-internal-isystem"
+// CHECK-BE-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/mips-linux-gnu/uclibc/soft-float"
+// CHECK-BE-UC-SF-32: "-internal-isystem"
+// CHECK-BE-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/backward"
+// CHECK-BE-UC-SF-32: "-internal-externc-isystem"
+// CHECK-BE-UC-SF-32: "[[TC]]/include"
+// CHECK-BE-UC-SF-32: "-internal-externc-isystem"
+// CHECK-BE-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/usr/include"
+// CHECK-BE-UC-SF-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-UC-SF-32: "--sysroot=[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float"
+// CHECK-BE-UC-SF-32: "-dynamic-linker" "/lib/ld-uClibc.so.0"
+// CHECK-BE-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-UC-SF-32: "[[TC]]/uclibc/soft-float{{/|\\\\}}crtbegin.o"
+// CHECK-BE-UC-SF-32: "-L[[TC]]/uclibc/soft-float"
+// CHECK-BE-UC-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/uclibc/soft-float"
+// CHECK-BE-UC-SF-32-NOT: "-L[[TC]]"
+// CHECK-BE-UC-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/lib/../lib"
+// CHECK-BE-UC-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/usr/lib/../lib"
+// CHECK-BE-UC-SF-32: "[[TC]]/uclibc/soft-float{{/|\\\\}}crtend.o"
+// CHECK-BE-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Big-endian, soft float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips-linux-gnu -msoft-float -mips16 \
@@ -289,6 +376,35 @@
// CHECK-EL-HF-32: "[[TC]]/el{{/|\\\\}}crtend.o"
// CHECK-EL-HF-32: "[[TC]]/../../../../mips-linux-gnu/libc/el/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Little-endian, hard float, uclibc
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mhard-float -muclibc \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-UC-HF-32 %s
+// CHECK-EL-UC-HF-32: "-internal-isystem"
+// CHECK-EL-UC-HF-32: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
+// CHECK-EL-UC-HF-32: "-internal-isystem"
+// CHECK-EL-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/mips-linux-gnu/uclibc/el"
+// CHECK-EL-UC-HF-32: "-internal-isystem"
+// CHECK-EL-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/backward"
+// CHECK-EL-UC-HF-32: "-internal-externc-isystem"
+// CHECK-EL-UC-HF-32: "[[TC]]/include"
+// CHECK-EL-UC-HF-32: "-internal-externc-isystem"
+// CHECK-EL-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/usr/include"
+// CHECK-EL-UC-HF-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-UC-HF-32: "--sysroot=[[TC]]/../../../../mips-linux-gnu/libc/uclibc/el"
+// CHECK-EL-UC-HF-32: "-dynamic-linker" "/lib/ld-uClibc.so.0"
+// CHECK-EL-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-UC-HF-32: "[[TC]]/uclibc/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-UC-HF-32: "-L[[TC]]/uclibc/el"
+// CHECK-EL-UC-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/uclibc/el"
+// CHECK-EL-UC-HF-32-NOT: "-L[[TC]]"
+// CHECK-EL-UC-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/el/lib/../lib"
+// CHECK-EL-UC-HF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/el/usr/lib/../lib"
+// CHECK-EL-UC-HF-32: "[[TC]]/uclibc/el{{/|\\\\}}crtend.o"
+// CHECK-EL-UC-HF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/el/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Little-endian, hard float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-gnu -mips16 \
@@ -376,6 +492,35 @@
// CHECK-EL-HF-NAN: "[[TC]]/nan2008/el{{/|\\\\}}crtend.o"
// CHECK-EL-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/libc/nan2008/el/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Little-endian, hard float, uclibc, nan2008
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -muclibc -mnan=2008 \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-UC-HF-NAN %s
+// CHECK-EL-UC-HF-NAN: "-internal-isystem"
+// CHECK-EL-UC-HF-NAN: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
+// CHECK-EL-UC-HF-NAN: "-internal-isystem"
+// CHECK-EL-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/mips-linux-gnu/uclibc/nan2008/el"
+// CHECK-EL-UC-HF-NAN: "-internal-isystem"
+// CHECK-EL-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/backward"
+// CHECK-EL-UC-HF-NAN: "-internal-externc-isystem"
+// CHECK-EL-UC-HF-NAN: "[[TC]]/include"
+// CHECK-EL-UC-HF-NAN: "-internal-externc-isystem"
+// CHECK-EL-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/usr/include"
+// CHECK-EL-UC-HF-NAN: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-UC-HF-NAN: "--sysroot=[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/el"
+// CHECK-EL-UC-HF-NAN: "-dynamic-linker" "/lib/ld-uClibc-mipsn8.so.0"
+// CHECK-EL-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-UC-HF-NAN: "[[TC]]/uclibc/nan2008/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-UC-HF-NAN: "-L[[TC]]/uclibc/nan2008/el"
+// CHECK-EL-UC-HF-NAN: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/uclibc/nan2008/el"
+// CHECK-EL-UC-HF-NAN-NOT: "-L[[TC]]"
+// CHECK-EL-UC-HF-NAN: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/el/lib/../lib"
+// CHECK-EL-UC-HF-NAN: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/../lib"
+// CHECK-EL-UC-HF-NAN: "[[TC]]/uclibc/nan2008/el{{/|\\\\}}crtend.o"
+// CHECK-EL-UC-HF-NAN: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/nan2008/el/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Little-endian, soft float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-gnu -mfloat-abi=soft \
@@ -405,6 +550,35 @@
// CHECK-EL-SF-32: "[[TC]]/soft-float/el{{/|\\\\}}crtend.o"
// CHECK-EL-SF-32: "[[TC]]/../../../../mips-linux-gnu/libc/soft-float/el/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Little-endian, soft float, uclibc
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mfloat-abi=soft -muclibc \
+// RUN: --gcc-toolchain=%S/Inputs/mips_cs_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-UC-SF-32 %s
+// CHECK-EL-UC-SF-32: "-internal-isystem"
+// CHECK-EL-UC-SF-32: "[[TC:[^"]+/lib/gcc/mips-linux-gnu/4.6.3]]/../../../../mips-linux-gnu/include/c++/4.6.3"
+// CHECK-EL-UC-SF-32: "-internal-isystem"
+// CHECK-EL-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/mips-linux-gnu/uclibc/soft-float/el"
+// CHECK-EL-UC-SF-32: "-internal-isystem"
+// CHECK-EL-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/include/c++/4.6.3/backward"
+// CHECK-EL-UC-SF-32: "-internal-externc-isystem"
+// CHECK-EL-UC-SF-32: "[[TC]]/include"
+// CHECK-EL-UC-SF-32: "-internal-externc-isystem"
+// CHECK-EL-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/usr/include"
+// CHECK-EL-UC-SF-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-UC-SF-32: "--sysroot=[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/el"
+// CHECK-EL-UC-SF-32: "-dynamic-linker" "/lib/ld-uClibc.so.0"
+// CHECK-EL-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-UC-SF-32: "[[TC]]/uclibc/soft-float/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-UC-SF-32: "-L[[TC]]/uclibc/soft-float/el"
+// CHECK-EL-UC-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/lib/../lib/uclibc/soft-float/el"
+// CHECK-EL-UC-SF-32-NOT: "-L[[TC]]"
+// CHECK-EL-UC-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/el/lib/../lib"
+// CHECK-EL-UC-SF-32: "-L[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/../lib"
+// CHECK-EL-UC-SF-32: "[[TC]]/uclibc/soft-float/el{{/|\\\\}}crtend.o"
+// CHECK-EL-UC-SF-32: "[[TC]]/../../../../mips-linux-gnu/libc/uclibc/soft-float/el/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Little-endian, soft float, mips16
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-gnu -mips16 -msoft-float \
diff --git a/test/Driver/mips-features.c b/test/Driver/mips-features.c
index 03cc0fd7e368..f7022306fc11 100644
--- a/test/Driver/mips-features.c
+++ b/test/Driver/mips-features.c
@@ -1,5 +1,15 @@
// Check handling MIPS specific features options.
//
+// -mabicalls
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mabicalls 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MABICALLS %s
+// CHECK-MABICALLS: "-target-feature" "-noabicalls"
+//
+// -mno-abicalls
+// RUN: %clang -target mips-linux-gnu -### -c %s -mabicalls -mno-abicalls 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MNOABICALLS %s
+// CHECK-MNOABICALLS: "-target-feature" "+noabicalls"
+//
// -mips16
// RUN: %clang -target mips-linux-gnu -### -c %s \
// RUN: -mno-mips16 -mips16 2>&1 \
diff --git a/test/Driver/mips-fsf.cpp b/test/Driver/mips-fsf.cpp
index 34ad91456e12..07b95c8fe9de 100644
--- a/test/Driver/mips-fsf.cpp
+++ b/test/Driver/mips-fsf.cpp
@@ -297,6 +297,33 @@
// CHECK-BE-HF-32R2: "[[TC]]{{/|\\\\}}crtend.o"
// CHECK-BE-HF-32R2: "[[TC]]/../../../../sysroot/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Big-endian, mips32r2, hard float, uclibc
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mhard-float -muclibc \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-UC-HF-32R2 %s
+// CHECK-BE-UC-HF-32R2: "-internal-isystem"
+// CHECK-BE-UC-HF-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-UC-HF-32R2: "-internal-isystem"
+// CHECK-BE-UC-HF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc"
+// CHECK-BE-UC-HF-32R2: "-internal-isystem"
+// CHECK-BE-UC-HF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-UC-HF-32R2: "-internal-externc-isystem"
+// CHECK-BE-UC-HF-32R2: "[[TC]]/include"
+// CHECK-BE-UC-HF-32R2: "-internal-externc-isystem"
+// CHECK-BE-UC-HF-32R2: "[[TC]]/../../../../sysroot/uclibc/usr/include"
+// CHECK-BE-UC-HF-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-UC-HF-32R2: "--sysroot=[[TC]]/../../../../sysroot/uclibc"
+// CHECK-BE-UC-HF-32R2: "-dynamic-linker" "/lib/ld-uClibc.so.0"
+// CHECK-BE-UC-HF-32R2: "[[TC]]/../../../../sysroot/uclibc/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-UC-HF-32R2: "[[TC]]/../../../../sysroot/uclibc/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-UC-HF-32R2: "[[TC]]/uclibc{{/|\\\\}}crtbegin.o"
+// CHECK-BE-UC-HF-32R2: "-L[[TC]]/uclibc"
+// CHECK-BE-UC-HF-32R2: "-L[[TC]]/../../../../mips-mti-linux-gnu/lib/../lib/uclibc"
+// CHECK-BE-UC-HF-32R2: "-L[[TC]]/../../../../sysroot/uclibc/usr/lib/../lib"
+// CHECK-BE-UC-HF-32R2: "[[TC]]/uclibc{{/|\\\\}}crtend.o"
+// CHECK-BE-UC-HF-32R2: "[[TC]]/../../../../sysroot/uclibc/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Big-endian, mips32r2, fp64, hard float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips-linux-gnu -mips32r2 -mfp64 -mhard-float \
@@ -351,6 +378,33 @@
// CHECK-BE-SF-32R2: "[[TC]]/sof{{/|\\\\}}crtend.o"
// CHECK-BE-SF-32R2: "[[TC]]/../../../../sysroot/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Big-endian, mips32r2, soft float, uclibc
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -msoft-float -muclibc \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-UC-SF-32R2 %s
+// CHECK-BE-UC-SF-32R2: "-internal-isystem"
+// CHECK-BE-UC-SF-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-UC-SF-32R2: "-internal-isystem"
+// CHECK-BE-UC-SF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/sof"
+// CHECK-BE-UC-SF-32R2: "-internal-isystem"
+// CHECK-BE-UC-SF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-UC-SF-32R2: "-internal-externc-isystem"
+// CHECK-BE-UC-SF-32R2: "[[TC]]/include"
+// CHECK-BE-UC-SF-32R2: "-internal-externc-isystem"
+// CHECK-BE-UC-SF-32R2: "[[TC]]/../../../../sysroot/uclibc/usr/include"
+// CHECK-BE-UC-SF-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-UC-SF-32R2: "--sysroot=[[TC]]/../../../../sysroot/uclibc/sof"
+// CHECK-BE-UC-SF-32R2: "-dynamic-linker" "/lib/ld-uClibc.so.0"
+// CHECK-BE-UC-SF-32R2: "[[TC]]/../../../../sysroot/uclibc/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-UC-SF-32R2: "[[TC]]/../../../../sysroot/uclibc/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-UC-SF-32R2: "[[TC]]/uclibc/sof{{/|\\\\}}crtbegin.o"
+// CHECK-BE-UC-SF-32R2: "-L[[TC]]/uclibc/sof"
+// CHECK-BE-UC-SF-32R2: "-L[[TC]]/../../../../mips-mti-linux-gnu/lib/../lib/uclibc/sof"
+// CHECK-BE-UC-SF-32R2: "-L[[TC]]/../../../../sysroot/uclibc/sof/usr/lib/../lib"
+// CHECK-BE-UC-SF-32R2: "[[TC]]/uclibc/sof{{/|\\\\}}crtend.o"
+// CHECK-BE-UC-SF-32R2: "[[TC]]/../../../../sysroot/uclibc/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Big-endian, mips32r2 / mips16, hard float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips-linux-gnu -mips32r2 -mips16 -mhard-float \
@@ -513,6 +567,33 @@
// CHECK-BE-NAN-32R2: "[[TC]]/nan2008{{/|\\\\}}crtend.o"
// CHECK-BE-NAN-32R2: "[[TC]]/../../../../sysroot/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Big-endian, mips32r2, nan2008, uclibc
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-linux-gnu -mips32r2 -mnan=2008 -muclibc \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-BE-UC-NAN-32R2 %s
+// CHECK-BE-UC-NAN-32R2: "-internal-isystem"
+// CHECK-BE-UC-NAN-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-BE-UC-NAN-32R2: "-internal-isystem"
+// CHECK-BE-UC-NAN-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/nan2008"
+// CHECK-BE-UC-NAN-32R2: "-internal-isystem"
+// CHECK-BE-UC-NAN-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-BE-UC-NAN-32R2: "-internal-externc-isystem"
+// CHECK-BE-UC-NAN-32R2: "[[TC]]/include"
+// CHECK-BE-UC-NAN-32R2: "-internal-externc-isystem"
+// CHECK-BE-UC-NAN-32R2: "[[TC]]/../../../../sysroot/uclibc/usr/include"
+// CHECK-BE-UC-NAN-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BE-UC-NAN-32R2: "--sysroot=[[TC]]/../../../../sysroot/uclibc/nan2008"
+// CHECK-BE-UC-NAN-32R2: "-dynamic-linker" "/lib/ld-uClibc-mipsn8.so.0"
+// CHECK-BE-UC-NAN-32R2: "[[TC]]/../../../../sysroot/uclibc/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-BE-UC-NAN-32R2: "[[TC]]/../../../../sysroot/uclibc/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-BE-UC-NAN-32R2: "[[TC]]/uclibc/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-BE-UC-NAN-32R2: "-L[[TC]]/uclibc/nan2008"
+// CHECK-BE-UC-NAN-32R2: "-L[[TC]]/../../../../mips-mti-linux-gnu/lib/../lib/uclibc/nan2008"
+// CHECK-BE-UC-NAN-32R2: "-L[[TC]]/../../../../sysroot/uclibc/nan2008/usr/lib/../lib"
+// CHECK-BE-UC-NAN-32R2: "[[TC]]/uclibc/nan2008{{/|\\\\}}crtend.o"
+// CHECK-BE-UC-NAN-32R2: "[[TC]]/../../../../sysroot/uclibc/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Big-endian, mips32r2, fp64, nan2008
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips-linux-gnu -mips32r2 -mfp64 -mnan=2008 \
@@ -1566,6 +1647,33 @@
// CHECK-EL-HF-32R2: "[[TC]]/el{{/|\\\\}}crtend.o"
// CHECK-EL-HF-32R2: "[[TC]]/../../../../sysroot/el/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Little-endian, mips32r2, hard float, uclibc
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mhard-float -muclibc \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-UC-HF-32R2 %s
+// CHECK-EL-UC-HF-32R2: "-internal-isystem"
+// CHECK-EL-UC-HF-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-UC-HF-32R2: "-internal-isystem"
+// CHECK-EL-UC-HF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el"
+// CHECK-EL-UC-HF-32R2: "-internal-isystem"
+// CHECK-EL-UC-HF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-UC-HF-32R2: "-internal-externc-isystem"
+// CHECK-EL-UC-HF-32R2: "[[TC]]/include"
+// CHECK-EL-UC-HF-32R2: "-internal-externc-isystem"
+// CHECK-EL-UC-HF-32R2: "[[TC]]/../../../../sysroot/uclibc/usr/include"
+// CHECK-EL-UC-HF-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-UC-HF-32R2: "--sysroot=[[TC]]/../../../../sysroot/uclibc/el"
+// CHECK-EL-UC-HF-32R2: "-dynamic-linker" "/lib/ld-uClibc.so.0"
+// CHECK-EL-UC-HF-32R2: "[[TC]]/../../../../sysroot/uclibc/el/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-UC-HF-32R2: "[[TC]]/../../../../sysroot/uclibc/el/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-UC-HF-32R2: "[[TC]]/uclibc/el{{/|\\\\}}crtbegin.o"
+// CHECK-EL-UC-HF-32R2: "-L[[TC]]/uclibc/el"
+// CHECK-EL-UC-HF-32R2: "-L[[TC]]/../../../../mips-mti-linux-gnu/lib/../lib/uclibc/el"
+// CHECK-EL-UC-HF-32R2: "-L[[TC]]/../../../../sysroot/uclibc/el/usr/lib/../lib"
+// CHECK-EL-UC-HF-32R2: "[[TC]]/uclibc/el{{/|\\\\}}crtend.o"
+// CHECK-EL-UC-HF-32R2: "[[TC]]/../../../../sysroot/uclibc/el/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Little-endian, mips32r2, fp64, hard float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-gnu -mips32r2 -mfp64 -mhard-float \
@@ -1620,6 +1728,33 @@
// CHECK-EL-SF-32R2: "[[TC]]/el/sof{{/|\\\\}}crtend.o"
// CHECK-EL-SF-32R2: "[[TC]]/../../../../sysroot/el/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Little-endian, mips32r2, soft float, uclibc
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -msoft-float -muclibc \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-UC-SF-32R2 %s
+// CHECK-EL-UC-SF-32R2: "-internal-isystem"
+// CHECK-EL-UC-SF-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-UC-SF-32R2: "-internal-isystem"
+// CHECK-EL-UC-SF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el/sof"
+// CHECK-EL-UC-SF-32R2: "-internal-isystem"
+// CHECK-EL-UC-SF-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-UC-SF-32R2: "-internal-externc-isystem"
+// CHECK-EL-UC-SF-32R2: "[[TC]]/include"
+// CHECK-EL-UC-SF-32R2: "-internal-externc-isystem"
+// CHECK-EL-UC-SF-32R2: "[[TC]]/../../../../sysroot/uclibc/usr/include"
+// CHECK-EL-UC-SF-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-UC-SF-32R2: "--sysroot=[[TC]]/../../../../sysroot/uclibc/el/sof"
+// CHECK-EL-UC-SF-32R2: "-dynamic-linker" "/lib/ld-uClibc.so.0"
+// CHECK-EL-UC-SF-32R2: "[[TC]]/../../../../sysroot/uclibc/el/sof/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-UC-SF-32R2: "[[TC]]/../../../../sysroot/uclibc/el/sof/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-UC-SF-32R2: "[[TC]]/uclibc/el/sof{{/|\\\\}}crtbegin.o"
+// CHECK-EL-UC-SF-32R2: "-L[[TC]]/uclibc/el/sof"
+// CHECK-EL-UC-SF-32R2: "-L[[TC]]/../../../../mips-mti-linux-gnu/lib/../lib/uclibc/el/sof"
+// CHECK-EL-UC-SF-32R2: "-L[[TC]]/../../../../sysroot/uclibc/el/sof/usr/lib/../lib"
+// CHECK-EL-UC-SF-32R2: "[[TC]]/uclibc/el/sof{{/|\\\\}}crtend.o"
+// CHECK-EL-UC-SF-32R2: "[[TC]]/../../../../sysroot/uclibc/el/sof/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Little-endian, mips32r2 / mips16, hard float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-gnu -mips32r2 -mips16 -mhard-float \
@@ -1782,6 +1917,33 @@
// CHECK-EL-NAN-32R2: "[[TC]]/el/nan2008{{/|\\\\}}crtend.o"
// CHECK-EL-NAN-32R2: "[[TC]]/../../../../sysroot/el/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
//
+// = Little-endian, mips32r2, nan2008, uclibc
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mipsel-linux-gnu -mips32r2 -mnan=2008 -muclibc \
+// RUN: --gcc-toolchain=%S/Inputs/mips_fsf_tree \
+// RUN: | FileCheck --check-prefix=CHECK-EL-UC-NAN-32R2 %s
+// CHECK-EL-UC-NAN-32R2: "-internal-isystem"
+// CHECK-EL-UC-NAN-32R2: "[[TC:[^"]+/lib/gcc/mips-mti-linux-gnu/4.9.0]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0"
+// CHECK-EL-UC-NAN-32R2: "-internal-isystem"
+// CHECK-EL-UC-NAN-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/mips-mti-linux-gnu/uclibc/el/nan2008"
+// CHECK-EL-UC-NAN-32R2: "-internal-isystem"
+// CHECK-EL-UC-NAN-32R2: "[[TC]]/../../../../mips-mti-linux-gnu/include/c++/4.9.0/backward"
+// CHECK-EL-UC-NAN-32R2: "-internal-externc-isystem"
+// CHECK-EL-UC-NAN-32R2: "[[TC]]/include"
+// CHECK-EL-UC-NAN-32R2: "-internal-externc-isystem"
+// CHECK-EL-UC-NAN-32R2: "[[TC]]/../../../../sysroot/uclibc/usr/include"
+// CHECK-EL-UC-NAN-32R2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-EL-UC-NAN-32R2: "--sysroot=[[TC]]/../../../../sysroot/uclibc/el/nan2008"
+// CHECK-EL-UC-NAN-32R2: "-dynamic-linker" "/lib/ld-uClibc-mipsn8.so.0"
+// CHECK-EL-UC-NAN-32R2: "[[TC]]/../../../../sysroot/uclibc/el/nan2008/usr/lib/../lib{{/|\\\\}}crt1.o"
+// CHECK-EL-UC-NAN-32R2: "[[TC]]/../../../../sysroot/uclibc/el/nan2008/usr/lib/../lib{{/|\\\\}}crti.o"
+// CHECK-EL-UC-NAN-32R2: "[[TC]]/uclibc/el/nan2008{{/|\\\\}}crtbegin.o"
+// CHECK-EL-UC-NAN-32R2: "-L[[TC]]/uclibc/el/nan2008"
+// CHECK-EL-UC-NAN-32R2: "-L[[TC]]/../../../../mips-mti-linux-gnu/lib/../lib/uclibc/el/nan2008"
+// CHECK-EL-UC-NAN-32R2: "-L[[TC]]/../../../../sysroot/uclibc/el/nan2008/usr/lib/../lib"
+// CHECK-EL-UC-NAN-32R2: "[[TC]]/uclibc/el/nan2008{{/|\\\\}}crtend.o"
+// CHECK-EL-UC-NAN-32R2: "[[TC]]/../../../../sysroot/uclibc/el/nan2008/usr/lib/../lib{{/|\\\\}}crtn.o"
+//
// = Little-endian, mips32r2, fp64, nan2008
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-gnu -mips32r2 -mfp64 -mnan=2008 \
diff --git a/test/Driver/mips-integrated-as.s b/test/Driver/mips-integrated-as.s
index c3b1db391e0f..b648650e4be9 100644
--- a/test/Driver/mips-integrated-as.s
+++ b/test/Driver/mips-integrated-as.s
@@ -205,3 +205,13 @@
// FPXX-ODDSPREG: -cc1as
// FPXX-ODDSPREG: "-target-feature" "+fpxx"
// FPXX-ODDSPREG: "-target-feature" "-nooddspreg"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -mabicalls 2>&1 | \
+// RUN: FileCheck -check-prefix=ABICALLS-ON %s
+// ABICALLS-ON: -cc1as
+// ABICALLS-ON: "-target-feature" "-noabicalls"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -mno-abicalls 2>&1 | \
+// RUN: FileCheck -check-prefix=ABICALLS-OFF %s
+// ABICALLS-OFF: -cc1as
+// ABICALLS-OFF: "-target-feature" "+noabicalls"
diff --git a/test/Driver/mips-reduced-toolchain.cpp b/test/Driver/mips-reduced-toolchain.cpp
index fe7ed8ae045d..894bdb5a756b 100644
--- a/test/Driver/mips-reduced-toolchain.cpp
+++ b/test/Driver/mips-reduced-toolchain.cpp
@@ -4,6 +4,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_reduced_mips_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPS %s
// CHECK-DEBIAN-MIPS: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
// CHECK-DEBIAN-MIPS: "{{.*}}/usr/lib/gcc/mips-linux-gnu/4.7{{/|\\\\}}crtbegin.o"
@@ -17,6 +18,7 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_reduced_mips_tree \
+// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-MIPSEL %s
// CHECK-DEBIAN-MIPSEL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
// CHECK-DEBIAN-MIPSEL: "{{.*}}/usr/lib/gcc/mipsel-linux-gnu/4.7{{/|\\\\}}crtbegin.o"
diff --git a/test/Driver/modules.m b/test/Driver/modules.m
index d8e20e4148e9..8a0c8ba4d88f 100644
--- a/test/Driver/modules.m
+++ b/test/Driver/modules.m
@@ -4,18 +4,36 @@
// RUN: %clang -fmodules -fno-modules -fmodules -### %s 2>&1 | FileCheck -check-prefix=CHECK-HAS-MODULES %s
// CHECK-HAS-MODULES: -fmodules
-// RUN: %clang -fbuild-session-timestamp=123 -### %s 2>&1 | FileCheck -check-prefix=TIMESTAMP_ONLY %s
-// TIMESTAMP_ONLY: -fbuild-session-timestamp=123
+// RUN: %clang -fbuild-session-file=doesntexist -### %s 2>&1 | FileCheck -check-prefix=NOFILE %s
+// NOFILE: no such file or directory: 'doesntexist'
+
+// RUN: touch -m -a -t 201008011501 %t.build-session-file
+// RUN: %clang -fbuild-session-file=%t.build-session-file -### %s 2>&1 | FileCheck -check-prefix=TIMESTAMP_ONLY %s
+
+// RUN: %clang -fbuild-session-timestamp=1280703457 -### %s 2>&1 | FileCheck -check-prefix=TIMESTAMP_ONLY %s
+// TIMESTAMP_ONLY: -fbuild-session-timestamp=128
+
+// RUN: %clang -fbuild-session-file=%t.build-session-file -fbuild-session-timestamp=123 -### %s 2>&1 | FileCheck -check-prefix=CONFLICT %s
+// CONFLICT: error: invalid argument '-fbuild-session-file={{.*}}.build-session-file' not allowed with '-fbuild-session-timestamp'
// RUN: %clang -fbuild-session-timestamp=123 -fmodules-validate-once-per-build-session -### %s 2>&1 | FileCheck -check-prefix=MODULES_VALIDATE_ONCE %s
// MODULES_VALIDATE_ONCE: -fbuild-session-timestamp=123
// MODULES_VALIDATE_ONCE: -fmodules-validate-once-per-build-session
+// RUN: %clang -fbuild-session-file=%t.build-session-file -fmodules-validate-once-per-build-session -### %s 2>&1 | FileCheck -check-prefix=MODULES_VALIDATE_ONCE_FILE %s
+// MODULES_VALIDATE_ONCE_FILE: -fbuild-session-timestamp=128
+// MODULES_VALIDATE_ONCE_FILE: -fmodules-validate-once-per-build-session
+
// RUN: %clang -fmodules-validate-once-per-build-session -### %s 2>&1 | FileCheck -check-prefix=MODULES_VALIDATE_ONCE_ERR %s
-// MODULES_VALIDATE_ONCE_ERR: option '-fmodules-validate-once-per-build-session' requires '-fbuild-session-timestamp=<seconds since Epoch>'
+// MODULES_VALIDATE_ONCE_ERR: option '-fmodules-validate-once-per-build-session' requires '-fbuild-session-timestamp=<seconds since Epoch>' or '-fbuild-session-file=<file>'
// RUN: %clang -### %s 2>&1 | FileCheck -check-prefix=MODULES_VALIDATE_SYSTEM_HEADERS_DEFAULT %s
// MODULES_VALIDATE_SYSTEM_HEADERS_DEFAULT-NOT: -fmodules-validate-system-headers
// RUN: %clang -fmodules-validate-system-headers -### %s 2>&1 | FileCheck -check-prefix=MODULES_VALIDATE_SYSTEM_HEADERS %s
// MODULES_VALIDATE_SYSTEM_HEADERS: -fmodules-validate-system-headers
+
+// RUN: %clang -fmodules -fmodule-map-file=foo.map -fmodule-map-file=bar.map -### %s 2>&1 | FileCheck -check-prefix=CHECK-MODULE-MAP-FILES %s
+// CHECK-MODULE-MAP-FILES: "-fmodules"
+// CHECK-MODULE-MAP-FILES: "-fmodule-map-file=foo.map"
+// CHECK-MODULE-MAP-FILES: "-fmodule-map-file=bar.map"
diff --git a/test/Driver/modules.mm b/test/Driver/modules.mm
index b2948c4b3d96..63db69956e45 100644
--- a/test/Driver/modules.mm
+++ b/test/Driver/modules.mm
@@ -1,6 +1,8 @@
-// RUN: %clang -fmodules -### %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MODULES %s
+// RUN: %clang -### %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MODULES %s
// RUN: %clang -fcxx-modules -### %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MODULES %s
+// RUN: %clang -fmodules -fno-cxx-modules -### %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MODULES %s
// CHECK-NO-MODULES-NOT: -fmodules
-// RUN: %clang -fcxx-modules -fmodules -### %s 2>&1 | FileCheck -check-prefix=CHECK-HAS-MODULES %s
+// RUN: %clang -fmodules -### %s 2>&1 | FileCheck -check-prefix=CHECK-HAS-MODULES %s
+// RUN: %clang -fmodules -fno-cxx-modules -fcxx-modules -### %s 2>&1 | FileCheck -check-prefix=CHECK-HAS-MODULES %s
// CHECK-HAS-MODULES: -fmodules
diff --git a/test/Driver/msvc_forward.c b/test/Driver/msvc_forward.c
index fe0ae84790e0..15f941ef95de 100644
--- a/test/Driver/msvc_forward.c
+++ b/test/Driver/msvc_forward.c
@@ -1,5 +1,7 @@
-// RUN: %clang -target i686-pc-win32 -lkernel32.lib -luser32.lib -### %s 2>&1 | FileCheck %s
+// RUN: %clang -target i686-pc-win32 -loldnames -lkernel32.lib -luser32.lib -### %s 2>&1 | FileCheck %s
+// CHECK-NOT: "-loldnames.lib"
// CHECK-NOT: "-lkernel32.lib"
// CHECK-NOT: "-luser32.lib"
+// CHECK: "oldnames.lib"
// CHECK: "kernel32.lib"
// CHECK: "user32.lib"
diff --git a/test/Driver/netbsd.c b/test/Driver/netbsd.c
index 0e3ebf3c9a28..eded7f52df7e 100644
--- a/test/Driver/netbsd.c
+++ b/test/Driver/netbsd.c
@@ -13,36 +13,42 @@
// RUN: %clang -no-canonical-prefixes -target aarch64--netbsd7.0.0 \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=AARCH64-7 %s
-// RUN: %clang -no-canonical-prefixes -target arm64--netbsd \
-// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM64 %s
-// RUN: %clang -no-canonical-prefixes -target arm64--netbsd7.0.0 \
-// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM64-7 %s
// RUN: %clang -no-canonical-prefixes -target arm--netbsd-eabi \
// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=ARM %s
+// RUN: %clang -no-canonical-prefixes -target armeb--netbsd-eabi \
+// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=ARMEB %s
// RUN: %clang -no-canonical-prefixes -target arm--netbsd \
// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=ARM-APCS %s
+// RUN: %clang -no-canonical-prefixes -target arm--netbsd-eabihf \
+// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM-HF %s
// RUN: %clang -no-canonical-prefixes -target thumb--netbsd-eabi \
// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=THUMB %s
+// RUN: %clang -no-canonical-prefixes -target thumbeb--netbsd-eabi \
+// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=THUMBEB %s
// RUN: %clang -no-canonical-prefixes -target arm--netbsd7.0.0-eabi \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=ARM-7 %s
// RUN: %clang -no-canonical-prefixes -target arm--netbsd6.0.0-eabi \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=ARM-6 %s
-// RUN: %clang -no-canonical-prefixes -target arm--netbsd-eabihf \
-// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM-HF %s
// RUN: %clang -no-canonical-prefixes -target sparc--netbsd \
// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=SPARC %s
// RUN: %clang -no-canonical-prefixes -target sparc64--netbsd \
// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=SPARC64 %s
+// RUN: %clang -no-canonical-prefixes -target powerpc--netbsd \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=POWERPC %s
+// RUN: %clang -no-canonical-prefixes -target powerpc64--netbsd \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=POWERPC64 %s
// RUN: %clang -no-canonical-prefixes -target x86_64--netbsd -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
@@ -59,15 +65,12 @@
// RUN: %clang -no-canonical-prefixes -target aarch64--netbsd7.0.0 -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-AARCH64-7 %s
-// RUN: %clang -no-canonical-prefixes -target arm64--netbsd -static \
-// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=S-ARM64 %s
-// RUN: %clang -no-canonical-prefixes -target arm64--netbsd7.0.0 -static \
-// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=S-ARM64-7 %s
// RUN: %clang -no-canonical-prefixes -target arm--netbsd-eabi -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-ARM %s
+// RUN: %clang -no-canonical-prefixes -target armeb--netbsd-eabi -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-ARMEB %s
// RUN: %clang -no-canonical-prefixes -target arm--netbsd7.0.0-eabi -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-ARM-7 %s
@@ -80,6 +83,12 @@
// RUN: %clang -no-canonical-prefixes -target sparc64--netbsd -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-SPARC64 %s
+// RUN: %clang -no-canonical-prefixes -target powerpc--netbsd -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-POWERPC %s
+// RUN: %clang -no-canonical-prefixes -target powerpc64--netbsd -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-POWERPC64 %s
// X86_64: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd"
// X86_64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
@@ -103,30 +112,14 @@
// AARCH64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// AARCH64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
// AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
-// AARCH64: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
// AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
// AARCH64-7: clang{{.*}}" "-cc1" "-triple" "aarch64--netbsd7.0.0"
// AARCH64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// AARCH64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
// AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
-// AARCH64-7: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
// AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-// ARM64: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd"
-// ARM64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
-// ARM64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
-// ARM64: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
-// ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-
-// ARM64-7: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd7.0.0"
-// ARM64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
-// ARM64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
-// ARM64-7: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
-// ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-
// ARM: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd-eabi"
// ARM: as{{.*}}" "-mcpu=arm926ej-s" "-o"
// ARM: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
@@ -136,6 +129,15 @@
// ARM: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// ARM: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// ARMEB: clang{{.*}}" "-cc1" "-triple" "armebv5e--netbsd-eabi"
+// ARMEB: as{{.*}}" "-mcpu=arm926ej-s" "-o"
+// ARMEB: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// ARMEB: "-m" "armelfb_nbsd_eabi"
+// ARMEB: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// ARMEB: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o"
+// ARMEB: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// ARMEB: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// ARM-APCS: clang{{.*}}" "-cc1" "-triple" "armv4--netbsd"
// ARM-APCS: as{{.*}}" "-mcpu=strongarm" "-o"
// ARM-APCS: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
@@ -145,6 +147,15 @@
// ARM-APCS: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// ARM-APCS: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// ARM-HF: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd-eabihf"
+// ARM-HF: as{{.*}}" "-mcpu=arm926ej-s" "-o"
+// ARM-HF: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// ARM-HF: "-m" "armelf_nbsd_eabihf"
+// ARM-HF: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// ARM-HF: "{{.*}}/usr/lib{{/|\\\\}}eabihf{{/|\\\\}}crti.o"
+// ARM-HF: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// ARM-HF: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// THUMB: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd-eabi"
// THUMB: as{{.*}}" "-mcpu=arm926ej-s" "-o"
// THUMB: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
@@ -154,6 +165,15 @@
// THUMB: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// THUMB: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// THUMBEB: clang{{.*}}" "-cc1" "-triple" "armebv5e--netbsd-eabi"
+// THUMBEB: as{{.*}}" "-mcpu=arm926ej-s" "-o"
+// THUMBEB: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// THUMBEB: "-m" "armelfb_nbsd_eabi"
+// THUMBEB: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// THUMBEB: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o"
+// THUMBEB: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// THUMBEB: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// ARM-7: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd7.0.0-eabi"
// ARM-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// ARM-7: "-m" "armelf_nbsd_eabi"
@@ -170,9 +190,6 @@
// ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-// ARM-HF: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd-eabihf"
-// ARM-HF: ld{{.*}}" "-m" "armelf_nbsd_eabihf"
-
// SPARC: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd"
// SPARC: as{{.*}}" "-32" "-o"
// SPARC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
@@ -190,6 +207,22 @@
// SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// POWERPC: clang{{.*}}" "-cc1" "-triple" "powerpc--netbsd"
+// POWERPC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// POWERPC: "-m" "elf32ppc_nbsd"
+// POWERPC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// POWERPC: "{{.*}}/usr/lib{{/|\\\\}}powerpc{{/|\\\\}}crti.o"
+// POWERPC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// POWERPC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// POWERPC64: clang{{.*}}" "-cc1" "-triple" "powerpc64--netbsd"
+// POWERPC64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// POWERPC64: "-m" "elf64ppc"
+// POWERPC64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// S-X86_64: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd"
// S-X86_64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-X86_64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
@@ -213,30 +246,14 @@
// S-AARCH64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-AARCH64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
// S-AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
-// S-AARCH64: "-lgcc_eh" "-lc" "-lgcc"
// S-AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
// S-AARCH64-7: clang{{.*}}" "-cc1" "-triple" "aarch64--netbsd7.0.0"
// S-AARCH64-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-AARCH64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
// S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
-// S-AARCH64-7: "-lgcc_eh" "-lc" "-lgcc"
// S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-// S-ARM64: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd"
-// S-ARM64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
-// S-ARM64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// S-ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
-// S-ARM64: "-lgcc_eh" "-lc" "-lgcc"
-// S-ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-
-// S-ARM64-7: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd7.0.0"
-// S-ARM64-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
-// S-ARM64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// S-ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
-// S-ARM64-7: "-lgcc_eh" "-lc" "-lgcc"
-// S-ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-
// S-ARM: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd-eabi"
// S-ARM: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-ARM: "-m" "armelf_nbsd_eabi"
@@ -245,6 +262,14 @@
// S-ARM: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// S-ARM: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// S-ARMEB: clang{{.*}}" "-cc1" "-triple" "armebv5e--netbsd-eabi"
+// S-ARMEB: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-ARMEB: "-m" "armelfb_nbsd_eabi"
+// S-ARMEB: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-ARMEB: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o"
+// S-ARMEB: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-ARMEB: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// S-ARM-7: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd7.0.0-eabi"
// S-ARM-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-ARM-7: "-m" "armelf_nbsd_eabi"
@@ -278,3 +303,19 @@
// S-SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// S-SPARC64: "-lgcc_eh" "-lc" "-lgcc"
// S-SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-POWERPC: clang{{.*}}" "-cc1" "-triple" "powerpc--netbsd"
+// S-POWERPC: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-POWERPC: "-m" "elf32ppc_nbsd"
+// S-POWERPC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-POWERPC: "{{.*}}/usr/lib{{/|\\\\}}powerpc{{/|\\\\}}crti.o"
+// S-POWERPC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-POWERPC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-POWERPC64: clang{{.*}}" "-cc1" "-triple" "powerpc64--netbsd"
+// S-POWERPC64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-POWERPC64: "-m" "elf64ppc"
+// S-POWERPC64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
diff --git a/test/Driver/netbsd.cpp b/test/Driver/netbsd.cpp
index 43b9fdeaa587..e386a212de2c 100644
--- a/test/Driver/netbsd.cpp
+++ b/test/Driver/netbsd.cpp
@@ -19,18 +19,18 @@
// RUN: %clangxx -no-canonical-prefixes -target aarch64--netbsd7.0.0 \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=AARCH64-7 %s
-// RUN: %clangxx -no-canonical-prefixes -target arm64--netbsd \
-// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM64 %s
-// RUN: %clangxx -no-canonical-prefixes -target arm64--netbsd7.0.0 \
-// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=ARM64-7 %s
// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=SPARC %s
// RUN: %clangxx -no-canonical-prefixes -target sparc64--netbsd \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=SPARC64 %s
+// RUN: %clangxx -no-canonical-prefixes -target powerpc--netbsd \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=POWERPC %s
+// RUN: %clangxx -no-canonical-prefixes -target powerpc64--netbsd \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=POWERPC64 %s
// RUN: %clangxx -no-canonical-prefixes -target x86_64--netbsd -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
@@ -53,18 +53,18 @@
// RUN: %clangxx -no-canonical-prefixes -target aarch64--netbsd7.0.0 -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-AARCH64-7 %s
-// RUN: %clangxx -no-canonical-prefixes -target arm64--netbsd -static \
-// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=S-ARM64 %s
-// RUN: %clangxx -no-canonical-prefixes -target arm64--netbsd7.0.0 -static \
-// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=S-ARM64-7 %s
// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-SPARC %s
// RUN: %clangxx -no-canonical-prefixes -target sparc64--netbsd -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-SPARC64 %s
+// RUN: %clangxx -no-canonical-prefixes -target powerpc--netbsd -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-POWERPC %s
+// RUN: %clangxx -no-canonical-prefixes -target powerpc64--netbsd -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-POWERPC64 %s
// X86_64: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd"
// X86_64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
@@ -101,31 +101,17 @@
// AARCH64: clang{{.*}}" "-cc1" "-triple" "aarch64--netbsd"
// AARCH64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// AARCH64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// AARCH64: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// AARCH64: "-lm" "-lc"
// AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
// AARCH64-7: clang{{.*}}" "-cc1" "-triple" "aarch64--netbsd7.0.0"
// AARCH64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// AARCH64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// AARCH64-7: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// AARCH64-7: "-lm" "-lc"
// AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-// ARM64: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd"
-// ARM64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
-// ARM64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// ARM64: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
-// ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-
-// ARM64-7: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd7.0.0"
-// ARM64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
-// ARM64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// ARM64-7: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
-// ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-
// SPARC: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd"
// SPARC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
@@ -141,6 +127,20 @@
// SPARC64: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
// SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// POWERPC: clang{{.*}}" "-cc1" "-triple" "powerpc--netbsd"
+// POWERPC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// POWERPC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// POWERPC: "{{.*}}/usr/lib{{/|\\\\}}powerpc{{/|\\\\}}crti.o"
+// POWERPC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// POWERPC: "-lm" "-lc" "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// POWERPC64: clang{{.*}}" "-cc1" "-triple" "powerpc64--netbsd"
+// POWERPC64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// POWERPC64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// POWERPC64: "-lm" "-lc" "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// S-X86_64: clang{{.*}}" "-cc1" "-triple" "x86_64--netbsd"
// S-X86_64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-X86_64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
@@ -176,31 +176,17 @@
// S-AARCH64: clang{{.*}}" "-cc1" "-triple" "aarch64--netbsd"
// S-AARCH64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-AARCH64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// S-AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// S-AARCH64: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
+// S-AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-AARCH64: "-lm" "-lc"
// S-AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
// S-AARCH64-7: clang{{.*}}" "-cc1" "-triple" "aarch64--netbsd7.0.0"
// S-AARCH64-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-AARCH64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// S-AARCH64-7: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
+// S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-AARCH64-7: "-lm" "-lc"
// S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-// S-ARM64: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd"
-// S-ARM64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
-// S-ARM64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// S-ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// S-ARM64: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
-// S-ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-
-// S-ARM64-7: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd7.0.0"
-// S-ARM64-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
-// S-ARM64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// S-ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// S-ARM64-7: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
-// S-ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-
// S-SPARC: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd"
// S-SPARC: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
@@ -215,3 +201,17 @@
// S-SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
// S-SPARC64: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
// S-SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-POWERPC: clang{{.*}}" "-cc1" "-triple" "powerpc--netbsd"
+// S-POWERPC: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-POWERPC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-POWERPC: "{{.*}}/usr/lib{{/|\\\\}}powerpc{{/|\\\\}}crti.o"
+// S-POWERPC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-POWERPC: "-lm" "-lc" "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-POWERPC64: clang{{.*}}" "-cc1" "-triple" "powerpc64--netbsd"
+// S-POWERPC64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-POWERPC64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-POWERPC64: "-lm" "-lc" "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
diff --git a/test/Driver/no-canonical-prefixes.c b/test/Driver/no-canonical-prefixes.c
new file mode 100644
index 000000000000..1aef9f40a9a7
--- /dev/null
+++ b/test/Driver/no-canonical-prefixes.c
@@ -0,0 +1,10 @@
+// REQUIRES: shell
+// RUN: mkdir -p %t
+// RUN: cd %t
+// RUN: ln -sf %clang test-clang
+// RUN: ./test-clang -v -S %s 2>&1 | FileCheck %s
+// RUN: ./test-clang -v -S %s -no-canonical-prefixes 2>&1 | FileCheck --check-prefix=NCP %s
+
+
+// CHECK: /clang{{.*}}" -cc1
+// NCP: test-clang" -cc1
diff --git a/test/Driver/openbsd.c b/test/Driver/openbsd.c
index d263f485bf2f..74fef5092a96 100644
--- a/test/Driver/openbsd.c
+++ b/test/Driver/openbsd.c
@@ -8,6 +8,14 @@
// CHECK-PG: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
// CHECK-PG: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}gcrt0.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "-lpthread_p" "-lc_p" "-lgcc" "{{.*}}crtend.o"
+// Check CPU type for MIPS64
+// RUN: %clang -target mips64-unknown-openbsd -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-MIPS64-CPU %s
+// RUN: %clang -target mips64el-unknown-openbsd -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-MIPS64EL-CPU %s
+// CHECK-MIPS64-CPU: "-target-cpu" "mips3"
+// CHECK-MIPS64EL-CPU: "-target-cpu" "mips3"
+
// Check that the new linker flags are passed to OpenBSD
// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -r %s -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-LD-R %s
@@ -59,12 +67,3 @@
// CHECK-MIPS64-PIC: as{{.*}}" "-mabi" "64" "-EB" "-KPIC"
// CHECK-MIPS64EL: as{{.*}}" "-mabi" "64" "-EL"
// CHECK-MIPS64EL-PIC: as{{.*}}" "-mabi" "64" "-EL" "-KPIC"
-
-// Check that the integrated assembler is enabled for PowerPC and SPARC
-// RUN: %clang -target powerpc-unknown-openbsd -### -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK-IAS %s
-// RUN: %clang -target sparc-unknown-openbsd -### -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK-IAS %s
-// RUN: %clang -target sparc64-unknown-openbsd -### -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK-IAS %s
-// CHECK-IAS-NOT: "-no-integrated-as"
diff --git a/test/Driver/parse-progname.c b/test/Driver/parse-progname.c
new file mode 100644
index 000000000000..33c637822348
--- /dev/null
+++ b/test/Driver/parse-progname.c
@@ -0,0 +1,58 @@
+// REQUIRES: shell, arm-registered-target
+
+
+
+// RUN: ln -fs %clang %T/clang++
+// RUN: ln -fs %clang %T/clang++3.5.0
+// RUN: ln -fs %clang %T/clang++-3.5
+// RUN: ln -fs %clang %T/clang++-tot
+// RUN: ln -fs %clang %T/clang-c++
+// RUN: ln -fs %clang %T/clang-g++
+// RUN: ln -fs %clang %T/c++
+// RUN: ln -fs %clang %T/foo-clang++
+// RUN: ln -fs %clang %T/foo-clang++-3.5
+// RUN: ln -fs %clang %T/foo-clang++3.5
+// RUN: %T/clang++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %T/clang++3.5.0 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %T/clang++-3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %T/clang++-tot -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %T/clang-c++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %T/clang-g++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %T/c++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %T/foo-clang++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %T/foo-clang++-3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %T/foo-clang++3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// CXXMODE: "-x" "c++"
+
+
+// RUN: ln -fs %clang %T/clang-cl
+// RUN: ln -fs %clang %T/cl
+// RUN: ln -fs %clang %T/cl.exe
+// RUN: ln -fs %clang %T/clang-cl3.5
+// RUN: ln -fs %clang %T/clang-cl-3.5
+// Note: use -- in front of the filename so it's not mistaken for an option on
+// filesystems that use slashes for dir separators.
+// RUN: %T/clang-cl -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
+// RUN: %T/cl -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
+// RUN: %T/cl.exe -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
+// RUN: %T/clang-cl3.5 -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
+// RUN: %T/clang-cl-3.5 -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
+// CLMODE: "-fdiagnostics-format" "msvc"
+
+
+// RUN: ln -fs %clang %T/clang-cpp
+// RUN: ln -fs %clang %T/cpp
+// RUN: %T/clang-cpp -### %s 2>&1 | FileCheck -check-prefix=CPPMODE %s
+// RUN: %T/cpp -### %s 2>&1 | FileCheck -check-prefix=CPPMODE %s
+// CPPMODE: "-E"
+
+
+// RUN: ln -fs %clang %T/cl-clang
+// RUN: %T/cl-clang -### %s 2>&1 | FileCheck -check-prefix=CMODE %s
+// CMODE: "-x" "c"
+// CMODE-NOT: "-fdiagnostics-format" "msvc"
+
+
+// RUN: ln -fs %clang %T/arm-linux-gnueabi-clang
+// RUN: %T/arm-linux-gnueabi-clang -### %s 2>&1 | FileCheck -check-prefix=TARGET %s
+// TARGET: Target: arm--linux-gnueabi
diff --git a/test/Driver/phases.c b/test/Driver/phases.c
index 4c480d59c14a..0283800825ac 100644
--- a/test/Driver/phases.c
+++ b/test/Driver/phases.c
@@ -2,47 +2,53 @@
// RUN: %clang -target i386-unknown-unknown -ccc-print-phases -x c %s -x objective-c %s -x c++ %s -x objective-c++ -x assembler %s -x assembler-with-cpp %s -x none %s 2>&1 | FileCheck -check-prefix=BASIC %s
// BASIC: 0: input, "{{.*}}phases.c", c
// BASIC: 1: preprocessor, {0}, cpp-output
-// BASIC: 2: compiler, {1}, assembler
-// BASIC: 3: assembler, {2}, object
-// BASIC: 4: input, "{{.*}}phases.c", objective-c
-// BASIC: 5: preprocessor, {4}, objective-c-cpp-output
-// BASIC: 6: compiler, {5}, assembler
-// BASIC: 7: assembler, {6}, object
-// BASIC: 8: input, "{{.*}}phases.c", c++
-// BASIC: 9: preprocessor, {8}, c++-cpp-output
-// BASIC: 10: compiler, {9}, assembler
-// BASIC: 11: assembler, {10}, object
-// BASIC: 12: input, "{{.*}}phases.c", assembler
-// BASIC: 13: assembler, {12}, object
-// BASIC: 14: input, "{{.*}}phases.c", assembler-with-cpp
-// BASIC: 15: preprocessor, {14}, assembler
+// BASIC: 2: compiler, {1}, ir
+// BASIC: 3: backend, {2}, assembler
+// BASIC: 4: assembler, {3}, object
+// BASIC: 5: input, "{{.*}}phases.c", objective-c
+// BASIC: 6: preprocessor, {5}, objective-c-cpp-output
+// BASIC: 7: compiler, {6}, ir
+// BASIC: 8: backend, {7}, assembler
+// BASIC: 9: assembler, {8}, object
+// BASIC: 10: input, "{{.*}}phases.c", c++
+// BASIC: 11: preprocessor, {10}, c++-cpp-output
+// BASIC: 12: compiler, {11}, ir
+// BASIC: 13: backend, {12}, assembler
+// BASIC: 14: assembler, {13}, object
+// BASIC: 15: input, "{{.*}}phases.c", assembler
// BASIC: 16: assembler, {15}, object
-// BASIC: 17: input, "{{.*}}phases.c", c
-// BASIC: 18: preprocessor, {17}, cpp-output
-// BASIC: 19: compiler, {18}, assembler
-// BASIC: 20: assembler, {19}, object
-// BASIC: 21: linker, {3, 7, 11, 13, 16, 20}, image
+// BASIC: 17: input, "{{.*}}phases.c", assembler-with-cpp
+// BASIC: 18: preprocessor, {17}, assembler
+// BASIC: 19: assembler, {18}, object
+// BASIC: 20: input, "{{.*}}phases.c", c
+// BASIC: 21: preprocessor, {20}, cpp-output
+// BASIC: 22: compiler, {21}, ir
+// BASIC: 23: backend, {22}, assembler
+// BASIC: 24: assembler, {23}, object
+// BASIC: 25: linker, {4, 9, 14, 16, 19, 24}, image
// Universal linked image.
// RUN: %clang -target i386-apple-darwin9 -ccc-print-phases -x c %s -arch ppc -arch i386 2>&1 | FileCheck -check-prefix=ULI %s
// ULI: 0: input, "{{.*}}phases.c", c
// ULI: 1: preprocessor, {0}, cpp-output
-// ULI: 2: compiler, {1}, assembler
-// ULI: 3: assembler, {2}, object
-// ULI: 4: linker, {3}, image
-// ULI: 5: bind-arch, "ppc", {4}, image
-// ULI: 6: bind-arch, "i386", {4}, image
-// ULI: 7: lipo, {5, 6}, image
+// ULI: 2: compiler, {1}, ir
+// ULI: 3: backend, {2}, assembler
+// ULI: 4: assembler, {3}, object
+// ULI: 5: linker, {4}, image
+// ULI: 6: bind-arch, "ppc", {5}, image
+// ULI: 7: bind-arch, "i386", {5}, image
+// ULI: 8: lipo, {6, 7}, image
// Universal object file.
// RUN: %clang -target i386-apple-darwin9 -ccc-print-phases -c -x c %s -arch ppc -arch i386 2>&1 | FileCheck -check-prefix=UOF %s
// UOF: 0: input, "{{.*}}phases.c", c
// UOF: 1: preprocessor, {0}, cpp-output
-// UOF: 2: compiler, {1}, assembler
-// UOF: 3: assembler, {2}, object
-// UOF: 4: bind-arch, "ppc", {3}, object
-// UOF: 5: bind-arch, "i386", {3}, object
-// UOF: 6: lipo, {4, 5}, object
+// UOF: 2: compiler, {1}, ir
+// UOF: 3: backend, {2}, assembler
+// UOF: 4: assembler, {3}, object
+// UOF: 5: bind-arch, "ppc", {4}, object
+// UOF: 6: bind-arch, "i386", {4}, object
+// UOF: 7: lipo, {5, 6}, object
// Arch defaulting
// RUN: %clang -target i386-apple-darwin9 -ccc-print-phases -c -x assembler %s 2>&1 | FileCheck -check-prefix=ARCH1 %s
diff --git a/test/Driver/pic.c b/test/Driver/pic.c
index 3629cc473574..a3d989c8b4f4 100644
--- a/test/Driver/pic.c
+++ b/test/Driver/pic.c
@@ -118,12 +118,15 @@
// Make sure -pie is passed to along to ld and that the right *crt* files
// are linked in.
// RUN: %clang %s -target i386-unknown-freebsd -fPIE -pie -### \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_freebsd_tree 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIE-LD
// RUN: %clang %s -target i386-linux-gnu -fPIE -pie -### \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIE-LD
// RUN: %clang %s -target i386-linux-gnu -fPIC -pie -### \
+// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIE-LD
//
@@ -195,6 +198,8 @@
// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
// RUN: %clang -c %s -target armv7-apple-ios -mkernel -miphoneos-version-min=6.0.0 -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target arm64-apple-ios -mkernel -miphoneos-version-min=7.0.0 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
// RUN: %clang -c %s -target armv7-apple-ios -fapple-kext -miphoneos-version-min=5.0.0 -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
// RUN: %clang -c %s -target armv7-apple-ios -fapple-kext -miphoneos-version-min=6.0.0 -static -### 2>&1 \
diff --git a/test/Driver/ppc-abi.c b/test/Driver/ppc-abi.c
new file mode 100644
index 000000000000..6fee63a303cf
--- /dev/null
+++ b/test/Driver/ppc-abi.c
@@ -0,0 +1,19 @@
+// Check passing PowerPC ABI options to the backend.
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-ELFv1 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN: -mabi=elfv1 | FileCheck -check-prefix=CHECK-ELFv1 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN: -mabi=elfv2 | FileCheck -check-prefix=CHECK-ELFv2 %s
+
+// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-ELFv2 %s
+// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN: -mabi=elfv1 | FileCheck -check-prefix=CHECK-ELFv1 %s
+// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN: -mabi=elfv2 | FileCheck -check-prefix=CHECK-ELFv2 %s
+
+// CHECK-ELFv1: "-target-abi" "elfv1"
+// CHECK-ELFv2: "-target-abi" "elfv2"
+
diff --git a/test/Driver/ppc-features.cpp b/test/Driver/ppc-features.cpp
index fa9a7ecd4d2f..f7cc879f39ac 100644
--- a/test/Driver/ppc-features.cpp
+++ b/test/Driver/ppc-features.cpp
@@ -89,12 +89,24 @@
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-fprnd -mfprnd -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-FPRND %s
// CHECK-FPRND: "-target-feature" "+fprnd"
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-cmpb -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOCMPB %s
+// CHECK-NOCMPB: "-target-feature" "-cmpb"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-cmpb -mcmpb -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-CMPB %s
+// CHECK-CMPB: "-target-feature" "+cmpb"
+
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-vsx -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOVSX %s
// CHECK-NOVSX: "-target-feature" "-vsx"
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-vsx -mvsx -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-VSX %s
// CHECK-VSX: "-target-feature" "+vsx"
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-power8-vector -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOP8VECTOR %s
+// CHECK-NOP8VECTOR: "-target-feature" "-power8-vector"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-power8-vector -mpower8-vector -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-P8VECTOR %s
+// CHECK-P8VECTOR: "-target-feature" "+power8-vector"
+
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-crbits -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOCRBITS %s
// CHECK-NOCRBITS: "-target-feature" "-crbits"
@@ -102,11 +114,11 @@
// CHECK-CRBITS: "-target-feature" "+crbits"
// Assembler features
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK_BE_AS_ARGS %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -### -o %t.o -no-integrated-as 2>&1 | FileCheck -check-prefix=CHECK_BE_AS_ARGS %s
// CHECK_BE_AS_ARGS: "-mppc64"
// CHECK_BE_AS_ARGS: "-many"
-// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK_LE_AS_ARGS %s
+// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o -no-integrated-as 2>&1 | FileCheck -check-prefix=CHECK_LE_AS_ARGS %s
// CHECK_LE_AS_ARGS: "-mppc64"
// CHECK_LE_AS_ARGS: "-many"
// CHECK_LE_AS_ARGS: "-mlittle-endian"
diff --git a/test/Driver/prefixed-tools.c b/test/Driver/prefixed-tools.c
index d7c342a8a94b..cdd59dae133d 100644
--- a/test/Driver/prefixed-tools.c
+++ b/test/Driver/prefixed-tools.c
@@ -6,7 +6,7 @@
// RUN: -m32 -target x86_64--linux %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-M32 %s
-// CHECK-M64: "{{.*}}{{[/\\]}}prefixed_tools_tree{{[/\\]}}x86_64--linux-as"
-// CHECK-M64: "{{.*}}{{[/\\]}}prefixed_tools_tree{{[/\\]}}x86_64--linux-ld"
-// CHECK-M32: "{{.*}}{{[/\\]}}prefixed_tools_tree{{[/\\]}}x86_64--linux-as"
-// CHECK-M32: "{{.*}}{{[/\\]}}prefixed_tools_tree{{[/\\]}}x86_64--linux-ld"
+// CHECK-M64: "{{.*}}{{/|\\\\}}prefixed_tools_tree{{/|\\\\}}x86_64--linux-as"
+// CHECK-M64: "{{.*}}{{/|\\\\}}prefixed_tools_tree{{/|\\\\}}x86_64--linux-ld"
+// CHECK-M32: "{{.*}}{{/|\\\\}}prefixed_tools_tree{{/|\\\\}}x86_64--linux-as"
+// CHECK-M32: "{{.*}}{{/|\\\\}}prefixed_tools_tree{{/|\\\\}}x86_64--linux-ld"
diff --git a/test/Driver/r600-mcpu.cl b/test/Driver/r600-mcpu.cl
index 47c018512bed..94a77346e877 100644
--- a/test/Driver/r600-mcpu.cl
+++ b/test/Driver/r600-mcpu.cl
@@ -26,15 +26,15 @@
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=caicos %s -o - 2>&1 | FileCheck --check-prefix=CAICOS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cayman %s -o - 2>&1 | FileCheck --check-prefix=CAYMAN-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=aruba %s -o - 2>&1 | FileCheck --check-prefix=CAYMAN-CHECK %s
-// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=tahiti %s -o - 2>&1 | FileCheck --check-prefix=TAHITI-CHECK %s
-// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=pitcairn %s -o - 2>&1 | FileCheck --check-prefix=PITCAIRN-CHECK %s
-// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=verde %s -o - 2>&1 | FileCheck --check-prefix=VERDE-CHECK %s
-// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=oland %s -o - 2>&1 | FileCheck --check-prefix=OLAND-CHECK %s
-// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=bonaire %s -o - 2>&1 | FileCheck --check-prefix=BONAIRE-CHECK %s
-// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=kabini %s -o - 2>&1 | FileCheck --check-prefix=KABINI-CHECK %s
-// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=kaveri %s -o - 2>&1 | FileCheck --check-prefix=KAVERI-CHECK %s
-// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=hawaii %s -o - 2>&1 | FileCheck --check-prefix=HAWAII-CHECK %s
-// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=mullins %s -o - 2>&1 | FileCheck --check-prefix=MULLINS-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=tahiti %s -o - 2>&1 | FileCheck --check-prefix=TAHITI-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=pitcairn %s -o - 2>&1 | FileCheck --check-prefix=PITCAIRN-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=verde %s -o - 2>&1 | FileCheck --check-prefix=VERDE-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=oland %s -o - 2>&1 | FileCheck --check-prefix=OLAND-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=bonaire %s -o - 2>&1 | FileCheck --check-prefix=BONAIRE-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=kabini %s -o - 2>&1 | FileCheck --check-prefix=KABINI-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=kaveri %s -o - 2>&1 | FileCheck --check-prefix=KAVERI-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=hawaii %s -o - 2>&1 | FileCheck --check-prefix=HAWAII-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=mullins %s -o - 2>&1 | FileCheck --check-prefix=MULLINS-CHECK %s
// R600-CHECK: "-target-cpu" "r600"
// RS880-CHECK: "-target-cpu" "rs880"
diff --git a/test/Driver/response-file.c b/test/Driver/response-file.c
new file mode 100644
index 000000000000..208a941e8723
--- /dev/null
+++ b/test/Driver/response-file.c
@@ -0,0 +1,23 @@
+// REQUIRES: long_tests
+
+// Check that clang is able to process short response files
+// Since this is a short response file, clang must not use a response file
+// to pass its parameters to other tools. This is only necessary for a large
+// number of parameters.
+// RUN: echo "-DTEST" >> %t.0.txt
+// RUN: %clang -E @%t.0.txt %s -v 2>&1 | FileCheck %s -check-prefix=SHORT
+// SHORT-NOT: Arguments passed via response file
+// SHORT: extern int it_works;
+
+// Check that clang is able to process long response files, routing a long
+// sequence of arguments to other tools by using response files as well.
+// We generate a 2MB response file to be big enough to surpass any system
+// limit.
+// RUN: %clang -E %S/Inputs/gen-response.c | grep DTEST > %t.1.txt
+// RUN: %clang -E @%t.1.txt %s -v 2>&1 | FileCheck %s -check-prefix=LONG
+// LONG: Arguments passed via response file
+// LONG: extern int it_works;
+
+#ifdef TEST
+extern int it_works;
+#endif
diff --git a/test/Driver/rewrite-legacy-objc.m b/test/Driver/rewrite-legacy-objc.m
index 0c6404e323de..b0b78d00817a 100644
--- a/test/Driver/rewrite-legacy-objc.m
+++ b/test/Driver/rewrite-legacy-objc.m
@@ -3,11 +3,11 @@
// TEST0: clang{{.*}}" "-cc1"
// TEST0: "-rewrite-objc"
// FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead.
-// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
// TEST0: rewrite-legacy-objc.m"
// RUN: %clang -no-canonical-prefixes -target i386-apple-macosx10.9.0 -rewrite-legacy-objc %s -o - -### 2>&1 | \
// RUN: FileCheck -check-prefix=TEST1 %s
// RUN: %clang -no-canonical-prefixes -target i386-apple-macosx10.6.0 -rewrite-legacy-objc %s -o - -### 2>&1 | \
// RUN: FileCheck -check-prefix=TEST2 %s
-// TEST1: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fobjc-subscripting-legacy-runtime" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option"
-// TEST2: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option"
+// TEST1: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fobjc-subscripting-legacy-runtime" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
+// TEST2: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
diff --git a/test/Driver/rewrite-map-in-diagnostics.c b/test/Driver/rewrite-map-in-diagnostics.c
new file mode 100644
index 000000000000..984e0d6e8ce6
--- /dev/null
+++ b/test/Driver/rewrite-map-in-diagnostics.c
@@ -0,0 +1,12 @@
+// RUN: rm -rf "%t"
+// RUN: mkdir -p "%t"
+// RUN: not env TMPDIR="%t" TEMP="%t" TMP="%t" RC_DEBUG_OPTION=1 \
+// RUN: %clang -fsyntax-only -frewrite-map-file %p/Inputs/rewrite.map %s 2>&1 \
+// RUN: | FileCheck %s
+
+#pragma clang __debug parser_crash
+
+// CHECK: note: diagnostic msg: {{.*}}rewrite.map
+
+// FIXME: This doesn't fail on "env clang". Investigating.
+// REQUIRES: shell
diff --git a/test/Driver/rewrite-objc.m b/test/Driver/rewrite-objc.m
index 95db58294d2a..ba5f835ed8f5 100644
--- a/test/Driver/rewrite-objc.m
+++ b/test/Driver/rewrite-objc.m
@@ -3,4 +3,4 @@
// TEST0: clang{{.*}}" "-cc1"
// TEST0: "-rewrite-objc"
// FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead.
-// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
diff --git a/test/Driver/sanitizer-ld.c b/test/Driver/sanitizer-ld.c
index 786262c68b84..dc8e93e50f26 100644
--- a/test/Driver/sanitizer-ld.c
+++ b/test/Driver/sanitizer-ld.c
@@ -9,11 +9,12 @@
// CHECK-ASAN-LINUX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-ASAN-LINUX-NOT: "-lc"
// CHECK-ASAN-LINUX: libclang_rt.asan-i386.a"
+// CHECK-ASAN-LINUX-NOT: "-export-dynamic"
+// CHECK-ASAN-LINUX: "--dynamic-list={{.*}}libclang_rt.asan-i386.a.syms"
+// CHECK-ASAN-LINUX-NOT: "-export-dynamic"
// CHECK-ASAN-LINUX: "-lpthread"
// CHECK-ASAN-LINUX: "-lrt"
// CHECK-ASAN-LINUX: "-ldl"
-// CHECK-ASAN-LINUX-NOT: "-export-dynamic"
-// CHECK-ASAN-LINUX: "--dynamic-list={{.*}}libclang_rt.asan-i386.a.syms"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux -fsanitize=address -shared-libasan \
@@ -24,8 +25,8 @@
// CHECK-SHARED-ASAN-LINUX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-SHARED-ASAN-LINUX-NOT: "-lc"
// CHECK-SHARED-ASAN-LINUX-NOT: libclang_rt.asan-i386.a"
-// CHECK-SHARED-ASAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.asan-preinit-i386.a" "-no-whole-archive"
// CHECK-SHARED-ASAN-LINUX: libclang_rt.asan-i386.so"
+// CHECK-SHARED-ASAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.asan-preinit-i386.a" "-no-whole-archive"
// CHECK-SHARED-ASAN-LINUX-NOT: "-lpthread"
// CHECK-SHARED-ASAN-LINUX-NOT: "-lrt"
// CHECK-SHARED-ASAN-LINUX-NOT: "-ldl"
@@ -60,10 +61,10 @@
// CHECK-ASAN-FREEBSD-NOT: libclang_rt.asan_cxx
// CHECK-ASAN-FREEBSD: freebsd{{/|\\+}}libclang_rt.asan-i386.a"
// CHECK-ASAN-FREEBSD-NOT: libclang_rt.asan_cxx
+// CHECK-ASAN-FREEBSD-NOT: "--dynamic-list"
+// CHECK-ASAN-FREEBSD: "-export-dynamic"
// CHECK-ASAN-FREEBSD: "-lpthread"
// CHECK-ASAN-FREEBSD: "-lrt"
-// CHECK-ASAN-FREEBSD: "-export-dynamic"
-// CHECK-ASAN-FREEBSD-NOT: "--dynamic-list"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-freebsd -fsanitize=address \
@@ -82,14 +83,14 @@
//
// CHECK-ASAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-ASAN-LINUX-CXX-NOT: "-lc"
-// CHECK-ASAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.asan_cxx-i386.a" "-no-whole-archive"
// CHECK-ASAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.asan-i386.a" "-no-whole-archive"
+// CHECK-ASAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.asan_cxx-i386.a" "-no-whole-archive"
+// CHECK-ASAN-LINUX-CXX-NOT: "--dynamic-list"
+// CHECK-ASAN-LINUX-CXX: "-export-dynamic"
+// CHECK-ASAN-LINUX-CXX: stdc++
// CHECK-ASAN-LINUX-CXX: "-lpthread"
// CHECK-ASAN-LINUX-CXX: "-lrt"
// CHECK-ASAN-LINUX-CXX: "-ldl"
-// CHECK-ASAN-LINUX-CXX: "-export-dynamic"
-// CHECK-ASAN-LINUX-CXX-NOT: "--dynamic-list"
-// CHECK-ASAN-LINUX-CXX: stdc++
// RUN: %clang -no-canonical-prefixes %s -### -o /dev/null -fsanitize=address \
// RUN: -target i386-unknown-linux --sysroot=%S/Inputs/basic_linux_tree \
@@ -126,10 +127,10 @@
//
// CHECK-ASAN-ANDROID: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-ASAN-ANDROID-NOT: "-lc"
-// CHECK-ASAN-ANDROID: libclang_rt.asan-arm-android.so"
-// CHECK-ASAN-ANDROID-NOT: "-lpthread"
// CHECK-ASAN-ANDROID: "-pie"
// CHECK-ASAN-ANDROID-NOT: "-lpthread"
+// CHECK-ASAN-ANDROID: libclang_rt.asan-arm-android.so"
+// CHECK-ASAN-ANDROID-NOT: "-lpthread"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target arm-linux-androideabi -fsanitize=address \
@@ -159,12 +160,13 @@
// CHECK-TSAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-TSAN-LINUX-CXX-NOT: stdc++
// CHECK-TSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.tsan-x86_64.a" "-no-whole-archive"
-// CHECK-TSAN-LINUX-CXX: "-lpthread"
-// CHECK-TSAN-LINUX-CXX: "-lrt"
-// CHECK-TSAN-LINUX-CXX: "-ldl"
// CHECK-TSAN-LINUX-CXX-NOT: "-export-dynamic"
// CHECK-TSAN-LINUX-CXX: "--dynamic-list={{.*}}libclang_rt.tsan-x86_64.a.syms"
+// CHECK-TSAN-LINUX-CXX-NOT: "-export-dynamic"
// CHECK-TSAN-LINUX-CXX: stdc++
+// CHECK-TSAN-LINUX-CXX: "-lpthread"
+// CHECK-TSAN-LINUX-CXX: "-lrt"
+// CHECK-TSAN-LINUX-CXX: "-ldl"
// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target x86_64-unknown-linux -lstdc++ -fsanitize=memory \
@@ -175,12 +177,13 @@
// CHECK-MSAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-MSAN-LINUX-CXX-NOT: stdc++
// CHECK-MSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.msan-x86_64.a" "-no-whole-archive"
-// CHECK-MSAN-LINUX-CXX: "-lpthread"
-// CHECK-MSAN-LINUX-CXX: "-lrt"
-// CHECK-MSAN-LINUX-CXX: "-ldl"
// CHECK-MSAN-LINUX-CXX-NOT: "-export-dynamic"
// CHECK-MSAN-LINUX-CXX: "--dynamic-list={{.*}}libclang_rt.msan-x86_64.a.syms"
+// CHECK-MSAN-LINUX-CXX-NOT: "-export-dynamic"
// CHECK-MSAN-LINUX-CXX: stdc++
+// CHECK-MSAN-LINUX-CXX: "-lpthread"
+// CHECK-MSAN-LINUX-CXX: "-lrt"
+// CHECK-MSAN-LINUX-CXX: "-ldl"
// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux \
@@ -188,12 +191,23 @@
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX %s
// CHECK-UBSAN-LINUX: "{{.*}}ld{{(.exe)?}}"
// CHECK-UBSAN-LINUX-NOT: libclang_rt.asan
+// CHECK-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
// CHECK-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.san-i386.a" "-no-whole-archive"
// CHECK-UBSAN-LINUX-NOT: libclang_rt.asan
+// CHECK-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
// CHECK-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
+// CHECK-UBSAN-LINUX-NOT: libclang_rt.asan
// CHECK-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
-// CHECK-UBSAN-LINUX: "-lpthread"
// CHECK-UBSAN-LINUX-NOT: "-lstdc++"
+// CHECK-UBSAN-LINUX: "-lpthread"
+
+// RUN: %clang -fsanitize=undefined -fsanitize-link-c++-runtime %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX-LINK-CXX %s
+// CHECK-UBSAN-LINUX-LINK-CXX-NOT: "-lstdc++"
+// CHECK-UBSAN-LINUX-LINK-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan_cxx-i386.a" "-no-whole-archive"
+// CHECK-UBSAN-LINUX-LINK-CXX-NOT: "-lstdc++"
// RUN: %clangxx -fsanitize=undefined %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux \
@@ -205,11 +219,16 @@
// CHECK-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.san-i386.a" "-no-whole-archive"
// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
// CHECK-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
+// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
// CHECK-UBSAN-LINUX-CXX: "--dynamic-list={{.*}}libclang_rt.ubsan-i386.a.syms"
+// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
// CHECK-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan_cxx-i386.a" "-no-whole-archive"
-// CHECK-UBSAN-LINUX-CXX: "-lpthread"
+// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
// CHECK-UBSAN-LINUX-CXX: "--dynamic-list={{.*}}libclang_rt.ubsan_cxx-i386.a.syms"
+// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
// CHECK-UBSAN-LINUX-CXX: "-lstdc++"
+// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
+// CHECK-UBSAN-LINUX-CXX: "-lpthread"
// RUN: %clang -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux \
@@ -221,8 +240,8 @@
// CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.san
// CHECK-ASAN-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
// CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
-// CHECK-ASAN-UBSAN-LINUX: "-lpthread"
// CHECK-ASAN-UBSAN-LINUX-NOT: "-lstdc++"
+// CHECK-ASAN-UBSAN-LINUX: "-lpthread"
// RUN: %clangxx -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux \
@@ -234,8 +253,8 @@
// CHECK-ASAN-UBSAN-LINUX-CXX-NOT: libclang_rt.san
// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan_cxx-i386.a" "-no-whole-archive"
-// CHECK-ASAN-UBSAN-LINUX-CXX: "-lpthread"
// CHECK-ASAN-UBSAN-LINUX-CXX: "-lstdc++"
+// CHECK-ASAN-UBSAN-LINUX-CXX: "-lpthread"
// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux \
@@ -271,8 +290,8 @@
// CHECK-LSAN-UBSAN-LINUX-NOT: libclang_rt.san
// CHECK-LSAN-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.ubsan-x86_64.a" "-no-whole-archive"
// CHECK-LSAN-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
-// CHECK-LSAN-UBSAN-LINUX: "-lpthread"
// CHECK-LSAN-UBSAN-LINUX-NOT: "-lstdc++"
+// CHECK-LSAN-UBSAN-LINUX: "-lpthread"
// RUN: %clang -fsanitize=leak,address %s -### -o %t.o 2>&1 \
// RUN: -target x86_64-unknown-linux \
diff --git a/test/Driver/save-temps.c b/test/Driver/save-temps.c
index a4ca3b26649e..a157aeaaff4a 100644
--- a/test/Driver/save-temps.c
+++ b/test/Driver/save-temps.c
@@ -1,17 +1,28 @@
// RUN: %clang -target x86_64-apple-darwin -save-temps -arch x86_64 %s -### 2>&1 \
// RUN: | FileCheck %s
// CHECK: "-o" "save-temps.i"
+// CHECK: "-disable-llvm-optzns"
+// CHECK: "-o" "save-temps.bc"
// CHECK: "-o" "save-temps.s"
// CHECK: "-o" "save-temps.o"
// CHECK: "-o" "a.out"
+// Check for a single clang cc1 invocation when NOT using -save-temps.
+// RUN: %clang -target x86_64-apple-darwin -arch x86_64 -S %s -### 2>&1 \
+// RUN: | FileCheck %s -check-prefix=NO-TEMPS
+// NO-TEMPS: "-cc1"
+// NO-TEMPS: "-S"
+// NO-TEMPS: "-x" "c"
+
// RUN: %clang -target x86_64-apple-darwin -save-temps -arch i386 -arch x86_64 %s -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=MULT-ARCH
// MULT-ARCH: "-o" "save-temps-i386.i"
+// MULT-ARCH: "-o" "save-temps-i386.bc"
// MULT-ARCH: "-o" "save-temps-i386.s"
// MULT-ARCH: "-o" "save-temps-i386.o"
// MULT-ARCH: "-o" "a.out-i386"
// MULT-ARCH: "-o" "save-temps-x86_64.i"
+// MULT-ARCH: "-o" "save-temps-x86_64.bc"
// MULT-ARCH: "-o" "save-temps-x86_64.s"
// MULT-ARCH: "-o" "save-temps-x86_64.o"
// MULT-ARCH: "-o" "a.out-x86_64"
diff --git a/test/Driver/sparc-float.c b/test/Driver/sparc-float.c
index 15050d2c4ea4..e84c487c73c9 100644
--- a/test/Driver/sparc-float.c
+++ b/test/Driver/sparc-float.c
@@ -5,6 +5,7 @@
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target sparc-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-DEF %s
+// CHECK-DEF: "-target-feature" "+soft-float"
// CHECK-DEF: "-msoft-float"
//
// -mhard-float
@@ -17,12 +18,14 @@
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target sparc-linux-gnu -msoft-float \
// RUN: | FileCheck --check-prefix=CHECK-SOFT %s
+// CHECK-SOFT: "-target-feature" "+soft-float"
// CHECK-SOFT: "-msoft-float"
//
// Default sparc64
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target sparc64-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-DEF-SPARC64 %s
+// CHECK-DEF-SPARC64: "-target-feature" "+soft-float"
// CHECK-DEF-SPARC64: "-msoft-float"
//
// -mhard-float
@@ -35,4 +38,5 @@
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target sparc64-linux-gnu -msoft-float \
// RUN: | FileCheck --check-prefix=CHECK-SOFT-SPARC64 %s
+// CHECK-SOFT-SPARC64: "-target-feature" "+soft-float"
// CHECK-SOFT-SPARC64: "-msoft-float"
diff --git a/test/Driver/split-debug.c b/test/Driver/split-debug.c
index 792abbd55259..6296c4672e5c 100644
--- a/test/Driver/split-debug.c
+++ b/test/Driver/split-debug.c
@@ -1,6 +1,5 @@
// Check that we split debug output properly
//
-// REQUIRES: asserts
// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -c -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-ACTIONS < %t %s
//
diff --git a/test/Driver/split-debug.s b/test/Driver/split-debug.s
index d5f077af1346..64e8f2fa03d2 100644
--- a/test/Driver/split-debug.s
+++ b/test/Driver/split-debug.s
@@ -1,6 +1,5 @@
// Check that we split debug output properly
//
-// REQUIRES: asserts
// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -c -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-ACTIONS < %t %s
//
diff --git a/test/Driver/std.c b/test/Driver/std.c
index c82e9f15c7da..02dca6698d34 100644
--- a/test/Driver/std.c
+++ b/test/Driver/std.c
@@ -1,8 +1,18 @@
-// RUN: %clang -std=c99 -trigraphs -std=gnu99 %s -E -o - | FileCheck -check-prefix=OVERRIDE %s
+// RUN: %clang -w -std=c99 -trigraphs -std=gnu99 %s -E -o - | FileCheck -check-prefix=OVERRIDE %s
// OVERRIDE: ??(??)
-// RUN: %clang -ansi %s -E -o - | FileCheck -check-prefix=ANSI %s
+// RUN: %clang -w -std=c99 -trigraphs -std=gnu99 %s -E -o - | FileCheck -check-prefix=FOVERRIDE %s
+// FOVERRIDE: ??(??)
+// RUN: %clang -w -ansi %s -E -o - | FileCheck -check-prefix=ANSI %s
// ANSI: []
-// RUN: %clang -std=gnu99 -trigraphs %s -E -o - | FileCheck -check-prefix=EXPLICIT %s
+// RUN: %clang -w -ansi %s -fno-trigraphs -E -o - | FileCheck -check-prefix=ANSI-OVERRIDE %s
+// ANSI-OVERRIDE: ??(??)
+// RUN: %clang -w -std=gnu99 -trigraphs %s -E -o - | FileCheck -check-prefix=EXPLICIT %s
// EXPLICIT: []
+// RUN: %clang -w -std=gnu99 -ftrigraphs %s -E -o - | FileCheck -check-prefix=FEXPLICIT %s
+// FEXPLICIT: []
+// RUN: %clang -w -ftrigraphs -fno-trigraphs %s -E -o - | FileCheck -check-prefix=ONOFF %s
+// ONOFF: ??(??)
+// RUN: %clang -w -fno-trigraphs -trigraphs %s -E -o - | FileCheck -check-prefix=OFFFON %s
+// OFFFON: []
??(??)
diff --git a/test/Driver/symbol-rewriter.c b/test/Driver/symbol-rewriter.c
new file mode 100644
index 000000000000..3cfdb9d09cd9
--- /dev/null
+++ b/test/Driver/symbol-rewriter.c
@@ -0,0 +1,21 @@
+// RUN: %clang -frewrite-map-file %S/Inputs/rewrite.map -### %s 2>&1 | FileCheck %s -check-prefix CHECK-SINGLE
+
+// CHECK-SINGLE: "-frewrite-map-file" "{{.*[\\/]}}rewrite.map"
+
+// RUN: %clang -frewrite-map-file %S/Inputs/rewrite-1.map -frewrite-map-file %S/Inputs/rewrite-2.map -### %s 2>&1 | FileCheck %s -check-prefix CHECK-MULTIPLE
+
+// CHECK-MULTIPLE: "-frewrite-map-file" "{{.*[\\/]}}rewrite-1.map" "-frewrite-map-file" "{{.*[\\/]}}rewrite-2.map"
+
+// RUN: %clang -frewrite-map-file=%S/Inputs/rewrite.map -### %s 2>&1 | FileCheck %s -check-prefix CHECK-SINGLE-EQ
+
+// CHECK-SINGLE-EQ: "-frewrite-map-file" "{{.*[\\/]}}rewrite.map"
+
+// RUN: %clang -frewrite-map-file=%S/Inputs/rewrite-1.map -frewrite-map-file=%S/Inputs/rewrite-2.map -### %s 2>&1 | FileCheck %s -check-prefix CHECK-MULTIPLE-EQ
+
+// CHECK-MULTIPLE-EQ: "-frewrite-map-file" "{{.*[\\/]}}rewrite-1.map"
+// CHECK-MULTIPLE-EQ: "-frewrite-map-file" "{{.*[\\/]}}rewrite-2.map"
+
+// RUN: %clang -frewrite-map-file %S/Inputs/rewrite-1.map -frewrite-map-file=%S/Inputs/rewrite-2.map -### %s 2>&1 | FileCheck %s -check-prefix CHECK-MIXED
+
+// CHECK-MIXED: "-frewrite-map-file" "{{.*[\\/]}}rewrite-1.map" "-frewrite-map-file" "{{.*[\\/]}}rewrite-2.map"
+
diff --git a/test/Driver/systemz-as.s b/test/Driver/systemz-as.s
new file mode 100644
index 000000000000..34ad9c41eaf3
--- /dev/null
+++ b/test/Driver/systemz-as.s
@@ -0,0 +1,14 @@
+// Make sure SystemZ defaults to using the integrated assembler
+
+// RUN: %clang -target s390x-ibm-linux -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=IAS %s
+
+// RUN: %clang -target s390x-ibm-linux -integrated-as -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=IAS %s
+// IAS: "-cc1as"{{.*}} "-target-cpu" "z10"
+
+// RUN: %clang -target s390x-ibm-linux -no-integrated-as -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=NO-IAS %s
+// NO-IAS-NOT: -cc1as
+// NO-IAS: "-march=z10"
+
diff --git a/test/Driver/thread-model.c b/test/Driver/thread-model.c
new file mode 100644
index 000000000000..9702c2231a26
--- /dev/null
+++ b/test/Driver/thread-model.c
@@ -0,0 +1,15 @@
+// RUN: %clang -### -target arm-unknown-linux-gnu -c %s -mthread-model posix -v 2>&1 | FileCheck -check-prefix=CHECK-POSIX %s
+// RUN: %clang -### -target arm-unknown-linux-gnu -c %s -mthread-model single -v 2>&1 | FileCheck -check-prefix=CHECK-SINGLE %s
+// RUN: not %clang -target arm-unknown-linux-gnu -c %s -mthread-model silly -v 2>&1 | FileCheck -check-prefix=CHECK-INVALID %s
+// CHECK-POSIX: "-mthread-model" "posix"
+// CHECK-SINGLE: "-mthread-model" "single"
+// CHECK-INVALID: error: invalid thread model 'silly' in '-mthread-model silly' for this target
+
+// RUN: %clang -### -target arm-unknown-linux-gnu -c %s -v 2>&1 | FileCheck -check-prefix=CHECK-LINUX-POSIX %s
+// RUN: %clang -### -target arm-unknown-linux-gnu -c %s -v -mthread-model single 2>&1 | FileCheck -check-prefix=CHECK-LINUX-SINGLE %s
+// RUN: %clang -### -target arm-unknown-linux-gnu -c %s -v -mthread-model silly 2>&1 | FileCheck -check-prefix=CHECK-LINUX-INVALID %s
+// CHECK-LINUX-POSIX: Thread model: posix
+// CHECK-LINUX-POSIX: "-mthread-model" "posix"
+// CHECK-LINUX-SINGLE: Thread model: single
+// CHECK-LINUX-SINGLE: "-mthread-model" "single"
+// CHECK-LINUX-INVALID-NOT: Thread model:
diff --git a/test/Driver/unknown-gcc-arch.c b/test/Driver/unknown-gcc-arch.c
index 6317e13ec486..2aba50d53202 100644
--- a/test/Driver/unknown-gcc-arch.c
+++ b/test/Driver/unknown-gcc-arch.c
@@ -14,23 +14,23 @@
// RUN: -no-integrated-as 2>&1 | FileCheck -check-prefix=I386-M64 %s
// I386-M64: {{.*as.*--64}}
-
-// RUN: %clang -target powerpc64-unknown-unknown -c -x assembler %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=PPC64 %s
+// RUN: %clang -target powerpc64-unknown-unknown -c -x assembler %s -### \
+// RUN: -no-integrated-as 2>&1 | FileCheck -check-prefix=PPC64 %s
// PPC64: {{.*as.*-a64}}
-// RUN: %clang -target powerpc64-unknown-unknown -c -x assembler %s -### -m32 2>&1 \
-// RUN: | FileCheck -check-prefix=PPC64-M32 %s
+// RUN: %clang -target powerpc-unknown-unknown -c -x assembler %s -### -m64 \
+// RUN: -no-integrated-as 2>&1 | FileCheck -check-prefix=PPC-M64 %s
+// PPC-M64: {{.*as.*-a64}}
+
+
+// RUN: %clang -target powerpc64-unknown-unknown -c -x assembler %s -### -m32 \
+// RUN: -no-integrated-as 2>&1 | FileCheck -check-prefix=PPC64-M32 %s
// PPC64-M32: {{.*as.*-a32}}
// RUN: %clang -target powerpc-unknown-unknown -c -x assembler %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=PPC %s
+// RUN: -no-integrated-as | FileCheck -check-prefix=PPC %s
// PPC: {{.*as.*-a32}}
-// RUN: %clang -target powerpc-unknown-unknown -c -x assembler %s -### -m64 2>&1 \
-// RUN: | FileCheck -check-prefix=PPC-M64 %s
-// PPC-M64: {{.*as.*-a64}}
-
// RUN: %clang -target sparc64-unknown-unknown -no-integrated-as -c -x assembler %s -### -m32 2>&1 \
// RUN: | FileCheck -check-prefix=SPARCV8 %s
// SPARCV8: {{.*as.*-32}}
diff --git a/test/Driver/warning-options.cpp b/test/Driver/warning-options.cpp
index f1a335d2139d..4d9e1f7466de 100644
--- a/test/Driver/warning-options.cpp
+++ b/test/Driver/warning-options.cpp
@@ -3,11 +3,6 @@
// RUN: %clang -### -Wlarge-by-value-copy=128 %s 2>&1 | FileCheck -check-prefix=LARGE_VALUE_COPY_JOINED %s
// LARGE_VALUE_COPY_JOINED: -Wlarge-by-value-copy=128
-// FIXME: Remove this together with -Warc-abi once an Xcode is released that doesn't pass this flag.
-// RUN: %clang -### -Warc-abi -Wno-arc-abi %s 2>&1 | FileCheck -check-prefix=ARCABI %s
-// ARCABI-NOT: unknown warning option '-Warc-abi'
-// ARCABI-NOT: unknown warning option '-Wno-arc-abi'
-
// Check that -isysroot warns on nonexistent paths.
// RUN: %clang -### -c -target i386-apple-darwin10 -isysroot /FOO %s 2>&1 | FileCheck --check-prefix=CHECK-ISYSROOT %s
// CHECK-ISYSROOT: warning: no such sysroot directory: '{{([A-Za-z]:.*)?}}/FOO'
diff --git a/test/Driver/windows-cross.c b/test/Driver/windows-cross.c
new file mode 100644
index 000000000000..979f68539c01
--- /dev/null
+++ b/test/Driver/windows-cross.c
@@ -0,0 +1,40 @@
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -o /dev/null %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix CHECK-BASIC
+
+// CHECK-BASIC: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %s/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -rtlib=compiler-rt -o /dev/null %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix CHECK-RTLIB
+
+// CHECK-RTLIB: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -rtlib=compiler-rt -stdlib=libc++ -o /dev/null %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix CHECK-C-LIBCXX
+
+// CHECK-C-LIBCXX: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
+
+// RUN: %clangxx -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -rtlib=compiler-rt -stdlib=libc++ -o /dev/null %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix CHECK-LIBCXX
+
+// CHECK-LIBCXX: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "{{.*}}.o" "-lc++" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -shared -rtlib=compiler-rt -stdlib=libc++ -o shared.dll %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix CHECK-SHARED
+
+// CHECK-SHARED: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definition" "-o" "shared.dll" "--out-implib" "shared.lib" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbeginS.obj" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %s/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -shared -rtlib=compiler-rt -stdlib=libc++ -nostartfiles -o shared.dll %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix CHECK-NOSTARTFILES
+
+// CHECK-NOSTARTFILES: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definition" "-o" "shared.dll" "--out-implib" "shared.lib" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -shared -rtlib=compiler-rt -stdlib=libc++ -nostartfiles -nodefaultlibs -o shared.dll %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix CHECK-STANDALONE
+
+// CHECK-STANDALONE: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definition" "-o" "shared.dll" "--out-implib" "shared.lib" "{{.*}}.o"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %/Inputs/Windows/ARM/8.1/usr/bin -shared -o shared.dll -x c++ %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix CHECK-LIBSTDCXX
+
+// CHECK-LIBSTDCXX: "-internal-isystem" "{{.*}}/usr/include/c++" "-internal-isystem" "{{.*}}/usr/include/c++/armv7--windows-itanium" "-internal-isystem" "{{.*}}/usr/include/c++/backwards"
+
diff --git a/test/Driver/x86-march.c b/test/Driver/x86-march.c
new file mode 100644
index 000000000000..fd6e30b01593
--- /dev/null
+++ b/test/Driver/x86-march.c
@@ -0,0 +1,105 @@
+// Ensure we support the various CPU architecture names.
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=nocona 2>&1 \
+// RUN: | FileCheck %s -check-prefix=nocona
+// nocona: "-target-cpu" "nocona"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=core2 2>&1 \
+// RUN: | FileCheck %s -check-prefix=core2
+// core2: "-target-cpu" "core2"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=penryn 2>&1 \
+// RUN: | FileCheck %s -check-prefix=penryn
+// penryn: "-target-cpu" "penryn"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=nehalem 2>&1 \
+// RUN: | FileCheck %s -check-prefix=nehalem
+// nehalem: "-target-cpu" "nehalem"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=westmere 2>&1 \
+// RUN: | FileCheck %s -check-prefix=westmere
+// westmere: "-target-cpu" "westmere"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=sandybridge 2>&1 \
+// RUN: | FileCheck %s -check-prefix=sandybridge
+// sandybridge: "-target-cpu" "sandybridge"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=ivybridge 2>&1 \
+// RUN: | FileCheck %s -check-prefix=ivybridge
+// ivybridge: "-target-cpu" "ivybridge"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=haswell 2>&1 \
+// RUN: | FileCheck %s -check-prefix=haswell
+// haswell: "-target-cpu" "haswell"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=broadwell 2>&1 \
+// RUN: | FileCheck %s -check-prefix=broadwell
+// broadwell: "-target-cpu" "broadwell"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=bonnell 2>&1 \
+// RUN: | FileCheck %s -check-prefix=bonnell
+// bonnell: "-target-cpu" "bonnell"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=silvermont 2>&1 \
+// RUN: | FileCheck %s -check-prefix=silvermont
+// silvermont: "-target-cpu" "silvermont"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=k8 2>&1 \
+// RUN: | FileCheck %s -check-prefix=k8
+// k8: "-target-cpu" "k8"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=opteron 2>&1 \
+// RUN: | FileCheck %s -check-prefix=opteron
+// opteron: "-target-cpu" "opteron"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=athlon64 2>&1 \
+// RUN: | FileCheck %s -check-prefix=athlon64
+// athlon64: "-target-cpu" "athlon64"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=athlon-fx 2>&1 \
+// RUN: | FileCheck %s -check-prefix=athlon-fx
+// athlon-fx: "-target-cpu" "athlon-fx"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=k8-sse3 2>&1 \
+// RUN: | FileCheck %s -check-prefix=k8-sse3
+// k8-sse3: "-target-cpu" "k8-sse3"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=opteron-sse3 2>&1 \
+// RUN: | FileCheck %s -check-prefix=opteron-sse3
+// opteron-sse3: "-target-cpu" "opteron-sse3"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=athlon64-sse3 2>&1 \
+// RUN: | FileCheck %s -check-prefix=athlon64-sse3
+// athlon64-sse3: "-target-cpu" "athlon64-sse3"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=amdfam10 2>&1 \
+// RUN: | FileCheck %s -check-prefix=amdfam10
+// amdfam10: "-target-cpu" "amdfam10"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=barcelona 2>&1 \
+// RUN: | FileCheck %s -check-prefix=barcelona
+// barcelona: "-target-cpu" "barcelona"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=bdver1 2>&1 \
+// RUN: | FileCheck %s -check-prefix=bdver1
+// bdver1: "-target-cpu" "bdver1"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=bdver2 2>&1 \
+// RUN: | FileCheck %s -check-prefix=bdver2
+// bdver2: "-target-cpu" "bdver2"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=bdver3 2>&1 \
+// RUN: | FileCheck %s -check-prefix=bdver3
+// bdver3: "-target-cpu" "bdver3"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=bdver4 2>&1 \
+// RUN: | FileCheck %s -check-prefix=bdver4
+// bdver4: "-target-cpu" "bdver4"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=btver1 2>&1 \
+// RUN: | FileCheck %s -check-prefix=btver1
+// btver1: "-target-cpu" "btver1"
+//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=btver2 2>&1 \
+// RUN: | FileCheck %s -check-prefix=btver2
+// btver2: "-target-cpu" "btver2"
diff --git a/test/FixIt/fixit-class-method-messaging.m b/test/FixIt/fixit-class-method-messaging.m
new file mode 100644
index 000000000000..e2592d0c87f8
--- /dev/null
+++ b/test/FixIt/fixit-class-method-messaging.m
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// rdar://16263395
+
+@interface NSObject @end
+
+@interface I : NSObject // expected-note 3 {{receiver is instance of class declared here}}
++ (id) ClassMeth;
+- (I*) MethInstPI;
+@end
+
+I* pi;
+
+I* foobar();
+
+@implementation I
+- (id) PrivInstMeth {
+ [ foobar() ClassMeth]; // expected-warning {{instance method '-ClassMeth' not found (return type defaults to 'id')}} \
+ // expected-note {{receiver expression is here}}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:5-[[@LINE-2]]:13}:"I
+ [[self MethInstPI] ClassMeth]; // expected-warning {{instance method '-ClassMeth' not found (return type defaults to 'id')}} \
+ // expected-note {{receiver expression is here}}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:4-[[@LINE-2]]:21}:"I
+ return [pi ClassMeth]; // expected-warning {{instance method '-ClassMeth' not found (return type defaults to 'id')}} \
+ // expected-note {{receiver expression is here}}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"I
+}
++ (id) ClassMeth { return 0; }
+- (I*) MethInstPI { return 0; }
+@end
diff --git a/test/FixIt/fixit-cxx1y-compat.cpp b/test/FixIt/fixit-cxx1y-compat.cpp
index 9fd5ff26e558..819e3984c352 100644
--- a/test/FixIt/fixit-cxx1y-compat.cpp
+++ b/test/FixIt/fixit-cxx1y-compat.cpp
@@ -7,6 +7,6 @@
// This is a test of the code modification hints for C++1y-compatibility problems.
struct S {
- constexpr int &f(); // expected-warning {{'constexpr' non-static member function will not be implicitly 'const' in C++1y; add 'const' to avoid a change in behavior}}
+ constexpr int &f(); // expected-warning {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const' to avoid a change in behavior}}
int &f();
};
diff --git a/test/FixIt/fixit-errors.c b/test/FixIt/fixit-errors.c
index c425fc8a2d95..d727adb6fdfb 100644
--- a/test/FixIt/fixit-errors.c
+++ b/test/FixIt/fixit-errors.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
// RUN: cp %s %t
// RUN: not %clang_cc1 -pedantic -fixit -x c %t
-// RUN: %clang_cc1 -pedantic -Werror -x c %t
+// RUN: %clang_cc1 -pedantic -Werror -Wno-invalid-noreturn -x c %t
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
@@ -21,3 +21,11 @@ struct Point *get_origin();
void test_point() {
(void)get_origin->x; // expected-error {{base of member reference is a function; perhaps you meant to call it with no arguments?}}
}
+
+void noreturn_1() _Noreturn; // expected-error {{must precede function declarator}}
+void noreturn_1() {
+ return; // expected-warning {{should not return}}
+}
+void noreturn_2() _Noreturn { // expected-error {{must precede function declarator}}
+ return; // expected-warning {{should not return}}
+}
diff --git a/test/FixIt/fixit-unrecoverable.cpp b/test/FixIt/fixit-unrecoverable.cpp
index 1e1f1b8db210..f555792ed39b 100644
--- a/test/FixIt/fixit-unrecoverable.cpp
+++ b/test/FixIt/fixit-unrecoverable.cpp
@@ -6,7 +6,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
float f(int y) {
- return static_cst<float>(y); // expected-error{{use of undeclared identifier 'static_cst'; did you mean 'static_cast'?}} \
- // expected-error{{for function-style cast or type construction}}
+ return static_cst<float>(y); // expected-error{{use of undeclared identifier 'static_cst'; did you mean 'static_cast'?}}
}
-
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index f26493856560..585c216f90de 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -pedantic -Wall -Wno-comment -verify -fcxx-exceptions -x c++ %s
-// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ -std=c++11 %s 2>&1 | FileCheck %s
// RUN: cp %s %t
// RUN: not %clang_cc1 -pedantic -Wall -Wno-comment -fcxx-exceptions -fixit -x c++ %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -Wno-comment -fcxx-exceptions -x c++ %t
@@ -308,6 +308,13 @@ namespace dtor_fixit {
~bar() { } // expected-error {{expected the class name after '~' to name a destructor}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:9}:"foo"
};
+
+ class bar {
+ ~bar();
+ };
+ ~bar::bar() {} // expected-error {{'~' in destructor name should be after nested name specifier}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:4}:""
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:9-[[@LINE-2]]:9}:"~"
}
namespace PR5066 {
@@ -340,3 +347,43 @@ namespace PR15045 {
return c->a; // expected-error {{member reference type 'PR15045::Cl0' is not a pointer; maybe you meant to use '.'?}}
}
}
+
+namespace curly_after_base_clause {
+struct A { void f(); };
+struct B : A // expected-error{{expected '{' after base class list}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {"
+ int i;
+};
+struct C : A // expected-error{{expected '{' after base class list}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {"
+ using A::f;
+};
+struct D : A // expected-error{{expected '{' after base class list}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {"
+ protected:
+};
+struct E : A // expected-error{{expected '{' after base class list}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {"
+ template<typename T> struct inner { };
+};
+struct F : A // expected-error{{expected '{' after base class list}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {"
+ F() { }
+};
+#if __cplusplus >= 201103L
+struct G : A // expected-error{{expected '{' after base class list}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {"
+ constexpr G(int) { }
+};
+struct H : A // expected-error{{expected '{' after base class list}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {"
+ static_assert(true, "");
+};
+#endif
+}
+
+struct conversion_operator {
+ conversion_operator::* const operator int(); // expected-error {{put the complete type after 'operator'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:32}:""
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:44-[[@LINE-2]]:44}:" conversion_operator::* const"
+};
diff --git a/test/FixIt/multiarg-selector-fixit.m b/test/FixIt/multiarg-selector-fixit.m
new file mode 100644
index 000000000000..d60d31282ce7
--- /dev/null
+++ b/test/FixIt/multiarg-selector-fixit.m
@@ -0,0 +1,15 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -x objective-c -fixit %t
+// RUN: diff %t %s
+// rdar://15756038
+
+#define nil (void *)0
+
+@interface NSObject
+- (void)testDataSource:(id)object withMultipleArguments:(id)arguments;
+@end
+
+int main() {
+ id obj;
+ [obj TestDataSource:nil withMultipleArguments:nil];
+}
diff --git a/test/FixIt/property-access-fixit.m b/test/FixIt/property-access-fixit.m
new file mode 100644
index 000000000000..8623d29b9629
--- /dev/null
+++ b/test/FixIt/property-access-fixit.m
@@ -0,0 +1,31 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -x objective-c -fixit %t
+// RUN: %clang_cc1 -x objective-c -Werror %t
+//rdar://17911746
+
+@class BridgeFormatter;
+
+@interface NSObject
++ (id)new;
+@end
+
+@interface X : NSObject
+@property int x;
+@property int Y;
+@property(assign, readwrite, getter=formatter, setter=setFormatter:) BridgeFormatter* cppFormatter;
+@end
+
+@implementation X
+- (void) endit
+{
+ self.formatter = 0;
+}
+@end
+
+int main()
+{
+ X *obj = [X new];
+ obj.X = 3;
+ obj.y = 4;
+ return obj.x + obj.Y;
+}
diff --git a/test/Frontend/Inputs/profile-sample-use-loc-tracking.prof b/test/Frontend/Inputs/profile-sample-use-loc-tracking.prof
new file mode 100644
index 000000000000..ba9a678a4526
--- /dev/null
+++ b/test/Frontend/Inputs/profile-sample-use-loc-tracking.prof
@@ -0,0 +1,2 @@
+bar:100:100
+1: 2000
diff --git a/test/Frontend/exceptions.c b/test/Frontend/exceptions.c
index 4bbaaa39bfa6..981b5b9045b5 100644
--- a/test/Frontend/exceptions.c
+++ b/test/Frontend/exceptions.c
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -fms-compatibility -fexceptions -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -fms-compatibility -fexceptions -fcxx-exceptions -DMS_MODE -verify %s
// expected-no-diagnostics
-#if defined(__EXCEPTIONS)
+// RUN: %clang_cc1 -fms-compatibility -fexceptions -verify %s
+// expected-no-diagnostics
+
+#if defined(MS_MODE) && defined(__EXCEPTIONS)
#error __EXCEPTIONS should not be defined.
#endif
diff --git a/test/Frontend/invalid-o-level.c b/test/Frontend/invalid-o-level.c
index 73be9b1c21ff..0314448b0ff2 100644
--- a/test/Frontend/invalid-o-level.c
+++ b/test/Frontend/invalid-o-level.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -O900 -o /dev/null 2> %t.log
-// RUN: FileCheck %s -input-file=%t.log
+// RUN: %clang_cc1 %s -O900 -o /dev/null 2>&1 | FileCheck %s
-// CHECK: warning: optimization level '-O900' is not supported; using '-O3' instead
+// RUN: %clang_cc1 %s -O8 -o /dev/null 2>&1 | FileCheck %s
+
+// CHECK: warning: optimization level '-O{{.*}}' is not supported; using '-O3' instead
diff --git a/test/Frontend/output-failures.c b/test/Frontend/output-failures.c
index e2af7c7ddc90..362deb5e4629 100644
--- a/test/Frontend/output-failures.c
+++ b/test/Frontend/output-failures.c
@@ -1,4 +1,4 @@
// RUN: not %clang_cc1 -emit-llvm -o %S/doesnotexist/somename %s 2> %t
// RUN: FileCheck -check-prefix=OUTPUTFAIL -input-file=%t %s
-// OUTPUTFAIL: Error opening output file '{{.*}}doesnotexist{{.*}}'
+// OUTPUTFAIL: error: unable to open output file '{{.*}}{{[/\\]}}test{{[/\\]}}Frontend{{[/\\]}}doesnotexist{{[/\\]}}somename': '{{[nN]}}o such file or directory'
diff --git a/test/Frontend/print-header-includes.c b/test/Frontend/print-header-includes.c
index e248c76f9776..6fde00cbbe5b 100644
--- a/test/Frontend/print-header-includes.c
+++ b/test/Frontend/print-header-includes.c
@@ -1,3 +1,6 @@
+// REQUIRES: shell
+
+// RUN: cd %S
// RUN: %clang_cc1 -include Inputs/test3.h -E -H -o %t.out %s 2> %t.stderr
// RUN: FileCheck < %t.stderr %s
diff --git a/test/Frontend/profile-sample-use-loc-tracking.c b/test/Frontend/profile-sample-use-loc-tracking.c
new file mode 100644
index 000000000000..31faad68d39e
--- /dev/null
+++ b/test/Frontend/profile-sample-use-loc-tracking.c
@@ -0,0 +1,19 @@
+// This file tests that -fprofile-sample-use enables location tracking
+// generation in the same way that -Rpass does. The sample profiler needs
+// to associate line locations in the profile to the code, so it needs the
+// frontend to emit source location annotations.
+
+// RUN: %clang_cc1 %s -fprofile-sample-use=%S/Inputs/profile-sample-use-loc-tracking.prof -emit-llvm -o - 2>/dev/null | FileCheck %s
+
+// -fprofile-sample-use should produce source location annotations, exclusively
+// (just like -gmlt).
+// CHECK: , !dbg !
+// CHECK-NOT: DW_TAG_base_type
+
+// But llvm.dbg.cu should be missing (to prevent writing debug info to
+// the final output).
+// CHECK-NOT: !llvm.dbg.cu = !{
+
+int bar(int j) {
+ return (j + j - 2) * (j - 2) * j;
+}
diff --git a/test/Frontend/source-col-map.c b/test/Frontend/source-col-map.c
new file mode 100644
index 000000000000..a14023bc82a8
--- /dev/null
+++ b/test/Frontend/source-col-map.c
@@ -0,0 +1,37 @@
+// RUN: not %clang_cc1 %s -fsyntax-only -fmessage-length 75 -o /dev/null 2>&1 | FileCheck %s -strict-whitespace
+
+// Test case for the text diagnostics source column conversion crash.
+
+// This test case tries to check the error diagnostic message printer, which is
+// responsible to create the code snippet shorter than the message-length (in
+// number of columns.)
+//
+// The error diagnostic message printer should be able to handle the non-ascii
+// characters without any segmentation fault or assertion failure. If your
+// changes to clang frontend crashes this case, it is likely that you are mixing
+// column index with byte index which are two totally different concepts.
+
+// NOTE: This file is encoded in UTF-8 and intentionally contains some
+// non-ASCII characters.
+
+__attribute__((format(printf, 1, 2)))
+extern int printf(const char *fmt, ...);
+
+void test1(Unknown* b); // αααα αααα αααα αααα αααα αααα αααα αααα αααα αααα αααα
+// CHECK: unknown type name 'Unknown'
+// CHECK-NEXT: void test1(Unknown* b); // αααα αααα αααα αααα αααα αααα αααα ααα...
+// CHECK-NEXT: {{^ \^$}}
+
+void test2(Unknown* b); // αααα αααα αααα αααα αααα αααα αααα αααα αααα
+
+// CHECK: unknown type name 'Unknown'
+// CHECK-NEXT: void test2(Unknown* b); // αααα αααα αααα αααα αααα αααα αααα αααα αααα
+// CHECK-NEXT: {{^ \^$}}
+
+void test3() {
+ /* αααα αααα αααα αααα αααα αααα αααα αααα αααα αααα */ printf("%d", "s");
+}
+// CHECK: format specifies type 'int' but the argument has type 'char *'
+// CHECK-NEXT: ...αααα αααα αααα αααα αααα αααα αααα αααα αααα */ printf("%d", "s");
+// CHECK-NEXT: {{^ ~~ \^~~$}}
+// CHECK-NEXT: {{^ %s$}}
diff --git a/test/Frontend/std.cl b/test/Frontend/std.cl
new file mode 100644
index 000000000000..b811b64dabcb
--- /dev/null
+++ b/test/Frontend/std.cl
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -fsyntax-only -cl-std=CL
+// RUN: %clang_cc1 %s -fsyntax-only -cl-std=CL1.1
+// RUN: %clang_cc1 %s -fsyntax-only -cl-std=CL1.2
+// RUN: %clang_cc1 %s -fsyntax-only -cl-std=CL2.0
+// RUN: not %clang_cc1 %s -fsyntax-only -cl-std=invalid -DINVALID 2>&1 | FileCheck %s
+
+#ifdef INVALID
+// CHECK: invalid value 'invalid' in '-cl-std=invalid'
+#endif
diff --git a/test/Frontend/trigraphs.cpp b/test/Frontend/trigraphs.cpp
new file mode 100644
index 000000000000..552078951aee
--- /dev/null
+++ b/test/Frontend/trigraphs.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -DSTDCPP11 -std=c++11 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -DSTDGNU11 -std=gnu++11 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -DSTDGNU11TRI -ftrigraphs -std=gnu++11 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -DSTDCPP17 -std=c++1z -verify -fsyntax-only %s
+// RUN: %clang_cc1 -DSTDCPP17TRI -ftrigraphs -std=c++1z -verify -fsyntax-only %s
+// RUN: %clang_cc1 -DMSCOMPAT -fms-compatibility -std=c++11 -verify -fsyntax-only %s
+
+void foo() {
+#if defined(NOFLAGS) || defined(STDCPP11) || defined(STDGNU11TRI) || \
+ defined(STDCPP17TRI)
+ const char c[] = "??/n"; // expected-warning{{trigraph converted to '\' character}}
+#elif defined(STDGNU11) || defined(STDCPP17) || defined(MSCOMPAT)
+ const char c[] = "??/n"; // expected-warning{{trigraph ignored}}
+#else
+#error Not handled.
+#endif
+}
diff --git a/test/Frontend/verify-unknown-arg.c b/test/Frontend/verify-unknown-arg.c
new file mode 100644
index 000000000000..5767daedca3c
--- /dev/null
+++ b/test/Frontend/verify-unknown-arg.c
@@ -0,0 +1,6 @@
+// RUN: not %clang_cc1 -asdf -verify %s 2>&1 | FileCheck %s
+
+// expected-no-diagnostics
+
+// CHECK: error: 'error' diagnostics seen but not expected:
+// CHECK-NEXT: (frontend): unknown argument: '-asdf'
diff --git a/test/Frontend/x86-target-cpu.c b/test/Frontend/x86-target-cpu.c
new file mode 100644
index 000000000000..769c40a016e3
--- /dev/null
+++ b/test/Frontend/x86-target-cpu.c
@@ -0,0 +1,30 @@
+// Ensure we support the various CPU names.
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu nocona -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu core2 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu penryn -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu nehalem -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu westmere -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu sandybridge -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu ivybridge -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu haswell -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu broadwell -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu bonnell -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu silvermont -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu k8 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu opteron -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu athlon64 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu athlon-fx -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu k8-sse3 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu opteron-sse3 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu athlon64-sse3 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu amdfam10 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu barcelona -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu bdver1 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu bdver2 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu bdver3 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu bdver4 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu btver1 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-cpu btver2 -verify %s
+//
+// expected-no-diagnostics
diff --git a/test/Headers/altivec-header.c b/test/Headers/altivec-header.c
index 3d8595734893..7b6c5168b01e 100644
--- a/test/Headers/altivec-header.c
+++ b/test/Headers/altivec-header.c
@@ -12,4 +12,5 @@
// CHECK-NEXT: .file
// CHECK-NEXT: {{^$}}
// CHECK-NEXT: .ident{{.*$}}
+// CHECK-NEXT: .section ".note.GNU-stack","",@progbits
// CHECK-NOT: .
diff --git a/test/Headers/altivec-intrin.c b/test/Headers/altivec-intrin.c
new file mode 100644
index 000000000000..a4de7e75966b
--- /dev/null
+++ b/test/Headers/altivec-intrin.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -target-cpu power8 \
+// RUN: -faltivec -verify %s
+
+// Test special behavior of Altivec intrinsics in this file.
+
+#include <altivec.h>
+
+__attribute__((__aligned__(16))) float x[20];
+
+int main()
+{
+ vector unsigned char l = vec_lvsl (0, &x[1]); // expected-warning {{is deprecated: use assignment for unaligned little endian loads/stores}}
+ vector unsigned char r = vec_lvsr (0, &x[1]); // expected-warning {{is deprecated: use assignment for unaligned little endian loads/stores}}
+}
+// FIXME: As noted in ms-intrin.cpp, it would be nice if we didn't have to
+// hard-code the line number from altivec.h here.
+// expected-note@altivec.h:2389 {{deprecated here}}
+// expected-note@altivec.h:2524 {{deprecated here}}
diff --git a/test/Headers/c11.c b/test/Headers/c11.c
index b7b15011f3ce..6594823c2733 100644
--- a/test/Headers/c11.c
+++ b/test/Headers/c11.c
@@ -1,6 +1,6 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -fmodules -fmodules-cache-path=%t %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -fmodules -fmodules-cache-path=%t %s -D__STDC_WANT_LIB_EXT1__=1
// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -ffreestanding %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -triple i686-pc-win32 -fms-compatibility-version=17.00 %s
diff --git a/test/Headers/cpuid.c b/test/Headers/cpuid.c
new file mode 100644
index 000000000000..b0ba07af2f2a
--- /dev/null
+++ b/test/Headers/cpuid.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -ffreestanding -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-64
+// RUN: %clang_cc1 %s -ffreestanding -triple i386 -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-32
+
+#include <cpuid.h>
+
+// CHECK-64: {{.*}} call { i32, i32, i32, i32 } asm " xchgq %rbx,${1:q}\0A cpuid\0A xchgq %rbx,${1:q}", "={ax},=r,={cx},={dx},0,~{dirflag},~{fpsr},~{flags}"(i32 %{{[a-z0-9]+}})
+// CHECK-64: {{.*}} call { i32, i32, i32, i32 } asm " xchgq %rbx,${1:q}\0A cpuid\0A xchgq %rbx,${1:q}", "={ax},=r,={cx},={dx},0,2,~{dirflag},~{fpsr},~{flags}"(i32 %{{[a-z0-9]+}}, i32 %{{[a-z0-9]+}})
+
+// CHECK-32: {{.*}} call { i32, i32, i32, i32 } asm "cpuid", "={ax},={bx},={cx},={dx},0,~{dirflag},~{fpsr},~{flags}"(i32 %{{[a-z0-9]+}})
+// CHECK-32: {{.*}} call { i32, i32, i32, i32 } asm "cpuid", "={ax},={bx},={cx},={dx},0,2,~{dirflag},~{fpsr},~{flags}"(i32 %{{[a-z0-9]+}}, i32 %{{[a-z0-9]+}})
+
+unsigned eax0, ebx0, ecx0, edx0;
+unsigned eax1, ebx1, ecx1, edx1;
+
+void test_cpuid(unsigned level, unsigned count) {
+ __cpuid(level, eax1, ebx1, ecx1, edx1);
+ __cpuid_count(level, count, eax0, ebx0, ecx0, edx0);
+}
diff --git a/test/Headers/cxx11.cpp b/test/Headers/cxx11.cpp
index 5b0ec0b79ccb..0b35a7c2bdfa 100644
--- a/test/Headers/cxx11.cpp
+++ b/test/Headers/cxx11.cpp
@@ -1,5 +1,6 @@
+// RUN: rm -rf %t
// RUN: %clang_cc1 -ffreestanding -fsyntax-only -std=c++11 %s
-// RUN: %clang_cc1 -ffreestanding -fsyntax-only -std=c++11 -fmodules %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -std=c++11 -fmodules -fmodules-cache-path=%t %s
// This test fails on systems with older OS X 10.9 SDK headers, see PR18322.
diff --git a/test/Headers/ms-intrin.cpp b/test/Headers/ms-intrin.cpp
index 68f436cf2479..a83225e37f8e 100644
--- a/test/Headers/ms-intrin.cpp
+++ b/test/Headers/ms-intrin.cpp
@@ -3,6 +3,11 @@
// RUN: -ffreestanding -fsyntax-only -Werror \
// RUN: -isystem %S/Inputs/include %s
+// RUN: %clang_cc1 -triple i386-pc-win32 -target-cpu broadwell \
+// RUN: -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
+// RUN: -ffreestanding -fsyntax-only -Werror \
+// RUN: -isystem %S/Inputs/include %s
+
// RUN: %clang_cc1 -triple x86_64-pc-win32 \
// RUN: -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -ffreestanding -fsyntax-only -Werror \
diff --git a/test/Headers/x86intrin.c b/test/Headers/x86intrin.c
index d095c00674e0..6a1608b756a0 100644
--- a/test/Headers/x86intrin.c
+++ b/test/Headers/x86intrin.c
@@ -84,6 +84,45 @@
#ifndef __RDRND__
#define __RDRND__
#endif
+#ifndef __SHA__
+#define __SHA__
+#endif
+#ifndef __ADX__
+#define __ADX__
+#endif
+#ifndef __TBM__
+#define __TBM__
+#endif
+#ifndef __RTM__
+#define __RTM__
+#endif
+#ifndef __PCLMUL__
+#define __PCLMUL__
+#endif
+#ifndef __FSGSBASE__
+#define __FSGSBASE__
+#endif
+#ifndef __AVX512F__
+#define __AVX512F__
+#endif
+#ifndef __AVX512VL__
+#define __AVX512VL__
+#endif
+#ifndef __AVX512BW__
+#define __AVX512BW__
+#endif
+#ifndef __AVX512ER__
+#define __AVX512ER__
+#endif
+#ifndef __AVX512PF__
+#define __AVX512PF__
+#endif
+#ifndef __AVX512DQ__
+#define __AVX512DQ__
+#endif
+#ifndef __AVX512CD__
+#define __AVX512CD__
+#endif
// Now include the metaheader that includes all x86 intrinsic headers.
#include <x86intrin.h>
diff --git a/test/Index/Inputs/complete-at-EOF.c b/test/Index/Inputs/complete-at-EOF.c
new file mode 100644
index 000000000000..8207f7205518
--- /dev/null
+++ b/test/Index/Inputs/complete-at-EOF.c
@@ -0,0 +1,3 @@
+#define CAKE 1
+
+typedef int foo;
diff --git a/test/Index/Inputs/declare-objc-predef.h b/test/Index/Inputs/declare-objc-predef.h
new file mode 100644
index 000000000000..6a03c4f88d21
--- /dev/null
+++ b/test/Index/Inputs/declare-objc-predef.h
@@ -0,0 +1,3 @@
+@class Protocol;
+typedef struct objc_class *Class
+@class id;
diff --git a/test/Index/Inputs/module-undef.h b/test/Index/Inputs/module-undef.h
new file mode 100644
index 000000000000..8212d755a0ff
--- /dev/null
+++ b/test/Index/Inputs/module-undef.h
@@ -0,0 +1,2 @@
+#define MY_MACRO 1
+#undef MY_MACRO
diff --git a/test/Index/Inputs/module.map b/test/Index/Inputs/module.map
index 8f24840c81f9..4bfc109a8b13 100644
--- a/test/Index/Inputs/module.map
+++ b/test/Index/Inputs/module.map
@@ -4,3 +4,5 @@ module ModuleNeedsVFS {
export *
}
framework module * { }
+
+module ModuleUndef { header "module-undef.h" }
diff --git a/test/Index/annotate-deep-statements.cpp b/test/Index/annotate-deep-statements.cpp
index c0a55f25e49d..1803c2bacf5e 100644
--- a/test/Index/annotate-deep-statements.cpp
+++ b/test/Index/annotate-deep-statements.cpp
@@ -3,8 +3,8 @@
// rdar://11979525
// Check that we don't get stack overflow trying to annotate an extremely deep AST.
-// AddressSanitizer increases stack usage.
-// REQUIRES: not_asan
+// AddressSanitizer and UndefinedBehaviorSanitizer increases stack usage.
+// REQUIRES: not_asan, not_ubsan
struct S {
S &operator()();
diff --git a/test/Index/attributes-cuda.cu b/test/Index/attributes-cuda.cu
index 953ef3d51fee..824bdb4c883f 100644
--- a/test/Index/attributes-cuda.cu
+++ b/test/Index/attributes-cuda.cu
@@ -3,6 +3,7 @@
__attribute__((device)) void f_device();
__attribute__((global)) void f_global();
__attribute__((constant)) int* g_constant;
+__attribute__((shared)) float *g_shared;
__attribute__((host)) void f_host();
// CHECK: attributes-cuda.cu:3:30: FunctionDecl=f_device:3:30
@@ -11,5 +12,7 @@ __attribute__((host)) void f_host();
// CHECK-NEXT: attributes-cuda.cu:4:16: attribute(global)
// CHECK: attributes-cuda.cu:5:32: VarDecl=g_constant:5:32 (Definition)
// CHECK-NEXT: attributes-cuda.cu:5:16: attribute(constant)
-// CHECK: attributes-cuda.cu:6:28: FunctionDecl=f_host:6:28
-// CHECK-NEXT: attributes-cuda.cu:6:16: attribute(host)
+// CHECK: attributes-cuda.cu:6:32: VarDecl=g_shared:6:32 (Definition)
+// CHECK-NEXT: attributes-cuda.cu:6:16: attribute(shared)
+// CHECK: attributes-cuda.cu:7:28: FunctionDecl=f_host:7:28
+// CHECK-NEXT: attributes-cuda.cu:7:16: attribute(host)
diff --git a/test/Index/comment-c-decls.c b/test/Index/comment-c-decls.c
index 371e453bef4f..2a99b36ea820 100644
--- a/test/Index/comment-c-decls.c
+++ b/test/Index/comment-c-decls.c
@@ -101,4 +101,4 @@ int (^Block) (int i, int j);
*\brief block declaration
*/
int (^Block1) (int i, int j) = ^(int i, int j) { return i + j; };
-// CHECK: <Declaration>int (^Block1)(int, int) = ^(int i, int j) {}</Declaration>
+// CHECK: <Declaration>int (^Block1)(int, int) = ^(int i, int j) {\n}</Declaration>
diff --git a/test/Index/comment-lots-of-unknown-commands.c b/test/Index/comment-lots-of-unknown-commands.c
new file mode 100644
index 000000000000..f0640effebcb
--- /dev/null
+++ b/test/Index/comment-lots-of-unknown-commands.c
@@ -0,0 +1,295 @@
+// RUN: c-index-test -test-load-source-reparse 1 local %s | FileCheck %s
+
+// See PR 21254. We had too few bits to encode command IDs so if you created
+// enough of them the ID codes would wrap around. This test creates commands up
+// to an ID of 258. Ideally we should check for large numbers, but that would
+// require a test source file which is megabytes in size. This is the test case
+// from the PR.
+
+/**
+@s
+@tr
+@y
+@tt
+@tg
+@alu
+@U
+@I
+@r
+@t0
+@t1
+@ur
+@S
+@E
+@pb
+@f
+@pe
+@lue
+@re
+@oa
+@l
+@x
+@R
+@ute
+@am
+@ei
+@oun
+@ou
+@nl
+@ien
+@fr
+@en
+@tet
+@le
+@L
+@os
+@A
+@ro
+@o
+@ho
+@ca
+@Tie
+@tl
+@g
+@hr
+@et
+@fro
+@ast
+@ae
+@nN
+@pc
+@tae
+@ws
+@ia
+@N
+@lc
+@psg
+@ta
+@t2
+@D
+@str
+@ra
+@t3
+@t
+@xt
+@eN
+@fe
+@rU
+@ar
+@eD
+@iE
+@se
+@st1
+@rr
+@ime
+@ft
+@lm
+@wD
+@wne
+@h
+@otn
+@use
+@roi
+@ldc
+@ln
+@d
+@ee
+@ep
+@us
+@ut
+@u
+@n
+@Nme
+@min
+@ma
+@pct
+@hd
+@be
+@It
+@id
+@cm
+@ua
+@fs
+@Al
+@axn
+@rt
+@to
+@is
+@fo
+@i
+@an
+@de
+@tel
+@nd
+@dic
+@Lo
+@il
+@tle
+@axt
+@ba
+@ust
+@ac
+@tpe
+@tpl
+@ctG
+@ru
+@m
+@tG
+@it
+@rh
+@G
+@rpc
+@el
+@er
+@w
+@eo
+@tx
+@oo
+@dD
+@dD
+*/
+void f();
+
+// CHECK: CommentAST=[
+// CHECK: (CXComment_FullComment
+// CHECK: (CXComment_Paragraph
+// CHECK: (CXComment_InlineCommand CommandName=[s] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tr] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[y] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tt] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tg] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[alu] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[U] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[I] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[r] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[t0] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[t1] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ur] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[S] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[E] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[pb] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[f] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[pe] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[lue] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[re] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[oa] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[l] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[x] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[R] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ute] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[am] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ei] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[oun] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ou] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[nl] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ien] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[fr] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[en] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tet] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[le] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[L] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[os] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[A] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ro] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[o] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ho] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ca] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[Tie] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tl] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[g] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[hr] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[et] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[fro] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ast] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ae] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[nN] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[pc] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tae] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ws] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ia] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[N] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[lc] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[psg] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ta] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[t2] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[D] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[str] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ra] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[t3] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[t] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[xt] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[eN] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[fe] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[rU] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ar] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[eD] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[iE] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[se] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[st1] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[rr] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ime] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ft] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[lm] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[wD] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[wne] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[h] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[otn] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[use] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[roi] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ldc] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ln] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[d] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ee] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ep] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[us] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ut] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[u] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[n] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[Nme] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[min] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ma] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[pct] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[hd] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[be] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[It] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[id] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[cm] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ua] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[fs] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[Al] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[axn] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[rt] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[to] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[is] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[fo] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[i] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[an] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[de] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tel] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[nd] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[dic] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[Lo] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[il] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tle] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[axt] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ba] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ust] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ac] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tpe] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tpl] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ctG] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[ru] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[m] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tG] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[it] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[rh] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[G] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[rpc] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[el] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[er] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[w] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[eo] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[tx] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[oo] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[dD] RenderNormal HasTrailingNewline)
+// CHECK: (CXComment_InlineCommand CommandName=[dD] RenderNormal)))]
diff --git a/test/Index/comment-to-html-xml-conversion.cpp b/test/Index/comment-to-html-xml-conversion.cpp
index 95e11c3bc348..f31061aa12ab 100644
--- a/test/Index/comment-to-html-xml-conversion.cpp
+++ b/test/Index/comment-to-html-xml-conversion.cpp
@@ -325,7 +325,7 @@ void test_cmd_param_6(int x1, ...);
template<typename T>
void test_cmd_tparam_1(T aaa);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_1:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>test_cmd_tparam_1</Name><USR>c:@FT@&gt;1#Ttest_cmd_tparam_1#t0.0#</USR><Declaration>template &lt;typename T&gt; void test_cmd_tparam_1(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_1:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>test_cmd_tparam_1</Name><USR>c:@FT@&gt;1#Ttest_cmd_tparam_1#t0.0#v#</USR><Declaration>template &lt;typename T&gt; void test_cmd_tparam_1(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -342,7 +342,7 @@ void test_cmd_tparam_1(T aaa);
template<typename T>
void test_cmd_tparam_2(T aaa);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_2:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>test_cmd_tparam_2</Name><USR>c:@FT@&gt;1#Ttest_cmd_tparam_2#t0.0#</USR><Declaration>template &lt;typename T&gt; void test_cmd_tparam_2(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_2:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>test_cmd_tparam_2</Name><USR>c:@FT@&gt;1#Ttest_cmd_tparam_2#t0.0#v#</USR><Declaration>template &lt;typename T&gt; void test_cmd_tparam_2(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -359,7 +359,7 @@ void test_cmd_tparam_2(T aaa);
template<typename T1, typename T2>
void test_cmd_tparam_3(T1 aaa, T2 bbb);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_3:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>test_cmd_tparam_3</Name><USR>c:@FT@&gt;2#T#Ttest_cmd_tparam_3#t0.0#t0.1#</USR><Declaration>template &lt;typename T1, typename T2&gt; void test_cmd_tparam_3(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_3:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>test_cmd_tparam_3</Name><USR>c:@FT@&gt;2#T#Ttest_cmd_tparam_3#t0.0#t0.1#v#</USR><Declaration>template &lt;typename T1, typename T2&gt; void test_cmd_tparam_3(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -379,7 +379,7 @@ void test_cmd_tparam_3(T1 aaa, T2 bbb);
template<typename T1, typename T2, int V>
void test_cmd_tparam_4(T1 aaa, T2 bbb);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_4:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd><dt class="tparam-name-index-2">V</dt><dd class="tparam-descr-index-2"> Ccc </dd><dt class="tparam-name-index-invalid">U</dt><dd class="tparam-descr-index-invalid"> Zzz </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>test_cmd_tparam_4</Name><USR>c:@FT@&gt;3#T#T#NItest_cmd_tparam_4#t0.0#t0.1#</USR><Declaration>template &lt;typename T1, typename T2, int V&gt;\nvoid test_cmd_tparam_4(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>V</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>U</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_4:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd><dt class="tparam-name-index-2">V</dt><dd class="tparam-descr-index-2"> Ccc </dd><dt class="tparam-name-index-invalid">U</dt><dd class="tparam-descr-index-invalid"> Zzz </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>test_cmd_tparam_4</Name><USR>c:@FT@&gt;3#T#T#NItest_cmd_tparam_4#t0.0#t0.1#v#</USR><Declaration>template &lt;typename T1, typename T2, int V&gt;\nvoid test_cmd_tparam_4(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>V</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>U</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -407,7 +407,7 @@ void test_cmd_tparam_4(T1 aaa, T2 bbb);
template<template<template<typename T> class TT, class C> class TTT>
void test_cmd_tparam_5();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_5:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">TTT</dt><dd class="tparam-descr-index-0"> Ddd </dd><dt class="tparam-name-index-other">C</dt><dd class="tparam-descr-index-other"> Ccc </dd><dt class="tparam-name-index-other">T</dt><dd class="tparam-descr-index-other"> Aaa </dd><dt class="tparam-name-index-other">TT</dt><dd class="tparam-descr-index-other"> Bbb</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>test_cmd_tparam_5</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Ttest_cmd_tparam_5#</USR><Declaration>template &lt;template &lt;template &lt;typename T&gt; class TT, class C&gt; class TTT&gt;\nvoid test_cmd_tparam_5()</Declaration><TemplateParameters><Parameter><Name>TTT</Name><Index>0</Index><Discussion><Para> Ddd </Para></Discussion></Parameter><Parameter><Name>C</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>T</Name><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>TT</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_5:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">TTT</dt><dd class="tparam-descr-index-0"> Ddd </dd><dt class="tparam-name-index-other">C</dt><dd class="tparam-descr-index-other"> Ccc </dd><dt class="tparam-name-index-other">T</dt><dd class="tparam-descr-index-other"> Aaa </dd><dt class="tparam-name-index-other">TT</dt><dd class="tparam-descr-index-other"> Bbb</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>test_cmd_tparam_5</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Ttest_cmd_tparam_5#v#</USR><Declaration>template &lt;template &lt;template &lt;typename T&gt; class TT, class C&gt; class TTT&gt;\nvoid test_cmd_tparam_5()</Declaration><TemplateParameters><Parameter><Name>TTT</Name><Index>0</Index><Discussion><Para> Ddd </Para></Discussion></Parameter><Parameter><Name>C</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>T</Name><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>TT</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -736,47 +736,47 @@ void comment_to_html_conversion_36();
/// Aaa.
class comment_to_xml_conversion_01 {
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01</USR><Declaration>class comment_to_xml_conversion_01 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>comment_to_xml_conversion_01</Name><USR>c:@S@comment_to_xml_conversion_01</USR><Declaration>class comment_to_xml_conversion_01 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
/// \param aaa Blah blah.
comment_to_xml_conversion_01(int aaa);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXConstructor=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_01#I#</USR><Declaration>comment_to_xml_conversion_01(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXConstructor=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>comment_to_xml_conversion_01</Name><USR>c:@S@comment_to_xml_conversion_01@F@comment_to_xml_conversion_01#I#</USR><Declaration>comment_to_xml_conversion_01(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
/// Aaa.
~comment_to_xml_conversion_01();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXDestructor=~comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>~comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01@F@~comment_to_xml_conversion_01#</USR><Declaration>~comment_to_xml_conversion_01()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXDestructor=~comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>~comment_to_xml_conversion_01</Name><USR>c:@S@comment_to_xml_conversion_01@F@~comment_to_xml_conversion_01#</USR><Declaration>~comment_to_xml_conversion_01()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
/// \param aaa Blah blah.
int comment_to_xml_conversion_02(int aaa);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: CXXMethod=comment_to_xml_conversion_02:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_02</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_02#I#</USR><Declaration>int comment_to_xml_conversion_02(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: CXXMethod=comment_to_xml_conversion_02:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_02</Name><USR>c:@S@comment_to_xml_conversion_01@F@comment_to_xml_conversion_02#I#</USR><Declaration>int comment_to_xml_conversion_02(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
/// \param aaa Blah blah.
static int comment_to_xml_conversion_03(int aaa);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:14: CXXMethod=comment_to_xml_conversion_03:{{.*}} FullCommentAsXML=[<Function isClassMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="14"><Name>comment_to_xml_conversion_03</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_03#I#S</USR><Declaration>static int comment_to_xml_conversion_03(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:14: CXXMethod=comment_to_xml_conversion_03:{{.*}} FullCommentAsXML=[<Function isClassMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="14"><Name>comment_to_xml_conversion_03</Name><USR>c:@S@comment_to_xml_conversion_01@F@comment_to_xml_conversion_03#I#S</USR><Declaration>static int comment_to_xml_conversion_03(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
/// Aaa.
int comment_to_xml_conversion_04;
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: FieldDecl=comment_to_xml_conversion_04:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_04</Name><USR>c:@C@comment_to_xml_conversion_01@FI@comment_to_xml_conversion_04</USR><Declaration>int comment_to_xml_conversion_04</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: FieldDecl=comment_to_xml_conversion_04:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_04</Name><USR>c:@S@comment_to_xml_conversion_01@FI@comment_to_xml_conversion_04</USR><Declaration>int comment_to_xml_conversion_04</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
/// Aaa.
static int comment_to_xml_conversion_05;
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:14: VarDecl=comment_to_xml_conversion_05:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="14"><Name>comment_to_xml_conversion_05</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_05</USR><Declaration>static int comment_to_xml_conversion_05</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:14: VarDecl=comment_to_xml_conversion_05:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="14"><Name>comment_to_xml_conversion_05</Name><USR>c:@S@comment_to_xml_conversion_01@comment_to_xml_conversion_05</USR><Declaration>static int comment_to_xml_conversion_05</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
/// \param aaa Blah blah.
void operator()(int aaa);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:8: CXXMethod=operator():{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="8"><Name>operator()</Name><USR>c:@C@comment_to_xml_conversion_01@F@operator()#I#</USR><Declaration>void operator()(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:8: CXXMethod=operator():{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="8"><Name>operator()</Name><USR>c:@S@comment_to_xml_conversion_01@F@operator()#I#</USR><Declaration>void operator()(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
/// Aaa.
operator bool();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXConversion=operator bool:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>operator bool</Name><USR>c:@C@comment_to_xml_conversion_01@F@operator bool#</USR><Declaration>operator bool()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXConversion=operator bool:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>operator bool</Name><USR>c:@S@comment_to_xml_conversion_01@F@operator bool#</USR><Declaration>operator bool()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
/// Aaa.
typedef int comment_to_xml_conversion_06;
@@ -787,26 +787,26 @@ class comment_to_xml_conversion_01 {
/// Aaa.
using comment_to_xml_conversion_07 = int;
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:9: TypeAliasDecl=comment_to_xml_conversion_07:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="9"><Name>comment_to_xml_conversion_07</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_07</USR><Declaration>using comment_to_xml_conversion_07 = int</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:9: TypeAliasDecl=comment_to_xml_conversion_07:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="9"><Name>comment_to_xml_conversion_07</Name><USR>c:@S@comment_to_xml_conversion_01@comment_to_xml_conversion_07</USR><Declaration>using comment_to_xml_conversion_07 = int</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
/// Aaa.
template<typename T, typename U>
class comment_to_xml_conversion_08 { };
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:9: ClassTemplate=comment_to_xml_conversion_08:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="9"><Name>comment_to_xml_conversion_08</Name><USR>c:@C@comment_to_xml_conversion_01@CT&gt;2#T#T@comment_to_xml_conversion_08</USR><Declaration>template &lt;typename T, typename U&gt; class comment_to_xml_conversion_08 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:9: ClassTemplate=comment_to_xml_conversion_08:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="9"><Name>comment_to_xml_conversion_08</Name><USR>c:@S@comment_to_xml_conversion_01@ST&gt;2#T#T@comment_to_xml_conversion_08</USR><Declaration>template &lt;typename T, typename U&gt; class comment_to_xml_conversion_08 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
/// Aaa.
template<typename T>
using comment_to_xml_conversion_09 = comment_to_xml_conversion_08<T, int>;
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: UnexposedDecl=comment_to_xml_conversion_09:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>comment_to_xml_conversion_09</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_09</USR><Declaration>template &lt;typename T&gt;\nusing comment_to_xml_conversion_09 = comment_to_xml_conversion_08&lt;T, int&gt;</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: UnexposedDecl=comment_to_xml_conversion_09:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>comment_to_xml_conversion_09</Name><USR>c:@S@comment_to_xml_conversion_01@comment_to_xml_conversion_09</USR><Declaration>template &lt;typename T&gt;\nusing comment_to_xml_conversion_09 = comment_to_xml_conversion_08&lt;T, int&gt;</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
};
/// Aaa.
template<typename T, typename U>
void comment_to_xml_conversion_10(T aaa, U bbb);
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_xml_conversion_10</Name><USR>c:@FT@&gt;2#T#Tcomment_to_xml_conversion_10#t0.0#t0.1#</USR><Declaration>template &lt;typename T, typename U&gt;\nvoid comment_to_xml_conversion_10(T aaa, U bbb)</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_xml_conversion_10</Name><USR>c:@FT@&gt;2#T#Tcomment_to_xml_conversion_10#t0.0#t0.1#v#</USR><Declaration>template &lt;typename T, typename U&gt;\nvoid comment_to_xml_conversion_10(T aaa, U bbb)</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
/// Aaa.
template<>
@@ -818,19 +818,19 @@ void comment_to_xml_conversion_10(int aaa, int bbb);
template<typename T, typename U>
class comment_to_xml_conversion_11 { };
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CT&gt;2#T#T@comment_to_xml_conversion_11</USR><Declaration>template &lt;typename T, typename U&gt; class comment_to_xml_conversion_11 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@ST&gt;2#T#T@comment_to_xml_conversion_11</USR><Declaration>template &lt;typename T, typename U&gt; class comment_to_xml_conversion_11 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
/// Aaa.
template<typename T>
class comment_to_xml_conversion_11<T, int> { };
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassTemplatePartialSpecialization=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="partialSpecialization" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CP&gt;1#T@comment_to_xml_conversion_11&gt;#t0.0#I</USR><Declaration>class comment_to_xml_conversion_11 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassTemplatePartialSpecialization=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="partialSpecialization" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@SP&gt;1#T@comment_to_xml_conversion_11&gt;#t0.0#I</USR><Declaration>class comment_to_xml_conversion_11 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
/// Aaa.
template<>
class comment_to_xml_conversion_11<int, int> { };
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassDecl=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="specialization" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@C@comment_to_xml_conversion_11&gt;#I#I</USR><Declaration>class comment_to_xml_conversion_11 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassDecl=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="specialization" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@S@comment_to_xml_conversion_11&gt;#I#I</USR><Declaration>class comment_to_xml_conversion_11 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
/// Aaa.
int comment_to_xml_conversion_12;
@@ -902,7 +902,7 @@ void comment_to_xml_conversion_unsafe_html_07();
class BaseToSuper1_Base {};
class BaseToSuper1_Derived : public BaseToSuper1_Base {};
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper1_Derived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper1_Base</Name><USR>c:@C@BaseToSuper1_Base</USR><Declaration>class BaseToSuper1_Derived : public BaseToSuper1_Base {}</Declaration><Abstract><Para> BaseToSuper1_Base</Para></Abstract></Class>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper1_Derived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper1_Base</Name><USR>c:@S@BaseToSuper1_Base</USR><Declaration>class BaseToSuper1_Derived : public BaseToSuper1_Base {}</Declaration><Abstract><Para> BaseToSuper1_Base</Para></Abstract></Class>]
/// BaseToSuper2_Base
@@ -910,10 +910,10 @@ class BaseToSuper2_Base {};
/// BaseToSuper2_Derived
class BaseToSuper2_Derived : public BaseToSuper2_Base {};
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper2_Derived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper2_Derived</Name><USR>c:@C@BaseToSuper2_Derived</USR><Declaration>class BaseToSuper2_Derived : public BaseToSuper2_Base {}</Declaration><Abstract><Para> BaseToSuper2_Derived</Para></Abstract></Class>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper2_Derived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper2_Derived</Name><USR>c:@S@BaseToSuper2_Derived</USR><Declaration>class BaseToSuper2_Derived : public BaseToSuper2_Base {}</Declaration><Abstract><Para> BaseToSuper2_Derived</Para></Abstract></Class>]
class BaseToSuper2_MoreDerived : public BaseToSuper2_Derived {};
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper2_MoreDerived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper2_Derived</Name><USR>c:@C@BaseToSuper2_Derived</USR><Declaration>class BaseToSuper2_MoreDerived : public BaseToSuper2_Derived {}</Declaration><Abstract><Para> BaseToSuper2_Derived</Para></Abstract></Class>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper2_MoreDerived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper2_Derived</Name><USR>c:@S@BaseToSuper2_Derived</USR><Declaration>class BaseToSuper2_MoreDerived : public BaseToSuper2_Derived {}</Declaration><Abstract><Para> BaseToSuper2_Derived</Para></Abstract></Class>]
/// BaseToSuper3_Base
@@ -924,7 +924,7 @@ class BaseToSuper3_DerivedA : public virtual BaseToSuper3_Base {};
class BaseToSuper3_DerivedB : public virtual BaseToSuper3_Base {};
class BaseToSuper3_MoreDerived : public BaseToSuper3_DerivedA, public BaseToSuper3_DerivedB {};
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper3_MoreDerived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper3_Base</Name><USR>c:@C@BaseToSuper3_Base</USR><Declaration>class BaseToSuper3_MoreDerived : public BaseToSuper3_DerivedA,\n public BaseToSuper3_DerivedB {}</Declaration><Abstract><Para> BaseToSuper3_Base</Para></Abstract></Class>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper3_MoreDerived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper3_Base</Name><USR>c:@S@BaseToSuper3_Base</USR><Declaration>class BaseToSuper3_MoreDerived : public BaseToSuper3_DerivedA,\n public BaseToSuper3_DerivedB {}</Declaration><Abstract><Para> BaseToSuper3_Base</Para></Abstract></Class>]
// Check that we propagate comments only through public inheritance.
@@ -938,7 +938,7 @@ class BaseToSuper4_DerivedA : virtual BaseToSuper4_Base {};
class BaseToSuper4_DerivedB : public virtual BaseToSuper4_Base {};
class BaseToSuper4_MoreDerived : BaseToSuper4_DerivedA, public BaseToSuper4_DerivedB {};
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper4_MoreDerived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper4_Base</Name><USR>c:@C@BaseToSuper4_Base</USR><Declaration>class BaseToSuper4_MoreDerived : BaseToSuper4_DerivedA,\n public BaseToSuper4_DerivedB {}</Declaration><Abstract><Para> BaseToSuper4_Base</Para></Abstract></Class>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=BaseToSuper4_MoreDerived:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>BaseToSuper4_Base</Name><USR>c:@S@BaseToSuper4_Base</USR><Declaration>class BaseToSuper4_MoreDerived : BaseToSuper4_DerivedA,\n public BaseToSuper4_DerivedB {}</Declaration><Abstract><Para> BaseToSuper4_Base</Para></Abstract></Class>]
//===---
// Check the representation of \todo in XML.
diff --git a/test/Index/complete-at-EOF.c b/test/Index/complete-at-EOF.c
new file mode 100644
index 000000000000..d039aaa1af18
--- /dev/null
+++ b/test/Index/complete-at-EOF.c
@@ -0,0 +1,9 @@
+
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test \
+// RUN: -code-completion-at=%S/Inputs/complete-at-EOF.c:4:1 %S/Inputs/complete-at-EOF.c | FileCheck -check-prefix=CHECK-EOF %s
+// CHECK-EOF: macro definition:{TypedText CAKE}
+// CHECK-EOF: TypedefDecl:{TypedText foo}
+
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test \
+// RUN: -code-completion-at=%S/Inputs/complete-at-EOF.c:2:1 %S/Inputs/complete-at-EOF.c | FileCheck -check-prefix=CHECK-AFTER-PREAMBLE %s
+// CHECK-AFTER-PREAMBLE: macro definition:{TypedText CAKE}
diff --git a/test/Index/complete-module-undef.m b/test/Index/complete-module-undef.m
new file mode 100644
index 000000000000..a9dd00096411
--- /dev/null
+++ b/test/Index/complete-module-undef.m
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: env CINDEXTEST_COMPLETION_CACHING=1 \
+// RUN: c-index-test -test-load-source-reparse 2 local %s -fmodules -fmodules-cache-path=%t -I %S/Inputs \
+// RUN: | FileCheck %s
+
+// rdar://18416901 (used to crash)
+// CHECK: complete-module-undef.m:8:1: ModuleImport=ModuleUndef:8:1 (Definition) Extent=[8:1 - 8:20]
+@import ModuleUndef;
diff --git a/test/Index/cursor-dynamic-call.mm b/test/Index/cursor-dynamic-call.mm
index ac9e6d351a0a..a926c3d03d47 100644
--- a/test/Index/cursor-dynamic-call.mm
+++ b/test/Index/cursor-dynamic-call.mm
@@ -37,6 +37,18 @@ void foo(SS *ss, IS* is, Class cls) {
[cls ClsMeth];
}
+@interface NSObject
++(id)alloc;
+-(id)init;
+@end
+
+@interface Test : NSObject
+@end
+
+void test2() {
+ id o = [[Test alloc] init];
+}
+
// RUN: c-index-test -cursor-at=%s:8:11 \
// RUN: -cursor-at=%s:9:11 \
// RUN: -cursor-at=%s:25:11 \
@@ -46,6 +58,7 @@ void foo(SS *ss, IS* is, Class cls) {
// RUN: -cursor-at=%s:35:9 \
// RUN: -cursor-at=%s:36:9 \
// RUN: -cursor-at=%s:37:9 \
+// RUN: -cursor-at=%s:49:26 \
// RUN: %s | FileCheck %s
// CHECK: 8:11 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call
@@ -59,3 +72,4 @@ void foo(SS *ss, IS* is, Class cls) {
// CHECK-NOT: 36:3 {{.*}} Dynamic-call
// CHECK: 36:3 {{.*}} Receiver-type=ObjCInterface
// CHECK: 37:3 ObjCMessageExpr=ClsMeth:15:8 {{.*}} Dynamic-call Receiver-type=ObjCClass
+// CHECK-NOT: 49:10 {{.*}} Dynamic-call
diff --git a/test/Index/cxx11-lambdas.cpp b/test/Index/cxx11-lambdas.cpp
index afb540a84d5f..d0ee908059fa 100644
--- a/test/Index/cxx11-lambdas.cpp
+++ b/test/Index/cxx11-lambdas.cpp
@@ -30,4 +30,4 @@ struct X {
// CHECK-INDEX: [indexEntityReference]: kind: typedef | name: Integer | USR: c:cxx11-lambdas.cpp@T@Integer | lang: C | cursor: TypeRef=Integer:3:13 | loc: 7:38
// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localA | USR: c:cxx11-lambdas.cpp@100@S@X@F@f#@localA | lang: C | cursor: DeclRefExpr=localA:6:9 | loc: 8:14
// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localB | USR: c:cxx11-lambdas.cpp@100@S@X@F@f#@localB | lang: C | cursor: DeclRefExpr=localB:6:17 | loc: 8:23
-// CHECK-INDEX: [indexEntityReference]: kind: variable | name: x | USR: c:cxx11-lambdas.cpp@157@S@X@F@f#@Ca@F@operator()#I#1@x | lang: C | cursor: DeclRefExpr=x:7:46 | loc: 8:32
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: x | USR: c:cxx11-lambdas.cpp@157@S@X@F@f#@Sa@F@operator()#I#1@x | lang: C | cursor: DeclRefExpr=x:7:46 | loc: 8:32
diff --git a/test/Index/format-comment-cdecls.c b/test/Index/format-comment-cdecls.c
index 471be2baf234..34cedfdb16b3 100644
--- a/test/Index/format-comment-cdecls.c
+++ b/test/Index/format-comment-cdecls.c
@@ -96,4 +96,4 @@ int (^Block) (int i, int j);
*\brief block declaration
*/
int (^Block1) (int i, int j) = ^(int i, int j) { return i + j; };
-// CHECK: <Declaration>int (^Block1)(int, int) = ^(int i, int j) {}</Declaration>
+// CHECK: <Declaration>int (^Block1)(int, int) = ^(int i, int j) {\n}</Declaration>
diff --git a/test/Index/get-cursor.cpp b/test/Index/get-cursor.cpp
index 996ecc25ef42..60aab5f7ed79 100644
--- a/test/Index/get-cursor.cpp
+++ b/test/Index/get-cursor.cpp
@@ -65,6 +65,84 @@ template<> void TC<char>::init();
#define EXTERN_TEMPLATE(...) extern template __VA_ARGS__;
EXTERN_TEMPLATE(class TC<char>)
+class A {
+ A();
+ virtual ~A();
+
+ // Assignment operators
+ A& operator=(const A&);
+ A& operator=(A&&) noexcept;
+
+ // Unary operators
+ A operator+() const;
+ A operator-() const;
+ A operator~() const;
+ A operator*() const;
+ A operator&() const;
+ bool operator!() const;
+
+ // (pre-|post-) increment and decrement
+ A& operator++();
+ A& operator--();
+ A operator++(int);
+ A operator--(int);
+
+ // Arithmetic operators
+ A operator+(const A&) const;
+ A operator-(const A&) const;
+ A operator*(const A&) const;
+ A operator/(const A&) const;
+ A operator%(const A&) const;
+ A operator&(const A&) const;
+ A operator|(const A&) const;
+ A operator^(const A&) const;
+
+ A operator<<(const A&) const;
+ A operator>>(const A&) const;
+
+ // Arithmetic-assignment operators
+ A& operator+=(const A&);
+ A& operator-=(const A&);
+ A& operator*=(const A&);
+ A& operator/=(const A&);
+ A& operator%=(const A&);
+ A& operator&=(const A&);
+ A& operator|=(const A&);
+ A& operator^=(const A&);
+
+ A& operator<<=(const A&);
+ A& operator>>=(const A&);
+
+ // Logical operators
+ bool operator<(const A&) const;
+ bool operator>(const A&) const;
+
+ bool operator&&(const A&) const;
+ bool operator||(const A&) const;
+ bool operator<=(const A&) const;
+ bool operator>=(const A&) const;
+ bool operator!=(const A&) const;
+ bool operator==(const A&) const;
+
+ // Special operators
+ A& operator[](unsigned long long);
+ A* operator->();
+ A operator()(unsigned, int) const;
+
+ explicit operator bool() const;
+};
+
+struct TestColl {
+ int* begin();
+ int* end();
+};
+
+void test(TestColl coll) {
+ for (auto lv : coll) {
+ (void)lv;
+ }
+}
+
// RUN: c-index-test -cursor-at=%s:6:4 %s | FileCheck -check-prefix=CHECK-COMPLETION-1 %s
// CHECK-COMPLETION-1: CXXConstructor=X:6:3
// CHECK-COMPLETION-1-NEXT: Completion string: {TypedText X}{LeftParen (}{Placeholder int}{Comma , }{Placeholder int}{RightParen )}
@@ -128,3 +206,56 @@ EXTERN_TEMPLATE(class TC<char>)
// RUN: c-index-test -cursor-at=%s:66:23 %s | FileCheck -check-prefix=CHECK-TEMPLSPEC %s
// CHECK-TEMPLSPEC: 66:23 ClassDecl=TC:66:23 (Definition) [Specialization of TC:59:7] Extent=[66:1 - 66:31] Spelling=TC ([66:23 - 66:25])
+
+// RUN: c-index-test -cursor-at=%s:69:3 -cursor-at=%s:70:11 -cursor-at=%s:73:6 -cursor-at=%s:74:6 -cursor-at=%s:77:8 -cursor-at=%s:78:8 -cursor-at=%s:79:8 -cursor-at=%s:80:8 -cursor-at=%s:81:8 -cursor-at=%s:82:8 -cursor-at=%s:85:6 -cursor-at=%s:86:6 -cursor-at=%s:87:6 -cursor-at=%s:88:6 -cursor-at=%s:91:5 -cursor-at=%s:92:5 -cursor-at=%s:93:5 -cursor-at=%s:94:5 -cursor-at=%s:95:5 -cursor-at=%s:96:5 -cursor-at=%s:97:5 -cursor-at=%s:98:5 -cursor-at=%s:100:5 -cursor-at=%s:101:5 -cursor-at=%s:104:6 -cursor-at=%s:105:6 -cursor-at=%s:106:6 -cursor-at=%s:107:6 -cursor-at=%s:108:6 -cursor-at=%s:109:6 -cursor-at=%s:110:6 -cursor-at=%s:111:6 -cursor-at=%s:113:6 -cursor-at=%s:114:6 -cursor-at=%s:117:8 -cursor-at=%s:118:8 -cursor-at=%s:120:8 -cursor-at=%s:121:8 -cursor-at=%s:122:8 -cursor-at=%s:123:8 -cursor-at=%s:124:8 -cursor-at=%s:125:8 -cursor-at=%s:128:6 -cursor-at=%s:129:6 -cursor-at=%s:130:6 -cursor-at=%s:132:3 -std=c++11 %s | FileCheck -check-prefix=CHECK-SPELLING %s
+// CHECK-SPELLING: 69:3 CXXConstructor=A:69:3 Extent=[69:3 - 69:6] Spelling=A ([69:3 - 69:4])
+// CHECK-SPELLING: 70:11 CXXDestructor=~A:70:11 (virtual) Extent=[70:3 - 70:15] Spelling=~A ([70:11 - 70:13])
+// CHECK-SPELLING: 73:6 CXXMethod=operator=:73:6 Extent=[73:3 - 73:25] Spelling=operator= ([73:6 - 73:15])
+// CHECK-SPELLING: 74:6 CXXMethod=operator=:74:6 Extent=[74:3 - 74:29] Spelling=operator= ([74:6 - 74:15])
+// CHECK-SPELLING: 77:8 CXXMethod=operator+:77:8 (const) Extent=[77:3 - 77:25] Spelling=operator+ ([77:8 - 77:17])
+// CHECK-SPELLING: 78:8 CXXMethod=operator-:78:8 (const) Extent=[78:3 - 78:25] Spelling=operator- ([78:8 - 78:17])
+// CHECK-SPELLING: 79:8 CXXMethod=operator~:79:8 (const) Extent=[79:3 - 79:25] Spelling=operator~ ([79:8 - 79:17])
+// CHECK-SPELLING: 80:8 CXXMethod=operator*:80:8 (const) Extent=[80:3 - 80:25] Spelling=operator* ([80:8 - 80:17])
+// CHECK-SPELLING: 81:8 CXXMethod=operator&:81:8 (const) Extent=[81:3 - 81:25] Spelling=operator& ([81:8 - 81:17])
+// CHECK-SPELLING: 82:8 CXXMethod=operator!:82:8 (const) Extent=[82:3 - 82:25] Spelling=operator! ([82:8 - 82:17])
+// CHECK-SPELLING: 85:6 CXXMethod=operator++:85:6 Extent=[85:3 - 85:18] Spelling=operator++ ([85:6 - 85:16])
+// CHECK-SPELLING: 86:6 CXXMethod=operator--:86:6 Extent=[86:3 - 86:18] Spelling=operator-- ([86:6 - 86:16])
+// CHECK-SPELLING: 87:6 CXXMethod=operator++:87:6 Extent=[87:3 - 87:21] Spelling=operator++ ([87:6 - 87:16])
+// CHECK-SPELLING: 88:6 CXXMethod=operator--:88:6 Extent=[88:3 - 88:21] Spelling=operator-- ([88:6 - 88:16])
+// CHECK-SPELLING: 91:5 CXXMethod=operator+:91:5 (const) Extent=[91:3 - 91:30] Spelling=operator+ ([91:5 - 91:14])
+// CHECK-SPELLING: 92:5 CXXMethod=operator-:92:5 (const) Extent=[92:3 - 92:30] Spelling=operator- ([92:5 - 92:14])
+// CHECK-SPELLING: 93:5 CXXMethod=operator*:93:5 (const) Extent=[93:3 - 93:30] Spelling=operator* ([93:5 - 93:14])
+// CHECK-SPELLING: 94:5 CXXMethod=operator/:94:5 (const) Extent=[94:3 - 94:30] Spelling=operator/ ([94:5 - 94:14])
+// CHECK-SPELLING: 95:5 CXXMethod=operator%:95:5 (const) Extent=[95:3 - 95:30] Spelling=operator% ([95:5 - 95:14])
+// CHECK-SPELLING: 96:5 CXXMethod=operator&:96:5 (const) Extent=[96:3 - 96:30] Spelling=operator& ([96:5 - 96:14])
+// CHECK-SPELLING: 97:5 CXXMethod=operator|:97:5 (const) Extent=[97:3 - 97:30] Spelling=operator| ([97:5 - 97:14])
+// CHECK-SPELLING: 98:5 CXXMethod=operator^:98:5 (const) Extent=[98:3 - 98:30] Spelling=operator^ ([98:5 - 98:14])
+// CHECK-SPELLING: 100:5 CXXMethod=operator<<:100:5 (const) Extent=[100:3 - 100:31] Spelling=operator<< ([100:5 - 100:15])
+// CHECK-SPELLING: 101:5 CXXMethod=operator>>:101:5 (const) Extent=[101:3 - 101:31] Spelling=operator>> ([101:5 - 101:15])
+// CHECK-SPELLING: 104:6 CXXMethod=operator+=:104:6 Extent=[104:3 - 104:26] Spelling=operator+= ([104:6 - 104:16])
+// CHECK-SPELLING: 105:6 CXXMethod=operator-=:105:6 Extent=[105:3 - 105:26] Spelling=operator-= ([105:6 - 105:16])
+// CHECK-SPELLING: 106:6 CXXMethod=operator*=:106:6 Extent=[106:3 - 106:26] Spelling=operator*= ([106:6 - 106:16])
+// CHECK-SPELLING: 107:6 CXXMethod=operator/=:107:6 Extent=[107:3 - 107:26] Spelling=operator/= ([107:6 - 107:16])
+// CHECK-SPELLING: 108:6 CXXMethod=operator%=:108:6 Extent=[108:3 - 108:26] Spelling=operator%= ([108:6 - 108:16])
+// CHECK-SPELLING: 109:6 CXXMethod=operator&=:109:6 Extent=[109:3 - 109:26] Spelling=operator&= ([109:6 - 109:16])
+// CHECK-SPELLING: 110:6 CXXMethod=operator|=:110:6 Extent=[110:3 - 110:26] Spelling=operator|= ([110:6 - 110:16])
+// CHECK-SPELLING: 111:6 CXXMethod=operator^=:111:6 Extent=[111:3 - 111:26] Spelling=operator^= ([111:6 - 111:16])
+// CHECK-SPELLING: 113:6 CXXMethod=operator<<=:113:6 Extent=[113:3 - 113:27] Spelling=operator<<= ([113:6 - 113:17])
+// CHECK-SPELLING: 114:6 CXXMethod=operator>>=:114:6 Extent=[114:3 - 114:27] Spelling=operator>>= ([114:6 - 114:17])
+// CHECK-SPELLING: 117:8 CXXMethod=operator<:117:8 (const) Extent=[117:3 - 117:33] Spelling=operator< ([117:8 - 117:17])
+// CHECK-SPELLING: 118:8 CXXMethod=operator>:118:8 (const) Extent=[118:3 - 118:33] Spelling=operator> ([118:8 - 118:17])
+// CHECK-SPELLING: 120:8 CXXMethod=operator&&:120:8 (const) Extent=[120:3 - 120:34] Spelling=operator&& ([120:8 - 120:18])
+// CHECK-SPELLING: 121:8 CXXMethod=operator||:121:8 (const) Extent=[121:3 - 121:34] Spelling=operator|| ([121:8 - 121:18])
+// CHECK-SPELLING: 122:8 CXXMethod=operator<=:122:8 (const) Extent=[122:3 - 122:34] Spelling=operator<= ([122:8 - 122:18])
+// CHECK-SPELLING: 123:8 CXXMethod=operator>=:123:8 (const) Extent=[123:3 - 123:34] Spelling=operator>= ([123:8 - 123:18])
+// CHECK-SPELLING: 124:8 CXXMethod=operator!=:124:8 (const) Extent=[124:3 - 124:34] Spelling=operator!= ([124:8 - 124:18])
+// CHECK-SPELLING: 125:8 CXXMethod=operator==:125:8 (const) Extent=[125:3 - 125:34] Spelling=operator== ([125:8 - 125:18])
+// CHECK-SPELLING: 128:6 CXXMethod=operator[]:128:6 Extent=[128:3 - 128:36] Spelling=operator[] ([128:6 - 128:16])
+// CHECK-SPELLING: 129:6 CXXMethod=operator->:129:6 Extent=[129:3 - 129:18] Spelling=operator-> ([129:6 - 129:16])
+// CHECK-SPELLING: 130:6 CXXMethod=operator():130:6 (const) Extent=[130:3 - 130:37] Spelling=operator() ([130:6 - 130:16])
+// CHECK-SPELLING: 132:12 CXXConversion=operator bool:132:12 (const) Extent=[132:3 - 132:33] Spelling=operator bool ([132:12 - 132:25])
+
+// RUN: c-index-test -cursor-at=%s:141:13 -cursor-at=%s:141:18 -cursor-at=%s:142:11 -std=c++11 %s | FileCheck -check-prefix=CHECK-FORRANGE %s
+// CHECK-FORRANGE: 141:13 VarDecl=lv:141:13 (Definition) Extent=[141:8 - 141:17] Spelling=lv ([141:13 - 141:15])
+// CHECK-FORRANGE: 141:18 DeclRefExpr=coll:140:20 Extent=[141:18 - 141:22] Spelling=coll ([141:18 - 141:22])
+// CHECK-FORRANGE: 142:11 DeclRefExpr=lv:141:13 Extent=[142:11 - 142:13] Spelling=lv ([142:11 - 142:13])
diff --git a/test/Index/index-many-call-ops.cpp b/test/Index/index-many-call-ops.cpp
index e732b5f188ae..7644697d4e7c 100644
--- a/test/Index/index-many-call-ops.cpp
+++ b/test/Index/index-many-call-ops.cpp
@@ -4,6 +4,9 @@
// Check that we don't get stack overflow trying to index a huge number of
// call operators.
+// UBSan increses stack usage.
+// REQUIRES: not_ubsan
+
struct S {
S &operator()();
};
diff --git a/test/Index/index-many-logical-ops.c b/test/Index/index-many-logical-ops.c
index 67017decb777..0fd4e75236f1 100644
--- a/test/Index/index-many-logical-ops.c
+++ b/test/Index/index-many-logical-ops.c
@@ -4,6 +4,9 @@
// Check that we don't get stack overflow trying to index a huge number of
// logical operators.
+// UBSan increses stack usage.
+// REQUIRES: not_ubsan
+
// CHECK: [indexDeclaration]: kind: function | name: foo
int foo(int x) {
return
diff --git a/test/Index/index-module.m b/test/Index/index-module.m
index 8e0155607dda..8ed7a84e2e1a 100644
--- a/test/Index/index-module.m
+++ b/test/Index/index-module.m
@@ -40,7 +40,7 @@ int glob;
// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMOD_MODULE_H:.*/Modules/Inputs/Module\.framework[/\\]Headers[/\\]Module\.h]] | {{.*}} | hash loc: <invalid>
// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMODHDR:.*/Modules/Inputs/Module.framework[/\\]Headers.]]Sub.h | name: "Module/Sub.h" | hash loc: [[TMOD_MODULE_H]]:23:1 | isImport: 0 | isAngled: 1
// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMODHDR]]Sub2.h | name: "Module/Sub2.h" | hash loc: [[TMODHDR]]Sub.h:1:1 | isImport: 0 | isAngled: 1
-// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMODHDR]]Buried/Treasure.h | name: "Module/Buried/Treasure.h" | hash loc: [[TMOD_MODULE_H]]:24:1 | isImport: 0 | isAngled: 1
+// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMODHDR]]Buried{{[/\\]}}Treasure.h | name: "Module/Buried/Treasure.h" | hash loc: [[TMOD_MODULE_H]]:24:1 | isImport: 0 | isAngled: 1
// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMOD_SUB_H:.*[/\\]Modules[/\\]Inputs[/\\]Module\.framework[/\\]Frameworks[/\\]SubFramework\.framework[/\\]Headers[/\\]SubFramework\.h]] | {{.*}} | hash loc: <invalid>
// CHECK-TMOD-NEXT: [indexDeclaration]: kind: function | name: getModuleVersion | {{.*}} | loc: [[TMOD_MODULE_H]]:9:13
// CHECK-TMOD-NEXT: [indexDeclaration]: kind: objc-class | name: Module | {{.*}} | loc: [[TMOD_MODULE_H]]:15:12
@@ -52,6 +52,6 @@ int glob;
// CHECK-TMOD-NEXT: [importedASTFile]: [[PCM]] | loc: [[TMODHDR]]Sub.h:1:2 | name: "Module.Sub2" | isImplicit: 1
// CHECK-TMOD-NEXT: [indexDeclaration]: kind: variable | name: Module_Sub | {{.*}} | loc: [[TMODHDR]]Sub.h:2:6
// CHECK-TMOD-NEXT: [indexDeclaration]: kind: variable | name: Module_Sub2 | USR: c:@Module_Sub2 | {{.*}} | loc: [[TMODHDR]]Sub2.h:1:6
-// CHECK-TMOD-NEXT: [indexDeclaration]: kind: variable | name: Buried_Treasure | {{.*}} | loc: [[TMODHDR]]Buried/Treasure.h:1:11
+// CHECK-TMOD-NEXT: [indexDeclaration]: kind: variable | name: Buried_Treasure | {{.*}} | loc: [[TMODHDR]]Buried{{[/\\]}}Treasure.h:1:11
// CHECK-TMOD-NEXT: [indexDeclaration]: kind: variable | name: module_subframework | {{.*}} | loc: [[TMOD_SUB_H]]:4:7
// CHECK-TMOD-NOT: [indexDeclaration]
diff --git a/test/Index/index-templates.cpp b/test/Index/index-templates.cpp
index 5fcb652cea1a..570d7cf15d4d 100644
--- a/test/Index/index-templates.cpp
+++ b/test/Index/index-templates.cpp
@@ -100,6 +100,16 @@ template class Pair<int, int>;
template<typename T, typename U>
struct SuperPair : Pair<int, int>, Pair<T, U> { };
+enum FxnTmplEnum {
+ FxnTmplEnum_A, FxnTmplEnum_B, FxnTmplEnum_C,
+};
+template <typename T, int I, FxnTmplEnum, int E>
+void foo(T Value) {}
+
+static const int FxnTmpl_Var = 7;
+template <>
+void foo<float, 9, FxnTmplEnum_B, FxnTmpl_Var + 7>(float Value);
+
// RUN: c-index-test -test-load-source all -fno-delayed-template-parsing %s | FileCheck -check-prefix=CHECK-LOAD %s
// CHECK-LOAD: index-templates.cpp:4:6: FunctionTemplate=f:4:6 Extent=[3:1 - 4:22]
// CHECK-LOAD: index-templates.cpp:3:19: TemplateTypeParameter=T:3:19 (Definition) Extent=[3:10 - 3:20]
@@ -178,30 +188,30 @@ struct SuperPair : Pair<int, int>, Pair<T, U> { };
// CHECK-LOAD: index-templates.cpp:100:31: TemplateTypeParameter=U:100:31 (Definition) Extent=[100:22 - 100:32]
// CHECK-LOAD: index-templates.cpp:101:20: C++ base class specifier=Pair<int, int>:98:16 [access=public isVirtual=false] Extent=[101:20 - 101:34]
// CHECK-LOAD: index-templates.cpp:101:36: C++ base class specifier=Pair<T, U>:76:8 [access=public isVirtual=false] Extent=[101:36 - 101:46]
-
+// CHECK-LOAD: index-templates.cpp:111:6: FunctionDecl=foo:111:6 [Specialization of foo:107:6] [Template arg 0: kind: 1, type: float] [Template arg 1: kind: 4, intval: 9] [Template arg 2: kind: 4, intval: 1] [Template arg 3: kind: 4, intval: 14] Extent=[110:1 - 111:64]
// RUN: c-index-test -test-load-source-usrs all -fno-delayed-template-parsing %s | FileCheck -check-prefix=CHECK-USRS %s
-// CHECK-USRS: index-templates.cpp c:@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22S0_# Extent=[3:1 - 4:22]
+// CHECK-USRS: index-templates.cpp c:@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22S0_#v# Extent=[3:1 - 4:22]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@70 Extent=[3:10 - 3:20]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@82 Extent=[3:22 - 3:29]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@91 Extent=[3:31 - 3:67]
-// CHECK-USRS: index-templates.cpp c:index-templates.cpp@136@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22S0_#@x Extent=[4:8 - 4:21]
-// CHECK-USRS: index-templates.cpp c:@CT>1#T@allocator Extent=[6:1 - 6:37]
+// CHECK-USRS: index-templates.cpp c:index-templates.cpp@136@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22S0_#v#@x Extent=[4:8 - 4:21]
+// CHECK-USRS: index-templates.cpp c:@ST>1#T@allocator Extent=[6:1 - 6:37]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@162 Extent=[6:10 - 6:20]
-// CHECK-USRS: index-templates.cpp c:@CT>2#T#T@vector Extent=[8:1 - 11:2]
+// CHECK-USRS: index-templates.cpp c:@ST>2#T#T@vector Extent=[8:1 - 11:2]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@201 Extent=[8:10 - 8:20]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@213 Extent=[8:22 - 8:51]
-// CHECK-USRS: index-templates.cpp c:@CT>2#T#T@vector@F@clear# Extent=[10:3 - 10:15]
-// CHECK-USRS: index-templates.cpp c:@CP>1#T@vector>#*t0.0#>@CT>1#T@allocator1S0_ Extent=[13:1 - 14:21]
+// CHECK-USRS: index-templates.cpp c:@ST>2#T#T@vector@F@clear# Extent=[10:3 - 10:15]
+// CHECK-USRS: index-templates.cpp c:@SP>1#T@vector>#*t0.0#>@ST>1#T@allocator1S0_ Extent=[13:1 - 14:21]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@289 Extent=[13:10 - 13:20]
// CHECK-USRS: index-templates.cpp c:@S@Z1 Extent=[16:1 - 16:14]
-// CHECK-USRS: index-templates.cpp c:@C@vector>#$@S@Z1#$@C@allocator>#S0_ Extent=[18:1 - 18:26]
+// CHECK-USRS: index-templates.cpp c:@S@vector>#$@S@Z1#$@S@allocator>#S0_ Extent=[18:1 - 18:26]
// CHECK-USRS: index-templates.cpp c:@S@Z2 Extent=[20:1 - 20:14]
-// CHECK-USRS: index-templates.cpp c:@C@vector>#$@S@Z2#$@C@allocator>#S0_ Extent=[22:1 - 25:2]
-// CHECK-USRS: index-templates.cpp c:@C@vector>#$@S@Z2#$@C@allocator>#S0_@F@clear# Extent=[24:3 - 24:15]
+// CHECK-USRS: index-templates.cpp c:@S@vector>#$@S@Z2#$@S@allocator>#S0_ Extent=[22:1 - 25:2]
+// CHECK-USRS: index-templates.cpp c:@S@vector>#$@S@Z2#$@S@allocator>#S0_@F@clear# Extent=[24:3 - 24:15]
// CHECK-USRS: index-templates.cpp c:@ST>2#T#T@Y Extent=[27:1 - 31:2]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@443 Extent=[27:10 - 27:20]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@455 Extent=[27:22 - 27:32]
// CHECK-USRS-NOT: type
// CHECK-USRS: index-templates.cpp c:@S@Z3 Extent=[33:1 - 33:14]
-// CHECK-USRS: index-templates.cpp c:@F@f#$@S@map>#$@S@Z4#$@S@Pair>#I#S1_#$@S@compare>#$@S@Pair>#S1_#S2_#$@C@allocator>#S4_#
+// CHECK-USRS: index-templates.cpp c:@F@f#$@S@map>#$@S@Z4#$@S@Pair>#I#S1_#$@S@compare>#$@S@Pair>#S1_#S2_#$@S@allocator>#S4_#
diff --git a/test/Index/overriding-ftemplate-comments.cpp b/test/Index/overriding-ftemplate-comments.cpp
index 0bc3c2f0ae8e..7fc15f0b00bd 100644
--- a/test/Index/overriding-ftemplate-comments.cpp
+++ b/test/Index/overriding-ftemplate-comments.cpp
@@ -13,12 +13,12 @@
template<typename T>
void comment_to_html_conversion_17(T AAA);
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T AAA)</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#v#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T AAA)</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
template<typename T>
void comment_to_html_conversion_17(T PPP);
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T PPP)</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#v#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T PPP)</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
//===----------------------------------------------------------------------===//
@@ -27,12 +27,12 @@ void comment_to_html_conversion_17(T PPP);
template<typename AAA, typename BBB>
void comment_to_html_conversion_19(AAA aaa, BBB bbb);
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#</USR><Declaration>template &lt;typename AAA, typename BBB&gt;\nvoid comment_to_html_conversion_19(AAA aaa, BBB bbb)</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#v#</USR><Declaration>template &lt;typename AAA, typename BBB&gt;\nvoid comment_to_html_conversion_19(AAA aaa, BBB bbb)</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
template<typename PPP, typename QQQ>
void comment_to_html_conversion_19(PPP aaa, QQQ bbb);
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#</USR><Declaration>template &lt;typename PPP, typename QQQ&gt;\nvoid comment_to_html_conversion_19(PPP aaa, QQQ bbb)</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#v#</USR><Declaration>template &lt;typename PPP, typename QQQ&gt;\nvoid comment_to_html_conversion_19(PPP aaa, QQQ bbb)</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
//===----------------------------------------------------------------------===//
@@ -43,12 +43,12 @@ void comment_to_html_conversion_19(PPP aaa, QQQ bbb);
template<typename AAA, typename BBB, int CCC>
void comment_to_html_conversion_20(AAA aaa, BBB bbb);
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#</USR><Declaration>template &lt;typename AAA, typename BBB, int CCC&gt;\nvoid comment_to_html_conversion_20(AAA aaa, BBB bbb)</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>UUU</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#v#</USR><Declaration>template &lt;typename AAA, typename BBB, int CCC&gt;\nvoid comment_to_html_conversion_20(AAA aaa, BBB bbb)</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>UUU</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
template<typename PPP, typename QQQ, int RRR>
void comment_to_html_conversion_20(PPP aaa, QQQ bbb);
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#</USR><Declaration>template &lt;typename PPP, typename QQQ, int RRR&gt;\nvoid comment_to_html_conversion_20(PPP aaa, QQQ bbb)</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>UUU</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#v#</USR><Declaration>template &lt;typename PPP, typename QQQ, int RRR&gt;\nvoid comment_to_html_conversion_20(PPP aaa, QQQ bbb)</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>UUU</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
//===----------------------------------------------------------------------===//
@@ -59,12 +59,12 @@ void comment_to_html_conversion_20(PPP aaa, QQQ bbb);
template<template<template<typename CCC> class DDD, class BBB> class AAA>
void comment_to_html_conversion_21();
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#</USR><Declaration>template &lt;template &lt;template &lt;typename CCC&gt; class DDD, class BBB&gt; class AAA&gt;\nvoid comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>DDD</Name><Discussion><Para> Ddd</Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#v#</USR><Declaration>template &lt;template &lt;template &lt;typename CCC&gt; class DDD, class BBB&gt; class AAA&gt;\nvoid comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>DDD</Name><Discussion><Para> Ddd</Para></Discussion></Parameter></TemplateParameters></Function>]
template<template<template<typename RRR> class SSS, class QQQ> class PPP>
void comment_to_html_conversion_21();
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#</USR><Declaration>template &lt;template &lt;template &lt;typename RRR&gt; class SSS, class QQQ&gt; class PPP&gt;\nvoid comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>SSS</Name><Discussion><Para> Ddd</Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#v#</USR><Declaration>template &lt;template &lt;template &lt;typename RRR&gt; class SSS, class QQQ&gt; class PPP&gt;\nvoid comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>SSS</Name><Discussion><Para> Ddd</Para></Discussion></Parameter></TemplateParameters></Function>]
//===----------------------------------------------------------------------===//
@@ -77,10 +77,10 @@ void comment_to_html_conversion_21();
template <class C1, template <class C2, template <class C3, class C4> class BBB > class AAA>
void comment_to_html_conversion_22();
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#</USR><Declaration>template &lt;class C1, template &lt;class C2, template &lt;class C3, class C4&gt; class BBB&gt;\n class AAA&gt;\nvoid comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>C1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>AAA</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>C2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>C3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>C4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#v#</USR><Declaration>template &lt;class C1, template &lt;class C2, template &lt;class C3, class C4&gt; class BBB&gt;\n class AAA&gt;\nvoid comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>C1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>AAA</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>C2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>C3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>C4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
template<class CCC1, template<class CCC2, template<class CCC3, class CCC4> class QQQ> class PPP>
void comment_to_html_conversion_22();
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#</USR><Declaration>template &lt;class CCC1, template &lt;class CCC2, template &lt;class CCC3, class CCC4&gt;\n class QQQ&gt; class PPP&gt;\nvoid comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>CCC1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>PPP</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>CCC2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>CCC3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>CCC4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#v#</USR><Declaration>template &lt;class CCC1, template &lt;class CCC2, template &lt;class CCC3, class CCC4&gt;\n class QQQ&gt; class PPP&gt;\nvoid comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>CCC1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>PPP</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>CCC2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>CCC3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>CCC4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
diff --git a/test/Index/overriding-method-comments.mm b/test/Index/overriding-method-comments.mm
index 9285693396e0..d995e0eca782 100644
--- a/test/Index/overriding-method-comments.mm
+++ b/test/Index/overriding-method-comments.mm
@@ -116,10 +116,10 @@ void foo1(int TTT);
template<typename AAA, typename BBB>
void foo(AAA, BBB);
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="6"><Name>foo</Name><USR>c:@FT@&gt;2#T#Tfoo#t0.0#t0.1#</USR><Declaration>template &lt;typename AAA, typename BBB&gt; void foo(AAA, BBB)</Declaration><Abstract><Para> Documentation </Para></Abstract><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> The type, silly as well.</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> The type, silly. </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="6"><Name>foo</Name><USR>c:@FT@&gt;2#T#Tfoo#t0.0#t0.1#v#</USR><Declaration>template &lt;typename AAA, typename BBB&gt; void foo(AAA, BBB)</Declaration><Abstract><Para> Documentation </Para></Abstract><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> The type, silly as well.</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> The type, silly. </Para></Discussion></Parameter></TemplateParameters></Function>]
template<typename PPP, typename QQQ>
void foo(PPP, QQQ);
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="6"><Name>foo</Name><USR>c:@FT@&gt;2#T#Tfoo#t0.0#t0.1#</USR><Declaration>template &lt;typename PPP, typename QQQ&gt; void foo(PPP, QQQ)</Declaration><Abstract><Para> Documentation </Para></Abstract><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> The type, silly as well.</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> The type, silly. </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="6"><Name>foo</Name><USR>c:@FT@&gt;2#T#Tfoo#t0.0#t0.1#v#</USR><Declaration>template &lt;typename PPP, typename QQQ&gt; void foo(PPP, QQQ)</Declaration><Abstract><Para> Documentation </Para></Abstract><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> The type, silly as well.</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> The type, silly. </Para></Discussion></Parameter></TemplateParameters></Function>]
diff --git a/test/Index/preamble_macro_template.cpp b/test/Index/preamble_macro_template.cpp
index 20f16b5df2eb..0771caba2377 100644
--- a/test/Index/preamble_macro_template.cpp
+++ b/test/Index/preamble_macro_template.cpp
@@ -4,7 +4,7 @@ int main() { }
// RUN: c-index-test -write-pch %t.pch -fno-delayed-template-parsing -x c++-header %S/Inputs/preamble_macro_template.h
// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -fno-delayed-template-parsing -I %S/Inputs -include %t %s 2>&1 | tee %t.check.txt | FileCheck %s
-// CHECK: preamble_macro_template.h:4:6: FunctionDecl=foo:4:6 (Definition) [Specialization of foo:4:6] Extent=[4:1 - 6:2]
+// CHECK: preamble_macro_template.h:4:6: FunctionDecl=foo:4:6 (Definition) [Specialization of foo:4:6] [Template arg 0: kind: 1, type: int] Extent=[4:1 - 6:2]
// CHECK: preamble_macro_template.h:4:13: ParmDecl=p:4:13 (Definition) Extent=[4:10 - 4:14]
// CHECK: preamble_macro_template.h:4:16: CompoundStmt= Extent=[4:16 - 6:2]
// CHECK: preamble_macro_template.h:5:3: CStyleCastExpr= Extent=[5:3 - 5:27]
diff --git a/test/Index/print-mangled-name.cpp b/test/Index/print-mangled-name.cpp
new file mode 100644
index 000000000000..b7e79c3f6d65
--- /dev/null
+++ b/test/Index/print-mangled-name.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -emit-pch %s -o %t_linux.ast
+// RUN: c-index-test -test-print-mangle %t_linux.ast | FileCheck %s --check-prefix=ITANIUM
+
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-pch %s -o %t_macho.ast
+// RUN: c-index-test -test-print-mangle %t_macho.ast | FileCheck %s --check-prefix=MACHO
+
+// RUN: %clang_cc1 -triple i686-pc-win32 -emit-pch %s -o %t_msft.ast
+// RUN: c-index-test -test-print-mangle %t_msft.ast | FileCheck %s --check-prefix=MICROSOFT
+
+int foo(int, int);
+// ITANIUM: mangled=_Z3fooii
+// MACHO: mangled=__Z3fooii
+// MICROSOFT: mangled=?foo@@YAHHH
+
+int foo(float, int);
+// ITANIUM: mangled=_Z3foofi
+// MACHO: mangled=__Z3foofi
+// MICROSOFT: mangled=?foo@@YAHMH
+
+struct S {
+ int x, y;
+};
+// ITANIUM: StructDecl{{.*}}mangled=]
+// MACHO: StructDecl{{.*}}mangled=]
+// MICROSOFT: StructDecl{{.*}}mangled=]
+
+int foo(S, S&);
+// ITANIUM: mangled=_Z3foo1SRS_
+// MACHO: mangled=__Z3foo1SRS_
+// MICROSOFT: mangled=?foo@@YAHUS
diff --git a/test/Index/reparse-predef-objc-protocol.m b/test/Index/reparse-predef-objc-protocol.m
new file mode 100644
index 000000000000..fc9d8572e0c1
--- /dev/null
+++ b/test/Index/reparse-predef-objc-protocol.m
@@ -0,0 +1,9 @@
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 3 local %s -I %S/Inputs
+#import "declare-objc-predef.h"
+// PR20633
+
+// CHECK: declare-objc-predef.h:1:8: ObjCInterfaceDecl=Protocol:1:8 Extent=[1:1 - 1:16]
+// CHECK: declare-objc-predef.h:1:8: ObjCClassRef=Protocol:1:8 Extent=[1:8 - 1:16]
+// CHECK: declare-objc-predef.h:2:16: StructDecl=objc_class:2:16 Extent=[2:9 - 2:26]
+// CHECK: declare-objc-predef.h:2:28: TypedefDecl=Class:2:28 (Definition) Extent=[2:1 - 2:33]
+// CHECK: declare-objc-predef.h:2:16: TypeRef=struct objc_class:2:16 Extent=[2:16 - 2:26]
diff --git a/test/Index/skip-parsed-bodies/compile_commands.json b/test/Index/skip-parsed-bodies/compile_commands.json
index da5e777d8181..6707e84d2642 100644
--- a/test/Index/skip-parsed-bodies/compile_commands.json
+++ b/test/Index/skip-parsed-bodies/compile_commands.json
@@ -16,7 +16,7 @@
}
]
-// XFAIL: mingw32,win32
+// XFAIL: mingw32,win32,windows-gnu
// RUN: c-index-test -index-compile-db %s | FileCheck %s
// CHECK: [enteredMainFile]: t1.cpp
diff --git a/test/Index/usrs-cxx0x.cpp b/test/Index/usrs-cxx0x.cpp
index a48b4467b731..b40bc4c12c7b 100644
--- a/test/Index/usrs-cxx0x.cpp
+++ b/test/Index/usrs-cxx0x.cpp
@@ -3,6 +3,16 @@ struct tuple { };
void f(tuple<int, float, double>);
+class TestCls {
+ void meth() &;
+ void meth() &&;
+ void meth(int&&);
+};
+
// RUN: c-index-test -test-load-source-usrs all -std=c++11 %s | FileCheck %s
// CHECK: usrs-cxx0x.cpp c:@ST>1#pT@tuple Extent=[1:1 - 2:17]
// CHECK: usrs-cxx0x.cpp c:@F@f#$@S@tuple>#p3Ifd# Extent=[4:1 - 4:34]
+
+// CHECK: usrs-cxx0x.cpp c:@S@TestCls@F@meth#& Extent=[7:3 - 7:16]
+// CHECK: usrs-cxx0x.cpp c:@S@TestCls@F@meth#&& Extent=[8:3 - 8:17]
+// CHECK: usrs-cxx0x.cpp c:@S@TestCls@F@meth#&&I# Extent=[9:3 - 9:19]
diff --git a/test/Index/usrs.cpp b/test/Index/usrs.cpp
index 909ce75922a9..8ad17021b50d 100644
--- a/test/Index/usrs.cpp
+++ b/test/Index/usrs.cpp
@@ -79,7 +79,23 @@ void rdar9371763() {
foo.bar();
}
-// RUN: c-index-test -test-load-source-usrs all %s | FileCheck %s
+template <class T> typename T::A someTemplFn() {}
+template <class T> typename T::B someTemplFn() {}
+template <class T> int someTemplFn() {}
+
+void funWithChar(char c) {}
+void funWithChar(unsigned char c) {}
+void funWithChar(signed char c) {}
+
+struct { int x; } embedS1;
+struct { int x; } embedS2;
+
+template <typename T>
+class TC1 {
+ void meth(TC1);
+};
+
+// RUN: c-index-test -test-load-source-usrs all -fno-delayed-template-parsing %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]
// CHECK: usrs.cpp c:@N@foo@F@bar#I# Extent=[3:3 - 3:18]
@@ -88,20 +104,20 @@ void rdar9371763() {
// CHECK: usrs.cpp c:usrs.cpp@N@bar@T@QType Extent=[6:3 - 6:20]
// CHECK: usrs.cpp c:@N@bar@F@bar#I# Extent=[7:3 - 7:20]
// CHECK: usrs.cpp c:usrs.cpp@94@N@bar@F@bar#I#@z Extent=[7:12 - 7:19]
-// CHECK: usrs.cpp c:@C@ClsA Extent=[10:1 - 14:2]
+// CHECK: usrs.cpp c:@S@ClsA Extent=[10:1 - 14:2]
// CHECK: usrs.cpp c: Extent=[11:1 - 11:8]
-// CHECK: usrs.cpp c:@C@ClsA@FI@a Extent=[12:3 - 12:8]
-// CHECK: usrs.cpp c:@C@ClsA@FI@b Extent=[12:3 - 12:11]
-// CHECK: usrs.cpp c:@C@ClsA@F@ClsA#I#I# Extent=[13:3 - 13:37]
-// CHECK: usrs.cpp c:usrs.cpp@147@C@ClsA@F@ClsA#I#I#@A Extent=[13:8 - 13:13]
-// CHECK: usrs.cpp c:usrs.cpp@154@C@ClsA@F@ClsA#I#I#@B Extent=[13:15 - 13:20]
+// CHECK: usrs.cpp c:@S@ClsA@FI@a Extent=[12:3 - 12:8]
+// CHECK: usrs.cpp c:@S@ClsA@FI@b Extent=[12:3 - 12:11]
+// CHECK: usrs.cpp c:@S@ClsA@F@ClsA#I#I# Extent=[13:3 - 13:37]
+// CHECK: usrs.cpp c:usrs.cpp@147@S@ClsA@F@ClsA#I#I#@A Extent=[13:8 - 13:13]
+// CHECK: usrs.cpp c:usrs.cpp@154@S@ClsA@F@ClsA#I#I#@B Extent=[13:15 - 13:20]
// CHECK: usrs.cpp c:@N@foo Extent=[16:1 - 22:2]
-// CHECK: usrs.cpp c:@N@foo@C@ClsB Extent=[17:3 - 21:4]
+// CHECK: usrs.cpp c:@N@foo@S@ClsB Extent=[17:3 - 21:4]
// CHECK: usrs.cpp c: Extent=[18:3 - 18:10]
-// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@ClsB# Extent=[19:5 - 19:27]
-// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[20:5 - 20:23]
-// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[24:1 - 26:2]
-// CHECK: usrs.cpp c:usrs.cpp@aN@C@ClsC Extent=[29:3 - 29:35]
+// CHECK: usrs.cpp c:@N@foo@S@ClsB@F@ClsB# Extent=[19:5 - 19:27]
+// CHECK: usrs.cpp c:@N@foo@S@ClsB@F@result#1 Extent=[20:5 - 20:23]
+// CHECK: usrs.cpp c:@N@foo@S@ClsB@F@result#1 Extent=[24:1 - 26:2]
+// CHECK: usrs.cpp c:usrs.cpp@aN@S@ClsC Extent=[29:3 - 29:35]
// CHECK: usrs.cpp c:usrs.cpp@aN@w Extent=[30:3 - 30:8]
// CHECK: usrs.cpp c:@z Extent=[33:1 - 33:6]
// CHECK: usrs.cpp c:@N@foo Extent=[35:1 - 40:2]
@@ -115,19 +131,19 @@ void rdar9371763() {
// CHECK: usrs.cpp c:usrs.cpp@529@N@foo@N@taz@F@sub#I#I#@b Extent=[38:19 - 38:24]
// CHECK: usrs.cpp c:@N@foo Extent=[42:1 - 52:3]
// CHECK: usrs.cpp c:@N@foo@N@taz Extent=[42:17 - 52:2]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD Extent=[43:3 - 51:4]
+// CHECK: usrs.cpp c:@N@foo@N@taz@S@ClsD Extent=[43:3 - 51:4]
// CHECK: usrs.cpp c: Extent=[44:3 - 44:10]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#I# Extent=[45:5 - 45:52]
-// CHECK: usrs.cpp c:usrs.cpp@638@N@foo@N@taz@C@ClsD@F@operator=#I#@x Extent=[45:21 - 45:26]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#d# Extent=[46:5 - 46:61]
-// CHECK: usrs.cpp c:usrs.cpp@690@N@foo@N@taz@C@ClsD@F@operator=#d#@x Extent=[46:21 - 46:29]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#&1$@N@foo@N@taz@C@ClsD# Extent=[47:5 - 47:62]
-// CHECK: usrs.cpp c:usrs.cpp@751@N@foo@N@taz@C@ClsD@F@operator=#&1$@N@foo@N@taz@C@ClsD#@x Extent=[47:21 - 47:34]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@qux#S Extent=[48:5 - 48:21]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@uz#I.#S Extent=[49:5 - 49:30]
-// CHECK: usrs.cpp c:usrs.cpp@833@N@foo@N@taz@C@ClsD@F@uz#I.#S@z Extent=[49:19 - 49:24]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator==#&1$@N@foo@N@taz@C@ClsD#1 Extent=[50:5 - 50:62]
-// CHECK: usrs.cpp c:usrs.cpp@866@N@foo@N@taz@C@ClsD@F@operator==#&1$@N@foo@N@taz@C@ClsD#1@x Extent=[50:21 - 50:34]
+// CHECK: usrs.cpp c:@N@foo@N@taz@S@ClsD@F@operator=#I# Extent=[45:5 - 45:52]
+// CHECK: usrs.cpp c:usrs.cpp@638@N@foo@N@taz@S@ClsD@F@operator=#I#@x Extent=[45:21 - 45:26]
+// CHECK: usrs.cpp c:@N@foo@N@taz@S@ClsD@F@operator=#d# Extent=[46:5 - 46:61]
+// CHECK: usrs.cpp c:usrs.cpp@690@N@foo@N@taz@S@ClsD@F@operator=#d#@x Extent=[46:21 - 46:29]
+// CHECK: usrs.cpp c:@N@foo@N@taz@S@ClsD@F@operator=#&1$@N@foo@N@taz@S@ClsD# Extent=[47:5 - 47:62]
+// CHECK: usrs.cpp c:usrs.cpp@751@N@foo@N@taz@S@ClsD@F@operator=#&1$@N@foo@N@taz@S@ClsD#@x Extent=[47:21 - 47:34]
+// CHECK: usrs.cpp c:@N@foo@N@taz@S@ClsD@F@qux#S Extent=[48:5 - 48:21]
+// CHECK: usrs.cpp c:@N@foo@N@taz@S@ClsD@F@uz#I.#S Extent=[49:5 - 49:30]
+// CHECK: usrs.cpp c:usrs.cpp@833@N@foo@N@taz@S@ClsD@F@uz#I.#S@z Extent=[49:19 - 49:24]
+// CHECK: usrs.cpp c:@N@foo@N@taz@S@ClsD@F@operator==#&1$@N@foo@N@taz@S@ClsD#1 Extent=[50:5 - 50:62]
+// CHECK: usrs.cpp c:usrs.cpp@866@N@foo@N@taz@S@ClsD@F@operator==#&1$@N@foo@N@taz@S@ClsD#1@x Extent=[50:21 - 50:34]
// CHECK: usrs.cpp c:@F@rez Extent=[55:3 - 55:25]
// CHECK: usrs.cpp c:usrs.cpp@941@F@rez@a Extent=[55:12 - 55:17]
// CHECK: usrs.cpp c:usrs.cpp@948@F@rez@b Extent=[55:19 - 55:24]
@@ -137,10 +153,22 @@ void rdar9371763() {
// CHECK-NOT: ClsB
// CHECK: usrs.cpp c:@NA@foo_alias3
// CHECK: usrs.cpp c:@aN Extent=[68:1 - 73:2]
-// CHECK: usrs.cpp c:usrs.cpp@aN@C@RDar9371763_Foo Extent=[69:1 - 72:2]
+// CHECK: usrs.cpp c:usrs.cpp@aN@S@RDar9371763_Foo Extent=[69:1 - 72:2]
// CHECK: usrs.cpp c: Extent=[70:1 - 70:8]
-// CHECK: usrs.cpp c:usrs.cpp@aN@C@RDar9371763_Foo@F@bar# Extent=[71:3 - 71:13]
-// CHECK: usrs.cpp c:usrs.cpp@aN@C@RDar9371763_Foo@F@bar# Extent=[75:1 - 75:31]
+// CHECK: usrs.cpp c:usrs.cpp@aN@S@RDar9371763_Foo@F@bar# Extent=[71:3 - 71:13]
+// CHECK: usrs.cpp c:usrs.cpp@aN@S@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]
+// CHECK: usrs.cpp c:@FT@>1#TsomeTemplFn#^type-parameter-0-0:::A# Extent=[82:1 - 82:50]
+// CHECK: usrs.cpp c:@FT@>1#TsomeTemplFn#^type-parameter-0-0:::B# Extent=[83:1 - 83:50]
+// CHECK: usrs.cpp c:@FT@>1#TsomeTemplFn#I# Extent=[84:1 - 84:40]
+
+// CHECK: usrs.cpp c:@F@funWithChar#C# Extent=[86:1 - 86:28]
+// CHECK: usrs.cpp c:@F@funWithChar#c# Extent=[87:1 - 87:37]
+// CHECK: usrs.cpp c:@F@funWithChar#r# Extent=[88:1 - 88:35]
+
+// CHECK: usrs.cpp c:usrs.cpp@S@usrs.cpp@1483@FI@x Extent=[90:10 - 90:15]
+// CHECK: usrs.cpp c:usrs.cpp@S@usrs.cpp@1510@FI@x Extent=[91:10 - 91:15]
+
+// CHECK: usrs.cpp c:@ST>1#T@TC1@F@meth#>@ST>1#T@TC11t0.0# Extent=[95:3 - 95:17]
diff --git a/test/Layout/itanium-union-bitfield.cpp b/test/Layout/itanium-union-bitfield.cpp
new file mode 100644
index 000000000000..b06fd36071e9
--- /dev/null
+++ b/test/Layout/itanium-union-bitfield.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple %itanium_abi_triple -fdump-record-layouts %s 2>/dev/null \
+// RUN: | FileCheck %s
+
+union A {
+ int f1: 3;
+ A();
+};
+
+A::A() {}
+
+union B {
+ char f1: 35;
+ B();
+};
+
+B::B() {}
+
+// CHECK:*** Dumping AST Record Layout
+// CHECK-NEXT: 0 | union A
+// CHECK-NEXT: 0 | int f1
+// CHECK-NEXT: | [sizeof=4, dsize=1, align=4
+// CHECK-NEXT: | nvsize=1, nvalign=4]
+
+// CHECK:*** Dumping AST Record Layout
+// CHECK-NEXT: 0 | union B
+// CHECK-NEXT: 0 | char f1
+// CHECK-NEXT: | [sizeof=8, dsize=5, align=4
+// CHECK-NEXT: | nvsize=5, nvalign=4]
+
diff --git a/test/Layout/ms-x86-basic-layout.cpp b/test/Layout/ms-x86-basic-layout.cpp
index b6ffeee7114a..aac7aed06019 100644
--- a/test/Layout/ms-x86-basic-layout.cpp
+++ b/test/Layout/ms-x86-basic-layout.cpp
@@ -816,6 +816,36 @@ struct RecordArrayTypedef {
// CHECK-X64-NEXT: | [sizeof=16, align=4
// CHECK-X64-NEXT: | nvsize=16, nvalign=4]
+struct EmptyIntMemb {
+ int FlexArrayMemb[0];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct EmptyIntMemb
+// CHECK-NEXT: 0 | int [0] FlexArrayMemb
+// CHECK-NEXT: | [sizeof=1, align=4
+// CHECK-NEXT: | nvsize=0, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct EmptyIntMemb
+// CHECK-X64-NEXT: 0 | int [0] FlexArrayMemb
+// CHECK-X64-NEXT: | [sizeof=4, align=4
+// CHECK-X64-NEXT: | nvsize=0, nvalign=4]
+
+struct EmptyLongLongMemb {
+ long long FlexArrayMemb[0];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct EmptyLongLongMemb
+// CHECK-NEXT: 0 | long long [0] FlexArrayMemb
+// CHECK-NEXT: | [sizeof=1, align=8
+// CHECK-NEXT: | nvsize=0, nvalign=8]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct EmptyLongLongMemb
+// CHECK-X64-NEXT: 0 | long long [0] FlexArrayMemb
+// CHECK-X64-NEXT: | [sizeof=8, align=8
+// CHECK-X64-NEXT: | nvsize=0, nvalign=8]
+
int a[
sizeof(TestF0)+
sizeof(TestF1)+
@@ -840,4 +870,6 @@ sizeof(F6)+
sizeof(ArrayFieldOfRecords)+
sizeof(ArrayOfArrayFieldOfRecords)+
sizeof(RecordArrayTypedef)+
+sizeof(EmptyIntMemb)+
+sizeof(EmptyLongLongMemb)+
0];
diff --git a/test/Layout/ms-x86-empty-layout.c b/test/Layout/ms-x86-empty-layout.c
new file mode 100644
index 000000000000..faca0be0a9c0
--- /dev/null
+++ b/test/Layout/ms-x86-empty-layout.c
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only %s 2>/dev/null \
+// RUN: | FileCheck %s
+
+struct EmptyIntMemb {
+ int FlexArrayMemb[0];
+};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: Type: struct EmptyIntMemb
+// CHECK: Record:
+// CHECK: Layout: <ASTRecordLayout
+// CHECK: Size:32
+// CHECK: Alignment:32
+// CHECK: FieldOffsets: [0]>
+
+struct EmptyLongLongMemb {
+ long long FlexArrayMemb[0];
+};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: Type: struct EmptyLongLongMemb
+// CHECK: Record:
+// CHECK: Layout: <ASTRecordLayout
+// CHECK: Size:32
+// CHECK: Alignment:64
+// CHECK: FieldOffsets: [0]>
+
+struct EmptyAligned2LongLongMemb {
+ long long __declspec(align(2)) FlexArrayMemb[0];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: Type: struct EmptyAligned2LongLongMemb
+// CHECK: Record:
+// CHECK: Layout: <ASTRecordLayout
+// CHECK: Size:32
+// CHECK: Alignment:64
+// CHECK: FieldOffsets: [0]>
+
+struct EmptyAligned8LongLongMemb {
+ long long __declspec(align(8)) FlexArrayMemb[0];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: Type: struct EmptyAligned8LongLongMemb
+// CHECK: Record:
+// CHECK: Layout: <ASTRecordLayout
+// CHECK: Size:64
+// CHECK: Alignment:64
+// CHECK: FieldOffsets: [0]>
+
+#pragma pack(1)
+struct __declspec(align(4)) EmptyPackedAligned4LongLongMemb {
+ long long FlexArrayMemb[0];
+};
+#pragma pack()
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: Type: struct EmptyPackedAligned4LongLongMemb
+// CHECK: Record:
+// CHECK: Layout: <ASTRecordLayout
+// CHECK: Size:32
+// CHECK: Alignment:32
+// CHECK: FieldOffsets: [0]>
+
+#pragma pack(1)
+struct EmptyPackedAligned8LongLongMemb {
+ long long __declspec(align(8)) FlexArrayMemb[0];
+};
+#pragma pack()
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: Type: struct EmptyPackedAligned8LongLongMemb
+// CHECK: Record:
+// CHECK: Layout: <ASTRecordLayout
+// CHECK: Size:64
+// CHECK: Alignment:64
+// CHECK: FieldOffsets: [0]>
+
+
+int a[
+sizeof(struct EmptyIntMemb)+
+sizeof(struct EmptyLongLongMemb)+
+sizeof(struct EmptyAligned2LongLongMemb)+
+sizeof(struct EmptyAligned8LongLongMemb)+
+sizeof(struct EmptyPackedAligned4LongLongMemb)+
+sizeof(struct EmptyPackedAligned8LongLongMemb)+
+0];
diff --git a/test/Layout/ms-x86-pack-and-align.cpp b/test/Layout/ms-x86-pack-and-align.cpp
index 5e1aae1ca757..9783233d66ac 100644
--- a/test/Layout/ms-x86-pack-and-align.cpp
+++ b/test/Layout/ms-x86-pack-and-align.cpp
@@ -652,7 +652,154 @@ struct OD : OC {};
// CHECK-X64-NEXT: | [sizeof=12, align=1
// CHECK-X64-NEXT: | nvsize=8, nvalign=1]
+struct __declspec(align(4)) PA {
+ int c;
+};
+
+typedef __declspec(align(8)) PA PB;
+#pragma pack(push, 1)
+struct PC {
+ char a;
+ PB x;
+};
+#pragma pack(pop)
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct PC
+// CHECK-NEXT: 0 | char a
+// CHECK-NEXT: 8 | struct PA x
+// CHECK-NEXT: 8 | int c
+// CHECK-NEXT: | [sizeof=4, align=4
+// CHECK-NEXT: | nvsize=4, nvalign=4]
+// CHECK-NEXT: | [sizeof=16, align=8
+// CHECK-NEXT: | nvsize=12, nvalign=8]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct PC
+// CHECK-X64-NEXT: 0 | char a
+// CHECK-X64-NEXT: 8 | struct PA x
+// CHECK-X64-NEXT: 8 | int c
+// CHECK-X64-NEXT: | [sizeof=4, align=4
+// CHECK-X64-NEXT: | nvsize=4, nvalign=4]
+// CHECK-X64-NEXT: | [sizeof=16, align=8
+// CHECK-X64-NEXT: | nvsize=12, nvalign=8]
+
+typedef PB PD;
+
+#pragma pack(push, 1)
+struct PE {
+ char a;
+ PD x;
+};
+#pragma pack(pop)
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: 0 | struct PE
+// CHECK-NEXT: 0 | char a
+// CHECK-NEXT: 8 | struct PA x
+// CHECK-NEXT: 8 | int c
+// CHECK-NEXT: | [sizeof=4, align=4
+// CHECK-NEXT: | nvsize=4, nvalign=4]
+// CHECK-NEXT: | [sizeof=16, align=8
+// CHECK-NEXT: | nvsize=12, nvalign=8]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: 0 | struct PE
+// CHECK-X64-NEXT: 0 | char a
+// CHECK-X64-NEXT: 8 | struct PA x
+// CHECK-X64-NEXT: 8 | int c
+// CHECK-X64-NEXT: | [sizeof=4, align=4
+// CHECK-X64-NEXT: | nvsize=4, nvalign=4]
+// CHECK-X64-NEXT: | [sizeof=16, align=8
+// CHECK-X64-NEXT: | nvsize=12, nvalign=8]
+
+typedef int __declspec(align(2)) QA;
+#pragma pack(push, 1)
+struct QB {
+ char a;
+ QA b;
+};
+#pragma pack(pop)
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct QB
+// CHECK-NEXT: 0 | char a
+// CHECK-NEXT: 2 | QA b
+// CHECK-NEXT: | [sizeof=6, align=2
+// CHECK-NEXT: | nvsize=6, nvalign=2]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct QB
+// CHECK-X64-NEXT: 0 | char a
+// CHECK-X64-NEXT: 2 | QA b
+// CHECK-X64-NEXT: | [sizeof=6, align=2
+// CHECK-X64-NEXT: | nvsize=6, nvalign=2]
+
+struct QC {
+ char a;
+ QA b;
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct QC
+// CHECK-NEXT: 0 | char a
+// CHECK-NEXT: 4 | QA b
+// CHECK-NEXT: | [sizeof=8, align=4
+// CHECK-NEXT: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct QC
+// CHECK-X64-NEXT: 0 | char a
+// CHECK-X64-NEXT: 4 | QA b
+// CHECK-X64-NEXT: | [sizeof=8, align=4
+// CHECK-X64-NEXT: | nvsize=8, nvalign=4]
+
+struct QD {
+ char a;
+ QA b : 3;
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct QD
+// CHECK-NEXT: 0 | char a
+// CHECK-NEXT: 4 | QA b
+// CHECK-NEXT: | [sizeof=8, align=4
+// CHECK-NEXT: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct QD
+// CHECK-X64-NEXT: 0 | char a
+// CHECK-X64-NEXT: 4 | QA b
+// CHECK-X64-NEXT: | [sizeof=8, align=4
+// CHECK-X64-NEXT: | nvsize=8, nvalign=4]
+
+struct __declspec(align(4)) EmptyAlignedLongLongMemb {
+ long long FlexArrayMemb[0];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct EmptyAlignedLongLongMemb
+// CHECK-NEXT: 0 | long long [0] FlexArrayMemb
+// CHECK-NEXT: | [sizeof=8, align=8
+// CHECK-NEXT: | nvsize=0, nvalign=8]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct EmptyAlignedLongLongMemb
+// CHECK-X64-NEXT: 0 | long long [0] FlexArrayMemb
+// CHECK-X64-NEXT: | [sizeof=8, align=8
+// CHECK-X64-NEXT: | nvsize=0, nvalign=8]
+
+#pragma pack(1)
+struct __declspec(align(4)) EmptyPackedAlignedLongLongMemb {
+ long long FlexArrayMemb[0];
+};
+#pragma pack()
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct EmptyPackedAlignedLongLongMemb
+// CHECK-NEXT: 0 | long long [0] FlexArrayMemb
+// CHECK-NEXT: | [sizeof=4, align=4
+// CHECK-NEXT: | nvsize=0, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct EmptyPackedAlignedLongLongMemb
+// CHECK-X64-NEXT: 0 | long long [0] FlexArrayMemb
+// CHECK-X64-NEXT: | [sizeof=4, align=4
+// CHECK-X64-NEXT: | nvsize=0, nvalign=4]
int a[
sizeof(X)+
@@ -680,4 +827,11 @@ sizeof(RC)+
sizeof(RE)+
sizeof(ND)+
sizeof(OD)+
+sizeof(PC)+
+sizeof(PE)+
+sizeof(QB)+
+sizeof(QC)+
+sizeof(QD)+
+sizeof(EmptyAlignedLongLongMemb)+
+sizeof(EmptyPackedAlignedLongLongMemb)+
0];
diff --git a/test/Layout/ms-x86-vtordisp.cpp b/test/Layout/ms-x86-vtordisp.cpp
index 60779fb1975b..1b78d9fe8435 100644
--- a/test/Layout/ms-x86-vtordisp.cpp
+++ b/test/Layout/ms-x86-vtordisp.cpp
@@ -416,6 +416,31 @@ struct HC : virtual HB {};
// CHECK-X64-NEXT: | [sizeof=32, align=8
// CHECK-X64-NEXT: | nvsize=8, nvalign=8]
+struct IA {
+ virtual void f();
+};
+struct __declspec(dllexport) IB : virtual IA {
+ virtual void f() = 0;
+ IB() {}
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct IB
+// CHECK-NEXT: 0 | (IB vbtable pointer)
+// CHECK-NEXT: 4 | struct IA (virtual base)
+// CHECK-NEXT: 4 | (IA vftable pointer)
+// CHECK-NEXT: | [sizeof=8, align=4
+// CHECK-NEXT: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct IB
+// CHECK-X64-NEXT: 0 | (IB vbtable pointer)
+// CHECK-X64-NEXT: 8 | struct IA (virtual base)
+// CHECK-X64-NEXT: 8 | (IA vftable pointer)
+// CHECK-X64-NEXT: | [sizeof=16, align=8
+// CHECK-X64-NEXT: | nvsize=8, nvalign=8]
+
int a[
sizeof(A)+
sizeof(C)+
@@ -428,4 +453,5 @@ sizeof(pragma_test3::C)+
sizeof(pragma_test4::C)+
sizeof(GD)+
sizeof(HC)+
+sizeof(IB)+
0];
diff --git a/test/Lexer/bcpl-escaped-newline.c b/test/Lexer/bcpl-escaped-newline.c
index 05d4773b87eb..0883173b224f 100644
--- a/test/Lexer/bcpl-escaped-newline.c
+++ b/test/Lexer/bcpl-escaped-newline.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Eonly -trigraphs %s
+// RUN: %clang_cc1 -Eonly -ftrigraphs %s
// RUN: %clang_cc1 -Eonly -verify %s
//\
diff --git a/test/Lexer/block_cmt_end.c b/test/Lexer/block_cmt_end.c
index f54b6a4a21a8..1d00137644c3 100644
--- a/test/Lexer/block_cmt_end.c
+++ b/test/Lexer/block_cmt_end.c
@@ -1,9 +1,9 @@
/*
- RUN: %clang_cc1 -E -trigraphs %s | grep bar
- RUN: %clang_cc1 -E -trigraphs %s | grep foo
- 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
+ RUN: %clang_cc1 -E -ftrigraphs %s | grep bar
+ RUN: %clang_cc1 -E -ftrigraphs %s | grep foo
+ RUN: %clang_cc1 -E -ftrigraphs %s | not grep qux
+ RUN: %clang_cc1 -E -ftrigraphs %s | not grep xyz
+ RUN: %clang_cc1 -fsyntax-only -ftrigraphs -verify %s
*/
// This is a simple comment, /*/ does not end a comment, the trailing */ does.
diff --git a/test/Lexer/constants.c b/test/Lexer/constants.c
index f0cd4d7cf29c..9c84ddc01929 100644
--- a/test/Lexer/constants.c
+++ b/test/Lexer/constants.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -trigraphs %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -ftrigraphs %s
int x = 000000080; // expected-error {{invalid digit}}
@@ -15,9 +15,9 @@ float Y = 08.123456;
#endif
#if -01000000000000000000000 // should not warn.
#endif
-#if 9223372036854775808 // expected-warning {{integer constant is larger than the largest signed integer type}}
+#if 9223372036854775808 // expected-warning {{integer literal is too large to be represented in a signed integer type, interpreting as unsigned}}
#endif
-#if 0x10000000000000000 // expected-error {{integer constant is larger than the largest unsigned integer type}}
+#if 0x10000000000000000 // expected-error {{integer literal is too large to be represented in any integer type}}
#endif
int c[] = {
diff --git a/test/Lexer/cxx-features.cpp b/test/Lexer/cxx-features.cpp
index 1202ecb18349..670a105aa40c 100644
--- a/test/Lexer/cxx-features.cpp
+++ b/test/Lexer/cxx-features.cpp
@@ -16,6 +16,10 @@
#error "wrong value for __cpp_binary_literals"
#endif
+#if check(digit_separators, 0, 0, 201309)
+#error "wrong value for __cpp_digit_separators"
+#endif
+
#if check(init_captures, 0, 0, 201304)
#error "wrong value for __cpp_init_captures"
#endif
@@ -24,6 +28,10 @@
#error "wrong value for __cpp_generic_lambdas"
#endif
+#if check(sized_deallocation, 0, 0, 201309)
+#error "wrong value for __cpp_sized_deallocation"
+#endif
+
#if check(constexpr, 0, 200704, 201304)
#error "wrong value for __cpp_constexpr"
#endif
@@ -68,6 +76,10 @@
#error "wrong value for __cpp_lambdas"
#endif
+#if check(range_based_for, 0, 200907, 200907)
+#error "wrong value for __cpp_range_based_for"
+#endif
+
#if check(static_assert, 0, 200410, 200410)
#error "wrong value for __cpp_static_assert"
#endif
@@ -87,3 +99,27 @@
#if check(variadic_templates, 0, 200704, 200704)
#error "wrong value for __cpp_variadic_templates"
#endif
+
+#if check(initializer_lists, 0, 200806, 200806)
+#error "wrong value for __cpp_initializer_lists"
+#endif
+
+#if check(delegating_constructors, 0, 200604, 200604)
+#error "wrong value for __cpp_delegating_constructors"
+#endif
+
+#if check(nsdmi, 0, 200809, 200809)
+#error "wrong value for __cpp_nsdmi"
+#endif
+
+#if check(inheriting_constructors, 0, 200802, 200802)
+#error "wrong value for __cpp_inheriting_constructors"
+#endif
+
+#if check(ref_qualifiers, 0, 200710, 200710)
+#error "wrong value for __cpp_ref_qualifiers"
+#endif
+
+#if check(alias_templates, 0, 200704, 200704)
+#error "wrong value for __cpp_alias_templates"
+#endif
diff --git a/test/Lexer/cxx1z-trigraphs.cpp b/test/Lexer/cxx1z-trigraphs.cpp
index 410626fd7bb8..0ea2adbe1e03 100644
--- a/test/Lexer/cxx1z-trigraphs.cpp
+++ b/test/Lexer/cxx1z-trigraphs.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -std=c++1z %s -verify
-// RUN: %clang_cc1 -std=c++1z %s -trigraphs -fsyntax-only
+// RUN: %clang_cc1 -std=c++1z %s -ftrigraphs -fsyntax-only
??= define foo ; // expected-error {{}} expected-warning {{trigraph ignored}}
diff --git a/test/Lexer/escape_newline.c b/test/Lexer/escape_newline.c
index d0f27dffdf71..9fc73dc7a429 100644
--- a/test/Lexer/escape_newline.c
+++ b/test/Lexer/escape_newline.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -E -trigraphs %s | grep -- ' ->'
-// RUN: %clang_cc1 -E -trigraphs %s 2>&1 | grep 'backslash and newline separated by space'
-// RUN: %clang_cc1 -E -trigraphs %s 2>&1 | grep 'trigraph converted'
-// RUN: %clang_cc1 -E -CC -trigraphs %s
+// RUN: %clang_cc1 -E -ftrigraphs %s | grep -- ' ->'
+// RUN: %clang_cc1 -E -ftrigraphs %s 2>&1 | grep 'backslash and newline separated by space'
+// RUN: %clang_cc1 -E -ftrigraphs %s 2>&1 | grep 'trigraph converted'
+// RUN: %clang_cc1 -E -CC -ftrigraphs %s
// This is an ugly way to spell a -> token.
-??/
diff --git a/test/Lexer/has_extension.c b/test/Lexer/has_extension.c
index 3b08510aa440..b7efece64e83 100644
--- a/test/Lexer/has_extension.c
+++ b/test/Lexer/has_extension.c
@@ -1,5 +1,5 @@
-// 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
+// RUN: %clang_cc1 -std=c99 -E %s -o - | FileCheck --check-prefix=CHECK-PED-NONE %s
+// RUN: %clang_cc1 -std=c99 -pedantic-errors -E %s -o - | FileCheck --check-prefix=CHECK-PED-ERR %s
// CHECK-PED-NONE: no_dummy_extension
#if !__has_extension(dummy_extension)
@@ -36,6 +36,14 @@ int has_c_alignas();
int no_c_alignas();
#endif
+// CHECK-PED-NONE: has_c_alignof
+// CHECK-PED-ERR: no_c_alignof
+#if __has_extension(c_alignof)
+int has_c_alignof();
+#else
+int no_c_alignof();
+#endif
+
// Arbitrary feature to test that the extension name can be surrounded with
// double underscores.
// CHECK-PED-NONE: has_double_underscores
diff --git a/test/Lexer/has_feature_c1x.c b/test/Lexer/has_feature_c1x.c
index e26e309c0371..ff1778010b75 100644
--- a/test/Lexer/has_feature_c1x.c
+++ b/test/Lexer/has_feature_c1x.c
@@ -1,12 +1,17 @@
-// RUN: %clang_cc1 -E -triple x86_64-linux-gnu -std=c1x %s -o - | FileCheck --check-prefix=CHECK-1X %s
-// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-1X %s
+// RUN: %clang_cc1 -E -triple x86_64-linux-gnu -std=c89 %s -o - | FileCheck --check-prefix=CHECK-NO-1X %s
+// RUN: %clang_cc1 -E -triple x86_64-linux-gnu -std=iso9899:199409 %s -o - | FileCheck --check-prefix=CHECK-NO-1X %s
+// RUN: %clang_cc1 -E -triple x86_64-linux-gnu -std=c99 %s -o - | FileCheck --check-prefix=CHECK-NO-1X %s
+// RUN: %clang_cc1 -E -triple x86_64-linux-gnu -std=c11 %s -o - | FileCheck --check-prefix=CHECK-1X %s
+//
+// RUN: %clang_cc1 -E -triple x86_64-linux-gnu -std=gnu89 %s -o - | FileCheck --check-prefix=CHECK-NO-1X %s
+// RUN: %clang_cc1 -E -triple x86_64-linux-gnu -std=gnu99 %s -o - | FileCheck --check-prefix=CHECK-NO-1X %s
+// RUN: %clang_cc1 -E -triple x86_64-linux-gnu -std=gnu11 %s -o - | FileCheck --check-prefix=CHECK-1X %s
#if __has_feature(c_atomic)
int has_atomic();
#else
int no_atomic();
#endif
-
// CHECK-1X: has_atomic
// CHECK-NO-1X: no_atomic
@@ -15,7 +20,6 @@ int has_static_assert();
#else
int no_static_assert();
#endif
-
// CHECK-1X: has_static_assert
// CHECK-NO-1X: no_static_assert
@@ -24,7 +28,6 @@ int has_generic_selections();
#else
int no_generic_selections();
#endif
-
// CHECK-1X: has_generic_selections
// CHECK-NO-1X: no_generic_selections
@@ -33,10 +36,17 @@ int has_alignas();
#else
int no_alignas();
#endif
-
// CHECK-1X: has_alignas
// CHECK-NO-1X: no_alignas
+#if __has_feature(c_alignof)
+int has_alignof();
+#else
+int no_alignof();
+#endif
+// CHECK-1X: has_alignof
+// CHECK-NO-1X: no_alignof
+
#if __has_feature(c_thread_local)
int has_thread_local();
#else
diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp
index e558f8804b22..9fb05de31a23 100644
--- a/test/Lexer/has_feature_cxx0x.cpp
+++ b/test/Lexer/has_feature_cxx0x.cpp
@@ -234,6 +234,16 @@ int no_alignas();
// CHECK-11: has_alignas
// CHECK-NO-11: no_alignas
+#if __has_feature(cxx_alignof)
+int has_alignof();
+#else
+int no_alignof();
+#endif
+
+// CHECK-1Y: has_alignof
+// CHECK-11: has_alignof
+// CHECK-NO-11: no_alignof
+
#if __has_feature(cxx_raw_string_literals)
int has_raw_string_literals();
#else
diff --git a/test/Lexer/ms-compatibility.c b/test/Lexer/ms-compatibility.c
new file mode 100644
index 000000000000..d159ad1b8d92
--- /dev/null
+++ b/test/Lexer/ms-compatibility.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -E -fms-compatibility %s | FileCheck --check-prefix=CHECK-MS-COMPAT %s
+// RUN: %clang_cc1 -fsyntax-only -E %s | FileCheck --check-prefix=CHECK-NO-MS-COMPAT %s
+
+#define FN(x) L#x
+#define F L "aaa"
+void *v1 = FN(aaa);
+void *v2 = F;
+// CHECK-MS-COMPAT: void *v1 = L"aaa";
+// CHECK-MS-COMPAT: void *v2 = L "aaa";
+// CHECK-NO-MS-COMPAT: void *v1 = L "aaa";
+// CHECK-NO-MS-COMPAT: void *v2 = L "aaa";
diff --git a/test/Lexer/string-literal-errors.cpp b/test/Lexer/string-literal-errors.cpp
index d8e29934f367..223dca4b94f6 100644
--- a/test/Lexer/string-literal-errors.cpp
+++ b/test/Lexer/string-literal-errors.cpp
@@ -23,3 +23,5 @@ void foo() {
// CHECK: {{^ \^~$}}
// CHECK: {{^ \^~$}}
}
+
+#define foo() lots and lots of tokens, need at least 8 to fill up the smallvector buffer #BadThingsHappenNow
diff --git a/test/Lexer/utf8-char-literal.cpp b/test/Lexer/utf8-char-literal.cpp
index 7a4d126097a7..0ddaabc84225 100644
--- a/test/Lexer/utf8-char-literal.cpp
+++ b/test/Lexer/utf8-char-literal.cpp
@@ -1,6 +1,15 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c11 -x c -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++1z -fsyntax-only -verify %s
int array0[u'ñ' == u'\xf1'? 1 : -1];
int array1['\xF1' != u'\xf1'? 1 : -1];
int array1['ñ' != u'\xf1'? 1 : -1]; // expected-error {{character too large for enclosing character literal type}}
+#if __cplusplus > 201402L
+char a = u8'ñ'; // expected-error {{character too large for enclosing character literal type}}
+char b = u8'\x80'; // ok
+char c = u8'\u0080'; // expected-error {{character too large for enclosing character literal type}}
+char d = u8'\u1234'; // expected-error {{character too large for enclosing character literal type}}
+char e = u8'ሴ'; // expected-error {{character too large for enclosing character literal type}}
+char f = u8'ab'; // expected-error {{Unicode character literals may not contain multiple characters}}
+#endif
diff --git a/test/Lexer/wchar-signedness.c b/test/Lexer/wchar-signedness.c
index b5d4ac8f000c..1d8bc4d5dd03 100644
--- a/test/Lexer/wchar-signedness.c
+++ b/test/Lexer/wchar-signedness.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -dM -E %s -triple x86_64-none-linux-gnu | FileCheck %s --check-prefix=CHECK-X86
// RUN: %clang_cc1 -fsyntax-only -dM -E %s -triple armv7-none-eabi | FileCheck %s --check-prefix=CHECK-ARM
+// RUN: %clang_cc1 -fsyntax-only -dM -E %s -triple thumbv7-none-eabi | FileCheck %s --check-prefix=CHECK-ARM
// CHECK-X86-NOT: #define __WCHAR_UNSIGNED__
// CHECK-X86: #define __WINT_UNSIGNED__ 1
diff --git a/test/Misc/ast-dump-arm-attr.c b/test/Misc/ast-dump-arm-attr.c
index bec3531828b1..41328165d210 100644
--- a/test/Misc/ast-dump-arm-attr.c
+++ b/test/Misc/ast-dump-arm-attr.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple arm-apple-darwin -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
-
-__attribute__((interrupt)) void Test(void);
-// CHECK: FunctionDecl{{.*}}Test
-// CHECK-NEXT: ARMInterruptAttr
+// RUN: %clang_cc1 -triple arm-apple-darwin -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
+
+__attribute__((interrupt)) void Test(void);
+// CHECK: FunctionDecl{{.*}}Test
+// CHECK-NEXT: ARMInterruptAttr
diff --git a/test/Misc/ast-dump-attr.cpp b/test/Misc/ast-dump-attr.cpp
index 1aa6adf79b09..446f0fa692f9 100644
--- a/test/Misc/ast-dump-attr.cpp
+++ b/test/Misc/ast-dump-attr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++11 -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++11 -Wno-deprecated-declarations -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
int TestLocation
__attribute__((unused));
@@ -135,3 +135,18 @@ void func() {
// CHECK-NOT: NoReturnAttr
// CHECK: CXXConversionDecl{{.*}}operator void (*)() __attribute__((noreturn))
}
+
+namespace PR20930 {
+struct S {
+ struct { int Test __attribute__((deprecated)); };
+ // CHECK: FieldDecl{{.*}}Test 'int'
+ // CHECK-NEXT: DeprecatedAttr
+};
+
+void f() {
+ S s;
+ s.Test = 1;
+ // CHECK: IndirectFieldDecl{{.*}}Test 'int'
+ // CHECK: DeprecatedAttr
+}
+}
diff --git a/test/Misc/ast-dump-color.cpp b/test/Misc/ast-dump-color.cpp
index b4660b4a724e..479467df7160 100644
--- a/test/Misc/ast-dump-color.cpp
+++ b/test/Misc/ast-dump-color.cpp
@@ -29,8 +29,8 @@ struct Invalid {
__attribute__((noinline)) Invalid(error);
} Invalid;
-//CHECK: {{^}}[[Blue:.\[0;34m]][[RESET:.\[0m]][[GREEN:.\[0;1;32m]]TranslationUnitDecl[[RESET]][[Yellow:.\[0;33m]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]<invalid sloc>[[RESET]]> [[Yellow]]<invalid sloc>[[RESET]]{{$}}
-//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]TypedefDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]<invalid sloc>[[RESET]]> [[Yellow]]<invalid sloc>[[RESET]] implicit[[CYAN:.\[0;1;36m]] __int128_t[[RESET]] [[Green:.\[0;32m]]'__int128'[[RESET]]{{$}}
+//CHECK: {{^}}[[GREEN:.\[0;1;32m]]TranslationUnitDecl[[RESET:.\[0m]][[Yellow:.\[0;33m]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]<invalid sloc>[[RESET]]> [[Yellow]]<invalid sloc>[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue:.\[0;34m]]|-[[RESET]][[GREEN]]TypedefDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]<invalid sloc>[[RESET]]> [[Yellow]]<invalid sloc>[[RESET]] implicit[[CYAN:.\[0;1;36m]] __int128_t[[RESET]] [[Green:.\[0;32m]]'__int128'[[RESET]]{{$}}
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]TypedefDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]<invalid sloc>[[RESET]]> [[Yellow]]<invalid sloc>[[RESET]] implicit[[CYAN]] __uint128_t[[RESET]] [[Green]]'unsigned __int128'[[RESET]]{{$}}
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]TypedefDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]<invalid sloc>[[RESET]]> [[Yellow]]<invalid sloc>[[RESET]] implicit[[CYAN]] __builtin_va_list[[RESET]] [[Green]]'__va_list_tag [1]'[[RESET]]{{$}}
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]{{.*}}ast-dump-color.cpp:6:1[[RESET]], [[Yellow]]col:5[[RESET]]> [[Yellow]]col:5[[RESET]][[CYAN]] Test[[RESET]] [[Green]]'int'[[RESET]]
@@ -75,29 +75,29 @@ struct Invalid {
//CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[Blue]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:22[[RESET]]> Text=" Another variable"{{$}}
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[Blue]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:23:6[[RESET]], [[Yellow]]col:44[[RESET]]>{{$}}
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[Blue]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:44[[RESET]]> Text=" Like the other variable, but different"{{$}}
-//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:33[[RESET]]> [[Yellow]]col:33[[RESET]] implicit used[[CYAN]] Mutex[[RESET]] [[Green]]'void (void)'[[RESET]] inline{{.*$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:33[[RESET]]> [[Yellow]]col:33[[RESET]] implicit used[[CYAN]] Mutex[[RESET]] [[Green]]'void (void) noexcept'[[RESET]] inline{{.*$}}
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]CompoundStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]>{{$}}
-//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]> [[Yellow]]col:33[[RESET]] implicit[[CYAN]] Mutex[[RESET]] [[Green]]'void (const class Mutex &)'[[RESET]] inline{{ .*$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]> [[Yellow]]col:33[[RESET]] implicit constexpr[[CYAN]] Mutex[[RESET]] [[Green]]'void (const class Mutex &)'[[RESET]] inline{{ .*$}}
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]> [[Yellow]]col:33[[RESET]] [[Green]]'const class Mutex &'[[RESET]]{{$}}
-//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]> [[Yellow]]col:33[[RESET]] implicit[[CYAN]] Mutex[[RESET]] [[Green]]'void (class Mutex &&)'[[RESET]] inline{{ .*$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]> [[Yellow]]col:33[[RESET]] implicit constexpr[[CYAN]] Mutex[[RESET]] [[Green]]'void (class Mutex &&)'[[RESET]] inline{{ .*$}}
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]> [[Yellow]]col:33[[RESET]] [[Green]]'class Mutex &&'[[RESET]]{{$}}
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]line:25:3[[RESET]]> [[Yellow]]col:3[[RESET]] referenced[[CYAN]] mu1[[RESET]] [[Green]]'class Mutex':'class Mutex'[[RESET]]
-//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]CXXConstructExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:3[[RESET]]> [[Green]]'class Mutex':'class Mutex'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]] [[Green]]'void (void)'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]CXXConstructExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:3[[RESET]]> [[Green]]'class Mutex':'class Mutex'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]] [[Green]]'void (void) noexcept'[[RESET]]{{$}}
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:1[[RESET]], [[Yellow]]line:25:8[[RESET]]> [[Yellow]]col:8[[RESET]][[CYAN]] mu2[[RESET]] [[Green]]'class Mutex':'class Mutex'[[RESET]]
-//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]CXXConstructExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Green]]'class Mutex':'class Mutex'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]] [[Green]]'void (void)'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]CXXConstructExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Green]]'class Mutex':'class Mutex'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]] [[Green]]'void (void) noexcept'[[RESET]]{{$}}
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:26:1[[RESET]], [[Yellow]]col:5[[RESET]]> [[Yellow]]col:5[[RESET]][[CYAN]] TestExpr[[RESET]] [[Green]]'int'[[RESET]]
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[BLUE]]GuardedByAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:29[[RESET]], [[Yellow]]col:43[[RESET]]>{{$}}
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]DeclRefExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:40[[RESET]]> [[Green]]'class Mutex':'class Mutex'[[RESET]][[Cyan]] lvalue[[RESET]][[Cyan]][[RESET]] [[GREEN]]Var[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]][[CYAN]] 'mu1'[[RESET]] [[Green]]'class Mutex':'class Mutex'[[RESET]]{{$}}
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:28:1[[RESET]], [[Yellow]]line:30:1[[RESET]]> [[Yellow]]line:28:8[[RESET]] struct[[CYAN]] Invalid[[RESET]] definition
-//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit struct[[CYAN]] Invalid[[RESET]]
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit referenced struct[[CYAN]] Invalid[[RESET]]
//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:29:3[[RESET]], [[Yellow]]col:42[[RESET]]> [[Yellow]]col:29[[RESET]] invalid[[CYAN]] Invalid[[RESET]] [[Green]]'void (int)'[[RESET]]
//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:37[[RESET]], [[Yellow]]<invalid sloc>[[RESET]]> [[Yellow]]col:42[[RESET]] invalid [[Green]]'int'[[RESET]]
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[BLUE]]NoInlineAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:18[[RESET]]>
-//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:28:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit used[[CYAN]] Invalid[[RESET]] [[Green]]'void (void)'[[RESET]] inline noexcept-unevaluated 0x{{[0-9a-fA-F]*}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:28:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit used constexpr[[CYAN]] Invalid[[RESET]] [[Green]]'void (void) noexcept'[[RESET]] inline
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]CompoundStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]>
-//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit[[CYAN]] Invalid[[RESET]] [[Green]]'void (const struct Invalid &)'[[RESET]] inline noexcept-unevaluated 0x{{[0-9a-fA-F]*}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit constexpr[[CYAN]] Invalid[[RESET]] [[Green]]'void (const struct Invalid &)'[[RESET]] inline noexcept-unevaluated 0x{{[0-9a-fA-F]*}}
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] [[Green]]'const struct Invalid &'[[RESET]]
-//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit[[CYAN]] Invalid[[RESET]] [[Green]]'void (struct Invalid &&)'[[RESET]] inline noexcept-unevaluated 0x{{[0-9a-fA-F]*}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit constexpr[[CYAN]] Invalid[[RESET]] [[Green]]'void (struct Invalid &&)'[[RESET]] inline noexcept-unevaluated 0x{{[0-9a-fA-F]*}}
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] [[Green]]'struct Invalid &&'[[RESET]]
//CHECK: {{^}}[[Blue]]`-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]line:30:3[[RESET]]> [[Yellow]]col:3[[RESET]][[CYAN]] Invalid[[RESET]] [[Green]]'struct Invalid':'struct Invalid'[[RESET]]
-//CHECK: {{^}}[[Blue]] `-[[RESET]][[MAGENTA]]CXXConstructExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:3[[RESET]]> [[Green]]'struct Invalid':'struct Invalid'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]] [[Green]]'void (void)'[[RESET]]
+//CHECK: {{^}}[[Blue]] `-[[RESET]][[MAGENTA]]CXXConstructExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:3[[RESET]]> [[Green]]'struct Invalid':'struct Invalid'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]] [[Green]]'void (void) noexcept'[[RESET]]
diff --git a/test/Misc/ast-dump-decl.cpp b/test/Misc/ast-dump-decl.cpp
index b41e4ee3d0f0..fe7ea7503df3 100644
--- a/test/Misc/ast-dump-decl.cpp
+++ b/test/Misc/ast-dump-decl.cpp
@@ -116,6 +116,7 @@ namespace testCXXConstructorDecl {
class TestCXXConstructorDecl : public A {
int I;
TestCXXConstructorDecl(A &a, int i) : A(a), I(i) { }
+ TestCXXConstructorDecl(A &a) : TestCXXConstructorDecl(a, 0) { }
};
}
// CHECK: CXXConstructorDecl{{.*}} TestCXXConstructorDecl 'void {{.*}}'
@@ -126,6 +127,10 @@ namespace testCXXConstructorDecl {
// CHECK: CXXCtorInitializer{{.*}}I
// CHECK-NEXT: Expr
// CHECK: CompoundStmt
+// CHECK: CXXConstructorDecl{{.*}} TestCXXConstructorDecl 'void {{.*}}'
+// CHECK-NEXT: ParmVarDecl{{.*}} a
+// CHECK-NEXT: CXXCtorInitializer{{.*}}TestCXXConstructorDecl
+// CHECK-NEXT: CXXConstructExpr{{.*}}TestCXXConstructorDecl
class TestCXXDestructorDecl {
~TestCXXDestructorDecl() { }
diff --git a/test/Misc/ast-dump-invalid.cpp b/test/Misc/ast-dump-invalid.cpp
new file mode 100644
index 000000000000..3b97cc65409b
--- /dev/null
+++ b/test/Misc/ast-dump-invalid.cpp
@@ -0,0 +1,20 @@
+// RUN: not %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -fms-extensions -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix CHECK -strict-whitespace %s
+
+namespace TestInvalidRParenOnCXXUnresolvedConstructExpr {
+template <class T>
+void f(T i, T j) {
+ return T (i, j;
+}
+}
+
+// CHECK: NamespaceDecl {{.*}} <{{.*}}> {{.*}} TestInvalidRParenOnCXXUnresolvedConstructExpr
+// CHECK-NEXT: `-FunctionTemplateDecl
+// CHECK-NEXT: |-TemplateTypeParmDecl
+// CHECK-NEXT: `-FunctionDecl
+// CHECK-NEXT: |-ParmVarDecl
+// CHECK-NEXT: |-ParmVarDecl
+// CHECK-NEXT: `-CompoundStmt
+// CHECK-NEXT: `-ReturnStmt
+// CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} <col:10, col:16> 'T'
+// CHECK-NEXT: |-DeclRefExpr {{.*}} <col:13> 'T' lvalue ParmVar {{.*}} 'i' 'T'
+// CHECK-NEXT: `-DeclRefExpr {{.*}} <col:16> 'T' lvalue ParmVar {{.*}} 'j' 'T'
diff --git a/test/Misc/ast-dump-lookups.cpp b/test/Misc/ast-dump-lookups.cpp
new file mode 100644
index 000000000000..5c6da48b3afb
--- /dev/null
+++ b/test/Misc/ast-dump-lookups.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix DECLS %s
+// RUN: %clang_cc1 -std=c++11 -ast-dump-lookups -ast-dump-filter Test %s | FileCheck -check-prefix LOOKUPS %s
+// RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-lookups -ast-dump-filter Test %s | FileCheck -check-prefix DECLS-LOOKUPS %s
+
+namespace Test {
+ extern int a;
+ int a = 0;
+}
+
+namespace Test { }
+
+// DECLS: Dumping Test:
+// DECLS-NEXT: NamespaceDecl {{.*}} Test
+// DECLS-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern
+// DECLS-NEXT: `-VarDecl {{.*}} prev [[EXTERN_A]] {{.*}} a 'int' cinit
+// DECLS-NEXT: `-IntegerLiteral {{.*}} 'int' 0
+//
+// DECLS: Dumping Test:
+// DECLS-NEXT: NamespaceDecl {{.*}} Test
+
+// LOOKUPS: Dumping Test:
+// LOOKUPS-NEXT: StoredDeclsMap Namespace {{.*}} 'Test'
+// LOOKUPS-NEXT: `-DeclarationName 'a'
+// LOOKUPS-NEXT: `-Var {{.*}} 'a' 'int'
+//
+// LOOKUPS: Dumping Test:
+// LOOKUPS-NEXT: Lookup map is in primary DeclContext
+
+// DECLS-LOOKUPS: Dumping Test:
+// DECLS-LOOKUPS-NEXT: StoredDeclsMap Namespace {{.*}} 'Test'
+// DECLS-LOOKUPS-NEXT: `-DeclarationName 'a'
+// DECLS-LOOKUPS-NEXT: `-Var [[A:[^ ]*]] 'a' 'int'
+// DECLS-LOOKUPS-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern
+// DECLS-LOOKUPS-NEXT: `-VarDecl [[A]] prev [[EXTERN_A]] {{.*}} a 'int' cinit
+// DECLS-LOOKUPS-NEXT: `-IntegerLiteral {{.*}} 'int' 0
+//
+// DECLS-LOOKUPS: Dumping Test:
+// DECLS-LOOKUPS-NEXT: Lookup map is in primary DeclContext
diff --git a/test/Misc/ast-dump-msp430-attr.c b/test/Misc/ast-dump-msp430-attr.c
index 170e0bef9d99..3ccb3bdb705f 100644
--- a/test/Misc/ast-dump-msp430-attr.c
+++ b/test/Misc/ast-dump-msp430-attr.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple msp430-unknown-unknown -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
-
-__attribute__((interrupt(12))) void Test(void);
-// CHECK: FunctionDecl{{.*}}Test
-// CHECK-NEXT: MSP430InterruptAttr
+// RUN: %clang_cc1 -triple msp430-unknown-unknown -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
+
+__attribute__((interrupt(12))) void Test(void);
+// CHECK: FunctionDecl{{.*}}Test
+// CHECK-NEXT: MSP430InterruptAttr
diff --git a/test/Misc/ast-dump-templates.cpp b/test/Misc/ast-dump-templates.cpp
index b7aeca8d55df..022d5c41127c 100644
--- a/test/Misc/ast-dump-templates.cpp
+++ b/test/Misc/ast-dump-templates.cpp
@@ -39,6 +39,18 @@ void baz() {
// CHECK1: template <int A, typename B> B bar()
// CHECK2: template <int A, typename B> B bar()
+// CHECK1-LABEL: template <typename ...T> struct A {
+// CHECK1-NEXT: template <T ...x[3]> struct B {
+template <typename ...T> struct A {
+ template <T ...x[3]> struct B {};
+};
+
+// CHECK1-LABEL: template <typename ...T> void f(T ...[3]) {
+// CHECK1-NEXT: A<T [3]...> a;
+template <typename ...T> void f(T ...[3]) {
+ A<T [3]...> a;
+}
+
namespace test2 {
void func(int);
void func(float);
diff --git a/test/Misc/ast-print-objectivec.m b/test/Misc/ast-print-objectivec.m
new file mode 100644
index 000000000000..ef0fcaa9e32f
--- /dev/null
+++ b/test/Misc/ast-print-objectivec.m
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -ast-print %s -o - | FileCheck %s
+
+@interface NSObject @end
+
+@protocol P
+- (void)MethP __attribute__((availability(macosx,introduced=10.1.0,deprecated=10.2)));
+@end
+
+@interface I : NSObject <P>
+- (void)MethI __attribute__((availability(macosx,introduced=10.1.0,deprecated=10.2)));
+@end
+
+@interface I(CAT)
+- (void)MethCAT __attribute__((availability(macosx,introduced=10_1_0,deprecated=10_2)));
+@end
+
+@implementation I
+- (void)MethP __attribute__((availability(macosx,introduced=10.1.0,deprecated=10.2))) {}
+- (void)MethI __attribute__((availability(macosx,introduced=10.1.0,deprecated=10.2))) {}
+@end
+
+// CHECK: @protocol P
+// CHECK: - (void) MethP __attribute__((availability(macosx, introduced=10.1.0, deprecated=10.2)));
+// CHECK: @end
+
+// CHECK: @interface I : NSObject<P>
+// CHECK: - (void) MethI __attribute__((availability(macosx, introduced=10.1.0, deprecated=10.2)));
+// CHECK: @end
+
+// CHECK: @interface I(CAT)
+// CHECK: - (void) MethCAT __attribute__((availability(macosx, introduced=10_1_0, deprecated=10_2)));
+// CHECK: @end
+
+// CHECK: @implementation I
+// CHECK: - (void) MethP __attribute__((availability(macosx, introduced=10.1.0, deprecated=10.2))) {
+// CHECK: }
+
+// CHECK: - (void) MethI __attribute__((availability(macosx, introduced=10.1.0, deprecated=10.2))) {
+// CHECK: }
+
+// CHECK: @end
diff --git a/test/Misc/ast-print-pragmas.cpp b/test/Misc/ast-print-pragmas.cpp
index 25421fcd0c3e..23f533fc3766 100644
--- a/test/Misc/ast-print-pragmas.cpp
+++ b/test/Misc/ast-print-pragmas.cpp
@@ -38,3 +38,18 @@ void test(int *List, int Length) {
i++;
}
}
+
+template <int V, int I>
+void test_nontype_template_param(int *List, int Length) {
+#pragma clang loop vectorize_width(V) interleave_count(I)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+// CHECK: #pragma clang loop interleave_count(I)
+// CHECK: #pragma clang loop vectorize_width(V)
+
+void test_templates(int *List, int Length) {
+ test_nontype_template_param<2, 4>(List, Length);
+}
diff --git a/test/Misc/attr-source-range.cpp b/test/Misc/attr-source-range.cpp
new file mode 100644
index 000000000000..d5540ad64fa5
--- /dev/null
+++ b/test/Misc/attr-source-range.cpp
@@ -0,0 +1,16 @@
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-print-source-range-info %s 2>&1 | FileCheck %s
+
+void f(int i) __attribute__((format_arg(1)));
+// CHECK: attr-source-range.cpp:3:30:{3:41-3:42}{3:8-3:13}
+
+void g(int i, ...) __attribute__((format(printf, 1, 1)));
+// CHECK: attr-source-range.cpp:6:35:{6:50-6:51}{6:8-6:13}
+
+int h(void) __attribute__((returns_nonnull));
+// CHECK: attr-source-range.cpp:9:28:{9:1-9:4}
+
+void i(int j) __attribute__((nonnull(1)));
+// CHECK: attr-source-range.cpp:12:30:{12:38-12:39}{12:8-12:13}
+
+void j(__attribute__((nonnull)) int i);
+// CHECK: attr-source-range.cpp:15:23:{15:8-15:38}
diff --git a/test/Misc/diag-special-chars.c b/test/Misc/diag-special-chars.c
new file mode 100644
index 000000000000..e656a09b4279
--- /dev/null
+++ b/test/Misc/diag-special-chars.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -verify
+// RUN: not %clang_cc1 %s 2>&1 | FileCheck %s
+
+// There is a special characters on the following line, which is used as a
+// marker character for diagnostic printing. Ensure diagnostics involving
+// this character does not cause problems with the diagnostic printer.
+#error Hi  Bye
+//expected-error@-1 {{Hi Bye}}
+
+// CHECK: error: Hi Bye
+// CHECK: #error Hi <U+007F> Bye
diff --git a/test/Misc/serialized-diags-driver.c b/test/Misc/serialized-diags-driver.c
new file mode 100644
index 000000000000..ad07d666c8c1
--- /dev/null
+++ b/test/Misc/serialized-diags-driver.c
@@ -0,0 +1,20 @@
+// Test that the driver correctly combines its own diagnostics with CC1's in the
+// serialized diagnostics. To test this, we need to trigger diagnostics from
+// both processes, so we compile code that has a warning (with an associated
+// note) and then force the driver to crash. We compile stdin so that the crash
+// doesn't litter the user's system with preprocessed output.
+
+// RUN: rm -f %t
+// RUN: %clang -Wx-unknown-warning -Wall -fsyntax-only --serialize-diagnostics %t.diag %s
+// RUN: c-index-test -read-diagnostics %t.diag 2>&1 | FileCheck %s
+
+// CHECK: warning: unknown warning option '-Wx-unknown-warning' [-Wunknown-warning-option] []
+
+// CHECK: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized]
+// CHECK: note: initialize the variable 'voodoo' to silence this warning []
+// CHECK: Number of diagnostics: 2
+
+void foo() {
+ int voodoo;
+ voodoo = voodoo + 1;
+}
diff --git a/test/Misc/serialized-diags.m b/test/Misc/serialized-diags.m
index aac791e9e287..71c983b88385 100644
--- a/test/Misc/serialized-diags.m
+++ b/test/Misc/serialized-diags.m
@@ -21,7 +21,7 @@
// CHECK: Range: {{.*[/\\]}}serialized-diags.m:8:4 {{.*[/\\]}}serialized-diags.m:8:9
// CHECK: Number FIXITs = 1
// CHECK: FIXIT: ({{.*[/\\]}}serialized-diags.m:8:4 - {{.*[/\\]}}serialized-diags.m:8:9): "self"
-// CHECK: +-(null):0:0: note: 'self' is an implicit parameter [] []
+// CHECK: +-(null):0:0: note: 'self' is an implicit parameter [] [Semantic Issue]
// CHECK: Number FIXITs = 0
// CHECK: {{.*[/\\]}}serialized-diags.m:1:12: warning: class 'Foo' defined without specifying a base class [-Wobjc-root-class] [Semantic Issue]
// CHECK: Number FIXITs = 0
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index f58d2bf52b1f..74ab56667c94 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -18,8 +18,7 @@ This test serves two purposes:
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (103):
-CHECK-NEXT: ext_delete_void_ptr_operand
+CHECK: Warnings without flags (96):
CHECK-NEXT: ext_excess_initializers
CHECK-NEXT: ext_excess_initializers_in_char_array_initializer
CHECK-NEXT: ext_expected_semi_decl_list
@@ -90,7 +89,6 @@ CHECK-NEXT: warn_missing_dependent_template_keyword
CHECK-NEXT: warn_missing_exception_specification
CHECK-NEXT: warn_missing_whitespace_after_macro_name
CHECK-NEXT: warn_mt_message
-CHECK-NEXT: warn_multiple_method_decl
CHECK-NEXT: warn_no_constructor_for_refconst
CHECK-NEXT: warn_not_compound_assign
CHECK-NEXT: warn_objc_property_copy_missing_on_block
@@ -103,12 +101,7 @@ CHECK-NEXT: warn_pp_expr_overflow
CHECK-NEXT: warn_pp_line_decimal
CHECK-NEXT: warn_pragma_pack_pop_identifer_and_alignment
CHECK-NEXT: warn_pragma_pack_show
-CHECK-NEXT: warn_property_attr_mismatch
-CHECK-NEXT: warn_property_attribute
CHECK-NEXT: warn_property_getter_owning_mismatch
-CHECK-NEXT: warn_property_types_are_incompatible
-CHECK-NEXT: warn_readonly_property
-CHECK-NEXT: warn_redeclaration_without_attribute_prev_attribute_ignored
CHECK-NEXT: warn_register_objc_catch_parm
CHECK-NEXT: warn_related_result_type_compatibility_class
CHECK-NEXT: warn_related_result_type_compatibility_protocol
diff --git a/test/Modules/Inputs/AddRemovePrivate.framework/Headers/AddRemovePrivate.h b/test/Modules/Inputs/AddRemovePrivate.framework/Headers/AddRemovePrivate.h
new file mode 100644
index 000000000000..3ab77431aa2c
--- /dev/null
+++ b/test/Modules/Inputs/AddRemovePrivate.framework/Headers/AddRemovePrivate.h
@@ -0,0 +1 @@
+// AddRemovePrivate.h
diff --git a/test/Modules/Inputs/AddRemovePrivate.framework/Modules/module.modulemap b/test/Modules/Inputs/AddRemovePrivate.framework/Modules/module.modulemap
new file mode 100644
index 000000000000..7d84297a970f
--- /dev/null
+++ b/test/Modules/Inputs/AddRemovePrivate.framework/Modules/module.modulemap
@@ -0,0 +1 @@
+framework module AddRemovePrivate { umbrella header "AddRemovePrivate.h" }
diff --git a/test/Modules/Inputs/AddRemovePrivate.framework/Modules/module.private.modulemap b/test/Modules/Inputs/AddRemovePrivate.framework/Modules/module.private.modulemap
new file mode 100644
index 000000000000..69b67c2cee7a
--- /dev/null
+++ b/test/Modules/Inputs/AddRemovePrivate.framework/Modules/module.private.modulemap
@@ -0,0 +1 @@
+explicit module AddRemovePrivate.Private { }
diff --git a/test/Modules/Inputs/PR20399/FirstHeader.h b/test/Modules/Inputs/PR20399/FirstHeader.h
new file mode 100644
index 000000000000..43adf3d847ed
--- /dev/null
+++ b/test/Modules/Inputs/PR20399/FirstHeader.h
@@ -0,0 +1,14 @@
+#ifndef FIRSTHEADER
+#define FIRSTHEADER
+
+#include "SecondHeader.h" // Just a class which gets in the lazy deserialization chain
+
+#include "stl_map.h"
+#include "vector"
+typedef std::map<int>::iterator el;
+
+inline void func() {
+ std::vector<int>::func();
+}
+
+#endif
diff --git a/test/Modules/Inputs/PR20399/SecondHeader.h b/test/Modules/Inputs/PR20399/SecondHeader.h
new file mode 100644
index 000000000000..92815e996482
--- /dev/null
+++ b/test/Modules/Inputs/PR20399/SecondHeader.h
@@ -0,0 +1,13 @@
+#ifndef SECONDHEADER
+#define SECONDHEADER
+
+#include "vector"
+
+template <class T>
+struct Address {};
+
+template <>
+struct Address<std::vector<bool>>
+ : Address<std::vector<bool>::iterator> {};
+
+#endif
diff --git a/test/Modules/Inputs/PR20399/module.modulemap b/test/Modules/Inputs/PR20399/module.modulemap
new file mode 100644
index 000000000000..223434adba19
--- /dev/null
+++ b/test/Modules/Inputs/PR20399/module.modulemap
@@ -0,0 +1,18 @@
+module stdlib [system] {
+ header "stl_map.h"
+ header "vector"
+ }
+
+module libCore {
+ header "SecondHeader.h"
+ use stdlib
+ export *
+}
+
+module libGdml {
+ header "FirstHeader.h"
+ use libCore
+ use stdlib
+ export *
+}
+
diff --git a/test/Modules/Inputs/PR20399/stl_map.h b/test/Modules/Inputs/PR20399/stl_map.h
new file mode 100644
index 000000000000..334f8b308f40
--- /dev/null
+++ b/test/Modules/Inputs/PR20399/stl_map.h
@@ -0,0 +1,13 @@
+namespace std {
+struct reverse_iterator {};
+
+inline void
+operator-(int __x, reverse_iterator __y) {}
+
+template <typename _Key>
+struct map {
+ typedef int iterator;
+
+ friend bool operator<(const map &, const map &);
+};
+} // namespace std
diff --git a/test/Modules/Inputs/PR20399/vector b/test/Modules/Inputs/PR20399/vector
new file mode 100644
index 000000000000..1e1b6705f51b
--- /dev/null
+++ b/test/Modules/Inputs/PR20399/vector
@@ -0,0 +1,17 @@
+namespace std {
+template <typename _Tp, typename _Alloc = int>
+struct vector {
+ static void func() { vector *i, *j; i - j; }
+};
+
+struct bit_iterator { ~bit_iterator() {} };
+
+inline void operator-(int __x, const bit_iterator &__y) {
+}
+
+template <typename _Alloc>
+struct vector<bool, _Alloc> : bit_iterator {
+ typedef bit_iterator iterator;
+};
+
+} // namespace std
diff --git a/test/Modules/Inputs/PR20786/TBranchProxy.h b/test/Modules/Inputs/PR20786/TBranchProxy.h
new file mode 100644
index 000000000000..91f3730c3b88
--- /dev/null
+++ b/test/Modules/Inputs/PR20786/TBranchProxy.h
@@ -0,0 +1,2 @@
+#include "random.h"
+#include "TFormula.h"
diff --git a/test/Modules/Inputs/PR20786/TFormula.h b/test/Modules/Inputs/PR20786/TFormula.h
new file mode 100644
index 000000000000..316e3ad7222b
--- /dev/null
+++ b/test/Modules/Inputs/PR20786/TFormula.h
@@ -0,0 +1 @@
+#include "TMath.h"
diff --git a/test/Modules/Inputs/PR20786/TMath.h b/test/Modules/Inputs/PR20786/TMath.h
new file mode 100644
index 000000000000..b7dba620f7d1
--- /dev/null
+++ b/test/Modules/Inputs/PR20786/TMath.h
@@ -0,0 +1 @@
+#include "random.h"
diff --git a/test/Modules/Inputs/PR20786/module.modulemap b/test/Modules/Inputs/PR20786/module.modulemap
new file mode 100644
index 000000000000..daf78cd0cd3f
--- /dev/null
+++ b/test/Modules/Inputs/PR20786/module.modulemap
@@ -0,0 +1,3 @@
+module TMath { header "TMath.h" }
+module TFormula { header "TFormula.h" }
+module TBranchProxy { header "TBranchProxy.h" }
diff --git a/test/Modules/Inputs/PR20786/random.h b/test/Modules/Inputs/PR20786/random.h
new file mode 100644
index 000000000000..86a7d83c19c0
--- /dev/null
+++ b/test/Modules/Inputs/PR20786/random.h
@@ -0,0 +1,12 @@
+namespace std {
+ template<typename> struct mersenne_twister_engine {
+ friend bool operator==(const mersenne_twister_engine &,
+ const mersenne_twister_engine &) {
+ return false;
+ }
+ };
+ struct random_device {
+ mersenne_twister_engine<int> mt; // require complete type
+ };
+}
+
diff --git a/test/Modules/Inputs/StdDef/include_again.h b/test/Modules/Inputs/StdDef/include_again.h
new file mode 100644
index 000000000000..f29f6366cc69
--- /dev/null
+++ b/test/Modules/Inputs/StdDef/include_again.h
@@ -0,0 +1,2 @@
+#include <stddef.h>
+
diff --git a/test/Modules/Inputs/StdDef/module.map b/test/Modules/Inputs/StdDef/module.map
index 69c69eac35b5..5c4e0dae7ba6 100644
--- a/test/Modules/Inputs/StdDef/module.map
+++ b/test/Modules/Inputs/StdDef/module.map
@@ -8,4 +8,14 @@ module StdDef {
header "other.h"
export *
}
+
+ module PtrDiffT {
+ header "ptrdiff_t.h"
+ export *
+ }
+
+ module IncludeAgain {
+ header "include_again.h"
+ export *
+ }
}
diff --git a/test/Modules/Inputs/StdDef/ptrdiff_t.h b/test/Modules/Inputs/StdDef/ptrdiff_t.h
new file mode 100644
index 000000000000..acb0ab81ffc7
--- /dev/null
+++ b/test/Modules/Inputs/StdDef/ptrdiff_t.h
@@ -0,0 +1,2 @@
+#define __need_ptrdiff_t
+#include <stddef.h>
diff --git a/test/Modules/Inputs/attr-unavailable/module.modulemap b/test/Modules/Inputs/attr-unavailable/module.modulemap
new file mode 100644
index 000000000000..a5159420c22c
--- /dev/null
+++ b/test/Modules/Inputs/attr-unavailable/module.modulemap
@@ -0,0 +1,4 @@
+module two { header "two.h" }
+module oneA { header "oneA.h" }
+module oneB { header "oneB.h" export oneA }
+module oneC { header "oneC.h" }
diff --git a/test/Modules/Inputs/attr-unavailable/oneA.h b/test/Modules/Inputs/attr-unavailable/oneA.h
new file mode 100644
index 000000000000..a4e572ffacd9
--- /dev/null
+++ b/test/Modules/Inputs/attr-unavailable/oneA.h
@@ -0,0 +1,4 @@
+@interface C
+-(void)method2 __attribute__((unavailable));
+-(void)method3 __attribute__((unavailable));
+@end
diff --git a/test/Modules/Inputs/attr-unavailable/oneB.h b/test/Modules/Inputs/attr-unavailable/oneB.h
new file mode 100644
index 000000000000..b9536ad15ba7
--- /dev/null
+++ b/test/Modules/Inputs/attr-unavailable/oneB.h
@@ -0,0 +1,5 @@
+@import oneA;
+
+@interface D
+-(void)method2;
+@end
diff --git a/test/Modules/Inputs/attr-unavailable/oneC.h b/test/Modules/Inputs/attr-unavailable/oneC.h
new file mode 100644
index 000000000000..9dc305e70fb4
--- /dev/null
+++ b/test/Modules/Inputs/attr-unavailable/oneC.h
@@ -0,0 +1,3 @@
+@interface E
+-(void)method3;
+@end
diff --git a/test/Modules/Inputs/attr-unavailable/two.h b/test/Modules/Inputs/attr-unavailable/two.h
new file mode 100644
index 000000000000..0423f610108d
--- /dev/null
+++ b/test/Modules/Inputs/attr-unavailable/two.h
@@ -0,0 +1,6 @@
+@interface A
+-(void)method1;
+@end
+@interface B
+-(void)method1 __attribute__((unavailable));
+@end
diff --git a/test/Modules/Inputs/cxx-decls-imported.h b/test/Modules/Inputs/cxx-decls-imported.h
index 38cc00d863f2..8c1e74f17c3c 100644
--- a/test/Modules/Inputs/cxx-decls-imported.h
+++ b/test/Modules/Inputs/cxx-decls-imported.h
@@ -23,3 +23,27 @@ void *operator new[](__SIZE_TYPE__);
extern int mergeUsedFlag;
inline int getMergeUsedFlag() { return mergeUsedFlag; }
+
+typedef struct {
+ int n;
+ int m;
+} NameForLinkage;
+
+struct HasVirtualFunctions {
+ virtual void f();
+};
+struct OverridesVirtualFunctions : HasVirtualFunctions {
+ void f();
+};
+extern "C" void ExternCFunction();
+
+typedef struct {
+ struct Inner {
+ int n;
+ };
+} NameForLinkage2;
+auto name_for_linkage2_inner_a = NameForLinkage2::Inner();
+typedef decltype(name_for_linkage2_inner_a) NameForLinkage2Inner;
+
+namespace Aliased { extern int a; }
+namespace Alias = Aliased;
diff --git a/test/Modules/Inputs/cxx-decls-merged.h b/test/Modules/Inputs/cxx-decls-merged.h
index ccc3b0154872..86e81a9bb681 100644
--- a/test/Modules/Inputs/cxx-decls-merged.h
+++ b/test/Modules/Inputs/cxx-decls-merged.h
@@ -1 +1,27 @@
extern int mergeUsedFlag;
+
+typedef struct {
+ int n;
+ int m;
+} NameForLinkage;
+extern NameForLinkage name_for_linkage;
+
+struct HasVirtualFunctions {
+ virtual void f();
+};
+struct OverridesVirtualFunctions : HasVirtualFunctions {
+ void f();
+};
+extern OverridesVirtualFunctions overrides_virtual_functions;
+extern "C" void ExternCFunction();
+
+typedef struct {
+ struct Inner {
+ int n;
+ };
+} NameForLinkage2;
+auto name_for_linkage2_inner_b = NameForLinkage2::Inner();
+typedef decltype(name_for_linkage2_inner_b) NameForLinkage2Inner;
+
+namespace Aliased { extern int b; }
+namespace Alias = Aliased;
diff --git a/test/Modules/Inputs/cxx-decls-premerged.h b/test/Modules/Inputs/cxx-decls-premerged.h
new file mode 100644
index 000000000000..064fb9ea67bb
--- /dev/null
+++ b/test/Modules/Inputs/cxx-decls-premerged.h
@@ -0,0 +1,3 @@
+extern "C" void ExternCFunction();
+
+#include "cxx-decls-imported.h"
diff --git a/test/Modules/Inputs/cxx-irgen-left.h b/test/Modules/Inputs/cxx-irgen-left.h
index ceb50846bbf4..31ae805c9a19 100644
--- a/test/Modules/Inputs/cxx-irgen-left.h
+++ b/test/Modules/Inputs/cxx-irgen-left.h
@@ -9,3 +9,18 @@ inline int instantiate_min() {
inline int instantiate_CtorInit(CtorInit<int> i = CtorInit<int>()) {
return i.a;
}
+
+namespace ImplicitSpecialMembers {
+ inline void create_left() {
+ // Trigger declaration, but not definition, of special members.
+ B b(0); C c(0); D d(0);
+ // Trigger definition of copy constructor.
+ C c2(c); D d2(d);
+ }
+}
+
+namespace OperatorDeleteLookup {
+ // Trigger definition of A::~A() and lookup of operator delete.
+ // Likewise for B<int>::~B().
+ inline void f() { A a; B<int> b; }
+}
diff --git a/test/Modules/Inputs/cxx-irgen-right.h b/test/Modules/Inputs/cxx-irgen-right.h
index 4400c760f07a..30686a12479a 100644
--- a/test/Modules/Inputs/cxx-irgen-right.h
+++ b/test/Modules/Inputs/cxx-irgen-right.h
@@ -1,3 +1,13 @@
#include "cxx-irgen-top.h"
inline int h() { return S<int>::f(); }
+
+namespace ImplicitSpecialMembers {
+ inline void create_right() {
+ // Trigger declaration, but not definition, of special members.
+ B b(0); C c(0); D d(0);
+ // Trigger definition of move constructor.
+ B b2(static_cast<B&&>(b));
+ D d2(static_cast<D&&>(d));
+ }
+}
diff --git a/test/Modules/Inputs/cxx-irgen-top.h b/test/Modules/Inputs/cxx-irgen-top.h
index 8753d8daa3dc..f1a0bee21250 100644
--- a/test/Modules/Inputs/cxx-irgen-top.h
+++ b/test/Modules/Inputs/cxx-irgen-top.h
@@ -14,3 +14,38 @@ template<typename T> struct CtorInit {
int a;
CtorInit() : a(f()) {}
};
+
+namespace ImplicitSpecialMembers {
+ struct A {
+ A(const A&);
+ };
+ struct B {
+ A a;
+ B(int);
+ };
+ struct C {
+ A a;
+ C(int);
+ };
+ struct D {
+ A a;
+ D(int);
+ };
+}
+
+namespace OperatorDeleteLookup {
+ struct A { void operator delete(void*); virtual ~A() = default; };
+ template<typename T> struct B { void operator delete(void*); virtual ~B() {} typedef int t; };
+ typedef B<int>::t b_int_instantated;
+}
+
+namespace EmitInlineMethods {
+ struct A {
+ void f() {}
+ void g();
+ };
+ struct B {
+ void f();
+ void g() {}
+ };
+}
diff --git a/test/Modules/Inputs/cxx-lookup/a.h b/test/Modules/Inputs/cxx-lookup/a.h
new file mode 100644
index 000000000000..25f614fe50b9
--- /dev/null
+++ b/test/Modules/Inputs/cxx-lookup/a.h
@@ -0,0 +1,2 @@
+// a
+namespace llvm { class GlobalValue; }
diff --git a/test/Modules/Inputs/cxx-lookup/b.h b/test/Modules/Inputs/cxx-lookup/b.h
new file mode 100644
index 000000000000..c2ede9f28dc2
--- /dev/null
+++ b/test/Modules/Inputs/cxx-lookup/b.h
@@ -0,0 +1,3 @@
+// b
+namespace llvm { class GlobalValue; }
+#include "y.h"
diff --git a/test/Modules/Inputs/cxx-lookup/c1.h b/test/Modules/Inputs/cxx-lookup/c1.h
new file mode 100644
index 000000000000..dba4a4c0a00e
--- /dev/null
+++ b/test/Modules/Inputs/cxx-lookup/c1.h
@@ -0,0 +1,3 @@
+// c1
+#include "a.h"
+#include "b.h"
diff --git a/test/Modules/Inputs/cxx-lookup/c2.h b/test/Modules/Inputs/cxx-lookup/c2.h
new file mode 100644
index 000000000000..463e270e267a
--- /dev/null
+++ b/test/Modules/Inputs/cxx-lookup/c2.h
@@ -0,0 +1,2 @@
+// c2
+namespace llvm { class GlobalValue; }
diff --git a/test/Modules/Inputs/cxx-lookup/module.modulemap b/test/Modules/Inputs/cxx-lookup/module.modulemap
new file mode 100644
index 000000000000..6d397af250c8
--- /dev/null
+++ b/test/Modules/Inputs/cxx-lookup/module.modulemap
@@ -0,0 +1,8 @@
+module A { header "a.h" export * }
+module B { header "b.h" export * }
+module C {
+ module C2 { header "c2.h" export * }
+ module C1 { header "c1.h" export * }
+}
+module X { header "x.h" export * }
+module Y { header "y.h" export * }
diff --git a/test/Modules/Inputs/cxx-lookup/x.h b/test/Modules/Inputs/cxx-lookup/x.h
new file mode 100644
index 000000000000..a8826e005817
--- /dev/null
+++ b/test/Modules/Inputs/cxx-lookup/x.h
@@ -0,0 +1,2 @@
+template <class T> class allocator;
+struct X { virtual allocator<char> f(); };
diff --git a/test/Modules/Inputs/cxx-lookup/y.h b/test/Modules/Inputs/cxx-lookup/y.h
new file mode 100644
index 000000000000..8867e8a8becd
--- /dev/null
+++ b/test/Modules/Inputs/cxx-lookup/y.h
@@ -0,0 +1,5 @@
+#include "x.h"
+namespace llvm {
+ struct ulittle32_t;
+ extern allocator<ulittle32_t> *x;
+}
diff --git a/test/Modules/Inputs/cxx-templates-a.h b/test/Modules/Inputs/cxx-templates-a.h
index c95dc6325e49..4340910d1e2a 100644
--- a/test/Modules/Inputs/cxx-templates-a.h
+++ b/test/Modules/Inputs/cxx-templates-a.h
@@ -29,6 +29,8 @@ void use_some_template_a() {
SomeTemplate<char[2]> a;
SomeTemplate<char[1]> b, c;
b = c;
+
+ (void)&WithImplicitSpecialMembers<int>::n;
}
template<int> struct MergeTemplates;
@@ -56,6 +58,7 @@ template<typename T> struct WithPartialSpecialization<T*> {
T &f() { static T t; return t; }
};
typedef WithPartialSpecializationUse::type WithPartialSpecializationInstantiate;
+typedef WithPartialSpecialization<void(int)>::type WithPartialSpecializationInstantiate2;
template<> struct WithExplicitSpecialization<int> {
int n;
@@ -73,3 +76,31 @@ template<typename T> struct MergeTemplateDefinitions {
static constexpr int g();
};
template<typename T> constexpr int MergeTemplateDefinitions<T>::f() { return 1; }
+
+template<typename T> using AliasTemplate = T;
+
+template<typename T> struct PartiallyInstantiatePartialSpec {};
+template<typename T> struct PartiallyInstantiatePartialSpec<T*> {
+ static T *foo() { return reinterpret_cast<T*>(0); }
+ static T *bar() { return reinterpret_cast<T*>(0); }
+};
+typedef PartiallyInstantiatePartialSpec<int*> PartiallyInstantiatePartialSpecHelper;
+
+void InstantiateWithAliasTemplate(WithAliasTemplate<int>::X<char>);
+inline int InstantiateWithAnonymousDeclsA(WithAnonymousDecls<int> x) { return (x.k ? x.a : x.b) + (x.k ? x.s.c : x.s.d) + x.e; }
+inline int InstantiateWithAnonymousDeclsB2(WithAnonymousDecls<char> x);
+
+
+template<typename T1 = int>
+struct MergeAnonUnionMember {
+ MergeAnonUnionMember() { (void)values.t1; }
+ union { int t1; } values;
+};
+inline MergeAnonUnionMember<> maum_a() { return {}; }
+
+template<typename T> struct DontWalkPreviousDeclAfterMerging { struct Inner { typedef T type; }; };
+
+namespace TestInjectedClassName {
+ template<typename T> struct X { X(); };
+ typedef X<char[1]> A;
+}
diff --git a/test/Modules/Inputs/cxx-templates-b.h b/test/Modules/Inputs/cxx-templates-b.h
index efd07c617e52..d763c8040ba3 100644
--- a/test/Modules/Inputs/cxx-templates-b.h
+++ b/test/Modules/Inputs/cxx-templates-b.h
@@ -24,6 +24,11 @@ template<typename T> template<typename U>
constexpr int Outer<T>::Inner<U>::g() { return 2; }
static_assert(Outer<int>::Inner<int>::g() == 2, "");
+namespace TestInjectedClassName {
+ template<typename T> struct X { X(); };
+ typedef X<char[2]> B;
+}
+
@import cxx_templates_b_impl;
template<typename T, typename> struct Identity { typedef T type; };
@@ -46,6 +51,8 @@ void use_some_template_b() {
SomeTemplate<char[1]> a;
SomeTemplate<char[2]> b, c;
b = c;
+
+ WithImplicitSpecialMembers<int> wism1, wism2(wism1);
}
auto enum_b_from_b = CommonTemplate<int>::b;
@@ -55,6 +62,8 @@ template<int> struct UseInt;
template<typename T> void UseRedeclaredEnum(UseInt<T() + CommonTemplate<char>::a>);
constexpr void (*UseRedeclaredEnumB)(UseInt<1>) = UseRedeclaredEnum<int>;
+typedef WithPartialSpecialization<void(int)>::type WithPartialSpecializationInstantiate3;
+
template<typename> struct MergeSpecializations;
template<typename T> struct MergeSpecializations<T&> {
typedef int partially_specialized_in_b;
@@ -63,6 +72,16 @@ template<> struct MergeSpecializations<double> {
typedef int explicitly_specialized_in_b;
};
+template<typename U> using AliasTemplate = U;
+
+void InstantiateWithAliasTemplate(WithAliasTemplate<int>::X<char>);
+inline int InstantiateWithAnonymousDeclsB(WithAnonymousDecls<int> x) {
+ return (x.k ? x.a : x.b) + (x.k ? x.s.c : x.s.d) + x.e;
+}
+inline int InstantiateWithAnonymousDeclsB2(WithAnonymousDecls<char> x) {
+ return (x.k ? x.a : x.b) + (x.k ? x.s.c : x.s.d) + x.e;
+}
+
@import cxx_templates_a;
template<typename T> void UseDefinedInBImplIndirectly(T &v) {
PerformDelayedLookup(v);
@@ -71,4 +90,6 @@ template<typename T> void UseDefinedInBImplIndirectly(T &v) {
void TriggerInstantiation() {
UseDefinedInBImpl<void>();
Std::f<int>();
+ PartiallyInstantiatePartialSpec<int*>::foo();
+ WithPartialSpecialization<void(int)>::type x;
}
diff --git a/test/Modules/Inputs/cxx-templates-c.h b/test/Modules/Inputs/cxx-templates-c.h
index 6daffadc6ced..e5395b6c7ed8 100644
--- a/test/Modules/Inputs/cxx-templates-c.h
+++ b/test/Modules/Inputs/cxx-templates-c.h
@@ -11,3 +11,18 @@ template<typename T> struct MergeTemplateDefinitions {
static constexpr int g();
};
template<typename T> constexpr int MergeTemplateDefinitions<T>::g() { return 2; }
+
+template<typename T1 = int>
+struct MergeAnonUnionMember {
+ MergeAnonUnionMember() { (void)values.t1; }
+ union { int t1; } values;
+};
+inline MergeAnonUnionMember<> maum_c() { return {}; }
+
+template<typename T> struct DontWalkPreviousDeclAfterMerging { struct Inner { typedef T type; }; };
+typedef DontWalkPreviousDeclAfterMerging<char>::Inner dwpdam_typedef;
+
+namespace TestInjectedClassName {
+ template<typename T> struct X { X(); };
+ typedef X<char[3]> C;
+}
diff --git a/test/Modules/Inputs/cxx-templates-common.h b/test/Modules/Inputs/cxx-templates-common.h
index 682ef939cec0..a9ca62448671 100644
--- a/test/Modules/Inputs/cxx-templates-common.h
+++ b/test/Modules/Inputs/cxx-templates-common.h
@@ -32,7 +32,25 @@ template<typename T> struct Outer {
};
template<typename T> struct WithPartialSpecialization {};
+template<typename T> struct WithPartialSpecialization<void(T)> { typedef int type; };
typedef WithPartialSpecialization<int*> WithPartialSpecializationUse;
+typedef WithPartialSpecialization<void(int)> WithPartialSpecializationUse2;
template<typename T> struct WithExplicitSpecialization;
typedef WithExplicitSpecialization<int> WithExplicitSpecializationUse;
+
+template<typename T> struct WithImplicitSpecialMembers { int n; };
+
+template<typename T> struct WithAliasTemplate {
+ template<typename> using X = T;
+};
+
+template<typename T> struct WithAnonymousDecls {
+ struct { bool k; };
+ union { int a, b; };
+ struct { int c, d; } s;
+ enum { e = 123 };
+ typedef int X;
+};
+
+#include "cxx-templates-textual.h"
diff --git a/test/Modules/Inputs/cxx-templates-d.h b/test/Modules/Inputs/cxx-templates-d.h
new file mode 100644
index 000000000000..1fb1a2282b96
--- /dev/null
+++ b/test/Modules/Inputs/cxx-templates-d.h
@@ -0,0 +1,9 @@
+@import cxx_templates_common;
+
+inline int InstantiateWithAnonymousDeclsD(WithAnonymousDecls<char> x) { return (x.k ? x.a : x.b) + (x.k ? x.s.c : x.s.d) + x.e; }
+
+namespace TestInjectedClassName {
+ template<typename T> struct X { X(); };
+ typedef X<int> D;
+ inline D UseD() { return D(); }
+}
diff --git a/test/Modules/Inputs/cxx-templates-textual.h b/test/Modules/Inputs/cxx-templates-textual.h
new file mode 100644
index 000000000000..8bffb8eddc28
--- /dev/null
+++ b/test/Modules/Inputs/cxx-templates-textual.h
@@ -0,0 +1,2 @@
+template<typename T> struct MergeClassTemplateSpecializations_basic_string {};
+typedef MergeClassTemplateSpecializations_basic_string<char> MergeClassTemplateSpecializations_string;
diff --git a/test/Modules/Inputs/declare-use/k.h b/test/Modules/Inputs/declare-use/k.h
new file mode 100644
index 000000000000..338178e86cb3
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/k.h
@@ -0,0 +1,8 @@
+#ifdef GIMME_A_K
+
+#ifndef K_H
+#define K_H
+const int k = 42;
+#endif
+
+#endif
diff --git a/test/Modules/Inputs/declare-use/l.h b/test/Modules/Inputs/declare-use/l.h
new file mode 100644
index 000000000000..a43fd1a3d063
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/l.h
@@ -0,0 +1,8 @@
+#ifdef GIMME_AN_L
+
+#ifndef L_H
+#define L_H
+const int l = 42;
+#endif
+
+#endif
diff --git a/test/Modules/Inputs/declare-use/m.h b/test/Modules/Inputs/declare-use/m.h
new file mode 100644
index 000000000000..e9089ab725d5
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/m.h
@@ -0,0 +1,8 @@
+#ifdef GIMME_AN_M
+
+#ifndef M_H
+#define M_H
+const int m = 42;
+#endif
+
+#endif
diff --git a/test/Modules/Inputs/declare-use/m2.h b/test/Modules/Inputs/declare-use/m2.h
new file mode 100644
index 000000000000..9e72835c3bce
--- /dev/null
+++ b/test/Modules/Inputs/declare-use/m2.h
@@ -0,0 +1 @@
+#include "m.h"
diff --git a/test/Modules/Inputs/declare-use/module.map b/test/Modules/Inputs/declare-use/module.map
index a176fb3a141f..ae8615278aca 100644
--- a/test/Modules/Inputs/declare-use/module.map
+++ b/test/Modules/Inputs/declare-use/module.map
@@ -38,6 +38,7 @@ module XG {
use XC
use XE
use XJ
+ use XK
}
module XH {
@@ -52,5 +53,18 @@ module XJ {
header "j.h"
}
+module XK {
+ textual header "k.h"
+}
+
+module XL {
+ textual header "l.h"
+}
+
+module XM {
+ private textual header "m.h"
+ textual header "m2.h"
+}
+
module XS {
}
diff --git a/test/Modules/Inputs/dependency-gen-base.modulemap b/test/Modules/Inputs/dependency-gen-base.modulemap
new file mode 100644
index 000000000000..8b30ffa67455
--- /dev/null
+++ b/test/Modules/Inputs/dependency-gen-base.modulemap
@@ -0,0 +1,6 @@
+module "test-base" {
+ export *
+ header "Inputs/dependency-gen-included.h"
+ use "test-base2"
+}
+extern module "test-base2" "Inputs/dependency-gen-base2.modulemap"
diff --git a/test/Modules/Inputs/dependency-gen-base2.modulemap b/test/Modules/Inputs/dependency-gen-base2.modulemap
new file mode 100644
index 000000000000..7808c8041aec
--- /dev/null
+++ b/test/Modules/Inputs/dependency-gen-base2.modulemap
@@ -0,0 +1,4 @@
+module "test-base2" {
+ export *
+ textual header "Inputs/dependency-gen-included2.h"
+}
diff --git a/test/Modules/Inputs/dependency-gen-included.h b/test/Modules/Inputs/dependency-gen-included.h
new file mode 100644
index 000000000000..0e1cdfcd1e18
--- /dev/null
+++ b/test/Modules/Inputs/dependency-gen-included.h
@@ -0,0 +1,9 @@
+//#ifndef DEPENDENCY_GEN_INCLUDED_H
+//#define DEPENDENCY_GEN_INCLUDED_H
+
+#include "Inputs/dependency-gen-included2.h"
+
+void g() {
+}
+
+//#endif
diff --git a/test/Modules/Inputs/dependency-gen-included2.h b/test/Modules/Inputs/dependency-gen-included2.h
new file mode 100644
index 000000000000..fcd8f12ba5ad
--- /dev/null
+++ b/test/Modules/Inputs/dependency-gen-included2.h
@@ -0,0 +1,7 @@
+#ifndef DEPENDENCY_GEN_INCLUDED2_H
+#define DEPENDENCY_GEN_INCLUDED2_H
+
+void h() {
+}
+
+#endif
diff --git a/test/Modules/Inputs/dependency-gen.h b/test/Modules/Inputs/dependency-gen.h
new file mode 100644
index 000000000000..2671e262c6ac
--- /dev/null
+++ b/test/Modules/Inputs/dependency-gen.h
@@ -0,0 +1,11 @@
+//#ifndef DEPENDENCY_GEN_H
+//#define DEPENDENCY_GEN_H
+
+#include "dependency-gen-included.h"
+
+void f() {
+ g();
+ h();
+}
+
+//#endif
diff --git a/test/Modules/Inputs/diamond_left.h b/test/Modules/Inputs/diamond_left.h
index fce2e48882f8..6494551e4bfa 100644
--- a/test/Modules/Inputs/diamond_left.h
+++ b/test/Modules/Inputs/diamond_left.h
@@ -1,3 +1,5 @@
+int top_left_before(void *);
+
@import diamond_top;
float left(float *);
diff --git a/test/Modules/Inputs/diamond_top.h b/test/Modules/Inputs/diamond_top.h
index 34998cd4324b..30da14f6449b 100644
--- a/test/Modules/Inputs/diamond_top.h
+++ b/test/Modules/Inputs/diamond_top.h
@@ -2,3 +2,4 @@ int top(int *);
int top_left(char *c);
+int top_left_before(void *);
diff --git a/test/Modules/Inputs/explicit-build/a.h b/test/Modules/Inputs/explicit-build/a.h
new file mode 100644
index 000000000000..5e3602f58ffe
--- /dev/null
+++ b/test/Modules/Inputs/explicit-build/a.h
@@ -0,0 +1,5 @@
+#if !__building_module(a)
+#error "should only get here when building module a"
+#endif
+
+const int a = 1;
diff --git a/test/Modules/Inputs/explicit-build/b.h b/test/Modules/Inputs/explicit-build/b.h
new file mode 100644
index 000000000000..449b3859ab45
--- /dev/null
+++ b/test/Modules/Inputs/explicit-build/b.h
@@ -0,0 +1,7 @@
+#include "a.h"
+
+#if !__building_module(b)
+#error "should only get here when building module b"
+#endif
+
+const int b = 2;
diff --git a/test/Modules/Inputs/explicit-build/c.h b/test/Modules/Inputs/explicit-build/c.h
new file mode 100644
index 000000000000..2c66a23e8927
--- /dev/null
+++ b/test/Modules/Inputs/explicit-build/c.h
@@ -0,0 +1,7 @@
+#include "b.h"
+
+#if !__building_module(c)
+#error "should only get here when building module c"
+#endif
+
+const int c = 3;
diff --git a/test/Modules/Inputs/explicit-build/module.modulemap b/test/Modules/Inputs/explicit-build/module.modulemap
new file mode 100644
index 000000000000..bd6ea830c2d4
--- /dev/null
+++ b/test/Modules/Inputs/explicit-build/module.modulemap
@@ -0,0 +1,3 @@
+module a { header "a.h" }
+module b { header "b.h" export * }
+module c { header "c.h" export * }
diff --git a/test/Modules/Inputs/filename/a.h b/test/Modules/Inputs/filename/a.h
new file mode 100644
index 000000000000..8f896a9ba8f4
--- /dev/null
+++ b/test/Modules/Inputs/filename/a.h
@@ -0,0 +1 @@
+const char *p = __FILE__;
diff --git a/test/Modules/Inputs/filename/module.map b/test/Modules/Inputs/filename/module.map
new file mode 100644
index 000000000000..ff164ad7bac8
--- /dev/null
+++ b/test/Modules/Inputs/filename/module.map
@@ -0,0 +1,3 @@
+module "A" {
+ header "a.h"
+}
diff --git a/test/Modules/Inputs/include_next/x/a.h b/test/Modules/Inputs/include_next/x/a.h
new file mode 100644
index 000000000000..71822876313a
--- /dev/null
+++ b/test/Modules/Inputs/include_next/x/a.h
@@ -0,0 +1,2 @@
+#include_next "a.h"
+enum { ax = 1 };
diff --git a/test/Modules/Inputs/include_next/x/module.modulemap b/test/Modules/Inputs/include_next/x/module.modulemap
new file mode 100644
index 000000000000..d0956d98ab84
--- /dev/null
+++ b/test/Modules/Inputs/include_next/x/module.modulemap
@@ -0,0 +1,2 @@
+module xa { header "a.h" export * }
+module xb { header "subdir/b.h" export * }
diff --git a/test/Modules/Inputs/include_next/x/subdir/b.h b/test/Modules/Inputs/include_next/x/subdir/b.h
new file mode 100644
index 000000000000..d9449e11a32f
--- /dev/null
+++ b/test/Modules/Inputs/include_next/x/subdir/b.h
@@ -0,0 +1,2 @@
+#include_next <b.h>
+enum { bx = 3 };
diff --git a/test/Modules/Inputs/include_next/y/a.h b/test/Modules/Inputs/include_next/y/a.h
new file mode 100644
index 000000000000..703ec958785d
--- /dev/null
+++ b/test/Modules/Inputs/include_next/y/a.h
@@ -0,0 +1 @@
+enum { ay = 2 };
diff --git a/test/Modules/Inputs/include_next/y/b.h b/test/Modules/Inputs/include_next/y/b.h
new file mode 100644
index 000000000000..629e7fde1fe2
--- /dev/null
+++ b/test/Modules/Inputs/include_next/y/b.h
@@ -0,0 +1 @@
+enum { by = 4 };
diff --git a/test/Modules/Inputs/include_next/y/module.modulemap b/test/Modules/Inputs/include_next/y/module.modulemap
new file mode 100644
index 000000000000..5dc3c535cefc
--- /dev/null
+++ b/test/Modules/Inputs/include_next/y/module.modulemap
@@ -0,0 +1,2 @@
+module ya { header "a.h" export * }
+module yb { header "b.h" export * }
diff --git a/test/Modules/Inputs/inferred-attr/InferredExternC.framework/Headers/InferredExternC.h b/test/Modules/Inputs/inferred-attr/InferredExternC.framework/Headers/InferredExternC.h
new file mode 100644
index 000000000000..63242fae9a11
--- /dev/null
+++ b/test/Modules/Inputs/inferred-attr/InferredExternC.framework/Headers/InferredExternC.h
@@ -0,0 +1 @@
+// InferredExternC.h
diff --git a/test/Modules/Inputs/inferred-attr/module.modulemap b/test/Modules/Inputs/inferred-attr/module.modulemap
new file mode 100644
index 000000000000..beb6ea159de3
--- /dev/null
+++ b/test/Modules/Inputs/inferred-attr/module.modulemap
@@ -0,0 +1 @@
+framework module * [extern_c] { }
diff --git a/test/Modules/Inputs/macros_bottom.h b/test/Modules/Inputs/macros_bottom.h
new file mode 100644
index 000000000000..fc0a78e46207
--- /dev/null
+++ b/test/Modules/Inputs/macros_bottom.h
@@ -0,0 +1,3 @@
+@import macros_right;
+
+extern TOP_DEF_RIGHT_UNDEF *TDRUp;
diff --git a/test/Modules/Inputs/macros_right_undef.h b/test/Modules/Inputs/macros_right_undef.h
index 15a83666a136..5084561e108b 100644
--- a/test/Modules/Inputs/macros_right_undef.h
+++ b/test/Modules/Inputs/macros_right_undef.h
@@ -2,3 +2,4 @@
@import macros_top;
#undef TOP_OTHER_DEF_RIGHT_UNDEF
+#undef TOP_DEF_RIGHT_UNDEF
diff --git a/test/Modules/Inputs/macros_top.h b/test/Modules/Inputs/macros_top.h
index 10935043e2a1..e063133a172d 100644
--- a/test/Modules/Inputs/macros_top.h
+++ b/test/Modules/Inputs/macros_top.h
@@ -22,3 +22,4 @@
#define TOP_OTHER_DEF_RIGHT_UNDEF void
#define TOP_REDEF_IN_SUBMODULES 0
+#define TOP_DEF_RIGHT_UNDEF void
diff --git a/test/Modules/Inputs/malformed/c.h b/test/Modules/Inputs/malformed/c.h
new file mode 100644
index 000000000000..2cce2ca9caa2
--- /dev/null
+++ b/test/Modules/Inputs/malformed/c.h
@@ -0,0 +1 @@
+template<typename T> void f() { T::error; }
diff --git a/test/Modules/Inputs/malformed/module.map b/test/Modules/Inputs/malformed/module.map
index 5277ffa41edd..3f088d1431d9 100644
--- a/test/Modules/Inputs/malformed/module.map
+++ b/test/Modules/Inputs/malformed/module.map
@@ -6,3 +6,4 @@ module malformed_b {
module b1 { header "b1.h" }
module b2 { header "b2.h" }
}
+module c { header "c.h" }
diff --git a/test/Modules/Inputs/merge-typedefs/a1.h b/test/Modules/Inputs/merge-typedefs/a1.h
new file mode 100644
index 000000000000..cacc530c3d0a
--- /dev/null
+++ b/test/Modules/Inputs/merge-typedefs/a1.h
@@ -0,0 +1,11 @@
+#ifndef A1_H
+#define A1_H
+namespace llvm {
+class MachineBasicBlock;
+template <class NodeT> class DomTreeNodeBase;
+typedef DomTreeNodeBase<MachineBasicBlock> MachineDomTreeNode;
+}
+
+typedef struct {} foo_t;
+typedef foo_t foo2_t;
+#endif
diff --git a/test/Modules/Inputs/merge-typedefs/a2.h b/test/Modules/Inputs/merge-typedefs/a2.h
new file mode 100644
index 000000000000..ba306663e3b5
--- /dev/null
+++ b/test/Modules/Inputs/merge-typedefs/a2.h
@@ -0,0 +1,3 @@
+#ifndef A2_H
+#define A2_H
+#endif
diff --git a/test/Modules/Inputs/merge-typedefs/b1.h b/test/Modules/Inputs/merge-typedefs/b1.h
new file mode 100644
index 000000000000..8dde5f6fbadd
--- /dev/null
+++ b/test/Modules/Inputs/merge-typedefs/b1.h
@@ -0,0 +1,11 @@
+#ifndef B1_H
+#define B1_H
+typedef struct {} foo_t;
+typedef foo_t foo2_t;
+#include "a2.h"
+namespace llvm {
+class MachineBasicBlock;
+template <class NodeT> class DomTreeNodeBase;
+typedef DomTreeNodeBase<MachineBasicBlock> MachineDomTreeNode;
+}
+#endif
diff --git a/test/Modules/Inputs/merge-typedefs/b2.h b/test/Modules/Inputs/merge-typedefs/b2.h
new file mode 100644
index 000000000000..75bd63affb16
--- /dev/null
+++ b/test/Modules/Inputs/merge-typedefs/b2.h
@@ -0,0 +1,3 @@
+#ifndef B2_H
+#define B2_H
+#endif
diff --git a/test/Modules/Inputs/merge-typedefs/module.modulemap b/test/Modules/Inputs/merge-typedefs/module.modulemap
new file mode 100644
index 000000000000..4858f1be63ac
--- /dev/null
+++ b/test/Modules/Inputs/merge-typedefs/module.modulemap
@@ -0,0 +1,9 @@
+module A {
+ module A1 { header "a1.h" export * }
+ module A2 { header "a2.h" export * }
+}
+
+module B {
+ module B1 { header "b1.h" export * }
+ module B2 { header "b2.h" export * }
+}
diff --git a/test/Modules/Inputs/merge-using-decls/a.h b/test/Modules/Inputs/merge-using-decls/a.h
new file mode 100644
index 000000000000..0fe0067bf23c
--- /dev/null
+++ b/test/Modules/Inputs/merge-using-decls/a.h
@@ -0,0 +1,43 @@
+struct X {
+ int v;
+ typedef int t;
+};
+
+struct YA {
+ int value;
+ typedef int type;
+};
+
+template<typename T> struct C : X, T {
+ using T::value;
+ using typename T::type;
+ using X::v;
+ using typename X::t;
+};
+
+template<typename T> struct D : X, T {
+ using T::value;
+ using typename T::type;
+ using X::v;
+ using typename X::t;
+};
+
+template<typename T> struct E : X, T {
+ using T::value;
+ using typename T::type;
+ using X::v;
+ using typename X::t;
+};
+
+template<typename T> struct F : X, T {
+ using T::value;
+ using typename T::type;
+ using X::v;
+ using typename X::t;
+};
+
+// Force instantiation.
+typedef C<YA>::type I;
+typedef D<YA>::type I;
+typedef E<YA>::type I;
+typedef F<YA>::type I;
diff --git a/test/Modules/Inputs/merge-using-decls/b.h b/test/Modules/Inputs/merge-using-decls/b.h
new file mode 100644
index 000000000000..359555570a43
--- /dev/null
+++ b/test/Modules/Inputs/merge-using-decls/b.h
@@ -0,0 +1,50 @@
+struct X {
+ int v;
+ typedef int t;
+};
+
+struct YB {
+ typedef YB Y;
+ int value;
+ typedef int type;
+};
+
+struct YBRev {
+ typedef int value;
+ int type;
+};
+
+template<typename T> struct C : X, T {
+ using T::value;
+ using typename T::type;
+ using X::v;
+ using typename X::t;
+};
+
+template<typename T> struct D : X, T {
+ // Mismatch in type/non-type-ness.
+ using typename T::value;
+ using T::type;
+ using X::v;
+ using typename X::t;
+};
+
+template<typename T> struct E : X, T {
+ // Mismatch in using/access-declaration-ness.
+ T::value;
+ X::v;
+};
+
+template<typename T> struct F : X, T {
+ // Mismatch in nested-name-specifier.
+ using T::Y::value;
+ using typename T::Y::type;
+ using ::X::v;
+ using typename ::X::t;
+};
+
+// Force instantiation.
+typedef C<YB>::type I;
+typedef D<YBRev>::t I;
+typedef E<YB>::type I;
+typedef F<YB>::type I;
diff --git a/test/Modules/Inputs/merge-using-decls/module.modulemap b/test/Modules/Inputs/merge-using-decls/module.modulemap
new file mode 100644
index 000000000000..a415527813c7
--- /dev/null
+++ b/test/Modules/Inputs/merge-using-decls/module.modulemap
@@ -0,0 +1,2 @@
+module A { header "a.h" }
+module B { header "b.h" }
diff --git a/test/Modules/Inputs/modular_maps-moduleb-cwd.map b/test/Modules/Inputs/modular_maps-moduleb-cwd.map
new file mode 100644
index 000000000000..1ff307f4b3df
--- /dev/null
+++ b/test/Modules/Inputs/modular_maps-moduleb-cwd.map
@@ -0,0 +1,4 @@
+module B {
+ header "Inputs/modular_maps/common.h"
+ private header "Inputs/modular_maps/b.h"
+}
diff --git a/test/Modules/Inputs/modular_maps/c.h b/test/Modules/Inputs/modular_maps/c.h
new file mode 100644
index 000000000000..6e3468e72602
--- /dev/null
+++ b/test/Modules/Inputs/modular_maps/c.h
@@ -0,0 +1,4 @@
+#ifndef C_H
+#define C_H
+const int c = 5;
+#endif
diff --git a/test/Modules/Inputs/modular_maps/common.h b/test/Modules/Inputs/modular_maps/common.h
index f690bcbd399b..349bf5f7c473 100644
--- a/test/Modules/Inputs/modular_maps/common.h
+++ b/test/Modules/Inputs/modular_maps/common.h
@@ -1,4 +1,4 @@
#ifndef COMMON_H
#define COMMON_H
-const int c = 2;
+const int x = 2;
#endif
diff --git a/test/Modules/Inputs/modular_maps/modulea-cwd.map b/test/Modules/Inputs/modular_maps/modulea-cwd.map
new file mode 100644
index 000000000000..10be5237fc7a
--- /dev/null
+++ b/test/Modules/Inputs/modular_maps/modulea-cwd.map
@@ -0,0 +1,7 @@
+module A {
+ header "Inputs/modular_maps/common.h"
+ header "Inputs/modular_maps/a.h"
+}
+
+extern module B "Inputs/modular_maps-moduleb-cwd.map"
+
diff --git a/test/Modules/Inputs/modular_maps/modulec-cwd.map b/test/Modules/Inputs/modular_maps/modulec-cwd.map
new file mode 100644
index 000000000000..ca38b542df4a
--- /dev/null
+++ b/test/Modules/Inputs/modular_maps/modulec-cwd.map
@@ -0,0 +1,3 @@
+module C {
+ header "Inputs/modular_maps/c.h"
+}
diff --git a/test/Modules/Inputs/modular_maps/modulec.map b/test/Modules/Inputs/modular_maps/modulec.map
new file mode 100644
index 000000000000..c5a1ffe4577c
--- /dev/null
+++ b/test/Modules/Inputs/modular_maps/modulec.map
@@ -0,0 +1,3 @@
+module C {
+ header "c.h"
+}
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
index fea12015233b..7040ee7e5ab6 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -40,6 +40,10 @@ module macros_right {
header "macros_right_undef.h"
}
}
+module macros_bottom {
+ header "macros_bottom.h"
+ export *
+}
module macros { header "macros.h" }
module macros_other { header "macros_other.h" }
module category_top { header "category_top.h" }
@@ -229,6 +233,10 @@ module cxx_templates_c {
header "cxx-templates-c.h"
}
+module cxx_templates_d {
+ header "cxx-templates-d.h"
+}
+
module cxx_decls {
module unimported {
header "cxx-decls-unimported.h"
@@ -238,6 +246,10 @@ module cxx_decls {
}
}
+module cxx_decls_premerged {
+ header "cxx-decls-premerged.h"
+}
+
module cxx_decls_merged {
header "cxx-decls-merged.h"
}
@@ -280,6 +292,10 @@ module warning {
header "warning.h"
}
+module warn_unused_local_typedef {
+ header "warn-unused-local-typedef.h"
+}
+
module initializer_list {
header "initializer_list"
}
diff --git a/test/Modules/Inputs/odr/a.h b/test/Modules/Inputs/odr/a.h
index 26144b86e8d1..5a3f52409486 100644
--- a/test/Modules/Inputs/odr/a.h
+++ b/test/Modules/Inputs/odr/a.h
@@ -8,6 +8,12 @@ struct X {
int n;
} x1;
+template<typename T>
+struct F {
+ int n;
+ friend bool operator==(const F &a, const F &b) { return a.n == b.n; }
+};
+
int f() {
return y1.n + e1 + y1.f + x1.n;
}
diff --git a/test/Modules/Inputs/odr/b.h b/test/Modules/Inputs/odr/b.h
index b4063979474f..a4a693df2bf1 100644
--- a/test/Modules/Inputs/odr/b.h
+++ b/test/Modules/Inputs/odr/b.h
@@ -4,6 +4,12 @@ struct Y {
} y2;
enum E { e2 };
+template<typename T>
+struct F {
+ int n;
+ friend bool operator==(const F &a, const F &b) { return a.n == b.n; }
+};
+
int g() {
- return y2.m + e2 + y2.f;
+ return y2.m + e2 + y2.f + (F<int>{0} == F<int>{1});
}
diff --git a/test/Modules/Inputs/pch-used.h b/test/Modules/Inputs/pch-used.h
index 60e0097ea909..bc53bb37a9df 100644
--- a/test/Modules/Inputs/pch-used.h
+++ b/test/Modules/Inputs/pch-used.h
@@ -1,2 +1,3 @@
@import cstd.stdio;
+@import other_constants.dbl_max;
static inline void SPXTrace() { fprintf(__stderrp, ""); }
diff --git a/test/Modules/Inputs/pr19692/AIX.h b/test/Modules/Inputs/pr19692/AIX.h
new file mode 100644
index 000000000000..710871e21f21
--- /dev/null
+++ b/test/Modules/Inputs/pr19692/AIX.h
@@ -0,0 +1,2 @@
+ #undef INT64_MAX
+
diff --git a/test/Modules/Inputs/pr19692/Blah.h b/test/Modules/Inputs/pr19692/Blah.h
new file mode 100644
index 000000000000..bdaa83a5a363
--- /dev/null
+++ b/test/Modules/Inputs/pr19692/Blah.h
@@ -0,0 +1,2 @@
+ #include "stdint.h"
+
diff --git a/test/Modules/Inputs/pr19692/TBlah.h b/test/Modules/Inputs/pr19692/TBlah.h
new file mode 100644
index 000000000000..a045a8bd7377
--- /dev/null
+++ b/test/Modules/Inputs/pr19692/TBlah.h
@@ -0,0 +1,3 @@
+#include "Blah.h"
+ int use = INT64_MAX;
+
diff --git a/test/Modules/Inputs/pr19692/TFoo.h b/test/Modules/Inputs/pr19692/TFoo.h
new file mode 100644
index 000000000000..8b137891791f
--- /dev/null
+++ b/test/Modules/Inputs/pr19692/TFoo.h
@@ -0,0 +1 @@
+
diff --git a/test/Modules/Inputs/pr19692/module.map b/test/Modules/Inputs/pr19692/module.map
new file mode 100644
index 000000000000..f4120dce6f8c
--- /dev/null
+++ b/test/Modules/Inputs/pr19692/module.map
@@ -0,0 +1,3 @@
+module cstd { module stdint { header "stdint.h" } }
+module LLVMSupport { module Blah { header "Blah.h" export * } module AIX { header "AIX.h" } }
+module LLVMTarget { module Blah { header "TBlah.h" export * } module Foo { header "TFoo.h" } }
diff --git a/test/Modules/Inputs/pr19692/stdint.h b/test/Modules/Inputs/pr19692/stdint.h
new file mode 100644
index 000000000000..7615e832495d
--- /dev/null
+++ b/test/Modules/Inputs/pr19692/stdint.h
@@ -0,0 +1,2 @@
+ #define INT64_MAX 42
+
diff --git a/test/Modules/Inputs/preprocess-prefix.h b/test/Modules/Inputs/preprocess-prefix.h
new file mode 100644
index 000000000000..04d01758320b
--- /dev/null
+++ b/test/Modules/Inputs/preprocess-prefix.h
@@ -0,0 +1,2 @@
+int left_and_right(int *);
+#import "diamond_left.h"
diff --git a/test/Modules/Inputs/relative-dep-gen-1.h b/test/Modules/Inputs/relative-dep-gen-1.h
new file mode 100644
index 000000000000..deb56982bb82
--- /dev/null
+++ b/test/Modules/Inputs/relative-dep-gen-1.h
@@ -0,0 +1 @@
+// empty 1
diff --git a/test/Modules/Inputs/relative-dep-gen-2.h b/test/Modules/Inputs/relative-dep-gen-2.h
new file mode 100644
index 000000000000..2b9517d9787d
--- /dev/null
+++ b/test/Modules/Inputs/relative-dep-gen-2.h
@@ -0,0 +1 @@
+// empty 2
diff --git a/test/Modules/Inputs/relative-dep-gen-cwd.modulemap b/test/Modules/Inputs/relative-dep-gen-cwd.modulemap
new file mode 100644
index 000000000000..b8678d309d6b
--- /dev/null
+++ b/test/Modules/Inputs/relative-dep-gen-cwd.modulemap
@@ -0,0 +1,4 @@
+module "relative-dep-gen" {
+ header "Inputs/relative-dep-gen-1.h"
+ header "Inputs/relative-dep-gen-2.h"
+}
diff --git a/test/Modules/Inputs/relative-dep-gen.modulemap b/test/Modules/Inputs/relative-dep-gen.modulemap
new file mode 100644
index 000000000000..4c821e19ae55
--- /dev/null
+++ b/test/Modules/Inputs/relative-dep-gen.modulemap
@@ -0,0 +1,4 @@
+module "relative-dep-gen" {
+ header "relative-dep-gen-1.h"
+ header "relative-dep-gen-2.h"
+}
diff --git a/test/Modules/Inputs/templates-left.h b/test/Modules/Inputs/templates-left.h
index 2bd79be94584..cbe89434f9f3 100644
--- a/test/Modules/Inputs/templates-left.h
+++ b/test/Modules/Inputs/templates-left.h
@@ -60,3 +60,13 @@ template<typename T> void testDelayUpdates(DelayUpdates<T> *p = 0) {}
void outOfLineInlineUseLeftF(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::f);
void outOfLineInlineUseLeftG(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::g);
void outOfLineInlineUseLeftH(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::h);
+
+namespace EmitDefaultedSpecialMembers {
+ inline void f() {
+ SmallString<256> SS;
+ };
+}
+
+inline int *getStaticDataMemberLeft() {
+ return WithUndefinedStaticDataMember<int[]>::undefined;
+}
diff --git a/test/Modules/Inputs/templates-right.h b/test/Modules/Inputs/templates-right.h
index 5907cbca73ee..daea97b86b88 100644
--- a/test/Modules/Inputs/templates-right.h
+++ b/test/Modules/Inputs/templates-right.h
@@ -43,3 +43,7 @@ template<typename T> struct MergePatternDecl;
void outOfLineInlineUseRightF(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::f);
void outOfLineInlineUseRightG(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::g);
void outOfLineInlineUseRightH(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::h);
+
+inline int *getStaticDataMemberRight() {
+ return WithUndefinedStaticDataMember<int[]>::undefined;
+}
diff --git a/test/Modules/Inputs/templates-top.h b/test/Modules/Inputs/templates-top.h
index 1216266f34fb..31f5e4199281 100644
--- a/test/Modules/Inputs/templates-top.h
+++ b/test/Modules/Inputs/templates-top.h
@@ -40,3 +40,20 @@ template<typename T> struct OutOfLineInline {
template<typename T> inline void OutOfLineInline<T>::f() {}
template<typename T> inline void OutOfLineInline<T>::g() {}
template<typename T> inline void OutOfLineInline<T>::h() {}
+
+namespace EmitDefaultedSpecialMembers {
+ template<typename T> struct SmallVectorImpl {
+ SmallVectorImpl() {}
+ ~SmallVectorImpl() {} // non-trivial dtor
+ };
+ template<typename T, unsigned N> struct SmallVector : SmallVectorImpl<T> {
+ // trivial dtor
+ };
+ template<unsigned N> struct SmallString : SmallVector<char, N> {
+ // trivial dtor
+ };
+}
+
+template<typename T> struct WithUndefinedStaticDataMember {
+ static T undefined;
+};
diff --git a/test/Modules/Inputs/va_list/module.modulemap b/test/Modules/Inputs/va_list/module.modulemap
new file mode 100644
index 000000000000..870f38bb0ecd
--- /dev/null
+++ b/test/Modules/Inputs/va_list/module.modulemap
@@ -0,0 +1,2 @@
+module va_list_a { header "va_list_a.h" }
+module va_list_b { header "va_list_b.h" }
diff --git a/test/Modules/Inputs/va_list/va_list_a.h b/test/Modules/Inputs/va_list/va_list_a.h
new file mode 100644
index 000000000000..7193ca2ec340
--- /dev/null
+++ b/test/Modules/Inputs/va_list/va_list_a.h
@@ -0,0 +1 @@
+int vprintf(const char * __restrict, va_list);
diff --git a/test/Modules/Inputs/va_list/va_list_b.h b/test/Modules/Inputs/va_list/va_list_b.h
new file mode 100644
index 000000000000..b7f9b3d367c5
--- /dev/null
+++ b/test/Modules/Inputs/va_list/va_list_b.h
@@ -0,0 +1,2 @@
+@import va_list_a;
+void NSLogv(id, va_list);
diff --git a/test/Modules/Inputs/warn-unused-local-typedef.h b/test/Modules/Inputs/warn-unused-local-typedef.h
new file mode 100644
index 000000000000..6006de0cc8cc
--- /dev/null
+++ b/test/Modules/Inputs/warn-unused-local-typedef.h
@@ -0,0 +1 @@
+inline void myfun() { typedef int a; }
diff --git a/test/Modules/Rmodule-build.m b/test/Modules/Rmodule-build.m
index b8abc01c2c1a..e8f293535178 100644
--- a/test/Modules/Rmodule-build.m
+++ b/test/Modules/Rmodule-build.m
@@ -1,34 +1,41 @@
-// REQUIRES: shell
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: echo '// A' > %t/A.h
-// RUN: echo '// B' > %t/B.h
+// RUN: echo '#include "C.h"' > %t/B.h
+// RUN: echo '// C' > %t/C.h
// RUN: echo 'module A { header "A.h" }' > %t/module.modulemap
// RUN: echo 'module B { header "B.h" }' >> %t/module.modulemap
+// RUN: echo 'module C { header "C.h" }' >> %t/module.modulemap
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fsyntax-only %s -verify \
// RUN: -I %t -Rmodule-build
-@import A; // expected-remark{{building module 'A' as}}
-@import B; // expected-remark{{building module 'B' as}}
+@import A; // expected-remark{{building module 'A' as}} expected-remark {{finished building module 'A'}}
+@import B; // expected-remark{{building module 'B' as}} expected-remark {{finished building module 'B'}}
@import A; // no diagnostic
@import B; // no diagnostic
-// RUN: echo ' ' >> %t/B.h
+// RUN: echo ' ' >> %t/C.h
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fsyntax-only %s -I %t \
// RUN: -Rmodule-build 2>&1 | FileCheck %s
-// RUN: echo ' ' >> %t/B.h
+// RUN: echo ' ' >> %t/C.h
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fsyntax-only %s -I %t \
// RUN: -Reverything 2>&1 | FileCheck %s
// RUN: echo ' ' >> %t/B.h
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fsyntax-only %s -I %t \
-// RUN: 2>&1 | count 0
+// RUN: 2>&1 | FileCheck -allow-empty -check-prefix=NO-REMARKS %s
// RUN: echo ' ' >> %t/B.h
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fsyntax-only %s -I %t \
-// RUN: -Rmodule-build -Rno-everything 2>&1 | count 0
+// RUN: -Rmodule-build -Rno-everything 2>&1 | \
+// RUN: FileCheck -allow-empty -check-prefix=NO-REMARKS %s
// CHECK-NOT: building module 'A'
// CHECK: building module 'B'
+// CHECK: building module 'C'
+// CHECK: finished building module 'C'
+// CHECK: finished building module 'B'
+// NO-REMARKS-NOT: building module 'A'
+// NO-REMARKS-NOT: building module 'B'
diff --git a/test/Modules/Werror-Wsystem-headers.m b/test/Modules/Werror-Wsystem-headers.m
index c4cd1a6378cc..4391aa027977 100644
--- a/test/Modules/Werror-Wsystem-headers.m
+++ b/test/Modules/Werror-Wsystem-headers.m
@@ -1,21 +1,20 @@
-// REQUIRES: shell
// RUN: rm -rf %t
// RUN: rm -rf %t-saved
// RUN: mkdir %t-saved
// Initial module build
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash \
-// RUN: -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -fsyntax-only %s -verify
+// RUN: -isystem %S/Inputs/System/usr/include -fsyntax-only %s -verify
// RUN: cp %t/cstd.pcm %t-saved/cstd.pcm
// Even with -Werror don't rebuild a system module
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash \
-// RUN: -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -fsyntax-only %s -verify -Werror
+// RUN: -isystem %S/Inputs/System/usr/include -fsyntax-only %s -verify -Werror
// RUN: diff %t/cstd.pcm %t-saved/cstd.pcm
// Unless -Wsystem-headers is on
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash \
-// RUN: -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -fsyntax-only %s -verify \
+// RUN: -isystem %S/Inputs/System/usr/include -fsyntax-only %s -verify \
// RUN: -Werror=unused -Wsystem-headers
// RUN: not diff %t/cstd.pcm %t-saved/cstd.pcm
diff --git a/test/Modules/Werror.m b/test/Modules/Werror.m
index 94a98a5a198d..6444ea513b81 100644
--- a/test/Modules/Werror.m
+++ b/test/Modules/Werror.m
@@ -1,4 +1,3 @@
-// REQUIRES: shell
// RUN: rm -rf %t
// RUN: rm -rf %t-saved
// RUN: mkdir -p %t-saved
diff --git a/test/Modules/add-remove-private.m b/test/Modules/add-remove-private.m
new file mode 100644
index 000000000000..49e81e11141d
--- /dev/null
+++ b/test/Modules/add-remove-private.m
@@ -0,0 +1,28 @@
+// RUN: rm -rf %t
+// RUN: rm -rf %t.mcp
+// RUN: mkdir -p %t
+// RUN: cp -r %S/Inputs/AddRemovePrivate.framework %t/AddRemovePrivate.framework
+
+// Build with module.private.modulemap
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t.mcp -fdisable-module-hash -F %t %s -verify -DP
+// RUN: cp %t.mcp/AddRemovePrivate.pcm %t/with.pcm
+
+// Build without module.private.modulemap
+// RUN: rm %t/AddRemovePrivate.framework/Modules/module.private.modulemap
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t.mcp -fdisable-module-hash -F %t %s -verify
+// RUN: not diff %t.mcp/AddRemovePrivate.pcm %t/with.pcm
+// RUN: cp %t.mcp/AddRemovePrivate.pcm %t/without.pcm
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t.mcp -fdisable-module-hash -F %t %s -DP 2>&1 | FileCheck %s
+// CHECK: no submodule named 'Private'
+
+// Build with module.private.modulemap (again)
+// RUN: cp %S/Inputs/AddRemovePrivate.framework/Modules/module.private.modulemap %t/AddRemovePrivate.framework/Modules/module.private.modulemap
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t.mcp -fdisable-module-hash -F %t %s -verify -DP
+// RUN: not diff %t.mcp/AddRemovePrivate.pcm %t/without.pcm
+
+// expected-no-diagnostics
+
+@import AddRemovePrivate;
+#ifdef P
+@import AddRemovePrivate.Private;
+#endif
diff --git a/test/Modules/attr-unavailable.m b/test/Modules/attr-unavailable.m
new file mode 100644
index 000000000000..0188a84d9816
--- /dev/null
+++ b/test/Modules/attr-unavailable.m
@@ -0,0 +1,25 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/attr-unavailable %s -fsyntax-only -verify
+
+@import two;
+void f(id x) {
+ [x method1];
+}
+
+@import oneA;
+void g(id x) {
+ [x method2]; // expected-error{{'method2' is unavailable}}
+ // expected-note@oneA.h:2 {{'method2' has been explicitly marked unavailable here}}
+ [x method3]; // expected-error{{'method3' is unavailable}}
+ // expected-note@oneA.h:3 {{'method3' has been explicitly marked unavailable here}}
+}
+
+@import oneB;
+void h(id x) {
+ [x method2]; // could be from interface D in module oneB
+}
+
+@import oneC;
+void i(id x) {
+ [x method3]; // could be from interface E in module oncC
+}
diff --git a/test/Modules/autolink.m b/test/Modules/autolink.m
index 47eda3f80e01..5f2e9bd20208 100644
--- a/test/Modules/autolink.m
+++ b/test/Modules/autolink.m
@@ -37,14 +37,14 @@ int use_autolink_sub3() {
// NOTE: "autolink_sub" is intentionally not linked.
// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = metadata !{i32 6, metadata !"Linker Options", metadata ![[AUTOLINK_OPTIONS:[0-9]+]]}
-// CHECK: ![[AUTOLINK_OPTIONS]] = metadata !{metadata ![[AUTOLINK_PCH:[0-9]+]], metadata ![[AUTOLINK_FRAMEWORK:[0-9]+]], metadata ![[AUTOLINK:[0-9]+]], metadata ![[DEPENDSONMODULE:[0-9]+]], metadata ![[MODULE:[0-9]+]], metadata ![[NOUMBRELLA:[0-9]+]]}
-// CHECK: ![[AUTOLINK_PCH]] = metadata !{metadata !"{{(-l|/DEFAULTLIB:)}}autolink_from_pch{{(\.lib)?}}"}
-// CHECK: ![[AUTOLINK_FRAMEWORK]] = metadata !{metadata !"-framework", metadata !"autolink_framework"}
-// CHECK: ![[AUTOLINK]] = metadata !{metadata !"{{(-l|/DEFAULTLIB:)}}autolink{{(\.lib)?}}"}
-// CHECK: ![[DEPENDSONMODULE]] = metadata !{metadata !"-framework", metadata !"DependsOnModule"}
-// CHECK: ![[MODULE]] = metadata !{metadata !"-framework", metadata !"Module"}
-// CHECK: ![[NOUMBRELLA]] = metadata !{metadata !"-framework", metadata !"NoUmbrella"}
+// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[AUTOLINK_OPTIONS:[0-9]+]]}
+// CHECK: ![[AUTOLINK_OPTIONS]] = !{![[AUTOLINK_PCH:[0-9]+]], ![[AUTOLINK_FRAMEWORK:[0-9]+]], ![[AUTOLINK:[0-9]+]], ![[DEPENDSONMODULE:[0-9]+]], ![[MODULE:[0-9]+]], ![[NOUMBRELLA:[0-9]+]]}
+// CHECK: ![[AUTOLINK_PCH]] = !{!"{{(-l|/DEFAULTLIB:)}}autolink_from_pch{{(\.lib)?}}"}
+// CHECK: ![[AUTOLINK_FRAMEWORK]] = !{!"-framework", !"autolink_framework"}
+// CHECK: ![[AUTOLINK]] = !{!"{{(-l|/DEFAULTLIB:)}}autolink{{(\.lib)?}}"}
+// CHECK: ![[DEPENDSONMODULE]] = !{!"-framework", !"DependsOnModule"}
+// CHECK: ![[MODULE]] = !{!"-framework", !"Module"}
+// CHECK: ![[NOUMBRELLA]] = !{!"-framework", !"NoUmbrella"}
// CHECK-AUTOLINK-DISABLED: !llvm.module.flags
// CHECK-AUTOLINK-DISABLED-NOT: "Linker Options"
diff --git a/test/Modules/cstd.m b/test/Modules/cstd.m
index 3d1dcf38e33c..24bca19b7aa9 100644
--- a/test/Modules/cstd.m
+++ b/test/Modules/cstd.m
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang -fsyntax-only -isystem %S/Inputs/System/usr/include -fmodules -fmodules-cache-path=%t -D__need_wint_t -Werror=implicit-function-declaration %s
+// RUN: %clang -fsyntax-only -isystem %S/Inputs/System/usr/include -ffreestanding -fmodules -fmodules-cache-path=%t -D__need_wint_t -Werror=implicit-function-declaration %s
@import uses_other_constants;
const double other_value = DBL_MAX;
diff --git a/test/Modules/cxx-decls.cpp b/test/Modules/cxx-decls.cpp
index 5498b47fc9fe..109306ed79df 100644
--- a/test/Modules/cxx-decls.cpp
+++ b/test/Modules/cxx-decls.cpp
@@ -30,7 +30,27 @@ void use_implicit_new_again() { operator new[](3); }
int importMergeUsedFlag = getMergeUsedFlag();
+int use_name_for_linkage(NameForLinkage &nfl) {
+ return nfl.n + nfl.m;
+}
+int use_overrides_virtual_functions(OverridesVirtualFunctions ovf) { return 0; }
+
@import cxx_decls_merged;
+NameForLinkage2Inner use_name_for_linkage2_inner;
+NameForLinkage2 use_name_for_linkage2;
+
+int name_for_linkage_test = use_name_for_linkage(name_for_linkage);
+int overrides_virtual_functions_test =
+ use_overrides_virtual_functions(overrides_virtual_functions);
+
+void use_extern_c_function() { ExternCFunction(); }
+
+int use_namespace_alias() { return Alias::a + Alias::b; }
+
+@import cxx_decls_premerged;
+
+void use_extern_c_function_2() { ExternCFunction(); }
+
// CHECK: VarDecl [[mergeUsedFlag:0x[0-9a-f]*]] {{.*}} in cxx_decls.imported used mergeUsedFlag
// CHECK: VarDecl {{0x[0-9a-f]*}} prev [[mergeUsedFlag]] {{.*}} in cxx_decls_merged used mergeUsedFlag
diff --git a/test/Modules/cxx-irgen.cpp b/test/Modules/cxx-irgen.cpp
index 4c61a3a3583b..ecaf704b87bb 100644
--- a/test/Modules/cxx-irgen.cpp
+++ b/test/Modules/cxx-irgen.cpp
@@ -1,5 +1,6 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -x objective-c++ -std=c++11 -fmodules-cache-path=%t -I %S/Inputs -triple %itanium_abi_triple -disable-llvm-optzns -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fmodules -x objective-c++ -std=c++11 -fmodules-cache-path=%t -I %S/Inputs -triple %itanium_abi_triple -disable-llvm-optzns -emit-llvm -g -o - %s | FileCheck %s
// FIXME: When we have a syntax for modules in C++, use that.
@import cxx_irgen_top;
@@ -10,13 +11,66 @@ CtorInit<int> x;
@import cxx_irgen_left;
@import cxx_irgen_right;
+// Keep these two namespace definitions separate; merging them hides the bug.
+namespace EmitInlineMethods {
+ // CHECK-DAG: define linkonce_odr [[CC:(x86_thiscallcc[ ]+)?]]void @_ZN17EmitInlineMethods1C1fEPNS_1AE(
+ // CHECK-DAG: declare [[CC]]void @_ZN17EmitInlineMethods1A1gEv(
+ struct C {
+ __attribute__((used)) void f(A *p) { p->g(); }
+ };
+}
+namespace EmitInlineMethods {
+ // CHECK-DAG: define linkonce_odr [[CC]]void @_ZN17EmitInlineMethods1D1fEPNS_1BE(
+ // CHECK-DAG: define linkonce_odr [[CC]]void @_ZN17EmitInlineMethods1B1gEv(
+ struct D {
+ __attribute__((used)) void f(B *p) { p->g(); }
+ };
+}
+
// CHECK-DAG: define available_externally hidden {{signext i32|i32}} @_ZN1SIiE1gEv({{.*}} #[[ALWAYS_INLINE:.*]] align
int a = S<int>::g();
-// CHECK-DAG: define available_externally {{signext i32|i32}} @_ZN1SIiE1fEv({{.*}} #[[ALWAYS_INLINE]] align
int b = h();
// CHECK-DAG: define linkonce_odr {{signext i32|i32}} @_Z3minIiET_S0_S0_(i32
int c = min(1, 2);
+// CHECK-LABEL: define {{.*}} @_ZN20OperatorDeleteLookup1AD0Ev(
+// CHECK: call void @_ZN20OperatorDeleteLookup1AdlEPv(
+
+namespace ImplicitSpecialMembers {
+ // CHECK-LABEL: define {{.*}} @_ZN22ImplicitSpecialMembers1DC2EOS0_(
+ // CHECK: call {{.*}} @_ZN22ImplicitSpecialMembers1AC1ERKS0_(
+ // CHECK-LABEL: define {{.*}} @_ZN22ImplicitSpecialMembers1DC2ERKS0_(
+ // CHECK: call {{.*}} @_ZN22ImplicitSpecialMembers1AC1ERKS0_(
+ // CHECK-LABEL: define {{.*}} @_ZN22ImplicitSpecialMembers1CC2EOS0_(
+ // CHECK: call {{.*}} @_ZN22ImplicitSpecialMembers1AC1ERKS0_(
+ // CHECK-LABEL: define {{.*}} @_ZN22ImplicitSpecialMembers1CC2ERKS0_(
+ // CHECK: call {{.*}} @_ZN22ImplicitSpecialMembers1AC1ERKS0_(
+ // CHECK-LABEL: define {{.*}} @_ZN22ImplicitSpecialMembers1BC2EOS0_(
+ // CHECK: call {{.*}} @_ZN22ImplicitSpecialMembers1AC1ERKS0_(
+ // CHECK-LABEL: define {{.*}} @_ZN22ImplicitSpecialMembers1BC2ERKS0_(
+ // CHECK: call {{.*}} @_ZN22ImplicitSpecialMembers1AC1ERKS0_(
+
+ extern B b1;
+ B b2(b1);
+ B b3(static_cast<B&&>(b1));
+
+ extern C c1;
+ C c2(c1);
+ C c3(static_cast<C&&>(c1));
+
+ extern D d1;
+ D d2(d1);
+ D d3(static_cast<D&&>(d1));
+}
+
+namespace OperatorDeleteLookup {
+ // Trigger emission of B's vtable and deleting dtor.
+ // This requires us to know what operator delete was selected.
+ void g() { f(); }
+}
+
+// CHECK: define available_externally {{signext i32|i32}} @_ZN1SIiE1fEv({{.*}} #[[ALWAYS_INLINE]] align
+
// CHECK: attributes #[[ALWAYS_INLINE]] = {{.*}} alwaysinline
diff --git a/test/Modules/cxx-lookup.cpp b/test/Modules/cxx-lookup.cpp
new file mode 100644
index 000000000000..47c879dbb636
--- /dev/null
+++ b/test/Modules/cxx-lookup.cpp
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -I%S/Inputs/cxx-lookup -verify
+// expected-no-diagnostics
+namespace llvm {}
+#include "c2.h"
+llvm::GlobalValue *p;
diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp
index cbe9f3508951..d9c8a8c27d0d 100644
--- a/test/Modules/cxx-templates.cpp
+++ b/test/Modules/cxx-templates.cpp
@@ -1,12 +1,18 @@
// RUN: rm -rf %t
-// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL
-// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N
+// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL
+// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N
// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump | FileCheck %s --check-prefix=CHECK-DUMP
// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -DEARLY_IMPORT
+
+#ifdef EARLY_IMPORT
+#include "cxx-templates-textual.h"
+#endif
@import cxx_templates_a;
@import cxx_templates_b;
@import cxx_templates_c;
+@import cxx_templates_d;
@import cxx_templates_common;
template<typename, char> struct Tmpl_T_C {};
@@ -22,15 +28,21 @@ void g() {
f<double>(1.0);
f<int>();
f(); // expected-error {{no matching function}}
+#ifdef EARLY_IMPORT
+ // FIXME: The textual inclusion above shouldn't affect this!
+ // expected-note@Inputs/cxx-templates-a.h:3 {{couldn't infer template argument}}
+ // expected-note@Inputs/cxx-templates-a.h:4 {{requires 1 argument}}
+#else
// expected-note@Inputs/cxx-templates-b.h:3 {{couldn't infer template argument}}
// expected-note@Inputs/cxx-templates-b.h:4 {{requires single argument}}
+#endif
N::f(0);
N::f<double>(1.0);
N::f<int>();
N::f(); // expected-error {{no matching function}}
- // expected-note@Inputs/cxx-templates-a.h:6 {{couldn't infer template argument}}
- // expected-note@Inputs/cxx-templates-a.h:7 {{requires 1 argument}}
+ // expected-note@Inputs/cxx-templates-b.h:6 {{couldn't infer template argument}}
+ // expected-note@Inputs/cxx-templates-b.h:7 {{requires single argument}}
template_param_kinds_1<0>(); // ok, from cxx-templates-a.h
template_param_kinds_1<int>(); // ok, from cxx-templates-b.h
@@ -105,11 +117,22 @@ void g() {
int &p = WithPartialSpecializationUse().f();
int &q = WithExplicitSpecializationUse().inner_template<int>();
+ int *r = PartiallyInstantiatePartialSpec<int*>::bar();
+
+ (void)&WithImplicitSpecialMembers<int>::n;
+
+ MergeClassTemplateSpecializations_string s;
+
+ extern TestInjectedClassName::A *use_a;
+ extern TestInjectedClassName::C *use_c;
+ TestInjectedClassName::UseD();
}
static_assert(Outer<int>::Inner<int>::f() == 1, "");
static_assert(Outer<int>::Inner<int>::g() == 2, "");
+#ifndef EARLY_IMPORT
+// FIXME: The textual inclusion above shouldn't cause this to fail!
static_assert(MergeTemplateDefinitions<int>::f() == 1, "");
static_assert(MergeTemplateDefinitions<int>::g() == 2, "");
@@ -123,6 +146,21 @@ MergeSpecializations<int[]>::partially_specialized_in_c spec_in_c_1;
MergeSpecializations<char>::explicitly_specialized_in_a spec_in_a_2;
MergeSpecializations<double>::explicitly_specialized_in_b spec_in_b_2;
MergeSpecializations<bool>::explicitly_specialized_in_c spec_in_c_2;
+#endif
+
+MergeAnonUnionMember<> maum_main;
+typedef DontWalkPreviousDeclAfterMerging<int> dwpdam_typedef_2;
+dwpdam_typedef::type dwpdam_typedef_use;
+DontWalkPreviousDeclAfterMerging<int>::Inner::type dwpdam;
+
+using AliasTemplateMergingTest = WithAliasTemplate<int>::X<char>;
+
+int AnonymousDeclsMergingTest(WithAnonymousDecls<int> WAD, WithAnonymousDecls<char> WADC) {
+ return InstantiateWithAnonymousDeclsA(WAD) +
+ InstantiateWithAnonymousDeclsB(WAD) +
+ InstantiateWithAnonymousDeclsB2(WADC) +
+ InstantiateWithAnonymousDeclsD(WADC);
+}
@import cxx_templates_common;
diff --git a/test/Modules/dependency-gen.m b/test/Modules/dependency-gen.m
index dec83848f061..d3d66bfaab21 100644
--- a/test/Modules/dependency-gen.m
+++ b/test/Modules/dependency-gen.m
@@ -1,7 +1,7 @@
// RUN: rm -rf %t-mcp
// RUN: mkdir -p %t-mcp
-// RUN: %clang_cc1 -x objective-c -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -dependency-file %t.d.1 -MT %s.o -I %S/Inputs -fsyntax-only -fmodules -fmodules-cache-path=%t-mcp %s
+// RUN: %clang_cc1 -x objective-c -isystem %S/Inputs/System/usr/include -dependency-file %t.d.1 -MT %s.o -I %S/Inputs -fsyntax-only -fmodules -fmodules-cache-path=%t-mcp %s
// RUN: FileCheck %s < %t.d.1
// CHECK: dependency-gen.m
// CHECK: Inputs{{.}}diamond_top.h
@@ -10,7 +10,7 @@
// CHECK-NOT: stdint.h
-// RUN: %clang_cc1 -x objective-c -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -dependency-file %t.d.2 -MT %s.o -I %S/Inputs -sys-header-deps -fsyntax-only -fmodules -fmodules-cache-path=%t-mcp %s
+// RUN: %clang_cc1 -x objective-c -isystem %S/Inputs/System/usr/include -dependency-file %t.d.2 -MT %s.o -I %S/Inputs -sys-header-deps -fsyntax-only -fmodules -fmodules-cache-path=%t-mcp %s
// RUN: FileCheck %s -check-prefix=CHECK-SYS < %t.d.2
// CHECK-SYS: dependency-gen.m
// CHECK-SYS: Inputs{{.}}diamond_top.h
diff --git a/test/Modules/dependency-gen.modulemap.cpp b/test/Modules/dependency-gen.modulemap.cpp
new file mode 100644
index 000000000000..c49714c14ed9
--- /dev/null
+++ b/test/Modules/dependency-gen.modulemap.cpp
@@ -0,0 +1,18 @@
+// REQUIRES: shell
+//
+// RUN: cd %S
+// RUN: rm -f %t.cpm %t-base.pcm %t-base.d %t.d
+// RUN: %clang_cc1 -I. -x c++ -fmodule-maps -fmodule-name=test-base -fno-modules-implicit-maps -fmodules -emit-module -fno-validate-pch -fmodules-strict-decluse Inputs/dependency-gen-base.modulemap -dependency-file %t-base.d -MT %t-base.pcm -o %t-base.pcm -fmodule-map-file-home-is-cwd
+// RUN: %clang_cc1 -I. -x c++ -fmodule-maps -fmodule-name=test -fno-modules-implicit-maps -fmodules -emit-module -fno-validate-pch -fmodules-strict-decluse -fmodule-file=%t-base.pcm dependency-gen.modulemap.cpp -dependency-file %t.d -MT %t.pcm -o %t.pcm -fmodule-map-file-home-is-cwd
+// RUN: FileCheck %s < %t.d
+module "test" {
+ export *
+ header "Inputs/dependency-gen.h"
+ use "test-base"
+ use "test-base2"
+}
+extern module "test-base2" "Inputs/dependency-gen-base2.modulemap"
+extern module "test-base" "Inputs/dependency-gen-base.modulemap"
+
+// CHECK: {{ |\./}}Inputs/dependency-gen-included2.h
+// CHECK: {{ |\./}}Inputs/dependency-gen-base.modulemap
diff --git a/test/Modules/explicit-build-flags.cpp b/test/Modules/explicit-build-flags.cpp
new file mode 100644
index 000000000000..6ced215a06d1
--- /dev/null
+++ b/test/Modules/explicit-build-flags.cpp
@@ -0,0 +1,49 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo 'module tmp { header "tmp.h" }' > %t/map
+// RUN: touch %t/tmp.h
+// RUN: %clang_cc1 -fmodules -DFOO=1 -x c++ -fmodule-name=tmp %t/map -emit-module -o %t/tmp.pcm
+
+// Can use the module.
+// RUN: %clang_cc1 -fmodules -DFOO=1 -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp.pcm -verify -I%t %s
+
+// Can use the module if an input file is newer. (This happens on
+// remote file systems.)
+// RUN: sleep 1
+// RUN: touch %t/tmp.h
+// RUN: %clang_cc1 -fmodules -DFOO=1 -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp.pcm -verify -I%t %s
+
+// Can use the module if -D flags change.
+// RUN: %clang_cc1 -fmodules -DFOO=2 -DBAR=1 -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp.pcm -verify -I%t %s
+// RUN: %clang_cc1 -fmodules -DBAR=2 -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp.pcm -verify -I%t %s
+
+// Can use the module if -W flags change.
+// RUN: %clang_cc1 -fmodules -DBAR=2 -Wextra -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp.pcm -verify -I%t %s
+
+// Can use the module if -I flags change.
+// RUN: %clang_cc1 -fmodules -DBAR=2 -I. -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp.pcm -verify -I%t %s
+
+// Can use the module if -O flags change.
+// RUN: %clang_cc1 -fmodules -DBAR=2 -Os -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp.pcm -verify -I%t %s
+//
+// RUN: %clang_cc1 -fmodules -DFOO=1 -O2 -x c++ -fmodule-name=tmp %t/map -emit-module -o %t/tmp-O2.pcm
+// RUN: %clang_cc1 -fmodules -DBAR=2 -O0 -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp-O2.pcm -verify -I%t %s
+// RUN: %clang_cc1 -fmodules -DBAR=2 -Os -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp-O2.pcm -verify -I%t %s
+
+#include "tmp.h" // expected-no-diagnostics
+
+#ifndef BAR
+#if FOO != 1
+#error bad FOO from command line and module
+#endif
+#elif BAR == 1
+#if FOO != 2
+#error bad FOO from command line overriding module
+#endif
+#elif BAR == 2
+#ifdef FOO
+#error FOO leaked from module
+#endif
+#else
+#error bad BAR
+#endif
diff --git a/test/Modules/explicit-build-relpath.cpp b/test/Modules/explicit-build-relpath.cpp
new file mode 100644
index 000000000000..d9c15660b6ad
--- /dev/null
+++ b/test/Modules/explicit-build-relpath.cpp
@@ -0,0 +1,49 @@
+// REQUIRES: shell
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: cd %t
+
+// ----------------------
+// Build modules A and B.
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-name=a -emit-module %S/Inputs/explicit-build/module.modulemap -o a.pcm
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=a.pcm \
+// RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o b-rel.pcm
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o b-abs.pcm
+
+// ------------------------------------------
+// Mix and match relative and absolute paths.
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=a.pcm \
+// RUN: -verify %s
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=b-rel.pcm \
+// RUN: -verify %s
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=a.pcm \
+// RUN: -fmodule-file=b-abs.pcm \
+// RUN: -verify %s
+//
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=b-rel.pcm \
+// RUN: -fmodule-file=b-abs.pcm \
+// RUN: -verify %s 2>&1 | FileCheck %s
+// CHECK: module 'b' is defined in both '{{.*}}b-rel.pcm' and '{{.*}}b-abs.pcm'
+
+#include "a.h"
+static_assert(a == 1, "");
+// expected-no-diagnostics
diff --git a/test/Modules/explicit-build.cpp b/test/Modules/explicit-build.cpp
new file mode 100644
index 000000000000..ce3a1af41626
--- /dev/null
+++ b/test/Modules/explicit-build.cpp
@@ -0,0 +1,175 @@
+// RUN: rm -rf %t
+
+// -------------------------------
+// Build chained modules A, B, and C
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-name=a -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/a.pcm \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/b.pcm \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/b.pcm \
+// RUN: -fmodule-name=c -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/c.pcm \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
+//
+// CHECK-NO-IMPLICIT-BUILD-NOT: building module
+
+// -------------------------------
+// Build B with an implicit build of A
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/b-not-a.pcm \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-B-NO-A %s
+//
+// CHECK-B-NO-A: While building module 'b':
+// CHECK-B-NO-A: building module 'a' as
+
+// -------------------------------
+// Check that we can use the explicitly-built A, B, and C modules.
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -verify %s -DHAVE_A
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -verify %s -DHAVE_A
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/b.pcm \
+// RUN: -verify %s -DHAVE_A -DHAVE_B
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/b.pcm \
+// RUN: -verify %s -DHAVE_A -DHAVE_B
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/b.pcm \
+// RUN: -fmodule-file=%t/c.pcm \
+// RUN: -verify %s -DHAVE_A -DHAVE_B -DHAVE_C
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/c.pcm \
+// RUN: -verify %s -DHAVE_A -DHAVE_B -DHAVE_C
+
+#if HAVE_A
+ #include "a.h"
+ static_assert(a == 1, "");
+#else
+ const int use_a = a; // expected-error {{undeclared identifier}}
+#endif
+
+#if HAVE_B
+ #include "b.h"
+ static_assert(b == 2, "");
+#else
+ const int use_b = b; // expected-error {{undeclared identifier}}
+#endif
+
+#if HAVE_C
+ #include "c.h"
+ static_assert(c == 3, "");
+#else
+ const int use_c = c; // expected-error {{undeclared identifier}}
+#endif
+
+#if HAVE_A && HAVE_B && HAVE_C
+// expected-no-diagnostics
+#endif
+
+// -------------------------------
+// Check that we can use a mixture of implicit and explicit modules.
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/b-not-a.pcm \
+// RUN: -verify %s -DHAVE_A -DHAVE_B
+
+// -------------------------------
+// Try to use two different flavors of the 'a' module.
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/b-not-a.pcm \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s
+//
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/b-not-a.pcm \
+// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-name=a -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/a-alt.pcm \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
+//
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/a-alt.pcm \
+// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s
+//
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a-alt.pcm \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s
+//
+// CHECK-MULTIPLE-AS: error: module 'a' is defined in both '{{.*}}/a{{.*}}.pcm' and '{{.*[/\\]}}a{{.*}}.pcm'
+
+// -------------------------------
+// Try to import a PCH with -fmodule-file=
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-name=a -emit-pch %S/Inputs/explicit-build/a.h -o %t/a.pch \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
+//
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pch \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AS-PCH %s
+//
+// CHECK-A-AS-PCH: fatal error: AST file '{{.*}}a.pch' was not built as a module
+
+// -------------------------------
+// Try to import a non-AST file with -fmodule-file=
+//
+// RUN: touch %t/not.pcm
+//
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/not.pcm \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-BAD-FILE %s
+//
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/nonexistent.pcm \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-BAD-FILE %s
+//
+// CHECK-BAD-FILE: fatal error: file '{{.*}}t.pcm' is not a precompiled module file
+
+// -------------------------------
+// Check that we don't get upset if B's timestamp is newer than C's.
+// RUN: touch %t/b.pcm
+//
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/c.pcm \
+// RUN: -verify %s -DHAVE_A -DHAVE_B -DHAVE_C
+//
+// ... but that we do get upset if our B is different from the B that C expects.
+//
+// RUN: cp %t/b-not-a.pcm %t/b.pcm
+//
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/c.pcm \
+// RUN: %s -DHAVE_A -DHAVE_B -DHAVE_C 2>&1 | FileCheck --check-prefix=CHECK-MISMATCHED-B %s
+//
+// CHECK-MISMATCHED-B: fatal error: malformed or corrupted AST file: {{.*}}b.pcm": module file out of date
diff --git a/test/Modules/filename.cpp b/test/Modules/filename.cpp
new file mode 100644
index 000000000000..66891a04b744
--- /dev/null
+++ b/test/Modules/filename.cpp
@@ -0,0 +1,9 @@
+// RUN: cd %S
+// RUN: %clang_cc1 -I. -fmodule-maps -fmodule-name=A -fmodule-map-file=%S/Inputs/filename/module.map %s -E | FileCheck %s
+// REQUIRES: shell
+
+#include "Inputs/filename/a.h"
+
+// Make sure that headers that are referenced by module maps have __FILE__
+// reflect the include path they were found with.
+// CHECK: const char *p = "./Inputs/filename/a.h"
diff --git a/test/Modules/fmodules-validate-once-per-build-session.c b/test/Modules/fmodules-validate-once-per-build-session.c
index 346d5a72c3e8..dcbd0db3cbfe 100644
--- a/test/Modules/fmodules-validate-once-per-build-session.c
+++ b/test/Modules/fmodules-validate-once-per-build-session.c
@@ -6,39 +6,53 @@
// RUN: mkdir -p %t/modules-to-compare
// ===
-// Create a module with system headers.
+// Create a module. We will use -I or -isystem to determine whether to treat
+// foo.h as a system header.
// RUN: echo 'void meow(void);' > %t/Inputs/foo.h
-// RUN: echo 'module Foo [system] { header "foo.h" }' > %t/Inputs/module.map
+// RUN: echo 'module Foo { header "foo.h" }' > %t/Inputs/module.map
// ===
// Compile the module.
-// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -fsyntax-only -I %t/Inputs -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session %s
+// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -fsyntax-only -isystem %t/Inputs -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session %s
+// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache-user -fsyntax-only -I %t/Inputs -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session %s
// RUN: ls -R %t/modules-cache | grep Foo.pcm.timestamp
+// RUN: ls -R %t/modules-cache-user | grep Foo.pcm.timestamp
// RUN: cp %t/modules-cache/Foo.pcm %t/modules-to-compare/Foo-before.pcm
+// RUN: cp %t/modules-cache-user/Foo.pcm %t/modules-to-compare/Foo-before-user.pcm
// ===
// Use it, and make sure that we did not recompile it.
-// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -fsyntax-only -I %t/Inputs -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session %s
+// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -fsyntax-only -isystem %t/Inputs -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session %s
+// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache-user -fsyntax-only -I %t/Inputs -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session %s
// RUN: ls -R %t/modules-cache | grep Foo.pcm.timestamp
+// RUN: ls -R %t/modules-cache-user | grep Foo.pcm.timestamp
// RUN: cp %t/modules-cache/Foo.pcm %t/modules-to-compare/Foo-after.pcm
+// RUN: cp %t/modules-cache-user/Foo.pcm %t/modules-to-compare/Foo-after-user.pcm
// RUN: diff %t/modules-to-compare/Foo-before.pcm %t/modules-to-compare/Foo-after.pcm
+// RUN: diff %t/modules-to-compare/Foo-before-user.pcm %t/modules-to-compare/Foo-after-user.pcm
// ===
// Change the sources.
// RUN: echo 'void meow2(void);' > %t/Inputs/foo.h
// ===
-// Use the module, and make sure that we did not recompile it, even though the sources changed.
-// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -fsyntax-only -I %t/Inputs -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session %s
+// Use the module, and make sure that we did not recompile it if foo.h is a
+// system header, even though the sources changed.
+// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -fsyntax-only -isystem %t/Inputs -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session %s
+// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache-user -fsyntax-only -I %t/Inputs -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session %s
// RUN: ls -R %t/modules-cache | grep Foo.pcm.timestamp
+// RUN: ls -R %t/modules-cache-user | grep Foo.pcm.timestamp
// RUN: cp %t/modules-cache/Foo.pcm %t/modules-to-compare/Foo-after.pcm
+// RUN: cp %t/modules-cache-user/Foo.pcm %t/modules-to-compare/Foo-after-user.pcm
// RUN: diff %t/modules-to-compare/Foo-before.pcm %t/modules-to-compare/Foo-after.pcm
+// When foo.h is a user header, we will always validate it.
+// RUN: not diff %t/modules-to-compare/Foo-before-user.pcm %t/modules-to-compare/Foo-after-user.pcm
// ===
// Recompile the module if the today's date is before 01 January 2030.
-// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -fsyntax-only -I %t/Inputs -fbuild-session-timestamp=1893456000 -fmodules-validate-once-per-build-session %s
+// RUN: %clang_cc1 -cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -fsyntax-only -isystem %t/Inputs -fbuild-session-timestamp=1893456000 -fmodules-validate-once-per-build-session %s
// RUN: ls -R %t/modules-cache | grep Foo.pcm.timestamp
// RUN: cp %t/modules-cache/Foo.pcm %t/modules-to-compare/Foo-after.pcm
diff --git a/test/Modules/implementation-of-module.m b/test/Modules/implementation-of-module.m
new file mode 100644
index 000000000000..b39840420156
--- /dev/null
+++ b/test/Modules/implementation-of-module.m
@@ -0,0 +1,29 @@
+// RUN: not %clang_cc1 -fmodule-implementation-of Foo -fmodule-name=Bar %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-IMPL-OF-ERR %s
+// CHECK-IMPL-OF-ERR: conflicting module names specified: '-fmodule-name=Bar' and '-fmodule-implementation-of Foo'
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \
+// RUN: -fmodule-implementation-of category_right -fsyntax-only
+
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \
+// RUN: -fmodule-implementation-of category_right -dM -E -o - 2>&1 | FileCheck %s
+// CHECK-NOT: __building_module
+
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \
+// RUN: -fmodule-implementation-of category_left -verify
+
+// RUN: %clang_cc1 -x objective-c-header -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \
+// RUN: -fmodule-implementation-of category_right -emit-pch -o %t.pch
+// RUN: %clang_cc1 -x objective-c-header -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \
+// RUN: -DWITH_PREFIX -include-pch %t.pch -fmodule-implementation-of category_right
+
+#ifndef WITH_PREFIX
+
+@import category_left; // expected-error{{@import of module 'category_left' in implementation of 'category_left'; use #import}}
+@import category_left.sub; // expected-error{{@import of module 'category_left.sub' in implementation of 'category_left'; use #import}}
+#import "category_right.h" // expected-error{{treating}}
+#import "category_right_sub.h" // expected-error{{treating}}
+
+#endif
+
diff --git a/test/Modules/include_next.c b/test/Modules/include_next.c
new file mode 100644
index 000000000000..f2dafb4a91de
--- /dev/null
+++ b/test/Modules/include_next.c
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -I%S/Inputs/include_next/x -I%S/Inputs/include_next/y -verify %s
+// RUN: %clang_cc1 -I%S/Inputs/include_next/x -I%S/Inputs/include_next/y -verify %s -fmodules -fmodules-cache-path=%t
+
+// expected-no-diagnostics
+#include "a.h"
+#include "subdir/b.h"
+_Static_assert(ax == 1, "");
+_Static_assert(ay == 2, "");
+_Static_assert(bx == 3, "");
+_Static_assert(by == 4, "");
diff --git a/test/Modules/incomplete-module.m b/test/Modules/incomplete-module.m
index 8edaea983cb9..8181ae863de9 100644
--- a/test/Modules/incomplete-module.m
+++ b/test/Modules/incomplete-module.m
@@ -2,4 +2,8 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules-cache-path=%t -Wincomplete-module -fmodules -I %S/Inputs %s 2>&1 | FileCheck %s
-// CHECK: {{warning: header '.*incomplete_mod_missing.h' is included in module 'incomplete_mod' but not listed in module map}}
+// CHECK: warning: include of non-modular header inside module 'incomplete_mod'
+
+// RUN: rm -rf %t
+// RUN: not %clang_cc1 -fmodules-cache-path=%t -fmodules-strict-decluse -fmodules -I %S/Inputs %s 2>&1 | FileCheck %s -check-prefix=DECLUSE
+// DECLUSE: error: module incomplete_mod does not depend on a module exporting {{'.*incomplete_mod_missing.h'}}
diff --git a/test/Modules/inferred-attributes.mm b/test/Modules/inferred-attributes.mm
new file mode 100644
index 000000000000..5fc1d623f396
--- /dev/null
+++ b/test/Modules/inferred-attributes.mm
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -F %S/Inputs/inferred-attr -fsyntax-only -verify %s
+// expected-no-diagnostics
+extern "C" {
+@import InferredExternC;
+}
diff --git a/test/Modules/load-after-failure.m b/test/Modules/load-after-failure.m
index f471fd88d505..38d4a3653205 100644
--- a/test/Modules/load-after-failure.m
+++ b/test/Modules/load-after-failure.m
@@ -1,4 +1,3 @@
-// REQUIRES: shell
// RUN: rm -rf %t
// RUN: mkdir -p %t
diff --git a/test/Modules/macro-reexport/c1.h b/test/Modules/macro-reexport/c1.h
index d6a20e7419c1..b63c278577f6 100644
--- a/test/Modules/macro-reexport/c1.h
+++ b/test/Modules/macro-reexport/c1.h
@@ -1,2 +1,4 @@
+#pragma once
+
#include "b1.h"
#define assert(x) c
diff --git a/test/Modules/macro-reexport/d1.h b/test/Modules/macro-reexport/d1.h
index fbd68d5de582..99abd2481597 100644
--- a/test/Modules/macro-reexport/d1.h
+++ b/test/Modules/macro-reexport/d1.h
@@ -1,2 +1,5 @@
+#pragma once
+
#include "c1.h"
+#undef assert
#define assert(x) d
diff --git a/test/Modules/macro-reexport/e1.h b/test/Modules/macro-reexport/e1.h
new file mode 100644
index 000000000000..6c6829df3654
--- /dev/null
+++ b/test/Modules/macro-reexport/e1.h
@@ -0,0 +1,2 @@
+#include "c1.h"
+#undef assert
diff --git a/test/Modules/macro-reexport/e2.h b/test/Modules/macro-reexport/e2.h
new file mode 100644
index 000000000000..7bc0b4972d2c
--- /dev/null
+++ b/test/Modules/macro-reexport/e2.h
@@ -0,0 +1,2 @@
+#include "d1.h"
+#undef assert
diff --git a/test/Modules/macro-reexport/f1.h b/test/Modules/macro-reexport/f1.h
new file mode 100644
index 000000000000..f8f6502a90c6
--- /dev/null
+++ b/test/Modules/macro-reexport/f1.h
@@ -0,0 +1,3 @@
+#include "e1.h"
+#include "d1.h"
+
diff --git a/test/Modules/macro-reexport/macro-reexport.cpp b/test/Modules/macro-reexport/macro-reexport.cpp
index 47b15c2740bd..af2ec847ce07 100644
--- a/test/Modules/macro-reexport/macro-reexport.cpp
+++ b/test/Modules/macro-reexport/macro-reexport.cpp
@@ -1,13 +1,30 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fsyntax-only -DD2 -I. %s -fmodules-cache-path=%t -verify
-// RUN: %clang_cc1 -fsyntax-only -DD2 -I. -fmodules %s -fmodules-cache-path=%t -verify
// RUN: %clang_cc1 -fsyntax-only -DC1 -I. %s -fmodules-cache-path=%t -verify
// RUN: %clang_cc1 -fsyntax-only -DC1 -I. -fmodules %s -fmodules-cache-path=%t -verify
+// RUN: %clang_cc1 -fsyntax-only -DD1 -I. %s -fmodules-cache-path=%t -verify
+// RUN: %clang_cc1 -fsyntax-only -DD1 -I. -fmodules %s -fmodules-cache-path=%t -verify
+// RUN: %clang_cc1 -fsyntax-only -DD2 -I. %s -fmodules-cache-path=%t -verify
+// RUN: %clang_cc1 -fsyntax-only -DD2 -I. -fmodules %s -fmodules-cache-path=%t -verify
+// RUN: %clang_cc1 -fsyntax-only -DF1 -I. %s -fmodules-cache-path=%t -verify
+// RUN: %clang_cc1 -fsyntax-only -DF1 -I. -fmodules %s -fmodules-cache-path=%t -verify
-#ifdef D2
+#if defined(F1)
+#include "f1.h"
+void f() { return assert(true); } // expected-error {{undeclared identifier 'd'}}
+#include "e2.h" // undefines d1's macro
+void g() { return assert(true); } // expected-error {{undeclared identifier 'assert'}}
+#elif defined(D1)
+#include "e1.h" // undefines c1's macro but not d1's macro
+#include "d1.h"
+void f() { return assert(true); } // expected-error {{undeclared identifier 'd'}}
+#include "e2.h" // undefines d1's macro
+void g() { return assert(true); } // expected-error {{undeclared identifier 'assert'}}
+#elif defined(D2)
#include "d2.h"
void f() { return assert(true); } // expected-error {{undeclared identifier 'b'}}
#else
+// e2 undefines d1's macro, which overrides c1's macro.
+#include "e2.h"
#include "c1.h"
-void f() { return assert(true); } // expected-error {{undeclared identifier 'c'}}
+void f() { return assert(true); } // expected-error {{undeclared identifier 'assert'}}
#endif
diff --git a/test/Modules/macro-reexport/module.modulemap b/test/Modules/macro-reexport/module.modulemap
index 21585b692e3f..896bda041c30 100644
--- a/test/Modules/macro-reexport/module.modulemap
+++ b/test/Modules/macro-reexport/module.modulemap
@@ -13,3 +13,11 @@ module d {
module d1 { header "d1.h" export * }
module d2 { header "d2.h" export * }
}
+module e {
+ module e1 { header "e1.h" export * }
+ module e2 { header "e2.h" export * }
+}
+module f {
+ module f1 { header "f1.h" export * }
+ module f2 { header "f2.h" export * }
+}
diff --git a/test/Modules/macros.c b/test/Modules/macros.c
index 7a7e570ca256..92ea88a48020 100644
--- a/test/Modules/macros.c
+++ b/test/Modules/macros.c
@@ -130,8 +130,14 @@ void test3() {
# error TOP_RIGHT_UNDEF should still be defined
#endif
+@import macros_bottom;
+
+TOP_DEF_RIGHT_UNDEF *TDRUf() { return TDRUp; }
+
@import macros_right.undef;
+int TOP_DEF_RIGHT_UNDEF; // ok, no longer defined
+
// FIXME: When macros_right.undef is built, macros_top is visible because
// the state from building macros_right leaks through, so macros_right.undef
// undefines macros_top's macro.
diff --git a/test/Modules/malformed.cpp b/test/Modules/malformed.cpp
index cd7b33493998..2554c3a8729f 100644
--- a/test/Modules/malformed.cpp
+++ b/test/Modules/malformed.cpp
@@ -1,23 +1,37 @@
+// This test explicitly cd's to the test/Modules directory so that we can test
+// that filenames found via relative -I paths are printed correctly.
+//
+// REQUIRES: shell
+//
// RUN: rm -rf %t
-// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/malformed -DHEADER="a1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-A
-// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/malformed -DHEADER="b1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-B
+// RUN: cd %S
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="a1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-A
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="b1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-B
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="c.h" malformed.cpp 2>&1 | FileCheck %s --check-prefix=CHECK-C
#define STR2(x) #x
#define STR(x) STR2(x)
#include STR(HEADER)
// CHECK-A: While building module 'malformed_a'
-// CHECK-A: a1.h:1:{{.*}} error: expected '}'
-// CHECK-A: a1.h:1:{{.*}} note: to match this '{'
+// CHECK-A: {{^}}Inputs/malformed/a1.h:1:{{.*}} error: expected '}'
+// CHECK-A: {{^}}Inputs/malformed/a1.h:1:{{.*}} note: to match this '{'
//
// CHECK-A: While building module 'malformed_a'
-// CHECK-A: a2.h:1:{{.*}} error: extraneous closing brace
+// CHECK-A: {{^}}Inputs/malformed/a2.h:1:{{.*}} error: extraneous closing brace
// CHECK-B: While building module 'malformed_b'
-// CHECK-B: b1.h:2:{{.*}} error: expected '}'
-// CHECK-B: b1.h:1:{{.*}} note: to match this '{'
-// CHECK-B: b1.h:3:{{.*}} error: extraneous closing brace ('}')
+// CHECK-B: {{^}}Inputs/malformed/b1.h:2:{{.*}} error: expected '}'
+// CHECK-B: {{^}}Inputs/malformed/b1.h:1:{{.*}} note: to match this '{'
+// CHECK-B: {{^}}Inputs/malformed/b1.h:3:{{.*}} error: extraneous closing brace ('}')
//
// CHECK-B: While building module 'malformed_b'
-// CHECK-B: b2.h:1:{{.*}} error: redefinition of 'g'
-// CHECK-B: b2.h:1:{{.*}} note: previous definition is here
+// CHECK-B: {{^}}Inputs/malformed/b2.h:1:{{.*}} error: redefinition of 'g'
+// CHECK-B: {{^}}Inputs/malformed/b2.h:1:{{.*}} note: previous definition is here
+
+void test() { f<int>(); }
+// Test that we use relative paths to name files within an imported module.
+//
+// CHECK-C: In module 'c' imported from malformed.cpp:14:
+// CHECK-C: {{^}}Inputs/malformed/c.h:1:33: error: type 'int' cannot be used prior to '::'
+// CHECK-C: {{^}}malformed.cpp:[[@LINE-5]]:15: note: in instantiation of
diff --git a/test/Modules/merge-typedefs.cpp b/test/Modules/merge-typedefs.cpp
new file mode 100644
index 000000000000..607f8c5ad0ec
--- /dev/null
+++ b/test/Modules/merge-typedefs.cpp
@@ -0,0 +1,10 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x c++ -I%S/Inputs/merge-typedefs -verify %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-typedefs -verify %s
+
+#include "b2.h"
+#include "a1.h"
+
+// expected-no-diagnostics
+llvm::MachineDomTreeNode *p;
+foo2_t f2t;
diff --git a/test/Modules/merge-using-decls.cpp b/test/Modules/merge-using-decls.cpp
new file mode 100644
index 000000000000..3b84d0e5a3a0
--- /dev/null
+++ b/test/Modules/merge-using-decls.cpp
@@ -0,0 +1,69 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify %s -DORDER=1
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify %s -DORDER=2
+
+#if ORDER == 1
+#include "a.h"
+#include "b.h"
+#else
+#include "b.h"
+#include "a.h"
+#endif
+
+struct Y {
+ int value; // expected-note 0-1{{target of using}}
+ typedef int type; // expected-note 0-1{{target of using}}
+};
+
+template<typename T> int Use() {
+ int k = T().v + T().value; // expected-note 0-2{{instantiation of}}
+ typedef typename T::type I;
+ typedef typename T::t I;
+ typedef int I;
+ return k;
+}
+
+template<typename T> int UseAll() {
+ return Use<C<T> >() + Use<D<T> >() + Use<E<T> >() + Use<F<T> >(); // expected-note 0-2{{instantiation of}}
+}
+
+template int UseAll<YA>();
+template int UseAll<YB>();
+template int UseAll<Y>();
+
+#if ORDER == 1
+// Here, we're instantiating the definition from 'A' and merging the definition
+// from 'B' into it.
+
+// expected-error@b.h:* {{'E::value' from module 'B' is not present in definition of 'E<T>' in module 'A'}}
+// expected-error@b.h:* {{'E::v' from module 'B' is not present in definition of 'E<T>' in module 'A'}}
+
+// expected-error@b.h:* {{'F::type' from module 'B' is not present in definition of 'F<T>' in module 'A'}}
+// expected-error@b.h:* {{'F::t' from module 'B' is not present in definition of 'F<T>' in module 'A'}}
+// expected-error@b.h:* {{'F::value' from module 'B' is not present in definition of 'F<T>' in module 'A'}}
+// expected-error@b.h:* {{'F::v' from module 'B' is not present in definition of 'F<T>' in module 'A'}}
+
+// expected-note@a.h:* +{{does not match}}
+#else
+// Here, we're instantiating the definition from 'B' and merging the definition
+// from 'A' into it.
+
+// expected-error@a.h:* {{'D::type' from module 'A' is not present in definition of 'D<T>' in module 'B'}}
+// expected-error@a.h:* {{'D::value' from module 'A' is not present in definition of 'D<T>' in module 'B'}}
+// expected-error@b.h:* 2{{'typename' keyword used on a non-type}}
+// expected-error@b.h:* 2{{dependent using declaration resolved to type without 'typename'}}
+
+// expected-error@a.h:* {{'E::type' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
+// expected-error@a.h:* {{'E::t' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
+// expected-error@a.h:* {{'E::value' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
+// expected-error@a.h:* {{'E::v' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
+// expected-note@b.h:* 2{{definition has no member}}
+
+// expected-error@a.h:* {{'F::type' from module 'A' is not present in definition of 'F<T>' in module 'B'}}
+// expected-error@a.h:* {{'F::t' from module 'A' is not present in definition of 'F<T>' in module 'B'}}
+// expected-error@a.h:* {{'F::value' from module 'A' is not present in definition of 'F<T>' in module 'B'}}
+// expected-error@a.h:* {{'F::v' from module 'A' is not present in definition of 'F<T>' in module 'B'}}
+
+// expected-note@b.h:* +{{does not match}}
+// expected-note@b.h:* +{{target of using}}
+#endif
diff --git a/test/Modules/modular_maps.cpp b/test/Modules/modular_maps.cpp
index 9c9aba85a918..606c979c4c2f 100644
--- a/test/Modules/modular_maps.cpp
+++ b/test/Modules/modular_maps.cpp
@@ -1,8 +1,22 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=%S/Inputs/modular_maps/modulea.map -I %S/Inputs/modular_maps %s -verify
+//
+// RxN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=%S/Inputs/modular_maps/modulea.map -fmodule-map-file=%S/Inputs/modular_maps/modulec.map -I %S/Inputs/modular_maps %s -verify
+// RxN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=%S/Inputs/modular_maps/modulec.map -fmodule-map-file=%S/Inputs/modular_maps/modulea.map -I %S/Inputs/modular_maps %s -verify
+//
+// RxN: cd %S
+// RxN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=Inputs/modular_maps/modulea.map -fmodule-map-file=Inputs/modular_maps/modulec.map -I Inputs/modular_maps %s -verify
+// RxN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=Inputs/modular_maps/modulec.map -fmodule-map-file=Inputs/modular_maps/modulea.map -I Inputs/modular_maps %s -verify
+//
+// RUN: cd %S
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=Inputs/modular_maps/modulea-cwd.map -fmodule-map-file=Inputs/modular_maps/modulec-cwd.map -I Inputs/modular_maps %s -verify -fmodule-map-file-home-is-cwd
+// RxN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=Inputs/modular_maps/modulec-cwd.map -fmodule-map-file=Inputs/modular_maps/modulea-cwd.map -I Inputs/modular_maps %s -verify -fmodule-map-file-home-is-cwd
+
+// chdir is unsupported on Lit internal runner.
+// REQUIRES: shell
#include "common.h"
#include "a.h"
#include "b.h" // expected-error {{private header}}
-const int v = a + c;
-const int val = a + b + c; // expected-error {{undeclared identifier}}
+@import C;
+const int v = a + c + x;
+const int val = a + b + c + x; // expected-error {{undeclared identifier}}
diff --git a/test/Modules/module_file_info.m b/test/Modules/module_file_info.m
index 2447a747e3dd..1b0a838bf823 100644
--- a/test/Modules/module_file_info.m
+++ b/test/Modules/module_file_info.m
@@ -17,8 +17,8 @@
// CHECK: Target options:
// CHECK: Triple:
-// CHECK: CPU:
-// CHECK: ABI:
+// CHECK: CPU:
+// CHECK: ABI:
// CHECK: Diagnostic options:
// CHECK: IgnoreWarnings: Yes
@@ -28,7 +28,7 @@
// CHECK: Header search options:
// CHECK: System root [-isysroot=]: '/'
// CHECK: Use builtin include directories [-nobuiltininc]: Yes
-// CHECK: Use standard system include directories [-nostdinc]: Yes
+// CHECK: Use standard system include directories [-nostdinc]: No
// CHECK: Use standard C++ include directories [-nostdinc++]: Yes
// CHECK: Use libc++ (rather than libstdc++) [-stdlib=]:
diff --git a/test/Modules/modules-with-same-name.m b/test/Modules/modules-with-same-name.m
index c90aa5d7d842..d362f756a60a 100644
--- a/test/Modules/modules-with-same-name.m
+++ b/test/Modules/modules-with-same-name.m
@@ -1,4 +1,3 @@
-// REQUIRES: shell
// RUN: rm -rf %t
// A from path 1
diff --git a/test/Modules/no-implicit-maps.cpp b/test/Modules/no-implicit-maps.cpp
new file mode 100644
index 000000000000..cb270a05014e
--- /dev/null
+++ b/test/Modules/no-implicit-maps.cpp
@@ -0,0 +1,3 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -fno-modules-implicit-maps -fmodules-cache-path=%t -fmodules -I %S/Inputs/private %s -verify
+@import libPrivate1; // expected-error {{not found}}
diff --git a/test/Modules/no-stale-modtime.m b/test/Modules/no-stale-modtime.m
index 1bff2b017a43..53512126a1b6 100644
--- a/test/Modules/no-stale-modtime.m
+++ b/test/Modules/no-stale-modtime.m
@@ -1,7 +1,6 @@
// Ensure that when rebuilding a module we don't save its old modtime when
// building modules that depend on it.
-// REQUIRES: shell
// RUN: rm -rf %t
// RUN: mkdir -p %t
// This could be replaced by diamond_*, except we want to modify the top header
diff --git a/test/Modules/odr.cpp b/test/Modules/odr.cpp
index 5ab10d2ce419..120ca20e0a87 100644
--- a/test/Modules/odr.cpp
+++ b/test/Modules/odr.cpp
@@ -6,6 +6,9 @@ struct X { // expected-note {{definition has no member 'n'}}
};
@import a;
+
+bool b = F<int>{0} == F<int>{1};
+
@import b;
// Trigger the declarations from a and b to be imported.
diff --git a/test/Modules/pch-used.m b/test/Modules/pch-used.m
index 56961ba404cc..74f21f5dac0f 100644
--- a/test/Modules/pch-used.m
+++ b/test/Modules/pch-used.m
@@ -4,5 +4,6 @@
// RUN: %clang_cc1 %s -include-pch %t/pch-used.h.pch -fmodules -fmodules-cache-path=%t/cache -O0 -isystem %S/Inputs/System/usr/include -emit-llvm -o - | FileCheck %s
void f() { SPXTrace(); }
+void g() { double x = DBL_MAX; }
// CHECK: define internal void @SPXTrace
diff --git a/test/Modules/pr19692.cpp b/test/Modules/pr19692.cpp
new file mode 100644
index 000000000000..6cc515312f00
--- /dev/null
+++ b/test/Modules/pr19692.cpp
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -I%S/Inputs/pr19692 -verify %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I%S/Inputs/pr19692 -verify %s
+#include "TFoo.h"
+#include "stdint.h"
+
+int k = INT64_MAX; // expected-no-diagnostics
diff --git a/test/Modules/pr20399.cpp b/test/Modules/pr20399.cpp
new file mode 100644
index 000000000000..4f4a02561fc2
--- /dev/null
+++ b/test/Modules/pr20399.cpp
@@ -0,0 +1,2 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-name=libGdml -emit-module -x c++ -std=c++11 %S/Inputs/PR20399/module.modulemap
diff --git a/test/Modules/pr20786.cpp b/test/Modules/pr20786.cpp
new file mode 100644
index 000000000000..4c0426ed5e58
--- /dev/null
+++ b/test/Modules/pr20786.cpp
@@ -0,0 +1,2 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-name=TBranchProxy -emit-module -x c++ %S/Inputs/PR20786/module.modulemap
diff --git a/test/Modules/pr21217.cpp b/test/Modules/pr21217.cpp
new file mode 100644
index 000000000000..a439c97e9577
--- /dev/null
+++ b/test/Modules/pr21217.cpp
@@ -0,0 +1,3 @@
+// RUN: not %clang_cc1 -fmodules -fmodule-map-file=does-not-exist.modulemap -verify %s 2>&1 | FileCheck %s
+
+// CHECK: module map file 'does-not-exist.modulemap' not found
diff --git a/test/Modules/preprocess.m b/test/Modules/preprocess.m
new file mode 100644
index 000000000000..5c32997f62fb
--- /dev/null
+++ b/test/Modules/preprocess.m
@@ -0,0 +1,21 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs -include %S/Inputs/preprocess-prefix.h -E %s | FileCheck -strict-whitespace %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs -x objective-c-header -emit-pch %S/Inputs/preprocess-prefix.h -o %t.pch
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs -include-pch %t.pch -E %s | FileCheck -strict-whitespace %s
+#import "diamond_right.h"
+#import "diamond_right.h" // to check that imports get their own line
+void test() {
+ top_left_before();
+ left_and_right();
+}
+
+
+// CHECK: int left_and_right(int *);{{$}}
+// CHECK-NEXT: @import diamond_left; /* clang -E: implicit import for "{{.*}}diamond_left.h" */{{$}}
+
+// CHECK: @import diamond_right; /* clang -E: implicit import for "{{.*}}diamond_right.h" */{{$}}
+// CHECK: @import diamond_right; /* clang -E: implicit import for "{{.*}}diamond_right.h" */{{$}}
+// CHECK-NEXT: void test() {{{$}}
+// CHECK-NEXT: top_left_before();{{$}}
+// CHECK-NEXT: left_and_right();{{$}}
+// CHECK-NEXT: }{{$}}
diff --git a/test/Modules/rebuild.m b/test/Modules/rebuild.m
new file mode 100644
index 000000000000..4d4d05529e7d
--- /dev/null
+++ b/test/Modules/rebuild.m
@@ -0,0 +1,45 @@
+// RUN: rm -rf %t
+
+// Build Module and set its timestamp
+// RUN: echo '@import Module;' | %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs -x objective-c -
+// RUN: touch -m -a -t 201101010000 %t/Module.pcm
+// RUN: cp %t/Module.pcm %t/Module.pcm.saved
+// RUN: wc -c %t/Module.pcm > %t/Module.size.saved
+
+// Build DependsOnModule
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs %s
+// RUN: diff %t/Module.pcm %t/Module.pcm.saved
+// RUN: cp %t/DependsOnModule.pcm %t/DependsOnModule.pcm.saved
+
+// Rebuild Module, reset its timestamp, and verify its size hasn't changed
+// RUN: rm %t/Module.pcm
+// RUN: echo '@import Module;' | %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs -x objective-c -
+// RUN: touch -m -a -t 201101010000 %t/Module.pcm
+// RUN: wc -c %t/Module.pcm > %t/Module.size
+// RUN: diff %t/Module.size %t/Module.size.saved
+// RUN: cp %t/Module.pcm %t/Module.pcm.saved.2
+
+// But the signature at least is expected to change, so we rebuild DependsOnModule.
+// NOTE: if we change how the signature is created, this test may need updating.
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs %s
+// RUN: diff %t/Module.pcm %t/Module.pcm.saved.2
+// RUN: not diff %t/DependsOnModule.pcm %t/DependsOnModule.pcm.saved
+
+// Rebuild Module, reset its timestamp, and verify its size hasn't changed
+// RUN: rm %t/Module.pcm
+// RUN: echo '@import Module;' | %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs -x objective-c -
+// RUN: touch -m -a -t 201101010000 %t/Module.pcm
+// RUN: wc -c %t/Module.pcm > %t/Module.size
+// RUN: diff %t/Module.size %t/Module.size.saved
+// RUN: cp %t/Module.pcm %t/Module.pcm.saved.2
+
+// Verify again with Module pre-imported.
+// NOTE: if we change how the signature is created, this test may need updating.
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs %s
+// RUN: diff %t/Module.pcm %t/Module.pcm.saved.2
+// RUN: not diff %t/DependsOnModule.pcm %t/DependsOnModule.pcm.saved
+
+#ifdef PREIMPORT
+@import Module;
+#endif
+@import DependsOnModule;
diff --git a/test/Modules/relative-dep-gen.cpp b/test/Modules/relative-dep-gen.cpp
new file mode 100644
index 000000000000..c8171777154a
--- /dev/null
+++ b/test/Modules/relative-dep-gen.cpp
@@ -0,0 +1,26 @@
+// REQUIRES: shell
+//
+// RUN: cd %S
+// RUN: rm -rf %t
+// RUN: mkdir %t
+//
+// RUN: %clang_cc1 -cc1 -fmodule-name=relative-dep-gen -emit-module -x c++ Inputs/relative-dep-gen.modulemap -dependency-file %t/build.d -MT mod.pcm -o %t/mod.pcm
+// RUN: %clang_cc1 -cc1 -fmodule-map-file=Inputs/relative-dep-gen.modulemap -fmodule-file=%t/mod.pcm -dependency-file %t/use-explicit.d -MT use.o relative-dep-gen.cpp -fsyntax-only
+// RUN: %clang_cc1 -cc1 -fmodule-map-file=Inputs/relative-dep-gen.modulemap -dependency-file %t/use-implicit.d relative-dep-gen.cpp -MT use.o -fsyntax-only
+//
+// RUN: FileCheck --check-prefix=CHECK-BUILD %s < %t/build.d
+// RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-explicit.d
+// RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-implicit.d
+//
+// RUN: %clang_cc1 -cc1 -fmodule-name=relative-dep-gen -emit-module -x c++ Inputs/relative-dep-gen-cwd.modulemap -dependency-file %t/build-cwd.d -MT mod.pcm -o %t/mod-cwd.pcm -fmodule-map-file-home-is-cwd
+// RUN: %clang_cc1 -cc1 -fmodule-map-file=Inputs/relative-dep-gen-cwd.modulemap -fmodule-file=%t/mod-cwd.pcm -dependency-file %t/use-explicit-cwd.d -MT use.o relative-dep-gen.cpp -fsyntax-only -fmodule-map-file-home-is-cwd
+// RUN: %clang_cc1 -cc1 -fmodule-map-file=Inputs/relative-dep-gen-cwd.modulemap -dependency-file %t/use-implicit-cwd.d relative-dep-gen.cpp -MT use.o -fsyntax-only -fmodule-map-file-home-is-cwd
+//
+// RUN: FileCheck --check-prefix=CHECK-BUILD %s < %t/build-cwd.d
+// RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-explicit-cwd.d
+// RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-implicit-cwd.d
+
+#include "Inputs/relative-dep-gen-1.h"
+
+// CHECK-BUILD: mod.pcm: Inputs/relative-dep-gen-1.h Inputs/relative-dep-gen-2.h
+// CHECK-USE: use.o: relative-dep-gen.cpp Inputs/relative-dep-gen-1.h
diff --git a/test/Modules/require-modular-includes.m b/test/Modules/require-modular-includes.m
index 835a35243396..302e4cd191cd 100644
--- a/test/Modules/require-modular-includes.m
+++ b/test/Modules/require-modular-includes.m
@@ -1,5 +1,4 @@
// RUN: rm -rf %t
-// REQUIRES: shell
// Including a header from the imported module
// RUN: echo '@import FromImportedModuleOK;' | \
diff --git a/test/Modules/resolution-change.m b/test/Modules/resolution-change.m
index 011782eec2bf..6882fe44c5cb 100644
--- a/test/Modules/resolution-change.m
+++ b/test/Modules/resolution-change.m
@@ -11,15 +11,15 @@
// Use the PCH with no way to resolve DependsOnA
// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-NODOA %s
-// CHECK-NODOA: module 'DependsOnA' imported by AST file '{{.*A.pch}}' not found
+// CHECK-NODOA: module 'DependsOnA' in AST file '{{.*DependsOnA.*pcm}}' (imported by AST file '{{.*A.pch}}') is not defined in any loaded module map
// Use the PCH with no way to resolve A
// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-NOA %s
-// CHECK-NOA: module 'A' imported by AST file '{{.*DependsOnA.*pcm}}' not found
+// CHECK-NOA: module 'A' in AST file '{{.*A.*pcm}}' (imported by AST file '{{.*DependsOnA.*pcm}}') is not defined in any loaded module map
-// Use the PCH and have it resolve the the other A
+// Use the PCH and have it resolve to the other A
// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path2/A -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-WRONGA %s
-// CHECK-WRONGA: module 'A' imported by AST file '{{.*DependsOnA.*pcm}}' found in a different module map file ({{.*path2.*}}) than when the importing AST file was built ({{.*path1.*}})
+// CHECK-WRONGA: module 'A' was built in directory '{{.*Inputs.modules-with-same-name.path1.A}}' but now resides in directory '{{.*Inputs.modules-with-same-name.path2.A}}'
#ifndef HEADER
#define HEADER
diff --git a/test/Modules/stddef.c b/test/Modules/stddef.c
new file mode 100644
index 000000000000..aefc90f9a117
--- /dev/null
+++ b/test/Modules/stddef.c
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I%S/Inputs/StdDef %s -verify -fno-modules-error-recovery
+
+#include "ptrdiff_t.h"
+
+ptrdiff_t pdt;
+
+size_t st; // expected-error {{must be imported}}
+// expected-note@stddef.h:* {{previous}}
+
+#include "include_again.h"
+
+size_t st2;
diff --git a/test/Modules/system_headers.m b/test/Modules/system_headers.m
index 39b13ca5fc4a..8adc7e857699 100644
--- a/test/Modules/system_headers.m
+++ b/test/Modules/system_headers.m
@@ -1,8 +1,13 @@
// Test that system-headerness works for building modules.
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -isystem %S/Inputs -pedantic -Werror %s -verify
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -isystem %S/Inputs -pedantic -Werror %s -verify -std=c11
// expected-no-diagnostics
@import warning;
int i = bigger_than_int;
+
+#include <stddef.h>
+
+#define __need_size_t
+#include <stddef.h>
diff --git a/test/Modules/system_version.m b/test/Modules/system_version.m
index bc82bf8bc17b..55174ef1506c 100644
--- a/test/Modules/system_version.m
+++ b/test/Modules/system_version.m
@@ -1,6 +1,5 @@
// Test checking that we're hashing a system version file in the
// module hash.
-// REQUIRES: shell
// First, build a system root.
// RUN: rm -rf %t
diff --git a/test/Modules/templates-2.mm b/test/Modules/templates-2.mm
new file mode 100644
index 000000000000..b7ceafbbc5ba
--- /dev/null
+++ b/test/Modules/templates-2.mm
@@ -0,0 +1,36 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs -verify %s -Wno-objc-root-class
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs -emit-llvm %s -o - -Wno-objc-root-class | FileCheck %s
+// expected-no-diagnostics
+
+@import templates_top;
+
+struct TestEmitDefaultedSpecialMembers {
+ EmitDefaultedSpecialMembers::SmallVector<char, 256> V;
+};
+
+@import templates_left;
+
+void testEmitDefaultedSpecialMembers() {
+ EmitDefaultedSpecialMembers::SmallString<256> V;
+ // CHECK: call {{.*}} @_ZN27EmitDefaultedSpecialMembers11SmallStringILj256EEC1Ev(
+ // CHECK: call {{.*}} @_ZN27EmitDefaultedSpecialMembers11SmallStringILj256EED1Ev(
+}
+
+// CHECK-LABEL: define {{.*}} @_ZN27EmitDefaultedSpecialMembers11SmallStringILj256EEC1Ev(
+// CHECK: call {{.*}} @_ZN27EmitDefaultedSpecialMembers11SmallStringILj256EEC2Ev(
+
+// CHECK-LABEL: define {{.*}} @_ZN27EmitDefaultedSpecialMembers11SmallStringILj256EED1Ev(
+// CHECK: call {{.*}} @_ZN27EmitDefaultedSpecialMembers11SmallStringILj256EED2Ev(
+
+// CHECK-LABEL: define linkonce_odr void @_ZN27EmitDefaultedSpecialMembers11SmallStringILj256EED2Ev(
+// CHECK: call void @_ZN27EmitDefaultedSpecialMembers11SmallVectorIcLj256EED2Ev(
+// CHECK-LABEL: define linkonce_odr void @_ZN27EmitDefaultedSpecialMembers11SmallVectorIcLj256EED2Ev(
+// CHECK: call void @_ZN27EmitDefaultedSpecialMembers15SmallVectorImplIcED2Ev(
+// CHECK-LABEL: define linkonce_odr void @_ZN27EmitDefaultedSpecialMembers15SmallVectorImplIcED2Ev(
+
+// CHECK-LABEL: define linkonce_odr void @_ZN27EmitDefaultedSpecialMembers11SmallStringILj256EEC2Ev(
+// CHECK: call void @_ZN27EmitDefaultedSpecialMembers11SmallVectorIcLj256EEC2Ev(
+// CHECK-LABEL: define linkonce_odr void @_ZN27EmitDefaultedSpecialMembers11SmallVectorIcLj256EEC2Ev(
+// CHECK: call void @_ZN27EmitDefaultedSpecialMembers15SmallVectorImplIcEC2Ev(
+// CHECK-LABEL: define linkonce_odr void @_ZN27EmitDefaultedSpecialMembers15SmallVectorImplIcEC2Ev(
diff --git a/test/Modules/templates.mm b/test/Modules/templates.mm
index 78348af41e77..d60b873d0f38 100644
--- a/test/Modules/templates.mm
+++ b/test/Modules/templates.mm
@@ -12,10 +12,11 @@ void testInlineRedeclEarly() {
@import templates_right;
-// CHECK: @list_left = global { %{{.*}}*, i32, [4 x i8] } { %{{.*}}* null, i32 8,
-// CHECK: @list_right = global { %{{.*}}*, i32, [4 x i8] } { %{{.*}}* null, i32 12,
-// CHECK: @_ZZ15testMixedStructvE1l = {{.*}} constant { %{{.*}}*, i32, [4 x i8] } { %{{.*}}* null, i32 1,
-// CHECK: @_ZZ15testMixedStructvE1r = {{.*}} constant { %{{.*}}*, i32, [4 x i8] } { %{{.*}}* null, i32 2,
+// CHECK-DAG: @list_left = global %class.List { %"struct.List<int>::node"* null, i32 8 }, align 8
+// CHECK-DAG: @list_right = global %class.List { %"struct.List<int>::node"* null, i32 12 }, align 8
+// CHECK-DAG: @_ZZ15testMixedStructvE1l = {{.*}} constant %class.List { %{{.*}}* null, i32 1 }, align 8
+// CHECK-DAG: @_ZZ15testMixedStructvE1r = {{.*}} constant %class.List { %{{.*}}* null, i32 2 }, align 8
+// CHECK-DAG: @_ZN29WithUndefinedStaticDataMemberIA_iE9undefinedE = external global
void testTemplateClasses() {
Vector<int> vec_int;
@@ -100,3 +101,17 @@ template struct ExplicitInstantiation<false, true>;
template struct ExplicitInstantiation<true, true>;
void testDelayUpdatesImpl() { testDelayUpdates<int>(); }
+
+void testStaticDataMember() {
+ WithUndefinedStaticDataMember<int[]> load_it;
+
+ // CHECK-LABEL: define linkonce_odr i32* @_Z23getStaticDataMemberLeftv(
+ // CHECK: ret i32* getelementptr inbounds ([0 x i32]* @_ZN29WithUndefinedStaticDataMemberIA_iE9undefinedE, i32 0, i32 0)
+ (void) getStaticDataMemberLeft();
+
+ // CHECK-LABEL: define linkonce_odr i32* @_Z24getStaticDataMemberRightv(
+ // CHECK: ret i32* getelementptr inbounds ([0 x i32]* @_ZN29WithUndefinedStaticDataMemberIA_iE9undefinedE, i32 0, i32 0)
+ (void) getStaticDataMemberRight();
+}
+
+
diff --git a/test/Modules/textual-headers.cpp b/test/Modules/textual-headers.cpp
new file mode 100644
index 000000000000..cab9991e3291
--- /dev/null
+++ b/test/Modules/textual-headers.cpp
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodule-maps -fmodules-cache-path=%t -fmodules-strict-decluse -fmodule-name=XG -I %S/Inputs/declare-use %s -verify
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-strict-decluse -fmodule-name=XG -I %S/Inputs/declare-use %s -verify -fno-modules-error-recovery
+
+#define GIMME_A_K
+#include "k.h"
+
+#define GIMME_AN_L
+#include "l.h" // expected-error {{module XG does not depend on a module exporting 'l.h'}}
+
+#include "m2.h" // expected-error {{module XG does not depend on a module exporting 'm2.h'}}
+const int use_m = m; // expected-error {{undeclared identifier}}
+
+#define GIMME_AN_M
+#include "m.h" // expected-error {{use of private header from outside its module: 'm.h'}}
+const int use_m_2 = m;
+
+const int g = k + l;
diff --git a/test/Modules/va_list.m b/test/Modules/va_list.m
new file mode 100644
index 000000000000..5a305180fcfa
--- /dev/null
+++ b/test/Modules/va_list.m
@@ -0,0 +1,27 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10 -fmodules -fmodules-cache-path=%t \
+// RUN: -fmodules-ignore-macro=PREFIX -DPREFIX -I %S/Inputs/va_list \
+// RUN: -x objective-c-header %s -o %t.pch -emit-pch
+
+// Include the pch, as a sanity check.
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10 -fmodules -fmodules-cache-path=%t \
+// RUN: -fmodules-ignore-macro=PREFIX -I %S/Inputs/va_list -include-pch %t.pch \
+// RUN: -x objective-c %s -fsyntax-only
+
+// Repeat the previous emit-pch, but not we will have a global module index.
+// For some reason, this results in an identifier for __va_list_tag being
+// emitted into the pch.
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10 -fmodules -fmodules-cache-path=%t \
+// RUN: -fmodules-ignore-macro=PREFIX -DPREFIX -I %S/Inputs/va_list \
+// RUN: -x objective-c-header %s -o %t.pch -emit-pch
+
+// Include the pch, which now has __va_list_tag in it, which needs to be merged.
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10 -fmodules -fmodules-cache-path=%t \
+// RUN: -fmodules-ignore-macro=PREFIX -I %S/Inputs/va_list -include-pch %t.pch \
+// RUN: -x objective-c %s -fsyntax-only
+
+// rdar://18039719
+
+#ifdef PREFIX
+@import va_list_b;
+#endif
diff --git a/test/Modules/validate-system-headers.m b/test/Modules/validate-system-headers.m
index 48ea64c5a938..8cdc886322bd 100644
--- a/test/Modules/validate-system-headers.m
+++ b/test/Modules/validate-system-headers.m
@@ -5,39 +5,37 @@
////
// Build a module using a system header
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t/Inputs -fmodules -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s
+// RUN: %clang_cc1 -isystem %t/Inputs/usr/include -fmodules -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s
// RUN: cp %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
////
// Modify the system header, and confirm that we don't notice without -fmodules-validate-system-headers.
// The pcm file in the cache should fail to validate.
// RUN: echo ' ' >> %t/Inputs/usr/include/foo.h
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t/Inputs -fmodules -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s
+// RUN: %clang_cc1 -isystem %t/Inputs/usr/include -fmodules -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s
// RUN: diff %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
////
// Now make sure we rebuild the module when -fmodules-validate-system-headers is set.
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t/Inputs -fmodules -fmodules-validate-system-headers -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s
+// RUN: %clang_cc1 -isystem %t/Inputs/usr/include -fmodules -fmodules-validate-system-headers -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s
// RUN: not diff %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
////
// This should override -fmodules-validate-once-per-build-session
// RUN: cp %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t/Inputs -fmodules -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session
+// RUN: %clang_cc1 -isystem %t/Inputs/usr/include -fmodules -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session
// RUN: diff %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
// Modify the system header...
// RUN: echo ' ' >> %t/Inputs/usr/include/foo.h
// Don't recompile due to -fmodules-validate-once-per-build-session
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t/Inputs -fmodules -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session
+// RUN: %clang_cc1 -isystem %t/Inputs/usr/include -fmodules -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session
// RUN: diff %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
// Now add -fmodules-validate-system-headers and rebuild
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t/Inputs -fmodules -fmodules-validate-system-headers -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session
+// RUN: %clang_cc1 -isystem %t/Inputs/usr/include -fmodules -fmodules-validate-system-headers -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session
// RUN: not diff %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
-// REQUIRES: shell
-
@import Foo;
diff --git a/test/Modules/warn-unused-local-typedef.cpp b/test/Modules/warn-unused-local-typedef.cpp
new file mode 100644
index 000000000000..60e0612d6ce7
--- /dev/null
+++ b/test/Modules/warn-unused-local-typedef.cpp
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: %clang -Wunused-local-typedef -c -x objective-c++ -fcxx-modules -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -o /dev/null 2>&1 | FileCheck %s -check-prefix=CHECK_1
+// RUN: %clang -Wunused-local-typedef -c -x objective-c++ -fcxx-modules -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -o /dev/null 2>&1 | FileCheck %s -check-prefix=CHECK_2 -allow-empty
+
+// For modules, the warning should only fire the first time, when the module is
+// built.
+// CHECK_1: warning: unused typedef
+// CHECK_2-NOT: warning: unused typedef
+@import warn_unused_local_typedef;
diff --git a/test/OpenMP/atomic_ast_print.cpp b/test/OpenMP/atomic_ast_print.cpp
new file mode 100644
index 000000000000..e75d291eab51
--- /dev/null
+++ b/test/OpenMP/atomic_ast_print.cpp
@@ -0,0 +1,176 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+template <class T>
+T foo(T argc) {
+ T b = T();
+ T a = T();
+#pragma omp atomic
+ a++;
+#pragma omp atomic read
+ a = argc;
+#pragma omp atomic write
+ a = argc + argc;
+#pragma omp atomic update
+ a = a + argc;
+#pragma omp atomic capture
+ a = b++;
+#pragma omp atomic capture
+ {
+ a = b;
+ b++;
+ }
+#pragma omp atomic seq_cst
+ a++;
+#pragma omp atomic read seq_cst
+ a = argc;
+#pragma omp atomic seq_cst write
+ a = argc + argc;
+#pragma omp atomic update seq_cst
+ a = a + argc;
+#pragma omp atomic seq_cst capture
+ a = b++;
+#pragma omp atomic capture seq_cst
+ {
+ a = b;
+ b++;
+ }
+ return T();
+}
+
+// CHECK: int a = int();
+// CHECK-NEXT: #pragma omp atomic
+// CHECK-NEXT: a++;
+// CHECK-NEXT: #pragma omp atomic read
+// CHECK-NEXT: a = argc;
+// CHECK-NEXT: #pragma omp atomic write
+// CHECK-NEXT: a = argc + argc;
+// CHECK-NEXT: #pragma omp atomic update
+// CHECK-NEXT: a = a + argc;
+// CHECK-NEXT: #pragma omp atomic capture
+// CHECK-NEXT: a = b++;
+// CHECK-NEXT: #pragma omp atomic capture
+// CHECK-NEXT: {
+// CHECK-NEXT: a = b;
+// CHECK-NEXT: b++;
+// CHECK-NEXT: }
+// CHECK-NEXT: #pragma omp atomic seq_cst
+// CHECK-NEXT: a++;
+// CHECK-NEXT: #pragma omp atomic read seq_cst
+// CHECK-NEXT: a = argc;
+// CHECK-NEXT: #pragma omp atomic seq_cst write
+// CHECK-NEXT: a = argc + argc;
+// CHECK-NEXT: #pragma omp atomic update seq_cst
+// CHECK-NEXT: a = a + argc;
+// CHECK-NEXT: #pragma omp atomic seq_cst capture
+// CHECK-NEXT: a = b++;
+// CHECK-NEXT: #pragma omp atomic capture seq_cst
+// CHECK-NEXT: {
+// CHECK-NEXT: a = b;
+// CHECK-NEXT: b++;
+// CHECK-NEXT: }
+// CHECK: T a = T();
+// CHECK-NEXT: #pragma omp atomic
+// CHECK-NEXT: a++;
+// CHECK-NEXT: #pragma omp atomic read
+// CHECK-NEXT: a = argc;
+// CHECK-NEXT: #pragma omp atomic write
+// CHECK-NEXT: a = argc + argc;
+// CHECK-NEXT: #pragma omp atomic update
+// CHECK-NEXT: a = a + argc;
+// CHECK-NEXT: #pragma omp atomic capture
+// CHECK-NEXT: a = b++;
+// CHECK-NEXT: #pragma omp atomic capture
+// CHECK-NEXT: {
+// CHECK-NEXT: a = b;
+// CHECK-NEXT: b++;
+// CHECK-NEXT: }
+// CHECK-NEXT: #pragma omp atomic seq_cst
+// CHECK-NEXT: a++;
+// CHECK-NEXT: #pragma omp atomic read seq_cst
+// CHECK-NEXT: a = argc;
+// CHECK-NEXT: #pragma omp atomic seq_cst write
+// CHECK-NEXT: a = argc + argc;
+// CHECK-NEXT: #pragma omp atomic update seq_cst
+// CHECK-NEXT: a = a + argc;
+// CHECK-NEXT: #pragma omp atomic seq_cst capture
+// CHECK-NEXT: a = b++;
+// CHECK-NEXT: #pragma omp atomic capture seq_cst
+// CHECK-NEXT: {
+// CHECK-NEXT: a = b;
+// CHECK-NEXT: b++;
+// CHECK-NEXT: }
+
+int main(int argc, char **argv) {
+ int b = 0;
+ int a = 0;
+// CHECK: int a = 0;
+#pragma omp atomic
+ a++;
+#pragma omp atomic read
+ a = argc;
+#pragma omp atomic write
+ a = argc + argc;
+#pragma omp atomic update
+ a = a + argc;
+#pragma omp atomic capture
+ a = b++;
+#pragma omp atomic capture
+ {
+ a = b;
+ b++;
+ }
+#pragma omp atomic seq_cst
+ a++;
+#pragma omp atomic read seq_cst
+ a = argc;
+#pragma omp atomic seq_cst write
+ a = argc + argc;
+#pragma omp atomic update seq_cst
+ a = a + argc;
+#pragma omp atomic seq_cst capture
+ a = b++;
+#pragma omp atomic capture seq_cst
+ {
+ a = b;
+ b++;
+ }
+ // CHECK-NEXT: #pragma omp atomic
+ // CHECK-NEXT: a++;
+ // CHECK-NEXT: #pragma omp atomic read
+ // CHECK-NEXT: a = argc;
+ // CHECK-NEXT: #pragma omp atomic write
+ // CHECK-NEXT: a = argc + argc;
+ // CHECK-NEXT: #pragma omp atomic update
+ // CHECK-NEXT: a = a + argc;
+ // CHECK-NEXT: #pragma omp atomic capture
+ // CHECK-NEXT: a = b++;
+ // CHECK-NEXT: #pragma omp atomic capture
+ // CHECK-NEXT: {
+ // CHECK-NEXT: a = b;
+ // CHECK-NEXT: b++;
+ // CHECK-NEXT: }
+ // CHECK-NEXT: #pragma omp atomic seq_cst
+ // CHECK-NEXT: a++;
+ // CHECK-NEXT: #pragma omp atomic read seq_cst
+ // CHECK-NEXT: a = argc;
+ // CHECK-NEXT: #pragma omp atomic seq_cst write
+ // CHECK-NEXT: a = argc + argc;
+ // CHECK-NEXT: #pragma omp atomic update seq_cst
+ // CHECK-NEXT: a = a + argc;
+ // CHECK-NEXT: #pragma omp atomic seq_cst capture
+ // CHECK-NEXT: a = b++;
+ // CHECK-NEXT: #pragma omp atomic capture seq_cst
+ // CHECK-NEXT: {
+ // CHECK-NEXT: a = b;
+ // CHECK-NEXT: b++;
+ // CHECK-NEXT: }
+ return foo(a);
+}
+
+#endif
diff --git a/test/OpenMP/atomic_messages.c b/test/OpenMP/atomic_messages.c
new file mode 100644
index 000000000000..ae490ee0841a
--- /dev/null
+++ b/test/OpenMP/atomic_messages.c
@@ -0,0 +1,102 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 %s
+
+int foo() {
+L1:
+ foo();
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+ foo();
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ }
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+ foo();
+ L2:
+ foo();
+ }
+
+ return 0;
+}
+
+struct S {
+ int a;
+};
+
+int readint() {
+ int a = 0, b = 0;
+// Test for atomic read
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected an expression statement}}
+ ;
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ foo();
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ a += b;
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected lvalue expression}}
+ a = 0;
+#pragma omp atomic read
+ a = b;
+ // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'read' clause}}
+#pragma omp atomic read read
+ a = b;
+
+ return 0;
+}
+
+int readS() {
+ struct S a, b;
+ // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'read' clause}}
+#pragma omp atomic read read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected expression of scalar type}}
+ a = b;
+
+ return a.a;
+}
+
+int writeint() {
+ int a = 0, b = 0;
+// Test for atomic write
+#pragma omp atomic write
+ // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}}
+ // expected-note@+1 {{expected an expression statement}}
+ ;
+#pragma omp atomic write
+ // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ foo();
+#pragma omp atomic write
+ // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ a += b;
+#pragma omp atomic write
+ a = 0;
+#pragma omp atomic write
+ a = b;
+ // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'write' clause}}
+#pragma omp atomic write write
+ a = b;
+
+ return 0;
+}
+
+int writeS() {
+ struct S a, b;
+ // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'write' clause}}
+#pragma omp atomic write write
+ // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}}
+ // expected-note@+1 {{expected expression of scalar type}}
+ a = b;
+
+ return a.a;
+}
diff --git a/test/OpenMP/atomic_messages.cpp b/test/OpenMP/atomic_messages.cpp
new file mode 100644
index 000000000000..a6c07ad9e289
--- /dev/null
+++ b/test/OpenMP/atomic_messages.cpp
@@ -0,0 +1,297 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 %s
+
+int foo() {
+L1:
+ foo();
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+ foo();
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ }
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+ foo();
+ L2:
+ foo();
+ }
+
+ return 0;
+}
+
+struct S {
+ int a;
+ S &operator=(int v) {
+ a = v;
+ return *this;
+ }
+ S &operator+=(const S &s) {
+ a += s.a;
+ return *this;
+ }
+};
+
+template <class T>
+T read() {
+ T a = T(), b = T();
+// Test for atomic read
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected an expression statement}}
+ ;
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ foo();
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ a += b;
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected lvalue expression}}
+ a = 0;
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ a = b;
+ // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'read' clause}}
+#pragma omp atomic read read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ a = b;
+
+ return a;
+}
+
+int read() {
+ int a = 0, b = 0;
+// Test for atomic read
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected an expression statement}}
+ ;
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ foo();
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ a += b;
+#pragma omp atomic read
+ // expected-error@+2 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both lvalue expressions with scalar type}}
+ // expected-note@+1 {{expected lvalue expression}}
+ a = 0;
+#pragma omp atomic read
+ a = b;
+ // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'read' clause}}
+#pragma omp atomic read read
+ a = b;
+
+ // expected-note@+1 {{in instantiation of function template specialization 'read<S>' requested here}}
+ return read<int>() + read<S>().a;
+}
+
+template <class T>
+T write() {
+ T a, b = 0;
+// Test for atomic write
+#pragma omp atomic write
+ // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}}
+ // expected-note@+1 {{expected an expression statement}}
+ ;
+// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'write' clause}}
+#pragma omp atomic write write
+ a = b;
+#pragma omp atomic write
+ // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ foo();
+#pragma omp atomic write
+ // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ a += b;
+#pragma omp atomic write
+ a = 0;
+#pragma omp atomic write
+ a = b;
+
+ return T();
+}
+
+int write() {
+ int a, b = 0;
+// Test for atomic write
+#pragma omp atomic write
+ // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}}
+ // expected-note@+1 {{expected an expression statement}}
+ ;
+// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'write' clause}}
+#pragma omp atomic write write
+ a = b;
+#pragma omp atomic write
+ // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ foo();
+#pragma omp atomic write
+ // expected-error@+2 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is a lvalue expression with scalar type}}
+ // expected-note@+1 {{expected built-in assignment operator}}
+ a += b;
+#pragma omp atomic write
+ a = 0;
+#pragma omp atomic write
+ a = foo();
+
+ return write<int>();
+}
+
+template <class T>
+T update() {
+ T a, b = 0;
+// Test for atomic update
+#pragma omp atomic update
+ // expected-error@+1 {{the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ ;
+// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'update' clause}}
+#pragma omp atomic update update
+ a += b;
+
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ ;
+
+ return T();
+}
+
+int update() {
+ int a, b = 0;
+// Test for atomic update
+#pragma omp atomic update
+ // expected-error@+1 {{the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ ;
+// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'update' clause}}
+#pragma omp atomic update update
+ a += b;
+
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ ;
+
+ return update<int>();
+}
+
+template <class T>
+T capture() {
+ T a, b = 0;
+// Test for atomic capture
+#pragma omp atomic capture
+ // expected-error@+1 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ ++a;
+#pragma omp atomic capture
+ // expected-error@+1 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ ;
+// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
+#pragma omp atomic capture capture
+ a = ++b;
+
+ return T();
+}
+
+int capture() {
+ int a, b = 0;
+// Test for atomic capture
+#pragma omp atomic capture
+ // expected-error@+1 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ ++a;
+#pragma omp atomic capture
+ // expected-error@+1 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ ;
+// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
+#pragma omp atomic capture capture
+ a = ++b;
+
+ return capture<int>();
+}
+
+template <class T>
+T seq_cst() {
+ T a, b = 0;
+// Test for atomic seq_cst
+#pragma omp atomic seq_cst
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ ;
+// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'seq_cst' clause}}
+#pragma omp atomic seq_cst seq_cst
+ a += b;
+
+#pragma omp atomic update seq_cst
+ // expected-error@+1 {{the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ ;
+
+ return T();
+}
+
+int seq_cst() {
+ int a, b = 0;
+// Test for atomic seq_cst
+#pragma omp atomic seq_cst
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ ;
+// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'seq_cst' clause}}
+#pragma omp atomic seq_cst seq_cst
+ a += b;
+
+#pragma omp atomic update seq_cst
+ // expected-error@+1 {{the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ ;
+
+ return seq_cst<int>();
+}
+
+template <class T>
+T mixed() {
+ T a, b = T();
+// expected-error@+2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
+// expected-note@+1 2 {{'read' clause used here}}
+#pragma omp atomic read write
+ a = b;
+// expected-error@+2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
+// expected-note@+1 2 {{'write' clause used here}}
+#pragma omp atomic write read
+ a = b;
+// expected-error@+2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
+// expected-note@+1 2 {{'update' clause used here}}
+#pragma omp atomic update read
+ a += b;
+// expected-error@+2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
+// expected-note@+1 2 {{'capture' clause used here}}
+#pragma omp atomic capture read
+ a = ++b;
+ return T();
+}
+
+int mixed() {
+ int a, b = 0;
+// expected-error@+2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
+// expected-note@+1 {{'read' clause used here}}
+#pragma omp atomic read write
+ a = b;
+// expected-error@+2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
+// expected-note@+1 {{'write' clause used here}}
+#pragma omp atomic write read
+ a = b;
+// expected-error@+2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
+// expected-note@+1 {{'write' clause used here}}
+#pragma omp atomic write update
+ a = b;
+// expected-error@+2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
+// expected-note@+1 {{'write' clause used here}}
+#pragma omp atomic write capture
+ a = b;
+ // expected-note@+1 {{in instantiation of function template specialization 'mixed<int>' requested here}}
+ return mixed<int>();
+}
+
diff --git a/test/OpenMP/barrier_codegen.cpp b/test/OpenMP/barrier_codegen.cpp
new file mode 100644
index 000000000000..2e817c138c3c
--- /dev/null
+++ b/test/OpenMP/barrier_codegen.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[IDENT_T:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[EXPLICIT_BARRIER_LOC:@.+]] = {{.+}} [[IDENT_T]] { i32 0, i32 34, i32 0, i32 0, i8* getelementptr inbounds ([{{[0-9]+}} x i8]* @{{.+}}, i32 0, i32 0) }
+// CHECK-DAG: [[LOC:@.+]] = {{.+}} [[IDENT_T]] { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([{{[0-9]+}} x i8]* @{{.+}}, i32 0, i32 0) }
+
+void foo() {}
+
+template <class T>
+T tmain(T argc) {
+ static T a;
+#pragma omp barrier
+ return a + argc;
+}
+
+// CHECK-LABEL: @main
+int main(int argc, char **argv) {
+ static int a;
+#pragma omp barrier
+ // CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T]]* [[LOC]])
+ // CHECK: call i32 @__kmpc_cancel_barrier([[IDENT_T]]* [[EXPLICIT_BARRIER_LOC]], i32 [[GTID]])
+ // CHECK: call {{.+}} [[TMAIN_INT:@.+]](i{{[0-9][0-9]}}
+ // CHECK: call {{.+}} [[TMAIN_CHAR:@.+]](i{{[0-9]}}
+ return tmain(argc) + tmain(argv[0][0]) + a;
+}
+
+// CHECK: define {{.+}} [[TMAIN_INT]](
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T]]* [[LOC]])
+// CHECK: call i32 @__kmpc_cancel_barrier([[IDENT_T]]* [[EXPLICIT_BARRIER_LOC]], i32 [[GTID]])
+
+// CHECK: define {{.+}} [[TMAIN_CHAR]](
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T]]* [[LOC]])
+// CHECK: call i32 @__kmpc_cancel_barrier([[IDENT_T]]* [[EXPLICIT_BARRIER_LOC]], i32 [[GTID]])
+
+#endif
diff --git a/test/OpenMP/critical_codegen.cpp b/test/OpenMP/critical_codegen.cpp
new file mode 100644
index 000000000000..dda532ca369b
--- /dev/null
+++ b/test/OpenMP/critical_codegen.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK: [[UNNAMED_LOCK:@.+]] = common global [8 x i32] zeroinitializer
+// CHECK: [[THE_NAME_LOCK:@.+]] = common global [8 x i32] zeroinitializer
+
+// CHECK: define void [[FOO:@.+]]()
+
+void foo() {}
+
+// CHECK-LABEL: @main
+int main() {
+// CHECK: [[A_ADDR:%.+]] = alloca i8
+ char a;
+
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
+// CHECK: call void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[UNNAMED_LOCK]])
+// CHECK-NEXT: store i8 2, i8* [[A_ADDR]]
+// CHECK-NEXT: call void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[UNNAMED_LOCK]])
+#pragma omp critical
+ a = 2;
+// CHECK: call void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]])
+// CHECK-NEXT: call void [[FOO]]()
+// CHECK-NEXT: call void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]])
+#pragma omp critical(the_name)
+ foo();
+// CHECK-NOT: call void @__kmpc_critical
+// CHECK-NOT: call void @__kmpc_end_critical
+ return a;
+}
+
+#endif
diff --git a/test/OpenMP/flush_codegen.cpp b/test/OpenMP/flush_codegen.cpp
new file mode 100644
index 000000000000..eb9c721e3508
--- /dev/null
+++ b/test/OpenMP/flush_codegen.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+template <class T>
+T tmain(T argc) {
+ static T a;
+#pragma omp flush
+#pragma omp flush(a)
+ return a + argc;
+}
+
+// CHECK-LABEL: @main
+int main() {
+ static int a;
+#pragma omp flush
+#pragma omp flush(a)
+ // CHECK: call void (%{{.+}}*, ...)* @__kmpc_flush(%{{.+}}* {{(@|%).+}}, i32 0)
+ // CHECK: call void (%{{.+}}*, ...)* @__kmpc_flush(%{{.+}}* {{(@|%).+}}, i32 0)
+ return tmain(a);
+ // CHECK: call {{.*}} [[TMAIN:@.+]](
+ // CHECK: ret
+}
+
+// CHECK: [[TMAIN]]
+// CHECK: call void (%{{.+}}*, ...)* @__kmpc_flush(%{{.+}}* {{(@|%).+}}, i32 0)
+// CHECK: call void (%{{.+}}*, ...)* @__kmpc_flush(%{{.+}}* {{(@|%).+}}, i32 0)
+// CHECK: ret
+
+#endif
diff --git a/test/OpenMP/for_codegen.cpp b/test/OpenMP/for_codegen.cpp
new file mode 100644
index 000000000000..757de65df46a
--- /dev/null
+++ b/test/OpenMP/for_codegen.cpp
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+//
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK-LABEL: define {{.*void}} @{{.*}}without_schedule_clause{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void without_schedule_clause(float *a, float *b, float *c, float *d) {
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]])
+ #pragma omp for
+// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
+// UB = min(UB, GlobalUB)
+// CHECK-NEXT: [[UB:%.+]] = load i32* [[OMP_UB]]
+// CHECK-NEXT: [[UBCMP:%.+]] = icmp sgt i32 [[UB]], 4571423
+// CHECK-NEXT: br i1 [[UBCMP]], label [[UB_TRUE:%[^,]+]], label [[UB_FALSE:%[^,]+]]
+// CHECK: [[UBRESULT:%.+]] = phi i32 [ 4571423, [[UB_TRUE]] ], [ [[UBVAL:%[^,]+]], [[UB_FALSE]] ]
+// CHECK-NEXT: store i32 [[UBRESULT]], i32* [[OMP_UB]]
+// CHECK-NEXT: [[LB:%.+]] = load i32* [[OMP_LB]]
+// CHECK-NEXT: store i32 [[LB]], i32* [[OMP_IV:[^,]+]]
+// Loop header
+// CHECK: [[IV:%.+]] = load i32* [[OMP_IV]]
+// CHECK-NEXT: [[UB:%.+]] = load i32* [[OMP_UB]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
+ for (int i = 33; i < 32000000; i += 7) {
+// CHECK: [[LOOP1_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV1_1:%.+]] = load i32* [[OMP_IV]]
+// CHECK-NEXT: [[CALC_I_1:%.+]] = mul nsw i32 [[IV1_1]], 7
+// CHECK-NEXT: [[CALC_I_2:%.+]] = add nsw i32 33, [[CALC_I_1]]
+// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
+ a[i] = b[i] * c[i] * d[i];
+// CHECK: [[IV1_2:%.+]] = load i32* [[OMP_IV]]{{.*}}
+// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1
+// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]
+// CHECK-NEXT: br label %{{.+}}
+ }
+// CHECK: [[LOOP1_END]]
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: ret void
+}
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}static_not_chunked{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void static_not_chunked(float *a, float *b, float *c, float *d) {
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]])
+ #pragma omp for schedule(static)
+// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
+// UB = min(UB, GlobalUB)
+// CHECK-NEXT: [[UB:%.+]] = load i32* [[OMP_UB]]
+// CHECK-NEXT: [[UBCMP:%.+]] = icmp sgt i32 [[UB]], 4571423
+// CHECK-NEXT: br i1 [[UBCMP]], label [[UB_TRUE:%[^,]+]], label [[UB_FALSE:%[^,]+]]
+// CHECK: [[UBRESULT:%.+]] = phi i32 [ 4571423, [[UB_TRUE]] ], [ [[UBVAL:%[^,]+]], [[UB_FALSE]] ]
+// CHECK-NEXT: store i32 [[UBRESULT]], i32* [[OMP_UB]]
+// CHECK-NEXT: [[LB:%.+]] = load i32* [[OMP_LB]]
+// CHECK-NEXT: store i32 [[LB]], i32* [[OMP_IV:[^,]+]]
+// Loop header
+// CHECK: [[IV:%.+]] = load i32* [[OMP_IV]]
+// CHECK-NEXT: [[UB:%.+]] = load i32* [[OMP_UB]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
+ for (int i = 32000000; i > 33; i += -7) {
+// CHECK: [[LOOP1_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV1_1:%.+]] = load i32* [[OMP_IV]]
+// CHECK-NEXT: [[CALC_I_1:%.+]] = mul nsw i32 [[IV1_1]], 7
+// CHECK-NEXT: [[CALC_I_2:%.+]] = sub nsw i32 32000000, [[CALC_I_1]]
+// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
+ a[i] = b[i] * c[i] * d[i];
+// CHECK: [[IV1_2:%.+]] = load i32* [[OMP_IV]]{{.*}}
+// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1
+// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]
+// CHECK-NEXT: br label %{{.+}}
+ }
+// CHECK: [[LOOP1_END]]
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: ret void
+}
+
+#endif // HEADER
+
diff --git a/test/OpenMP/for_firstprivate_messages.cpp b/test/OpenMP/for_firstprivate_messages.cpp
index f1d21b8ce5af..6aa977b65d92 100644
--- a/test/OpenMP/for_firstprivate_messages.cpp
+++ b/test/OpenMP/for_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
public:
S2() : a(0) {}
- S2(S2 &s2) : a(s2.a) {}
+ S2(const S2 &s2) : a(s2.a) {}
static float S2s;
static const float S2sc;
};
@@ -26,23 +26,23 @@ class S3 {
S3 &operator=(const S3 &s3);
public:
- S3() : a(0) {}
- S3(S3 &s3) : a(s3.a) {}
+ S3() : a(0) {} // expected-note {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
+ S3(S3 &s3) : a(s3.a) {} // expected-note {{candidate constructor not viable: 1st argument ('const S3') would lose const qualifier}}
};
const S3 c;
const S3 ca[5];
extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4(const S4 &s4);
+ S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
int a;
- S5(const S5 &s5) : a(s5.a) {}
+ S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
public:
S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- C g(5); // expected-note 2 {{'g' defined here}}
+ I e(4);
+ C g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel
@@ -107,7 +107,7 @@ int foomain(int argc, char **argv) {
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel
-#pragma omp for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel
@@ -138,7 +138,7 @@ int foomain(int argc, char **argv) {
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel
-#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel private(i) // expected-note {{defined as private}}
@@ -155,8 +155,8 @@ int foomain(int argc, char **argv) {
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note 2 {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
S3 m;
S6 n(2);
int i;
@@ -194,7 +194,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+#pragma omp for firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} expected-error {{no matching constructor for initialization of 'const S3'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
@@ -235,7 +235,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
@@ -263,7 +263,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
@@ -291,3 +291,4 @@ int main(int argc, char **argv) {
return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
}
+
diff --git a/test/OpenMP/for_loop_messages.cpp b/test/OpenMP/for_loop_messages.cpp
index 8cc882e13a9f..cb32484e43fb 100644
--- a/test/OpenMP/for_loop_messages.cpp
+++ b/test/OpenMP/for_loop_messages.cpp
@@ -11,6 +11,7 @@ public:
static int sii;
#pragma omp threadprivate(sii) // expected-note {{defined as threadprivate or thread local}}
+static int globalii;
int test_iteration_spaces() {
const int N = 100;
@@ -311,6 +312,23 @@ int test_iteration_spaces() {
}
#pragma omp parallel
+ {
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp for' directive may not be a variable with global storage without being explicitly marked as private}}
+#pragma omp for
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] = a[globalii];
+ }
+
+#pragma omp parallel
+ {
+// expected-error@+3 {{loop iteration variable in the associated loop of 'omp for' directive may not be a variable with global storage without being explicitly marked as private}}
+#pragma omp for collapse(2)
+ for (ii = 0; ii < 10; ii += 1)
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] += a[globalii] + ii;
+ }
+
+#pragma omp parallel
// expected-error@+2 {{statement after '#pragma omp for' must be a for loop}}
#pragma omp for
for (auto &item : a) {
@@ -360,6 +378,8 @@ public:
Iter0 operator--() { return *this; }
bool operator<(Iter0 a) { return true; }
};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'Iter0' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'Iter0' for 1st argument}}
int operator-(Iter0 a, Iter0 b) { return 0; }
class Iter1 {
public:
@@ -378,6 +398,7 @@ public:
GoodIter &operator=(const GoodIter &that) { return *this; }
GoodIter &operator=(const Iter0 &that) { return *this; }
GoodIter &operator+=(int x) { return *this; }
+ GoodIter &operator-=(int x) { return *this; }
explicit GoodIter(void *) {}
GoodIter operator++() { return *this; }
GoodIter operator--() { return *this; }
@@ -388,11 +409,20 @@ public:
typedef int difference_type;
typedef std::random_access_iterator_tag iterator_category;
};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'const Iter0' to 'GoodIter' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
int operator-(GoodIter a, GoodIter b) { return 0; }
+// expected-note@+1 3 {{candidate function not viable: requires single argument 'a', but 2 arguments were provided}}
GoodIter operator-(GoodIter a) { return a; }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'const Iter0' to 'int' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
GoodIter operator-(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'GoodIter' for 1st argument}}
GoodIter operator+(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'int' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'int' for 1st argument}}
GoodIter operator-(int v, GoodIter a) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'int' for 1st argument}}
GoodIter operator+(int v, GoodIter a) { return GoodIter(); }
int test_with_random_access_iterator() {
@@ -435,6 +465,8 @@ int test_with_random_access_iterator() {
#pragma omp for
for (begin = GoodIter(0); begin < end; ++begin)
++begin;
+// expected-error@+4 {{invalid operands to binary expression ('GoodIter' and 'const Iter0')}}
+// expected-error@+3 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
#pragma omp parallel
#pragma omp for
for (begin = begin0; begin < end; ++begin)
@@ -489,17 +521,22 @@ int test_with_random_access_iterator() {
#pragma omp for
for (GoodIter I = begin; I >= end; I = 2 - I)
++I;
+// In the following example, we cannot update the loop variable using '+='
+// expected-error@+3 {{invalid operands to binary expression ('Iter0' and 'int')}}
#pragma omp parallel
#pragma omp for
for (Iter0 I = begin0; I < end0; ++I)
++I;
#pragma omp parallel
// Initializer is constructor without params.
+// expected-error@+3 {{invalid operands to binary expression ('Iter0' and 'int')}}
// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
#pragma omp for
for (Iter0 I; I < end0; ++I)
++I;
Iter1 begin1, end1;
+// expected-error@+4 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+// expected-error@+3 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
#pragma omp parallel
#pragma omp for
for (Iter1 I = begin1; I < end1; ++I)
@@ -511,6 +548,8 @@ int test_with_random_access_iterator() {
for (Iter1 I = begin1; I >= end1; ++I)
++I;
#pragma omp parallel
+// expected-error@+5 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+// expected-error@+4 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
// Initializer is constructor with all default params.
// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
#pragma omp for
diff --git a/test/OpenMP/for_misc_messages.c b/test/OpenMP/for_misc_messages.c
index 854898c04432..8a721807d8dc 100644
--- a/test/OpenMP/for_misc_messages.c
+++ b/test/OpenMP/for_misc_messages.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -triple x86_64-unknown-unknown -verify %s
// expected-error@+1 {{unexpected OpenMP directive '#pragma omp for'}}
#pragma omp for
@@ -190,6 +190,16 @@ void test_collapse() {
#pragma omp for collapse(5 - 5)
for (i = 0; i < 16; ++i)
;
+#pragma omp parallel
+#pragma omp for collapse(2)
+ for (i = 0; i < 16; ++i)
+// expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}}
+ for (int j = 0; j < 16; ++j)
+// expected-error@+2 {{private variable cannot be reduction}}
+// expected-error@+1 {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp for' directive into a parallel region?}}
+#pragma omp for reduction(+ : i, j)
+ for (int k = 0; k < 16; ++k)
+ i += j;
}
void test_private() {
@@ -359,5 +369,11 @@ void test_loop_messages() {
for (double fi = 0; fi < 10.0; fi++) {
c[(int)fi] = a[(int)fi] + b[(int)fi];
}
+
+ // expected-warning@+2 {{OpenMP loop iteration variable cannot have more than 64 bits size and will be narrowed}}
+ #pragma omp for
+ for (__int128 ii = 0; ii < 10; ii++) {
+ c[ii] = a[ii] + b[ii];
+ }
}
diff --git a/test/OpenMP/for_private_messages.cpp b/test/OpenMP/for_private_messages.cpp
index f7a497930d01..45c8683cfa8e 100644
--- a/test/OpenMP/for_private_messages.cpp
+++ b/test/OpenMP/for_private_messages.cpp
@@ -24,16 +24,16 @@ public:
S3() : a(0) {}
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -109,8 +109,8 @@ int foomain(I argc, C **argv) {
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp for private // expected-error {{expected '(' after 'private'}}
@@ -143,7 +143,7 @@ int main(int argc, char **argv) {
#pragma omp for private(argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp for private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp for private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp for private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
diff --git a/test/OpenMP/for_simd_aligned_messages.cpp b/test/OpenMP/for_simd_aligned_messages.cpp
new file mode 100644
index 000000000000..70131d5e5a35
--- /dev/null
+++ b/test/OpenMP/for_simd_aligned_messages.cpp
@@ -0,0 +1,202 @@
+// RUN: %clang_cc1 -x c++ -std=c++11 -verify -fopenmp=libiomp5 %s
+
+struct B {
+ static int ib[20]; // expected-note 0 {{'B::ib' declared here}}
+ static constexpr int bfoo() { return 8; }
+};
+namespace X {
+ B x; // expected-note {{'x' defined here}}
+};
+constexpr int bfoo() { return 4; }
+
+int **z;
+const int C1 = 1;
+const int C2 = 2;
+void test_aligned_colons(int *&rp)
+{
+ int *B = 0;
+ #pragma omp for simd aligned(B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'}}
+ #pragma omp for simd aligned(B::ib:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp for simd aligned(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'?}}
+ #pragma omp for simd aligned(z:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp for simd aligned(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+2 {{integral constant expression must have integral or unscoped enumeration type, not 'int **'}}
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'B'}}
+ #pragma omp for simd aligned(X::x : ::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'B'}}
+ #pragma omp for simd aligned(B,rp,::z: X::x)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp for simd aligned(::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp for simd aligned(B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-warning@+1 {{aligned clause will be ignored because the requested alignment is not a power of 2}}
+ #pragma omp for simd aligned(B::ib,B:C1+C2)
+ for (int i = 0; i < 10; ++i) ;
+}
+
+// expected-note@+1 {{'num' defined here}}
+template<int L, class T, class N> T test_template(T* arr, N num) {
+ N i;
+ T sum = (T)0;
+ T ind2 = - num * L;
+ // Negative number is passed as L.
+ // expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
+ #pragma omp for simd aligned(arr:L)
+ for (i = 0; i < num; ++i) {
+ T cur = arr[(int)ind2];
+ ind2 += L;
+ sum += cur;
+ }
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp for simd aligned(num:4)
+ for (i = 0; i < num; ++i);
+ return T();
+}
+
+template<int LEN> int test_warn() {
+ int *ind2 = 0;
+ // expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
+ #pragma omp for simd aligned(ind2:LEN)
+ for (int i = 0; i < 100; i++) {
+ ind2 += LEN;
+ }
+ return 0;
+}
+
+struct S1; // expected-note 2 {{declared here}}
+extern S1 a; // expected-note {{'a' declared here}}
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+};
+const S2 b; // expected-note 1 {{'b' defined here}}
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4();
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h; // expected-note 2 {{'h' defined here}}
+#pragma omp threadprivate(h)
+
+template<class I, class C> int foomain(I argc, C **argv) {
+ I e(argc);
+ I g(argc);
+ int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
+ // expected-note@+2 {{declared here}}
+ // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int &j = i;
+ #pragma omp for simd aligned // expected-error {{expected '(' after 'aligned'}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned () // expected-error {{expected expression}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned (argc : 5) // expected-warning {{aligned clause will be ignored because the requested alignment is not a power of 2}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned (S1) // expected-error {{'S1' does not refer to a value}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned (argv[1]) // expected-error {{expected variable name}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned(e, g)
+ for (I k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S3'}}
+ #pragma omp for simd aligned(h)
+ for (I k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp for simd aligned(i)
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int *v = 0;
+ I i;
+ #pragma omp for simd aligned(v:16)
+ for (I k = 0; k < argc; ++k) { i = k; v += 2; }
+ }
+ float *f;
+ #pragma omp for simd aligned(f)
+ for (I k = 0; k < argc; ++k) ++k;
+ int v = 0;
+ // expected-note@+2 {{initializer of 'j' is not a constant expression}}
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp for simd aligned(f:j)
+ for (I k = 0; k < argc; ++k) { ++k; v += j; }
+ #pragma omp for simd aligned(f)
+ for (I k = 0; k < argc; ++k) ++k;
+ return 0;
+}
+
+// expected-note@+1 2 {{'argc' defined here}}
+int main(int argc, char **argv) {
+ double darr[100];
+ // expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
+ test_template<-4>(darr, 4);
+ test_warn<4>(); // ok
+ // expected-note@+1 {{in instantiation of function template specialization 'test_warn<0>' requested here}}
+ test_warn<0>();
+
+ int i;
+ int &j = i;
+ #pragma omp for simd aligned // expected-error {{expected '(' after 'aligned'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned (argv // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp for simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp for simd aligned (argc)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S1'}}
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S2'}}
+ #pragma omp for simd aligned (a, b)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd aligned (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S3'}}
+ #pragma omp for simd aligned(h)
+ for (int k = 0; k < argc; ++k) ++k;
+ int *pargc = &argc;
+ foomain<int*,char>(pargc,argv);
+ return 0;
+}
+
diff --git a/test/OpenMP/for_simd_ast_print.cpp b/test/OpenMP/for_simd_ast_print.cpp
new file mode 100644
index 000000000000..759706424692
--- /dev/null
+++ b/test/OpenMP/for_simd_ast_print.cpp
@@ -0,0 +1,128 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void foo() {}
+int g_ind = 1;
+template<class T, class N> T reduct(T* arr, N num) {
+ N i;
+ N ind;
+ N myind;
+ T sum = (T)0;
+// CHECK: T sum = (T)0;
+#pragma omp for simd private(myind, g_ind), linear(ind), aligned(arr)
+// CHECK-NEXT: #pragma omp for simd private(myind,g_ind) linear(ind) aligned(arr)
+ for (i = 0; i < num; ++i) {
+ myind = ind;
+ T cur = arr[myind];
+ ind += g_ind;
+ sum += cur;
+ }
+}
+
+template<class T> struct S {
+ S(const T &a)
+ :m_a(a)
+ {}
+ T result(T *v) const {
+ T res;
+ T val;
+ T lin = 0;
+// CHECK: T res;
+// CHECK: T val;
+// CHECK: T lin = 0;
+ #pragma omp for simd private(val) safelen(7) linear(lin : -5) lastprivate(res)
+// CHECK-NEXT: #pragma omp for simd private(val) safelen(7) linear(lin: -5) lastprivate(res)
+ for (T i = 7; i < m_a; ++i) {
+ val = v[i-7] + m_a;
+ res = val;
+ lin -= 5;
+ }
+ const T clen = 3;
+// CHECK: T clen = 3;
+ #pragma omp for simd safelen(clen-1)
+// CHECK-NEXT: #pragma omp for simd safelen(clen - 1)
+ for(T i = clen+2; i < 20; ++i) {
+// CHECK-NEXT: for (T i = clen + 2; i < 20; ++i) {
+ v[i] = v[v-clen] + 1;
+// CHECK-NEXT: v[i] = v[v - clen] + 1;
+ }
+// CHECK-NEXT: }
+ return res;
+ }
+ ~S()
+ {}
+ T m_a;
+};
+
+template<int LEN> struct S2 {
+ static void func(int n, float *a, float *b, float *c) {
+ int k1 = 0, k2 = 0;
+#pragma omp for simd safelen(LEN) linear(k1,k2:LEN) aligned(a:LEN)
+ for(int i = 0; i < n; i++) {
+ c[i] = a[i] + b[i];
+ c[k1] = a[k1] + b[k1];
+ c[k2] = a[k2] + b[k2];
+ k1 = k1 + LEN;
+ k2 = k2 + LEN;
+ }
+ }
+};
+
+// S2<4>::func is called below in main.
+// CHECK: template <int LEN = 4> struct S2 {
+// CHECK-NEXT: static void func(int n, float *a, float *b, float *c) {
+// CHECK-NEXT: int k1 = 0, k2 = 0;
+// CHECK-NEXT: #pragma omp for simd safelen(4) linear(k1,k2: 4) aligned(a: 4)
+// CHECK-NEXT: for (int i = 0; i < n; i++) {
+// CHECK-NEXT: c[i] = a[i] + b[i];
+// CHECK-NEXT: c[k1] = a[k1] + b[k1];
+// CHECK-NEXT: c[k2] = a[k2] + b[k2];
+// CHECK-NEXT: k1 = k1 + 4;
+// CHECK-NEXT: k2 = k2 + 4;
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+
+int main (int argc, char **argv) {
+ int b = argc, c, d, e, f, g;
+ int k1=0,k2=0;
+ static int *a;
+// CHECK: static int *a;
+#pragma omp for simd
+// CHECK-NEXT: #pragma omp for simd
+ for (int i=0; i < 2; ++i)*a=2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: *a = 2;
+#pragma omp parallel
+#pragma omp for simd private(argc, b),lastprivate(d,f) collapse(2) aligned(a : 4) ,firstprivate( g )
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;}
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: #pragma omp for simd private(argc,b) lastprivate(d,f) collapse(2) aligned(a: 4) firstprivate(g)
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: for (int j = 0; j < 10; ++j) {
+// CHECK-NEXT: foo();
+// CHECK-NEXT: k1 += 8;
+// CHECK-NEXT: k2 += 8;
+// CHECK-NEXT: }
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+ const int CLEN = 4;
+// CHECK-NEXT: const int CLEN = 4;
+ #pragma omp for simd aligned(a:CLEN) linear(a:CLEN) safelen(CLEN) collapse( 1 )
+// CHECK-NEXT: #pragma omp for simd aligned(a: CLEN) linear(a: CLEN) safelen(CLEN) collapse(1)
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+
+ float arr[16];
+ S2<4>::func(0,arr,arr,arr);
+ return (0);
+}
+
+#endif
diff --git a/test/OpenMP/for_simd_collapse_messages.cpp b/test/OpenMP/for_simd_collapse_messages.cpp
new file mode 100644
index 000000000000..3b43f1f5d29e
--- /dev/null
+++ b/test/OpenMP/for_simd_collapse_messages.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
+ #pragma omp for simd collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd collapse () // expected-error {{expected expression}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+ // expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ #pragma omp for simd collapse (argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp for simd collapse (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp for simd', but found only 1}}
+ // expected-error@+3 2 {{directive '#pragma omp for simd' cannot contain more than one 'collapse' clause}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp for simd collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd collapse (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp for simd collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd collapse (1)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd collapse (N) // expected-error {{argument to 'collapse' clause must be a positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd collapse (2) // expected-note {{as specified in 'collapse' clause}}
+ foo(); // expected-error {{expected 2 for loops after '#pragma omp for simd'}}
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp for simd collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd collapse () // expected-error {{expected expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd collapse (4 // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{as specified in 'collapse' clause}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp for simd', but found only 1}}
+ #pragma omp for simd collapse (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}} expected-note {{as specified in 'collapse' clause}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp for simd', but found only 1}}
+ #pragma omp for simd collapse (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{expression is not an integral constant expression}}
+ // expected-error@+2 2 {{directive '#pragma omp for simd' cannot contain more than one 'collapse' clause}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp for simd collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd collapse (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp for simd collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp for simd' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp for simd collapse(collapse(tmain<int, char, -1, -2>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ foo();
+ #pragma omp for simd collapse (2) // expected-note {{as specified in 'collapse' clause}}
+ foo(); // expected-error {{expected 2 for loops after '#pragma omp for simd'}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
+ return tmain<int, char, 1, 0>(argc, argv);
+}
+
diff --git a/test/OpenMP/for_simd_firstprivate_messages.cpp b/test/OpenMP/for_simd_firstprivate_messages.cpp
new file mode 100644
index 000000000000..1345bfc9886a
--- /dev/null
+++ b/test/OpenMP/for_simd_firstprivate_messages.cpp
@@ -0,0 +1,293 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2(const S2 &s2) : a(s2.a) {}
+ static float S2s;
+ static const float S2sc;
+};
+const float S2::S2sc = 0;
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+ S3 &operator=(const S3 &s3);
+
+public:
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 {
+ int a;
+ S4();
+ S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
+
+public:
+ S5() : a(0) {}
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+ S6() : a(0) {}
+
+public:
+ S6(const S6 &s6) : a(s6.a) {}
+ S6(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(int argc, char **argv) {
+ I e(4);
+ C g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp parallel
+#pragma omp for simd firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate(a, b) // expected-error {{a firstprivate variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd linear(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for simd' directive into a parallel or another task region?}}
+#pragma omp for simd firstprivate(i) // expected-error {{private variable cannot be firstprivate}}
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp for simd firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd firstprivate(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel private(i) // expected-note {{defined as private}}
+#pragma omp for simd firstprivate(i) // expected-error {{firstprivate variable must be shared}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel reduction(+ : i) // expected-note {{defined as reduction}}
+#pragma omp for simd firstprivate(i) // expected-error {{firstprivate variable must be shared}}
+ for (i = 0; i < argc; ++i)
+ foo();
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5;
+ const int da[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ S3 m;
+ S6 n(2);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp parallel
+#pragma omp for simd firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate() // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(argc)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(2 * 2) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(ba) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(ca) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(da) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+ int xa;
+#pragma omp parallel
+#pragma omp for simd firstprivate(xa) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(S2::S2s) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(S2::S2sc) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd safelen(5)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(m) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd private(xa), firstprivate(xa) // expected-error {{private variable cannot be firstprivate}} expected-note {{defined as private}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp for simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel shared(xa)
+#pragma omp for simd firstprivate(xa) // OK: may be firstprivate
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(n) firstprivate(n) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+ {
+ int v = 0;
+ int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for simd' directive into a parallel or another task region?}}
+#pragma omp for simd firstprivate(i) // expected-error {{private variable cannot be firstprivate}}
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel private(i) // expected-note {{defined as private}}
+#pragma omp for simd firstprivate(i) // expected-error {{firstprivate variable must be shared}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel reduction(+ : i) // expected-note {{defined as reduction}}
+#pragma omp for simd firstprivate(i) // expected-error {{firstprivate variable must be shared}}
+ for (i = 0; i < argc; ++i)
+ foo();
+
+ return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
+}
diff --git a/test/OpenMP/for_simd_lastprivate_messages.cpp b/test/OpenMP/for_simd_lastprivate_messages.cpp
new file mode 100644
index 000000000000..38651e5c8e27
--- /dev/null
+++ b/test/OpenMP/for_simd_lastprivate_messages.cpp
@@ -0,0 +1,266 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
+ static const float S2sc;
+};
+const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const S2 b;
+const S2 ba[5];
+class S3 { // expected-note 2 {{'S3' declared here}}
+ int a;
+ S3 &operator=(const S3 &s3);
+
+public:
+ S3() : a(0) {}
+ S3(S3 &s3) : a(s3.a) {}
+};
+const S3 c; // expected-note {{global variable is predetermined as shared}}
+const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
+extern const int f; // expected-note {{global variable is predetermined as shared}}
+class S4 { // expected-note 3 {{'S4' declared here}}
+ int a;
+ S4();
+ S4(const S4 &s4);
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 { // expected-note {{'S5' declared here}}
+ int a;
+ S5() : a(0) {}
+
+public:
+ S5(const S5 &s5) : a(s5.a) {}
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+ S6() : a(0) {}
+
+public:
+ S6(const S6 &s6) : a(s6.a) {}
+ S6(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(int argc, char **argv) {
+ I e(4); // expected-note {{'e' defined here}}
+ I g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp parallel
+#pragma omp for simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(a, b) // expected-error {{lastprivate variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for simd' directive into a parallel or another task region?}}
+#pragma omp for simd lastprivate(i) // expected-error {{lastprivate variable must be shared}}
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp for simd lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp for simd lastprivate(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note {{constant variable is predetermined as shared}}
+ const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ S3 m; // expected-note 2 {{'m' defined here}}
+ S6 n(2);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp parallel
+#pragma omp for simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate() // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(argc)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(2 * 2) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(ba)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(da) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+ int xa;
+#pragma omp parallel
+#pragma omp for simd lastprivate(xa) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd private(xa), lastprivate(xa) // expected-error {{private variable cannot be lastprivate}} expected-note {{defined as private}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(i) // expected-note {{defined as lastprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp for simd' directive may not be lastprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel private(xa) // expected-note {{defined as private}}
+#pragma omp for simd lastprivate(xa) // expected-error {{lastprivate variable must be shared}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel reduction(+ : xa) // expected-note {{defined as reduction}}
+#pragma omp for simd lastprivate(xa) // expected-error {{lastprivate variable must be shared}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd firstprivate(m) lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd lastprivate(n) firstprivate(n) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+ return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
+}
diff --git a/test/OpenMP/for_simd_linear_messages.cpp b/test/OpenMP/for_simd_linear_messages.cpp
new file mode 100644
index 000000000000..9a935c3fdf28
--- /dev/null
+++ b/test/OpenMP/for_simd_linear_messages.cpp
@@ -0,0 +1,206 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+namespace X {
+ int x;
+};
+
+struct B {
+ static int ib; // expected-note {{'B::ib' declared here}}
+ static int bfoo() { return 8; }
+};
+
+int bfoo() { return 4; }
+
+int z;
+const int C1 = 1;
+const int C2 = 2;
+void test_linear_colons()
+{
+ int B = 0;
+ #pragma omp for simd linear(B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'}}
+ #pragma omp for simd linear(B::ib:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{use of undeclared identifier 'ib'; did you mean 'B::ib'}}
+ #pragma omp for simd linear(B:ib)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'?}}
+ #pragma omp for simd linear(z:B:ib)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp for simd linear(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp for simd linear(X::x : ::z)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp for simd linear(B,::z, X::x)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp for simd linear(::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp for simd linear(B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp for simd linear(B::ib,B:C1+C2)
+ for (int i = 0; i < 10; ++i) ;
+}
+
+template<int L, class T, class N> T test_template(T* arr, N num) {
+ N i;
+ T sum = (T)0;
+ T ind2 = - num * L; // expected-note {{'ind2' defined here}}
+ // expected-error@+1 {{argument of a linear clause should be of integral or pointer type}}
+#pragma omp for simd linear(ind2:L)
+ for (i = 0; i < num; ++i) {
+ T cur = arr[(int)ind2];
+ ind2 += L;
+ sum += cur;
+ }
+ return T();
+}
+
+template<int LEN> int test_warn() {
+ int ind2 = 0;
+ // expected-warning@+1 {{zero linear step (ind2 should probably be const)}}
+ #pragma omp for simd linear(ind2:LEN)
+ for (int i = 0; i < 100; i++) {
+ ind2 += LEN;
+ }
+ return ind2;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+};
+const S2 b; // expected-note 2 {{'b' defined here}}
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4();
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template<class I, class C> int foomain(I argc, C **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp for simd linear // expected-error {{expected '(' after 'linear'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (argc : 5)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{linear variable with incomplete type 'S1'}}
+ // expected-error@+1 {{const-qualified variable cannot be linear}}
+ #pragma omp for simd linear (a, b:B::ib)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear(e, g)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int v = 0;
+ int i;
+ #pragma omp for simd linear(v:i)
+ for (int k = 0; k < argc; ++k) { i = k; v += i; }
+ }
+ #pragma omp for simd linear(j) // expected-error {{arguments of OpenMP clause 'linear' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k) ++k;
+ int v = 0;
+ #pragma omp for simd linear(v:j)
+ for (int k = 0; k < argc; ++k) { ++k; v += j; }
+ #pragma omp for simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ double darr[100];
+ // expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
+ test_template<-4>(darr, 4);
+ // expected-note@+1 {{in instantiation of function template specialization 'test_warn<0>' requested here}}
+ test_warn<0>();
+
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp for simd linear // expected-error {{expected '(' after 'linear'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (argc)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{linear variable with incomplete type 'S1'}}
+ // expected-error@+1 {{const-qualified variable cannot be linear}}
+ #pragma omp for simd linear (a, b)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{argument of a linear clause should be of integral or pointer type, not 'S4'}}
+ // expected-error@+1 {{argument of a linear clause should be of integral or pointer type, not 'S5'}}
+ #pragma omp for simd linear(e, g)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int i;
+ #pragma omp for simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear(i : 4)
+ for (int k = 0; k < argc; ++k) { ++k; i += 4; }
+ }
+ #pragma omp for simd linear(j) // expected-error {{arguments of OpenMP clause 'linear' cannot be of reference type 'int &'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+
+ foomain<int,char>(argc,argv);
+ return 0;
+}
+
diff --git a/test/OpenMP/for_simd_loop_messages.cpp b/test/OpenMP/for_simd_loop_messages.cpp
new file mode 100644
index 000000000000..403709f3453e
--- /dev/null
+++ b/test/OpenMP/for_simd_loop_messages.cpp
@@ -0,0 +1,734 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -x c++ -std=c++11 -fexceptions -fcxx-exceptions -verify %s
+
+class S {
+ int a;
+ S() : a(0) {}
+
+public:
+ S(int v) : a(v) {}
+ S(const S &s) : a(s.a) {}
+};
+
+static int sii;
+#pragma omp threadprivate(sii) // expected-note {{defined as threadprivate or thread local}}
+static int globalii;
+
+int test_iteration_spaces() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+ int ii, jj, kk;
+ float fii;
+ double dii;
+#pragma omp parallel
+#pragma omp for simd
+ for (int i = 0; i < 10; i += 1) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp for simd
+ for (char i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp for simd
+ for (char i = 0; i < 10; i += '\1') {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp for simd
+ for (long long i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+// expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'double'}}
+#pragma omp for simd
+ for (long long i = 0; i < 10; i += 1.5) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp for simd
+ for (long long i = 0; i < 'z'; i += 1u) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp for simd
+ for (float fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp for simd
+ for (double fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp for simd
+ for (int &ref = ii; ref < 10; ref++) {
+ }
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp for simd
+ for (int i; i < 10; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp for simd
+ for (int i = 0, j = 0; i < 10; ++i)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp for simd
+ for (; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-warning@+3 {{expression result unused}}
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp for simd
+ for (ii + 1; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp for simd
+ for (c[ii] = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// Ok to skip parenthesises.
+#pragma omp for simd
+ for (((ii)) = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp for simd
+ for (int i = 0; i; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+3 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'i'}}
+#pragma omp for simd
+ for (int i = 0; jj < kk; ii++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp for simd
+ for (int i = 0; !!i; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp for simd
+ for (int i = 0; i != 1; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp for simd
+ for (int i = 0;; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// Ok.
+#pragma omp for simd
+ for (int i = 11; i > 10; i--)
+ c[i] = a[i];
+
+#pragma omp parallel
+// Ok.
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i)
+ c[i] = a[i];
+
+#pragma omp parallel
+// Ok.
+#pragma omp for simd
+ for (ii = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp for simd
+ for (ii = 0; ii < 10; ++jj)
+ c[ii] = a[jj];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp for simd
+ for (ii = 0; ii < 10; ++++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// Ok but undefined behavior (in general, cannot check that incr
+// is really loop-invariant).
+#pragma omp for simd
+ for (ii = 0; ii < 10; ii = ii + ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'float'}}
+#pragma omp for simd
+ for (ii = 0; ii < 10; ii = ii + 1.0f)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// Ok - step was converted to integer type.
+#pragma omp for simd
+ for (ii = 0; ii < 10; ii = ii + (int)1.1f)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp for simd
+ for (ii = 0; ii < 10; jj = ii + 2)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-warning@+3 {{relational comparison result unused}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp for simd
+ for (ii = 0; ii<10; jj> kk + 2)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp for simd
+ for (ii = 0; ii < 10;)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-warning@+3 {{expression result unused}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp for simd
+ for (ii = 0; ii < 10; !ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp for simd
+ for (ii = 0; ii < 10; ii ? ++ii : ++jj)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp for simd
+ for (ii = 0; ii < 10; ii = ii < 10)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (ii = 0; ii < 10; ii = ii + 0)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (ii = 0; ii < 10; ii = ii + (int)(0.8 - 0.45))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (ii = 0; (ii) < 10; ii -= 25)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (ii = 0; (ii < 10); ii -= 0)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (ii = 0; ii > 10; (ii += 0))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (ii = 0; ii < 10; (ii) = (1 - 1) + (ii))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for ((ii = 0); ii > 10; (ii -= 0))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (ii = 0; (ii < 10); (ii -= 0))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+2 {{defined as firstprivate}}
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp for simd' directive may not be firstprivate, predetermined as linear}}
+#pragma omp for simd firstprivate(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+#pragma omp for simd linear(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+2 {{defined as private}}
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp for simd' directive may not be private, predetermined as linear}}
+#pragma omp for simd private(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+2 {{defined as lastprivate}}
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp for simd' directive may not be lastprivate, predetermined as linear}}
+#pragma omp for simd lastprivate(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+ {
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp for simd' directive may not be threadprivate or thread local, predetermined as linear}}
+#pragma omp for simd
+ for (sii = 0; sii < 10; sii += 1)
+ c[sii] = a[sii];
+ }
+
+#pragma omp parallel
+ {
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp for simd' directive may not be a variable with global storage without being explicitly marked as linear}}
+#pragma omp for simd
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] = a[globalii];
+ }
+
+#pragma omp parallel
+ {
+// expected-error@+3 {{loop iteration variable in the associated loop of 'omp for simd' directive may not be a variable with global storage without being explicitly marked as lastprivate}}
+#pragma omp for simd collapse(2)
+ for (ii = 0; ii < 10; ii += 1)
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] += a[globalii] + ii;
+ }
+
+#pragma omp parallel
+// expected-error@+2 {{statement after '#pragma omp for simd' must be a for loop}}
+#pragma omp for simd
+ for (auto &item : a) {
+ item = item + 1;
+ }
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'i' to increase on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (unsigned i = 9; i < 10; i--) {
+ c[i] = a[i] + b[i];
+ }
+
+ int(*lb)[4] = nullptr;
+#pragma omp parallel
+#pragma omp for simd
+ for (int(*p)[4] = lb; p < lb + 8; ++p) {
+ }
+
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp for simd
+ for (int a{0}; a < 10; ++a) {
+ }
+
+ return 0;
+}
+
+// Iterators allowed in openmp for-loops.
+namespace std {
+struct random_access_iterator_tag {};
+template <class Iter>
+struct iterator_traits {
+ typedef typename Iter::difference_type difference_type;
+ typedef typename Iter::iterator_category iterator_category;
+};
+template <class Iter>
+typename iterator_traits<Iter>::difference_type
+distance(Iter first, Iter last) { return first - last; }
+}
+class Iter0 {
+public:
+ Iter0() {}
+ Iter0(const Iter0 &) {}
+ Iter0 operator++() { return *this; }
+ Iter0 operator--() { return *this; }
+ bool operator<(Iter0 a) { return true; }
+};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'Iter0' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'Iter0' for 1st argument}}
+int operator-(Iter0 a, Iter0 b) { return 0; }
+class Iter1 {
+public:
+ Iter1(float f = 0.0f, double d = 0.0) {}
+ Iter1(const Iter1 &) {}
+ Iter1 operator++() { return *this; }
+ Iter1 operator--() { return *this; }
+ bool operator<(Iter1 a) { return true; }
+ bool operator>=(Iter1 a) { return false; }
+};
+class GoodIter {
+public:
+ GoodIter() {}
+ GoodIter(const GoodIter &) {}
+ GoodIter(int fst, int snd) {}
+ GoodIter &operator=(const GoodIter &that) { return *this; }
+ GoodIter &operator=(const Iter0 &that) { return *this; }
+ GoodIter &operator+=(int x) { return *this; }
+ explicit GoodIter(void *) {}
+ GoodIter operator++() { return *this; }
+ GoodIter operator--() { return *this; }
+ bool operator!() { return true; }
+ bool operator<(GoodIter a) { return true; }
+ bool operator<=(GoodIter a) { return true; }
+ bool operator>=(GoodIter a) { return false; }
+ typedef int difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'const Iter0' to 'GoodIter' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
+int operator-(GoodIter a, GoodIter b) { return 0; }
+// expected-note@+1 3 {{candidate function not viable: requires single argument 'a', but 2 arguments were provided}}
+GoodIter operator-(GoodIter a) { return a; }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'const Iter0' to 'int' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
+GoodIter operator-(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'GoodIter' for 1st argument}}
+GoodIter operator+(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'int' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'int' for 1st argument}}
+GoodIter operator-(int v, GoodIter a) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'int' for 1st argument}}
+GoodIter operator+(int v, GoodIter a) { return GoodIter(); }
+
+int test_with_random_access_iterator() {
+ GoodIter begin, end;
+ Iter0 begin0, end0;
+#pragma omp parallel
+#pragma omp for simd
+ for (GoodIter I = begin; I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp for simd
+ for (GoodIter &I = begin; I < end; ++I)
+ ++I;
+#pragma omp parallel
+#pragma omp for simd
+ for (GoodIter I = begin; I >= end; --I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp for simd
+ for (GoodIter I(begin); I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp for simd
+ for (GoodIter I(nullptr); I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp for simd
+ for (GoodIter I(0); I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp for simd
+ for (GoodIter I(1, 2); I < end; ++I)
+ ++I;
+#pragma omp parallel
+#pragma omp for simd
+ for (begin = GoodIter(0); begin < end; ++begin)
+ ++begin;
+#pragma omp parallel
+// expected-error@+3 {{invalid operands to binary expression ('GoodIter' and 'const Iter0')}}
+// expected-error@+2 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+#pragma omp for simd
+ for (begin = begin0; begin < end; ++begin)
+ ++begin;
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp for simd
+ for (++begin; begin < end; ++begin)
+ ++begin;
+#pragma omp parallel
+#pragma omp for simd
+ for (begin = end; begin < end; ++begin)
+ ++begin;
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp for simd
+ for (GoodIter I = begin; I - I; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp for simd
+ for (GoodIter I = begin; begin < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp for simd
+ for (GoodIter I = begin; !I; ++I)
+ ++I;
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (GoodIter I = begin; I >= end; I = I + 1)
+ ++I;
+#pragma omp parallel
+#pragma omp for simd
+ for (GoodIter I = begin; I >= end; I = I - 1)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+#pragma omp for simd
+ for (GoodIter I = begin; I >= end; I = -I)
+ ++I;
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (GoodIter I = begin; I >= end; I = 2 + I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+#pragma omp for simd
+ for (GoodIter I = begin; I >= end; I = 2 - I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{invalid operands to binary expression ('Iter0' and 'int')}}
+#pragma omp for simd
+ for (Iter0 I = begin0; I < end0; ++I)
+ ++I;
+#pragma omp parallel
+// Initializer is constructor without params.
+// expected-error@+3 {{invalid operands to binary expression ('Iter0' and 'int')}}
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp for simd
+ for (Iter0 I; I < end0; ++I)
+ ++I;
+ Iter1 begin1, end1;
+#pragma omp parallel
+// expected-error@+3 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+// expected-error@+2 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+#pragma omp for simd
+ for (Iter1 I = begin1; I < end1; ++I)
+ ++I;
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (Iter1 I = begin1; I >= end1; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+5 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+// expected-error@+4 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+// Initializer is constructor with all default params.
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp for simd
+ for (Iter1 I; I < end1; ++I) {
+ }
+ return 0;
+}
+
+template <typename IT, int ST>
+class TC {
+public:
+ int dotest_lt(IT begin, IT end) {
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (IT I = begin; I < end; I = I + ST) {
+ ++I;
+ }
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (IT I = begin; I <= end; I += ST) {
+ ++I;
+ }
+#pragma omp parallel
+#pragma omp for simd
+ for (IT I = begin; I < end; ++I) {
+ ++I;
+ }
+ }
+
+ static IT step() {
+ return IT(ST);
+ }
+};
+template <typename IT, int ST = 0>
+int dotest_gt(IT begin, IT end) {
+#pragma omp parallel
+// expected-note@+3 2 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (IT I = begin; I >= end; I = I + ST) {
+ ++I;
+ }
+#pragma omp parallel
+// expected-note@+3 2 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (IT I = begin; I >= end; I += ST) {
+ ++I;
+ }
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp for simd
+ for (IT I = begin; I >= end; ++I) {
+ ++I;
+ }
+
+#pragma omp parallel
+#pragma omp for simd
+ for (IT I = begin; I < end; I += TC<int, ST>::step()) {
+ ++I;
+ }
+}
+
+void test_with_template() {
+ GoodIter begin, end;
+ TC<GoodIter, 100> t1;
+ TC<GoodIter, -100> t2;
+ t1.dotest_lt(begin, end);
+ t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
+ dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
+ dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+}
+
+void test_loop_break() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+#pragma omp parallel
+#pragma omp for simd
+ for (int i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ for (int j = 0; j < 10; ++j) {
+ if (a[i] > b[j])
+ break; // OK in nested loop
+ }
+ switch (i) {
+ case 1:
+ b[i]++;
+ break;
+ default:
+ break;
+ }
+ if (c[i] > 10)
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+
+ if (c[i] > 11)
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+ }
+
+#pragma omp parallel
+#pragma omp for simd
+ for (int i = 0; i < 10; i++) {
+ for (int j = 0; j < 10; j++) {
+ c[i] = a[i] + b[i];
+ if (c[i] > 10) {
+ if (c[i] < 20) {
+ break; // OK
+ }
+ }
+ }
+ }
+}
+
+void test_loop_eh() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+#pragma omp parallel
+#pragma omp for simd
+ for (int i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ try { // expected-error {{'try' statement cannot be used in OpenMP simd region}}
+ for (int j = 0; j < 10; ++j) {
+ if (a[i] > b[j])
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ }
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ }
+ catch (float f) {
+ if (f > 0.1)
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ return; // expected-error {{cannot return from OpenMP region}}
+ }
+ switch (i) {
+ case 1:
+ b[i]++;
+ break;
+ default:
+ break;
+ }
+ for (int j = 0; j < 10; j++) {
+ if (c[i] > 10)
+ throw c[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ }
+ }
+ if (c[9] > 10)
+ throw c[9]; // OK
+
+#pragma omp parallel
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+ struct S {
+ void g() { throw 0; }
+ };
+ }
+}
+
+void test_loop_firstprivate_lastprivate() {
+ S s(4);
+#pragma omp parallel
+#pragma omp for simd lastprivate(s) firstprivate(s)
+ for (int i = 0; i < 16; ++i)
+ ;
+}
+
+void test_ordered() {
+#pragma omp parallel
+// expected-error@+1 2 {{unexpected OpenMP clause 'ordered' in directive '#pragma omp for simd'}}
+#pragma omp for simd ordered ordered // expected-error {{directive '#pragma omp for simd' cannot contain more than one 'ordered' clause}}
+ for (int i = 0; i < 16; ++i)
+ ;
+}
+
+void test_nowait() {
+#pragma omp parallel
+#pragma omp for simd nowait nowait // expected-error {{directive '#pragma omp for simd' cannot contain more than one 'nowait' clause}}
+ for (int i = 0; i < 16; ++i)
+ ;
+}
diff --git a/test/OpenMP/for_simd_misc_messages.c b/test/OpenMP/for_simd_misc_messages.c
new file mode 100644
index 000000000000..870c37df20aa
--- /dev/null
+++ b/test/OpenMP/for_simd_misc_messages.c
@@ -0,0 +1,659 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -verify %s
+
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp for simd'}}
+#pragma omp for simd
+
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp for simd'}}
+#pragma omp for simd foo
+
+void test_no_clause() {
+ int i;
+#pragma omp for simd
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-error@+2 {{statement after '#pragma omp for simd' must be a for loop}}
+#pragma omp for simd
+ ++i;
+}
+
+void test_branch_protected_scope() {
+ int i = 0;
+L1:
+ ++i;
+
+ int x[24];
+
+#pragma omp parallel
+#pragma omp for simd
+ for (i = 0; i < 16; ++i) {
+ if (i == 5)
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ else if (i == 6)
+ return; // expected-error {{cannot return from OpenMP region}}
+ else if (i == 7)
+ goto L2;
+ else if (i == 8) {
+ L2:
+ x[i]++;
+ }
+ }
+
+ if (x[0] == 0)
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+ else if (x[1] == 1)
+ goto L1;
+}
+
+void test_invalid_clause() {
+ int i;
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+#pragma omp for simd foo bar
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_non_identifiers() {
+ int i, x;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+#pragma omp for simd;
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+#pragma omp for simd linear(x);
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+#pragma omp for simd private(x);
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+#pragma omp for simd, private(x);
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+extern int foo();
+void test_safelen() {
+ int i;
+// expected-error@+1 {{expected '('}}
+#pragma omp for simd safelen
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd safelen(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd safelen()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd safelen(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd safelen(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-warning@+2 {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+// expected-error@+1 {{expected '('}}
+#pragma omp for simd safelen 4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp for simd safelen(4
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp for simd safelen(4,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp for simd safelen(4, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp for simd safelen(4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp for simd safelen(4 4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp for simd safelen(4, , 4)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp for simd safelen(4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp for simd safelen(4, 8)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp for simd safelen(2.5)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp for simd safelen(foo())
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+#pragma omp for simd safelen(-5)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+#pragma omp for simd safelen(0)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+#pragma omp for simd safelen(5 - 5)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_collapse() {
+ int i;
+#pragma omp parallel
+// expected-error@+1 {{expected '('}}
+#pragma omp for simd collapse
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd collapse(
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd collapse()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd collapse(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd collapse(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-warning@+2 {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+// expected-error@+1 {{expected '('}}
+#pragma omp for simd collapse 4)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp for simd collapse(4
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp for simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp for simd collapse(4,
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp for simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp for simd collapse(4, )
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp for simd', but found only 1}}
+#pragma omp parallel
+// expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp for simd collapse(4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp for simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp for simd collapse(4 4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp for simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp for simd collapse(4, , 4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp for simd', but found only 1}}
+#pragma omp parallel
+#pragma omp for simd collapse(4)
+ for (int i1 = 0; i1 < 16; ++i1)
+ for (int i2 = 0; i2 < 16; ++i2)
+ for (int i3 = 0; i3 < 16; ++i3)
+ for (int i4 = 0; i4 < 16; ++i4)
+ foo();
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp for simd collapse(4, 8)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp for simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp for simd collapse(2.5)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp for simd collapse(foo())
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+#pragma omp for simd collapse(-5)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+#pragma omp for simd collapse(0)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+#pragma omp for simd collapse(5 - 5)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp for simd collapse(2)
+ for (i = 0; i < 16; ++i)
+// expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for simd' directive into a parallel or another task region?}}
+ for (int j = 0; j < 16; ++j)
+// expected-error@+2 {{private variable cannot be reduction}}
+// expected-error@+1 {{OpenMP constructs may not be nested inside a simd region}}
+#pragma omp for simd reduction(+ : i, j)
+ for (int k = 0; k < 16; ++k)
+ i += j;
+}
+
+void test_linear() {
+ int i;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd linear(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd linear(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd linear(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd linear()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd linear(int)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected variable name}}
+#pragma omp for simd linear(0)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{use of undeclared identifier 'x'}}
+#pragma omp for simd linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{use of undeclared identifier 'x'}}
+// expected-error@+1 {{use of undeclared identifier 'y'}}
+#pragma omp for simd linear(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+3 {{use of undeclared identifier 'x'}}
+// expected-error@+2 {{use of undeclared identifier 'y'}}
+// expected-error@+1 {{use of undeclared identifier 'z'}}
+#pragma omp for simd linear(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y;
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd linear(x :)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd linear(x :, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp for simd linear(x : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp for simd linear(x : 2 * 2)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd linear(x : 1, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd linear(x : 1, y, z : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as linear}}
+// expected-error@+1 {{linear variable cannot be linear}}
+#pragma omp for simd linear(x) linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as private}}
+// expected-error@+1 {{private variable cannot be linear}}
+#pragma omp for simd private(x) linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as linear}}
+// expected-error@+1 {{linear variable cannot be private}}
+#pragma omp for simd linear(x) private(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-warning@+1 {{zero linear step (x and other variables in clause should probably be const)}}
+#pragma omp for simd linear(x, y : 0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as linear}}
+// expected-error@+1 {{linear variable cannot be lastprivate}}
+#pragma omp for simd linear(x) lastprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-note@+2 {{defined as lastprivate}}
+// expected-error@+1 {{lastprivate variable cannot be linear}}
+#pragma omp for simd lastprivate(x) linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_aligned() {
+ int i;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd aligned(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd aligned(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd aligned(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd aligned()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd aligned(int)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected variable name}}
+#pragma omp for simd aligned(0)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{use of undeclared identifier 'x'}}
+#pragma omp for simd aligned(x)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{use of undeclared identifier 'x'}}
+// expected-error@+1 {{use of undeclared identifier 'y'}}
+#pragma omp for simd aligned(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+3 {{use of undeclared identifier 'x'}}
+// expected-error@+2 {{use of undeclared identifier 'y'}}
+// expected-error@+1 {{use of undeclared identifier 'z'}}
+#pragma omp for simd aligned(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int *x, y, z[25]; // expected-note 4 {{'y' defined here}}
+#pragma omp for simd aligned(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp for simd aligned(z)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd aligned(x :)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd aligned(x :, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp for simd aligned(x : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp for simd aligned(x : 2 * 2)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd aligned(x : 1, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd aligned(x : 1, y, z : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-error@+1 {{argument of aligned clause should be array or pointer, not 'int'}}
+#pragma omp for simd aligned(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument of aligned clause should be array or pointer, not 'int'}}
+#pragma omp for simd aligned(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as aligned}}
+// expected-error@+1 {{a variable cannot appear in more than one aligned clause}}
+#pragma omp for simd aligned(x) aligned(z, x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+3 {{defined as aligned}}
+// expected-error@+2 {{a variable cannot appear in more than one aligned clause}}
+// expected-error@+1 2 {{argument of aligned clause should be array or pointer, not 'int'}}
+#pragma omp for simd aligned(x, y, z) aligned(y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+
+void test_private() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp for simd private(
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp for simd private(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp for simd private(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd private()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd private(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp for simd private(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp for simd private(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp for simd private(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp for simd private(x, y, z)
+ for (i = 0; i < 16; ++i) {
+ x = y * i + z;
+ }
+}
+
+void test_lastprivate() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd lastprivate(
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp for simd lastprivate(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp for simd lastprivate(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd lastprivate()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd lastprivate(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp for simd lastprivate(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp for simd lastprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp for simd lastprivate(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp for simd lastprivate(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_firstprivate() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd firstprivate(
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp for simd firstprivate(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp for simd firstprivate(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd firstprivate()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp for simd firstprivate(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp for simd firstprivate(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp for simd lastprivate(x) firstprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp for simd lastprivate(x, y) firstprivate(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp for simd lastprivate(x, y, z) firstprivate(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_loop_messages() {
+ float a[100], b[100], c[100];
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or pointer type}}
+#pragma omp for simd
+ for (float fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or pointer type}}
+#pragma omp for simd
+ for (double fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+}
+
diff --git a/test/OpenMP/for_simd_private_messages.cpp b/test/OpenMP/for_simd_private_messages.cpp
new file mode 100644
index 000000000000..016a5ec6b581
--- /dev/null
+++ b/test/OpenMP/for_simd_private_messages.cpp
@@ -0,0 +1,173 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+};
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+
+public:
+ S3() : a(0) {}
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+
+public:
+ S5(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(I argc, C **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp for simd private // expected-error {{expected '(' after 'private'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(a, b) // expected-error {{private variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(e, g)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp for simd'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp for simd private(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp for simd private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp for simd private // expected-error {{expected '(' after 'private'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(a, b) // expected-error {{private variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp for simd'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int i;
+#pragma omp for simd private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp for simd private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp for simd private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+
+ return 0;
+}
+
diff --git a/test/OpenMP/for_simd_reduction_messages.cpp b/test/OpenMP/for_simd_reduction_messages.cpp
new file mode 100644
index 000000000000..708973be51ba
--- /dev/null
+++ b/test/OpenMP/for_simd_reduction_messages.cpp
@@ -0,0 +1,350 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+ S2 &operator+=(const S2 &arg) { return (*this); }
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
+ static const float S2sc;
+};
+const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+S2 b; // expected-note 2 {{'b' defined here}}
+const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
+class S3 {
+ int a;
+
+public:
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+ S3 operator+=(const S3 &arg1) { return arg1; }
+};
+int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+S3 c; // expected-note 2 {{'c' defined here}}
+const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
+extern const int f; // expected-note 4 {{'f' declared here}}
+class S4 { // expected-note {{'S4' declared here}}
+ int a;
+ S4();
+ S4(const S4 &s4);
+ S4 &operator+=(const S4 &arg) { return (*this); }
+
+public:
+ S4(int v) : a(v) {}
+};
+S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
+class S5 {
+ int a;
+ S5() : a(0) {}
+ S5(const S5 &s5) : a(s5.a) {}
+ S5 &operator+=(const S5 &arg);
+
+public:
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+
+public:
+ S6() : a(6) {}
+ operator int() { return 6; }
+} o; // expected-note 2 {{'o' defined here}}
+
+S3 h, k;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class T> // expected-note {{declared here}}
+T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+ const T d = T(); // expected-note 4 {{'d' defined here}}
+ const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
+ T qa[5] = {T()};
+ T i;
+ T &j = i; // expected-note 4 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
+ T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
+ T fl; // expected-note {{'fl' defined here}}
+#pragma omp parallel
+#pragma omp for simd reduction // expected-error {{expected '(' after 'reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(^ : T) // expected-error {{'T' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(max : qa[1]) // expected-error 2 {{expected variable name}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : ba) // expected-error {{a reduction variable with array type 'const S2 [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(* : ca) // expected-error {{a reduction variable with array type 'const S3 [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp for simd reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : p), reduction(+ : p) // expected-error 3 {{variable can appear only once in OpenMP 'reduction' clause}} expected-note 3 {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : r) // expected-error 2 {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp for simd reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(fl) // expected-note 2 {{defined as private}}
+#pragma omp for simd reduction(+ : fl) // expected-error 2 {{reduction variable must be shared}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel reduction(* : fl) // expected-note 2 {{defined as reduction}}
+#pragma omp for simd reduction(+ : fl) // expected-error 2 {{reduction variable must be shared}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return T();
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note 2 {{'d' defined here}}
+ const int da[5] = {0}; // expected-note {{'da' defined here}}
+ int qa[5] = {0};
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note 2 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const int &r = da[i]; // expected-note {{'r' defined here}}
+ int &q = qa[i]; // expected-note {{'q' defined here}}
+ float fl; // expected-note {{'fl' defined here}}
+#pragma omp parallel
+#pragma omp for simd reduction // expected-error {{expected '(' after 'reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(~ : argc) // expected-error {{expected unqualified-id}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(max : argv[1]) // expected-error {{expected variable name}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : ba) // expected-error {{a reduction variable with array type 'const S2 [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(* : ca) // expected-error {{a reduction variable with array type 'const S3 [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp for simd reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for simd reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp for simd reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(fl) // expected-note {{defined as private}}
+#pragma omp for simd reduction(+ : fl) // expected-error {{reduction variable must be shared}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel reduction(* : fl) // expected-note {{defined as reduction}}
+#pragma omp for simd reduction(+ : fl) // expected-error {{reduction variable must be shared}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
+}
diff --git a/test/OpenMP/for_simd_safelen_messages.cpp b/test/OpenMP/for_simd_safelen_messages.cpp
new file mode 100644
index 000000000000..1a72964ce4e9
--- /dev/null
+++ b/test/OpenMP/for_simd_safelen_messages.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
+ #pragma omp for simd safelen // expected-error {{expected '(' after 'safelen'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd safelen ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd safelen () // expected-error {{expected expression}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+ // expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ #pragma omp for simd safelen (argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+ #pragma omp for simd safelen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd safelen (1)) // expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd safelen ((ST > 0) ? 1 + ST : 2)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 2 {{directive '#pragma omp for simd' cannot contain more than one 'safelen' clause}}
+ // expected-error@+2 2 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp for simd safelen (foobool(argc)), safelen (true), safelen (-5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd safelen (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp for simd safelen (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd safelen (4)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd safelen (N) // expected-error {{argument to 'safelen' clause must be a positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp for simd safelen // expected-error {{expected '(' after 'safelen'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd safelen ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd safelen () // expected-error {{expected expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd safelen (4 // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd safelen (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd safelen (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{expression is not an integral constant expression}}
+ // expected-error@+2 2 {{directive '#pragma omp for simd' cannot contain more than one 'safelen' clause}}
+ // expected-error@+1 2 {{argument to 'safelen' clause must be a positive integer value}}
+ #pragma omp for simd safelen (foobool(argc)), safelen (true), safelen (-5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd safelen (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp for simd safelen (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp for simd' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp for simd safelen(safelen(tmain<int, char, -1, -2>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ foo();
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 12, 4>' requested here}}
+ return tmain<int, char, 12, 4>(argc, argv);
+}
+
diff --git a/test/OpenMP/for_simd_schedule_messages.cpp b/test/OpenMP/for_simd_schedule_messages.cpp
new file mode 100644
index 000000000000..8624359eb420
--- /dev/null
+++ b/test/OpenMP/for_simd_schedule_messages.cpp
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) {
+ #pragma omp for simd schedule // expected-error {{expected '(' after 'schedule'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule (runtime, 3) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp for simd schedule (guided argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{argument to 'schedule' clause must be a positive integer value}}
+ #pragma omp for simd schedule (static, ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule (dynamic, 1)) // expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule (guided, (ST > 0) ? 1 + ST : 2)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+2 2 {{directive '#pragma omp for simd' cannot contain more than one 'schedule' clause}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ #pragma omp for simd schedule (static, foobool(argc)), schedule (dynamic, true), schedule (guided, -5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule (static, S) // expected-error {{'S' does not refer to a value}} expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp for simd schedule (guided, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule (dynamic, 1)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for simd schedule (static, N) // expected-error {{argument to 'schedule' clause must be a positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp for simd schedule // expected-error {{expected '(' after 'schedule'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd schedule (runtime, 3) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd schedule (guided, 4 // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd schedule (static, 2+2)) // expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd schedule (dynamic, foobool(1) > 0 ? 1 : 2)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+2 2 {{directive '#pragma omp for simd' cannot contain more than one 'schedule' clause}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ #pragma omp for simd schedule (guided, foobool(argc)), schedule (static, true), schedule (dynamic, -5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp for simd schedule (guided, S1) // expected-error {{'S1' does not refer to a value}} expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp for simd schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp for simd' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp for simd schedule(dynamic, schedule(tmain<int, char, -1, -2>(argc, argv) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
+ return tmain<int, char, 1, 0>(argc, argv);
+}
+
diff --git a/test/OpenMP/master_codegen.cpp b/test/OpenMP/master_codegen.cpp
new file mode 100644
index 000000000000..d354bae2d7ee
--- /dev/null
+++ b/test/OpenMP/master_codegen.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
+
+// CHECK: define void [[FOO:@.+]]()
+
+void foo() {}
+
+// CHECK-LABEL: @main
+int main() {
+ // CHECK: [[A_ADDR:%.+]] = alloca i8
+ char a;
+
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
+// CHECK: [[RES:%.+]] = call i32 @__kmpc_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK-NEXT: [[IS_MASTER:%.+]] = icmp ne i32 [[RES]], 0
+// CHECK-NEXT: br i1 [[IS_MASTER]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]]
+// CHECK: [[THEN]]
+// CHECK-NEXT: store i8 2, i8* [[A_ADDR]]
+// CHECK-NEXT: call void @__kmpc_end_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK-NEXT: br label {{%?}}[[EXIT]]
+// CHECK: [[EXIT]]
+#pragma omp master
+ a = 2;
+// CHECK: [[RES:%.+]] = call i32 @__kmpc_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK-NEXT: [[IS_MASTER:%.+]] = icmp ne i32 [[RES]], 0
+// CHECK-NEXT: br i1 [[IS_MASTER]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]]
+// CHECK: [[THEN]]
+// CHECK-NEXT: call void [[FOO]]()
+// CHECK-NEXT: call void @__kmpc_end_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK-NEXT: br label {{%?}}[[EXIT]]
+// CHECK: [[EXIT]]
+#pragma omp master
+ foo();
+// CHECK-NOT: call i32 @__kmpc_master
+// CHECK-NOT: call void @__kmpc_end_master
+ return a;
+}
+
+#endif
diff --git a/test/OpenMP/nesting_of_regions.cpp b/test/OpenMP/nesting_of_regions.cpp
index d8dcec5edf2e..a948ca3e3bcb 100644
--- a/test/OpenMP/nesting_of_regions.cpp
+++ b/test/OpenMP/nesting_of_regions.cpp
@@ -4,6 +4,7 @@ void bar();
template <class T>
void foo() {
+ T a = T();
// PARALLEL DIRECTIVE
#pragma omp parallel
#pragma omp for
@@ -14,6 +15,10 @@ void foo() {
for (int i = 0; i < 10; ++i)
;
#pragma omp parallel
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp parallel
#pragma omp sections
{
bar();
@@ -42,6 +47,10 @@ void foo() {
for (int i = 0; i < 10; ++i)
;
#pragma omp parallel
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp parallel
#pragma omp parallel sections
{
bar();
@@ -71,6 +80,26 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp parallel
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'parallel' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp parallel
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp parallel
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp parallel
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// SIMD DIRECTIVE
#pragma omp simd
@@ -87,6 +116,12 @@ void foo() {
}
#pragma omp simd
for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel // expected-error {{OpenMP constructs may not be nested inside a simd region}}
for (int i = 0; i < 10; ++i)
;
@@ -134,6 +169,12 @@ void foo() {
}
#pragma omp simd
for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel sections // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
bar();
@@ -166,6 +207,26 @@ void foo() {
#pragma omp flush // expected-error {{OpenMP constructs may not be nested inside a simd region}}
bar();
}
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
// FOR DIRECTIVE
#pragma omp for
@@ -182,6 +243,12 @@ void foo() {
}
#pragma omp for
for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -217,7 +284,7 @@ void foo() {
}
#pragma omp for
for (int i = 0; i < 10; ++i) {
-#pragma omp critical
+#pragma omp critical
{
bar();
}
@@ -247,6 +314,12 @@ void foo() {
}
#pragma omp for
for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel sections
{
bar();
@@ -279,6 +352,158 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp for ordered
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // OK
+ bar();
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target
+ ++a;
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
+
+// FOR SIMD DIRECTIVE
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp sections // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp section // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp single // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp master // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp critical // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel sections // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp task // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskyield // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp barrier // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskwait // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp flush // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
// SECTIONS DIRECTIVE
#pragma omp sections
@@ -295,6 +520,12 @@ void foo() {
}
#pragma omp sections
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'sections' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp sections
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -376,6 +607,12 @@ void foo() {
}
#pragma omp sections
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp sections
+ {
#pragma omp parallel sections
{
bar();
@@ -404,6 +641,26 @@ void foo() {
{
#pragma omp flush
}
+#pragma omp sections
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'sections' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp sections
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp sections
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp sections
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'sections' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// SECTION DIRECTIVE
#pragma omp section // expected-error {{orphaned 'omp section' directives are prohibited, it must be closely nested to a sections region}}
@@ -432,6 +689,15 @@ void foo() {
{
#pragma omp section
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'section' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+ }
+#pragma omp sections
+ {
+#pragma omp section
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -482,6 +748,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -502,6 +771,15 @@ void foo() {
{
#pragma omp section
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+ }
+#pragma omp sections
+ {
+#pragma omp section
+ {
#pragma omp parallel sections
{
bar();
@@ -550,6 +828,32 @@ void foo() {
bar();
}
}
+#pragma omp sections
+ {
+#pragma omp section
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'section' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+ }
+#pragma omp sections
+ {
+#pragma omp section
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp sections
+ {
+#pragma omp section
+#pragma omp target
+ ++a;
+ }
+#pragma omp sections
+ {
+#pragma omp section
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'section' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// SINGLE DIRECTIVE
#pragma omp single
@@ -566,6 +870,12 @@ void foo() {
}
#pragma omp single
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'single' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp single
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -609,6 +919,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -623,6 +936,12 @@ void foo() {
}
#pragma omp single
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp single
+ {
#pragma omp parallel sections
{
bar();
@@ -655,6 +974,26 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp single
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'single' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp single
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp single
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp single
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'single' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// MASTER DIRECTIVE
#pragma omp master
@@ -671,6 +1010,12 @@ void foo() {
}
#pragma omp master
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'master' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp master
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -714,6 +1059,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -728,6 +1076,12 @@ void foo() {
}
#pragma omp master
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp master
+ {
#pragma omp parallel sections
{
bar();
@@ -760,6 +1114,26 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp master
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'master' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp master
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp master
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp master
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'master' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// CRITICAL DIRECTIVE
#pragma omp critical
@@ -776,6 +1150,12 @@ void foo() {
}
#pragma omp critical
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'critical' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp critical
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -819,6 +1199,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -833,6 +1216,12 @@ void foo() {
}
#pragma omp critical
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp critical
+ {
#pragma omp parallel sections
{
bar();
@@ -865,7 +1254,7 @@ void foo() {
#pragma omp critical(grelka)
bar();
}
-#pragma omp critical(Belka)// expected-note {{previous 'critical' region starts here}}
+#pragma omp critical(Belka) // expected-note {{previous 'critical' region starts here}}
{
#pragma omp critical(Belka) // expected-error {{cannot nest 'critical' regions having the same name 'Belka'}}
{
@@ -879,6 +1268,26 @@ void foo() {
}
}
}
+#pragma omp critical
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'critical' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp critical
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp critical
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp critical
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'critical' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// PARALLEL FOR DIRECTIVE
#pragma omp parallel for
@@ -895,6 +1304,12 @@ void foo() {
}
#pragma omp parallel for
for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -948,6 +1363,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -962,6 +1380,12 @@ void foo() {
}
#pragma omp parallel for
for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel sections
{
bar();
@@ -994,6 +1418,186 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp parallel for ordered
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // OK
+ bar();
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target
+ ++a;
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
+
+// PARALLEL FOR SIMD DIRECTIVE
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp simd// expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp sections // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp section // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp single // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp master // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp critical // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+#pragma omp single
+ {
+ bar();
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp sections
+ {
+ bar();
+ }
+ }
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd// expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel sections // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp task // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskyield // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp barrier // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskwait // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp flush // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
// PARALLEL SECTIONS DIRECTIVE
#pragma omp parallel sections
@@ -1010,6 +1614,12 @@ void foo() {
}
#pragma omp parallel sections
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'parallel sections' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel sections
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -1063,6 +1673,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -1077,6 +1690,12 @@ void foo() {
}
#pragma omp parallel sections
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel sections
+ {
#pragma omp parallel sections
{
bar();
@@ -1105,6 +1724,26 @@ void foo() {
{
#pragma omp flush
}
+#pragma omp parallel sections
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'parallel sections' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp parallel sections
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp parallel sections
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp parallel sections
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel sections' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// TASK DIRECTIVE
#pragma omp task
@@ -1116,6 +1755,10 @@ void foo() {
for (int i = 0; i < 10; ++i)
;
#pragma omp task
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp task
#pragma omp sections // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp sections' directive into a parallel region?}}
{
bar();
@@ -1140,6 +1783,10 @@ void foo() {
for (int i = 0; i < 10; ++i)
;
#pragma omp task
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp task
#pragma omp parallel sections
{
bar();
@@ -1169,9 +1816,543 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp task
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp task
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp task
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp task
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
+
+// ORDERED DIRECTIVE
+#pragma omp ordered
+ {
+#pragma omp for // expected-error {{region cannot be closely nested inside 'ordered' region; perhaps you forget to enclose 'omp for' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp ordered
+ {
+#pragma omp simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp ordered
+ {
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'ordered' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp ordered
+ {
+#pragma omp parallel
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp ordered
+ {
+#pragma omp single // expected-error {{region cannot be closely nested inside 'ordered' region; perhaps you forget to enclose 'omp single' directive into a parallel region?}}
+ {
+ bar();
+ }
+ }
+#pragma omp ordered
+ {
+#pragma omp master // OK, though second 'ordered' is redundant
+ {
+ bar();
+ }
+ }
+#pragma omp ordered
+ {
+#pragma omp critical
+ {
+ bar();
+ }
+ }
+#pragma omp ordered
+ {
+#pragma omp sections // expected-error {{region cannot be closely nested inside 'ordered' region; perhaps you forget to enclose 'omp sections' directive into a parallel region?}}
+ {
+ bar();
+ }
+ }
+#pragma omp ordered
+ {
+#pragma omp parallel for ordered
+ for (int j = 0; j < 10; ++j) {
+#pragma omp ordered // OK
+ {
+ bar();
+ }
+ }
+ }
+#pragma omp ordered
+ {
+#pragma omp parallel for simd ordered //expected-error {{unexpected OpenMP clause 'ordered' in directive '#pragma omp parallel for simd'}}
+ for (int j = 0; j < 10; ++j) {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+ }
+#pragma omp ordered
+ {
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp ordered
+ {
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp ordered
+ {
+#pragma omp parallel sections
+ {
+ bar();
+ }
+ }
+#pragma omp ordered
+ {
+#pragma omp task
+ {
+ bar();
+ }
+ }
+#pragma omp ordered
+ {
+#pragma omp taskyield
+ bar();
+ }
+#pragma omp ordered
+ {
+#pragma omp barrier // expected-error {{region cannot be closely nested inside 'ordered' region}}
+ bar();
+ }
+#pragma omp ordered
+ {
+#pragma omp taskwait
+ bar();
+ }
+#pragma omp ordered
+ {
+#pragma omp flush
+ bar();
+ }
+#pragma omp ordered
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'ordered' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp ordered
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp ordered
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp ordered
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'ordered' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
+
+// ATOMIC DIRECTIVE
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp for // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp simd // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp for simd // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp parallel // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp sections // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp section // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp single // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp master // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp critical // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp parallel for // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp parallel for simd // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp parallel sections // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp task // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp taskyield // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ bar();
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp barrier // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ bar();
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp taskwait // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ bar();
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp flush // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ bar();
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ bar();
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp atomic // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ ++a;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp target // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ ++a;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ ++a;
+ }
+
+// TARGET DIRECTIVE
+#pragma omp target
+#pragma omp parallel
+ bar();
+#pragma omp target
+#pragma omp for
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp sections
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp section // expected-error {{'omp section' directive must be closely nested to a sections region, not a target region}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp single
+ bar();
+
+#pragma omp target
+#pragma omp master
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp critical
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp parallel sections
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp task
+ {
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp taskyield
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp barrier
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp taskwait
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp flush
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'target' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp target
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp target
+ {
+#pragma omp teams
+ ++a;
+ }
+#pragma omp target // expected-error {{target construct with nested teams region contains statements outside of the teams construct}}
+ {
+ ++a; // expected-note {{statement outside teams construct here}}
+#pragma omp teams // expected-note {{nested teams construct here}}
+ ++a;
+ }
+
+// TEAMS DIRECTIVE
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel
+ bar();
+#pragma omp target
+#pragma omp teams
+#pragma omp for // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp for' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp simd // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp sections // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp sections' directive into a parallel region?}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp section // expected-error {{'omp section' directive must be closely nested to a sections region, not a teams region}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp single // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp single' directive into a parallel region?}}
+ bar();
+
+#pragma omp target
+#pragma omp teams
+#pragma omp master // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp master' directive into a parallel region?}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp critical // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp critical' directive into a parallel region?}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel sections
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp task // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp task' directive into a parallel region?}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp taskyield // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp taskyield' directive into a parallel region?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp barrier // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp barrier' directive into a parallel region?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp taskwait // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp taskwait' directive into a parallel region?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp flush // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp flush' directive into a parallel region?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp atomic // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp atomic' directive into a parallel region?}}
+ ++a;
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp target // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp target' directive into a parallel region?}}
+ ++a;
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
}
void foo() {
+ int a = 0;
// PARALLEL DIRECTIVE
#pragma omp parallel
#pragma omp for
@@ -1182,6 +2363,10 @@ void foo() {
for (int i = 0; i < 10; ++i)
;
#pragma omp parallel
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp parallel
#pragma omp sections
{
bar();
@@ -1210,6 +2395,10 @@ void foo() {
for (int i = 0; i < 10; ++i)
;
#pragma omp parallel
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp parallel
#pragma omp parallel sections
{
bar();
@@ -1239,6 +2428,26 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp parallel
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'parallel' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp parallel
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp parallel
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp parallel
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// SIMD DIRECTIVE
#pragma omp simd
@@ -1255,6 +2464,12 @@ void foo() {
}
#pragma omp simd
for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel // expected-error {{OpenMP constructs may not be nested inside a simd region}}
for (int i = 0; i < 10; ++i)
;
@@ -1295,6 +2510,12 @@ void foo() {
}
#pragma omp simd
for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel sections // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
bar();
@@ -1327,6 +2548,26 @@ void foo() {
#pragma omp flush // expected-error {{OpenMP constructs may not be nested inside a simd region}}
bar();
}
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
// FOR DIRECTIVE
#pragma omp for
@@ -1343,6 +2584,12 @@ void foo() {
}
#pragma omp for
for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -1381,6 +2628,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -1395,6 +2645,12 @@ void foo() {
}
#pragma omp for
for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel sections
{
bar();
@@ -1427,6 +2683,151 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp for ordered
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // OK
+ bar();
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target
+ ++a;
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
+
+// FOR SIMD DIRECTIVE
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp sections // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp section // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp single // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+#pragma omp master // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp single // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+#pragma omp critical // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel sections // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp task // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskyield // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp barrier // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskwait // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp flush // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
// SECTIONS DIRECTIVE
#pragma omp sections
@@ -1443,6 +2844,12 @@ void foo() {
}
#pragma omp sections
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'sections' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp sections
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -1481,6 +2888,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -1495,6 +2905,12 @@ void foo() {
}
#pragma omp sections
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp sections
+ {
#pragma omp parallel sections
{
bar();
@@ -1524,6 +2940,26 @@ void foo() {
{
#pragma omp flush
}
+#pragma omp sections
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'sections' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp sections
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp sections
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp sections
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'sections' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// SECTION DIRECTIVE
#pragma omp section // expected-error {{orphaned 'omp section' directives are prohibited, it must be closely nested to a sections region}}
@@ -1552,6 +2988,15 @@ void foo() {
{
#pragma omp section
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'section' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+ }
+#pragma omp sections
+ {
+#pragma omp section
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -1602,6 +3047,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -1622,6 +3070,15 @@ void foo() {
{
#pragma omp section
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+ }
+#pragma omp sections
+ {
+#pragma omp section
+ {
#pragma omp parallel sections
{
bar();
@@ -1670,6 +3127,38 @@ void foo() {
bar();
}
}
+#pragma omp sections
+ {
+#pragma omp section
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'section' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+ }
+#pragma omp sections
+ {
+#pragma omp section
+ {
+#pragma omp atomic
+ ++a;
+ }
+ }
+#pragma omp sections
+ {
+#pragma omp section
+ {
+#pragma omp target
+ ++a;
+ }
+ }
+#pragma omp sections
+ {
+#pragma omp section
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'section' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
+ }
// SINGLE DIRECTIVE
#pragma omp single
@@ -1686,6 +3175,12 @@ void foo() {
}
#pragma omp single
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'single' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp single
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -1719,6 +3214,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -1733,6 +3231,12 @@ void foo() {
}
#pragma omp single
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp single
+ {
#pragma omp parallel sections
{
bar();
@@ -1765,6 +3269,26 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp single
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'single' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp single
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp single
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp single
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'single' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// MASTER DIRECTIVE
#pragma omp master
@@ -1781,6 +3305,12 @@ void foo() {
}
#pragma omp master
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'master' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp master
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -1824,6 +3354,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -1838,6 +3371,12 @@ void foo() {
}
#pragma omp master
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp master
+ {
#pragma omp parallel sections
{
bar();
@@ -1870,6 +3409,26 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp master
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'master' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp master
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp master
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp master
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'master' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// CRITICAL DIRECTIVE
#pragma omp critical
@@ -1886,6 +3445,12 @@ void foo() {
}
#pragma omp critical
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'critical' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp critical
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -1929,6 +3494,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -1943,6 +3511,12 @@ void foo() {
}
#pragma omp critical
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp critical
+ {
#pragma omp parallel sections
{
bar();
@@ -1975,7 +3549,7 @@ void foo() {
#pragma omp critical(Strelka)
bar();
}
-#pragma omp critical(Tuzik)// expected-note {{previous 'critical' region starts here}}
+#pragma omp critical(Tuzik) // expected-note {{previous 'critical' region starts here}}
{
#pragma omp critical(grelka) // expected-note {{previous 'critical' region starts here}}
{
@@ -1989,6 +3563,31 @@ void foo() {
}
}
}
+#pragma omp critical
+ {
+#pragma omp flush
+ bar();
+ }
+#pragma omp critical
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'critical' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp critical
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp critical
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp critical
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'critical' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// PARALLEL FOR DIRECTIVE
#pragma omp parallel for
@@ -2005,6 +3604,13 @@ void foo() {
}
#pragma omp parallel for
for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -2057,6 +3663,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -2071,6 +3680,12 @@ void foo() {
}
#pragma omp parallel for
for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
#pragma omp parallel sections
{
bar();
@@ -2103,6 +3718,186 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp parallel for ordered
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // OK
+ bar();
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target
+ ++a;
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
+
+// PARALLEL FOR SIMD DIRECTIVE
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp simd// expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp sections // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp section // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp single // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp master // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp critical // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+#pragma omp single
+ {
+ bar();
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp sections
+ {
+ bar();
+ }
+ }
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd// expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel sections // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp task // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ {
+ bar();
+ }
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskyield // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp barrier // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskwait // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp flush // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ bar();
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ ++a;
+ }
// PARALLEL SECTIONS DIRECTIVE
#pragma omp parallel sections
@@ -2119,6 +3914,12 @@ void foo() {
}
#pragma omp parallel sections
{
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'parallel sections' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel sections
+ {
#pragma omp parallel
for (int i = 0; i < 10; ++i)
;
@@ -2168,6 +3969,9 @@ void foo() {
#pragma omp for // OK
for (int i = 0; i < 10; ++i)
;
+#pragma omp for simd // OK
+ for (int i = 0; i < 10; ++i)
+ ;
#pragma omp sections // OK
{
bar();
@@ -2182,6 +3986,12 @@ void foo() {
}
#pragma omp parallel sections
{
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp parallel sections
+ {
#pragma omp parallel sections
{
bar();
@@ -2210,6 +4020,26 @@ void foo() {
{
#pragma omp flush
}
+#pragma omp parallel sections
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'parallel sections' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp parallel sections
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp parallel sections
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp parallel sections
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel sections' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
// TASK DIRECTIVE
#pragma omp task
@@ -2221,6 +4051,10 @@ void foo() {
for (int i = 0; i < 10; ++i)
;
#pragma omp task
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp task
#pragma omp sections // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp sections' directive into a parallel region?}}
{
bar();
@@ -2244,6 +4078,10 @@ void foo() {
for (int i = 0; i < 10; ++i)
;
#pragma omp task
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp task
#pragma omp parallel sections
{
bar();
@@ -2273,6 +4111,399 @@ void foo() {
#pragma omp flush
bar();
}
+#pragma omp task
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp task
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp task
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp task
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
+
+// ATOMIC DIRECTIVE
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp for // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp simd // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp for simd // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp parallel // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp sections // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp section // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp single // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp master // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp critical // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp parallel for // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp parallel for simd // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp parallel sections // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp task // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ {
+ bar();
+ }
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp taskyield // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ bar();
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp barrier // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ bar();
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp taskwait // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ bar();
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp flush // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ bar();
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ bar();
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp atomic // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ ++a;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp target // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ ++a;
+ }
+#pragma omp atomic
+ // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ {
+#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ ++a;
+ }
+
+// TARGET DIRECTIVE
+#pragma omp target
+#pragma omp parallel
+ bar();
+#pragma omp target
+#pragma omp for
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp sections
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp section // expected-error {{'omp section' directive must be closely nested to a sections region, not a target region}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp single
+ bar();
+
+#pragma omp target
+#pragma omp master
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp critical
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp parallel sections
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp task
+ {
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp taskyield
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp barrier
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp taskwait
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp flush
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'target' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp target
+ {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp target
+ {
+#pragma omp target
+ ++a;
+ }
+#pragma omp target
+ {
+#pragma omp teams
+ ++a;
+ }
+#pragma omp target // expected-error {{target construct with nested teams region contains statements outside of the teams construct}}
+ {
+ ++a; // expected-note {{statement outside teams construct here}}
+#pragma omp teams // expected-note {{nested teams construct here}}
+ ++a;
+ }
+
+// TEAMS DIRECTIVE
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel
+ bar();
+#pragma omp target
+#pragma omp teams
+#pragma omp for // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp for' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp simd // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp sections // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp sections' directive into a parallel region?}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp section // expected-error {{'omp section' directive must be closely nested to a sections region, not a teams region}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp single // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp single' directive into a parallel region?}}
+ bar();
+
+#pragma omp target
+#pragma omp teams
+#pragma omp master // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp master' directive into a parallel region?}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp critical // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp critical' directive into a parallel region?}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel sections
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp task // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp task' directive into a parallel region?}}
+ {
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp taskyield // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp taskyield' directive into a parallel region?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp barrier // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp barrier' directive into a parallel region?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp taskwait // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp taskwait' directive into a parallel region?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp flush // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp flush' directive into a parallel region?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp atomic // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp atomic' directive into a parallel region?}}
+ ++a;
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp target // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp target' directive into a parallel region?}}
+ ++a;
+ }
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
return foo<int>();
}
diff --git a/test/OpenMP/ordered_ast_print.cpp b/test/OpenMP/ordered_ast_print.cpp
new file mode 100644
index 000000000000..a44350070356
--- /dev/null
+++ b/test/OpenMP/ordered_ast_print.cpp
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void foo() {}
+
+template <class T>
+T tmain (T argc) {
+ T b = argc, c, d, e, f, g;
+ static T a;
+ #pragma omp for ordered
+ for (int i =0 ; i < argc; ++i)
+ #pragma omp ordered
+ {
+ a=2;
+ }
+ return (0);
+}
+
+// CHECK: static int a;
+// CHECK-NEXT: #pragma omp for ordered
+// CHECK-NEXT: for (int i = 0; i < argc; ++i)
+// CHECK-NEXT: #pragma omp ordered
+// CHECK-NEXT: {
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: }
+
+// CHECK: static T a;
+// CHECK-NEXT: #pragma omp for ordered
+// CHECK-NEXT: for (int i = 0; i < argc; ++i)
+// CHECK-NEXT: #pragma omp ordered
+// CHECK-NEXT: {
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: }
+
+int main (int argc, char **argv) {
+ int b = argc, c, d, e, f, g;
+ static int a;
+// CHECK: static int a;
+ #pragma omp for ordered
+ for (int i =0 ; i < argc; ++i)
+ #pragma omp ordered
+ {
+ a=2;
+ }
+// CHECK-NEXT: #pragma omp for ordered
+// CHECK-NEXT: for (int i = 0; i < argc; ++i)
+// CHECK-NEXT: #pragma omp ordered
+// CHECK-NEXT: {
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: }
+ return tmain(argc);
+}
+
+#endif
diff --git a/test/OpenMP/ordered_messages.cpp b/test/OpenMP/ordered_messages.cpp
new file mode 100644
index 000000000000..3f79df649895
--- /dev/null
+++ b/test/OpenMP/ordered_messages.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 -o - %s
+
+int foo();
+
+template <class T>
+T foo() {
+ #pragma omp for ordered
+ for (int i = 0; i < 10; ++i) {
+ L1:
+ foo();
+ #pragma omp ordered
+ {
+ foo();
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ }
+ }
+ #pragma omp for ordered
+ for (int i = 0; i < 10; ++i) {
+ foo();
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+ #pragma omp ordered
+ {
+ L2:
+ foo();
+ }
+ }
+
+ return T();
+}
+
+int foo() {
+ #pragma omp for ordered
+ for (int i = 0; i < 10; ++i) {
+ L1:
+ foo();
+ #pragma omp ordered
+ {
+ foo();
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ }
+ }
+ #pragma omp for ordered
+ for (int i = 0; i < 10; ++i) {
+ foo();
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+ #pragma omp ordered
+ {
+ L2:
+ foo();
+ }
+ }
+
+ return foo<int>();
+}
diff --git a/test/OpenMP/parallel_codegen.cpp b/test/OpenMP/parallel_codegen.cpp
index d9ff5ac02333..e50ab43c2808 100644
--- a/test/OpenMP/parallel_codegen.cpp
+++ b/test/OpenMP/parallel_codegen.cpp
@@ -39,7 +39,7 @@ int main (int argc, char **argv) {
// CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon* [[AGG_CAPTURED]], i32 0, i32 0
// CHECK-NEXT: store i32* {{%[a-z0-9.]+}}, i32** [[ARGC_REF]]
// CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
-// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @__captured_stmt to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-NEXT: [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}}
// CHECK-NEXT: [[RET:%.+]] = call {{[a-z]*[ ]?i32}} [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
// CHECK-NEXT: ret i32 [[RET]]
@@ -55,13 +55,13 @@ int main (int argc, char **argv) {
// CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC1]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
// CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
-// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @__captured_stmt to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-DEBUG-NEXT: [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}}
// CHECK-DEBUG-NEXT: [[RET:%.+]] = call i32 [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
// CHECK-DEBUG-NEXT: ret i32 [[RET]]
// CHECK-DEBUG-NEXT: }
-// CHECK-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
+// CHECK-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
// CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
// CHECK: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
// CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]]
@@ -73,7 +73,7 @@ int main (int argc, char **argv) {
// CHECK: call void @{{.+terminate.*}}(
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
-// CHECK-DEBUG-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
+// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
// CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
// CHECK-DEBUG: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
// CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]]
@@ -96,7 +96,7 @@ int main (int argc, char **argv) {
// CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon.0* [[AGG_CAPTURED]], i32 0, i32 0
// CHECK-NEXT: store i8*** {{%[a-z0-9.]+}}, i8**** [[ARGC_REF]]
// CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
-// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @__captured_stmt1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-NEXT: ret i32 0
// CHECK-NEXT: }
// CHECK-DEBUG: define linkonce_odr i32 [[TMAIN]](i8** %argc)
@@ -110,11 +110,11 @@ int main (int argc, char **argv) {
// CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC2]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
// CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
-// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @__captured_stmt1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-DEBUG-NEXT: ret i32 0
// CHECK-DEBUG-NEXT: }
-// CHECK-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
+// CHECK-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
// CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
// CHECK: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
// CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]]
@@ -126,7 +126,7 @@ int main (int argc, char **argv) {
// CHECK: call void @{{.+terminate.*}}(
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
-// CHECK-DEBUG-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
+// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
// CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
// CHECK-DEBUG: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
// CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]]
diff --git a/test/OpenMP/parallel_firstprivate_codegen.cpp b/test/OpenMP/parallel_firstprivate_codegen.cpp
new file mode 100644
index 000000000000..811f2df9df35
--- /dev/null
+++ b/test/OpenMP/parallel_firstprivate_codegen.cpp
@@ -0,0 +1,255 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+struct St {
+ int a, b;
+ St() : a(0), b(0) {}
+ St(const St &st) : a(st.a + st.b), b(0) {}
+ ~St() {}
+};
+
+volatile int g = 1212;
+
+template <class T>
+struct S {
+ T f;
+ S(T a) : f(a + g) {}
+ S() : f(g) {}
+ S(const S &s, St t = St()) : f(s.f + t.a) {}
+ operator T() { return T(); }
+ ~S() {}
+};
+
+// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
+// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
+// CHECK-DAG: [[ST_TY:%.+]] = type { i{{[0-9]+}}, i{{[0-9]+}} }
+// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* }
+// CHECK-DAG: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* }
+// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
+
+template <typename T>
+T tmain() {
+ S<T> test;
+ T t_var = T();
+ T vec[] = {1, 2};
+ S<T> s_arr[] = {1, 2};
+ S<T> var(3);
+#pragma omp parallel firstprivate(t_var, vec, s_arr, var)
+ {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
+ return T();
+}
+
+int main() {
+#ifdef LAMBDA
+ // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+ // LAMBDA: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]]
+ // LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
+ // LAMBDA: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
+#pragma omp parallel firstprivate(g)
+ {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+ // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]],
+ // LAMBDA: [[ARG:%.+]] = load %{{.+}}** [[ARG_REF]]
+ // LAMBDA: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_REF_ADDR]]
+ // LAMBDA: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}* [[G_REF]]
+ // LAMBDA: store volatile i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // LAMBDA: call i32 @__kmpc_cancel_barrier(
+ g = 1;
+ // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]]
+ // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g = 2;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}** [[ARG_PTR_REF]]
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_PTR_REF]]
+ // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]]
+ }();
+ }
+ }();
+ return 0;
+#elif defined(BLOCKS)
+ // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // BLOCKS-LABEL: @main
+ // BLOCKS: call void {{%.+}}(i8*
+ ^{
+ // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
+ // BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]]
+ // BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
+ // BLOCKS: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
+#pragma omp parallel firstprivate(g)
+ {
+ // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+ // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]],
+ // BLOCKS: [[ARG:%.+]] = load %{{.+}}** [[ARG_REF]]
+ // BLOCKS: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // BLOCKS: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_REF_ADDR]]
+ // BLOCKS: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}* [[G_REF]]
+ // BLOCKS: store volatile i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // BLOCKS: call i32 @__kmpc_cancel_barrier(
+ g = 1;
+ // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: call void {{%.+}}(i8*
+ ^{
+ // BLOCKS: define {{.+}} void {{@.+}}(i8*
+ g = 2;
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}*
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: ret
+ }();
+ }
+ }();
+ return 0;
+#else
+ S<float> test;
+ int t_var = 0;
+ int vec[] = {1, 2};
+ S<float> s_arr[] = {1, 2};
+ S<float> var(3);
+#pragma omp parallel firstprivate(t_var, vec, s_arr, var)
+ {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
+ return tmain<int>();
+#endif
+}
+
+// CHECK: define {{.*}}i{{[0-9]+}} @main()
+// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
+// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]*
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
+// CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_MAIN_TY]]* %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}** [[T_VAR_PTR_REF]],
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
+// CHECK: br label %[[VEC_PRIV_INIT:.+]]
+// CHECK: [[VEC_PRIV_INIT]]
+// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
+// CHECK: br label %[[VEC_PRIV_INIT_END:.+]]
+// CHECK: [[VEC_PRIV_INIT_END]]
+// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_FLOAT_TY]]]** [[S_ARR_REF_PTR]],
+// CHECK: br label %[[S_ARR_PRIV_INIT:.+]]
+// CHECK: [[S_ARR_PRIV_INIT]]
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
+// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
+// CHECK: [[S_ARR_BODY]]
+// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_CONSTR:@.+]]([[S_FLOAT_TY]]* {{.+}}, [[S_FLOAT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call {{.*}} [[ST_TY_DESTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
+// CHECK: br label %[[S_ARR_PRIV_INIT_END:.+]]
+// CHECK: [[S_ARR_PRIV_INIT_END]]
+// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[VAR_REF:%.+]] = load [[S_FLOAT_TY]]** [[VAR_REF_PTR]],
+// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]], [[S_FLOAT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
+// CHECK: ret void
+
+// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
+// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}** [[T_VAR_PTR_REF]],
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
+// CHECK: br label %[[VEC_PRIV_INIT:.+]]
+// CHECK: [[VEC_PRIV_INIT]]
+// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
+// CHECK: br label %[[VEC_PRIV_INIT_END:.+]]
+// CHECK: [[VEC_PRIV_INIT_END]]
+// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_INT_TY]]]** [[S_ARR_REF_PTR]],
+// CHECK: br label %[[S_ARR_PRIV_INIT:.+]]
+// CHECK: [[S_ARR_PRIV_INIT]]
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_INT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
+// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
+// CHECK: [[S_ARR_BODY]]
+// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call {{.*}} [[S_INT_TY_COPY_CONSTR:@.+]]([[S_INT_TY]]* {{.+}}, [[S_INT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
+// CHECK: br label %[[S_ARR_PRIV_INIT_END:.+]]
+// CHECK: [[S_ARR_PRIV_INIT_END]]
+// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[VAR_REF:%.+]] = load [[S_INT_TY]]** [[VAR_REF_PTR]],
+// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call {{.*}} [[S_INT_TY_COPY_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]], [[S_INT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]*
+// CHECK: ret void
+#endif
+
diff --git a/test/OpenMP/parallel_firstprivate_messages.cpp b/test/OpenMP/parallel_firstprivate_messages.cpp
index 9df45c60e708..7d1e3593500e 100644
--- a/test/OpenMP/parallel_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_firstprivate_messages.cpp
@@ -13,7 +13,7 @@ class S2 {
mutable int a;
public:
S2():a(0) { }
- S2(S2 &s2):a(s2.a) { }
+ S2(const S2 &s2):a(s2.a) { }
static float S2s;
static const float S2sc;
};
@@ -24,22 +24,22 @@ class S3 {
int a;
public:
S3():a(0) { }
- S3(S3 &s3):a(s3.a) { }
+ S3(const S3 &s3):a(s3.a) { }
};
const S3 c;
const S3 ca[5];
extern const int f;
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4(const S4 &s4);
+ S4(const S4 &s4); // expected-note {{implicitly declared private here}}
public:
S4(int v):a(v) { }
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
S5():a(0) {}
- S5(const S5 &s5):a(s5.a) { }
+ S5(const S5 &s5):a(s5.a) { } // expected-note {{implicitly declared private here}}
public:
S5(int v):a(v) { }
};
@@ -50,8 +50,8 @@ S3 h;
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = { 0 };
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel firstprivate // expected-error {{expected '(' after 'firstprivate'}}
@@ -69,7 +69,7 @@ int main(int argc, char **argv) {
#pragma omp parallel firstprivate(da)
#pragma omp parallel firstprivate(S2::S2s)
#pragma omp parallel firstprivate(S2::S2sc)
- #pragma omp parallel firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+ #pragma omp parallel firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
#pragma omp parallel firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
#pragma omp parallel private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
foo();
diff --git a/test/OpenMP/parallel_for_firstprivate_messages.cpp b/test/OpenMP/parallel_for_firstprivate_messages.cpp
index 99dd68f3cbfa..b4958733deca 100644
--- a/test/OpenMP/parallel_for_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
public:
S2() : a(0) {}
- S2(S2 &s2) : a(s2.a) {}
+ S2(const S2 &s2) : a(s2.a) {}
static float S2s;
static const float S2sc;
};
@@ -27,22 +27,22 @@ class S3 {
public:
S3() : a(0) {}
- S3(S3 &s3) : a(s3.a) {}
+ S3(const S3 &s3) : a(s3.a) {}
};
const S3 c;
const S3 ca[5];
extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4(const S4 &s4);
+ S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
int a;
- S5(const S5 &s5) : a(s5.a) {}
+ S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
public:
S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- C g(5); // expected-note 2 {{'g' defined here}}
+ I e(4);
+ C g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel for firstprivate // expected-error {{expected '(' after 'firstprivate'}}
@@ -96,7 +96,7 @@ int foomain(int argc, char **argv) {
#pragma omp parallel for firstprivate(argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp parallel for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel for firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
@@ -123,7 +123,7 @@ int foomain(int argc, char **argv) {
#pragma omp parallel for firstprivate(i)
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel private(i)
@@ -140,8 +140,8 @@ int foomain(int argc, char **argv) {
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note 2 {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
S3 m;
S6 n(2);
int i;
@@ -201,7 +201,7 @@ int main(int argc, char **argv) {
#pragma omp parallel for safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp parallel for'}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for firstprivate(m) // OK
@@ -223,7 +223,7 @@ int main(int argc, char **argv) {
#pragma omp parallel for firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for lastprivate(n) firstprivate(n) // OK
diff --git a/test/OpenMP/parallel_for_loop_messages.cpp b/test/OpenMP/parallel_for_loop_messages.cpp
index f029ef4d76cb..c3299976bd06 100644
--- a/test/OpenMP/parallel_for_loop_messages.cpp
+++ b/test/OpenMP/parallel_for_loop_messages.cpp
@@ -11,6 +11,7 @@ public:
static int sii;
#pragma omp threadprivate(sii) // expected-note {{defined as threadprivate or thread local}}
+static int globalii;
int test_iteration_spaces() {
const int N = 100;
@@ -263,6 +264,21 @@ int test_iteration_spaces() {
c[sii] = a[sii];
}
+ {
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp parallel for' directive may not be a variable with global storage without being explicitly marked as private}}
+#pragma omp parallel for
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] = a[globalii];
+ }
+
+ {
+// expected-error@+3 {{loop iteration variable in the associated loop of 'omp parallel for' directive may not be a variable with global storage without being explicitly marked as private}}
+#pragma omp parallel for collapse(2)
+ for (ii = 0; ii < 10; ii += 1)
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] += a[globalii] + ii;
+ }
+
// expected-error@+2 {{statement after '#pragma omp parallel for' must be a for loop}}
#pragma omp parallel for
for (auto &item : a) {
@@ -309,6 +325,8 @@ public:
Iter0 operator--() { return *this; }
bool operator<(Iter0 a) { return true; }
};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'Iter0' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'Iter0' for 1st argument}}
int operator-(Iter0 a, Iter0 b) { return 0; }
class Iter1 {
public:
@@ -327,6 +345,7 @@ public:
GoodIter &operator=(const GoodIter &that) { return *this; }
GoodIter &operator=(const Iter0 &that) { return *this; }
GoodIter &operator+=(int x) { return *this; }
+ GoodIter &operator-=(int x) { return *this; }
explicit GoodIter(void *) {}
GoodIter operator++() { return *this; }
GoodIter operator--() { return *this; }
@@ -337,11 +356,20 @@ public:
typedef int difference_type;
typedef std::random_access_iterator_tag iterator_category;
};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'const Iter0' to 'GoodIter' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
int operator-(GoodIter a, GoodIter b) { return 0; }
+// expected-note@+1 3 {{candidate function not viable: requires single argument 'a', but 2 arguments were provided}}
GoodIter operator-(GoodIter a) { return a; }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'const Iter0' to 'int' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
GoodIter operator-(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'GoodIter' for 1st argument}}
GoodIter operator+(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'int' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'int' for 1st argument}}
GoodIter operator-(int v, GoodIter a) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'int' for 1st argument}}
GoodIter operator+(int v, GoodIter a) { return GoodIter(); }
int test_with_random_access_iterator() {
@@ -376,6 +404,8 @@ int test_with_random_access_iterator() {
#pragma omp parallel for
for (begin = GoodIter(0); begin < end; ++begin)
++begin;
+// expected-error@+3 {{invalid operands to binary expression ('GoodIter' and 'const Iter0')}}
+// expected-error@+2 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
#pragma omp parallel for
for (begin = begin0; begin < end; ++begin)
++begin;
@@ -419,15 +449,19 @@ int test_with_random_access_iterator() {
#pragma omp parallel for
for (GoodIter I = begin; I >= end; I = 2 - I)
++I;
+// expected-error@+2 {{invalid operands to binary expression ('Iter0' and 'int')}}
#pragma omp parallel for
for (Iter0 I = begin0; I < end0; ++I)
++I;
// Initializer is constructor without params.
+// expected-error@+3 {{invalid operands to binary expression ('Iter0' and 'int')}}
// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
#pragma omp parallel for
for (Iter0 I; I < end0; ++I)
++I;
Iter1 begin1, end1;
+// expected-error@+3 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+// expected-error@+2 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
#pragma omp parallel for
for (Iter1 I = begin1; I < end1; ++I)
++I;
@@ -436,6 +470,8 @@ int test_with_random_access_iterator() {
#pragma omp parallel for
for (Iter1 I = begin1; I >= end1; ++I)
++I;
+// expected-error@+5 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+// expected-error@+4 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
// Initializer is constructor with all default params.
// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
#pragma omp parallel for
diff --git a/test/OpenMP/parallel_for_misc_messages.c b/test/OpenMP/parallel_for_misc_messages.c
index b236a613c319..f07a0f2a4c4c 100644
--- a/test/OpenMP/parallel_for_misc_messages.c
+++ b/test/OpenMP/parallel_for_misc_messages.c
@@ -165,6 +165,17 @@ void test_collapse() {
#pragma omp parallel for collapse(5 - 5)
for (i = 0; i < 16; ++i)
;
+// expected-note@+1 {{defined as firstprivate}}
+#pragma omp parallel for collapse(2) firstprivate(i)
+ for (i = 0; i < 16; ++i)
+// expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}}
+ for (int j = 0; j < 16; ++j)
+// expected-error@+3 {{reduction variable must be shared}}
+// expected-error@+2 {{private variable cannot be reduction}}
+// expected-error@+1 {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp for' directive into a parallel region?}}
+#pragma omp for reduction(+ : i, j)
+ for (int k = 0; k < 16; ++k)
+ i += j;
}
void test_private() {
diff --git a/test/OpenMP/parallel_for_private_messages.cpp b/test/OpenMP/parallel_for_private_messages.cpp
index 7366fe8c47c5..31b84588de0b 100644
--- a/test/OpenMP/parallel_for_private_messages.cpp
+++ b/test/OpenMP/parallel_for_private_messages.cpp
@@ -24,16 +24,16 @@ public:
S3() : a(0) {}
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -109,8 +109,8 @@ int foomain(I argc, C **argv) {
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel for private // expected-error {{expected '(' after 'private'}}
@@ -143,7 +143,7 @@ int main(int argc, char **argv) {
#pragma omp parallel for private(argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp parallel for private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp parallel for private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel for private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
diff --git a/test/OpenMP/parallel_for_simd_aligned_messages.cpp b/test/OpenMP/parallel_for_simd_aligned_messages.cpp
new file mode 100644
index 000000000000..ea4ec21f28a9
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_aligned_messages.cpp
@@ -0,0 +1,202 @@
+// RUN: %clang_cc1 -x c++ -std=c++11 -verify -fopenmp=libiomp5 %s
+
+struct B {
+ static int ib[20]; // expected-note 0 {{'B::ib' declared here}}
+ static constexpr int bfoo() { return 8; }
+};
+namespace X {
+ B x; // expected-note {{'x' defined here}}
+};
+constexpr int bfoo() { return 4; }
+
+int **z;
+const int C1 = 1;
+const int C2 = 2;
+void test_aligned_colons(int *&rp)
+{
+ int *B = 0;
+ #pragma omp parallel for simd aligned(B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'}}
+ #pragma omp parallel for simd aligned(B::ib:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp parallel for simd aligned(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'?}}
+ #pragma omp parallel for simd aligned(z:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp parallel for simd aligned(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+2 {{integral constant expression must have integral or unscoped enumeration type, not 'int **'}}
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'B'}}
+ #pragma omp parallel for simd aligned(X::x : ::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'B'}}
+ #pragma omp parallel for simd aligned(B,rp,::z: X::x)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp parallel for simd aligned(::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp parallel for simd aligned(B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-warning@+1 {{aligned clause will be ignored because the requested alignment is not a power of 2}}
+ #pragma omp parallel for simd aligned(B::ib,B:C1+C2)
+ for (int i = 0; i < 10; ++i) ;
+}
+
+// expected-note@+1 {{'num' defined here}}
+template<int L, class T, class N> T test_template(T* arr, N num) {
+ N i;
+ T sum = (T)0;
+ T ind2 = - num * L;
+ // Negative number is passed as L.
+ // expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
+ #pragma omp parallel for simd aligned(arr:L)
+ for (i = 0; i < num; ++i) {
+ T cur = arr[(int)ind2];
+ ind2 += L;
+ sum += cur;
+ }
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp parallel for simd aligned(num:4)
+ for (i = 0; i < num; ++i);
+ return T();
+}
+
+template<int LEN> int test_warn() {
+ int *ind2 = 0;
+ // expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
+ #pragma omp parallel for simd aligned(ind2:LEN)
+ for (int i = 0; i < 100; i++) {
+ ind2 += LEN;
+ }
+ return 0;
+}
+
+struct S1; // expected-note 2 {{declared here}}
+extern S1 a; // expected-note {{'a' declared here}}
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+};
+const S2 b; // expected-note 1 {{'b' defined here}}
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4();
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h; // expected-note 2 {{'h' defined here}}
+#pragma omp threadprivate(h)
+
+template<class I, class C> int foomain(I argc, C **argv) {
+ I e(argc);
+ I g(argc);
+ int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
+ // expected-note@+2 {{declared here}}
+ // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int &j = i;
+ #pragma omp parallel for simd aligned // expected-error {{expected '(' after 'aligned'}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned () // expected-error {{expected expression}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned (argc : 5) // expected-warning {{aligned clause will be ignored because the requested alignment is not a power of 2}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned (S1) // expected-error {{'S1' does not refer to a value}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned (argv[1]) // expected-error {{expected variable name}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned(e, g)
+ for (I k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S3'}}
+ #pragma omp parallel for simd aligned(h)
+ for (I k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp parallel for simd aligned(i)
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int *v = 0;
+ I i;
+ #pragma omp parallel for simd aligned(v:16)
+ for (I k = 0; k < argc; ++k) { i = k; v += 2; }
+ }
+ float *f;
+ #pragma omp parallel for simd aligned(f)
+ for (I k = 0; k < argc; ++k) ++k;
+ int v = 0;
+ // expected-note@+2 {{initializer of 'j' is not a constant expression}}
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp parallel for simd aligned(f:j)
+ for (I k = 0; k < argc; ++k) { ++k; v += j; }
+ #pragma omp parallel for simd aligned(f)
+ for (I k = 0; k < argc; ++k) ++k;
+ return 0;
+}
+
+// expected-note@+1 2 {{'argc' defined here}}
+int main(int argc, char **argv) {
+ double darr[100];
+ // expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
+ test_template<-4>(darr, 4);
+ test_warn<4>(); // ok
+ // expected-note@+1 {{in instantiation of function template specialization 'test_warn<0>' requested here}}
+ test_warn<0>();
+
+ int i;
+ int &j = i;
+ #pragma omp parallel for simd aligned // expected-error {{expected '(' after 'aligned'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned (argv // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp parallel for simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp parallel for simd aligned (argc)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S1'}}
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S2'}}
+ #pragma omp parallel for simd aligned (a, b)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd aligned (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S3'}}
+ #pragma omp parallel for simd aligned(h)
+ for (int k = 0; k < argc; ++k) ++k;
+ int *pargc = &argc;
+ foomain<int*,char>(pargc,argv);
+ return 0;
+}
+
diff --git a/test/OpenMP/parallel_for_simd_ast_print.cpp b/test/OpenMP/parallel_for_simd_ast_print.cpp
new file mode 100644
index 000000000000..4192695cf037
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_ast_print.cpp
@@ -0,0 +1,128 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void foo() {}
+int g_ind = 1;
+template<class T, class N> T reduct(T* arr, N num) {
+ N i;
+ N ind;
+ N myind;
+ T sum = (T)0;
+// CHECK: T sum = (T)0;
+#pragma omp parallel for simd private(myind, g_ind), linear(ind), aligned(arr)
+// CHECK-NEXT: #pragma omp parallel for simd private(myind,g_ind) linear(ind) aligned(arr)
+ for (i = 0; i < num; ++i) {
+ myind = ind;
+ T cur = arr[myind];
+ ind += g_ind;
+ sum += cur;
+ }
+}
+
+template<class T> struct S {
+ S(const T &a)
+ :m_a(a)
+ {}
+ T result(T *v) const {
+ T res;
+ T val;
+ T lin = 0;
+// CHECK: T res;
+// CHECK: T val;
+// CHECK: T lin = 0;
+ #pragma omp parallel for simd private(val) safelen(7) linear(lin : -5) lastprivate(res)
+// CHECK-NEXT: #pragma omp parallel for simd private(val) safelen(7) linear(lin: -5) lastprivate(res)
+ for (T i = 7; i < m_a; ++i) {
+ val = v[i-7] + m_a;
+ res = val;
+ lin -= 5;
+ }
+ const T clen = 3;
+// CHECK: T clen = 3;
+ #pragma omp parallel for simd safelen(clen-1)
+// CHECK-NEXT: #pragma omp parallel for simd safelen(clen - 1)
+ for(T i = clen+2; i < 20; ++i) {
+// CHECK-NEXT: for (T i = clen + 2; i < 20; ++i) {
+ v[i] = v[v-clen] + 1;
+// CHECK-NEXT: v[i] = v[v - clen] + 1;
+ }
+// CHECK-NEXT: }
+ return res;
+ }
+ ~S()
+ {}
+ T m_a;
+};
+
+template<int LEN> struct S2 {
+ static void func(int n, float *a, float *b, float *c) {
+ int k1 = 0, k2 = 0;
+#pragma omp parallel for simd safelen(LEN) linear(k1,k2:LEN) aligned(a:LEN)
+ for(int i = 0; i < n; i++) {
+ c[i] = a[i] + b[i];
+ c[k1] = a[k1] + b[k1];
+ c[k2] = a[k2] + b[k2];
+ k1 = k1 + LEN;
+ k2 = k2 + LEN;
+ }
+ }
+};
+
+// S2<4>::func is called below in main.
+// CHECK: template <int LEN = 4> struct S2 {
+// CHECK-NEXT: static void func(int n, float *a, float *b, float *c) {
+// CHECK-NEXT: int k1 = 0, k2 = 0;
+// CHECK-NEXT: #pragma omp parallel for simd safelen(4) linear(k1,k2: 4) aligned(a: 4)
+// CHECK-NEXT: for (int i = 0; i < n; i++) {
+// CHECK-NEXT: c[i] = a[i] + b[i];
+// CHECK-NEXT: c[k1] = a[k1] + b[k1];
+// CHECK-NEXT: c[k2] = a[k2] + b[k2];
+// CHECK-NEXT: k1 = k1 + 4;
+// CHECK-NEXT: k2 = k2 + 4;
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+
+int main (int argc, char **argv) {
+ int b = argc, c, d, e, f, g;
+ int k1=0,k2=0;
+ static int *a;
+// CHECK: static int *a;
+#pragma omp parallel for simd
+// CHECK-NEXT: #pragma omp parallel for simd
+ for (int i=0; i < 2; ++i)*a=2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: *a = 2;
+#pragma omp parallel
+#pragma omp parallel for simd private(argc, b),lastprivate(d,f) collapse(2) aligned(a : 4) ,firstprivate( g )
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;}
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: #pragma omp parallel for simd private(argc,b) lastprivate(d,f) collapse(2) aligned(a: 4) firstprivate(g)
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: for (int j = 0; j < 10; ++j) {
+// CHECK-NEXT: foo();
+// CHECK-NEXT: k1 += 8;
+// CHECK-NEXT: k2 += 8;
+// CHECK-NEXT: }
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+ const int CLEN = 4;
+// CHECK-NEXT: const int CLEN = 4;
+ #pragma omp parallel for simd aligned(a:CLEN) linear(a:CLEN) safelen(CLEN) collapse( 1 )
+// CHECK-NEXT: #pragma omp parallel for simd aligned(a: CLEN) linear(a: CLEN) safelen(CLEN) collapse(1)
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+
+ float arr[16];
+ S2<4>::func(0,arr,arr,arr);
+ return (0);
+}
+
+#endif
diff --git a/test/OpenMP/parallel_for_simd_collapse_messages.cpp b/test/OpenMP/parallel_for_simd_collapse_messages.cpp
new file mode 100644
index 000000000000..b829497e17f3
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_collapse_messages.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
+ #pragma omp parallel for simd collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd collapse () // expected-error {{expected expression}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+ // expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ #pragma omp parallel for simd collapse (argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp parallel for simd collapse (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp parallel for simd', but found only 1}}
+ // expected-error@+3 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'collapse' clause}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp parallel for simd collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd collapse (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp parallel for simd collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd collapse (1)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd collapse (N) // expected-error {{argument to 'collapse' clause must be a positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd collapse (2) // expected-note {{as specified in 'collapse' clause}}
+ foo(); // expected-error {{expected 2 for loops after '#pragma omp parallel for simd'}}
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp parallel for simd collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd collapse () // expected-error {{expected expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd collapse (4 // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{as specified in 'collapse' clause}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp parallel for simd', but found only 1}}
+ #pragma omp parallel for simd collapse (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} expected-note {{as specified in 'collapse' clause}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp parallel for simd', but found only 1}}
+ #pragma omp parallel for simd collapse (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{expression is not an integral constant expression}}
+ // expected-error@+2 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'collapse' clause}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp parallel for simd collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd collapse (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp parallel for simd collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp parallel for simd' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp parallel for simd collapse(collapse(tmain<int, char, -1, -2>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ foo();
+ #pragma omp parallel for simd collapse (2) // expected-note {{as specified in 'collapse' clause}}
+ foo(); // expected-error {{expected 2 for loops after '#pragma omp parallel for simd'}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
+ return tmain<int, char, 1, 0>(argc, argv);
+}
+
diff --git a/test/OpenMP/parallel_for_simd_copyin_messages.cpp b/test/OpenMP/parallel_for_simd_copyin_messages.cpp
new file mode 100644
index 000000000000..e0b7e6354ebb
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_copyin_messages.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2 &operator=(S2 &s2) { return *this; }
+};
+class S3 {
+ int a;
+
+public:
+ S3() : a(0) {}
+ S3 &operator=(S3 &s3) { return *this; }
+};
+class S4 { // expected-note {{'S4' declared here}}
+ int a;
+ S4();
+ S4 &operator=(const S4 &s4);
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 { // expected-note {{'S5' declared here}}
+ int a;
+ S5() : a(0) {}
+ S5 &operator=(const S5 &s5) { return *this; }
+
+public:
+ S5(int v) : a(v) {}
+};
+template <class T>
+class ST {
+public:
+ static T s;
+};
+
+S2 k;
+S3 h;
+S4 l(3); // expected-note {{'l' defined here}}
+S5 m(4); // expected-note {{'m' defined here}}
+#pragma omp threadprivate(h, k, l, m)
+
+int main(int argc, char **argv) {
+ int i;
+#pragma omp parallel for simd copyin // expected-error {{expected '(' after 'copyin'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin() // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin(k // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin(h, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin(l) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin(S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin(argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin(i) // expected-error {{copyin variable must be threadprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin(m) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd copyin(ST < int > ::s) // expected-error {{copyin variable must be threadprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+
+ return 0;
+}
diff --git a/test/OpenMP/parallel_for_simd_default_messages.cpp b/test/OpenMP/parallel_for_simd_default_messages.cpp
new file mode 100644
index 000000000000..6675029abe50
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_default_messages.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -o - %s
+
+void foo();
+
+int main(int argc, char **argv) {
+ int i;
+#pragma omp parallel for simd default // expected-error {{expected '(' after 'default'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd default( // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd default() // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd default(none // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}}
+ foo();
+#pragma omp parallel for simd default(shared), default(shared) // expected-error {{directive '#pragma omp parallel for simd' cannot contain more than one 'default' clause}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd default(x) // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+
+#pragma omp parallel for simd default(none)
+ for (i = 0; i < argc; ++i) // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}}
+ foo();
+
+#pragma omp parallel default(none)
+#pragma omp parallel for simd default(shared)
+ for (i = 0; i < argc; ++i)
+ foo();
+
+ return 0;
+}
diff --git a/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp b/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp
new file mode 100644
index 000000000000..876d422e634d
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp
@@ -0,0 +1,250 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2(const S2 &s2) : a(s2.a) {}
+ static float S2s;
+ static const float S2sc;
+};
+const float S2::S2sc = 0;
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+ S3 &operator=(const S3 &s3);
+
+public:
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 {
+ int a;
+ S4();
+ S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
+
+public:
+ S5() : a(0) {}
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+ S6() : a(0) {}
+
+public:
+ S6(const S6 &s6) : a(s6.a) {}
+ S6(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(int argc, char **argv) {
+ I e(4);
+ C g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp parallel for simd firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate(a, b) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd linear(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ {
+ int v = 0;
+ int i;
+#pragma omp parallel for simd firstprivate(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp parallel for simd firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd firstprivate(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel private(i)
+#pragma omp parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel reduction(+ : i)
+#pragma omp parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5;
+ const int da[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ S3 m;
+ S6 n(2);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp parallel for simd firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate() // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(argc)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(2 * 2) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(ba) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(ca) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(da) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+ int xa;
+#pragma omp parallel for simd firstprivate(xa) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(S2::S2s) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(S2::S2sc) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd safelen(5)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(m) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd private(xa), firstprivate(xa) // expected-error {{private variable cannot be firstprivate}} expected-note {{defined as private}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel for simd firstprivate(xa) // OK: may be firstprivate
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(n) firstprivate(n) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp parallel for simd firstprivate(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel private(i)
+#pragma omp parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel reduction(+ : i)
+#pragma omp parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+
+ return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
+}
diff --git a/test/OpenMP/parallel_for_simd_if_messages.cpp b/test/OpenMP/parallel_for_simd_if_messages.cpp
new file mode 100644
index 000000000000..b91dd18635bd
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_if_messages.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+ T i;
+ #pragma omp parallel for simd if // expected-error {{expected '(' after 'if'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if () // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (argc > 0 ? argv[1] : argv[2])
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp parallel for simd' cannot contain more than one 'if' clause}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (S) // expected-error {{'S' does not refer to a value}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if(argc)
+ for (i = 0; i < argc; ++i) foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int i;
+ #pragma omp parallel for simd if // expected-error {{expected '(' after 'if'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if () // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (argc > 0 ? argv[1] : argv[2])
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp parallel for simd' cannot contain more than one 'if' clause}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd if(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp b/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
new file mode 100644
index 000000000000..b620c7fc010b
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
@@ -0,0 +1,226 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
+ static const float S2sc;
+};
+const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const S2 b;
+const S2 ba[5];
+class S3 { // expected-note 2 {{'S3' declared here}}
+ int a;
+ S3 &operator=(const S3 &s3);
+
+public:
+ S3() : a(0) {}
+ S3(S3 &s3) : a(s3.a) {}
+};
+const S3 c; // expected-note {{global variable is predetermined as shared}}
+const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
+extern const int f; // expected-note {{global variable is predetermined as shared}}
+class S4 { // expected-note 3 {{'S4' declared here}}
+ int a;
+ S4();
+ S4(const S4 &s4);
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 { // expected-note {{'S5' declared here}}
+ int a;
+ S5() : a(0) {}
+
+public:
+ S5(const S5 &s5) : a(s5.a) {}
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+ S6() : a(0) {}
+
+public:
+ S6(const S6 &s6) : a(s6.a) {}
+ S6(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(int argc, char **argv) {
+ I e(4); // expected-note {{'e' defined here}}
+ I g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp parallel for simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(a, b) // expected-error {{lastprivate variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd linear(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp parallel for simd lastprivate(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp parallel for simd lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd lastprivate(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note {{constant variable is predetermined as shared}}
+ const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ S3 m; // expected-note 2 {{'m' defined here}}
+ S6 n(2);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp parallel for simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate() // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(argc)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(2 * 2) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(ba)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(da) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+ int xa;
+#pragma omp parallel for simd lastprivate(xa) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd safelen(5)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd private(xa), lastprivate(xa) // expected-error {{private variable cannot be lastprivate}} expected-note {{defined as private}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(i) // expected-note {{defined as lastprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be lastprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel private(xa)
+#pragma omp parallel for simd lastprivate(xa)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel reduction(+ : xa)
+#pragma omp parallel for simd lastprivate(xa)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd firstprivate(m) lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd lastprivate(n) firstprivate(n) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+ return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
+}
diff --git a/test/OpenMP/parallel_for_simd_linear_messages.cpp b/test/OpenMP/parallel_for_simd_linear_messages.cpp
new file mode 100644
index 000000000000..3918de2681db
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_linear_messages.cpp
@@ -0,0 +1,206 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+namespace X {
+ int x;
+};
+
+struct B {
+ static int ib; // expected-note {{'B::ib' declared here}}
+ static int bfoo() { return 8; }
+};
+
+int bfoo() { return 4; }
+
+int z;
+const int C1 = 1;
+const int C2 = 2;
+void test_linear_colons()
+{
+ int B = 0;
+ #pragma omp parallel for simd linear(B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'}}
+ #pragma omp parallel for simd linear(B::ib:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{use of undeclared identifier 'ib'; did you mean 'B::ib'}}
+ #pragma omp parallel for simd linear(B:ib)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'?}}
+ #pragma omp parallel for simd linear(z:B:ib)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp parallel for simd linear(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp parallel for simd linear(X::x : ::z)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp parallel for simd linear(B,::z, X::x)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp parallel for simd linear(::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp parallel for simd linear(B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp parallel for simd linear(B::ib,B:C1+C2)
+ for (int i = 0; i < 10; ++i) ;
+}
+
+template<int L, class T, class N> T test_template(T* arr, N num) {
+ N i;
+ T sum = (T)0;
+ T ind2 = - num * L; // expected-note {{'ind2' defined here}}
+ // expected-error@+1 {{argument of a linear clause should be of integral or pointer type}}
+#pragma omp parallel for simd linear(ind2:L)
+ for (i = 0; i < num; ++i) {
+ T cur = arr[(int)ind2];
+ ind2 += L;
+ sum += cur;
+ }
+ return T();
+}
+
+template<int LEN> int test_warn() {
+ int ind2 = 0;
+ // expected-warning@+1 {{zero linear step (ind2 should probably be const)}}
+ #pragma omp parallel for simd linear(ind2:LEN)
+ for (int i = 0; i < 100; i++) {
+ ind2 += LEN;
+ }
+ return ind2;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+};
+const S2 b; // expected-note 2 {{'b' defined here}}
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4();
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template<class I, class C> int foomain(I argc, C **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp parallel for simd linear // expected-error {{expected '(' after 'linear'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (argc : 5)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{linear variable with incomplete type 'S1'}}
+ // expected-error@+1 {{const-qualified variable cannot be linear}}
+ #pragma omp parallel for simd linear (a, b:B::ib)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear(e, g)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int v = 0;
+ int i;
+ #pragma omp parallel for simd linear(v:i)
+ for (int k = 0; k < argc; ++k) { i = k; v += i; }
+ }
+ #pragma omp parallel for simd linear(j) // expected-error {{arguments of OpenMP clause 'linear' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k) ++k;
+ int v = 0;
+ #pragma omp parallel for simd linear(v:j)
+ for (int k = 0; k < argc; ++k) { ++k; v += j; }
+ #pragma omp parallel for simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ double darr[100];
+ // expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
+ test_template<-4>(darr, 4);
+ // expected-note@+1 {{in instantiation of function template specialization 'test_warn<0>' requested here}}
+ test_warn<0>();
+
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp parallel for simd linear // expected-error {{expected '(' after 'linear'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (argc)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{linear variable with incomplete type 'S1'}}
+ // expected-error@+1 {{const-qualified variable cannot be linear}}
+ #pragma omp parallel for simd linear (a, b)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{argument of a linear clause should be of integral or pointer type, not 'S4'}}
+ // expected-error@+1 {{argument of a linear clause should be of integral or pointer type, not 'S5'}}
+ #pragma omp parallel for simd linear(e, g)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int i;
+ #pragma omp parallel for simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear(i : 4)
+ for (int k = 0; k < argc; ++k) { ++k; i += 4; }
+ }
+ #pragma omp parallel for simd linear(j) // expected-error {{arguments of OpenMP clause 'linear' cannot be of reference type 'int &'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel for simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+
+ foomain<int,char>(argc,argv);
+ return 0;
+}
+
diff --git a/test/OpenMP/parallel_for_simd_loop_messages.cpp b/test/OpenMP/parallel_for_simd_loop_messages.cpp
new file mode 100644
index 000000000000..50acb10feed9
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_loop_messages.cpp
@@ -0,0 +1,644 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -x c++ -std=c++11 -fexceptions -fcxx-exceptions -verify %s
+
+class S {
+ int a;
+ S() : a(0) {}
+
+public:
+ S(int v) : a(v) {}
+ S(const S &s) : a(s.a) {}
+};
+
+static int sii;
+#pragma omp threadprivate(sii) // expected-note {{defined as threadprivate or thread local}}
+static int globalii;
+
+int test_iteration_spaces() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+ int ii, jj, kk;
+ float fii;
+ double dii;
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; i += 1) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel for simd
+ for (char i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel for simd
+ for (char i = 0; i < 10; i += '\1') {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel for simd
+ for (long long i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ }
+// expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'double'}}
+#pragma omp parallel for simd
+ for (long long i = 0; i < 10; i += 1.5) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel for simd
+ for (long long i = 0; i < 'z'; i += 1u) {
+ c[i] = a[i] + b[i];
+ }
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp parallel for simd
+ for (float fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp parallel for simd
+ for (double fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp parallel for simd
+ for (int &ref = ii; ref < 10; ref++) {
+ }
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp parallel for simd
+ for (int i; i < 10; i++)
+ c[i] = a[i];
+
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp parallel for simd
+ for (int i = 0, j = 0; i < 10; ++i)
+ c[i] = a[i];
+
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp parallel for simd
+ for (; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+// expected-warning@+3 {{expression result unused}}
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp parallel for simd
+ for (ii + 1; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp parallel for simd
+ for (c[ii] = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+// Ok to skip parenthesises.
+#pragma omp parallel for simd
+ for (((ii)) = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp parallel for simd
+ for (int i = 0; i; i++)
+ c[i] = a[i];
+
+// expected-error@+3 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'i'}}
+#pragma omp parallel for simd
+ for (int i = 0; jj < kk; ii++)
+ c[i] = a[i];
+
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp parallel for simd
+ for (int i = 0; !!i; i++)
+ c[i] = a[i];
+
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp parallel for simd
+ for (int i = 0; i != 1; i++)
+ c[i] = a[i];
+
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp parallel for simd
+ for (int i = 0;; i++)
+ c[i] = a[i];
+
+// Ok.
+#pragma omp parallel for simd
+ for (int i = 11; i > 10; i--)
+ c[i] = a[i];
+
+// Ok.
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ c[i] = a[i];
+
+// Ok.
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; ++jj)
+ c[ii] = a[jj];
+
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; ++++ii)
+ c[ii] = a[ii];
+
+// Ok but undefined behavior (in general, cannot check that incr
+// is really loop-invariant).
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; ii = ii + ii)
+ c[ii] = a[ii];
+
+// expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'float'}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; ii = ii + 1.0f)
+ c[ii] = a[ii];
+
+// Ok - step was converted to integer type.
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; ii = ii + (int)1.1f)
+ c[ii] = a[ii];
+
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; jj = ii + 2)
+ c[ii] = a[ii];
+
+// expected-warning@+3 {{relational comparison result unused}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp parallel for simd
+ for (ii = 0; ii<10; jj> kk + 2)
+ c[ii] = a[ii];
+
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10;)
+ c[ii] = a[ii];
+
+// expected-warning@+3 {{expression result unused}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; !ii)
+ c[ii] = a[ii];
+
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; ii ? ++ii : ++jj)
+ c[ii] = a[ii];
+
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; ii = ii < 10)
+ c[ii] = a[ii];
+
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; ii = ii + 0)
+ c[ii] = a[ii];
+
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; ii = ii + (int)(0.8 - 0.45))
+ c[ii] = a[ii];
+
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (ii = 0; (ii) < 10; ii -= 25)
+ c[ii] = a[ii];
+
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (ii = 0; (ii < 10); ii -= 0)
+ c[ii] = a[ii];
+
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (ii = 0; ii > 10; (ii += 0))
+ c[ii] = a[ii];
+
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (ii = 0; ii < 10; (ii) = (1 - 1) + (ii))
+ c[ii] = a[ii];
+
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for ((ii = 0); ii > 10; (ii -= 0))
+ c[ii] = a[ii];
+
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (ii = 0; (ii < 10); (ii -= 0))
+ c[ii] = a[ii];
+
+// expected-note@+2 {{defined as firstprivate}}
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be firstprivate, predetermined as linear}}
+#pragma omp parallel for simd firstprivate(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel for simd linear(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+// expected-note@+2 {{defined as private}}
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be private, predetermined as linear}}
+#pragma omp parallel for simd private(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+// expected-note@+2 {{defined as lastprivate}}
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be lastprivate, predetermined as linear}}
+#pragma omp parallel for simd lastprivate(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+ {
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be threadprivate or thread local, predetermined as linear}}
+#pragma omp parallel for simd
+ for (sii = 0; sii < 10; sii += 1)
+ c[sii] = a[sii];
+ }
+
+ {
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be a variable with global storage without being explicitly marked as linear}}
+#pragma omp parallel for simd
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] = a[globalii];
+ }
+
+ {
+// expected-error@+3 {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be a variable with global storage without being explicitly marked as lastprivate}}
+#pragma omp parallel for simd collapse(2)
+ for (ii = 0; ii < 10; ii += 1)
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] += a[globalii] + ii;
+ }
+
+// expected-error@+2 {{statement after '#pragma omp parallel for simd' must be a for loop}}
+#pragma omp parallel for simd
+ for (auto &item : a) {
+ item = item + 1;
+ }
+
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'i' to increase on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (unsigned i = 9; i < 10; i--) {
+ c[i] = a[i] + b[i];
+ }
+
+ int(*lb)[4] = nullptr;
+#pragma omp parallel for simd
+ for (int(*p)[4] = lb; p < lb + 8; ++p) {
+ }
+
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp parallel for simd
+ for (int a{0}; a < 10; ++a) {
+ }
+
+ return 0;
+}
+
+// Iterators allowed in openmp for-loops.
+namespace std {
+struct random_access_iterator_tag {};
+template <class Iter>
+struct iterator_traits {
+ typedef typename Iter::difference_type difference_type;
+ typedef typename Iter::iterator_category iterator_category;
+};
+template <class Iter>
+typename iterator_traits<Iter>::difference_type
+distance(Iter first, Iter last) { return first - last; }
+}
+class Iter0 {
+public:
+ Iter0() {}
+ Iter0(const Iter0 &) {}
+ Iter0 operator++() { return *this; }
+ Iter0 operator--() { return *this; }
+ bool operator<(Iter0 a) { return true; }
+};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'Iter0' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'Iter0' for 1st argument}}
+int operator-(Iter0 a, Iter0 b) { return 0; }
+class Iter1 {
+public:
+ Iter1(float f = 0.0f, double d = 0.0) {}
+ Iter1(const Iter1 &) {}
+ Iter1 operator++() { return *this; }
+ Iter1 operator--() { return *this; }
+ bool operator<(Iter1 a) { return true; }
+ bool operator>=(Iter1 a) { return false; }
+};
+class GoodIter {
+public:
+ GoodIter() {}
+ GoodIter(const GoodIter &) {}
+ GoodIter(int fst, int snd) {}
+ GoodIter &operator=(const GoodIter &that) { return *this; }
+ GoodIter &operator=(const Iter0 &that) { return *this; }
+ GoodIter &operator+=(int x) { return *this; }
+ explicit GoodIter(void *) {}
+ GoodIter operator++() { return *this; }
+ GoodIter operator--() { return *this; }
+ bool operator!() { return true; }
+ bool operator<(GoodIter a) { return true; }
+ bool operator<=(GoodIter a) { return true; }
+ bool operator>=(GoodIter a) { return false; }
+ typedef int difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'const Iter0' to 'GoodIter' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
+int operator-(GoodIter a, GoodIter b) { return 0; }
+// expected-note@+1 3 {{candidate function not viable: requires single argument 'a', but 2 arguments were provided}}
+GoodIter operator-(GoodIter a) { return a; }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'const Iter0' to 'int' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
+GoodIter operator-(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'GoodIter' for 1st argument}}
+GoodIter operator+(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'int' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'int' for 1st argument}}
+GoodIter operator-(int v, GoodIter a) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'int' for 1st argument}}
+GoodIter operator+(int v, GoodIter a) { return GoodIter(); }
+
+int test_with_random_access_iterator() {
+ GoodIter begin, end;
+ Iter0 begin0, end0;
+#pragma omp parallel for simd
+ for (GoodIter I = begin; I < end; ++I)
+ ++I;
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp parallel for simd
+ for (GoodIter &I = begin; I < end; ++I)
+ ++I;
+#pragma omp parallel for simd
+ for (GoodIter I = begin; I >= end; --I)
+ ++I;
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp parallel for simd
+ for (GoodIter I(begin); I < end; ++I)
+ ++I;
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp parallel for simd
+ for (GoodIter I(nullptr); I < end; ++I)
+ ++I;
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp parallel for simd
+ for (GoodIter I(0); I < end; ++I)
+ ++I;
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp parallel for simd
+ for (GoodIter I(1, 2); I < end; ++I)
+ ++I;
+#pragma omp parallel for simd
+ for (begin = GoodIter(0); begin < end; ++begin)
+ ++begin;
+// expected-error@+3 {{invalid operands to binary expression ('GoodIter' and 'const Iter0')}}
+// expected-error@+2 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+#pragma omp parallel for simd
+ for (begin = begin0; begin < end; ++begin)
+ ++begin;
+// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+#pragma omp parallel for simd
+ for (++begin; begin < end; ++begin)
+ ++begin;
+#pragma omp parallel for simd
+ for (begin = end; begin < end; ++begin)
+ ++begin;
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp parallel for simd
+ for (GoodIter I = begin; I - I; ++I)
+ ++I;
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp parallel for simd
+ for (GoodIter I = begin; begin < end; ++I)
+ ++I;
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp parallel for simd
+ for (GoodIter I = begin; !I; ++I)
+ ++I;
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (GoodIter I = begin; I >= end; I = I + 1)
+ ++I;
+#pragma omp parallel for simd
+ for (GoodIter I = begin; I >= end; I = I - 1)
+ ++I;
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+#pragma omp parallel for simd
+ for (GoodIter I = begin; I >= end; I = -I)
+ ++I;
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (GoodIter I = begin; I >= end; I = 2 + I)
+ ++I;
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+#pragma omp parallel for simd
+ for (GoodIter I = begin; I >= end; I = 2 - I)
+ ++I;
+// expected-error@+2 {{invalid operands to binary expression ('Iter0' and 'int')}}
+#pragma omp parallel for simd
+ for (Iter0 I = begin0; I < end0; ++I)
+ ++I;
+// Initializer is constructor without params.
+// expected-error@+3 {{invalid operands to binary expression ('Iter0' and 'int')}}
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp parallel for simd
+ for (Iter0 I; I < end0; ++I)
+ ++I;
+ Iter1 begin1, end1;
+// expected-error@+3 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+// expected-error@+2 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+#pragma omp parallel for simd
+ for (Iter1 I = begin1; I < end1; ++I)
+ ++I;
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (Iter1 I = begin1; I >= end1; ++I)
+ ++I;
+// expected-error@+5 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+// expected-error@+4 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+// Initializer is constructor with all default params.
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp parallel for simd
+ for (Iter1 I; I < end1; ++I) {
+ }
+ return 0;
+}
+
+template <typename IT, int ST>
+class TC {
+public:
+ int dotest_lt(IT begin, IT end) {
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (IT I = begin; I < end; I = I + ST) {
+ ++I;
+ }
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (IT I = begin; I <= end; I += ST) {
+ ++I;
+ }
+#pragma omp parallel for simd
+ for (IT I = begin; I < end; ++I) {
+ ++I;
+ }
+ }
+
+ static IT step() {
+ return IT(ST);
+ }
+};
+template <typename IT, int ST = 0>
+int dotest_gt(IT begin, IT end) {
+// expected-note@+3 2 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (IT I = begin; I >= end; I = I + ST) {
+ ++I;
+ }
+// expected-note@+3 2 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (IT I = begin; I >= end; I += ST) {
+ ++I;
+ }
+
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp parallel for simd
+ for (IT I = begin; I >= end; ++I) {
+ ++I;
+ }
+
+#pragma omp parallel for simd
+ for (IT I = begin; I < end; I += TC<int, ST>::step()) {
+ ++I;
+ }
+}
+
+void test_with_template() {
+ GoodIter begin, end;
+ TC<GoodIter, 100> t1;
+ TC<GoodIter, -100> t2;
+ t1.dotest_lt(begin, end);
+ t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
+ dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
+ dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+}
+
+void test_loop_break() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ for (int j = 0; j < 10; ++j) {
+ if (a[i] > b[j])
+ break; // OK in nested loop
+ }
+ switch (i) {
+ case 1:
+ b[i]++;
+ break;
+ default:
+ break;
+ }
+ if (c[i] > 10)
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+
+ if (c[i] > 11)
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+ }
+
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; i++) {
+ for (int j = 0; j < 10; j++) {
+ c[i] = a[i] + b[i];
+ if (c[i] > 10) {
+ if (c[i] < 20) {
+ break; // OK
+ }
+ }
+ }
+ }
+}
+
+void test_loop_eh() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ try { // expected-error {{'try' statement cannot be used in OpenMP simd region}}
+ for (int j = 0; j < 10; ++j) {
+ if (a[i] > b[j])
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ }
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ } catch (float f) {
+ if (f > 0.1)
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ return; // expected-error {{cannot return from OpenMP region}}
+ }
+ switch (i) {
+ case 1:
+ b[i]++;
+ break;
+ default:
+ break;
+ }
+ for (int j = 0; j < 10; j++) {
+ if (c[i] > 10)
+ throw c[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ }
+ }
+ if (c[9] > 10)
+ throw c[9]; // OK
+
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+ struct S {
+ void g() { throw 0; }
+ };
+ }
+}
+
+void test_loop_firstprivate_lastprivate() {
+ S s(4);
+#pragma omp parallel for simd lastprivate(s) firstprivate(s)
+ for (int i = 0; i < 16; ++i)
+ ;
+}
+
+void test_ordered() {
+// expected-error@+1 2 {{unexpected OpenMP clause 'ordered' in directive '#pragma omp parallel for simd'}}
+#pragma omp parallel for simd ordered ordered // expected-error {{directive '#pragma omp parallel for simd' cannot contain more than one 'ordered' clause}}
+ for (int i = 0; i < 16; ++i)
+ ;
+}
+
+void test_nowait() {
+// expected-error@+1 2 {{unexpected OpenMP clause 'nowait' in directive '#pragma omp parallel for simd'}}
+#pragma omp parallel for simd nowait nowait // expected-error {{directive '#pragma omp parallel for simd' cannot contain more than one 'nowait' clause}}
+ for (int i = 0; i < 16; ++i)
+ ;
+}
+
diff --git a/test/OpenMP/parallel_for_simd_messages.cpp b/test/OpenMP/parallel_for_simd_messages.cpp
new file mode 100644
index 000000000000..67a025c5e6a6
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_messages.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -std=c++11 -o - %s
+
+void foo() {
+}
+
+#pragma omp parallel for simd // expected-error {{unexpected OpenMP directive '#pragma omp parallel for simd'}}
+
+int main(int argc, char **argv) {
+#pragma omp parallel for simd { // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd ( // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd[ // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd] // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd } // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd
+ for (int i = 0; i < argc; ++i)
+ foo();
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+#pragma omp parallel for simd unknown()
+ for (int i = 0; i < argc; ++i)
+ foo();
+L1:
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd
+ for (int i = 0; i < argc; ++i) {
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ argc++;
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ switch (argc) {
+ case (0):
+#pragma omp parallel for simd
+ for (int i = 0; i < argc; ++i) {
+ foo();
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+ continue;
+ }
+ default:
+ break;
+ }
+ }
+#pragma omp parallel for simd default(none)
+ for (int i = 0; i < 10; ++i)
+ ++argc; // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}}
+
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+#pragma omp parallel for simd
+ for (int i = 0; i < argc; ++i)
+ L2:
+ foo();
+#pragma omp parallel for simd
+ for (int i = 0; i < argc; ++i) {
+ return 1; // expected-error {{cannot return from OpenMP region}}
+ }
+
+ [[]] // expected-error {{an attribute list cannot appear here}}
+#pragma omp parallel for simd
+ for (int n = 0; n < 100; ++n) {
+ }
+
+ return 0;
+}
+
+void test_ordered() {
+// expected-error@+1 2 {{unexpected OpenMP clause 'ordered' in directive '#pragma omp parallel for simd'}}
+#pragma omp parallel for simd ordered ordered // expected-error {{directive '#pragma omp parallel for simd' cannot contain more than one 'ordered' clause}}
+ for (int i = 0; i < 16; ++i)
+ ;
+}
+
diff --git a/test/OpenMP/parallel_for_simd_misc_messages.c b/test/OpenMP/parallel_for_simd_misc_messages.c
new file mode 100644
index 000000000000..4cb084318309
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_misc_messages.c
@@ -0,0 +1,657 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -verify %s
+
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp parallel for simd'}}
+#pragma omp parallel for simd
+
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp parallel for simd'}}
+#pragma omp parallel for simd foo
+
+void test_no_clause() {
+ int i;
+#pragma omp parallel for simd
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-error@+2 {{statement after '#pragma omp parallel for simd' must be a for loop}}
+#pragma omp parallel for simd
+ ++i;
+}
+
+void test_branch_protected_scope() {
+ int i = 0;
+L1:
+ ++i;
+
+ int x[24];
+
+#pragma omp parallel
+#pragma omp parallel for simd
+ for (i = 0; i < 16; ++i) {
+ if (i == 5)
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ else if (i == 6)
+ return; // expected-error {{cannot return from OpenMP region}}
+ else if (i == 7)
+ goto L2;
+ else if (i == 8) {
+ L2:
+ x[i]++;
+ }
+ }
+
+ if (x[0] == 0)
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+ else if (x[1] == 1)
+ goto L1;
+}
+
+void test_invalid_clause() {
+ int i;
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+#pragma omp parallel for simd foo bar
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_non_identifiers() {
+ int i, x;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+#pragma omp parallel for simd;
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+#pragma omp parallel for simd linear(x);
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+#pragma omp parallel for simd private(x);
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+#pragma omp parallel for simd, private(x);
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+extern int foo();
+void test_safelen() {
+ int i;
+// expected-error@+1 {{expected '('}}
+#pragma omp parallel for simd safelen
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd safelen(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd safelen()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd safelen(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd safelen(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-warning@+2 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+// expected-error@+1 {{expected '('}}
+#pragma omp parallel for simd safelen 4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd safelen(4
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd safelen(4,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd safelen(4, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel for simd safelen(4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd safelen(4 4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd safelen(4, , 4)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel for simd safelen(4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd safelen(4, 8)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp parallel for simd safelen(2.5)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp parallel for simd safelen(foo())
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+#pragma omp parallel for simd safelen(-5)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+#pragma omp parallel for simd safelen(0)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+#pragma omp parallel for simd safelen(5 - 5)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_collapse() {
+ int i;
+#pragma omp parallel
+// expected-error@+1 {{expected '('}}
+#pragma omp parallel for simd collapse
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd collapse(
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd collapse()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd collapse(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd collapse(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-warning@+2 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+// expected-error@+1 {{expected '('}}
+#pragma omp parallel for simd collapse 4)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp parallel for simd collapse(4
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp parallel for simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp parallel for simd collapse(4,
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp parallel for simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp parallel for simd collapse(4, )
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp parallel for simd', but found only 1}}
+#pragma omp parallel
+// expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp parallel for simd collapse(4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp parallel for simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp parallel for simd collapse(4 4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp parallel for simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp parallel for simd collapse(4, , 4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp parallel for simd', but found only 1}}
+#pragma omp parallel
+#pragma omp parallel for simd collapse(4)
+ for (int i1 = 0; i1 < 16; ++i1)
+ for (int i2 = 0; i2 < 16; ++i2)
+ for (int i3 = 0; i3 < 16; ++i3)
+ for (int i4 = 0; i4 < 16; ++i4)
+ foo();
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp parallel for simd collapse(4, 8)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp parallel for simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp parallel for simd collapse(2.5)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp parallel for simd collapse(foo())
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+#pragma omp parallel for simd collapse(-5)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+#pragma omp parallel for simd collapse(0)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+#pragma omp parallel for simd collapse(5 - 5)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp parallel for simd collapse(2)
+ for (i = 0; i < 16; ++i)
+ for (int j = 0; j < 16; ++j)
+// expected-error@+1 {{OpenMP constructs may not be nested inside a simd region}}
+#pragma omp parallel for simd reduction(+ : i, j)
+ for (int k = 0; k < 16; ++k)
+ i += j;
+}
+
+void test_linear() {
+ int i;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd linear(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd linear(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd linear(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd linear()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd linear(int)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected variable name}}
+#pragma omp parallel for simd linear(0)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{use of undeclared identifier 'x'}}
+#pragma omp parallel for simd linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{use of undeclared identifier 'x'}}
+// expected-error@+1 {{use of undeclared identifier 'y'}}
+#pragma omp parallel for simd linear(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+3 {{use of undeclared identifier 'x'}}
+// expected-error@+2 {{use of undeclared identifier 'y'}}
+// expected-error@+1 {{use of undeclared identifier 'z'}}
+#pragma omp parallel for simd linear(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y;
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd linear(x :)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd linear(x :, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel for simd linear(x : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel for simd linear(x : 2 * 2)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd linear(x : 1, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd linear(x : 1, y, z : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as linear}}
+// expected-error@+1 {{linear variable cannot be linear}}
+#pragma omp parallel for simd linear(x) linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as private}}
+// expected-error@+1 {{private variable cannot be linear}}
+#pragma omp parallel for simd private(x) linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as linear}}
+// expected-error@+1 {{linear variable cannot be private}}
+#pragma omp parallel for simd linear(x) private(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-warning@+1 {{zero linear step (x and other variables in clause should probably be const)}}
+#pragma omp parallel for simd linear(x, y : 0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as linear}}
+// expected-error@+1 {{linear variable cannot be lastprivate}}
+#pragma omp parallel for simd linear(x) lastprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-note@+2 {{defined as lastprivate}}
+// expected-error@+1 {{lastprivate variable cannot be linear}}
+#pragma omp parallel for simd lastprivate(x) linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_aligned() {
+ int i;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd aligned(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd aligned(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd aligned(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd aligned()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd aligned(int)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected variable name}}
+#pragma omp parallel for simd aligned(0)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{use of undeclared identifier 'x'}}
+#pragma omp parallel for simd aligned(x)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{use of undeclared identifier 'x'}}
+// expected-error@+1 {{use of undeclared identifier 'y'}}
+#pragma omp parallel for simd aligned(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+3 {{use of undeclared identifier 'x'}}
+// expected-error@+2 {{use of undeclared identifier 'y'}}
+// expected-error@+1 {{use of undeclared identifier 'z'}}
+#pragma omp parallel for simd aligned(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int *x, y, z[25]; // expected-note 4 {{'y' defined here}}
+#pragma omp parallel for simd aligned(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel for simd aligned(z)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd aligned(x :)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd aligned(x :, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel for simd aligned(x : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel for simd aligned(x : 2 * 2)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd aligned(x : 1, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd aligned(x : 1, y, z : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-error@+1 {{argument of aligned clause should be array or pointer, not 'int'}}
+#pragma omp parallel for simd aligned(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument of aligned clause should be array or pointer, not 'int'}}
+#pragma omp parallel for simd aligned(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as aligned}}
+// expected-error@+1 {{a variable cannot appear in more than one aligned clause}}
+#pragma omp parallel for simd aligned(x) aligned(z, x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+3 {{defined as aligned}}
+// expected-error@+2 {{a variable cannot appear in more than one aligned clause}}
+// expected-error@+1 2 {{argument of aligned clause should be array or pointer, not 'int'}}
+#pragma omp parallel for simd aligned(x, y, z) aligned(y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+
+void test_private() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp parallel for simd private(
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp parallel for simd private(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp parallel for simd private(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd private()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd private(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp parallel for simd private(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp parallel for simd private(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp parallel for simd private(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp parallel for simd private(x, y, z)
+ for (i = 0; i < 16; ++i) {
+ x = y * i + z;
+ }
+}
+
+void test_lastprivate() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd lastprivate(
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp parallel for simd lastprivate(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp parallel for simd lastprivate(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd lastprivate()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd lastprivate(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp parallel for simd lastprivate(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp parallel for simd lastprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp parallel for simd lastprivate(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp parallel for simd lastprivate(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_firstprivate() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd firstprivate(
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp parallel for simd firstprivate(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp parallel for simd firstprivate(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd firstprivate()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp parallel for simd firstprivate(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp parallel for simd firstprivate(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp parallel for simd lastprivate(x) firstprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp parallel for simd lastprivate(x, y) firstprivate(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp parallel for simd lastprivate(x, y, z) firstprivate(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_loop_messages() {
+ float a[100], b[100], c[100];
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or pointer type}}
+#pragma omp parallel for simd
+ for (float fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or pointer type}}
+#pragma omp parallel for simd
+ for (double fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+}
+
diff --git a/test/OpenMP/parallel_for_simd_num_threads_messages.cpp b/test/OpenMP/parallel_for_simd_num_threads_messages.cpp
new file mode 100644
index 000000000000..3d11d4f59cf6
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_num_threads_messages.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N> // expected-note {{declared here}}
+T tmain(T argc, S **argv) {
+ T i;
+ #pragma omp parallel for simd num_threads // expected-error {{expected '(' after 'num_threads'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads () // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (argc)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads ((argc > 0) ? argv[1] : argv[2]) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (S) // expected-error {{'S' does not refer to a value}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (argc)
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (N) // expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ for (i = 0; i < argc; ++i) foo();
+
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ int i;
+ #pragma omp parallel for simd num_threads // expected-error {{expected '(' after 'num_threads'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads () // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (argc)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (argc > 0 ? argv[1] : argv[2]) // expected-error {{integral }}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp parallel for simd num_threads (num_threads(tmain<int, char, -1>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}} expected-note {{in instantiation of function template specialization 'tmain<int, char, -1>' requested here}}
+ for (i = 0; i < argc; ++i) foo();
+
+ return tmain<int, char, 3>(argc, argv); // expected-note {{in instantiation of function template specialization 'tmain<int, char, 3>' requested here}}
+}
diff --git a/test/OpenMP/parallel_for_simd_private_messages.cpp b/test/OpenMP/parallel_for_simd_private_messages.cpp
new file mode 100644
index 000000000000..67d881318645
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_private_messages.cpp
@@ -0,0 +1,173 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+};
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+
+public:
+ S3() : a(0) {}
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+
+public:
+ S5(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(I argc, C **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp parallel for simd private // expected-error {{expected '(' after 'private'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(a, b) // expected-error {{private variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(e, g)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd nowait // expected-error {{unexpected OpenMP clause 'nowait' in directive '#pragma omp parallel for simd'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp parallel for simd private(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp parallel for simd private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp parallel for simd private // expected-error {{expected '(' after 'private'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(a, b) // expected-error {{private variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd nowait // expected-error {{unexpected OpenMP clause 'nowait' in directive '#pragma omp parallel for simd'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int i;
+#pragma omp parallel for simd private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp parallel for simd private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel for simd private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+
+ return 0;
+}
+
diff --git a/test/OpenMP/parallel_for_simd_proc_bind_messages.cpp b/test/OpenMP/parallel_for_simd_proc_bind_messages.cpp
new file mode 100644
index 000000000000..bc1e0d2b243b
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_proc_bind_messages.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -o - %s
+
+void foo();
+
+int main(int argc, char **argv) {
+ int i;
+#pragma omp parallel for simd proc_bind // expected-error {{expected '(' after 'proc_bind'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd proc_bind( // expected-error {{expected 'master', 'close' or 'spread' in OpenMP clause 'proc_bind'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd proc_bind() // expected-error {{expected 'master', 'close' or 'spread' in OpenMP clause 'proc_bind'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd proc_bind(master // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd proc_bind(close), proc_bind(spread) // expected-error {{directive '#pragma omp parallel for simd' cannot contain more than one 'proc_bind' clause}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel for simd proc_bind(x) // expected-error {{expected 'master', 'close' or 'spread' in OpenMP clause 'proc_bind'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+
+#pragma omp parallel for simd proc_bind(master)
+ for (i = 0; i < argc; ++i)
+ foo();
+
+#pragma omp parallel proc_bind(close)
+#pragma omp parallel for simd proc_bind(spread)
+ for (i = 0; i < argc; ++i)
+ foo();
+ return 0;
+}
diff --git a/test/OpenMP/parallel_for_simd_reduction_messages.cpp b/test/OpenMP/parallel_for_simd_reduction_messages.cpp
new file mode 100644
index 000000000000..61690ddd42c1
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_reduction_messages.cpp
@@ -0,0 +1,295 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+ S2 &operator+=(const S2 &arg) { return (*this); }
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
+ static const float S2sc;
+};
+const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+S2 b; // expected-note 2 {{'b' defined here}}
+const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
+class S3 {
+ int a;
+
+public:
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+ S3 operator+=(const S3 &arg1) { return arg1; }
+};
+int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+S3 c; // expected-note 2 {{'c' defined here}}
+const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
+extern const int f; // expected-note 4 {{'f' declared here}}
+class S4 { // expected-note {{'S4' declared here}}
+ int a;
+ S4();
+ S4(const S4 &s4);
+ S4 &operator+=(const S4 &arg) { return (*this); }
+
+public:
+ S4(int v) : a(v) {}
+};
+S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
+class S5 {
+ int a;
+ S5() : a(0) {}
+ S5(const S5 &s5) : a(s5.a) {}
+ S5 &operator+=(const S5 &arg);
+
+public:
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+
+public:
+ S6() : a(6) {}
+ operator int() { return 6; }
+} o; // expected-note 2 {{'o' defined here}}
+
+S3 h, k;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class T> // expected-note {{declared here}}
+T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+ const T d = T(); // expected-note 4 {{'d' defined here}}
+ const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
+ T qa[5] = {T()};
+ T i;
+ T &j = i; // expected-note 4 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
+ T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
+ T fl; // expected-note {{'fl' defined here}}
+#pragma omp parallel for simd reduction // expected-error {{expected '(' after 'reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(^ : T) // expected-error {{'T' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(max : qa[1]) // expected-error 2 {{expected variable name}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : ba) // expected-error {{a reduction variable with array type 'const S2 [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(* : ca) // expected-error {{a reduction variable with array type 'const S3 [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp parallel for simd reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : p), reduction(+ : p) // expected-error 3 {{variable can appear only once in OpenMP 'reduction' clause}} expected-note 3 {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : r) // expected-error 2 {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp parallel for simd reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(fl)
+#pragma omp parallel for simd reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel reduction(* : fl)
+#pragma omp parallel for simd reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return T();
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note 2 {{'d' defined here}}
+ const int da[5] = {0}; // expected-note {{'da' defined here}}
+ int qa[5] = {0};
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note 2 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const int &r = da[i]; // expected-note {{'r' defined here}}
+ int &q = qa[i]; // expected-note {{'q' defined here}}
+ float fl; // expected-note {{'fl' defined here}}
+#pragma omp parallel for simd reduction // expected-error {{expected '(' after 'reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(~ : argc) // expected-error {{expected unqualified-id}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(max : argv[1]) // expected-error {{expected variable name}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : ba) // expected-error {{a reduction variable with array type 'const S2 [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(* : ca) // expected-error {{a reduction variable with array type 'const S3 [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp parallel for simd reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel for simd reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp parallel for simd reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(fl)
+#pragma omp parallel for simd reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel reduction(* : fl)
+#pragma omp parallel for simd reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
+}
diff --git a/test/OpenMP/parallel_for_simd_safelen_messages.cpp b/test/OpenMP/parallel_for_simd_safelen_messages.cpp
new file mode 100644
index 000000000000..3fef81c74735
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_safelen_messages.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
+ #pragma omp parallel for simd safelen // expected-error {{expected '(' after 'safelen'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd safelen ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd safelen () // expected-error {{expected expression}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+ // expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ #pragma omp parallel for simd safelen (argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+ #pragma omp parallel for simd safelen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd safelen (1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd safelen ((ST > 0) ? 1 + ST : 2)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'safelen' clause}}
+ // expected-error@+2 2 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp parallel for simd safelen (foobool(argc)), safelen (true), safelen (-5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd safelen (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp parallel for simd safelen (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd safelen (4)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd safelen (N) // expected-error {{argument to 'safelen' clause must be a positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp parallel for simd safelen // expected-error {{expected '(' after 'safelen'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd safelen ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd safelen () // expected-error {{expected expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd safelen (4 // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd safelen (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd safelen (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{expression is not an integral constant expression}}
+ // expected-error@+2 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'safelen' clause}}
+ // expected-error@+1 2 {{argument to 'safelen' clause must be a positive integer value}}
+ #pragma omp parallel for simd safelen (foobool(argc)), safelen (true), safelen (-5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd safelen (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp parallel for simd safelen (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp parallel for simd' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp parallel for simd safelen(safelen(tmain<int, char, -1, -2>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ foo();
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 12, 4>' requested here}}
+ return tmain<int, char, 12, 4>(argc, argv);
+}
+
diff --git a/test/OpenMP/parallel_for_simd_schedule_messages.cpp b/test/OpenMP/parallel_for_simd_schedule_messages.cpp
new file mode 100644
index 000000000000..9e153d99a0a4
--- /dev/null
+++ b/test/OpenMP/parallel_for_simd_schedule_messages.cpp
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) {
+ #pragma omp parallel for simd schedule // expected-error {{expected '(' after 'schedule'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule (runtime, 3) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp parallel for simd schedule (guided argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{argument to 'schedule' clause must be a positive integer value}}
+ #pragma omp parallel for simd schedule (static, ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule (dynamic, 1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule (guided, (ST > 0) ? 1 + ST : 2)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+2 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'schedule' clause}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ #pragma omp parallel for simd schedule (static, foobool(argc)), schedule (dynamic, true), schedule (guided, -5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule (static, S) // expected-error {{'S' does not refer to a value}} expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel for simd schedule (guided, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule (dynamic, 1)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp parallel for simd schedule (static, N) // expected-error {{argument to 'schedule' clause must be a positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp parallel for simd schedule // expected-error {{expected '(' after 'schedule'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd schedule (runtime, 3) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd schedule (guided, 4 // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd schedule (static, 2+2)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd schedule (dynamic, foobool(1) > 0 ? 1 : 2)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+2 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'schedule' clause}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ #pragma omp parallel for simd schedule (guided, foobool(argc)), schedule (static, true), schedule (dynamic, -5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp parallel for simd schedule (guided, S1) // expected-error {{'S1' does not refer to a value}} expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel for simd schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp parallel for simd' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp parallel for simd schedule(dynamic, schedule(tmain<int, char, -1, -2>(argc, argv) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
+ return tmain<int, char, 1, 0>(argc, argv);
+}
+
diff --git a/test/OpenMP/parallel_if_codegen.cpp b/test/OpenMP/parallel_if_codegen.cpp
new file mode 100644
index 000000000000..44c874f1fb06
--- /dev/null
+++ b/test/OpenMP/parallel_if_codegen.cpp
@@ -0,0 +1,124 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+void fn1();
+void fn2();
+void fn3();
+void fn4();
+void fn5();
+void fn6();
+
+int Arg;
+
+// CHECK-LABEL: define void @{{.+}}gtid_test
+void gtid_test() {
+// CHECK: call void {{.+}}* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, {{.+}}* [[GTID_TEST_REGION1:@.+]] to void
+#pragma omp parallel
+#pragma omp parallel if (false)
+ gtid_test();
+// CHECK: ret void
+}
+
+// CHECK: define internal void [[GTID_TEST_REGION1]](i{{.+}}* [[GTID_PARAM:%.+]], i
+// CHECK: store i{{[0-9]+}}* [[GTID_PARAM]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]],
+// CHECK: [[GTID_ADDR:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_REF]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]]
+// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i{{.+}} [[GTID]])
+// CHECK: [[GTID_ADDR:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_REF]]
+// CHECK: call void [[GTID_TEST_REGION2:@.+]](i{{[0-9]+}}* [[GTID_ADDR]]
+// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i{{.+}} [[GTID]])
+// CHECK: ret void
+
+// CHECK: define internal void [[GTID_TEST_REGION2]](
+// CHECK: call void @{{.+}}gtid_test
+// CHECK: ret void
+
+template <typename T>
+int tmain(T Arg) {
+#pragma omp parallel if (true)
+ fn1();
+#pragma omp parallel if (false)
+ fn2();
+#pragma omp parallel if (Arg)
+ fn3();
+ return 0;
+}
+
+// CHECK-LABEL: define {{.*}}i{{[0-9]+}} @main()
+int main() {
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
+// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN4:@.+]] to void
+#pragma omp parallel if (true)
+ fn4();
+// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
+// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
+// CHECK: call void [[CAP_FN5:@.+]](i32* [[GTID_ADDR]],
+// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
+#pragma omp parallel if (false)
+ fn5();
+
+// CHECK: br i1 %{{.+}}, label %[[OMP_THEN:.+]], label %[[OMP_ELSE:.+]]
+// CHECK: [[OMP_THEN]]
+// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN6:@.+]] to void
+// CHECK: br label %[[OMP_END:.+]]
+// CHECK: [[OMP_ELSE]]
+// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
+// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
+// CHECK: call void [[CAP_FN6]](i32* [[GTID_ADDR]],
+// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
+// CHECK: br label %[[OMP_END]]
+// CHECK: [[OMP_END]]
+#pragma omp parallel if (Arg)
+ fn6();
+ // CHECK: = call {{.*}}i{{.+}} @{{.+}}tmain
+ return tmain(Arg);
+}
+
+// CHECK: define internal void [[CAP_FN4]]
+// CHECK: call void @{{.+}}fn4
+// CHECK: ret void
+
+// CHECK: define internal void [[CAP_FN5]]
+// CHECK: call void @{{.+}}fn5
+// CHECK: ret void
+
+// CHECK: define internal void [[CAP_FN6]]
+// CHECK: call void @{{.+}}fn6
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.+}} @{{.+}}tmain
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
+// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN1:@.+]] to void
+// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
+// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
+// CHECK: call void [[CAP_FN2:@.+]](i32* [[GTID_ADDR]],
+// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
+// CHECK: br i1 %{{.+}}, label %[[OMP_THEN:.+]], label %[[OMP_ELSE:.+]]
+// CHECK: [[OMP_THEN]]
+// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN3:@.+]] to void
+// CHECK: br label %[[OMP_END:.+]]
+// CHECK: [[OMP_ELSE]]
+// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
+// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
+// CHECK: call void [[CAP_FN3]](i32* [[GTID_ADDR]],
+// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
+// CHECK: br label %[[OMP_END]]
+// CHECK: [[OMP_END]]
+
+// CHECK: define internal void [[CAP_FN1]]
+// CHECK: call void @{{.+}}fn1
+// CHECK: ret void
+
+// CHECK: define internal void [[CAP_FN2]]
+// CHECK: call void @{{.+}}fn2
+// CHECK: ret void
+
+// CHECK: define internal void [[CAP_FN3]]
+// CHECK: call void @{{.+}}fn3
+// CHECK: ret void
+
+#endif
diff --git a/test/OpenMP/parallel_num_threads_codegen.cpp b/test/OpenMP/parallel_num_threads_codegen.cpp
new file mode 100644
index 000000000000..c095e430b60b
--- /dev/null
+++ b/test/OpenMP/parallel_num_threads_codegen.cpp
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple %itanium_abi_triple -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+typedef __INTPTR_TYPE__ intptr_t;
+
+// CHECK-DAG: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[S_TY:%.+]] = type { [[INTPTR_T_TY:i[0-9]+]], [[INTPTR_T_TY]], [[INTPTR_T_TY]] }
+// CHECK-DAG: [[STR:@.+]] = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00"
+// CHECK-DAG: [[DEF_LOC_2:@.+]] = private unnamed_addr constant [[IDENT_T_TY]] { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8]* [[STR]], i32 0, i32 0) }
+
+void foo();
+
+struct S {
+ intptr_t a, b, c;
+ S(intptr_t a) : a(a) {}
+ operator char() { return a; }
+ ~S() {}
+};
+
+template <typename T, int C>
+int tmain() {
+#pragma omp parallel num_threads(C)
+ foo();
+#pragma omp parallel num_threads(T(23))
+ foo();
+ return 0;
+}
+
+int main() {
+ S s(0);
+ char a = s;
+#pragma omp parallel num_threads(2)
+ foo();
+#pragma omp parallel num_threads(a)
+ foo();
+ return a + tmain<char, 5>() + tmain<S, 1>();
+}
+
+// CHECK-LABEL: define {{.*}}i{{[0-9]+}} @main()
+// CHECK-DAG: [[S_ADDR:%.+]] = alloca [[S_TY]]
+// CHECK-DAG: [[A_ADDR:%.+]] = alloca i8
+// CHECK-DAG: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEF_LOC_2]])
+// CHECK-DAG: call {{.*}} [[S_TY_CONSTR:@.+]]([[S_TY]]* [[S_ADDR]], [[INTPTR_T_TY]] [[INTPTR_T_TY_ATTR:(signext )?]]0)
+// CHECK: [[S_CHAR_OP:%.+]] = invoke{{.*}} i8 [[S_TY_CHAR_OP:@.+]]([[S_TY]]* [[S_ADDR]])
+// CHECK: store i8 [[S_CHAR_OP]], i8* [[A_ADDR]]
+// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 2)
+// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: [[A_VAL:%.+]] = load i8* [[A_ADDR]]
+// CHECK: [[RES:%.+]] = sext i8 [[A_VAL]] to i32
+// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 [[RES]])
+// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: invoke{{.*}} [[INT_TY:i[0-9]+]] [[TMAIN_CHAR_5:@.+]]()
+// CHECK: invoke{{.*}} [[INT_TY]] [[TMAIN_S_1:@.+]]()
+// CHECK: call {{.*}} [[S_TY_DESTR:@.+]]([[S_TY]]* [[S_ADDR]])
+// CHECK: ret [[INT_TY]]
+// CHECK: }
+
+// CHECK: define{{.*}} [[INT_TY]] [[TMAIN_CHAR_5]]()
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEF_LOC_2]])
+// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 5)
+// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 23)
+// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: ret [[INT_TY]] 0
+// CHECK-NEXT: }
+
+// CHECK: define{{.*}} [[INT_TY]] [[TMAIN_S_1]]()
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEF_LOC_2]])
+// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 1)
+// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: call {{.*}} [[S_TY_CONSTR]]([[S_TY]]* [[S_TEMP:%.+]], [[INTPTR_T_TY]] [[INTPTR_T_TY_ATTR]]23)
+// CHECK: [[S_CHAR_OP:%.+]] = invoke{{.*}} i8 [[S_TY_CHAR_OP]]([[S_TY]]* [[S_TEMP]])
+// CHECK: [[RES:%.+]] = sext {{.*}}i8 [[S_CHAR_OP]] to i32
+// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 [[RES]])
+// CHECK: call {{.*}} [[S_TY_DESTR]]([[S_TY]]* [[S_TEMP]])
+// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: ret [[INT_TY]] 0
+// CHECK: }
+
+#endif
diff --git a/test/OpenMP/parallel_private_codegen.cpp b/test/OpenMP/parallel_private_codegen.cpp
new file mode 100644
index 000000000000..6911068250f5
--- /dev/null
+++ b/test/OpenMP/parallel_private_codegen.cpp
@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+template <class T>
+struct S {
+ T f;
+ S(T a) : f(a) {}
+ S() : f() {}
+ operator T() { return T(); }
+ ~S() {}
+};
+
+volatile int g = 1212;
+
+// CHECK: [[S_FLOAT_TY:%.+]] = type { float }
+// CHECK: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* }
+// CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
+// CHECK: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* }
+// CHECK: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
+template <typename T>
+T tmain() {
+ S<T> test;
+ T t_var = T();
+ T vec[] = {1, 2};
+ S<T> s_arr[] = {1, 2};
+ S<T> var(3);
+#pragma omp parallel private(t_var, vec, s_arr, var)
+ {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
+ return T();
+}
+
+int main() {
+#ifdef LAMBDA
+ // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+ // LAMBDA: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]]
+ // LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
+ // LAMBDA: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
+#pragma omp parallel private(g)
+ {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+ // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]],
+ // LAMBDA: call i32 @__kmpc_cancel_barrier(
+ g = 1;
+ // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]]
+ // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g = 2;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}** [[ARG_PTR_REF]]
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_PTR_REF]]
+ // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]]
+ }();
+ }
+ }();
+ return 0;
+#elif defined(BLOCKS)
+ // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // BLOCKS-LABEL: @main
+ // BLOCKS: call void {{%.+}}(i8*
+ ^{
+ // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
+ // BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]]
+ // BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
+ // BLOCKS: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
+#pragma omp parallel private(g)
+ {
+ // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+ // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]],
+ // BLOCKS: call i32 @__kmpc_cancel_barrier(
+ g = 1;
+ // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: call void {{%.+}}(i8*
+ ^{
+ // BLOCKS: define {{.+}} void {{@.+}}(i8*
+ g = 2;
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}*
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: ret
+ }();
+ }
+ }();
+ return 0;
+#else
+ S<float> test;
+ int t_var = 0;
+ int vec[] = {1, 2};
+ S<float> s_arr[] = {1, 2};
+ S<float> var(3);
+#pragma omp parallel private(t_var, vec, s_arr, var)
+ {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
+ return tmain<int>();
+#endif
+}
+
+// CHECK: define i{{[0-9]+}} @main()
+// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
+// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]*
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: = call i{{.+}} [[TMAIN_INT:@.+]]()
+// CHECK: call void [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_MAIN_TY]]* %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_FLOAT_TY]]*
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]])
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_REF]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
+// CHECK: ret void
+
+// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
+// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// CHECK: call void [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_INT_TY]]*
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[S_ARR_PRIV_ITEM]])
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_REF]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]*
+// CHECK: ret void
+#endif
+
diff --git a/test/OpenMP/parallel_private_messages.cpp b/test/OpenMP/parallel_private_messages.cpp
index 1cd86d2b5fbc..14c5cbdb8aea 100644
--- a/test/OpenMP/parallel_private_messages.cpp
+++ b/test/OpenMP/parallel_private_messages.cpp
@@ -25,15 +25,15 @@ public:
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v):a(v) { }
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5():a(0) {}
+ S5():a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v):a(v) { }
};
@@ -44,8 +44,8 @@ int threadvar;
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = { 0 }; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g[] = {5, 6};
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel private // expected-error {{expected '(' after 'private'}}
@@ -62,7 +62,7 @@ int main(int argc, char **argv) {
#pragma omp parallel private(ca) // expected-error {{shared variable cannot be private}}
#pragma omp parallel private(da) // expected-error {{shared variable cannot be private}}
#pragma omp parallel private(S2::S2s) // expected-error {{shared variable cannot be private}}
- #pragma omp parallel private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+ #pragma omp parallel private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
#pragma omp parallel private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
#pragma omp parallel shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
foo();
diff --git a/test/OpenMP/parallel_sections_firstprivate_messages.cpp b/test/OpenMP/parallel_sections_firstprivate_messages.cpp
index ffd2b0cfd5e5..2d27b1a600da 100644
--- a/test/OpenMP/parallel_sections_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_sections_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
public:
S2() : a(0) {}
- S2(S2 &s2) : a(s2.a) {}
+ S2(const S2 &s2) : a(s2.a) {}
static float S2s;
static const float S2sc;
};
@@ -27,22 +27,22 @@ class S3 {
public:
S3() : a(0) {}
- S3(S3 &s3) : a(s3.a) {}
+ S3(const S3 &s3) : a(s3.a) {}
};
const S3 c;
const S3 ca[5];
extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4(const S4 &s4);
+ S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
int a;
- S5(const S5 &s5) : a(s5.a) {}
+ S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
public:
S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- C g(5); // expected-note 2 {{'g' defined here}}
+ I e(4);
+ C g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel sections firstprivate // expected-error {{expected '(' after 'firstprivate'}}
@@ -106,7 +106,7 @@ int foomain(int argc, char **argv) {
{
foo();
}
-#pragma omp parallel sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
@@ -138,7 +138,7 @@ int foomain(int argc, char **argv) {
{
foo();
}
-#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
@@ -158,8 +158,8 @@ int foomain(int argc, char **argv) {
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note 2 {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
S3 m;
S6 n(2);
int i;
@@ -237,7 +237,7 @@ int main(int argc, char **argv) {
{
foo();
}
-#pragma omp parallel sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
@@ -262,7 +262,7 @@ int main(int argc, char **argv) {
{
foo();
}
-#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
diff --git a/test/OpenMP/parallel_sections_private_messages.cpp b/test/OpenMP/parallel_sections_private_messages.cpp
index 7d39c7e2c5bb..e0b7488e5162 100644
--- a/test/OpenMP/parallel_sections_private_messages.cpp
+++ b/test/OpenMP/parallel_sections_private_messages.cpp
@@ -24,16 +24,16 @@ public:
S3() : a(0) {}
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -124,8 +124,8 @@ int foomain(I argc, C **argv) {
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel sections private // expected-error {{expected '(' after 'private'}}
@@ -168,7 +168,7 @@ int main(int argc, char **argv) {
{
foo();
}
-#pragma omp parallel sections private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp parallel sections private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
diff --git a/test/OpenMP/sections_firstprivate_messages.cpp b/test/OpenMP/sections_firstprivate_messages.cpp
index b030ce549d33..ecee45900fea 100644
--- a/test/OpenMP/sections_firstprivate_messages.cpp
+++ b/test/OpenMP/sections_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
public:
S2() : a(0) {}
- S2(S2 &s2) : a(s2.a) {}
+ S2(const S2 &s2) : a(s2.a) {}
static float S2s;
static const float S2sc;
};
@@ -27,22 +27,22 @@ class S3 {
public:
S3() : a(0) {}
- S3(S3 &s3) : a(s3.a) {}
+ S3(const S3 &s3) : a(s3.a) {}
};
const S3 c;
const S3 ca[5];
extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4(const S4 &s4);
+ S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
int a;
- S5(const S5 &s5) : a(s5.a) {}
+ S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
public:
S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- C g(5); // expected-note 2 {{'g' defined here}}
+ I e(4);
+ C g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel
@@ -117,7 +117,7 @@ int foomain(int argc, char **argv) {
foo();
}
#pragma omp parallel
-#pragma omp sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
@@ -153,7 +153,7 @@ int foomain(int argc, char **argv) {
foo();
}
#pragma omp parallel
-#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
@@ -173,8 +173,8 @@ int foomain(int argc, char **argv) {
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note 2 {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
S3 m;
S6 n(2);
int i;
@@ -271,7 +271,7 @@ int main(int argc, char **argv) {
foo();
}
#pragma omp parallel
-#pragma omp sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
@@ -301,7 +301,7 @@ int main(int argc, char **argv) {
foo();
}
#pragma omp parallel
-#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
diff --git a/test/OpenMP/sections_private_messages.cpp b/test/OpenMP/sections_private_messages.cpp
index 7f5aa849682a..8b330bf71052 100644
--- a/test/OpenMP/sections_private_messages.cpp
+++ b/test/OpenMP/sections_private_messages.cpp
@@ -24,16 +24,16 @@ public:
S3() : a(0) {}
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -124,8 +124,8 @@ int foomain(I argc, C **argv) {
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp sections private // expected-error {{expected '(' after 'private'}}
@@ -168,7 +168,7 @@ int main(int argc, char **argv) {
{
foo();
}
-#pragma omp sections private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp sections private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
diff --git a/test/OpenMP/simd_aligned_messages.cpp b/test/OpenMP/simd_aligned_messages.cpp
index 84cf40c1731b..dfa6b541c909 100644
--- a/test/OpenMP/simd_aligned_messages.cpp
+++ b/test/OpenMP/simd_aligned_messages.cpp
@@ -39,6 +39,7 @@ void test_aligned_colons(int *&rp)
// expected-error@+1 {{expected variable name}}
#pragma omp simd aligned(B::bfoo())
for (int i = 0; i < 10; ++i) ;
+ // expected-warning@+1 {{aligned clause will be ignored because the requested alignment is not a power of 2}}
#pragma omp simd aligned(B::ib,B:C1+C2)
for (int i = 0; i < 10; ++i) ;
}
@@ -122,7 +123,7 @@ template<class I, class C> int foomain(I argc, C **argv) {
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
for (I k = 0; k < argc; ++k) ++k;
- #pragma omp simd aligned (argc : 5)
+ #pragma omp simd aligned (argc : 5) // expected-warning {{aligned clause will be ignored because the requested alignment is not a power of 2}}
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (S1) // expected-error {{'S1' does not refer to a value}}
for (I k = 0; k < argc; ++k) ++k;
diff --git a/test/OpenMP/simd_codegen.cpp b/test/OpenMP/simd_codegen.cpp
new file mode 100644
index 000000000000..b8073c2948e0
--- /dev/null
+++ b/test/OpenMP/simd_codegen.cpp
@@ -0,0 +1,407 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+//
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}simple{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void simple(float *a, float *b, float *c, float *d) {
+ #pragma omp simd
+// CHECK: store i32 0, i32* [[OMP_IV:%[^,]+]]
+
+// CHECK: [[IV:%.+]] = load i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID:[0-9]+]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp slt i32 [[IV]], 6
+// CHECK-NEXT: br i1 [[CMP]], label %[[SIMPLE_LOOP1_BODY:.+]], label %[[SIMPLE_LOOP1_END:[^,]+]]
+ for (int i = 3; i < 32; i += 5) {
+// CHECK: [[SIMPLE_LOOP1_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV1_1:%.+]] = load i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK: [[CALC_I_1:%.+]] = mul nsw i32 [[IV1_1]], 5
+// CHECK-NEXT: [[CALC_I_2:%.+]] = add nsw i32 3, [[CALC_I_1]]
+// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* {{%.+}}{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+ a[i] = b[i] * c[i] * d[i];
+// CHECK: [[IV1_2:%.+]] = load i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1
+// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// br label %{{.+}}, !llvm.loop !{{.+}}
+ }
+// CHECK: [[SIMPLE_LOOP1_END]]
+
+ #pragma omp simd
+// CHECK: store i32 0, i32* [[OMP_IV2:%[^,]+]]
+
+// CHECK: [[IV2:%.+]] = load i32* [[OMP_IV2]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID:[0-9]+]]
+// CHECK-NEXT: [[CMP2:%.+]] = icmp slt i32 [[IV2]], 9
+// CHECK-NEXT: br i1 [[CMP2]], label %[[SIMPLE_LOOP2_BODY:.+]], label %[[SIMPLE_LOOP2_END:[^,]+]]
+ for (int i = 10; i > 1; i--) {
+// CHECK: [[SIMPLE_LOOP2_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV2_0:%.+]] = load i32* [[OMP_IV2]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID]]
+// FIXME: It is interesting, why the following "mul 1" was not constant folded?
+// CHECK-NEXT: [[IV2_1:%.+]] = mul nsw i32 [[IV2_0]], 1
+// CHECK-NEXT: [[LC_I_1:%.+]] = sub nsw i32 10, [[IV2_1]]
+// CHECK-NEXT: store i32 [[LC_I_1]], i32* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID]]
+ a[i]++;
+// CHECK: [[IV2_2:%.+]] = load i32* [[OMP_IV2]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID]]
+// CHECK-NEXT: [[ADD2_2:%.+]] = add nsw i32 [[IV2_2]], 1
+// CHECK-NEXT: store i32 [[ADD2_2]], i32* [[OMP_IV2]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID]]
+// br label {{.+}}, !llvm.loop ![[SIMPLE_LOOP2_ID]]
+ }
+// CHECK: [[SIMPLE_LOOP2_END]]
+
+ #pragma omp simd
+// CHECK: store i64 0, i64* [[OMP_IV3:%[^,]+]]
+
+// CHECK: [[IV3:%.+]] = load i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID:[0-9]+]]
+// CHECK-NEXT: [[CMP3:%.+]] = icmp ult i64 [[IV3]], 4
+// CHECK-NEXT: br i1 [[CMP3]], label %[[SIMPLE_LOOP3_BODY:.+]], label %[[SIMPLE_LOOP3_END:[^,]+]]
+ for (unsigned long long it = 2000; it >= 600; it-=400) {
+// CHECK: [[SIMPLE_LOOP3_BODY]]
+// Start of body: calculate it from IV:
+// CHECK: [[IV3_0:%.+]] = load i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: [[LC_IT_1:%.+]] = mul i64 [[IV3_0]], 400
+// CHECK-NEXT: [[LC_IT_2:%.+]] = sub i64 2000, [[LC_IT_1]]
+// CHECK-NEXT: store i64 [[LC_IT_2]], i64* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+ a[it]++;
+// CHECK: [[IV3_2:%.+]] = load i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: [[ADD3_2:%.+]] = add i64 [[IV3_2]], 1
+// CHECK-NEXT: store i64 [[ADD3_2]], i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+ }
+// CHECK: [[SIMPLE_LOOP3_END]]
+
+ #pragma omp simd
+// CHECK: store i32 0, i32* [[OMP_IV4:%[^,]+]]
+
+// CHECK: [[IV4:%.+]] = load i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID:[0-9]+]]
+// CHECK-NEXT: [[CMP4:%.+]] = icmp slt i32 [[IV4]], 4
+// CHECK-NEXT: br i1 [[CMP4]], label %[[SIMPLE_LOOP4_BODY:.+]], label %[[SIMPLE_LOOP4_END:[^,]+]]
+ for (short it = 6; it <= 20; it-=-4) {
+// CHECK: [[SIMPLE_LOOP4_BODY]]
+// Start of body: calculate it from IV:
+// CHECK: [[IV4_0:%.+]] = load i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i32 [[IV4_0]], 4
+// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i32 6, [[LC_IT_1]]
+// CHECK-NEXT: [[LC_IT_3:%.+]] = trunc i32 [[LC_IT_2]] to i16
+// CHECK-NEXT: store i16 [[LC_IT_3]], i16* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+
+// CHECK: [[IV4_2:%.+]] = load i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK-NEXT: [[ADD4_2:%.+]] = add nsw i32 [[IV4_2]], 1
+// CHECK-NEXT: store i32 [[ADD4_2]], i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+ }
+// CHECK: [[SIMPLE_LOOP4_END]]
+
+ #pragma omp simd
+// CHECK: store i32 0, i32* [[OMP_IV5:%[^,]+]]
+
+// CHECK: [[IV5:%.+]] = load i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID:[0-9]+]]
+// CHECK-NEXT: [[CMP5:%.+]] = icmp slt i32 [[IV5]], 26
+// CHECK-NEXT: br i1 [[CMP5]], label %[[SIMPLE_LOOP5_BODY:.+]], label %[[SIMPLE_LOOP5_END:[^,]+]]
+ for (unsigned char it = 'z'; it >= 'a'; it+=-1) {
+// CHECK: [[SIMPLE_LOOP5_BODY]]
+// Start of body: calculate it from IV:
+// CHECK: [[IV5_0:%.+]] = load i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK-NEXT: [[IV5_1:%.+]] = mul nsw i32 [[IV5_0]], 1
+// CHECK-NEXT: [[LC_IT_1:%.+]] = sub nsw i32 122, [[IV5_1]]
+// CHECK-NEXT: [[LC_IT_2:%.+]] = trunc i32 [[LC_IT_1]] to i8
+// CHECK-NEXT: store i8 [[LC_IT_2]], i8* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+
+// CHECK: [[IV5_2:%.+]] = load i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK-NEXT: [[ADD5_2:%.+]] = add nsw i32 [[IV5_2]], 1
+// CHECK-NEXT: store i32 [[ADD5_2]], i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+ }
+// CHECK: [[SIMPLE_LOOP5_END]]
+
+ #pragma omp simd
+// FIXME: I think we would get wrong result using 'unsigned' in the loop below.
+// So we'll need to add zero trip test for 'unsigned' counters.
+//
+// CHECK: store i32 0, i32* [[OMP_IV6:%[^,]+]]
+
+// CHECK: [[IV6:%.+]] = load i32* [[OMP_IV6]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP6_ID:[0-9]+]]
+// CHECK-NEXT: [[CMP6:%.+]] = icmp slt i32 [[IV6]], -8
+// CHECK-NEXT: br i1 [[CMP6]], label %[[SIMPLE_LOOP6_BODY:.+]], label %[[SIMPLE_LOOP6_END:[^,]+]]
+ for (int i=100; i<10; i+=10) {
+// CHECK: [[SIMPLE_LOOP6_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV6_0:%.+]] = load i32* [[OMP_IV6]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP6_ID]]
+// CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i32 [[IV6_0]], 10
+// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i32 100, [[LC_IT_1]]
+// CHECK-NEXT: store i32 [[LC_IT_2]], i32* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP6_ID]]
+
+// CHECK: [[IV6_2:%.+]] = load i32* [[OMP_IV6]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP6_ID]]
+// CHECK-NEXT: [[ADD6_2:%.+]] = add nsw i32 [[IV6_2]], 1
+// CHECK-NEXT: store i32 [[ADD6_2]], i32* [[OMP_IV6]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP6_ID]]
+ }
+// CHECK: [[SIMPLE_LOOP6_END]]
+
+ int A;
+ #pragma omp simd lastprivate(A)
+// Clause 'lastprivate' implementation is not completed yet.
+// Test checks that one iteration is separated in presence of lastprivate.
+//
+// CHECK: store i64 0, i64* [[OMP_IV7:%[^,]+]]
+// CHECK: br i1 true, label %[[SIMPLE_IF7_THEN:.+]], label %[[SIMPLE_IF7_END:[^,]+]]
+// CHECK: [[SIMPLE_IF7_THEN]]
+// CHECK: br label %[[SIMD_LOOP7_COND:[^,]+]]
+// CHECK: [[SIMD_LOOP7_COND]]
+// CHECK-NEXT: [[IV7:%.+]] = load i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID:[0-9]+]]
+// CHECK-NEXT: [[CMP7:%.+]] = icmp slt i64 [[IV7]], 6
+// CHECK-NEXT: br i1 [[CMP7]], label %[[SIMPLE_LOOP7_BODY:.+]], label %[[SIMPLE_LOOP7_END:[^,]+]]
+ for (long long i = -10; i < 10; i += 3) {
+// CHECK: [[SIMPLE_LOOP7_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV7_0:%.+]] = load i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i64 [[IV7_0]], 3
+// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i64 -10, [[LC_IT_1]]
+// CHECK-NEXT: store i64 [[LC_IT_2]], i64* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+ A = i;
+// CHECK: [[IV7_2:%.+]] = load i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: [[ADD7_2:%.+]] = add nsw i64 [[IV7_2]], 1
+// CHECK-NEXT: store i64 [[ADD7_2]], i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+ }
+// CHECK: [[SIMPLE_LOOP7_END]]
+// Separated last iteration.
+// CHECK: [[IV7_4:%.+]] = load i64* [[OMP_IV7]]
+// CHECK-NEXT: [[LC_FIN_1:%.+]] = mul nsw i64 [[IV7_4]], 3
+// CHECK-NEXT: [[LC_FIN_2:%.+]] = add nsw i64 -10, [[LC_FIN_1]]
+// CHECK-NEXT: store i64 [[LC_FIN_2]], i64* [[ADDR_I:%[^,]+]]
+// CHECK: [[LOAD_I:%.+]] = load i64* [[ADDR_I]]
+// CHECK-NEXT: [[CONV_I:%.+]] = trunc i64 [[LOAD_I]] to i32
+//
+// CHECK: br label %[[SIMPLE_IF7_END]]
+// CHECK: [[SIMPLE_IF7_END]]
+//
+
+// CHECK: ret void
+}
+
+template <class T, unsigned K> T tfoo(T a) { return a + K; }
+
+template <typename T, unsigned N>
+int templ1(T a, T *z) {
+ #pragma omp simd collapse(N)
+ for (int i = 0; i < N * 2; i++) {
+ for (long long j = 0; j < (N + N + N + N); j += 2) {
+ z[i + j] = a + tfoo<T, N>(i + j);
+ }
+ }
+ return 0;
+}
+
+// Instatiation templ1<float,2>
+// CHECK-LABEL: define {{.*i32}} @{{.*}}templ1{{.*}}(float {{.+}}, float* {{.+}})
+// CHECK: store i64 0, i64* [[T1_OMP_IV:[^,]+]]
+// ...
+// CHECK: [[IV:%.+]] = load i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID:[0-9]+]]
+// CHECK-NEXT: [[CMP1:%.+]] = icmp slt i64 [[IV]], 16
+// CHECK-NEXT: br i1 [[CMP1]], label %[[T1_BODY:.+]], label %[[T1_END:[^,]+]]
+// CHECK: [[T1_BODY]]
+// Loop counters i and j updates:
+// CHECK: [[IV1:%.+]] = load i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK-NEXT: [[I_1:%.+]] = sdiv i64 [[IV1]], 4
+// CHECK-NEXT: [[I_1_MUL1:%.+]] = mul nsw i64 [[I_1]], 1
+// CHECK-NEXT: [[I_1_ADD0:%.+]] = add nsw i64 0, [[I_1_MUL1]]
+// CHECK-NEXT: [[I_2:%.+]] = trunc i64 [[I_1_ADD0]] to i32
+// CHECK-NEXT: store i32 [[I_2]], i32* {{%.+}}{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK: [[IV2:%.+]] = load i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK-NEXT: [[J_1:%.+]] = srem i64 [[IV2]], 4
+// CHECK-NEXT: [[J_2:%.+]] = mul nsw i64 [[J_1]], 2
+// CHECK-NEXT: [[J_2_ADD0:%.+]] = add nsw i64 0, [[J_2]]
+// CHECK-NEXT: store i64 [[J_2_ADD0]], i64* {{%.+}}{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// simd.for.inc:
+// CHECK: [[IV3:%.+]] = load i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK-NEXT: [[INC:%.+]] = add nsw i64 [[IV3]], 1
+// CHECK-NEXT: store i64 [[INC]], i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK-NEXT: br label {{%.+}}
+// CHECK: [[T1_END]]
+// CHECK: ret i32 0
+//
+void inst_templ1() {
+ float a;
+ float z[100];
+ templ1<float,2> (a, z);
+}
+
+
+typedef int MyIdx;
+
+class IterDouble {
+ double *Ptr;
+public:
+ IterDouble operator++ () const {
+ IterDouble n;
+ n.Ptr = Ptr + 1;
+ return n;
+ }
+ bool operator < (const IterDouble &that) const {
+ return Ptr < that.Ptr;
+ }
+ double & operator *() const {
+ return *Ptr;
+ }
+ MyIdx operator - (const IterDouble &that) const {
+ return (MyIdx) (Ptr - that.Ptr);
+ }
+ IterDouble operator + (int Delta) {
+ IterDouble re;
+ re.Ptr = Ptr + Delta;
+ return re;
+ }
+
+ ///~IterDouble() {}
+};
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}iter_simple{{.*}}
+void iter_simple(IterDouble ia, IterDouble ib, IterDouble ic) {
+//
+// CHECK: store i32 0, i32* [[IT_OMP_IV:%[^,]+]]
+// Calculate number of iterations before the loop body.
+// CHECK: [[DIFF1:%.+]] = call {{.*}}i32 @{{.*}}IterDouble{{.*}}
+// CHECK-NEXT: [[DIFF2:%.+]] = sub nsw i32 [[DIFF1]], 1
+// CHECK-NEXT: [[DIFF3:%.+]] = add nsw i32 [[DIFF2]], 1
+// CHECK-NEXT: [[DIFF4:%.+]] = sdiv i32 [[DIFF3]], 1
+// CHECK-NEXT: [[DIFF5:%.+]] = sub nsw i32 [[DIFF4]], 1
+// CHECK-NEXT: store i32 [[DIFF5]], i32* [[OMP_LAST_IT:%[^,]+]]{{.+}}
+ #pragma omp simd
+
+// CHECK: [[IV:%.+]] = load i32* [[IT_OMP_IV]]{{.+}} !llvm.mem.parallel_loop_access ![[ITER_LOOP_ID:[0-9]+]]
+// CHECK-NEXT: [[LAST_IT:%.+]] = load i32* [[OMP_LAST_IT]]{{.+}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK-NEXT: [[NUM_IT:%.+]] = add nsw i32 [[LAST_IT]], 1
+// CHECK-NEXT: [[CMP:%.+]] = icmp slt i32 [[IV]], [[NUM_IT]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[IT_BODY:[^,]+]], label %[[IT_END:[^,]+]]
+ for (IterDouble i = ia; i < ib; ++i) {
+// CHECK: [[IT_BODY]]
+// Start of body: calculate i from index:
+// CHECK: [[IV1:%.+]] = load i32* [[IT_OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// Call of operator+ (i, IV).
+// CHECK: {{%.+}} = call {{.+}} @{{.*}}IterDouble{{.*}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// ... loop body ...
+ *i = *ic * 0.5;
+// Float multiply and save result.
+// CHECK: [[MULR:%.+]] = fmul double {{%.+}}, 5.000000e-01
+// CHECK-NEXT: call {{.+}} @{{.*}}IterDouble{{.*}}
+// CHECK: store double [[MULR:%.+]], double* [[RESULT_ADDR:%.+]], !llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+ ++ic;
+//
+// CHECK: [[IV2:%.+]] = load i32* [[IT_OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK-NEXT: [[ADD2:%.+]] = add nsw i32 [[IV2]], 1
+// CHECK-NEXT: store i32 [[ADD2]], i32* [[IT_OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// br label %{{.*}}, !llvm.loop ![[ITER_LOOP_ID]]
+ }
+// CHECK: [[IT_END]]
+// CHECK: ret void
+}
+
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}collapsed{{.*}}
+void collapsed(float *a, float *b, float *c, float *d) {
+ int i; // outer loop counter
+ unsigned j; // middle loop couter, leads to unsigned icmp in loop header.
+ // k declared in the loop init below
+ short l; // inner loop counter
+// CHECK: store i32 0, i32* [[OMP_IV:[^,]+]]
+//
+ #pragma omp simd collapse(4)
+
+// CHECK: [[IV:%.+]] = load i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID:[0-9]+]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp ult i32 [[IV]], 120
+// CHECK-NEXT: br i1 [[CMP]], label %[[COLL1_BODY:[^,]+]], label %[[COLL1_END:[^,]+]]
+ for (i = 1; i < 3; i++) // 2 iterations
+ for (j = 2u; j < 5u; j++) //3 iterations
+ for (int k = 3; k <= 6; k++) // 4 iterations
+ for (l = 4; l < 9; ++l) // 5 iterations
+ {
+// CHECK: [[COLL1_BODY]]
+// Start of body: calculate i from index:
+// CHECK: [[IV1:%.+]] = load i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// Calculation of the loop counters values.
+// CHECK: [[CALC_I_1:%.+]] = udiv i32 [[IV1]], 60
+// CHECK-NEXT: [[CALC_I_1_MUL1:%.+]] = mul i32 [[CALC_I_1]], 1
+// CHECK-NEXT: [[CALC_I_2:%.+]] = add i32 1, [[CALC_I_1_MUL1]]
+// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
+// CHECK: [[IV1_2:%.+]] = load i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK-NEXT: [[CALC_J_1:%.+]] = udiv i32 [[IV1_2]], 20
+// CHECK-NEXT: [[CALC_J_2:%.+]] = urem i32 [[CALC_J_1]], 3
+// CHECK-NEXT: [[CALC_J_2_MUL1:%.+]] = mul i32 [[CALC_J_2]], 1
+// CHECK-NEXT: [[CALC_J_3:%.+]] = add i32 2, [[CALC_J_2_MUL1]]
+// CHECK-NEXT: store i32 [[CALC_J_3]], i32* [[LC_J:.+]]
+// CHECK: [[IV1_3:%.+]] = load i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK-NEXT: [[CALC_K_1:%.+]] = udiv i32 [[IV1_3]], 5
+// CHECK-NEXT: [[CALC_K_2:%.+]] = urem i32 [[CALC_K_1]], 4
+// CHECK-NEXT: [[CALC_K_2_MUL1:%.+]] = mul i32 [[CALC_K_2]], 1
+// CHECK-NEXT: [[CALC_K_3:%.+]] = add i32 3, [[CALC_K_2_MUL1]]
+// CHECK-NEXT: store i32 [[CALC_K_3]], i32* [[LC_K:.+]]
+// CHECK: [[IV1_4:%.+]] = load i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK-NEXT: [[CALC_L_1:%.+]] = urem i32 [[IV1_4]], 5
+// CHECK-NEXT: [[CALC_L_1_MUL1:%.+]] = mul i32 [[CALC_L_1]], 1
+// CHECK-NEXT: [[CALC_L_2:%.+]] = add i32 4, [[CALC_L_1_MUL1]]
+// CHECK-NEXT: [[CALC_L_3:%.+]] = trunc i32 [[CALC_L_2]] to i16
+// CHECK-NEXT: store i16 [[CALC_L_3]], i16* [[LC_L:.+]]
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+ float res = b[j] * c[k];
+ a[i] = res * d[l];
+// CHECK: [[IV2:%.+]] = load i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK-NEXT: [[ADD2:%.+]] = add i32 [[IV2]], 1
+// CHECK-NEXT: store i32 [[ADD2]], i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// br label %{{[^,]+}}, !llvm.loop ![[COLL1_LOOP_ID]]
+// CHECK: [[COLL1_END]]
+ }
+// i,j,l are updated; k is not updated.
+// CHECK: store i32 3, i32* [[I:%[^,]+]]
+// CHECK-NEXT: store i32 5, i32* [[I:%[^,]+]]
+// CHECK-NEXT: store i16 9, i16* [[I:%[^,]+]]
+// CHECK: ret void
+}
+
+extern char foo();
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}widened{{.*}}
+void widened(float *a, float *b, float *c, float *d) {
+ int i; // outer loop counter
+ short j; // inner loop counter
+// Counter is widened to 64 bits.
+// CHECK: store i64 0, i64* [[OMP_IV:[^,]+]]
+//
+ #pragma omp simd collapse(2)
+
+// CHECK: [[IV:%.+]] = load i64* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID:[0-9]+]]
+// CHECK-NEXT: [[LI:%.+]] = load i64* [[OMP_LI:%[^,]+]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK-NEXT: [[NUMIT:%.+]] = add nsw i64 [[LI]], 1
+// CHECK-NEXT: [[CMP:%.+]] = icmp slt i64 [[IV]], [[NUMIT]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[WIDE1_BODY:[^,]+]], label %[[WIDE1_END:[^,]+]]
+ for (i = 1; i < 3; i++) // 2 iterations
+ for (j = 0; j < foo(); j++) // foo() iterations
+ {
+// CHECK: [[WIDE1_BODY]]
+// Start of body: calculate i from index:
+// CHECK: [[IV1:%.+]] = load i64* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// Calculation of the loop counters values...
+// CHECK: store i32 {{[^,]+}}, i32* [[LC_I:.+]]
+// CHECK: [[IV1_2:%.+]] = load i64* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: store i16 {{[^,]+}}, i16* [[LC_J:.+]]
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+ float res = b[j] * c[j];
+ a[i] = res * d[i];
+// CHECK: [[IV2:%.+]] = load i64* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK-NEXT: [[ADD2:%.+]] = add nsw i64 [[IV2]], 1
+// CHECK-NEXT: store i64 [[ADD2]], i64* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// br label %{{[^,]+}}, !llvm.loop ![[WIDE1_LOOP_ID]]
+// CHECK: [[WIDE1_END]]
+ }
+// i,j are updated.
+// CHECK: store i32 3, i32* [[I:%[^,]+]]
+// CHECK: store i16
+// CHECK: ret void
+}
+
+#endif // HEADER
+
diff --git a/test/OpenMP/simd_loop_messages.cpp b/test/OpenMP/simd_loop_messages.cpp
index ea663fddd9cf..ce64842d68a9 100644
--- a/test/OpenMP/simd_loop_messages.cpp
+++ b/test/OpenMP/simd_loop_messages.cpp
@@ -2,6 +2,7 @@
static int sii;
#pragma omp threadprivate(sii) // expected-note {{defined as threadprivate or thread local}}
+static int globalii;
int test_iteration_spaces() {
const int N = 100;
@@ -257,6 +258,23 @@ int test_iteration_spaces() {
c[sii] = a[sii];
}
+ #pragma omp parallel
+ {
+ // expected-error@+2 {{loop iteration variable in the associated loop of 'omp simd' directive may not be a variable with global storage without being explicitly marked as linear}}
+ #pragma omp simd
+ for (globalii = 0; globalii < 10; globalii+=1)
+ c[globalii] = a[globalii];
+ }
+
+ #pragma omp parallel
+ {
+// expected-error@+3 {{loop iteration variable in the associated loop of 'omp simd' directive may not be a variable with global storage without being explicitly marked as lastprivate}}
+#pragma omp simd collapse(2)
+ for (ii = 0; ii < 10; ii += 1)
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] += a[globalii] + ii;
+ }
+
// expected-error@+2 {{statement after '#pragma omp simd' must be a for loop}}
#pragma omp simd
for (auto &item : a) {
@@ -300,8 +318,10 @@ class Iter0 {
Iter0(const Iter0 &) { }
Iter0 operator ++() { return *this; }
Iter0 operator --() { return *this; }
+ Iter0 operator + (int delta) { return *this; }
bool operator <(Iter0 a) { return true; }
};
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'Iter0' for 1st argument}}
int operator -(Iter0 a, Iter0 b) { return 0; }
class Iter1 {
public:
@@ -330,10 +350,14 @@ class GoodIter {
typedef int difference_type;
typedef std::random_access_iterator_tag iterator_category;
};
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
int operator -(GoodIter a, GoodIter b) { return 0; }
+// expected-note@+1 2 {{candidate function not viable: requires single argument 'a', but 2 arguments were provided}}
GoodIter operator -(GoodIter a) { return a; }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
GoodIter operator -(GoodIter a, int v) { return GoodIter(); }
GoodIter operator +(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'int' for 1st argument}}
GoodIter operator -(int v, GoodIter a) { return GoodIter(); }
GoodIter operator +(int v, GoodIter a) { return GoodIter(); }
@@ -370,7 +394,7 @@ int test_with_random_access_iterator() {
for (begin = GoodIter(0); begin < end; ++begin)
++begin;
#pragma omp simd
- for (begin = begin0; begin < end; ++begin)
+ for (begin = GoodIter(1,2); begin < end; ++begin)
++begin;
// expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
#pragma omp simd
@@ -415,12 +439,16 @@ int test_with_random_access_iterator() {
#pragma omp simd
for (Iter0 I = begin0; I < end0; ++I)
++I;
+
// Initializer is constructor without params.
// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
#pragma omp simd
for (Iter0 I; I < end0; ++I)
++I;
+
Iter1 begin1, end1;
+ // expected-error@+3 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+ // expected-error@+2 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
#pragma omp simd
for (Iter1 I = begin1; I < end1; ++I)
++I;
@@ -429,11 +457,15 @@ int test_with_random_access_iterator() {
#pragma omp simd
for (Iter1 I = begin1; I >= end1; ++I)
++I;
+
// Initializer is constructor with all default params.
+ // expected-error@+4 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+ // expected-error@+3 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
#pragma omp simd
for (Iter1 I; I < end1; ++I) {
}
+
return 0;
}
diff --git a/test/OpenMP/simd_metadata.c b/test/OpenMP/simd_metadata.c
index a0588adf7dad..4552669c80b7 100644
--- a/test/OpenMP/simd_metadata.c
+++ b/test/OpenMP/simd_metadata.c
@@ -1,10 +1,23 @@
-// RUN: %clang_cc1 -fopenmp=libiomp5 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
-void h1(float *c, float *a, float *b, int size)
+void h1(float *c, float *a, double b[], int size)
{
// CHECK-LABEL: define void @h1
int t = 0;
-#pragma omp simd safelen(16) linear(t)
+#pragma omp simd safelen(16) linear(t) aligned(c:32) aligned(a,b)
+// CHECK: [[C_PTRINT:%.+]] = ptrtoint
+// CHECK-NEXT: [[C_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[C_PTRINT]], 31
+// CHECK-NEXT: [[C_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[C_MASKEDPTR]], 0
+// CHECK-NEXT: call void @llvm.assume(i1 [[C_MASKCOND]])
+// CHECK: [[A_PTRINT:%.+]] = ptrtoint
+// CHECK-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 15
+// CHECK-NEXT: [[A_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[A_MASKEDPTR]], 0
+// CHECK-NEXT: call void @llvm.assume(i1 [[A_MASKCOND]])
+// CHECK: [[B_PTRINT:%.+]] = ptrtoint
+// CHECK-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 15
+// CHECK-NEXT: [[B_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[B_MASKEDPTR]], 0
+// CHECK-NEXT: call void @llvm.assume(i1 [[B_MASKCOND]])
for (int i = 0; i < size; ++i) {
c[i] = a[i] * a[i] + b[i] * b[t];
++t;
@@ -39,13 +52,13 @@ void h3(float *c, float *a, float *b, int size)
}
// Metadata for h1:
-// CHECK: [[LOOP_H1_HEADER:![0-9]+]] = metadata !{metadata [[LOOP_H1_HEADER]], metadata [[LOOP_WIDTH_16:![0-9]+]], metadata [[LOOP_VEC_ENABLE:![0-9]+]]}
-// CHECK: [[LOOP_WIDTH_16]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 16}
-// CHECK: [[LOOP_VEC_ENABLE]] = metadata !{metadata !"llvm.loop.vectorize.enable", i1 true}
+// CHECK: [[LOOP_H1_HEADER:![0-9]+]] = distinct !{[[LOOP_H1_HEADER]], [[LOOP_WIDTH_16:![0-9]+]], [[LOOP_VEC_ENABLE:![0-9]+]]}
+// CHECK: [[LOOP_WIDTH_16]] = !{!"llvm.loop.vectorize.width", i32 16}
+// CHECK: [[LOOP_VEC_ENABLE]] = !{!"llvm.loop.vectorize.enable", i1 true}
//
// Metadata for h2:
-// CHECK: [[LOOP_H2_HEADER]] = metadata !{metadata [[LOOP_H2_HEADER]], metadata [[LOOP_VEC_ENABLE]]}
+// CHECK: [[LOOP_H2_HEADER]] = distinct !{[[LOOP_H2_HEADER]], [[LOOP_VEC_ENABLE]]}
//
// Metadata for h3:
-// CHECK: [[LOOP_H3_HEADER:![0-9]+]] = metadata !{metadata [[LOOP_H3_HEADER]], metadata [[LOOP_VEC_ENABLE]]}
+// CHECK: [[LOOP_H3_HEADER:![0-9]+]] = distinct !{[[LOOP_H3_HEADER]], [[LOOP_VEC_ENABLE]]}
//
diff --git a/test/OpenMP/simd_misc_messages.c b/test/OpenMP/simd_misc_messages.c
index 67edc6d1f867..f94bb3870ca2 100644
--- a/test/OpenMP/simd_misc_messages.c
+++ b/test/OpenMP/simd_misc_messages.c
@@ -9,26 +9,25 @@
// expected-error@+1 {{unexpected OpenMP directive '#pragma omp simd'}}
#pragma omp simd safelen(4)
-void test_no_clause()
-{
+void test_no_clause() {
int i;
- #pragma omp simd
- for (i = 0; i < 16; ++i) ;
+#pragma omp simd
+ for (i = 0; i < 16; ++i)
+ ;
- // expected-error@+2 {{statement after '#pragma omp simd' must be a for loop}}
- #pragma omp simd
+// expected-error@+2 {{statement after '#pragma omp simd' must be a for loop}}
+#pragma omp simd
++i;
}
-void test_branch_protected_scope()
-{
+void test_branch_protected_scope() {
int i = 0;
L1:
++i;
int x[24];
- #pragma omp simd
+#pragma omp simd
for (i = 0; i < 16; ++i) {
if (i == 5)
goto L1; // expected-error {{use of undeclared label 'L1'}}
@@ -37,7 +36,7 @@ L1:
else if (i == 7)
goto L2;
else if (i == 8) {
-L2:
+ L2:
x[i]++;
}
}
@@ -48,506 +47,632 @@ L2:
goto L1;
}
-void test_invalid_clause()
-{
+void test_invalid_clause() {
int i;
- // expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}}
- #pragma omp simd foo bar
- for (i = 0; i < 16; ++i) ;
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}}
+#pragma omp simd foo bar
+ for (i = 0; i < 16; ++i)
+ ;
}
-void test_non_identifiers()
-{
+void test_non_identifiers() {
int i, x;
- // expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}}
- #pragma omp simd;
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}}
- // expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}}
- #pragma omp simd firstprivate(x);
- for (i = 0; i < 16; ++i) ;
-
- // expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}}
- #pragma omp simd private(x);
- for (i = 0; i < 16; ++i) ;
-
- // expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}}
- #pragma omp simd , private(x);
- for (i = 0; i < 16; ++i) ;
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}}
+#pragma omp simd;
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}}
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}}
+#pragma omp simd firstprivate(x);
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}}
+#pragma omp simd private(x);
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}}
+#pragma omp simd, private(x);
+ for (i = 0; i < 16; ++i)
+ ;
}
extern int foo();
-void test_safelen()
-{
+void test_safelen() {
int i;
- // expected-error@+1 {{expected '('}}
- #pragma omp simd safelen
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd safelen(
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd safelen()
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd safelen(,
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd safelen(,)
- for (i = 0; i < 16; ++i) ;
- // expected-warning@+2 {{extra tokens at the end of '#pragma omp simd' are ignored}}
- // expected-error@+1 {{expected '('}}
- #pragma omp simd safelen 4)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}}
- #pragma omp simd safelen(4
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}}
- #pragma omp simd safelen(4,
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}}
- #pragma omp simd safelen(4,)
- for (i = 0; i < 16; ++i) ;
- // xxpected-error@+1 {{expected expression}}
- #pragma omp simd safelen(4)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}}
- #pragma omp simd safelen(4 4)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}}
- #pragma omp simd safelen(4,,4)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd safelen(4)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}}
- #pragma omp simd safelen(4,8)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expression is not an integer constant expression}}
- #pragma omp simd safelen(2.5)
- for (i = 0; i < 16; ++i);
- // expected-error@+1 {{expression is not an integer constant expression}}
- #pragma omp simd safelen(foo())
- for (i = 0; i < 16; ++i);
- // expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
- #pragma omp simd safelen(-5)
- for (i = 0; i < 16; ++i);
- // expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
- #pragma omp simd safelen(0)
- for (i = 0; i < 16; ++i);
- // expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
- #pragma omp simd safelen(5-5)
- for (i = 0; i < 16; ++i);
+// expected-error@+1 {{expected '('}}
+#pragma omp simd safelen
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd safelen(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd safelen()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd safelen(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd safelen(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-warning@+2 {{extra tokens at the end of '#pragma omp simd' are ignored}}
+// expected-error@+1 {{expected '('}}
+#pragma omp simd safelen 4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp simd safelen(4
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp simd safelen(4,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp simd safelen(4, )
+ for (i = 0; i < 16; ++i)
+ ;
+// xxpected-error@+1 {{expected expression}}
+#pragma omp simd safelen(4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp simd safelen(4 4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp simd safelen(4, , 4)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd safelen(4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}}
+#pragma omp simd safelen(4, 8)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp simd safelen(2.5)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp simd safelen(foo())
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+#pragma omp simd safelen(-5)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+#pragma omp simd safelen(0)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+#pragma omp simd safelen(5 - 5)
+ for (i = 0; i < 16; ++i)
+ ;
}
-void test_collapse()
-{
+void test_collapse() {
int i;
- // expected-error@+1 {{expected '('}}
- #pragma omp simd collapse
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd collapse(
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd collapse()
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd collapse(,
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd collapse(,)
- for (i = 0; i < 16; ++i) ;
- // expected-warning@+2 {{extra tokens at the end of '#pragma omp simd' are ignored}}
- // expected-error@+1 {{expected '('}}
- #pragma omp simd collapse 4)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
- #pragma omp simd collapse(4
- for (i = 0; i < 16; ++i) ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
- #pragma omp simd collapse(4,
- for (i = 0; i < 16; ++i) ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
- #pragma omp simd collapse(4,)
- for (i = 0; i < 16; ++i) ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
- // xxpected-error@+1 {{expected expression}} expected-note@+1 {{as specified in 'collapse' clause}}
- #pragma omp simd collapse(4)
- for (i = 0; i < 16; ++i) ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
- #pragma omp simd collapse(4 4)
- for (i = 0; i < 16; ++i) ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
- #pragma omp simd collapse(4,,4)
- for (i = 0; i < 16; ++i) ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
- #pragma omp simd collapse(4)
+// expected-error@+1 {{expected '('}}
+#pragma omp simd collapse
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd collapse(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd collapse()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd collapse(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd collapse(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-warning@+2 {{extra tokens at the end of '#pragma omp simd' are ignored}}
+// expected-error@+1 {{expected '('}}
+#pragma omp simd collapse 4)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp simd collapse(4
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp simd collapse(4,
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp simd collapse(4, )
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
+// xxpected-error@+1 {{expected expression}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp simd collapse(4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp simd collapse(4 4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp simd collapse(4, , 4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
+#pragma omp simd collapse(4)
for (int i1 = 0; i1 < 16; ++i1)
for (int i2 = 0; i2 < 16; ++i2)
for (int i3 = 0; i3 < 16; ++i3)
for (int i4 = 0; i4 < 16; ++i4)
foo();
- // expected-error@+2 {{expected ')'}}
- // expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
- #pragma omp simd collapse(4,8)
- for (i = 0; i < 16; ++i) ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
- // expected-error@+1 {{expression is not an integer constant expression}}
- #pragma omp simd collapse(2.5)
- for (i = 0; i < 16; ++i);
- // expected-error@+1 {{expression is not an integer constant expression}}
- #pragma omp simd collapse(foo())
- for (i = 0; i < 16; ++i);
- // expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
- #pragma omp simd collapse(-5)
- for (i = 0; i < 16; ++i);
- // expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
- #pragma omp simd collapse(0)
- for (i = 0; i < 16; ++i);
- // expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
- #pragma omp simd collapse(5-5)
- for (i = 0; i < 16; ++i);
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp simd collapse(4, 8)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp simd', but found only 1}}
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp simd collapse(2.5)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp simd collapse(foo())
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+#pragma omp simd collapse(-5)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+#pragma omp simd collapse(0)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+#pragma omp simd collapse(5 - 5)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-note@+2 {{defined as reduction}}
+#pragma omp parallel
+#pragma omp simd collapse(2) reduction(+ : i)
+ for (i = 0; i < 16; ++i)
+ // expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}}
+ for (int j = 0; j < 16; ++j)
+// expected-error@+3 {{reduction variable must be shared}}
+// expected-error@+2 {{private variable cannot be reduction}}
+// expected-error@+1 {{OpenMP constructs may not be nested inside a simd region}}
+#pragma omp for reduction(+ : i, j)
+ for (int k = 0; k < 16; ++k)
+ i += j;
}
-void test_linear()
-{
+void test_linear() {
int i;
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd linear(
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected expression}}
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd linear(,
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected expression}}
- // expected-error@+1 {{expected expression}}
- #pragma omp simd linear(,)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd linear()
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd linear(int)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected variable name}}
- #pragma omp simd linear(0)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{use of undeclared identifier 'x'}}
- #pragma omp simd linear(x)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{use of undeclared identifier 'x'}}
- // expected-error@+1 {{use of undeclared identifier 'y'}}
- #pragma omp simd linear(x, y)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+3 {{use of undeclared identifier 'x'}}
- // expected-error@+2 {{use of undeclared identifier 'y'}}
- // expected-error@+1 {{use of undeclared identifier 'z'}}
- #pragma omp simd linear(x, y, z)
- for (i = 0; i < 16; ++i) ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd linear(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd linear(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}}
+#pragma omp simd linear(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd linear()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd linear(int)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected variable name}}
+#pragma omp simd linear(0)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{use of undeclared identifier 'x'}}
+#pragma omp simd linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{use of undeclared identifier 'x'}}
+// expected-error@+1 {{use of undeclared identifier 'y'}}
+#pragma omp simd linear(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+3 {{use of undeclared identifier 'x'}}
+// expected-error@+2 {{use of undeclared identifier 'y'}}
+// expected-error@+1 {{use of undeclared identifier 'z'}}
+#pragma omp simd linear(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
int x, y;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd linear(x:)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd linear(x:,)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd linear(x:1)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd linear(x:2*2)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd linear(x:1,y)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd linear(x:1,y,z:1)
- for (i = 0; i < 16; ++i) ;
-
- // expected-note@+2 {{defined as linear}}
- // expected-error@+1 {{linear variable cannot be linear}}
- #pragma omp simd linear(x) linear(x)
- for (i = 0; i < 16; ++i) ;
-
- // expected-note@+2 {{defined as private}}
- // expected-error@+1 {{private variable cannot be linear}}
- #pragma omp simd private(x) linear(x)
- for (i = 0; i < 16; ++i) ;
-
- // expected-note@+2 {{defined as linear}}
- // expected-error@+1 {{linear variable cannot be private}}
- #pragma omp simd linear(x) private(x)
- for (i = 0; i < 16; ++i) ;
-
- // expected-warning@+1 {{zero linear step (x and other variables in clause should probably be const)}}
- #pragma omp simd linear(x,y:0)
- for (i = 0; i < 16; ++i) ;
-
- // expected-note@+2 {{defined as linear}}
- // expected-error@+1 {{linear variable cannot be lastprivate}}
- #pragma omp simd linear(x) lastprivate(x)
- for (i = 0; i < 16; ++i) ;
-
- // expected-note@+2 {{defined as lastprivate}}
- // expected-error@+1 {{lastprivate variable cannot be linear}}
- #pragma omp simd lastprivate(x) linear(x)
- for (i = 0; i < 16; ++i) ;
-
+// expected-error@+1 {{expected expression}}
+#pragma omp simd linear(x :)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd linear(x :, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd linear(x : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd linear(x : 2 * 2)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd linear(x : 1, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd linear(x : 1, y, z : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as linear}}
+// expected-error@+1 {{linear variable cannot be linear}}
+#pragma omp simd linear(x) linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as private}}
+// expected-error@+1 {{private variable cannot be linear}}
+#pragma omp simd private(x) linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as linear}}
+// expected-error@+1 {{linear variable cannot be private}}
+#pragma omp simd linear(x) private(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-warning@+1 {{zero linear step (x and other variables in clause should probably be const)}}
+#pragma omp simd linear(x, y : 0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as linear}}
+// expected-error@+1 {{linear variable cannot be lastprivate}}
+#pragma omp simd linear(x) lastprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as lastprivate}}
+// expected-error@+1 {{lastprivate variable cannot be linear}}
+#pragma omp simd lastprivate(x) linear(x)
+ for (i = 0; i < 16; ++i)
+ ;
}
-void test_aligned()
-{
+void test_aligned() {
int i;
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd aligned(
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected expression}}
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd aligned(,
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected expression}}
- // expected-error@+1 {{expected expression}}
- #pragma omp simd aligned(,)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd aligned()
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd aligned(int)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected variable name}}
- #pragma omp simd aligned(0)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{use of undeclared identifier 'x'}}
- #pragma omp simd aligned(x)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{use of undeclared identifier 'x'}}
- // expected-error@+1 {{use of undeclared identifier 'y'}}
- #pragma omp simd aligned(x, y)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+3 {{use of undeclared identifier 'x'}}
- // expected-error@+2 {{use of undeclared identifier 'y'}}
- // expected-error@+1 {{use of undeclared identifier 'z'}}
- #pragma omp simd aligned(x, y, z)
- for (i = 0; i < 16; ++i) ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd aligned(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd aligned(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected expression}}
+#pragma omp simd aligned(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd aligned()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd aligned(int)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected variable name}}
+#pragma omp simd aligned(0)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{use of undeclared identifier 'x'}}
+#pragma omp simd aligned(x)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{use of undeclared identifier 'x'}}
+// expected-error@+1 {{use of undeclared identifier 'y'}}
+#pragma omp simd aligned(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+3 {{use of undeclared identifier 'x'}}
+// expected-error@+2 {{use of undeclared identifier 'y'}}
+// expected-error@+1 {{use of undeclared identifier 'z'}}
+#pragma omp simd aligned(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
int *x, y, z[25]; // expected-note 4 {{'y' defined here}}
- #pragma omp simd aligned(x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd aligned(z)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd aligned(x:)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd aligned(x:,)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd aligned(x:1)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd aligned(x:2*2)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd aligned(x:1,y)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd aligned(x:1,y,z:1)
- for (i = 0; i < 16; ++i) ;
-
- // expected-error@+1 {{argument of aligned clause should be array or pointer, not 'int'}}
- #pragma omp simd aligned(x, y)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{argument of aligned clause should be array or pointer, not 'int'}}
- #pragma omp simd aligned(x, y, z)
- for (i = 0; i < 16; ++i) ;
-
- // expected-note@+2 {{defined as aligned}}
- // expected-error@+1 {{a variable cannot appear in more than one aligned clause}}
- #pragma omp simd aligned(x) aligned(z,x)
- for (i = 0; i < 16; ++i) ;
-
- // expected-note@+3 {{defined as aligned}}
- // expected-error@+2 {{a variable cannot appear in more than one aligned clause}}
- // expected-error@+1 2 {{argument of aligned clause should be array or pointer, not 'int'}}
- #pragma omp simd aligned(x,y,z) aligned(y,z)
- for (i = 0; i < 16; ++i) ;
+#pragma omp simd aligned(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd aligned(z)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd aligned(x :)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd aligned(x :, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd aligned(x : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd aligned(x : 2 * 2)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd aligned(x : 1, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd aligned(x : 1, y, z : 1)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-error@+1 {{argument of aligned clause should be array or pointer, not 'int'}}
+#pragma omp simd aligned(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{argument of aligned clause should be array or pointer, not 'int'}}
+#pragma omp simd aligned(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+2 {{defined as aligned}}
+// expected-error@+1 {{a variable cannot appear in more than one aligned clause}}
+#pragma omp simd aligned(x) aligned(z, x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-note@+3 {{defined as aligned}}
+// expected-error@+2 {{a variable cannot appear in more than one aligned clause}}
+// expected-error@+1 2 {{argument of aligned clause should be array or pointer, not 'int'}}
+#pragma omp simd aligned(x, y, z) aligned(y, z)
+ for (i = 0; i < 16; ++i)
+ ;
}
-void test_private()
-{
+void test_private() {
int i;
- // expected-error@+2 {{expected expression}}
- // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
- #pragma omp simd private(
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
- // expected-error@+1 2 {{expected expression}}
- #pragma omp simd private(,
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 2 {{expected expression}}
- #pragma omp simd private(,)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd private()
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd private(int)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected variable name}}
- #pragma omp simd private(0)
- for (i = 0; i < 16; ++i) ;
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp simd private(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp simd private(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 2 {{expected expression}}
+#pragma omp simd private(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd private()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd private(int)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected variable name}}
+#pragma omp simd private(0)
+ for (i = 0; i < 16; ++i)
+ ;
int x, y, z;
- #pragma omp simd private(x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd private(x, y)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd private(x, y, z)
+#pragma omp simd private(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd private(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd private(x, y, z)
for (i = 0; i < 16; ++i) {
x = y * i + z;
}
}
-void test_firstprivate()
-{
+void test_firstprivate() {
int i;
- // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
- // expected-error@+2 {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}}
- // expected-error@+1 {{expected expression}}
- #pragma omp simd firstprivate(
- for (i = 0; i < 16; ++i) ;
+// expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}}
+// expected-error@+1 {{expected expression}}
+#pragma omp simd firstprivate(
+ for (i = 0; i < 16; ++i)
+ ;
}
-void test_lastprivate()
-{
+void test_lastprivate() {
int i;
- // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
- // expected-error@+1 {{expected expression}}
- #pragma omp simd lastprivate(
- for (i = 0; i < 16; ++i) ;
-
- // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
- // expected-error@+1 2 {{expected expression}}
- #pragma omp simd lastprivate(,
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 2 {{expected expression}}
- #pragma omp simd lastprivate(,)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd lastprivate()
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd lastprivate(int)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected variable name}}
- #pragma omp simd lastprivate(0)
- for (i = 0; i < 16; ++i) ;
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 {{expected expression}}
+#pragma omp simd lastprivate(
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp simd lastprivate(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 2 {{expected expression}}
+#pragma omp simd lastprivate(, )
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd lastprivate()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd lastprivate(int)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected variable name}}
+#pragma omp simd lastprivate(0)
+ for (i = 0; i < 16; ++i)
+ ;
int x, y, z;
- #pragma omp simd lastprivate(x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd lastprivate(x, y)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd lastprivate(x, y, z)
- for (i = 0; i < 16; ++i) ;
+#pragma omp simd lastprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd lastprivate(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd lastprivate(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
}
-void test_reduction()
-{
+void test_reduction() {
int i, x, y;
- // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
- // expected-error@+2 {{expected identifier}}
- // expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
- #pragma omp simd reduction(
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected identifier}}
- // expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
- #pragma omp simd reduction()
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected expression}}
- // expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
- #pragma omp simd reduction(x)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected identifier}}
- #pragma omp simd reduction(:x)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
- // expected-error@+2 {{expected identifier}}
- // expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
- #pragma omp simd reduction(,
- for (i = 0; i < 16; ++i) ;
- // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
- // expected-error@+2 {{expected expression}}
- // expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
- #pragma omp simd reduction(+
- for (i = 0; i < 16; ++i) ;
-
- // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
- //
- // expected-error@+1 {{expected expression}}
- #pragma omp simd reduction(+:
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd reduction(+:)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd reduction(+:,y)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected expression}}
- #pragma omp simd reduction(+:x,+:y)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+2 {{expected identifier}}
- // expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
- #pragma omp simd reduction(%:x)
- for (i = 0; i < 16; ++i) ;
-
- #pragma omp simd reduction(+:x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd reduction(*:x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd reduction(-:x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd reduction(&:x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd reduction(|:x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd reduction(^:x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd reduction(&&:x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd reduction(||:x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd reduction(max:x)
- for (i = 0; i < 16; ++i) ;
- #pragma omp simd reduction(min:x)
- for (i = 0; i < 16; ++i) ;
- struct X { int x; };
+// expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected identifier}}
+// expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
+#pragma omp simd reduction(
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected identifier}}
+// expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
+#pragma omp simd reduction()
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+2 {{expected expression}}
+// expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
+#pragma omp simd reduction(x)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected identifier}}
+#pragma omp simd reduction( : x)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected identifier}}
+// expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
+#pragma omp simd reduction(,
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected expression}}
+// expected-warning@+1 {{missing ':' after reduction identifier - ignoring}}
+#pragma omp simd reduction(+
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+//
+// expected-error@+1 {{expected expression}}
+#pragma omp simd reduction(+:
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd reduction(+ :)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd reduction(+ :, y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected expression}}
+#pragma omp simd reduction(+ : x, + : y)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected identifier}}
+#pragma omp simd reduction(% : x)
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp simd reduction(+ : x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd reduction(* : x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd reduction(- : x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd reduction(& : x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd reduction(| : x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd reduction(^ : x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd reduction(&& : x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd reduction(|| : x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd reduction(max : x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp simd reduction(min : x)
+ for (i = 0; i < 16; ++i)
+ ;
+ struct X {
+ int x;
+ };
struct X X;
- // expected-error@+1 {{expected variable name}}
- #pragma omp simd reduction(+:X.x)
- for (i = 0; i < 16; ++i) ;
- // expected-error@+1 {{expected variable name}}
- #pragma omp simd reduction(+:x+x)
- for (i = 0; i < 16; ++i) ;
+// expected-error@+1 {{expected variable name}}
+#pragma omp simd reduction(+ : X.x)
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{expected variable name}}
+#pragma omp simd reduction(+ : x + x)
+ for (i = 0; i < 16; ++i)
+ ;
}
-void test_loop_messages()
-{
+void test_loop_messages() {
float a[100], b[100], c[100];
- // expected-error@+2 {{variable must be of integer or pointer type}}
- #pragma omp simd
+// expected-error@+2 {{variable must be of integer or pointer type}}
+#pragma omp simd
for (float fi = 0; fi < 10.0; fi++) {
c[(int)fi] = a[(int)fi] + b[(int)fi];
}
- // expected-error@+2 {{variable must be of integer or pointer type}}
- #pragma omp simd
+// expected-error@+2 {{variable must be of integer or pointer type}}
+#pragma omp simd
for (double fi = 0; fi < 10.0; fi++) {
c[(int)fi] = a[(int)fi] + b[(int)fi];
}
diff --git a/test/OpenMP/simd_private_messages.cpp b/test/OpenMP/simd_private_messages.cpp
index e5e4fe5b8b39..56922e888b99 100644
--- a/test/OpenMP/simd_private_messages.cpp
+++ b/test/OpenMP/simd_private_messages.cpp
@@ -22,15 +22,15 @@ public:
S3():a(0) { }
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v):a(v) { }
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5():a(0) {}
+ S5():a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v):a(v) { }
};
@@ -86,8 +86,8 @@ template<class I, class C> int foomain(I argc, C **argv) {
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp simd private // expected-error {{expected '(' after 'private'}}
@@ -110,7 +110,7 @@ int main(int argc, char **argv) {
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd private (argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k) ++k;
- #pragma omp simd private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+ #pragma omp simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
for (int k = 0; k < argc; ++k) ++k;
diff --git a/test/OpenMP/single_copyprivate_messages.cpp b/test/OpenMP/single_copyprivate_messages.cpp
index f07ab12bfb46..7bb145c6d325 100644
--- a/test/OpenMP/single_copyprivate_messages.cpp
+++ b/test/OpenMP/single_copyprivate_messages.cpp
@@ -155,3 +155,23 @@ int main(int argc, char **argv) {
return tmain(argc, argv); // expected-note {{in instantiation of function template specialization 'tmain<int, char>' requested here}}
}
+
+extern void abort(void);
+
+void
+single(int a, int b) {
+#pragma omp single copyprivate(a) copyprivate(b)
+ {
+ a = b = 5;
+ }
+
+ if (a != b)
+ abort();
+}
+
+int parallel() {
+#pragma omp parallel
+ single(1, 2);
+
+ return 0;
+}
diff --git a/test/OpenMP/single_firstprivate_messages.cpp b/test/OpenMP/single_firstprivate_messages.cpp
index 6d4988254fb6..9f6f16083544 100644
--- a/test/OpenMP/single_firstprivate_messages.cpp
+++ b/test/OpenMP/single_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
public:
S2() : a(0) {}
- S2(S2 &s2) : a(s2.a) {}
+ S2(const S2 &s2) : a(s2.a) {}
static float S2s;
static const float S2sc;
};
@@ -27,22 +27,22 @@ class S3 {
public:
S3() : a(0) {}
- S3(S3 &s3) : a(s3.a) {}
+ S3(const S3 &s3) : a(s3.a) {}
};
const S3 c;
const S3 ca[5];
extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4(const S4 &s4);
+ S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
int a;
- S5(const S5 &s5) : a(s5.a) {}
+ S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
public:
S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- C g(5); // expected-note 2 {{'g' defined here}}
+ I e(4);
+ C g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel
@@ -97,7 +97,7 @@ int foomain(int argc, char **argv) {
#pragma omp single firstprivate(argv[1]) // expected-error {{expected variable name}}
foo();
#pragma omp parallel
-#pragma omp single firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp single firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
foo();
#pragma omp parallel
#pragma omp single firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
@@ -121,7 +121,7 @@ int foomain(int argc, char **argv) {
#pragma omp single firstprivate(i)
foo();
#pragma omp parallel
-#pragma omp single firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp single firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
foo();
#pragma omp parallel private(i) // expected-note {{defined as private}}
#pragma omp single firstprivate(i) // expected-error {{firstprivate variable must be shared}}
@@ -135,8 +135,8 @@ int foomain(int argc, char **argv) {
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note 2 {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
S3 m;
S6 n(2);
int i;
@@ -197,7 +197,7 @@ int main(int argc, char **argv) {
#pragma omp single safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp single'}}
foo();
#pragma omp parallel
-#pragma omp single firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp single firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
foo();
#pragma omp parallel
#pragma omp single firstprivate(m) // OK
@@ -215,7 +215,7 @@ int main(int argc, char **argv) {
#pragma omp single firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
foo();
#pragma omp parallel
-#pragma omp single firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp single firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
foo();
#pragma omp parallel
#pragma omp single firstprivate(n) // OK
diff --git a/test/OpenMP/single_private_messages.cpp b/test/OpenMP/single_private_messages.cpp
index 1414a92ee030..8bdc48f1a506 100644
--- a/test/OpenMP/single_private_messages.cpp
+++ b/test/OpenMP/single_private_messages.cpp
@@ -24,16 +24,16 @@ public:
S3() : a(0) {}
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -92,8 +92,8 @@ int foomain(I argc, C **argv) {
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp single private // expected-error {{expected '(' after 'private'}}
@@ -116,7 +116,7 @@ int main(int argc, char **argv) {
foo();
#pragma omp single private(argv[1]) // expected-error {{expected variable name}}
foo();
-#pragma omp single private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp single private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
foo();
#pragma omp single private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
foo();
diff --git a/test/OpenMP/target_ast_print.cpp b/test/OpenMP/target_ast_print.cpp
new file mode 100644
index 000000000000..c57c04955f8d
--- /dev/null
+++ b/test/OpenMP/target_ast_print.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void foo() {}
+
+template <typename T, int C>
+T tmain(T argc, T *argv) {
+#pragma omp target
+ foo();
+#pragma omp target if (argc > 0)
+ foo();
+#pragma omp target if (C)
+ foo();
+ return 0;
+}
+
+// CHECK: template <typename T = int, int C = 5> int tmain(int argc, int *argv) {
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target if(argc > 0)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target if(5)
+// CHECK-NEXT: foo()
+// CHECK: template <typename T = char, int C = 1> char tmain(char argc, char *argv) {
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target if(argc > 0)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target if(1)
+// CHECK-NEXT: foo()
+// CHECK: template <typename T, int C> T tmain(T argc, T *argv) {
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target if(argc > 0)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target if(C)
+// CHECK-NEXT: foo()
+
+// CHECK-LABEL: int main(int argc, char **argv) {
+int main (int argc, char **argv) {
+#pragma omp target
+// CHECK-NEXT: #pragma omp target
+ foo();
+// CHECK-NEXT: foo();
+#pragma omp target if (argc > 0)
+// CHECK-NEXT: #pragma omp target if(argc > 0)
+ foo();
+// CHECK-NEXT: foo();
+ return tmain<int, 5>(argc, &argc) + tmain<char, 1>(argv[0][0], argv[0]);
+}
+
+#endif
diff --git a/test/OpenMP/target_if_messages.cpp b/test/OpenMP/target_if_messages.cpp
new file mode 100644
index 000000000000..50a9ed2a202f
--- /dev/null
+++ b/test/OpenMP/target_if_messages.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+ #pragma omp target if // expected-error {{expected '(' after 'if'}}
+ #pragma omp target if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target if () // expected-error {{expected expression}}
+ #pragma omp target if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}}
+ #pragma omp target if (argc > 0 ? argv[1] : argv[2])
+ #pragma omp target if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp target' cannot contain more than one 'if' clause}}
+ #pragma omp target if (S) // expected-error {{'S' does not refer to a value}}
+ #pragma omp target if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target if (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target if(argc)
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp target if // expected-error {{expected '(' after 'if'}}
+ #pragma omp target if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target if () // expected-error {{expected expression}}
+ #pragma omp target if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}}
+ #pragma omp target if (argc > 0 ? argv[1] : argv[2])
+ #pragma omp target if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp target' cannot contain more than one 'if' clause}}
+ #pragma omp target if (S1) // expected-error {{'S1' does not refer to a value}}
+ #pragma omp target if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target if (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target if (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target if(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/target_messages.cpp b/test/OpenMP/target_messages.cpp
new file mode 100644
index 000000000000..fb492281e2b4
--- /dev/null
+++ b/test/OpenMP/target_messages.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -std=c++11 -o - %s
+
+void foo() {
+}
+
+#pragma omp target // expected-error {{unexpected OpenMP directive '#pragma omp target'}}
+
+int main(int argc, char **argv) {
+ #pragma omp target { // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}}
+ foo();
+ #pragma omp target ( // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}}
+ foo();
+ #pragma omp target [ // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}}
+ foo();
+ #pragma omp target ] // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}}
+ foo();
+ #pragma omp target ) // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}}
+ foo();
+ #pragma omp target } // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}}
+ foo();
+ #pragma omp target
+ // expected-warning@+1 {{extra tokens at the end of '#pragma omp target' are ignored}}
+ #pragma omp target unknown()
+ foo();
+ L1:
+ foo();
+ #pragma omp target
+ ;
+ #pragma omp target
+ {
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ argc++;
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ switch(argc) {
+ case (0):
+ #pragma omp target
+ {
+ foo();
+ break; // expected-error {{'break' statement not in loop or switch statement}}
+ continue; // expected-error {{'continue' statement not in loop statement}}
+ }
+ default:
+ break;
+ }
+ }
+
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+ #pragma omp target
+ L2:
+ foo();
+ #pragma omp target
+ {
+ return 1; // expected-error {{cannot return from OpenMP region}}
+ }
+
+ [[]] // expected-error {{an attribute list cannot appear here}}
+ #pragma omp target
+ for (int n = 0; n < 100; ++n) {}
+
+ return 0;
+}
+
diff --git a/test/OpenMP/task_firstprivate_messages.cpp b/test/OpenMP/task_firstprivate_messages.cpp
index 85d3f9f46144..6c5ccfca57bf 100644
--- a/test/OpenMP/task_firstprivate_messages.cpp
+++ b/test/OpenMP/task_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
public:
S2() : a(0) {}
- S2(S2 &s2) : a(s2.a) {}
+ S2(const S2 &s2) : a(s2.a) {}
static float S2s;
static const float S2sc;
};
@@ -26,23 +26,23 @@ class S3 {
public:
S3() : a(0) {}
- S3(S3 &s3) : a(s3.a) {}
+ S3(const S3 &s3) : a(s3.a) {}
};
const S3 c;
const S3 ca[5];
extern const int f;
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4(const S4 &s4);
+ S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
S5() : a(0) {}
- S5(const S5 &s5) : a(s5.a) {}
+ S5(const S5 &s5) : a(s5.a) {} // expected-note 2 {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -54,8 +54,8 @@ S3 h;
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp task firstprivate // expected-error {{expected '(' after 'firstprivate'}}
@@ -73,7 +73,7 @@ int main(int argc, char **argv) {
#pragma omp task firstprivate(da)
#pragma omp task firstprivate(S2::S2s)
#pragma omp task firstprivate(S2::S2sc)
-#pragma omp task firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp task firstprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}} expected-error 2 {{calling a private constructor of class 'S5'}}
#pragma omp task firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
#pragma omp task private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
foo();
diff --git a/test/OpenMP/task_messages.cpp b/test/OpenMP/task_messages.cpp
index 88c339afc117..b02b43c2b395 100644
--- a/test/OpenMP/task_messages.cpp
+++ b/test/OpenMP/task_messages.cpp
@@ -5,8 +5,8 @@ void foo() {
#pragma omp task // expected-error {{unexpected OpenMP directive '#pragma omp task'}}
-class S { // expected-note 6 {{'S' declared here}}
- S(const S &s) { a = s.a + 12; }
+class S {
+ S(const S &s) { a = s.a + 12; } // expected-note 6 {{implicitly declared private here}}
int a;
public:
@@ -17,23 +17,35 @@ public:
S operator+(const S &) { return *this; }
};
+class S1 {
+ int a;
+
+public:
+ S1() : a(0) {}
+ S1 &operator++() { return *this; }
+ S1(const S1 &) = delete; // expected-note 2 {{'S1' has been explicitly marked deleted here}}
+};
+
template <class T>
int foo() {
- T a; // expected-note 3 {{'a' defined here}}
+ T a;
T &b = a; // expected-note 4 {{'b' defined here}}
int r;
+ S1 s1;
+// expected-error@+1 2 {{call to deleted constructor of 'S1'}}
+#pragma omp task
+// expected-note@+1 2 {{predetermined as a firstprivate in a task construct here}}
+ ++s1;
#pragma omp task default(none)
#pragma omp task default(shared)
++a;
-// expected-error@+2 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
#pragma omp task default(none)
#pragma omp task
-// expected-note@+1 {{used here}}
+ // expected-error@+1 {{calling a private constructor of class 'S'}}
++a;
#pragma omp task
-// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
#pragma omp task
- // expected-note@+1 {{used here}}
+ // expected-error@+1 {{calling a private constructor of class 'S'}}
++a;
#pragma omp task default(shared)
#pragma omp task
@@ -46,11 +58,11 @@ int foo() {
#pragma omp task
// expected-note@+1 2 {{used here}}
++b;
-// expected-error@+3 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'int &'}}
-// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
-// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
+// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'int &'}}
+// expected-error@+1 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
#pragma omp task
-// expected-note@+1 3 {{used here}}
+// expected-error@+2 {{calling a private constructor of class 'S'}}
+// expected-note@+1 2 {{used here}}
#pragma omp parallel shared(a, b)
++a, ++b;
// expected-note@+1 3 {{defined as reduction}}
@@ -109,7 +121,7 @@ int foo() {
int main(int argc, char **argv) {
int a;
int &b = a; // expected-note 2 {{'b' defined here}}
- S sa; // expected-note 3 {{'sa' defined here}}
+ S sa;
S &sb = sa; // expected-note 2 {{'sb' defined here}}
int r;
#pragma omp task { // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
@@ -193,14 +205,12 @@ L2:
#pragma omp task default(shared)
++sa;
#pragma omp task default(none)
-// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
#pragma omp task
-// expected-note@+1 {{used here}}
+ // expected-error@+1 {{calling a private constructor of class 'S'}}
++sa;
#pragma omp task
-// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
#pragma omp task
-// expected-note@+1 {{used here}}
+ // expected-error@+1 {{calling a private constructor of class 'S'}}
++sa;
#pragma omp task default(shared)
#pragma omp task
@@ -212,10 +222,10 @@ L2:
#pragma omp task
// expected-note@+1 {{used here}}
++sb;
-// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
-// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
+// expected-error@+1 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
#pragma omp task
-// expected-note@+1 2 {{used here}}
+// expected-error@+2 {{calling a private constructor of class 'S'}}
+// expected-note@+1 {{used here}}
#pragma omp parallel shared(sa, sb)
++sa, ++sb;
// expected-note@+1 2 {{defined as reduction}}
diff --git a/test/OpenMP/task_private_messages.cpp b/test/OpenMP/task_private_messages.cpp
index 0be238dd90c4..9a3bb757681c 100644
--- a/test/OpenMP/task_private_messages.cpp
+++ b/test/OpenMP/task_private_messages.cpp
@@ -27,16 +27,16 @@ public:
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -48,8 +48,8 @@ int threadvar;
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp task private // expected-error {{expected '(' after 'private'}}
@@ -66,7 +66,7 @@ int main(int argc, char **argv) {
#pragma omp task private(ca) // expected-error {{shared variable cannot be private}}
#pragma omp task private(da) // expected-error {{shared variable cannot be private}}
#pragma omp task private(S2::S2s) // expected-error {{shared variable cannot be private}}
-#pragma omp task private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp task private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
#pragma omp task private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
#pragma omp task shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
foo();
diff --git a/test/OpenMP/teams_ast_print.cpp b/test/OpenMP/teams_ast_print.cpp
new file mode 100644
index 000000000000..394ec73a841c
--- /dev/null
+++ b/test/OpenMP/teams_ast_print.cpp
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void foo() {}
+
+template <class T>
+struct S {
+ operator T() {return T();}
+ static T TS;
+ #pragma omp threadprivate(TS)
+};
+
+// CHECK: template <class T = int> struct S {
+// CHECK: static int TS;
+// CHECK-NEXT: #pragma omp threadprivate(S<int>::TS)
+// CHECK-NEXT: }
+// CHECK: template <class T = long> struct S {
+// CHECK: static long TS;
+// CHECK-NEXT: #pragma omp threadprivate(S<long>::TS)
+// CHECK-NEXT: }
+// CHECK: template <class T> struct S {
+// CHECK: static T TS;
+// CHECK-NEXT: #pragma omp threadprivate(S::TS)
+// CHECK: };
+
+template <typename T, int C>
+T tmain(T argc, T *argv) {
+ T b = argc, c, d, e, f, g;
+ static T a;
+ S<T> s;
+#pragma omp target
+#pragma omp teams
+ a=2;
+#pragma omp target
+#pragma omp teams default(none), private(argc,b) firstprivate(argv) shared (d) reduction(+:c) reduction(max:e)
+ foo();
+#pragma omp target
+#pragma omp teams reduction(^:e, f) reduction(&& : g)
+ foo();
+ return 0;
+}
+
+// CHECK: template <typename T = int, int C = 5> int tmain(int argc, int *argv) {
+// CHECK-NEXT: int b = argc, c, d, e, f, g;
+// CHECK-NEXT: static int a;
+// CHECK-NEXT: S<int> s;
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) shared(d) reduction(+: c) reduction(max: e)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams reduction(^: e,f) reduction(&&: g)
+// CHECK-NEXT: foo()
+// CHECK: template <typename T = long, int C = 1> long tmain(long argc, long *argv) {
+// CHECK-NEXT: long b = argc, c, d, e, f, g;
+// CHECK-NEXT: static long a;
+// CHECK-NEXT: S<long> s;
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) shared(d) reduction(+: c) reduction(max: e)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams reduction(^: e,f) reduction(&&: g)
+// CHECK-NEXT: foo()
+// CHECK: template <typename T, int C> T tmain(T argc, T *argv) {
+// CHECK-NEXT: T b = argc, c, d, e, f, g;
+// CHECK-NEXT: static T a;
+// CHECK-NEXT: S<T> s;
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) shared(d) reduction(+: c) reduction(max: e)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams reduction(^: e,f) reduction(&&: g)
+// CHECK-NEXT: foo()
+
+enum Enum { };
+
+int main (int argc, char **argv) {
+ long x;
+ int b = argc, c, d, e, f, g;
+ static int a;
+ #pragma omp threadprivate(a)
+ Enum ee;
+// CHECK: Enum ee;
+#pragma omp target
+#pragma omp teams
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams
+ a=2;
+// CHECK-NEXT: a = 2;
+#pragma omp target
+#pragma omp teams default(none), private(argc,b) firstprivate(argv) reduction(| : c, d) reduction(* : e)
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) reduction(|: c,d) reduction(*: e)
+ foo();
+// CHECK-NEXT: foo();
+ return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);
+}
+
+#endif
diff --git a/test/OpenMP/teams_default_messages.cpp b/test/OpenMP/teams_default_messages.cpp
new file mode 100644
index 000000000000..4f5a267150f9
--- /dev/null
+++ b/test/OpenMP/teams_default_messages.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -o - %s
+
+void foo();
+
+int main(int argc, char **argv) {
+ #pragma omp target
+ #pragma omp teams default // expected-error {{expected '(' after 'default'}}
+ foo();
+ #pragma omp target
+ #pragma omp teams default ( // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp target
+ #pragma omp teams default () // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}}
+ foo();
+ #pragma omp target
+ #pragma omp teams default (none // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp target
+ #pragma omp teams default (shared), default(shared) // expected-error {{directive '#pragma omp teams' cannot contain more than one 'default' clause}}
+ foo();
+ #pragma omp target
+ #pragma omp teams default (x) // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}}
+ foo();
+
+ #pragma omp target
+ #pragma omp teams default(none)
+ ++argc; // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}}
+
+ #pragma omp target
+ #pragma omp teams default(none)
+ #pragma omp parallel default(shared)
+ ++argc;
+ return 0;
+}
diff --git a/test/OpenMP/teams_firstprivate_messages.cpp b/test/OpenMP/teams_firstprivate_messages.cpp
new file mode 100644
index 000000000000..3d4a21999eea
--- /dev/null
+++ b/test/OpenMP/teams_firstprivate_messages.cpp
@@ -0,0 +1,124 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note{{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2(const S2 &s2) : a(s2.a) {}
+ static float S2s;
+ static const float S2sc;
+};
+const float S2::S2sc = 0;
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+
+public:
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 {
+ int a;
+ S4();
+ S4(const S4 &s4); // expected-note {{implicitly declared private here}}
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5() : a(0) {}
+ S5(const S5 &s5) : a(s5.a) {} // expected-note {{implicitly declared private here}}
+public:
+ S5(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+
+int main(int argc, char **argv) {
+ const int d = 5;
+ const int da[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+#pragma omp target
+#pragma omp teams firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate() // expected-error {{expected expression}}
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(argc)
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(argv[1]) // expected-error {{expected variable name}}
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(ba)
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(ca)
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(da)
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(S2::S2s)
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(S2::S2sc)
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ foo();
+#pragma omp target
+#pragma omp teams private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
+ foo();
+#pragma omp target
+#pragma omp teams shared(i)
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(i)
+ foo();
+#pragma omp target
+#pragma omp teams firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
+ foo();
+
+ return 0;
+}
diff --git a/test/OpenMP/teams_messages.cpp b/test/OpenMP/teams_messages.cpp
new file mode 100644
index 000000000000..56ed548a0377
--- /dev/null
+++ b/test/OpenMP/teams_messages.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -std=c++11 -o - %s
+
+void foo() {
+}
+
+#pragma omp teams // expected-error {{unexpected OpenMP directive '#pragma omp teams'}}
+
+int main(int argc, char **argv) {
+ #pragma omp target
+ #pragma omp teams { // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+ #pragma omp target
+ #pragma omp teams ( // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+ #pragma omp target
+ #pragma omp teams [ // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+ #pragma omp target
+ #pragma omp teams ] // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+ #pragma omp target
+ #pragma omp teams ) // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+ #pragma omp target
+ #pragma omp teams } // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+ #pragma omp target
+ #pragma omp teams
+ foo();
+ // expected-warning@+2 {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ #pragma omp target
+ #pragma omp teams unknown()
+ foo();
+ L1:
+ foo();
+ #pragma omp target
+ #pragma omp teams
+ ;
+ #pragma omp target
+ #pragma omp teams
+ {
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ argc++;
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ switch(argc) {
+ case (0):
+ #pragma omp target
+ #pragma omp teams
+ {
+ foo();
+ break; // expected-error {{'break' statement not in loop or switch statement}}
+ continue; // expected-error {{'continue' statement not in loop statement}}
+ }
+ default:
+ break;
+ }
+ }
+ #pragma omp target
+ #pragma omp teams default(none)
+ ++argc; // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}}
+
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+ #pragma omp target
+ #pragma omp teams
+ L2:
+ foo();
+ #pragma omp target
+ #pragma omp teams
+ {
+ return 1; // expected-error {{cannot return from OpenMP region}}
+ }
+
+ [[]] // expected-error {{an attribute list cannot appear here}}
+ #pragma omp target
+ #pragma omp teams
+ for (int n = 0; n < 100; ++n) {}
+
+ return 0;
+}
+
diff --git a/test/OpenMP/teams_private_messages.cpp b/test/OpenMP/teams_private_messages.cpp
new file mode 100644
index 000000000000..16ecb74ea0cb
--- /dev/null
+++ b/test/OpenMP/teams_private_messages.cpp
@@ -0,0 +1,119 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note{{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
+};
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 c; // expected-note {{global variable is predetermined as shared}}
+const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
+extern const int f; // expected-note {{global variable is predetermined as shared}}
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {} // expected-note {{implicitly declared private here}}
+public:
+ S5(int v):a(v) { }
+};
+
+int threadvar;
+#pragma omp threadprivate(threadvar) // expected-note {{defined as threadprivate or thread local}}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note {{constant variable is predetermined as shared}}
+ const int da[5] = { 0 }; // expected-note {{constant variable is predetermined as shared}}
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp target
+ #pragma omp teams private // expected-error {{expected '(' after 'private'}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private () // expected-error {{expected expression}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private (argc argv) // expected-error {{expected ',' or ')' in 'private' clause}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private (S1) // expected-error {{'S1' does not refer to a value}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private (a, b, c, d, f) // expected-error {{a private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private (argv[1]) // expected-error {{expected variable name}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private(ba)
+ foo();
+ #pragma omp target
+ #pragma omp teams private(ca) // expected-error {{shared variable cannot be private}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private(da) // expected-error {{shared variable cannot be private}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private(S2::S2s) // expected-error {{shared variable cannot be private}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
+ foo();
+ #pragma omp target
+ #pragma omp teams shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
+ foo();
+ #pragma omp target
+ #pragma omp teams firstprivate(i) private(i) // expected-error {{firstprivate variable cannot be private}} expected-note {{defined as firstprivate}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private(i)
+ foo();
+ #pragma omp target
+ #pragma omp teams private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type 'int &'}}
+ foo();
+ #pragma omp target
+ #pragma omp teams firstprivate(i)
+ for (int k = 0; k < 10; ++k) {
+ #pragma omp parallel private(i)
+ foo();
+ }
+
+ return 0;
+}
diff --git a/test/OpenMP/teams_reduction_messages.cpp b/test/OpenMP/teams_reduction_messages.cpp
new file mode 100644
index 000000000000..afedfc3e46fd
--- /dev/null
+++ b/test/OpenMP/teams_reduction_messages.cpp
@@ -0,0 +1,307 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+ S2 &operator+=(const S2 &arg) { return (*this); }
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
+ static const float S2sc;
+};
+const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+S2 b; // expected-note 2 {{'b' defined here}}
+const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
+class S3 {
+ int a;
+
+public:
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+ S3 operator+=(const S3 &arg1) { return arg1; }
+};
+int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+S3 c; // expected-note 2 {{'c' defined here}}
+const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
+extern const int f; // expected-note 4 {{'f' declared here}}
+class S4 { // expected-note {{'S4' declared here}}
+ int a;
+ S4();
+ S4(const S4 &s4);
+ S4 &operator+=(const S4 &arg) { return (*this); }
+
+public:
+ S4(int v) : a(v) {}
+};
+S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
+class S5 {
+ int a;
+ S5() : a(0) {}
+ S5(const S5 &s5) : a(s5.a) {}
+ S5 &operator+=(const S5 &arg);
+
+public:
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+
+public:
+ S6() : a(6) {}
+ operator int() { return 6; }
+} o; // expected-note 2 {{'o' defined here}}
+
+S3 h, k;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class T> // expected-note {{declared here}}
+T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+ const T d = T(); // expected-note 4 {{'d' defined here}}
+ const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
+ T qa[5] = {T()};
+ T i;
+ T &j = i; // expected-note 4 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
+ T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
+ T fl; // expected-note {{'fl' defined here}}
+#pragma omp target
+#pragma omp teams reduction // expected-error {{expected '(' after 'reduction'}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(&& : argc)
+ foo();
+#pragma omp target
+#pragma omp teams reduction(^ : T) // expected-error {{'T' does not refer to a value}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(max : qa[1]) // expected-error 2 {{expected variable name}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : ba) // expected-error {{a reduction variable with array type 'const S2 [5]'}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(* : ca) // expected-error {{a reduction variable with array type 'const S3 [5]'}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+ foo();
+#pragma omp target
+#pragma omp teams private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp parallel private(k)
+#pragma omp target
+#pragma omp teams reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : p), reduction(+ : p) // expected-error 3 {{variable can appear only once in OpenMP 'reduction' clause}} expected-note 3 {{previously referenced here}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : r) // expected-error 2 {{const-qualified variable cannot be reduction}}
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp target
+#pragma omp teams reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel for private(fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp target
+#pragma omp teams reduction(+ : fl)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel for reduction(- : fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp target
+#pragma omp teams reduction(+ : fl)
+ foo();
+
+ return T();
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note 2 {{'d' defined here}}
+ const int da[5] = {0}; // expected-note {{'da' defined here}}
+ int qa[5] = {0};
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note 2 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const int &r = da[i]; // expected-note {{'r' defined here}}
+ int &q = qa[i]; // expected-note {{'q' defined here}}
+ float fl; // expected-note {{'fl' defined here}}
+#pragma omp target
+#pragma omp teams reduction // expected-error {{expected '(' after 'reduction'}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(~ : argc) // expected-error {{expected unqualified-id}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(&& : argc)
+ foo();
+#pragma omp target
+#pragma omp teams reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(max : argv[1]) // expected-error {{expected variable name}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : ba) // expected-error {{a reduction variable with array type 'const S2 [5]'}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(* : ca) // expected-error {{a reduction variable with array type 'const S3 [5]'}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+ foo();
+#pragma omp target
+#pragma omp teams private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp parallel private(k)
+#pragma omp target
+#pragma omp teams reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}}
+ foo();
+#pragma omp target
+#pragma omp teams reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}}
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp target
+#pragma omp teams reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel for private(fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp target
+#pragma omp teams reduction(+ : fl)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp parallel for reduction(- : fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp target
+#pragma omp teams reduction(+ : fl)
+ foo();
+
+ return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
+}
diff --git a/test/OpenMP/teams_shared_messages.cpp b/test/OpenMP/teams_shared_messages.cpp
new file mode 100644
index 000000000000..ce2f917e207c
--- /dev/null
+++ b/test/OpenMP/teams_shared_messages.cpp
@@ -0,0 +1,125 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+ S2(S2 &s2):a(s2.a) { }
+};
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+ S3(S3 &s3):a(s3.a) { }
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 {
+ int a;
+ S4();
+ S4(const S4 &s4);
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+ S5(const S5 &s5):a(s5.a) { }
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+
+int main(int argc, char **argv) {
+ const int d = 5;
+ const int da[5] = { 0 };
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i;
+ #pragma omp target
+ #pragma omp teams shared // expected-error {{expected '(' after 'shared'}}
+ foo();
+ #pragma omp target
+ #pragma omp teams shared ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp target
+ #pragma omp teams shared () // expected-error {{expected expression}}
+ foo();
+ #pragma omp target
+ #pragma omp teams shared (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp target
+ #pragma omp teams shared (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp target
+ #pragma omp teams shared (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ foo();
+ #pragma omp target
+ #pragma omp teams shared (argc)
+ foo();
+ #pragma omp target
+ #pragma omp teams shared (S1) // expected-error {{'S1' does not refer to a value}}
+ foo();
+ #pragma omp target
+ #pragma omp teams shared (a, b, c, d, f)
+ foo();
+ #pragma omp target
+ #pragma omp teams shared (argv[1]) // expected-error {{expected variable name}}
+ foo();
+ #pragma omp target
+ #pragma omp teams shared(ba)
+ foo();
+ #pragma omp target
+ #pragma omp teams shared(ca)
+ foo();
+ #pragma omp target
+ #pragma omp teams shared(da)
+ foo();
+ #pragma omp target
+ #pragma omp teams shared(e, g)
+ foo();
+ #pragma omp target
+ #pragma omp teams shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}}
+ foo();
+ #pragma omp target
+ #pragma omp teams firstprivate(i), shared(i) // expected-error {{firstprivate variable cannot be shared}} expected-note {{defined as firstprivate}}
+ foo();
+ #pragma omp target
+ #pragma omp teams private(i)
+ foo();
+ #pragma omp target
+ #pragma omp teams shared(i)
+ foo();
+ #pragma omp target
+ #pragma omp teams shared(j)
+ foo();
+ #pragma omp target
+ #pragma omp teams firstprivate(i)
+ foo();
+ #pragma omp target
+ #pragma omp teams shared(i)
+ foo();
+ #pragma omp target
+ #pragma omp teams shared(j)
+ foo();
+
+ return 0;
+}
diff --git a/test/OpenMP/threadprivate_codegen.cpp b/test/OpenMP/threadprivate_codegen.cpp
new file mode 100644
index 000000000000..98b7917714b8
--- /dev/null
+++ b/test/OpenMP/threadprivate_codegen.cpp
@@ -0,0 +1,707 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -DBODY -triple x86_64-unknown-unknown -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -DBODY -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK-DEBUG %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+// CHECK-DAG: [[IDENT:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[S1:%.+]] = type { [[INT:i[0-9]+]] }
+// CHECK-DAG: [[S2:%.+]] = type { [[INT]], double }
+// CHECK-DAG: [[S3:%.+]] = type { [[INT]], float }
+// CHECK-DAG: [[S4:%.+]] = type { [[INT]], [[INT]] }
+// CHECK-DAG: [[S5:%.+]] = type { [[INT]], [[INT]], [[INT]] }
+// CHECK-DAG: [[SMAIN:%.+]] = type { [[INT]], double, double }
+// CHECK-DEBUG-DAG: [[IDENT:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK-DEBUG-DAG: [[S1:%.+]] = type { [[INT:i[0-9]+]] }
+// CHECK-DEBUG-DAG: [[S2:%.+]] = type { [[INT]], double }
+// CHECK-DEBUG-DAG: [[S3:%.+]] = type { [[INT]], float }
+// CHECK-DEBUG-DAG: [[S4:%.+]] = type { [[INT]], [[INT]] }
+// CHECK-DEBUG-DAG: [[S5:%.+]] = type { [[INT]], [[INT]], [[INT]] }
+// CHECK-DEBUG-DAG: [[SMAIN:%.+]] = type { [[INT]], double, double }
+
+struct S1 {
+ int a;
+ S1()
+ : a(0) {
+ }
+ S1(int a)
+ : a(a) {
+ }
+ S1(const S1 &s) {
+ a = 12 + s.a;
+ }
+ ~S1() {
+ a = 0;
+ }
+};
+
+struct S2 {
+ int a;
+ double b;
+ S2()
+ : a(0) {
+ }
+ S2(int a)
+ : a(a) {
+ }
+ S2(const S2 &s) {
+ a = 12 + s.a;
+ }
+ ~S2() {
+ a = 0;
+ }
+};
+
+struct S3 {
+ int a;
+ float b;
+ S3()
+ : a(0) {
+ }
+ S3(int a)
+ : a(a) {
+ }
+ S3(const S3 &s) {
+ a = 12 + s.a;
+ }
+ ~S3() {
+ a = 0;
+ }
+};
+
+struct S4 {
+ int a, b;
+ S4()
+ : a(0) {
+ }
+ S4(int a)
+ : a(a) {
+ }
+ S4(const S4 &s) {
+ a = 12 + s.a;
+ }
+ ~S4() {
+ a = 0;
+ }
+};
+
+struct S5 {
+ int a, b, c;
+ S5()
+ : a(0) {
+ }
+ S5(int a)
+ : a(a) {
+ }
+ S5(const S5 &s) {
+ a = 12 + s.a;
+ }
+ ~S5() {
+ a = 0;
+ }
+};
+
+// CHECK-DAG: [[GS1:@.+]] = internal global [[S1]] zeroinitializer
+// CHECK-DAG: [[GS1]].cache. = common global i8** null
+// CHECK-DAG: [[DEFAULT_LOC:@.+]] = private unnamed_addr constant [[IDENT]] { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([{{[0-9]+}} x i8]* {{@.+}}, i32 0, i32 0) }
+// CHECK-DAG: [[GS2:@.+]] = internal global [[S2]] zeroinitializer
+// CHECK-DAG: [[ARR_X:@.+]] = global [2 x [3 x [[S1]]]] zeroinitializer
+// CHECK-DAG: [[ARR_X]].cache. = common global i8** null
+// CHECK-DAG: [[SM:@.+]] = internal global [[SMAIN]] zeroinitializer
+// CHECK-DAG: [[SM]].cache. = common global i8** null
+// CHECK-DAG: [[STATIC_S:@.+]] = external global [[S3]]
+// CHECK-DAG: [[STATIC_S]].cache. = common global i8** null
+// CHECK-DAG: [[GS3:@.+]] = external global [[S5]]
+// CHECK-DAG: [[GS3]].cache. = common global i8** null
+// CHECK-DAG: [[ST_INT_ST:@.+]] = linkonce_odr global i32 23
+// CHECK-DAG: [[ST_INT_ST]].cache. = common global i8** null
+// CHECK-DAG: [[ST_FLOAT_ST:@.+]] = linkonce_odr global float 2.300000e+01
+// CHECK-DAG: [[ST_FLOAT_ST]].cache. = common global i8** null
+// CHECK-DAG: [[ST_S4_ST:@.+]] = linkonce_odr global %struct.S4 zeroinitializer
+// CHECK-DAG: [[ST_S4_ST]].cache. = common global i8** null
+// CHECK-NOT: .cache. = common global i8** null
+// There is no cache for gs2 - it is not threadprivate. Check that there is only
+// 8 caches created (for Static::s, gs1, gs3, arr_x, main::sm, ST<int>::st,
+// ST<float>::st, ST<S4>::st)
+// CHECK-DEBUG-DAG: [[GS1:@.+]] = internal global [[S1]] zeroinitializer
+// CHECK-DEBUG-DAG: [[GS2:@.+]] = internal global [[S2]] zeroinitializer
+// CHECK-DEBUG-DAG: [[ARR_X:@.+]] = global [2 x [3 x [[S1]]]] zeroinitializer
+// CHECK-DEBUG-DAG: [[SM:@.+]] = internal global [[SMAIN]] zeroinitializer
+// CHECK-DEBUG-DAG: [[STATIC_S:@.+]] = external global [[S3]]
+// CHECK-DEBUG-DAG: [[GS3:@.+]] = external global [[S5]]
+// CHECK-DEBUG-DAG: [[ST_INT_ST:@.+]] = linkonce_odr global i32 23
+// CHECK-DEBUG-DAG: [[ST_FLOAT_ST:@.+]] = linkonce_odr global float 2.300000e+01
+// CHECK-DEBUG-DAG: [[ST_S4_ST:@.+]] = linkonce_odr global %struct.S4 zeroinitializer
+// CHECK-DEBUG-DAG: [[LOC1:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;162;9;;\00"
+// CHECK-DEBUG-DAG: [[LOC2:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;216;9;;\00"
+// CHECK-DEBUG-DAG: [[LOC3:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;303;19;;\00"
+// CHECK-DEBUG-DAG: [[LOC4:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;328;9;;\00"
+// CHECK-DEBUG-DAG: [[LOC5:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;341;9;;\00"
+// CHECK-DEBUG-DAG: [[LOC6:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;358;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC7:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;375;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC8:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;401;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC9:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;422;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC10:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;437;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC11:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;454;27;;\00"
+// CHECK-DEBUG-DAG: [[LOC12:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;471;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC13:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;550;9;;\00"
+// CHECK-DEBUG-DAG: [[LOC14:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;567;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC15:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;593;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC16:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;614;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC17:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;629;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC18:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;646;27;;\00"
+// CHECK-DEBUG-DAG: [[LOC19:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;663;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC20:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;275;9;;\00"
+
+struct Static {
+ static S3 s;
+#pragma omp threadprivate(s)
+};
+
+static S1 gs1(5);
+#pragma omp threadprivate(gs1)
+// CHECK: define {{.*}} [[S1_CTOR:@.*]]([[S1]]* {{.*}},
+// CHECK: define {{.*}} [[S1_DTOR:@.*]]([[S1]]* {{.*}})
+// CHECK: define internal {{.*}}i8* [[GS1_CTOR:@\.__kmpc_global_ctor_\..*]](i8*)
+// CHECK: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK: [[RES:%.*]] = bitcast i8* [[ARG]] to [[S1]]*
+// CHECK-NEXT: call {{.*}} [[S1_CTOR]]([[S1]]* [[RES]], {{.*}} 5)
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK: ret i8* [[ARG]]
+// CHECK-NEXT: }
+// CHECK: define internal {{.*}}void [[GS1_DTOR:@\.__kmpc_global_dtor_\..*]](i8*)
+// CHECK: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK: [[RES:%.*]] = bitcast i8* [[ARG]] to [[S1]]*
+// CHECK-NEXT: call {{.*}} [[S1_DTOR]]([[S1]]* [[RES]])
+// CHECK-NEXT: ret void
+// CHECK-NEXT: }
+// CHECK: define internal {{.*}}void [[GS1_INIT:@\.__omp_threadprivate_init_\..*]]()
+// CHECK: call {{.*}}void @__kmpc_threadprivate_register([[IDENT]]* [[DEFAULT_LOC]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i8* (i8*)* [[GS1_CTOR]], i8* (i8*, i8*)* null, void (i8*)* [[GS1_DTOR]])
+// CHECK-NEXT: ret void
+// CHECK-NEXT: }
+// CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]]
+// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+// CHECK-DEBUG: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC1]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+// CHECK-DEBUG: @__kmpc_global_thread_num
+// CHECK-DEBUG: call {{.*}}void @__kmpc_threadprivate_register([[IDENT]]* [[KMPC_LOC_ADDR]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i8* (i8*)* [[GS1_CTOR:@\.__kmpc_global_ctor_\..*]], i8* (i8*, i8*)* null, void (i8*)* [[GS1_DTOR:@\.__kmpc_global_dtor_\..*]])
+// CHECK-DEBUG: define internal {{.*}}i8* [[GS1_CTOR]](i8*)
+// CHECK-DEBUG: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK-DEBUG: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK-DEBUG: [[RES:%.*]] = bitcast i8* [[ARG]] to [[S1]]*
+// CHECK-DEBUG-NEXT: call {{.*}} [[S1_CTOR:@.+]]([[S1]]* [[RES]], {{.*}} 5)
+// CHECK-DEBUG: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK-DEBUG: ret i8* [[ARG]]
+// CHECK-DEBUG-NEXT: }
+// CHECK-DEBUG: define {{.*}} [[S1_CTOR]]([[S1]]* {{.*}},
+// CHECK-DEBUG: define internal {{.*}}void [[GS1_DTOR]](i8*)
+// CHECK-DEBUG: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK-DEBUG: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK-DEBUG: [[RES:%.*]] = bitcast i8* [[ARG]] to [[S1]]*
+// CHECK-DEBUG-NEXT: call {{.*}} [[S1_DTOR:@.+]]([[S1]]* [[RES]])
+// CHECK-DEBUG-NEXT: ret void
+// CHECK-DEBUG-NEXT: }
+// CHECK-DEBUG: define {{.*}} [[S1_DTOR]]([[S1]]* {{.*}})
+static S2 gs2(27);
+// CHECK: define {{.*}} [[S2_CTOR:@.*]]([[S2]]* {{.*}},
+// CHECK: define {{.*}} [[S2_DTOR:@.*]]([[S2]]* {{.*}})
+// No another call for S2 constructor because it is not threadprivate
+// CHECK-NOT: call {{.*}} [[S2_CTOR]]([[S2]]*
+// CHECK-DEBUG: define {{.*}} [[S2_CTOR:@.*]]([[S2]]* {{.*}},
+// CHECK-DEBUG: define {{.*}} [[S2_DTOR:@.*]]([[S2]]* {{.*}})
+// No another call for S2 constructor because it is not threadprivate
+// CHECK-DEBUG-NOT: call {{.*}} [[S2_CTOR]]([[S2]]*
+S1 arr_x[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
+#pragma omp threadprivate(arr_x)
+// CHECK: define internal {{.*}}i8* [[ARR_X_CTOR:@\.__kmpc_global_ctor_\..*]](i8*)
+// CHECK: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK: [[RES:%.*]] = bitcast i8* [[ARG]] to [2 x [3 x [[S1]]]]*
+// CHECK: [[ARR1:%.*]] = getelementptr inbounds [2 x [3 x [[S1]]]]* [[RES]], i{{.*}} 0, i{{.*}} 0
+// CHECK: [[ARR:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR1]], i{{.*}} 0, i{{.*}} 0
+// CHECK: invoke {{.*}} [[S1_CTOR]]([[S1]]* [[ARR]], [[INT]] {{.*}}1)
+// CHECK: [[ARR_ELEMENT:%.*]] = getelementptr inbounds [[S1]]* [[ARR]], i{{.*}} 1
+// CHECK: invoke {{.*}} [[S1_CTOR]]([[S1]]* [[ARR_ELEMENT]], [[INT]] {{.*}}2)
+// CHECK: [[ARR_ELEMENT2:%.*]] = getelementptr inbounds [[S1]]* [[ARR_ELEMENT]], i{{.*}} 1
+// CHECK: invoke {{.*}} [[S1_CTOR]]([[S1]]* [[ARR_ELEMENT2]], [[INT]] {{.*}}3)
+// CHECK: [[ARR_ELEMENT3:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR1]], i{{.*}} 1
+// CHECK: [[ARR_:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR_ELEMENT3]], i{{.*}} 0, i{{.*}} 0
+// CHECK: invoke {{.*}} [[S1_CTOR]]([[S1]]* [[ARR_]], [[INT]] {{.*}}4)
+// CHECK: [[ARR_ELEMENT:%.*]] = getelementptr inbounds [[S1]]* [[ARR_]], i{{.*}} 1
+// CHECK: invoke {{.*}} [[S1_CTOR]]([[S1]]* [[ARR_ELEMENT]], [[INT]] {{.*}}5)
+// CHECK: [[ARR_ELEMENT2:%.*]] = getelementptr inbounds [[S1]]* [[ARR_ELEMENT]], i{{.*}} 1
+// CHECK: invoke {{.*}} [[S1_CTOR]]([[S1]]* [[ARR_ELEMENT2]], [[INT]] {{.*}}6)
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK: ret i8* [[ARG]]
+// CHECK: }
+// CHECK: define internal {{.*}}void [[ARR_X_DTOR:@\.__kmpc_global_dtor_\..*]](i8*)
+// CHECK: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK: [[ARR_BEGIN:%.*]] = bitcast i8* [[ARG]] to [[S1]]*
+// CHECK-NEXT: [[ARR_CUR:%.*]] = getelementptr inbounds [[S1]]* [[ARR_BEGIN]], i{{.*}} 6
+// CHECK-NEXT: br label %[[ARR_LOOP:.*]]
+// CHECK: {{.*}}[[ARR_LOOP]]{{.*}}
+// CHECK-NEXT: [[ARR_ELEMENTPAST:%.*]] = phi [[S1]]* [ [[ARR_CUR]], {{.*}} ], [ [[ARR_ELEMENT:%.*]], {{.*}} ]
+// CHECK-NEXT: [[ARR_ELEMENT:%.*]] = getelementptr inbounds [[S1]]* [[ARR_ELEMENTPAST]], i{{.*}} -1
+// CHECK-NEXT: invoke {{.*}} [[S1_DTOR]]([[S1]]* [[ARR_ELEMENT]])
+// CHECK: [[ARR_DONE:%.*]] = icmp eq [[S1]]* [[ARR_ELEMENT]], [[ARR_BEGIN]]
+// CHECK-NEXT: br i1 [[ARR_DONE]], label %[[ARR_EXIT:.*]], label %[[ARR_LOOP]]
+// CHECK: {{.*}}[[ARR_EXIT]]{{.*}}
+// CHECK-NEXT: ret void
+// CHECK: }
+// CHECK: define internal {{.*}}void [[ARR_X_INIT:@\.__omp_threadprivate_init_\..*]]()
+// CHECK: call {{.*}}void @__kmpc_threadprivate_register([[IDENT]]* [[DEFAULT_LOC]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i8* (i8*)* [[ARR_X_CTOR]], i8* (i8*, i8*)* null, void (i8*)* [[ARR_X_DTOR]])
+// CHECK-NEXT: ret void
+// CHECK-NEXT: }
+// CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]]
+// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+// CHECK-DEBUG: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC2]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+// CHECK-DEBUG: @__kmpc_global_thread_num
+// CHECK-DEBUG: call {{.*}}void @__kmpc_threadprivate_register([[IDENT]]* [[KMPC_LOC_ADDR]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i8* (i8*)* [[ARR_X_CTOR:@\.__kmpc_global_ctor_\..*]], i8* (i8*, i8*)* null, void (i8*)* [[ARR_X_DTOR:@\.__kmpc_global_dtor_\..*]])
+// CHECK-DEBUG: define internal {{.*}}i8* [[ARR_X_CTOR]](i8*)
+// CHECK-DEBUG: }
+// CHECK-DEBUG: define internal {{.*}}void [[ARR_X_DTOR]](i8*)
+// CHECK-DEBUG: }
+extern S5 gs3;
+#pragma omp threadprivate(gs3)
+// No call for S5 constructor because gs3 has just declaration, not a definition.
+// CHECK-NOT: call {{.*}}([[S5]]*
+// CHECK-DEBUG-NOT: call {{.*}}([[S5]]*
+
+template <class T>
+struct ST {
+ static T st;
+#pragma omp threadprivate(st)
+};
+
+template <class T>
+T ST<T>::st(23);
+
+// CHECK-LABEL: @main()
+// CHECK-DEBUG-LABEL: @main()
+int main() {
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]]
+ int Res;
+ struct Smain {
+ int a;
+ double b, c;
+ Smain()
+ : a(0) {
+ }
+ Smain(int a)
+ : a(a) {
+ }
+ Smain(const Smain &s) {
+ a = 12 + s.a;
+ }
+ ~Smain() {
+ a = 0;
+ }
+ };
+
+ static Smain sm(gs1.a);
+// CHECK: [[THREAD_NUM:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT]]* [[DEFAULT_LOC]])
+// CHECK: call {{.*}}i{{.*}} @__cxa_guard_acquire
+// CHECK: call {{.*}}i32 @__kmpc_global_thread_num([[IDENT]]* [[DEFAULT_LOC]])
+// CHECK: call {{.*}}void @__kmpc_threadprivate_register([[IDENT]]* [[DEFAULT_LOC]], i8* bitcast ([[SMAIN]]* [[SM]] to i8*), i8* (i8*)* [[SM_CTOR:@\.__kmpc_global_ctor_\..+]], i8* (i8*, i8*)* null, void (i8*)* [[SM_DTOR:@\.__kmpc_global_dtor_\..+]])
+// CHECK: [[GS1_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[GS1]].cache.)
+// CHECK-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]*
+// CHECK-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0
+// CHECK-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]]
+// CHECK-NEXT: invoke {{.*}} [[SMAIN_CTOR:.*]]([[SMAIN]]* [[SM]], [[INT]] {{.*}}[[GS1_A]])
+// CHECK: call {{.*}}void @__cxa_guard_release
+// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC3]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+// CHECK-DEBUG-NEXT: [[THREAD_NUM:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT]]* [[KMPC_LOC_ADDR]])
+// CHECK-DEBUG: call {{.*}}i{{.*}} @__cxa_guard_acquire
+// CHECK-DEBUG: call {{.*}}i32 @__kmpc_global_thread_num([[IDENT]]* [[KMPC_LOC_ADDR]])
+// CHECK-DEBUG: call {{.*}}void @__kmpc_threadprivate_register([[IDENT]]* [[KMPC_LOC_ADDR]], i8* bitcast ([[SMAIN]]* [[SM]] to i8*), i8* (i8*)* [[SM_CTOR:@\.__kmpc_global_ctor_\..+]], i8* (i8*, i8*)* null, void (i8*)* [[SM_DTOR:@\.__kmpc_global_dtor_\..+]])
+// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC3]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+// CHECK-DEBUG: [[GS1_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+// CHECK-DEBUG-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]*
+// CHECK-DEBUG-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0
+// CHECK-DEBUG-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]]
+// CHECK-DEBUG-NEXT: invoke {{.*}} [[SMAIN_CTOR:.*]]([[SMAIN]]* [[SM]], [[INT]] {{.*}}[[GS1_A]])
+// CHECK-DEBUG: call {{.*}}void @__cxa_guard_release
+#pragma omp threadprivate(sm)
+ // CHECK: [[STATIC_S_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S3]]* [[STATIC_S]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[STATIC_S]].cache.)
+ // CHECK-NEXT: [[STATIC_S_ADDR:%.*]] = bitcast i8* [[STATIC_S_TEMP_ADDR]] to [[S3]]*
+ // CHECK-NEXT: [[STATIC_S_A_ADDR:%.*]] = getelementptr inbounds [[S3]]* [[STATIC_S_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[STATIC_S_A:%.*]] = load [[INT]]* [[STATIC_S_A_ADDR]]
+ // CHECK-NEXT: store [[INT]] [[STATIC_S_A]], [[INT]]* [[RES_ADDR:[^,]+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC5]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[STATIC_S_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S3]]* [[STATIC_S]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[STATIC_S_ADDR:%.*]] = bitcast i8* [[STATIC_S_TEMP_ADDR]] to [[S3]]*
+ // CHECK-DEBUG-NEXT: [[STATIC_S_A_ADDR:%.*]] = getelementptr inbounds [[S3]]* [[STATIC_S_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[STATIC_S_A:%.*]] = load [[INT]]* [[STATIC_S_A_ADDR]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[STATIC_S_A]], [[INT]]* [[RES_ADDR:[^,]+]]
+ Res = Static::s.a;
+ // CHECK: [[SM_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[SMAIN]]* [[SM]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[SM]].cache.)
+ // CHECK-NEXT: [[SM_ADDR:%.*]] = bitcast i8* [[SM_TEMP_ADDR]] to [[SMAIN]]*
+ // CHECK-NEXT: [[SM_A_ADDR:%.*]] = getelementptr inbounds [[SMAIN]]* [[SM_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[SM_A:%.*]] = load [[INT]]* [[SM_A_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[SM_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC6]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[SM_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[SMAIN]]* [[SM]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[SM_ADDR:%.*]] = bitcast i8* [[SM_TEMP_ADDR]] to [[SMAIN]]*
+ // CHECK-DEBUG-NEXT: [[SM_A_ADDR:%.*]] = getelementptr inbounds [[SMAIN]]* [[SM_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[SM_A:%.*]] = load [[INT]]* [[SM_A_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[SM_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += sm.a;
+ // CHECK: [[GS1_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[GS1]].cache.)
+ // CHECK-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]*
+ // CHECK-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS1_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC7]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[GS1_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]*
+ // CHECK-DEBUG-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS1_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += gs1.a;
+ // CHECK: [[GS2_A:%.*]] = load [[INT]]* getelementptr inbounds ([[S2]]* [[GS2]], i{{.*}} 0, i{{.*}} 0)
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS2_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[GS2_A:%.*]] = load [[INT]]* getelementptr inbounds ([[S2]]* [[GS2]], i{{.*}} 0, i{{.*}} 0)
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS2_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += gs2.a;
+ // CHECK: [[GS3_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S5]]* [[GS3]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[GS3]].cache.)
+ // CHECK-NEXT: [[GS3_ADDR:%.*]] = bitcast i8* [[GS3_TEMP_ADDR]] to [[S5]]*
+ // CHECK-NEXT: [[GS3_A_ADDR:%.*]] = getelementptr inbounds [[S5]]* [[GS3_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[GS3_A:%.*]] = load [[INT]]* [[GS3_A_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS3_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC8]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[GS3_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S5]]* [[GS3]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[GS3_ADDR:%.*]] = bitcast i8* [[GS3_TEMP_ADDR]] to [[S5]]*
+ // CHECK-DEBUG-NEXT: [[GS3_A_ADDR:%.*]] = getelementptr inbounds [[S5]]* [[GS3_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[GS3_A:%.*]] = load [[INT]]* [[GS3_A_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS3_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += gs3.a;
+ // CHECK: [[ARR_X_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ARR_X]].cache.)
+ // CHECK-NEXT: [[ARR_X_ADDR:%.*]] = bitcast i8* [[ARR_X_TEMP_ADDR]] to [2 x [3 x [[S1]]]]*
+ // CHECK-NEXT: [[ARR_X_1_ADDR:%.*]] = getelementptr inbounds [2 x [3 x [[S1]]]]* [[ARR_X_ADDR]], i{{.*}} 0, i{{.*}} 1
+ // CHECK-NEXT: [[ARR_X_1_1_ADDR:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR_X_1_ADDR]], i{{.*}} 0, i{{.*}} 1
+ // CHECK-NEXT: [[ARR_X_1_1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[ARR_X_1_1_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[ARR_X_1_1_A:%.*]] = load [[INT]]* [[ARR_X_1_1_A_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ARR_X_1_1_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC9]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[ARR_X_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[ARR_X_ADDR:%.*]] = bitcast i8* [[ARR_X_TEMP_ADDR]] to [2 x [3 x [[S1]]]]*
+ // CHECK-DEBUG-NEXT: [[ARR_X_1_ADDR:%.*]] = getelementptr inbounds [2 x [3 x [[S1]]]]* [[ARR_X_ADDR]], i{{.*}} 0, i{{.*}} 1
+ // CHECK-DEBUG-NEXT: [[ARR_X_1_1_ADDR:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR_X_1_ADDR]], i{{.*}} 0, i{{.*}} 1
+ // CHECK-DEBUG-NEXT: [[ARR_X_1_1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[ARR_X_1_1_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[ARR_X_1_1_A:%.*]] = load [[INT]]* [[ARR_X_1_1_A_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ARR_X_1_1_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += arr_x[1][1].a;
+ // CHECK: [[ST_INT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[INT]]* [[ST_INT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_INT_ST]].cache.)
+ // CHECK-NEXT: [[ST_INT_ST_ADDR:%.*]] = bitcast i8* [[ST_INT_ST_TEMP_ADDR]] to [[INT]]*
+ // CHECK-NEXT: [[ST_INT_ST_VAL:%.*]] = load [[INT]]* [[ST_INT_ST_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_INT_ST_VAL]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC10]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[ST_INT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[INT]]* [[ST_INT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[ST_INT_ST_ADDR:%.*]] = bitcast i8* [[ST_INT_ST_TEMP_ADDR]] to [[INT]]*
+ // CHECK-DEBUG-NEXT: [[ST_INT_ST_VAL:%.*]] = load [[INT]]* [[ST_INT_ST_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_INT_ST_VAL]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += ST<int>::st;
+ // CHECK: [[ST_FLOAT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast (float* [[ST_FLOAT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_FLOAT_ST]].cache.)
+ // CHECK-NEXT: [[ST_FLOAT_ST_ADDR:%.*]] = bitcast i8* [[ST_FLOAT_ST_TEMP_ADDR]] to float*
+ // CHECK-NEXT: [[ST_FLOAT_ST_VAL:%.*]] = load float* [[ST_FLOAT_ST_ADDR]]
+ // CHECK-NEXT: [[FLOAT_TO_INT_CONV:%.*]] = fptosi float [[ST_FLOAT_ST_VAL]] to [[INT]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[FLOAT_TO_INT_CONV]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC11]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[ST_FLOAT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast (float* [[ST_FLOAT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[ST_FLOAT_ST_ADDR:%.*]] = bitcast i8* [[ST_FLOAT_ST_TEMP_ADDR]] to float*
+ // CHECK-DEBUG-NEXT: [[ST_FLOAT_ST_VAL:%.*]] = load float* [[ST_FLOAT_ST_ADDR]]
+ // CHECK-DEBUG-NEXT: [[FLOAT_TO_INT_CONV:%.*]] = fptosi float [[ST_FLOAT_ST_VAL]] to [[INT]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[FLOAT_TO_INT_CONV]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += static_cast<int>(ST<float>::st);
+ // CHECK: [[ST_S4_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_S4_ST]].cache.)
+ // CHECK-NEXT: [[ST_S4_ST_ADDR:%.*]] = bitcast i8* [[ST_S4_ST_TEMP_ADDR]] to [[S4]]*
+ // CHECK-NEXT: [[ST_S4_ST_A_ADDR:%.*]] = getelementptr inbounds [[S4]]* [[ST_S4_ST_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[ST_S4_ST_A:%.*]] = load [[INT]]* [[ST_S4_ST_A_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_S4_ST_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC12]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[ST_S4_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[ST_S4_ST_ADDR:%.*]] = bitcast i8* [[ST_S4_ST_TEMP_ADDR]] to [[S4]]*
+ // CHECK-DEBUG-NEXT: [[ST_S4_ST_A_ADDR:%.*]] = getelementptr inbounds [[S4]]* [[ST_S4_ST_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[ST_S4_ST_A:%.*]] = load [[INT]]* [[ST_S4_ST_A_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_S4_ST_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += ST<S4>::st.a;
+ // CHECK: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: ret [[INT]] [[RES]]
+ // CHECK-DEBUG: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: ret [[INT]] [[RES]]
+ return Res;
+}
+// CHECK: }
+
+// CHECK: define internal {{.*}}i8* [[SM_CTOR]](i8*)
+// CHECK: [[THREAD_NUM:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT]]* [[DEFAULT_LOC]])
+// CHECK: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK: [[RES:%.*]] = bitcast i8* [[ARG]] to [[SMAIN]]*
+// CHECK: [[GS1_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[GS1]].cache.)
+// CHECK-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]*
+// CHECK-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0
+// CHECK-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]]
+// CHECK-NEXT: call {{.*}} [[SMAIN_CTOR:@.+]]([[SMAIN]]* [[RES]], [[INT]] {{.*}}[[GS1_A]])
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK-NEXT: ret i8* [[ARG]]
+// CHECK-NEXT: }
+// CHECK: define {{.*}} [[SMAIN_CTOR]]([[SMAIN]]* {{.*}},
+// CHECK: define internal {{.*}}void [[SM_DTOR]](i8*)
+// CHECK: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK: [[RES:%.*]] = bitcast i8* [[ARG]] to [[SMAIN]]*
+// CHECK-NEXT: call {{.*}} [[SMAIN_DTOR:@.+]]([[SMAIN]]* [[RES]])
+// CHECK-NEXT: ret void
+// CHECK-NEXT: }
+// CHECK: define {{.*}} [[SMAIN_DTOR]]([[SMAIN]]* {{.*}})
+// CHECK-DEBUG: define internal {{.*}}i8* [[SM_CTOR]](i8*)
+// CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]]
+// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC3]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+// CHECK-DEBUG-NEXT: [[THREAD_NUM:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT]]* [[KMPC_LOC_ADDR]])
+// CHECK-DEBUG: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK-DEBUG: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK-DEBUG: [[RES:%.*]] = bitcast i8* [[ARG]] to [[SMAIN]]*
+// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC3]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+// CHECK-DEBUG: [[GS1_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+// CHECK-DEBUG-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]*
+// CHECK-DEBUG-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0
+// CHECK-DEBUG-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]]
+// CHECK-DEBUG-NEXT: call {{.*}} [[SMAIN_CTOR:@.+]]([[SMAIN]]* [[RES]], [[INT]] {{.*}}[[GS1_A]])
+// CHECK-DEBUG: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK-DEBUG-NEXT: ret i8* [[ARG]]
+// CHECK-DEBUG-NEXT: }
+// CHECK-DEBUG: define {{.*}} [[SMAIN_CTOR]]([[SMAIN]]* {{.*}},
+// CHECK-DEBUG: define internal {{.*}} [[SM_DTOR:@.+]](i8*)
+// CHECK-DEBUG: call {{.*}} [[SMAIN_DTOR:@.+]]([[SMAIN]]*
+// CHECK-DEBUG: }
+// CHECK-DEBUG: define {{.*}} [[SMAIN_DTOR]]([[SMAIN]]* {{.*}})
+
+#endif
+
+#ifdef BODY
+// CHECK-LABEL: @{{.*}}foobar{{.*}}()
+// CHECK-DEBUG-LABEL: @{{.*}}foobar{{.*}}()
+int foobar() {
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]]
+ int Res;
+ // CHECK: [[THREAD_NUM:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT]]* [[DEFAULT_LOC]])
+ // CHECK: [[STATIC_S_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S3]]* [[STATIC_S]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[STATIC_S]].cache.)
+ // CHECK-NEXT: [[STATIC_S_ADDR:%.*]] = bitcast i8* [[STATIC_S_TEMP_ADDR]] to [[S3]]*
+ // CHECK-NEXT: [[STATIC_S_A_ADDR:%.*]] = getelementptr inbounds [[S3]]* [[STATIC_S_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[STATIC_S_A:%.*]] = load [[INT]]* [[STATIC_S_A_ADDR]]
+ // CHECK-NEXT: store [[INT]] [[STATIC_S_A]], [[INT]]* [[RES_ADDR:[^,]+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC13]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[THREAD_NUM:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT]]* [[KMPC_LOC_ADDR]])
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC13]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[STATIC_S_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S3]]* [[STATIC_S]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[STATIC_S_ADDR:%.*]] = bitcast i8* [[STATIC_S_TEMP_ADDR]] to [[S3]]*
+ // CHECK-DEBUG-NEXT: [[STATIC_S_A_ADDR:%.*]] = getelementptr inbounds [[S3]]* [[STATIC_S_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[STATIC_S_A:%.*]] = load [[INT]]* [[STATIC_S_A_ADDR]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[STATIC_S_A]], [[INT]]* [[RES_ADDR:[^,]+]]
+ Res = Static::s.a;
+ // CHECK: [[GS1_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[GS1]].cache.)
+ // CHECK-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]*
+ // CHECK-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS1_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC14]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[GS1_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]*
+ // CHECK-DEBUG-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS1_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += gs1.a;
+ // CHECK: [[GS2_A:%.*]] = load [[INT]]* getelementptr inbounds ([[S2]]* [[GS2]], i{{.*}} 0, i{{.*}} 0)
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS2_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[GS2_A:%.*]] = load [[INT]]* getelementptr inbounds ([[S2]]* [[GS2]], i{{.*}} 0, i{{.*}} 0)
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS2_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += gs2.a;
+ // CHECK: [[GS3_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S5]]* [[GS3]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[GS3]].cache.)
+ // CHECK-NEXT: [[GS3_ADDR:%.*]] = bitcast i8* [[GS3_TEMP_ADDR]] to [[S5]]*
+ // CHECK-NEXT: [[GS3_A_ADDR:%.*]] = getelementptr inbounds [[S5]]* [[GS3_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[GS3_A:%.*]] = load [[INT]]* [[GS3_A_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS3_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC15]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[GS3_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S5]]* [[GS3]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[GS3_ADDR:%.*]] = bitcast i8* [[GS3_TEMP_ADDR]] to [[S5]]*
+ // CHECK-DEBUG-NEXT: [[GS3_A_ADDR:%.*]] = getelementptr inbounds [[S5]]* [[GS3_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[GS3_A:%.*]] = load [[INT]]* [[GS3_A_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS3_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += gs3.a;
+ // CHECK: [[ARR_X_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ARR_X]].cache.)
+ // CHECK-NEXT: [[ARR_X_ADDR:%.*]] = bitcast i8* [[ARR_X_TEMP_ADDR]] to [2 x [3 x [[S1]]]]*
+ // CHECK-NEXT: [[ARR_X_1_ADDR:%.*]] = getelementptr inbounds [2 x [3 x [[S1]]]]* [[ARR_X_ADDR]], i{{.*}} 0, i{{.*}} 1
+ // CHECK-NEXT: [[ARR_X_1_1_ADDR:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR_X_1_ADDR]], i{{.*}} 0, i{{.*}} 1
+ // CHECK-NEXT: [[ARR_X_1_1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[ARR_X_1_1_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[ARR_X_1_1_A:%.*]] = load [[INT]]* [[ARR_X_1_1_A_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ARR_X_1_1_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC16]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[ARR_X_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[ARR_X_ADDR:%.*]] = bitcast i8* [[ARR_X_TEMP_ADDR]] to [2 x [3 x [[S1]]]]*
+ // CHECK-DEBUG-NEXT: [[ARR_X_1_ADDR:%.*]] = getelementptr inbounds [2 x [3 x [[S1]]]]* [[ARR_X_ADDR]], i{{.*}} 0, i{{.*}} 1
+ // CHECK-DEBUG-NEXT: [[ARR_X_1_1_ADDR:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR_X_1_ADDR]], i{{.*}} 0, i{{.*}} 1
+ // CHECK-DEBUG-NEXT: [[ARR_X_1_1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[ARR_X_1_1_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[ARR_X_1_1_A:%.*]] = load [[INT]]* [[ARR_X_1_1_A_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ARR_X_1_1_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += arr_x[1][1].a;
+ // CHECK: [[ST_INT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[INT]]* [[ST_INT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_INT_ST]].cache.)
+ // CHECK-NEXT: [[ST_INT_ST_ADDR:%.*]] = bitcast i8* [[ST_INT_ST_TEMP_ADDR]] to [[INT]]*
+ // CHECK-NEXT: [[ST_INT_ST_VAL:%.*]] = load [[INT]]* [[ST_INT_ST_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_INT_ST_VAL]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC17]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[ST_INT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[INT]]* [[ST_INT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[ST_INT_ST_ADDR:%.*]] = bitcast i8* [[ST_INT_ST_TEMP_ADDR]] to [[INT]]*
+ // CHECK-DEBUG-NEXT: [[ST_INT_ST_VAL:%.*]] = load [[INT]]* [[ST_INT_ST_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_INT_ST_VAL]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += ST<int>::st;
+ // CHECK: [[ST_FLOAT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast (float* [[ST_FLOAT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_FLOAT_ST]].cache.)
+ // CHECK-NEXT: [[ST_FLOAT_ST_ADDR:%.*]] = bitcast i8* [[ST_FLOAT_ST_TEMP_ADDR]] to float*
+ // CHECK-NEXT: [[ST_FLOAT_ST_VAL:%.*]] = load float* [[ST_FLOAT_ST_ADDR]]
+ // CHECK-NEXT: [[FLOAT_TO_INT_CONV:%.*]] = fptosi float [[ST_FLOAT_ST_VAL]] to [[INT]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[FLOAT_TO_INT_CONV]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC18]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[ST_FLOAT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast (float* [[ST_FLOAT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[ST_FLOAT_ST_ADDR:%.*]] = bitcast i8* [[ST_FLOAT_ST_TEMP_ADDR]] to float*
+ // CHECK-DEBUG-NEXT: [[ST_FLOAT_ST_VAL:%.*]] = load float* [[ST_FLOAT_ST_ADDR]]
+ // CHECK-DEBUG-NEXT: [[FLOAT_TO_INT_CONV:%.*]] = fptosi float [[ST_FLOAT_ST_VAL]] to [[INT]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[FLOAT_TO_INT_CONV]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += static_cast<int>(ST<float>::st);
+ // CHECK: [[ST_S4_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_S4_ST]].cache.)
+ // CHECK-NEXT: [[ST_S4_ST_ADDR:%.*]] = bitcast i8* [[ST_S4_ST_TEMP_ADDR]] to [[S4]]*
+ // CHECK-NEXT: [[ST_S4_ST_A_ADDR:%.*]] = getelementptr inbounds [[S4]]* [[ST_S4_ST_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-NEXT: [[ST_S4_ST_A:%.*]] = load [[INT]]* [[ST_S4_ST_A_ADDR]]
+ // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_S4_ST_A]]
+ // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+ // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC19]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+ // CHECK-DEBUG-NEXT: [[ST_S4_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8***
+ // CHECK-DEBUG-NEXT: [[ST_S4_ST_ADDR:%.*]] = bitcast i8* [[ST_S4_ST_TEMP_ADDR]] to [[S4]]*
+ // CHECK-DEBUG-NEXT: [[ST_S4_ST_A_ADDR:%.*]] = getelementptr inbounds [[S4]]* [[ST_S4_ST_ADDR]], i{{.*}} 0, i{{.*}} 0
+ // CHECK-DEBUG-NEXT: [[ST_S4_ST_A:%.*]] = load [[INT]]* [[ST_S4_ST_A_ADDR]]
+ // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_S4_ST_A]]
+ // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]]
+ Res += ST<S4>::st.a;
+ // CHECK: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-NEXT: ret [[INT]] [[RES]]
+ // CHECK-DEBUG: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]]
+ // CHECK-DEBUG-NEXT: ret [[INT]] [[RES]]
+ return Res;
+}
+#endif
+
+// CHECK: call {{.*}}void @__kmpc_threadprivate_register([[IDENT]]* [[DEFAULT_LOC]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i8* (i8*)* [[ST_S4_ST_CTOR:@\.__kmpc_global_ctor_\..+]], i8* (i8*, i8*)* null, void (i8*)* [[ST_S4_ST_DTOR:@\.__kmpc_global_dtor_\..+]])
+// CHECK: define internal {{.*}}i8* [[ST_S4_ST_CTOR]](i8*)
+// CHECK: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK: [[RES:%.*]] = bitcast i8* [[ARG]] to [[S4]]*
+// CHECK-NEXT: call {{.*}} [[S4_CTOR:@.+]]([[S4]]* [[RES]], {{.*}} 23)
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK-NEXT: ret i8* [[ARG]]
+// CHECK-NEXT: }
+// CHECK: define {{.*}} [[S4_CTOR]]([[S4]]* {{.*}},
+// CHECK: define internal {{.*}}void [[ST_S4_ST_DTOR]](i8*)
+// CHECK: store i8* %0, i8** [[ARG_ADDR:%.*]],
+// CHECK: [[ARG:%.+]] = load i8** [[ARG_ADDR]]
+// CHECK: [[RES:%.*]] = bitcast i8* [[ARG]] to [[S4]]*
+// CHECK-NEXT: call {{.*}} [[S4_DTOR:@.+]]([[S4]]* [[RES]])
+// CHECK-NEXT: ret void
+// CHECK-NEXT: }
+// CHECK: define {{.*}} [[S4_DTOR]]([[S4]]* {{.*}})
+// CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]]
+// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4
+// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC20]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]]
+// CHECK-DEBUG: @__kmpc_global_thread_num
+// CHECK-DEBUG: call {{.*}}void @__kmpc_threadprivate_register([[IDENT]]* [[KMPC_LOC_ADDR]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i8* (i8*)* [[ST_S4_ST_CTOR:@\.__kmpc_global_ctor_\..+]], i8* (i8*, i8*)* null, void (i8*)* [[ST_S4_ST_DTOR:@\.__kmpc_global_dtor_\..+]])
+// CHECK-DEBUG: define internal {{.*}}i8* [[ST_S4_ST_CTOR]](i8*)
+// CHECK-DEBUG: }
+// CHECK-DEBUG: define {{.*}} [[S4_CTOR:@.*]]([[S4]]* {{.*}},
+// CHECK-DEBUG: define internal {{.*}}void [[ST_S4_ST_DTOR]](i8*)
+// CHECK-DEBUG: }
+// CHECK-DEBUG: define {{.*}} [[S4_DTOR:@.*]]([[S4]]* {{.*}})
+
+// CHECK: define internal {{.*}}void {{@.*}}()
+// CHECK-DAG: call {{.*}}void [[GS1_INIT]]()
+// CHECK-DAG: call {{.*}}void [[ARR_X_INIT]]()
+// CHECK: ret void
+// CHECK-DEBUG: define internal {{.*}}void {{@.*}}()
+// CHECK-DEBUG: ret void
diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp
index 491f30ad041f..27b36fbe024c 100644
--- a/test/OpenMP/threadprivate_messages.cpp
+++ b/test/OpenMP/threadprivate_messages.cpp
@@ -96,6 +96,9 @@ class TempClass {
static __thread int t; // expected-note {{'t' defined here}}
#pragma omp threadprivate (t) // expected-error {{variable 't' cannot be threadprivate because it is thread-local}}
+register int reg0 __asm__("0"); // expected-note {{'reg0' defined here}}
+#pragma omp threadprivate (reg0) // expected-error {{variable 'reg0' cannot be threadprivate because it is a global named register variable}}
+
int o; // expected-note {{candidate found by name lookup is 'o'}}
#pragma omp threadprivate (o)
namespace {
diff --git a/test/PCH/chain-openmp-threadprivate.cpp b/test/PCH/chain-openmp-threadprivate.cpp
new file mode 100644
index 000000000000..5187257b06ed
--- /dev/null
+++ b/test/PCH/chain-openmp-threadprivate.cpp
@@ -0,0 +1,26 @@
+// no PCH
+// RUN: %clang_cc1 -fopenmp=libiomp5 -emit-llvm -include %s -include %s %s -o - | FileCheck %s
+// with PCH
+// RUN: %clang_cc1 -fopenmp=libiomp5 -emit-llvm -chain-include %s -chain-include %s %s -o - | FileCheck %s
+#if !defined(PASS1)
+#define PASS1
+
+extern "C" int* malloc (int size);
+int *a = malloc(20);
+
+#elif !defined(PASS2)
+#define PASS2
+
+#pragma omp threadprivate(a)
+
+#else
+
+// CHECK: call {{.*}} @__kmpc_threadprivate_register(
+
+// CHECK-LABEL: foo
+int foo() {
+ return *a;
+ // CHECK: call {{.*}} @__kmpc_global_thread_num(
+ // CHECK: call {{.*}} @__kmpc_threadprivate_cached(
+}
+#endif
diff --git a/test/PCH/cxx-namespaces.cpp b/test/PCH/cxx-namespaces.cpp
index e0feaab6910a..d1bf98b4ca17 100644
--- a/test/PCH/cxx-namespaces.cpp
+++ b/test/PCH/cxx-namespaces.cpp
@@ -4,12 +4,12 @@
// Test with pch.
// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-namespaces.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
-// RUN: %clang_cc1 -include-pch %t -fsyntax-only -ast-dump -ast-dump-lookups -ast-dump-filter N %s | FileCheck %s
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -ast-dump-lookups -ast-dump-filter N %s | FileCheck %s
// Test with modules.
// RUN: %clang_cc1 -fmodules -x c++-header -emit-pch -o %t %S/cxx-namespaces.h
// RUN: %clang_cc1 -fmodules -include-pch %t -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fmodules -include-pch %t -fsyntax-only -ast-dump -ast-dump-lookups -ast-dump-filter N %s | FileCheck %s
+// RUN: %clang_cc1 -fmodules -include-pch %t -fsyntax-only -ast-dump-lookups -ast-dump-filter N %s | FileCheck %s
// expected-no-diagnostics
diff --git a/test/PCH/cxx-traits.cpp b/test/PCH/cxx-traits.cpp
index ffdfccc6f47f..fc3e1335dd60 100644
--- a/test/PCH/cxx-traits.cpp
+++ b/test/PCH/cxx-traits.cpp
@@ -1,15 +1,66 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/cxx-traits.h -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-extensions -include %S/cxx-traits.h -std=c++11 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %S/cxx-traits.h
-// RUN: %clang_cc1 -std=c++11 -include-pch %t -DPCH -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-extensions -x c++-header -std=c++11 -emit-pch -o %t %S/cxx-traits.h
+// RUN: %clang_cc1 -fms-extensions -std=c++11 -include-pch %t -DPCH -fsyntax-only -verify %s
#ifdef PCH
// expected-no-diagnostics
#endif
-bool _Is_pod_comparator = __is_pod<int>::__value;
-bool _Is_empty_check = __is_empty<int>::__value;
+bool _Is_pod_comparator = n::__is_pod<int>::__value;
+bool _Is_empty_check = n::__is_empty<int>::__value;
-bool default_construct_int = is_trivially_constructible<int>::value;
-bool copy_construct_int = is_trivially_constructible<int, const int&>::value;
+bool default_construct_int = n::is_trivially_constructible<int>::value;
+bool copy_construct_int = n::is_trivially_constructible<int, const int&>::value;
+
+// The built-ins should still work too:
+bool _is_abstract_result = __is_abstract(int);
+bool _is_arithmetic_result = __is_arithmetic(int);
+bool _is_array_result = __is_array(int);
+bool _is_base_of_result = __is_base_of(int, int);
+bool _is_class_result = __is_class(int);
+bool _is_complete_type_result = __is_complete_type(int);
+bool _is_compound_result = __is_compound(int);
+bool _is_const_result = __is_const(int);
+bool _is_constructible_result = __is_constructible(int);
+bool _is_convertible_result = __is_convertible(int, int);
+bool _is_convertible_to_result = __is_convertible_to(int, int);
+bool _is_destructible_result = __is_destructible(int);
+bool _is_empty_result = __is_empty(int);
+bool _is_enum_result = __is_enum(int);
+bool _is_floating_point_result = __is_floating_point(int);
+bool _is_final_result = __is_final(int);
+bool _is_function_result = __is_function(int);
+bool _is_fundamental_result = __is_fundamental(int);
+bool _is_integral_result = __is_integral(int);
+bool _is_interface_class_result = __is_interface_class(int);
+bool _is_literal_result = __is_literal(int);
+bool _is_lvalue_expr_result = __is_lvalue_expr(0);
+bool _is_lvalue_reference_result = __is_lvalue_reference(int);
+bool _is_member_function_pointer_result = __is_member_function_pointer(int);
+bool _is_member_object_pointer_result = __is_member_object_pointer(int);
+bool _is_member_pointer_result = __is_member_pointer(int);
+bool _is_nothrow_assignable_result = __is_nothrow_assignable(int, int);
+bool _is_nothrow_constructible_result = __is_nothrow_constructible(int);
+bool _is_nothrow_destructible_result = __is_nothrow_destructible(int);
+bool _is_object_result = __is_object(int);
+bool _is_pod_result = __is_pod(int);
+bool _is_pointer_result = __is_pointer(int);
+bool _is_polymorphic_result = __is_polymorphic(int);
+bool _is_reference_result = __is_reference(int);
+bool _is_rvalue_expr_result = __is_rvalue_expr(0);
+bool _is_rvalue_reference_result = __is_rvalue_reference(int);
+bool _is_same_result = __is_same(int, int);
+bool _is_scalar_result = __is_scalar(int);
+bool _is_sealed_result = __is_sealed(int);
+bool _is_signed_result = __is_signed(int);
+bool _is_standard_layout_result = __is_standard_layout(int);
+bool _is_trivial_result = __is_trivial(int);
+bool _is_trivially_assignable_result = __is_trivially_assignable(int, int);
+bool _is_trivially_constructible_result = __is_trivially_constructible(int);
+bool _is_trivially_copyable_result = __is_trivially_copyable(int);
+bool _is_union_result = __is_union(int);
+bool _is_unsigned_result = __is_unsigned(int);
+bool _is_void_result = __is_void(int);
+bool _is_volatile_result = __is_volatile(int);
diff --git a/test/PCH/cxx-traits.h b/test/PCH/cxx-traits.h
index e6f2feb1d116..21324768186e 100644
--- a/test/PCH/cxx-traits.h
+++ b/test/PCH/cxx-traits.h
@@ -1,5 +1,7 @@
// Header for PCH test cxx-traits.cpp
+namespace n {
+
template<typename _Tp>
struct __is_pod { // expected-warning {{keyword '__is_pod' will be made available as an identifier for the remainder of the translation unit}}
enum { __value };
@@ -14,3 +16,54 @@ template<typename T, typename ...Args>
struct is_trivially_constructible {
static const bool value = __is_trivially_constructible(T, Args...);
};
+
+struct __is_abstract {}; // expected-warning {{made available}}
+struct __is_arithmetic {}; // expected-warning {{made available}}
+struct __is_array {}; // expected-warning {{made available}}
+struct __is_base_of {}; // expected-warning {{made available}}
+struct __is_class {}; // expected-warning {{made available}}
+struct __is_complete_type {}; // expected-warning {{made available}}
+struct __is_compound {}; // expected-warning {{made available}}
+struct __is_const {}; // expected-warning {{made available}}
+struct __is_constructible {}; // expected-warning {{made available}}
+struct __is_convertible {}; // expected-warning {{made available}}
+struct __is_convertible_to {}; // expected-warning {{made available}}
+struct __is_destructible {}; // expected-warning {{made available}}
+struct __is_enum {}; // expected-warning {{made available}}
+struct __is_floating_point {}; // expected-warning {{made available}}
+struct __is_final {}; // expected-warning {{made available}}
+struct __is_function {}; // expected-warning {{made available}}
+struct __is_fundamental {}; // expected-warning {{made available}}
+struct __is_integral {}; // expected-warning {{made available}}
+struct __is_interface_class {}; // expected-warning {{made available}}
+struct __is_literal {}; // expected-warning {{made available}}
+struct __is_lvalue_expr {}; // expected-warning {{made available}}
+struct __is_lvalue_reference {}; // expected-warning {{made available}}
+struct __is_member_function_pointer {}; // expected-warning {{made available}}
+struct __is_member_object_pointer {}; // expected-warning {{made available}}
+struct __is_member_pointer {}; // expected-warning {{made available}}
+struct __is_nothrow_assignable {}; // expected-warning {{made available}}
+struct __is_nothrow_constructible {}; // expected-warning {{made available}}
+struct __is_nothrow_destructible {}; // expected-warning {{made available}}
+struct __is_object {}; // expected-warning {{made available}}
+struct __is_pointer {}; // expected-warning {{made available}}
+struct __is_polymorphic {}; // expected-warning {{made available}}
+struct __is_reference {}; // expected-warning {{made available}}
+struct __is_rvalue_expr {}; // expected-warning {{made available}}
+struct __is_rvalue_reference {}; // expected-warning {{made available}}
+struct __is_same {}; // expected-warning {{made available}}
+struct __is_scalar {}; // expected-warning {{made available}}
+struct __is_sealed {}; // expected-warning {{made available}}
+struct __is_signed {}; // expected-warning {{made available}}
+struct __is_standard_layout {}; // expected-warning {{made available}}
+struct __is_trivial {}; // expected-warning {{made available}}
+struct __is_trivially_assignable {}; // expected-warning {{made available}}
+struct __is_trivially_constructible {}; // expected-warning {{made available}}
+struct __is_trivially_copyable {}; // expected-warning {{made available}}
+struct __is_union {}; // expected-warning {{made available}}
+struct __is_unsigned {}; // expected-warning {{made available}}
+struct __is_void {}; // expected-warning {{made available}}
+struct __is_volatile {}; // expected-warning {{made available}}
+
+
+}
diff --git a/test/PCH/cxx1y-lambdas.mm b/test/PCH/cxx1y-lambdas.mm
index ee4a2ba3ecc9..becf6cb64222 100644
--- a/test/PCH/cxx1y-lambdas.mm
+++ b/test/PCH/cxx1y-lambdas.mm
@@ -50,7 +50,7 @@ int add(int x, int y) {
}
// CHECK-PRINT: inline int add_int_slowly_twice
-// CHECK-PRINT: lambda = [] ($auto-0-0 z
+// CHECK-PRINT: lambda = [] (type-parameter-0-0 z
// CHECK-PRINT: init_capture
// CHECK-PRINT: [&, x( t )]
diff --git a/test/PCH/pragma-loop.cpp b/test/PCH/pragma-loop.cpp
index 1456a2778f33..2640020f0007 100644
--- a/test/PCH/pragma-loop.cpp
+++ b/test/PCH/pragma-loop.cpp
@@ -10,11 +10,14 @@
// CHECK: #pragma clang loop unroll(disable)
// CHECK: #pragma clang loop interleave(disable)
// CHECK: #pragma clang loop vectorize(enable)
-// CHECK: #pragma clang loop unroll(enable)
+// CHECK: #pragma clang loop unroll(full)
// CHECK: #pragma clang loop interleave(enable)
// CHECK: #pragma clang loop vectorize(disable)
// CHECK: #pragma unroll
// CHECK: #pragma unroll (32)
+// CHECK: #pragma nounroll
+// CHECK: #pragma clang loop interleave_count(I)
+// CHECK: #pragma clang loop vectorize_width(V)
#ifndef HEADER
#define HEADER
@@ -47,7 +50,7 @@ public:
int i = 0;
#pragma clang loop vectorize(disable)
#pragma clang loop interleave(enable)
-#pragma clang loop unroll(enable)
+#pragma clang loop unroll(full)
while (i - 3 < Length) {
List[i] = i;
i++;
@@ -71,8 +74,25 @@ public:
i++;
}
}
-};
+ inline void run6(int *List, int Length) {
+ int i = 0;
+#pragma nounroll
+ while (i - 3 < Length) {
+ List[i] = i;
+ i++;
+ }
+ }
+
+ template <int V, int I>
+ inline void run7(int *List, int Length) {
+#pragma clang loop vectorize_width(V)
+#pragma clang loop interleave_count(I)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+ }
+};
#else
void test() {
@@ -85,6 +105,8 @@ void test() {
pt.run3(List, 100);
pt.run4(List, 100);
pt.run5(List, 100);
+ pt.run6(List, 100);
+ pt.run7<2, 4>(List, 100);
}
#endif
diff --git a/test/PCH/pragma-optimize.c b/test/PCH/pragma-optimize.c
index 2206fe75cd82..9570117448e2 100644
--- a/test/PCH/pragma-optimize.c
+++ b/test/PCH/pragma-optimize.c
@@ -5,6 +5,12 @@
// RUN: %clang_cc1 %s -emit-pch -o %t
// RUN: %clang_cc1 %s -emit-llvm -include-pch %t -o - | FileCheck %s
+// The first run line creates a pch, and since at that point HEADER is not
+// defined, the only thing contained in the pch is the pragma. The second line
+// then includes that pch, so HEADER is defined and the actual code is compiled.
+// The check then makes sure that the pragma is in effect in the file that
+// includes the pch.
+
// expected-no-diagnostics
#ifndef HEADER
diff --git a/test/PCH/stmt-attrs.cpp b/test/PCH/stmt-attrs.cpp
index 3d7c7a27a7e2..170e34975e62 100644
--- a/test/PCH/stmt-attrs.cpp
+++ b/test/PCH/stmt-attrs.cpp
@@ -1,24 +1,24 @@
-// RUN: %clang_cc1 -std=c++11 -emit-pch -o %t.a %s
-// RUN: %clang_cc1 -std=c++11 -include-pch %t.a %s -ast-print -o - | FileCheck %s
-
-#ifndef HEADER
-#define HEADER
-
-inline void test(int i) {
- switch (i) {
- case 1:
- // Notice that the NullStmt has two attributes.
- // CHECK: {{\[\[clang::fallthrough\]\] \[\[clang::fallthrough\]\]}}
- [[clang::fallthrough]] [[clang::fallthrough]];
- case 2:
- break;
- }
-}
-
-#else
-
-void foo(void) {
- test(1);
-}
-
-#endif
+// RUN: %clang_cc1 -std=c++11 -emit-pch -o %t.a %s
+// RUN: %clang_cc1 -std=c++11 -include-pch %t.a %s -ast-print -o - | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+
+inline void test(int i) {
+ switch (i) {
+ case 1:
+ // Notice that the NullStmt has two attributes.
+ // CHECK: {{\[\[clang::fallthrough\]\] \[\[clang::fallthrough\]\]}}
+ [[clang::fallthrough]] [[clang::fallthrough]];
+ case 2:
+ break;
+ }
+}
+
+#else
+
+void foo(void) {
+ test(1);
+}
+
+#endif
diff --git a/test/PCH/verify_pch.m b/test/PCH/verify_pch.m
index dcfb286e2a11..e905f2537c7f 100644
--- a/test/PCH/verify_pch.m
+++ b/test/PCH/verify_pch.m
@@ -5,25 +5,25 @@
// RUN: cp %s %t.h
//
// Precompile
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t -x objective-c-header -emit-pch -o %t.pch %t.h
+// RUN: %clang_cc1 -isystem %t/usr/include -x objective-c-header -emit-pch -o %t.pch %t.h
// Verify successfully
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t -verify-pch %t.pch
+// RUN: %clang_cc1 -isystem %t/usr/include -verify-pch %t.pch
// Incompatible lang options ignored
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t -x objective-c -fno-builtin -verify-pch %t.pch
+// RUN: %clang_cc1 -isystem %t/usr/include -x objective-c -fno-builtin -verify-pch %t.pch
// Stale dependency
// RUN: echo ' ' >> %t.h
-// RUN: not %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t -verify-pch %t.pch 2> %t.log.2
+// RUN: not %clang_cc1 -isystem %t/usr/include -verify-pch %t.pch 2> %t.log.2
// RUN: FileCheck -check-prefix=CHECK-STALE-DEP %s < %t.log.2
// CHECK-STALE-DEP: file '{{.*}}.h' has been modified since the precompiled header '{{.*}}.pch' was built
// Stale dependency in system header
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t -x objective-c-header -emit-pch -o %t.pch %t.h
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t -verify-pch %t.pch
+// RUN: %clang_cc1 -isystem %t/usr/include -x objective-c-header -emit-pch -o %t.pch %t.h
+// RUN: %clang_cc1 -isystem %t/usr/include -verify-pch %t.pch
// RUN: echo ' ' >> %t/usr/include/sys_header.h
-// RUN: not %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t -verify-pch %t.pch 2> %t.log.3
+// RUN: not %clang_cc1 -isystem %t/usr/include -verify-pch %t.pch 2> %t.log.3
// RUN: FileCheck -check-prefix=CHECK-STALE-SYS-H %s < %t.log.3
// CHECK-STALE-SYS-H: file '{{.*}}sys_header.h' has been modified since the precompiled header '{{.*}}.pch' was built
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
index d7ea20bca01c..ea25ccd1af33 100644
--- a/test/Parser/MicrosoftExtensions.c
+++ b/test/Parser/MicrosoftExtensions.c
@@ -85,3 +85,11 @@ int * __uptr __ptr64 pup64;
/* Legal to have nested pointer attributes */
int * __sptr * __ptr32 ppsp32;
+
+// Ignored type qualifiers after comma in declarator lists
+typedef int ignored_quals_dummy1, const volatile __ptr32 __ptr64 __w64 __unaligned __sptr __uptr ignored_quals1; // expected-warning {{qualifiers after comma in declarator list are ignored}}
+typedef void(*ignored_quals_dummy2)(), __fastcall ignored_quals2; // expected-warning {{qualifiers after comma in declarator list are ignored}}
+typedef void(*ignored_quals_dummy3)(), __stdcall ignored_quals3; // expected-warning {{qualifiers after comma in declarator list are ignored}}
+typedef void(*ignored_quals_dummy4)(), __thiscall ignored_quals4; // expected-warning {{qualifiers after comma in declarator list are ignored}}
+typedef void(*ignored_quals_dummy5)(), __cdecl ignored_quals5; // expected-warning {{qualifiers after comma in declarator list are ignored}}
+typedef void(*ignored_quals_dummy6)(), __vectorcall ignored_quals6; // expected-warning {{qualifiers after comma in declarator list are ignored}}
diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp
index 0174ec2f292d..73a1bb57af36 100644
--- a/test/Parser/MicrosoftExtensions.cpp
+++ b/test/Parser/MicrosoftExtensions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple i386-mingw32 -std=c++11 -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions -fms-compatibility -fdelayed-template-parsing
+// RUN: %clang_cc1 %s -triple i386-mingw32 -std=c++11 -fsyntax-only -Wno-unused-getter-return-value -Wno-unused-value -Wmicrosoft -verify -fms-extensions -fms-compatibility -fdelayed-template-parsing
/* Microsoft attribute tests */
[repeatable][source_annotation_attribute( Parameter|ReturnValue )]
@@ -208,12 +208,12 @@ extern TypenameWrongPlace<AAAA> PR16925;
__interface MicrosoftInterface;
__interface MicrosoftInterface {
- void foo1() = 0;
+ void foo1() = 0; // expected-note {{overridden virtual function is here}}
virtual void foo2() = 0;
};
__interface MicrosoftDerivedInterface : public MicrosoftInterface {
- void foo1();
+ void foo1(); // expected-warning {{'foo1' overrides a member function but is not marked 'override'}}
void foo2() override;
void foo3();
};
@@ -226,6 +226,11 @@ void interface_test() {
}
__int64 x7 = __int64(0);
+_int64 x8 = _int64(0);
+static_assert(sizeof(_int64) == 8, "");
+static_assert(sizeof(_int32) == 4, "");
+static_assert(sizeof(_int16) == 2, "");
+static_assert(sizeof(_int8) == 1, "");
int __identifier(generic) = 3;
int __identifier(int) = 4;
@@ -315,6 +320,7 @@ struct StructWithProperty {
__declspec(property(get=GetV,)) int V10; // expected-error {{expected 'get' or 'put' in property declaration}}
__declspec(property(get=GetV,put=SetV)) int V11; // no-warning
__declspec(property(get=GetV,put=SetV,get=GetV)) int V12; // expected-error {{property declaration specifies 'get' accessor twice}}
+ __declspec(property(get=GetV)) int V13 = 3; // expected-error {{property declaration cannot have an in-class initializer}}
int GetV() { return 123; }
void SetV(int v) {}
@@ -361,3 +367,11 @@ void foo(void) {
template <int *>
struct NullptrArg {};
NullptrArg<nullptr> a;
+
+// Ignored type qualifiers after comma in declarator lists
+typedef int ignored_quals_dummy1, const volatile __ptr32 __ptr64 __w64 __unaligned __sptr __uptr ignored_quals1; // expected-warning {{qualifiers after comma in declarator list are ignored}}
+typedef void(*ignored_quals_dummy2)(), __fastcall ignored_quals2; // expected-warning {{qualifiers after comma in declarator list are ignored}}
+typedef void(*ignored_quals_dummy3)(), __stdcall ignored_quals3; // expected-warning {{qualifiers after comma in declarator list are ignored}}
+typedef void(*ignored_quals_dummy4)(), __thiscall ignored_quals4; // expected-warning {{qualifiers after comma in declarator list are ignored}}
+typedef void(*ignored_quals_dummy5)(), __cdecl ignored_quals5; // expected-warning {{qualifiers after comma in declarator list are ignored}}
+typedef void(*ignored_quals_dummy6)(), __vectorcall ignored_quals6; // expected-warning {{qualifiers after comma in declarator list are ignored}}
diff --git a/test/Parser/PR21872.cpp b/test/Parser/PR21872.cpp
new file mode 100644
index 000000000000..ae0a13d9c1ea
--- /dev/null
+++ b/test/Parser/PR21872.cpp
@@ -0,0 +1,4 @@
+// RUN: not %clang_cc1 -fsyntax-only %s
+template <typename T> struct S {
+ int k = ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
+int f;
diff --git a/test/Parser/access-spec-attrs.cpp b/test/Parser/access-spec-attrs.cpp
index 4fa597581165..2958e385f8b5 100644
--- a/test/Parser/access-spec-attrs.cpp
+++ b/test/Parser/access-spec-attrs.cpp
@@ -5,6 +5,7 @@ public __attribute__((unavailable)): // expected-error {{access specifier can on
void foo();
private __attribute__((annotate("foobar"))):
void bar();
+private __attribute__((annotate())): // expected-error {{'annotate' attribute takes one argument}}
};
void f(X x) {
diff --git a/test/Parser/altivec.c b/test/Parser/altivec.c
index 0b8147a3b7b0..d852511fc06d 100644
--- a/test/Parser/altivec.c
+++ b/test/Parser/altivec.c
@@ -18,6 +18,9 @@ __vector float vv_f;
__vector bool char vv_bc;
__vector bool short vv_bs;
__vector bool int vv_bi;
+__vector __bool char vv___bc;
+__vector __bool short vv___bs;
+__vector __bool int vv_bi;
__vector __pixel vv_p;
__vector pixel vv__p;
__vector int vf__r();
@@ -40,6 +43,9 @@ vector float v_f;
vector bool char v_bc;
vector bool short v_bs;
vector bool int v_bi;
+vector __bool char v___bc;
+vector __bool short v___bs;
+vector __bool int v___bi;
vector __pixel v_p;
vector pixel v__p;
vector int f__r();
@@ -61,15 +67,16 @@ vector unsigned long v_ul; // expected-warning {{Use of 'long' with '__
vector long int v_li; // expected-warning {{Use of 'long' with '__vector' is deprecated}}
vector signed long int v_sli; // expected-warning {{Use of 'long' with '__vector' is deprecated}}
vector unsigned long int v_uli; // expected-warning {{Use of 'long' with '__vector' is deprecated}}
-__vector long double vv_ld; // expected-warning {{Use of 'long' with '__vector' is deprecated}} expected-error {{cannot use 'double' with '__vector'}}
-vector long double v_ld; // expected-warning {{Use of 'long' with '__vector' is deprecated}} expected-error {{cannot use 'double' with '__vector'}}
+__vector long double vv_ld; // expected-error {{cannot use 'long double' with '__vector'}}
+vector long double v_ld; // expected-error {{cannot use 'long double' with '__vector'}}
vector bool v_b; // expected-warning {{type specifier missing, defaults to 'int'}}
+vector __bool v___b; // expected-warning {{type specifier missing, defaults to 'int'}}
// These should have errors.
-__vector double vv_d1; // expected-error {{cannot use 'double' with '__vector'}}
-vector double v_d2; // expected-error {{cannot use 'double' with '__vector'}}
-__vector long double vv_ld3; // expected-warning {{Use of 'long' with '__vector' is deprecated}} expected-error {{cannot use 'double' with '__vector'}}
-vector long double v_ld4; // expected-warning {{Use of 'long' with '__vector' is deprecated}} expected-error {{cannot use 'double' with '__vector'}}
+__vector double vv_d1; // expected-error {{use of 'double' with '__vector' requires VSX support to be enabled (available on the POWER7 or later)}}
+vector double v_d2; // expected-error {{use of 'double' with '__vector' requires VSX support to be enabled (available on the POWER7 or later)}}
+__vector long double vv_ld3; // expected-error {{cannot use 'long double' with '__vector'}}
+vector long double v_ld4; // expected-error {{cannot use 'long double' with '__vector'}}
vector bool float v_bf; // expected-error {{cannot use 'float' with '__vector bool'}}
vector bool double v_bd; // expected-error {{cannot use 'double' with '__vector bool'}}
vector bool pixel v_bp; // expected-error {{cannot use '__pixel' with '__vector bool'}}
@@ -77,6 +84,18 @@ vector bool signed char v_bsc; // expected-error {{cannot use 'signed' wit
vector bool unsigned int v_bsc2; // expected-error {{cannot use 'unsigned' with '__vector bool'}}
vector bool long v_bl; // expected-error {{cannot use 'long' with '__vector bool'}}
vector bool long long v_bll; // expected-error {{cannot use 'long long' with '__vector bool'}}
+vector __bool float v___bf; // expected-error {{cannot use 'float' with '__vector bool'}}
+vector __bool double v___bd; // expected-error {{cannot use 'double' with '__vector bool'}}
+vector __bool pixel v___bp; // expected-error {{cannot use '__pixel' with '__vector bool'}}
+vector __bool signed char v___bsc; // expected-error {{cannot use 'signed' with '__vector bool'}}
+vector __bool unsigned int v___bsc2; // expected-error {{cannot use 'unsigned' with '__vector bool'}}
+vector __bool long v___bl; // expected-error {{cannot use 'long' with '__vector bool'}}
+vector __bool long long v___bll; // expected-error {{cannot use 'long long' with '__vector bool'}}
+
+// vector long is deprecated, but vector long long is not.
+vector long long v_ll;
+vector signed long long v_sll;
+vector unsigned long long v_ull;
typedef char i8;
typedef short i16;
diff --git a/test/Parser/asm.cpp b/test/Parser/asm.cpp
index 35a497c83a1e..9f64dfea476e 100644
--- a/test/Parser/asm.cpp
+++ b/test/Parser/asm.cpp
@@ -6,3 +6,4 @@ int foo3 asm (u8"bar3"); // expected-error {{cannot use unicode string literal i
int foo4 asm (u"bar4"); // expected-error {{cannot use unicode string literal in 'asm'}}
int foo5 asm (U"bar5"); // expected-error {{cannot use unicode string literal in 'asm'}}
int foo6 asm ("bar6"_x); // expected-error {{string literal with user-defined suffix cannot be used here}}
+int foo6 asm ("" L"bar7"); // expected-error {{cannot use wide string literal in 'asm'}}
diff --git a/test/Parser/atomic.c b/test/Parser/atomic.c
index 432deeb59c12..07a83dddcd3c 100644
--- a/test/Parser/atomic.c
+++ b/test/Parser/atomic.c
@@ -33,3 +33,6 @@ typedef _Atomic(int) __attribute__((address_space(1))) atomic_addr_space_int;
typedef _Atomic int __attribute__((vector_size(16))) atomic_vector_int;
typedef _Atomic(int __attribute__((vector_size(16)))) atomic_vector_int;
+
+struct S
+_Atomic atomic_s_no_missing_semicolon;
diff --git a/test/Parser/attributes.c b/test/Parser/attributes.c
index 3d69c72c322c..b815b8da3dc6 100644
--- a/test/Parser/attributes.c
+++ b/test/Parser/attributes.c
@@ -95,3 +95,13 @@ void testFundef5() __attribute__(()) { }
__attribute__((pure)) int testFundef6(int a) { return a; }
void deprecatedTestFun(void) __attribute__((deprecated()));
+
+struct s {
+ int a;
+};
+
+// This test ensure compatibility with parsing GNU-style attributes
+// where the attribute is on a separate line from the elaborated type
+// specifier.
+struct s
+__attribute__((used)) bar;
diff --git a/test/Parser/c11-noreturn.c b/test/Parser/c11-noreturn.c
index e61901dfb791..9b932abeaff2 100644
--- a/test/Parser/c11-noreturn.c
+++ b/test/Parser/c11-noreturn.c
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify %s
-// RUN: not %clang_cc1 -pedantic -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXT %s
+// RUN: not %clang_cc1 -std=c99 -pedantic -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXT %s
_Noreturn int f();
int _Noreturn f(); // expected-note {{previous}}
int f _Noreturn(); // expected-error {{expected ';'}} expected-error 2{{}}
-int f() _Noreturn; // expected-error {{expected ';'}} expected-warning {{does not declare anything}} expected-error {{'_Noreturn' can only appear on functions}}
+int f() _Noreturn; // expected-error {{'_Noreturn' keyword must precede function declarator}}
_Noreturn char c1; // expected-error {{'_Noreturn' can only appear on functions}}
char _Noreturn c2; // expected-error {{'_Noreturn' can only appear on functions}}
diff --git a/test/Parser/c1x-alignas.c b/test/Parser/c1x-alignas.c
index 5b29df262d3c..ce8436c12fbb 100644
--- a/test/Parser/c1x-alignas.c
+++ b/test/Parser/c1x-alignas.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify %s
-// RUN: not %clang_cc1 -pedantic -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXT %s
+// RUN: not %clang_cc1 -std=c99 -pedantic -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXT %s
_Alignas(4) char c1;
unsigned _Alignas(long) char c2;
diff --git a/test/Parser/colon-colon-parentheses.cpp b/test/Parser/colon-colon-parentheses.cpp
index 55948fdb0051..e031ce2e9045 100644
--- a/test/Parser/colon-colon-parentheses.cpp
+++ b/test/Parser/colon-colon-parentheses.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -fsyntax-only -verify -DPR21815
// RUN: cp %s %t
// RUN: not %clang_cc1 -x c++ -fixit %t
// RUN: %clang_cc1 -x c++ %t
@@ -20,3 +20,11 @@ void foo() {
a = ::(h; // expected-error{{unexpected parenthesis after '::'}}
a = ::i;
}
+
+#ifdef PR21815
+// expected-error@+4{{C++ requires a type specifier for all declarations}}
+// expected-error@+3{{expected unqualified-id}}
+// expected-error@+3{{expected expression}}
+// expected-error@+1{{expected ';' after top level declarator}}
+a (::(
+#endif
diff --git a/test/Parser/cxx-altivec.cpp b/test/Parser/cxx-altivec.cpp
index 565decc601f8..f2ba28b641a6 100644
--- a/test/Parser/cxx-altivec.cpp
+++ b/test/Parser/cxx-altivec.cpp
@@ -61,14 +61,14 @@ vector unsigned long v_ul; // expected-warning {{Use of 'long' with '__
vector long int v_li; // expected-warning {{Use of 'long' with '__vector' is deprecated}}
vector signed long int v_sli; // expected-warning {{Use of 'long' with '__vector' is deprecated}}
vector unsigned long int v_uli; // expected-warning {{Use of 'long' with '__vector' is deprecated}}
-__vector long double vv_ld; // expected-warning {{Use of 'long' with '__vector' is deprecated}} expected-error {{cannot use 'double' with '__vector'}}
-vector long double v_ld; // expected-warning {{Use of 'long' with '__vector' is deprecated}} expected-error {{cannot use 'double' with '__vector'}}
+__vector long double vv_ld; // expected-error {{cannot use 'long double' with '__vector'}}
+vector long double v_ld; // expected-error {{cannot use 'long double' with '__vector'}}
// These should have errors.
-__vector double vv_d1; // expected-error {{cannot use 'double' with '__vector'}}
-vector double v_d2; // expected-error {{cannot use 'double' with '__vector'}}
-__vector long double vv_ld3; // expected-warning {{Use of 'long' with '__vector' is deprecated}} expected-error {{cannot use 'double' with '__vector'}}
-vector long double v_ld4; // expected-warning {{Use of 'long' with '__vector' is deprecated}} expected-error {{cannot use 'double' with '__vector'}}
+__vector double vv_d1; // expected-error {{use of 'double' with '__vector' requires VSX support to be enabled (available on the POWER7 or later)}}
+vector double v_d2; // expected-error {{use of 'double' with '__vector' requires VSX support to be enabled (available on the POWER7 or later)}}
+__vector long double vv_ld3; // expected-error {{cannot use 'long double' with '__vector'}}
+vector long double v_ld4; // expected-error {{cannot use 'long double' with '__vector'}}
vector bool v_b; // expected-error {{C++ requires a type specifier for all declarations}}
vector bool float v_bf; // expected-error {{cannot use 'float' with '__vector bool'}}
vector bool double v_bd; // expected-error {{cannot use 'double' with '__vector bool'}}
@@ -78,6 +78,11 @@ vector bool unsigned int v_bsc2; // expected-error {{cannot use 'unsigned'
vector bool long v_bl; // expected-error {{cannot use 'long' with '__vector bool'}}
vector bool long long v_bll; // expected-error {{cannot use 'long long' with '__vector bool'}}
+// vector long is deprecated, but vector long long is not.
+vector long long v_ll;
+vector signed long long v_sll;
+vector unsigned long long v_ull;
+
void f() {
__vector unsigned int v = {0,0,0,0};
__vector int v__cast = (__vector int)v;
diff --git a/test/Parser/cxx-ambig-init-templ.cpp b/test/Parser/cxx-ambig-init-templ.cpp
index ac79f77e152d..1f692664137c 100644
--- a/test/Parser/cxx-ambig-init-templ.cpp
+++ b/test/Parser/cxx-ambig-init-templ.cpp
@@ -169,3 +169,9 @@ namespace ElaboratedTypeSpecifiers {
enum E {};
};
}
+
+namespace PR20459 {
+ template <typename EncTraits> struct A {
+ void foo(int = EncTraits::template TypeEnc<int, int>::val); // ok
+ };
+}
diff --git a/test/Parser/cxx-attributes.cpp b/test/Parser/cxx-attributes.cpp
index 6fd7f4f68a46..6591532a91a2 100644
--- a/test/Parser/cxx-attributes.cpp
+++ b/test/Parser/cxx-attributes.cpp
@@ -20,3 +20,5 @@ namespace PR17666 {
typedef int __attribute__((aligned(int(1)))) T1;
typedef int __attribute__((aligned(int))) T2; // expected-error {{expected '(' for function-style cast}}
}
+
+__attribute((typename)) int x; // expected-warning {{unknown attribute 'typename' ignored}}
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
index 80cd8288011d..0e9a3b9d54d3 100644
--- a/test/Parser/cxx-class.cpp
+++ b/test/Parser/cxx-class.cpp
@@ -139,6 +139,54 @@ namespace CtorErrors {
};
}
+namespace DtorErrors {
+ struct A { ~A(); } a;
+ ~A::A() {} // expected-error {{'~' in destructor name should be after nested name specifier}} expected-note {{previous}}
+ A::~A() {} // expected-error {{redefinition}}
+
+ struct B { ~B(); } *b;
+ DtorErrors::~B::B() {} // expected-error {{'~' in destructor name should be after nested name specifier}}
+
+ void f() {
+ a.~A::A(); // expected-error {{'~' in destructor name should be after nested name specifier}}
+ b->~DtorErrors::~B::B(); // expected-error {{'~' in destructor name should be after nested name specifier}}
+ }
+}
+
+namespace BadFriend {
+ struct A {
+ friend int : 3; // expected-error {{friends can only be classes or functions}}
+ friend void f() = 123; // expected-error {{illegal initializer}}
+ friend virtual void f(); // expected-error {{'virtual' is invalid in friend declarations}}
+ friend void f() final; // expected-error {{'final' is invalid in friend declarations}}
+ friend void f() override; // expected-error {{'override' is invalid in friend declarations}}
+ };
+}
+
+class PR20760_a {
+ int a = ); // expected-warning {{extension}} expected-error {{expected expression}}
+ int b = }; // expected-warning {{extension}} expected-error {{expected expression}}
+ int c = ]; // expected-warning {{extension}} expected-error {{expected expression}}
+};
+class PR20760_b {
+ int d = d); // expected-warning {{extension}} expected-error {{expected ';'}}
+ int e = d]; // expected-warning {{extension}} expected-error {{expected ';'}}
+ int f = d // expected-warning {{extension}} expected-error {{expected ';'}}
+};
+
+namespace PR20887 {
+class X1 { a::operator=; }; // expected-error {{undeclared identifier 'a'}}
+class X2 { a::a; }; // expected-error {{undeclared identifier 'a'}}
+}
+
+class BadExceptionSpec {
+ void f() throw(int; // expected-error {{expected ')'}} expected-note {{to match}}
+ void g() throw( // expected-note {{to match}}
+ int( // expected-note {{to match}}
+ ; // expected-error 2{{expected ')'}} expected-error {{unexpected end of exception specification}}
+ ));
+};
+
// PR11109 must appear at the end of the source file
class pr11109r3 { // expected-note{{to match this '{'}}
public // expected-error{{expected ':'}} expected-error{{expected '}'}} expected-error{{expected ';' after class}}
diff --git a/test/Parser/cxx-default-args.cpp b/test/Parser/cxx-default-args.cpp
index 36abf0d8cb38..0095a2f04dc4 100644
--- a/test/Parser/cxx-default-args.cpp
+++ b/test/Parser/cxx-default-args.cpp
@@ -31,3 +31,13 @@ struct T {
void f7(bool a = T1<int, bool>::V < 3);
void f8(int = func<0,1<2>(0), int = 1<0, T1<int,int>(int) = 0);
};
+
+// rdar://18508589
+struct S {
+ void f(int &r = error); // expected-error {{use of undeclared identifier 'error'}}
+};
+
+struct U {
+ void i(int x = ) {} // expected-error{{expected expression}}
+ typedef int *fp(int x = ); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
+};
diff --git a/test/Parser/cxx-member-initializers.cpp b/test/Parser/cxx-member-initializers.cpp
index ff8c880a1849..8e52adbbfd33 100644
--- a/test/Parser/cxx-member-initializers.cpp
+++ b/test/Parser/cxx-member-initializers.cpp
@@ -66,12 +66,12 @@ namespace PR16480 {
struct T { int n; };
template<typename> struct A { int n; };
- }; // expected-error +{{}}
+ };
// FIXME: This is valid now, but may be made ill-formed by DR1607.
struct G : X<0> {
G() : X<0 && [](){return 0;}()>{} // expected-error +{{}}
- }; // expected-error +{{}}
+ };
struct Errs : X<0> {
Errs(X<0>) : decltype X<0>() {} // expected-error {{expected '(' after 'decltype'}}
@@ -79,3 +79,29 @@ namespace PR16480 {
Errs(X<2>) : decltype(X<0> // expected-note {{to match this '('}}
}; // expected-error {{expected ')'}}
}
+
+template <class U, class V> struct C {
+ int f() { return 4; }
+ class C1 {};
+};
+
+class D {};
+namespace N {
+struct E {
+ class F {};
+};
+}
+
+class G {
+ // These are all valid:
+ void f(int x = C<int, D>().f()) {}
+ void g(int x = C<int, ::D>().f()) {}
+ void h(int x = C<int, N::E>().f()) {}
+ void i(int x = C<int, ::N::E>().f()) {}
+ void j(int x = C<int, decltype(N::E())::F>().f()) {}
+ void k(int x = C<int, C<int, int>>().f()) {}
+ void l(int x = C<int, C<int, int>::C1>().f()) {}
+
+ // This isn't, but it shouldn't crash. The diagnostics don't matter much.
+ void m(int x = C<int, union int>().f()) {} // expected-error {{declaration of anonymous union must be a definition}} expected-error {{expected a type}}
+};
diff --git a/test/Parser/cxx-template-argument.cpp b/test/Parser/cxx-template-argument.cpp
index bbd53b2bdd69..c9cc6b807902 100644
--- a/test/Parser/cxx-template-argument.cpp
+++ b/test/Parser/cxx-template-argument.cpp
@@ -106,3 +106,8 @@ namespace pr16225add {
{ };
}
+
+namespace PR18793 {
+ template<typename T, T> struct S {};
+ template<typename T> int g(S<T, (T())> *);
+}
diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp
index 8b2b12037b3c..efa42ad30d04 100644
--- a/test/Parser/cxx-template-decl.cpp
+++ b/test/Parser/cxx-template-decl.cpp
@@ -210,3 +210,31 @@ void Instantiate() {
}
}
+
+namespace func_tmpl_spec_def_in_func {
+// We failed to diagnose function template specialization definitions inside
+// functions during recovery previously.
+template <class> void FuncTemplate() {}
+void TopLevelFunc() {
+ // expected-error@+2 {{expected a qualified name after 'typename'}}
+ // expected-error@+1 {{function definition is not allowed here}}
+ typename template <> void FuncTemplate<void>() { }
+ // expected-error@+1 {{function definition is not allowed here}}
+ void NonTemplateInner() { }
+}
+}
+
+namespace broken_baseclause {
+template<typename T>
+struct base { };
+
+struct t1 : base<int,
+ public: // expected-error {{expected expression}}
+}; // expected-error {{expected class name}}
+// expected-error@-1 {{expected '{' after base class list}}
+struct t2 : base<int,
+ public // expected-error {{expected expression}}
+}; // expected-error {{expected class name}}
+// expected-error@-1 {{expected '{' after base class list}}
+
+}
diff --git a/test/Parser/cxx-variadic-func.cpp b/test/Parser/cxx-variadic-func.cpp
index b9360d6ed10a..98a34d3e1bf6 100644
--- a/test/Parser/cxx-variadic-func.cpp
+++ b/test/Parser/cxx-variadic-func.cpp
@@ -1,5 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
void f(...) {
- int g(int(...));
+ // FIXME: There's no disambiguation here; this is unambiguous.
+ int g(int(...)); // expected-warning {{disambiguated}} expected-note {{paren}}
}
+
+void h(int n..., int m); // expected-error {{expected ')'}} expected-note {{to match}}
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index f8abc76fb2f3..c68a119fc740 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -Wc++14-compat %s
// Need std::initializer_list
namespace std {
@@ -86,6 +86,10 @@ class [[]] [[]] final_class_another
[[]] [[]] alignas(16) final // expected-error {{an attribute list cannot appear here}}
[[]] [[]] alignas(16) [[]]{}; // expected-error {{an attribute list cannot appear here}}
+// The diagnostics here don't matter much, this just shouldn't crash:
+class C final [[deprecated(l]] {}); // expected-error {{use of undeclared identifier}} expected-error {{expected ']'}} expected-error {{an attribute list cannot appear here}} expected-error {{expected unqualified-id}}
+class D final alignas ([l) {}]{}); // expected-error {{expected ',' or ']' in lambda capture list}} expected-error {{an attribute list cannot appear here}}
+
[[]] struct with_init_declarators {} init_declarator;
[[]] struct no_init_declarators; // expected-error {{an attribute list cannot appear here}}
template<typename> [[]] struct no_init_declarators_template; // expected-error {{an attribute list cannot appear here}}
@@ -121,6 +125,7 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
[[]] using ns::i; // expected-error {{an attribute list cannot appear here}}
[[unknown]] using namespace ns; // expected-warning {{unknown attribute 'unknown' ignored}}
[[noreturn]] using namespace ns; // expected-error {{'noreturn' attribute only applies to functions}}
+namespace [[]] ns2 {} // expected-warning {{attributes on a namespace declaration are incompatible with C++ standards before C++1z}}
using [[]] alignas(4) [[]] ns::i; // expected-error {{an attribute list cannot appear here}}
using [[]] alignas(4) [[]] foobar = int; // expected-error {{an attribute list cannot appear here}} expected-error {{'alignas' attribute only applies to}}
@@ -172,7 +177,7 @@ enum [[]] E2; // expected-error {{forbids forward references}}
enum [[]] E1;
enum [[]] E3 : int;
enum [[]] {
- k_123 [[]] = 123 // expected-error {{an attribute list cannot appear here}}
+ k_123 [[]] = 123 // expected-warning {{attributes on an enumerator declaration are incompatible with C++ standards before C++1z}}
};
enum [[]] E1 e; // expected-error {{an attribute list cannot appear here}}
enum [[]] class E4 { }; // expected-error {{an attribute list cannot appear here}}
@@ -329,3 +334,10 @@ namespace {
[[deprecated()]] void foo(); // expected-error {{parentheses must be omitted if 'deprecated' attribute's argument list is empty}}
[[gnu::deprecated()]] void quux();
}
+
+namespace {
+[[ // expected-error {{expected ']'}}
+#pragma pack(pop)
+deprecated
+]] void bad();
+}
diff --git a/test/Parser/cxx0x-decl.cpp b/test/Parser/cxx0x-decl.cpp
index a0334cdde292..994104fc9dfb 100644
--- a/test/Parser/cxx0x-decl.cpp
+++ b/test/Parser/cxx0x-decl.cpp
@@ -116,9 +116,19 @@ namespace DuplicateSpecifier {
};
}
+namespace ColonColonDecltype {
+ struct S { struct T {}; };
+ ::decltype(S())::T invalid; // expected-error {{expected unqualified-id}}
+}
+
struct Base { virtual void f() = 0; virtual void g() = 0; virtual void h() = 0; };
struct MemberComponentOrder : Base {
void f() override __asm__("foobar") __attribute__(( )) {}
void g() __attribute__(( )) override;
void h() __attribute__(( )) override {}
};
+
+void NoMissingSemicolonHere(struct S
+ [3]);
+template<int ...N> void NoMissingSemicolonHereEither(struct S
+ ... [N]);
diff --git a/test/Parser/cxx0x-in-cxx98.cpp b/test/Parser/cxx0x-in-cxx98.cpp
index 724993811631..10cb4d2fa53a 100644
--- a/test/Parser/cxx0x-in-cxx98.cpp
+++ b/test/Parser/cxx0x-in-cxx98.cpp
@@ -28,3 +28,7 @@ struct Auto {
auto Auto::n = 0; // expected-warning {{'auto' type specifier is a C++11 extension}}
auto Auto::m = 0; // expected-error {{no member named 'm' in 'Auto'}}
// expected-warning@-1 {{'auto' type specifier is a C++11 extension}}
+
+struct Conv { template<typename T> operator T(); };
+bool pr21367_a = new int && false;
+bool pr21367_b = &Conv::operator int && false;
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
index 8cfe7f3b02da..6f69d8096e22 100644
--- a/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -91,3 +91,20 @@ class C {
__attribute__((noreturn)) { while(1); }; // expected-error {{expected body of lambda expression}}
}
};
+
+template <typename>
+void PR22122() {
+ [](int) -> {}; // expected-error {{expected a type}}
+}
+
+template void PR22122<int>();
+
+struct S {
+ template <typename T>
+ void m (T x =[0); // expected-error{{expected variable name or 'this' in lambda capture list}}
+} s;
+
+struct U {
+ template <typename T>
+ void m_fn1(T x = 0[0); // expected-error{{expected ']'}} expected-note{{to match this '['}}
+} *U;
diff --git a/test/Parser/cxx11-templates.cpp b/test/Parser/cxx11-templates.cpp
new file mode 100644
index 000000000000..ed0495281c17
--- /dev/null
+++ b/test/Parser/cxx11-templates.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+struct S {
+ template <typename Ty = char>
+ static_assert(sizeof(Ty) != 1, "Not a char"); // expected-error {{a static_assert declaration cannot be a template}}
+};
+
+template <typename Ty = char>
+static_assert(sizeof(Ty) != 1, "Not a char"); // expected-error {{a static_assert declaration cannot be a template}}
+
+namespace Ellipsis {
+ template<typename ...T> void f(T t..., int n); // expected-error {{must immediately precede declared identifier}}
+ template<typename ...T> void f(int n, T t...); // expected-error {{must immediately precede declared identifier}}
+ template<typename ...T> void f(int n, T t, ...); // expected-error {{unexpanded parameter pack}}
+ template<typename ...T> void f() {
+ f([]{
+ void g(T
+ t // expected-note {{place '...' immediately before declared identifier to declare a function parameter pack}}
+ ... // expected-warning {{'...' in this location creates a C-style varargs function, not a function parameter pack}}
+ // expected-note@-1 {{insert ',' before '...' to silence this warning}}
+ );
+ void h(T (&
+ ) // expected-note {{place '...' here to declare a function parameter pack}}
+ ... // expected-warning {{'...' in this location creates a C-style varargs function, not a function parameter pack}}
+ // expected-note@-1 {{insert ',' before '...' to silence this warning}}
+ );
+ void i(T (&), ...);
+ }...);
+ }
+ template<typename ...T> struct S {
+ void f(T t...); // expected-error {{must immediately precede declared identifier}}
+ void f(T ... // expected-note {{preceding '...' declares a function parameter pack}}
+ t...); // expected-warning-re {{'...' in this location creates a C-style varargs function{{$}}}}
+ // expected-note@-1 {{insert ',' before '...' to silence this warning}}
+ };
+
+ // FIXME: We should just issue a single error in this case pointing out where
+ // the '...' goes. It's tricky to recover correctly in this case, though,
+ // because the parameter is in scope in the default argument, so must be
+ // passed to Sema before we reach the ellipsis.
+ template<typename...T> void f(T n = 1 ...);
+ // expected-warning@-1 {{creates a C-style varargs}}
+ // expected-note@-2 {{place '...' immediately before declared identifier}}
+ // expected-note@-3 {{insert ','}}
+ // expected-error@-4 {{unexpanded parameter pack}}
+}
diff --git a/test/Parser/cxx1z-attributes.cpp b/test/Parser/cxx1z-attributes.cpp
new file mode 100644
index 000000000000..1267091ab253
--- /dev/null
+++ b/test/Parser/cxx1z-attributes.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
+
+namespace [[]] foo {}
+namespace [[]] {}
+namespace [[]] bad = foo; // expected-error {{attributes cannot be specified on namespace alias}}
+
+namespace [[]] A::B {} // expected-error {{attributes cannot be specified on a nested namespace definition}}
+
+enum test {
+ bing [[]],
+ bar [[]] = 1,
+ baz [[]][[]],
+ quux [[]][[]] = 4
+};
diff --git a/test/Parser/cxx1z-fold-expressions.cpp b/test/Parser/cxx1z-fold-expressions.cpp
new file mode 100644
index 000000000000..a908311ea316
--- /dev/null
+++ b/test/Parser/cxx1z-fold-expressions.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+template<typename ...T> constexpr auto sum(T ...t) { return (... + t); }
+template<typename ...T> constexpr auto product(T ...t) { return (t * ...); }
+template<typename ...T> constexpr auto all(T ...t) { return (true && ... && t); }
+template<typename ...T> constexpr auto all2(T ...t) { return (t && ... && true); }
+
+int k1 = (1 + ... + 2); // expected-error {{does not contain any unexpanded parameter packs}}
+int k2 = (1 + ...); // expected-error {{does not contain any unexpanded parameter packs}}
+int k3 = (... + 2); // expected-error {{does not contain any unexpanded parameter packs}}
+
+template<int ...N> void bad1() { (N + ... + N); } // expected-error {{unexpanded parameter packs in both operands}}
+// FIXME: it would be reasonable to support this as an extension.
+template<int ...N> void bad2() { (2 * N + ... + 1); } // expected-error {{expression not permitted as operand}}
+template<int ...N> void bad3() { (2 + N * ... * 1); } // expected-error {{expression not permitted as operand}}
+template<int ...N, int ...M> void bad4(int (&...x)[N]) { (N + M * ... * 1); } // expected-error {{expression not permitted as operand}}
+template<int ...N, int ...M> void fixed4(int (&...x)[N]) { ((N + M) * ... * 1); }
+
+// Parens are mandatory.
+template<int ...N> void bad5() { N + ...; } // expected-error {{expected expression}} expected-error +{{}}
+template<int ...N> void bad6() { ... + N; } // expected-error {{expected expression}}
+template<int ...N> void bad7() { N + ... + N; } // expected-error {{expected expression}} expected-error +{{}}
+
+// Must have a fold-operator in the relevant places.
+template<int ...N> int bad8() { return (N + ... * 3); } // expected-error {{operators in fold expression must be the same}}
+template<int ...N> int bad9() { return (3 + ... * N); } // expected-error {{operators in fold expression must be the same}}
+template<int ...N> int bad10() { return (3 ? ... : N); } // expected-error +{{}} expected-note {{to match}}
+template<int ...N> int bad11() { return (N + ... 0); } // expected-error {{expected a foldable binary operator}} expected-error {{expected expression}}
+template<int ...N> int bad12() { return (... N); } // expected-error {{expected expression}}
diff --git a/test/Parser/cxx1z-nested-namespace-definition.cpp b/test/Parser/cxx1z-nested-namespace-definition.cpp
new file mode 100644
index 000000000000..96f34c540acc
--- /dev/null
+++ b/test/Parser/cxx1z-nested-namespace-definition.cpp
@@ -0,0 +1,38 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -x c++ -fixit %t -Werror -DFIXIT
+// RUN: %clang_cc1 -x c++ %t -DFIXIT
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z -Wc++14-compat
+
+namespace foo1::foo2::foo3 {
+#if __cplusplus <= 201400L
+// expected-warning@-2 {{nested namespace definition is a C++1z extension; define each namespace separately}}
+#else
+// expected-warning@-4 {{nested namespace definition is incompatible with C++ standards before C++1z}}
+#endif
+ int foo(int x) { return x; }
+}
+
+#ifndef FIXIT
+inline namespace goo::bar { // expected-error {{nested namespace definition cannot be 'inline'}} expected-warning 0-1{{C++11 feature}}
+ int n;
+}
+
+int m = goo::bar::n;
+#endif
+
+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/debugger-import-module.m b/test/Parser/debugger-import-module.m
new file mode 100644
index 000000000000..b6001aed6a89
--- /dev/null
+++ b/test/Parser/debugger-import-module.m
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -fdebugger-support -verify %s
+// expected-no-diagnostics
+
+void importAModule() {
+ @import AModuleThatDoesntExist
+}
diff --git a/test/Parser/declarators.c b/test/Parser/declarators.c
index 39d9dc94490d..48936d592269 100644
--- a/test/Parser/declarators.c
+++ b/test/Parser/declarators.c
@@ -7,6 +7,7 @@ void f1(int [*]);
void f2(int [const *]);
void f3(int [volatile const*]);
int f4(*XX)(void); /* expected-error {{cannot return}} expected-warning {{type specifier missing, defaults to 'int'}} */
+int f5(int [static]); /* expected-error {{'static' may not be used without an array size}} */
char ((((*X))));
@@ -112,6 +113,7 @@ enum E1 { e1 }: // expected-error {{expected ';'}}
struct EnumBitfield { // expected-warning {{struct without named members is a GNU extension}}
enum E2 { e2 } : 4; // ok
struct S { int n; }: // expected-error {{expected ';'}}
+ // expected-warning@-1 {{declaration does not declare anything}}
};
@@ -148,3 +150,5 @@ enum E16 {
A6; // expected-error{{expected '= constant-expression' or end of enumerator definition}}
A6a
};
+
+int PR20634 = sizeof(struct { int n; } [5]);
diff --git a/test/Parser/eof2.cpp b/test/Parser/eof2.cpp
new file mode 100644
index 000000000000..6a8b862e6099
--- /dev/null
+++ b/test/Parser/eof2.cpp
@@ -0,0 +1,15 @@
+// RUN: not %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
+
+// CHECK: error: expected expression
+// CHECK: error: expected member name or ';' after declaration specifiers
+// CHECK: error: expected '}'
+// CHECK: note: to match this '{'
+// CHECK: error: expected ';' after class
+// CHECK: 4 errors generated.
+
+// Do not add anything to the end of this file. This requires the whitespace
+// plus EOF after the '<' token.
+
+template <typename T>
+class a {
+ a<
diff --git a/test/Parser/ms-if-exists.c b/test/Parser/ms-if-exists.c
new file mode 100644
index 000000000000..7dd20544a6b4
--- /dev/null
+++ b/test/Parser/ms-if-exists.c
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 %s -fsyntax-only -Wmicrosoft -verify -fms-extensions
+// expected-no-diagnostics
+
+struct Type {
+};
+
+void test_if_exists_stmts() {
+ int b = 0;
+ __if_exists(Type) {
+ b++;
+ b++;
+ }
+ __if_exists(Type_not) {
+ this will not compile.
+ }
+ __if_not_exists(Type) {
+ this will not compile.
+ }
+ __if_not_exists(Type_not) {
+ b++;
+ b++;
+ }
+}
+
+int if_exists_creates_no_scope() {
+ __if_exists(Type) {
+ int x; // 'x' is declared in the parent scope.
+ }
+ __if_not_exists(Type_not) {
+ x++;
+ }
+ return x;
+}
+
+__if_exists(Type) {
+ int var23;
+}
+
+__if_exists(Type_not) {
+ this will not compile.
+}
+
+__if_not_exists(Type) {
+ this will not compile.
+}
+
+__if_not_exists(Type_not) {
+ int var244;
+}
+
+void test_if_exists_init_list() {
+
+ int array1[] = {
+ 0,
+ __if_exists(Type) {2, }
+ 3
+ };
+
+ int array2[] = {
+ 0,
+ __if_exists(Type_not) { this will not compile }
+ 3
+ };
+
+ int array3[] = {
+ 0,
+ __if_not_exists(Type_not) {2, }
+ 3
+ };
+
+ int array4[] = {
+ 0,
+ __if_not_exists(Type) { this will not compile }
+ 3
+ };
+
+}
+
+
+void test_nested_if_exists() {
+ __if_exists(Type) {
+ int x = 42;
+ __if_not_exists(Type_not) {
+ x++;
+ }
+ }
+}
diff --git a/test/Parser/ms-inline-asm.c b/test/Parser/ms-inline-asm.c
index 00508f5cf098..72c96c3715d9 100644
--- a/test/Parser/ms-inline-asm.c
+++ b/test/Parser/ms-inline-asm.c
@@ -48,6 +48,9 @@ void t10() {
void t11() {
do { __asm mov eax, 0 __asm { __asm mov edx, 1 } } while(0);
}
+void t12() {
+ __asm jmp label // expected-error {{use of undeclared label 'label'}}
+}
int t_fail() { // expected-note {{to match this}}
__asm
- __asm { // expected-error 3 {{expected}} expected-note {{to match this}}
+ __asm { // expected-error 2 {{expected}} expected-note {{to match this}}
diff --git a/test/Parser/namespaces.cpp b/test/Parser/namespaces.cpp
index 6491cfd446b3..25ff73b8ec01 100644
--- a/test/Parser/namespaces.cpp
+++ b/test/Parser/namespaces.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// PR6596
namespace g { enum { o = 0 }; }
@@ -10,3 +10,7 @@ void foo() {
// PR14085
namespace PR14085 {}
namespace = PR14085; // expected-error {{expected identifier}}
+
+struct namespace_nested_in_record {
+ int k = ({namespace {}}); // expected-error {{statement expression not allowed at file scope}}
+};
diff --git a/test/Parser/nested-namespaces-recovery.cpp b/test/Parser/nested-namespaces-recovery.cpp
deleted file mode 100644
index d45938bb3e67..000000000000
--- a/test/Parser/nested-namespaces-recovery.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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-cl20.cl b/test/Parser/opencl-cl20.cl
new file mode 100644
index 000000000000..b71869919ba9
--- /dev/null
+++ b/test/Parser/opencl-cl20.cl
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0 -DCL20
+
+#ifdef CL20
+// expected-no-diagnostics
+#endif
+
+__generic int * __generic_test(__generic int *arg) {
+ __generic int *var;
+ return var;
+}
+#ifndef CL20
+// expected-error@-5 {{OpenCL does not support the '__generic' type qualifier}}
+// expected-error@-6 {{OpenCL does not support the '__generic' type qualifier}}
+// expected-error@-6 {{OpenCL does not support the '__generic' type qualifier}}
+#endif
+
+generic int * generic_test(generic int *arg) {
+ generic int *var;
+ return var;
+}
+#ifndef CL20
+// expected-error@-5 {{OpenCL does not support the 'generic' type qualifier}}
+// expected-error@-6 {{OpenCL does not support the 'generic' type qualifier}}
+// expected-error@-6 {{OpenCL does not support the 'generic' type qualifier}}
+#endif
diff --git a/test/Parser/pragma-loop.cpp b/test/Parser/pragma-loop.cpp
index 23f185d52284..547d87395ef5 100644
--- a/test/Parser/pragma-loop.cpp
+++ b/test/Parser/pragma-loop.cpp
@@ -3,12 +3,85 @@
// Note that this puts the expected lines before the directives to work around
// limitations in the -verify mode.
+template <int V, int I>
+void test_nontype_template_param(int *List, int Length) {
+#pragma clang loop vectorize_width(V) interleave_count(I)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+
+#pragma clang loop vectorize_width(V + 4) interleave_count(I + 4)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+template <int V>
+void test_nontype_template_vectorize(int *List, int Length) {
+ /* expected-error {{invalid value '-1'; must be positive}} */ #pragma clang loop vectorize_width(V)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+
+ /* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop vectorize_width(V / 2)
+ for (int i = 0; i < Length; i++) {
+ List[i] += i;
+ }
+}
+
+template <int I>
+void test_nontype_template_interleave(int *List, int Length) {
+ /* expected-error {{invalid value '-1'; must be positive}} */ #pragma clang loop interleave_count(I)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+
+ /* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop interleave_count(2 % I)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+template <char V>
+void test_nontype_template_char(int *List, int Length) {
+ /* expected-error {{invalid argument of type 'char'; expected an integer type}} */ #pragma clang loop vectorize_width(V)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+template <bool V>
+void test_nontype_template_bool(int *List, int Length) {
+ /* expected-error {{invalid argument of type 'bool'; expected an integer type}} */ #pragma clang loop vectorize_width(V)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+template <int V, int I>
+void test_nontype_template_badarg(int *List, int Length) {
+ /* expected-error {{use of undeclared identifier 'Vec'}} */ #pragma clang loop vectorize_width(Vec) interleave_count(I)
+ /* expected-error {{use of undeclared identifier 'Int'}} */ #pragma clang loop vectorize_width(V) interleave_count(Int)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+template <typename T>
+void test_type_template_vectorize(int *List, int Length) {
+ const T Value = -1;
+ /* expected-error {{invalid value '-1'; must be positive}} */ #pragma clang loop vectorize_width(Value)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
void test(int *List, int Length) {
int i = 0;
#pragma clang loop vectorize(enable)
#pragma clang loop interleave(enable)
-#pragma clang loop unroll(enable)
+#pragma clang loop unroll(full)
while (i + 1 < Length) {
List[i] = i;
}
@@ -43,68 +116,89 @@ void test(int *List, int Length) {
VList[j] = List[j];
}
+ test_nontype_template_param<4, 8>(List, Length);
+
/* expected-error {{expected '('}} */ #pragma clang loop vectorize
/* expected-error {{expected '('}} */ #pragma clang loop interleave
/* expected-error {{expected '('}} */ #pragma clang loop unroll
/* expected-error {{expected ')'}} */ #pragma clang loop vectorize(enable
/* expected-error {{expected ')'}} */ #pragma clang loop interleave(enable
-/* expected-error {{expected ')'}} */ #pragma clang loop unroll(enable
+/* expected-error {{expected ')'}} */ #pragma clang loop unroll(full
/* expected-error {{expected ')'}} */ #pragma clang loop vectorize_width(4
/* expected-error {{expected ')'}} */ #pragma clang loop interleave_count(4
/* expected-error {{expected ')'}} */ #pragma clang loop unroll_count(4
-/* expected-error {{missing argument to '#pragma clang loop vectorize'; expected a positive integer value}} */ #pragma clang loop vectorize()
-/* expected-error {{missing argument to '#pragma clang loop interleave_count'; expected a positive integer value}} */ #pragma clang loop interleave_count()
-/* expected-error {{missing argument to '#pragma clang loop unroll'; expected a positive integer value}} */ #pragma clang loop unroll()
+/* expected-error {{missing argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize()
+/* expected-error {{missing argument; expected an integer value}} */ #pragma clang loop interleave_count()
+/* expected-error {{missing argument; expected 'enable' or 'disable'}} */ #pragma clang loop unroll()
-/* expected-error {{missing option}} */ #pragma clang loop
+/* expected-error {{missing option; expected vectorize, vectorize_width, interleave, interleave_count, unroll, or unroll_count}} */ #pragma clang loop
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop badkeyword
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop badkeyword(enable)
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop vectorize(enable) badkeyword(4)
/* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize(enable) ,
-
while (i-4 < Length) {
List[i] = i;
}
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(0)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(0)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(0)
+/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop vectorize_width(0)
+/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop interleave_count(0)
+/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop unroll_count(0)
+
+/* expected-error {{expression is not an integral constant expression}} expected-note {{division by zero}} */ #pragma clang loop vectorize_width(10 / 0)
+/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop interleave_count(10 / 5 - 2)
while (i-5 < Length) {
List[i] = i;
}
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(3000000000)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(3000000000)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(3000000000)
+test_nontype_template_vectorize<4>(List, Length);
+/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_vectorize<-1>(List, Length);
+test_nontype_template_interleave<8>(List, Length);
+/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_interleave<-1>(List, Length);
+
+/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_char<'A'>(List, Length); // Loop hint arg cannot be a char.
+/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_bool<true>(List, Length); // Or a bool.
+/* expected-note {{in instantiation of function template specialization}} */ test_type_template_vectorize<int>(List, Length); // Or a template type.
+
+/* expected-error {{value '3000000000' is too large}} */ #pragma clang loop vectorize_width(3000000000)
+/* expected-error {{value '3000000000' is too large}} */ #pragma clang loop interleave_count(3000000000)
+/* expected-error {{value '3000000000' is too large}} */ #pragma clang loop unroll_count(3000000000)
while (i-6 < Length) {
List[i] = i;
}
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(badvalue)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(badvalue)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(badvalue)
+/* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize_width(1 +) 1
+/* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize_width(1) +1
+const int VV = 4;
+/* expected-error {{expected expression}} */ #pragma clang loop vectorize_width(VV +/ 2)
+/* expected-error {{use of undeclared identifier 'undefined'}} */ #pragma clang loop vectorize_width(VV+undefined)
+/* expected-error {{expected ')'}} */ #pragma clang loop vectorize_width(1+(^*/2 * ()
+/* expected-warning {{extra tokens at end of '#pragma clang loop' - ignored}} */ #pragma clang loop vectorize_width(1+(-0[0]))))))
+
+/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop vectorize_width(badvalue)
+/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop interleave_count(badvalue)
+/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop unroll_count(badvalue)
while (i-6 < Length) {
List[i] = i;
}
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize(badidentifier)
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop interleave(badidentifier)
-/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop unroll(badidentifier)
+/* expected-error {{invalid argument; expected 'full' or 'disable'}} */ #pragma clang loop unroll(badidentifier)
while (i-7 < Length) {
List[i] = i;
}
// PR20069 - Loop pragma arguments that are not identifiers or numeric
// constants crash FE.
-/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize(()
+/* expected-error {{expected ')'}} */ #pragma clang loop vectorize(()
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop interleave(*)
-/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop unroll(=)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(^)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(/)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(==)
+/* expected-error {{invalid argument; expected 'full' or 'disable'}} */ #pragma clang loop unroll(=)
+/* expected-error {{type name requires a specifier or qualifier}} expected-error {{expected expression}} */ #pragma clang loop vectorize_width(^)
+/* expected-error {{expected expression}} expected-error {{expected expression}} */ #pragma clang loop interleave_count(/)
+/* expected-error {{expected expression}} expected-error {{expected expression}} */ #pragma clang loop unroll_count(==)
while (i-8 < Length) {
List[i] = i;
}
@@ -136,7 +230,7 @@ void test(int *List, int Length) {
#pragma clang loop vectorize(disable)
/* expected-error {{duplicate directives 'interleave(disable)' and 'interleave(enable)'}} */ #pragma clang loop interleave(enable)
#pragma clang loop interleave(disable)
-/* expected-error {{duplicate directives 'unroll(disable)' and 'unroll(enable)'}} */ #pragma clang loop unroll(enable)
+/* expected-error {{duplicate directives 'unroll(disable)' and 'unroll(full)'}} */ #pragma clang loop unroll(full)
#pragma clang loop unroll(disable)
while (i-9 < Length) {
List[i] = i;
@@ -162,5 +256,12 @@ void test(int *List, int Length) {
List[i] = i;
}
+
+/* expected-error {{incompatible directives 'unroll(full)' and 'unroll_count(4)'}} */ #pragma clang loop unroll(full)
+#pragma clang loop unroll_count(4)
+ while (i-11 < Length) {
+ List[i] = i;
+ }
+
#pragma clang loop interleave(enable)
/* expected-error {{expected statement}} */ }
diff --git a/test/Parser/pragma-unroll.cpp b/test/Parser/pragma-unroll.cpp
index 1d89e63028c4..260945756f2f 100644
--- a/test/Parser/pragma-unroll.cpp
+++ b/test/Parser/pragma-unroll.cpp
@@ -11,47 +11,39 @@ void test(int *List, int Length) {
List[i] = i;
}
-#pragma unroll 4
- while (i - 1 < Length) {
- List[i] = i;
- }
-
-#pragma unroll(8)
- while (i - 2 < Length) {
+#pragma nounroll
+ while (i < Length) {
List[i] = i;
}
-#pragma unroll
-#pragma unroll(8)
- while (i - 3 < Length) {
+#pragma unroll 4
+ while (i - 1 < Length) {
List[i] = i;
}
-#pragma clang loop unroll(enable)
#pragma unroll(8)
- while (i - 4 < Length) {
- List[i] = i;
- }
-
-#pragma unroll
-#pragma clang loop unroll_count(4)
- while (i - 5 < Length) {
+ while (i - 2 < Length) {
List[i] = i;
}
/* expected-error {{expected ')'}} */ #pragma unroll(4
-/* expected-error {{missing argument to '#pragma unroll'; expected a positive integer value}} */ #pragma unroll()
+/* expected-error {{missing argument; expected an integer value}} */ #pragma unroll()
/* expected-warning {{extra tokens at end of '#pragma unroll'}} */ #pragma unroll 1 2
while (i-6 < Length) {
List[i] = i;
}
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(()
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll -
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(0)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll 0
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(3000000000)
-/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll 3000000000
+/* expected-warning {{extra tokens at end of '#pragma nounroll'}} */ #pragma nounroll 1
+ while (i-7 < Length) {
+ List[i] = i;
+ }
+
+/* expected-error {{expected ')'}} */ #pragma unroll(()
+/* expected-error {{expected expression}} */ #pragma unroll -
+/* expected-error {{invalid value '0'; must be positive}} */ #pragma unroll(0)
+/* expected-error {{invalid value '0'; must be positive}} */ #pragma unroll 0
+/* expected-error {{value '3000000000' is too large}} */ #pragma unroll(3000000000)
+/* expected-error {{value '3000000000' is too large}} */ #pragma unroll 3000000000
while (i-8 < Length) {
List[i] = i;
}
@@ -60,6 +52,8 @@ void test(int *List, int Length) {
/* expected-error {{expected a for, while, or do-while loop to follow '#pragma unroll'}} */ int j = Length;
#pragma unroll 4
/* expected-error {{expected a for, while, or do-while loop to follow '#pragma unroll'}} */ int k = Length;
+#pragma nounroll
+/* expected-error {{expected a for, while, or do-while loop to follow '#pragma nounroll'}} */ int l = Length;
/* expected-error {{incompatible directives 'unroll(disable)' and '#pragma unroll(4)'}} */ #pragma unroll 4
#pragma clang loop unroll(disable)
@@ -67,14 +61,38 @@ void test(int *List, int Length) {
List[i] = i;
}
+/* expected-error {{incompatible directives 'unroll(full)' and '#pragma unroll(4)'}} */ #pragma unroll(4)
+#pragma clang loop unroll(full)
+ while (i-11 < Length) {
+ List[i] = i;
+ }
+
+/* expected-error {{incompatible directives '#pragma unroll' and '#pragma unroll(4)'}} */ #pragma unroll(4)
+#pragma unroll
+ while (i-11 < Length) {
+ List[i] = i;
+ }
+
+/* expected-error {{incompatible directives '#pragma nounroll' and 'unroll_count(4)'}} */ #pragma clang loop unroll_count(4)
+#pragma nounroll
+ while (i-12 < Length) {
+ List[i] = i;
+ }
+
+/* expected-error {{duplicate directives '#pragma nounroll' and '#pragma nounroll'}} */ #pragma nounroll
+#pragma nounroll
+ while (i-13 < Length) {
+ List[i] = i;
+ }
+
/* expected-error {{duplicate directives '#pragma unroll' and '#pragma unroll'}} */ #pragma unroll
#pragma unroll
while (i-14 < Length) {
List[i] = i;
}
-/* expected-error {{duplicate directives 'unroll(enable)' and '#pragma unroll'}} */ #pragma unroll
-#pragma clang loop unroll(enable)
+/* expected-error {{duplicate directives 'unroll(full)' and '#pragma unroll'}} */ #pragma unroll
+#pragma clang loop unroll(full)
while (i-15 < Length) {
List[i] = i;
}
diff --git a/test/Parser/switch-recovery.cpp b/test/Parser/switch-recovery.cpp
index 534517018267..4b06d55ba594 100644
--- a/test/Parser/switch-recovery.cpp
+++ b/test/Parser/switch-recovery.cpp
@@ -220,3 +220,12 @@ bool bar0() {
case bar5: ; // expected-error{{use of undeclared identifier 'bar5'}}
}
}
+
+namespace pr21841 {
+void fn1() {
+ switch (0)
+ switch (0 // expected-note{{to match this '('}}
+ { // expected-error{{expected ')'}}
+ }
+} // expected-error{{expected statement}}
+}
diff --git a/test/Parser/vsx.c b/test/Parser/vsx.c
new file mode 100644
index 000000000000..ead09814c8c1
--- /dev/null
+++ b/test/Parser/vsx.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple=powerpc64-unknown-linux-gnu -faltivec -target-feature +vsx -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple=powerpc64le-unknown-linux-gnu -faltivec -target-feature +vsx -fsyntax-only -verify %s
+
+// Legitimate for VSX.
+__vector double vv_d1;
+vector double v_d2;
+
+// These should have errors.
+__vector long double vv_ld3; // expected-error {{cannot use 'long double' with '__vector'}}
+vector long double v_ld4; // expected-error {{cannot use 'long double' with '__vector'}}
diff --git a/test/Preprocessor/_Pragma.c b/test/Preprocessor/_Pragma.c
index 15725a422299..120e754cb986 100644
--- a/test/Preprocessor/_Pragma.c
+++ b/test/Preprocessor/_Pragma.c
@@ -11,3 +11,5 @@ _Pragma("message(\"foo \\\\\\\\ bar\")") // expected-warning {{foo \\ bar}}
#ifdef macro
#error #define invalid
#endif
+
+_Pragma( // expected-error{{_Pragma takes a parenthesized string literal}}
diff --git a/test/Preprocessor/aarch64-target-features.c b/test/Preprocessor/aarch64-target-features.c
index 137a1d81920a..4e9e6c7fde95 100644
--- a/test/Preprocessor/aarch64-target-features.c
+++ b/test/Preprocessor/aarch64-target-features.c
@@ -12,8 +12,11 @@
// CHECK: __ARM_FEATURE_CLZ 1
// CHECK-NOT: __ARM_FEATURE_CRC32 1
// CHECK-NOT: __ARM_FEATURE_CRYPTO 1
+// CHECK: __ARM_FEATURE_DIRECTED_ROUNDING 1
// CHECK: __ARM_FEATURE_DIV 1
// CHECK: __ARM_FEATURE_FMA 1
+// CHECK: __ARM_FEATURE_IDIV 1
+// CHECK: __ARM_FEATURE_NUMERIC_MAXMIN 1
// CHECK: __ARM_FEATURE_UNALIGNED 1
// CHECK: __ARM_FP 0xe
// CHECK: __ARM_FP16_FORMAT_IEEE 1
@@ -70,6 +73,9 @@
// CHECK-MCPU-A53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
// CHECK-MCPU-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
+// RUN: %clang -target x86_64-apple-macosx -arch arm64 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64 %s
+// CHECK-ARCH-ARM64: "-target-cpu" "cyclone" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+zcm" "-target-feature" "+zcz"
+
// RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s
// RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s
// RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s
diff --git a/test/Preprocessor/arm-acle-6.4.c b/test/Preprocessor/arm-acle-6.4.c
index a656f7608c0f..fc228d093c8c 100644
--- a/test/Preprocessor/arm-acle-6.4.c
+++ b/test/Preprocessor/arm-acle-6.4.c
@@ -5,6 +5,8 @@
// CHECK-CORTEX-M0-NOT: __ARM_ARCH_ISA_ARM
// CHECK-CORTEX-M0: __ARM_ARCH_ISA_THUMB 1
// CHECK-CORTEX-M0: __ARM_ARCH_PROFILE 'M'
+// CHECK-CORTEX-M0-NOT: __ARM_FEATURE_NUMERIC_MAXMIN
+// CHECK-CORTEX-M0-NOT: __ARM_FEATURE_DIRECTED_ROUNDING
// RUN: %clang -target arm-eabi -mcpu=arm810 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-ARM810
@@ -13,6 +15,8 @@
// CHECK-ARM810: __ARM_ARCH_ISA_ARM 1
// CHECK-ARM810-NOT: __ARM_ARCH_ISA_THUMB
// CHECK-ARM810-NOT: __ARM_ARCH_PROFILE
+// CHECK-ARM810-NOT: __ARM_FEATURE_NUMERIC_MAXMIN
+// CHECK-ARM810-NOT: __ARM_FEATURE_DIRECTED_ROUNDING
// RUN: %clang -target arm-eabi -mcpu=arm7tdmi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-ARM7TDMI
@@ -29,6 +33,8 @@
// CHECK-CORTEX-A7: __ARM_ARCH_ISA_ARM 1
// CHECK-CORTEX-A7: __ARM_ARCH_ISA_THUMB 2
// CHECK-CORTEX-A7: __ARM_ARCH_PROFILE 'A'
+// CHECK-CORTEX-A7-NOT: __ARM_FEATURE_NUMERIC_MAXMIN
+// CHECK-CORTEX-A7-NOT: __ARM_FEATURE_DIRECTED_ROUNDING
// RUN: %clang -target arm-eabi -mcpu=cortex-r4 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-CORTEX-R4
diff --git a/test/Preprocessor/arm-acle-6.5.c b/test/Preprocessor/arm-acle-6.5.c
new file mode 100644
index 000000000000..9db83b774b0c
--- /dev/null
+++ b/test/Preprocessor/arm-acle-6.5.c
@@ -0,0 +1,22 @@
+// RUN: %clang -target arm-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-DEFAULT
+
+// CHECK-DEFAULT-NOT: __ARM_FP
+
+// RUN: %clang -target arm-eabi -mfpu=vfp -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP
+// RUN: %clang -target arm-eabi -mfpu=vfp3 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP
+// RUN: %clang -target arm-eabi -mfpu=vfp3-d16 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP
+// RUN: %clang -target arm-eabi -mfpu=neon -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP
+// RUN: %clang -target arm-eabi -mfpu=vfp3 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP
+// RUN: %clang -target armv7-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP
+
+// CHECK-SP-DP: __ARM_FP 0xC
+
+// RUN: %clang -target arm-eabi -mfpu=vfpv4 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP-HP
+// RUN: %clang -target arm-eabi -mfpu=vfpv4-d16 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP-HP
+// RUN: %clang -target arm-eabi -mfpu=fp-armv8 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP-HP
+// RUN: %clang -target arm-eabi -mfpu=neon-fp-armv8 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP-HP
+// RUN: %clang -target arm-eabi -mfpu=crypto-neon-fp-armv8 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP-HP
+// RUN: %clang -target armv8-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP-HP
+
+// CHECK-SP-DP-HP: __ARM_FP 0xE
+
diff --git a/test/Preprocessor/arm-target-features.c b/test/Preprocessor/arm-target-features.c
index 08fe29a72502..e95a50d02277 100644
--- a/test/Preprocessor/arm-target-features.c
+++ b/test/Preprocessor/arm-target-features.c
@@ -3,18 +3,24 @@
// CHECK: __ARM_ARCH 8
// CHECK: __ARM_ARCH_8A__ 1
// CHECK: __ARM_FEATURE_CRC32 1
+// CHECK: __ARM_FEATURE_DIRECTED_ROUNDING 1
+// CHECK: __ARM_FEATURE_NUMERIC_MAXMIN 1
// RUN: %clang -target armv7a-none-linux-gnu -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-V7 %s
// CHECK-V7: __ARMEL__ 1
// CHECK-V7: __ARM_ARCH 7
// CHECK-V7: __ARM_ARCH_7A__ 1
// CHECK-V7-NOT: __ARM_FEATURE_CRC32
+// CHECK-V7-NOT: __ARM_FEATURE_NUMERIC_MAXMIN
+// CHECK-V7-NOT: __ARM_FEATURE_DIRECTED_ROUNDING
// RUN: %clang -target armv8a -mfloat-abi=hard -x c -E -dM %s | FileCheck --check-prefix=CHECK-V8-BAREHF %s
// CHECK-V8-BAREHF: __ARMEL__ 1
// CHECK-V8-BAREHF: __ARM_ARCH 8
// CHECK-V8-BAREHF: __ARM_ARCH_8A__ 1
// CHECK-V8-BAREHF: __ARM_FEATURE_CRC32 1
+// CHECK-V8-BAREHF: __ARM_FEATURE_DIRECTED_ROUNDING 1
+// CHECK-V8-BAREHF: __ARM_FEATURE_NUMERIC_MAXMIN 1
// CHECK-V8-BAREHF: __ARM_NEON__ 1
// CHECK-V8-BAREHF: __VFP_FP__ 1
@@ -137,18 +143,31 @@
// NONEON-A5:#define __ARM_VFPV4__ 1
// FIXME: add check for further predefines
+// Test whether predefines are as expected when targeting ep9312.
+// RUN: %clang -target armv4t -mcpu=ep9312 -x c -E -dM %s -o - | FileCheck --check-prefix=A4T %s
+// A4T-NOT:#define __ARM_FEATURE_DSP
+
+// Test whether predefines are as expected when targeting arm10tdmi.
+// RUN: %clang -target armv5 -mcpu=arm10tdmi -x c -E -dM %s -o - | FileCheck --check-prefix=A5T %s
+// A5T-NOT:#define __ARM_FEATURE_DSP
+
// Test whether predefines are as expected when targeting cortex-a5.
// RUN: %clang -target armv7 -mcpu=cortex-a5 -x c -E -dM %s -o - | FileCheck --check-prefix=A5-ARM %s
// A5-ARM-NOT:#define __ARM_ARCH_EXT_IDIV__
+// A5-ARM:#define __ARM_FEATURE_DSP
// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a5 -x c -E -dM %s -o - | FileCheck --check-prefix=A5-THUMB %s
// A5-THUMB-NOT:#define __ARM_ARCH_EXT_IDIV__
+// A5-THUMB:#define __ARM_FEATURE_DSP
// RUN: %clang -target armv7 -mcpu=cortex-a5 -x c -E -dM %s -o - | FileCheck --check-prefix=A5 %s
// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a5 -x c -E -dM %s -o - | FileCheck --check-prefix=A5 %s
// A5:#define __ARM_ARCH 7
// A5:#define __ARM_ARCH_7A__ 1
// A5:#define __ARM_ARCH_PROFILE 'A'
+// A5-NOT: #define __ARM_FEATURE_NUMERIC_MAXMIN
+// A5-NOT: #define __ARM_FEATURE_DIRECTED_ROUNDING
+// A5:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting cortex-a7.
// RUN: %clang -target armv7 -mcpu=cortex-a7 -x c -E -dM %s -o - | FileCheck --check-prefix=A7 %s
@@ -157,20 +176,25 @@
// A7:#define __ARM_ARCH_7A__ 1
// A7:#define __ARM_ARCH_EXT_IDIV__ 1
// A7:#define __ARM_ARCH_PROFILE 'A'
+// A7:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting cortex-a8.
// RUN: %clang -target armv7 -mcpu=cortex-a8 -x c -E -dM %s -o - | FileCheck --check-prefix=A8-ARM %s
// A8-ARM-NOT:#define __ARM_ARCH_EXT_IDIV__
+// A8-ARM:#define __ARM_FEATURE_DSP
// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a8 -x c -E -dM %s -o - | FileCheck --check-prefix=A8-THUMB %s
// A8-THUMB-NOT:#define __ARM_ARCH_EXT_IDIV__
+// A8-THUMB:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting cortex-a9.
// RUN: %clang -target armv7 -mcpu=cortex-a9 -x c -E -dM %s -o - | FileCheck --check-prefix=A9-ARM %s
// A9-ARM-NOT:#define __ARM_ARCH_EXT_IDIV__
+// A9-ARM:#define __ARM_FEATURE_DSP
// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a9 -x c -E -dM %s -o - | FileCheck --check-prefix=A9-THUMB %s
// A9-THUMB-NOT:#define __ARM_ARCH_EXT_IDIV__
+// A9-THUMB:#define __ARM_FEATURE_DSP
// Check that -mfpu works properly for Cortex-A12 (enabled by default).
@@ -191,53 +215,91 @@
// A12:#define __ARM_ARCH_7A__ 1
// A12:#define __ARM_ARCH_EXT_IDIV__ 1
// A12:#define __ARM_ARCH_PROFILE 'A'
+// A12:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting cortex-a15.
// RUN: %clang -target armv7 -mcpu=cortex-a15 -x c -E -dM %s -o - | FileCheck --check-prefix=A15-ARM %s
// A15-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+// A15-ARM:#define __ARM_FEATURE_DSP
// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a15 -x c -E -dM %s -o - | FileCheck --check-prefix=A15-THUMB %s
// A15-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+// A15-THUMB:#define __ARM_FEATURE_DSP
+
+// Check that -mfpu works properly for Cortex-A17 (enabled by default).
+// RUN: %clang -target armv7-none-linux-gnueabi -mcpu=cortex-a17 -x c -E -dM %s -o - | FileCheck --check-prefix=DEFAULTFPU-A17 %s
+// RUN: %clang -target armv7-none-linux-gnueabi -mthumb -mcpu=cortex-a17 -x c -E -dM %s -o - | FileCheck --check-prefix=DEFAULTFPU-A17 %s
+// DEFAULTFPU-A17:#define __ARM_NEON__ 1
+// DEFAULTFPU-A17:#define __ARM_VFPV4__ 1
+
+// RUN: %clang -target armv7-none-linux-gnueabi -mcpu=cortex-a17 -mfpu=none -x c -E -dM %s -o - | FileCheck --check-prefix=FPUNONE-A17 %s
+// RUN: %clang -target armv7-none-linux-gnueabi -mthumb -mcpu=cortex-a17 -mfpu=none -x c -E -dM %s -o - | FileCheck --check-prefix=FPUNONE-A17 %s
+// FPUNONE-A17-NOT:#define __ARM_NEON__ 1
+// FPUNONE-A17-NOT:#define __ARM_VFPV4__ 1
+
+// Test whether predefines are as expected when targeting cortex-a17.
+// RUN: %clang -target armv7 -mcpu=cortex-a17 -x c -E -dM %s -o - | FileCheck --check-prefix=A17 %s
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-a17 -x c -E -dM %s -o - | FileCheck --check-prefix=A17 %s
+// A17:#define __ARM_ARCH 7
+// A17:#define __ARM_ARCH_7A__ 1
+// A17:#define __ARM_ARCH_EXT_IDIV__ 1
+// A17:#define __ARM_ARCH_PROFILE 'A'
+// A17:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting swift.
// RUN: %clang -target armv7s -mcpu=swift -x c -E -dM %s -o - | FileCheck --check-prefix=SWIFT-ARM %s
// SWIFT-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+// SWIFT:#define __ARM_FEATURE_DSP
// RUN: %clang -target armv7s -mthumb -mcpu=swift -x c -E -dM %s -o - | FileCheck --check-prefix=SWIFT-THUMB %s
// SWIFT-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+// SWIFT-THUMB:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting cortex-a53.
// RUN: %clang -target armv8 -mcpu=cortex-a53 -x c -E -dM %s -o - | FileCheck --check-prefix=A53-ARM %s
// A53-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+// A53-ARM:#define __ARM_FEATURE_DSP
// RUN: %clang -target armv8 -mthumb -mcpu=cortex-a53 -x c -E -dM %s -o - | FileCheck --check-prefix=A53-THUMB %s
// A53-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+// A53-THUMB:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting cortex-r5.
// RUN: %clang -target armv7 -mcpu=cortex-r5 -x c -E -dM %s -o - | FileCheck --check-prefix=R5-ARM %s
// R5-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+// R5-ARM:#define __ARM_FEATURE_DSP
// RUN: %clang -target armv7 -mthumb -mcpu=cortex-r5 -x c -E -dM %s -o - | FileCheck --check-prefix=R5-THUMB %s
// R5-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+// R5-THUMB:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting cortex-m0.
// RUN: %clang -target armv7 -mthumb -mcpu=cortex-m0 -x c -E -dM %s -o - | FileCheck --check-prefix=M0-THUMB %s
// M0-THUMB-NOT:#define __ARM_ARCH_EXT_IDIV__
+// M0-THUMB-NOT:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting cortex-m3.
// RUN: %clang -target armv7 -mthumb -mcpu=cortex-m3 -x c -E -dM %s -o - | FileCheck --check-prefix=M3-THUMB %s
// M3-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+// M3-THUMB-NOT:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting cortex-m4.
// RUN: %clang -target armv7 -mthumb -mcpu=cortex-m4 -x c -E -dM %s -o - | FileCheck --check-prefix=M4-THUMB %s
// M4-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+// M4-THUMB:#define __ARM_FEATURE_DSP
+
+// Test whether predefines are as expected when targeting cortex-m7.
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-m7 -x c -E -dM %s -o - | FileCheck --check-prefix=M7-THUMB %s
+// M7-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+// M7-THUMB:#define __ARM_FEATURE_DSP
// Test whether predefines are as expected when targeting krait.
// RUN: %clang -target armv7 -mcpu=krait -x c -E -dM %s -o - | FileCheck --check-prefix=KRAIT-ARM %s
// KRAIT-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
+// KRAIT-ARM:#define __ARM_FEATURE_DSP
// KRAIT-ARM:#define __ARM_VFPV4__ 1
// RUN: %clang -target armv7 -mthumb -mcpu=krait -x c -E -dM %s -o - | FileCheck --check-prefix=KRAIT-THUMB %s
// KRAIT-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+// KRAIT-THUMB:#define __ARM_FEATURE_DSP
// KRAIT-THUMB:#define __ARM_VFPV4__ 1
-
diff --git a/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp b/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp
index 8e1351e34728..24a3898437f0 100644
--- a/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp
+++ b/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 %s -E -verify -fms-extensions
// expected-no-diagnostics
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+
bool f() {
// Check that operators still work before redefining them.
#if compl 0 bitand 1
diff --git a/test/Preprocessor/feature_tests.c b/test/Preprocessor/feature_tests.c
index 5a2c300e6ee1..fbde6a65476e 100644
--- a/test/Preprocessor/feature_tests.c
+++ b/test/Preprocessor/feature_tests.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=i686-apple-darwin9
+// RUN: %clang_cc1 %s -triple=i686-apple-darwin9 -verify -DVERIFY
// RUN: %clang_cc1 %s -E -triple=i686-apple-darwin9
#ifndef __has_feature
#error Should have __has_feature
@@ -53,3 +53,10 @@
#if !HAS_BUILTIN(MY_ALIAS_BUILTIN) || !HAS_FEATURE(MY_ALIAS_FEATURE)
#error Expansion should have occurred
#endif
+
+#ifdef VERIFY
+// expected-error@+2 {{builtin feature check macro requires a parenthesized identifier}}
+// expected-error@+1 {{expected value in expression}}
+#if __has_feature('x')
+#endif
+#endif
diff --git a/test/Preprocessor/has_attribute.c b/test/Preprocessor/has_attribute.c
index 5fe060e68d3c..0ef5b4857a38 100644
--- a/test/Preprocessor/has_attribute.c
+++ b/test/Preprocessor/has_attribute.c
@@ -48,3 +48,8 @@ int has_no_volatile_attribute();
#if !__has_attribute(dllexport)
int does_not_have_dllexport();
#endif
+
+// CHECK: does_not_have_uuid
+#if !__has_attribute(uuid)
+ int does_not_have_uuid
+#endif
diff --git a/test/Preprocessor/has_attribute.cpp b/test/Preprocessor/has_attribute.cpp
new file mode 100644
index 000000000000..1ab45020b444
--- /dev/null
+++ b/test/Preprocessor/has_attribute.cpp
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fms-compatibility -std=c++11 -E %s -o - | FileCheck %s
+
+// CHECK: has_cxx11_carries_dep
+#if __has_cpp_attribute(carries_dependency)
+ int has_cxx11_carries_dep();
+#endif
+
+// CHECK: has_clang_fallthrough_1
+#if __has_cpp_attribute(clang::fallthrough)
+ int has_clang_fallthrough_1();
+#endif
+
+// CHECK: does_not_have_selectany
+#if !__has_cpp_attribute(selectany)
+ int does_not_have_selectany();
+#endif
+
+// The attribute name can be bracketed with double underscores.
+// CHECK: has_clang_fallthrough_2
+#if __has_cpp_attribute(clang::__fallthrough__)
+ int has_clang_fallthrough_2();
+#endif
+
+// The scope cannot be bracketed with double underscores.
+// CHECK: does_not_have___clang___fallthrough
+#if !__has_cpp_attribute(__clang__::fallthrough)
+ int does_not_have___clang___fallthrough();
+#endif
+
+// Test that C++11, target-specific attributes behave properly.
+
+// CHECK: does_not_have_mips16
+#if !__has_cpp_attribute(gnu::mips16)
+ int does_not_have_mips16();
+#endif
+
+// Test that the version numbers of attributes listed in SD-6 are supported
+// correctly.
+
+// CHECK: has_cxx11_carries_dep_vers
+#if __has_cpp_attribute(carries_dependency) == 200809
+ int has_cxx11_carries_dep_vers();
+#endif
+
+// CHECK: has_cxx11_noreturn_vers
+#if __has_cpp_attribute(noreturn) == 200809
+ int has_cxx11_noreturn_vers();
+#endif
+
+// CHECK: has_cxx14_deprecated_vers
+#if __has_cpp_attribute(deprecated) == 201309
+ int has_cxx14_deprecated_vers();
+#endif
+
+// CHECK: has_declspec_uuid
+#if __has_declspec_attribute(uuid)
+ int has_declspec_uuid();
+#endif
+
+// CHECK: has_declspec_uuid2
+#if __has_declspec_attribute(__uuid__)
+ int has_declspec_uuid2();
+#endif
+
+// CHECK: does_not_have_declspec_fallthrough
+#if !__has_declspec_attribute(fallthrough)
+ int does_not_have_declspec_fallthrough();
+#endif
diff --git a/test/Preprocessor/headermap-rel2.c b/test/Preprocessor/headermap-rel2.c
index 430854de0679..d61f3385b22d 100644
--- a/test/Preprocessor/headermap-rel2.c
+++ b/test/Preprocessor/headermap-rel2.c
@@ -1,8 +1,8 @@
// This uses a headermap with this entry:
// someheader.h -> Product/someheader.h
-// RUN: %clang_cc1 -triple x86_64-apple-darwin13 -v -fsyntax-only %s -iquote %S/Inputs/headermap-rel2/project-headers.hmap -isysroot %S/Inputs/headermap-rel2/system -I %S/Inputs/headermap-rel2 -H
-// RUN: %clang_cc1 -triple x86_64-apple-darwin13 -fsyntax-only %s -iquote %S/Inputs/headermap-rel2/project-headers.hmap -isysroot %S/Inputs/headermap-rel2/system -I %S/Inputs/headermap-rel2 -H 2> %t.out
+// RUN: %clang_cc1 -v -fsyntax-only %s -iquote %S/Inputs/headermap-rel2/project-headers.hmap -isystem %S/Inputs/headermap-rel2/system/usr/include -I %S/Inputs/headermap-rel2 -H
+// RUN: %clang_cc1 -fsyntax-only %s -iquote %S/Inputs/headermap-rel2/project-headers.hmap -isystem %S/Inputs/headermap-rel2/system/usr/include -I %S/Inputs/headermap-rel2 -H 2> %t.out
// RUN: FileCheck %s -input-file %t.out
// CHECK: Product/someheader.h
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 7b73ce0fa60d..4f321140c6b2 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -80,7 +80,7 @@
// COMMON:#define __ORDER_LITTLE_ENDIAN__ 1234
// COMMON:#define __ORDER_PDP_ENDIAN__ 3412
// COMMON:#define __STDC_HOSTED__ 1
-// COMMON:#define __STDC_VERSION__
+// COMMON:#define __STDC_VERSION__ 201112L
// COMMON:#define __STDC__ 1
// COMMON:#define __VERSION__
// COMMON:#define __clang__ 1
@@ -422,7 +422,6 @@
// AARCH64:#define __aarch64__ 1
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64_be-none-none < /dev/null | FileCheck -check-prefix AARCH64-BE %s
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm64_be-none-none < /dev/null | FileCheck -check-prefix AARCH64-BE %s
//
// AARCH64-BE:#define _LP64 1
// AARCH64-BE:#define __AARCH64EB__ 1
@@ -802,6 +801,199 @@
// AARCH64-NETBSD:#define __WINT_TYPE__ int
// AARCH64-NETBSD:#define __WINT_WIDTH__ 32
// AARCH64-NETBSD:#define __aarch64__ 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-freebsd11 < /dev/null | FileCheck -check-prefix AARCH64-FREEBSD %s
+//
+// AARCH64-FREEBSD:#define _LP64 1
+// AARCH64-FREEBSD-NOT:#define __AARCH64EB__ 1
+// AARCH64-FREEBSD:#define __AARCH64EL__ 1
+// AARCH64-FREEBSD-NOT:#define __AARCH_BIG_ENDIAN 1
+// AARCH64-FREEBSD:#define __ARM_64BIT_STATE 1
+// AARCH64-FREEBSD:#define __ARM_ARCH 8
+// AARCH64-FREEBSD:#define __ARM_ARCH_ISA_A64 1
+// AARCH64-FREEBSD-NOT:#define __ARM_BIG_ENDIAN 1
+// AARCH64-FREEBSD:#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+// AARCH64-FREEBSD:#define __CHAR16_TYPE__ unsigned short
+// AARCH64-FREEBSD:#define __CHAR32_TYPE__ unsigned int
+// AARCH64-FREEBSD:#define __CHAR_BIT__ 8
+// AARCH64-FREEBSD:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// AARCH64-FREEBSD:#define __DBL_DIG__ 15
+// AARCH64-FREEBSD:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// AARCH64-FREEBSD:#define __DBL_HAS_DENORM__ 1
+// AARCH64-FREEBSD:#define __DBL_HAS_INFINITY__ 1
+// AARCH64-FREEBSD:#define __DBL_HAS_QUIET_NAN__ 1
+// AARCH64-FREEBSD:#define __DBL_MANT_DIG__ 53
+// AARCH64-FREEBSD:#define __DBL_MAX_10_EXP__ 308
+// AARCH64-FREEBSD:#define __DBL_MAX_EXP__ 1024
+// AARCH64-FREEBSD:#define __DBL_MAX__ 1.7976931348623157e+308
+// AARCH64-FREEBSD:#define __DBL_MIN_10_EXP__ (-307)
+// AARCH64-FREEBSD:#define __DBL_MIN_EXP__ (-1021)
+// AARCH64-FREEBSD:#define __DBL_MIN__ 2.2250738585072014e-308
+// AARCH64-FREEBSD:#define __DECIMAL_DIG__ 36
+// AARCH64-FREEBSD:#define __ELF__ 1
+// AARCH64-FREEBSD:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// AARCH64-FREEBSD:#define __FLT_DIG__ 6
+// AARCH64-FREEBSD:#define __FLT_EPSILON__ 1.19209290e-7F
+// AARCH64-FREEBSD:#define __FLT_EVAL_METHOD__ 0
+// AARCH64-FREEBSD:#define __FLT_HAS_DENORM__ 1
+// AARCH64-FREEBSD:#define __FLT_HAS_INFINITY__ 1
+// AARCH64-FREEBSD:#define __FLT_HAS_QUIET_NAN__ 1
+// AARCH64-FREEBSD:#define __FLT_MANT_DIG__ 24
+// AARCH64-FREEBSD:#define __FLT_MAX_10_EXP__ 38
+// AARCH64-FREEBSD:#define __FLT_MAX_EXP__ 128
+// AARCH64-FREEBSD:#define __FLT_MAX__ 3.40282347e+38F
+// AARCH64-FREEBSD:#define __FLT_MIN_10_EXP__ (-37)
+// AARCH64-FREEBSD:#define __FLT_MIN_EXP__ (-125)
+// AARCH64-FREEBSD:#define __FLT_MIN__ 1.17549435e-38F
+// AARCH64-FREEBSD:#define __FLT_RADIX__ 2
+// AARCH64-FREEBSD:#define __FreeBSD__ 11
+// AARCH64-FREEBSD:#define __INT16_C_SUFFIX__ {{$}}
+// AARCH64-FREEBSD:#define __INT16_FMTd__ "hd"
+// AARCH64-FREEBSD:#define __INT16_FMTi__ "hi"
+// AARCH64-FREEBSD:#define __INT16_MAX__ 32767
+// AARCH64-FREEBSD:#define __INT16_TYPE__ short
+// AARCH64-FREEBSD:#define __INT32_C_SUFFIX__ {{$}}
+// AARCH64-FREEBSD:#define __INT32_FMTd__ "d"
+// AARCH64-FREEBSD:#define __INT32_FMTi__ "i"
+// AARCH64-FREEBSD:#define __INT32_MAX__ 2147483647
+// AARCH64-FREEBSD:#define __INT32_TYPE__ int
+// AARCH64-FREEBSD:#define __INT64_C_SUFFIX__ L
+// AARCH64-FREEBSD:#define __INT64_FMTd__ "ld"
+// AARCH64-FREEBSD:#define __INT64_FMTi__ "li"
+// AARCH64-FREEBSD:#define __INT64_MAX__ 9223372036854775807L
+// AARCH64-FREEBSD:#define __INT64_TYPE__ long int
+// AARCH64-FREEBSD:#define __INT8_C_SUFFIX__ {{$}}
+// AARCH64-FREEBSD:#define __INT8_FMTd__ "hhd"
+// AARCH64-FREEBSD:#define __INT8_FMTi__ "hhi"
+// AARCH64-FREEBSD:#define __INT8_MAX__ 127
+// AARCH64-FREEBSD:#define __INT8_TYPE__ signed char
+// AARCH64-FREEBSD:#define __INTMAX_C_SUFFIX__ L
+// AARCH64-FREEBSD:#define __INTMAX_FMTd__ "ld"
+// AARCH64-FREEBSD:#define __INTMAX_FMTi__ "li"
+// AARCH64-FREEBSD:#define __INTMAX_MAX__ 9223372036854775807L
+// AARCH64-FREEBSD:#define __INTMAX_TYPE__ long int
+// AARCH64-FREEBSD:#define __INTMAX_WIDTH__ 64
+// AARCH64-FREEBSD:#define __INTPTR_FMTd__ "ld"
+// AARCH64-FREEBSD:#define __INTPTR_FMTi__ "li"
+// AARCH64-FREEBSD:#define __INTPTR_MAX__ 9223372036854775807L
+// AARCH64-FREEBSD:#define __INTPTR_TYPE__ long int
+// AARCH64-FREEBSD:#define __INTPTR_WIDTH__ 64
+// AARCH64-FREEBSD:#define __INT_FAST16_FMTd__ "hd"
+// AARCH64-FREEBSD:#define __INT_FAST16_FMTi__ "hi"
+// AARCH64-FREEBSD:#define __INT_FAST16_MAX__ 32767
+// AARCH64-FREEBSD:#define __INT_FAST16_TYPE__ short
+// AARCH64-FREEBSD:#define __INT_FAST32_FMTd__ "d"
+// AARCH64-FREEBSD:#define __INT_FAST32_FMTi__ "i"
+// AARCH64-FREEBSD:#define __INT_FAST32_MAX__ 2147483647
+// AARCH64-FREEBSD:#define __INT_FAST32_TYPE__ int
+// AARCH64-FREEBSD:#define __INT_FAST64_FMTd__ "ld"
+// AARCH64-FREEBSD:#define __INT_FAST64_FMTi__ "li"
+// AARCH64-FREEBSD:#define __INT_FAST64_MAX__ 9223372036854775807L
+// AARCH64-FREEBSD:#define __INT_FAST64_TYPE__ long int
+// AARCH64-FREEBSD:#define __INT_FAST8_FMTd__ "hhd"
+// AARCH64-FREEBSD:#define __INT_FAST8_FMTi__ "hhi"
+// AARCH64-FREEBSD:#define __INT_FAST8_MAX__ 127
+// AARCH64-FREEBSD:#define __INT_FAST8_TYPE__ signed char
+// AARCH64-FREEBSD:#define __INT_LEAST16_FMTd__ "hd"
+// AARCH64-FREEBSD:#define __INT_LEAST16_FMTi__ "hi"
+// AARCH64-FREEBSD:#define __INT_LEAST16_MAX__ 32767
+// AARCH64-FREEBSD:#define __INT_LEAST16_TYPE__ short
+// AARCH64-FREEBSD:#define __INT_LEAST32_FMTd__ "d"
+// AARCH64-FREEBSD:#define __INT_LEAST32_FMTi__ "i"
+// AARCH64-FREEBSD:#define __INT_LEAST32_MAX__ 2147483647
+// AARCH64-FREEBSD:#define __INT_LEAST32_TYPE__ int
+// AARCH64-FREEBSD:#define __INT_LEAST64_FMTd__ "ld"
+// AARCH64-FREEBSD:#define __INT_LEAST64_FMTi__ "li"
+// AARCH64-FREEBSD:#define __INT_LEAST64_MAX__ 9223372036854775807L
+// AARCH64-FREEBSD:#define __INT_LEAST64_TYPE__ long int
+// AARCH64-FREEBSD:#define __INT_LEAST8_FMTd__ "hhd"
+// AARCH64-FREEBSD:#define __INT_LEAST8_FMTi__ "hhi"
+// AARCH64-FREEBSD:#define __INT_LEAST8_MAX__ 127
+// AARCH64-FREEBSD:#define __INT_LEAST8_TYPE__ signed char
+// AARCH64-FREEBSD:#define __INT_MAX__ 2147483647
+// AARCH64-FREEBSD:#define __LDBL_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966L
+// AARCH64-FREEBSD:#define __LDBL_DIG__ 33
+// AARCH64-FREEBSD:#define __LDBL_EPSILON__ 1.92592994438723585305597794258492732e-34L
+// AARCH64-FREEBSD:#define __LDBL_HAS_DENORM__ 1
+// AARCH64-FREEBSD:#define __LDBL_HAS_INFINITY__ 1
+// AARCH64-FREEBSD:#define __LDBL_HAS_QUIET_NAN__ 1
+// AARCH64-FREEBSD:#define __LDBL_MANT_DIG__ 113
+// AARCH64-FREEBSD:#define __LDBL_MAX_10_EXP__ 4932
+// AARCH64-FREEBSD:#define __LDBL_MAX_EXP__ 16384
+// AARCH64-FREEBSD:#define __LDBL_MAX__ 1.18973149535723176508575932662800702e+4932L
+// AARCH64-FREEBSD:#define __LDBL_MIN_10_EXP__ (-4931)
+// AARCH64-FREEBSD:#define __LDBL_MIN_EXP__ (-16381)
+// AARCH64-FREEBSD:#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L
+// AARCH64-FREEBSD:#define __LITTLE_ENDIAN__ 1
+// AARCH64-FREEBSD:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// AARCH64-FREEBSD:#define __LONG_MAX__ 9223372036854775807L
+// AARCH64-FREEBSD:#define __LP64__ 1
+// AARCH64-FREEBSD:#define __POINTER_WIDTH__ 64
+// AARCH64-FREEBSD:#define __PTRDIFF_TYPE__ long int
+// AARCH64-FREEBSD:#define __PTRDIFF_WIDTH__ 64
+// AARCH64-FREEBSD:#define __SCHAR_MAX__ 127
+// AARCH64-FREEBSD:#define __SHRT_MAX__ 32767
+// AARCH64-FREEBSD:#define __SIG_ATOMIC_MAX__ 2147483647
+// AARCH64-FREEBSD:#define __SIG_ATOMIC_WIDTH__ 32
+// AARCH64-FREEBSD:#define __SIZEOF_DOUBLE__ 8
+// AARCH64-FREEBSD:#define __SIZEOF_FLOAT__ 4
+// AARCH64-FREEBSD:#define __SIZEOF_INT128__ 16
+// AARCH64-FREEBSD:#define __SIZEOF_INT__ 4
+// AARCH64-FREEBSD:#define __SIZEOF_LONG_DOUBLE__ 16
+// AARCH64-FREEBSD:#define __SIZEOF_LONG_LONG__ 8
+// AARCH64-FREEBSD:#define __SIZEOF_LONG__ 8
+// AARCH64-FREEBSD:#define __SIZEOF_POINTER__ 8
+// AARCH64-FREEBSD:#define __SIZEOF_PTRDIFF_T__ 8
+// AARCH64-FREEBSD:#define __SIZEOF_SHORT__ 2
+// AARCH64-FREEBSD:#define __SIZEOF_SIZE_T__ 8
+// AARCH64-FREEBSD:#define __SIZEOF_WCHAR_T__ 4
+// AARCH64-FREEBSD:#define __SIZEOF_WINT_T__ 4
+// AARCH64-FREEBSD:#define __SIZE_MAX__ 18446744073709551615UL
+// AARCH64-FREEBSD:#define __SIZE_TYPE__ long unsigned int
+// AARCH64-FREEBSD:#define __SIZE_WIDTH__ 64
+// AARCH64-FREEBSD:#define __UINT16_C_SUFFIX__ {{$}}
+// AARCH64-FREEBSD:#define __UINT16_MAX__ 65535
+// AARCH64-FREEBSD:#define __UINT16_TYPE__ unsigned short
+// AARCH64-FREEBSD:#define __UINT32_C_SUFFIX__ U
+// AARCH64-FREEBSD:#define __UINT32_MAX__ 4294967295U
+// AARCH64-FREEBSD:#define __UINT32_TYPE__ unsigned int
+// AARCH64-FREEBSD:#define __UINT64_C_SUFFIX__ UL
+// AARCH64-FREEBSD:#define __UINT64_MAX__ 18446744073709551615UL
+// AARCH64-FREEBSD:#define __UINT64_TYPE__ long unsigned int
+// AARCH64-FREEBSD:#define __UINT8_C_SUFFIX__ {{$}}
+// AARCH64-FREEBSD:#define __UINT8_MAX__ 255
+// AARCH64-FREEBSD:#define __UINT8_TYPE__ unsigned char
+// AARCH64-FREEBSD:#define __UINTMAX_C_SUFFIX__ UL
+// AARCH64-FREEBSD:#define __UINTMAX_MAX__ 18446744073709551615UL
+// AARCH64-FREEBSD:#define __UINTMAX_TYPE__ long unsigned int
+// AARCH64-FREEBSD:#define __UINTMAX_WIDTH__ 64
+// AARCH64-FREEBSD:#define __UINTPTR_MAX__ 18446744073709551615UL
+// AARCH64-FREEBSD:#define __UINTPTR_TYPE__ long unsigned int
+// AARCH64-FREEBSD:#define __UINTPTR_WIDTH__ 64
+// AARCH64-FREEBSD:#define __UINT_FAST16_MAX__ 65535
+// AARCH64-FREEBSD:#define __UINT_FAST16_TYPE__ unsigned short
+// AARCH64-FREEBSD:#define __UINT_FAST32_MAX__ 4294967295U
+// AARCH64-FREEBSD:#define __UINT_FAST32_TYPE__ unsigned int
+// AARCH64-FREEBSD:#define __UINT_FAST64_MAX__ 18446744073709551615UL
+// AARCH64-FREEBSD:#define __UINT_FAST64_TYPE__ long unsigned int
+// AARCH64-FREEBSD:#define __UINT_FAST8_MAX__ 255
+// AARCH64-FREEBSD:#define __UINT_FAST8_TYPE__ unsigned char
+// AARCH64-FREEBSD:#define __UINT_LEAST16_MAX__ 65535
+// AARCH64-FREEBSD:#define __UINT_LEAST16_TYPE__ unsigned short
+// AARCH64-FREEBSD:#define __UINT_LEAST32_MAX__ 4294967295U
+// AARCH64-FREEBSD:#define __UINT_LEAST32_TYPE__ unsigned int
+// AARCH64-FREEBSD:#define __UINT_LEAST64_MAX__ 18446744073709551615UL
+// AARCH64-FREEBSD:#define __UINT_LEAST64_TYPE__ long unsigned int
+// AARCH64-FREEBSD:#define __UINT_LEAST8_MAX__ 255
+// AARCH64-FREEBSD:#define __UINT_LEAST8_TYPE__ unsigned char
+// AARCH64-FREEBSD:#define __USER_LABEL_PREFIX__
+// AARCH64-FREEBSD:#define __WCHAR_MAX__ 4294967295U
+// AARCH64-FREEBSD:#define __WCHAR_TYPE__ unsigned int
+// AARCH64-FREEBSD:#define __WCHAR_UNSIGNED__ 1
+// AARCH64-FREEBSD:#define __WCHAR_WIDTH__ 32
+// AARCH64-FREEBSD:#define __WINT_TYPE__ int
+// AARCH64-FREEBSD:#define __WINT_WIDTH__ 32
+// AARCH64-FREEBSD:#define __aarch64__ 1
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-none-none < /dev/null | FileCheck -check-prefix ARM %s
//
@@ -1765,12 +1957,13 @@
// ARM-NETBSD:#define __arm 1
// ARM-NETBSD:#define __arm__ 1
-// RUN: %clang -target arm -arch armv7s -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
-// RUN: %clang -target arm -arch armv6m -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
-// RUN: %clang -target arm -arch armv7m -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
-// RUN: %clang -target arm -arch armv7em -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
+// RUN: %clang -target arm-apple-darwin-eabi -arch armv7s -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
+// RUN: %clang -target arm-apple-darwin-eabi -arch armv6m -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-EABI %s
+// RUN: %clang -target arm-apple-darwin-eabi -arch armv7m -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-EABI %s
+// RUN: %clang -target arm-apple-darwin-eabi -arch armv7em -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-EABI %s
// RUN: %clang -target thumbv7-apple-darwin-eabi -arch armv7 -x c -E -dM %s -o - | FileCheck --check-prefix=ARM-DARWIN-NO-EABI %s
// ARM-DARWIN-NO-EABI-NOT: #define __ARM_EABI__ 1
+// ARM-DARWIN-EABI: #define __ARM_EABI__ 1
// Check that -mhwdiv works properly for targets which don't have the hwdiv feature enabled by default.
@@ -2546,7 +2739,7 @@
// MIPS32BE:#define __SIZE_TYPE__ unsigned int
// MIPS32BE:#define __SIZE_WIDTH__ 32
// MIPS32BE:#define __STDC_HOSTED__ 0
-// MIPS32BE:#define __STDC_VERSION__ 199901L
+// MIPS32BE:#define __STDC_VERSION__ 201112L
// MIPS32BE:#define __STDC__ 1
// MIPS32BE:#define __UINT16_C_SUFFIX__ {{$}}
// MIPS32BE:#define __UINT16_MAX__ 65535
@@ -2945,6 +3138,7 @@
// MIPS64BE:#define __SIG_ATOMIC_WIDTH__ 32
// MIPS64BE:#define __SIZEOF_DOUBLE__ 8
// MIPS64BE:#define __SIZEOF_FLOAT__ 4
+// MIPS64BE-NOT:#define __SIZEOF_INT128__ 16
// MIPS64BE:#define __SIZEOF_INT__ 4
// MIPS64BE:#define __SIZEOF_LONG_DOUBLE__ 16
// MIPS64BE:#define __SIZEOF_LONG_LONG__ 8
@@ -3152,6 +3346,7 @@
// MIPS64EL:#define __SIG_ATOMIC_WIDTH__ 32
// MIPS64EL:#define __SIZEOF_DOUBLE__ 8
// MIPS64EL:#define __SIZEOF_FLOAT__ 4
+// MIPS64EL-NOT:#define __SIZEOF_INT128__ 16
// MIPS64EL:#define __SIZEOF_INT__ 4
// MIPS64EL:#define __SIZEOF_LONG_DOUBLE__ 16
// MIPS64EL:#define __SIZEOF_LONG_LONG__ 8
@@ -4917,6 +5112,15 @@
// PPC64-LINUX:#define __powerpc__ 1
// PPC64-LINUX:#define __ppc64__ 1
// PPC64-LINUX:#define __ppc__ 1
+
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-linux-gnu < /dev/null | FileCheck -check-prefix PPC64-ELFv1 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-linux-gnu -target-abi elfv1 < /dev/null | FileCheck -check-prefix PPC64-ELFv1 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-linux-gnu -target-abi elfv2 < /dev/null | FileCheck -check-prefix PPC64-ELFv2 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64le-unknown-linux-gnu < /dev/null | FileCheck -check-prefix PPC64-ELFv2 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64le-unknown-linux-gnu -target-abi elfv1 < /dev/null | FileCheck -check-prefix PPC64-ELFv1 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64le-unknown-linux-gnu -target-abi elfv2 < /dev/null | FileCheck -check-prefix PPC64-ELFv2 %s
+// PPC64-ELFv1:#define _CALL_ELF 1
+// PPC64-ELFv2:#define _CALL_ELF 2
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc-none-none -fno-signed-char < /dev/null | FileCheck -check-prefix PPC %s
//
@@ -5449,7 +5653,7 @@
// PPC-DARWIN:#define __SIZE_TYPE__ long unsigned int
// PPC-DARWIN:#define __SIZE_WIDTH__ 32
// PPC-DARWIN:#define __STDC_HOSTED__ 0
-// PPC-DARWIN:#define __STDC_VERSION__ 199901L
+// PPC-DARWIN:#define __STDC_VERSION__ 201112L
// PPC-DARWIN:#define __STDC__ 1
// PPC-DARWIN:#define __UINT16_C_SUFFIX__ {{$}}
// PPC-DARWIN:#define __UINT16_MAX__ 65535
@@ -6222,6 +6426,13 @@
// X86_64:#define __x86_64 1
// X86_64:#define __x86_64__ 1
//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=x86_64h-none-none < /dev/null | FileCheck -check-prefix X86_64H %s
+//
+// X86_64H:#define __x86_64 1
+// X86_64H:#define __x86_64__ 1
+// X86_64H:#define __x86_64h 1
+// X86_64H:#define __x86_64h__ 1
+
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=x86_64-none-none-gnux32 < /dev/null | FileCheck -check-prefix X32 %s
//
// X32:#define _ILP32 1
diff --git a/test/Preprocessor/iwithprefix.c b/test/Preprocessor/iwithprefix.c
index 59935ac1b8b5..a65a8043aa71 100644
--- a/test/Preprocessor/iwithprefix.c
+++ b/test/Preprocessor/iwithprefix.c
@@ -9,7 +9,7 @@
// CHECK: #include <...> search starts here:
// CHECK: {{.*}}.tmps/first
-// CHECK: {{/|\\}}lib{{/|\\}}clang{{/|\\}}{{[.0-9]+}}{{/|\\}}include
+// CHECK: {{/|\\}}lib{{(32|64)?}}{{/|\\}}clang{{/|\\}}{{[.0-9]+}}{{/|\\}}include
// CHECK: {{.*}}.tmps/second
// CHECK-NOT: {{.*}}.tmps
diff --git a/test/Preprocessor/line-directive.c b/test/Preprocessor/line-directive.c
index 0dd658f7f1a1..2ebe87e4680d 100644
--- a/test/Preprocessor/line-directive.c
+++ b/test/Preprocessor/line-directive.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify -pedantic %s
// RUN: not %clang_cc1 -E %s 2>&1 | grep 'blonk.c:92:2: error: ABC'
// RUN: not %clang_cc1 -E %s 2>&1 | grep 'blonk.c:93:2: error: DEF'
diff --git a/test/Preprocessor/macro-reserved-cxx11.cpp b/test/Preprocessor/macro-reserved-cxx11.cpp
new file mode 100644
index 000000000000..a740ff612954
--- /dev/null
+++ b/test/Preprocessor/macro-reserved-cxx11.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -pedantic -verify %s
+
+#define for 0 // expected-warning {{keyword is hidden by macro definition}}
+#define final 1 // expected-warning {{keyword is hidden by macro definition}}
+#define override // expected-warning {{keyword is hidden by macro definition}}
+
+int x;
diff --git a/test/Preprocessor/macro-reserved-ms.c b/test/Preprocessor/macro-reserved-ms.c
new file mode 100644
index 000000000000..c533ee36bde4
--- /dev/null
+++ b/test/Preprocessor/macro-reserved-ms.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -fms-extensions -verify %s
+// expected-no-diagnostics
+
+#define inline _inline
+#undef inline
+
+int x;
diff --git a/test/Preprocessor/macro-reserved.c b/test/Preprocessor/macro-reserved.c
new file mode 100644
index 000000000000..84b9262cb82e
--- /dev/null
+++ b/test/Preprocessor/macro-reserved.c
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+
+#define for 0 // expected-warning {{keyword is hidden by macro definition}}
+#define final 1
+#define __HAVE_X 0
+#define __cplusplus
+#define _HAVE_X 0
+#define X__Y
+
+#undef for
+#undef final
+#undef __HAVE_X
+#undef __cplusplus
+#undef _HAVE_X
+#undef X__Y
+
+// whitelisted definitions
+#define while while
+#define const
+#define static
+#define extern
+#define inline
+
+#undef while
+#undef const
+#undef static
+#undef extern
+#undef inline
+
+#define inline __inline
+#undef inline
+#define inline __inline__
+#undef inline
+
+#define inline inline__ // expected-warning {{keyword is hidden by macro definition}}
+#undef inline
+#define extern __inline // expected-warning {{keyword is hidden by macro definition}}
+#undef extern
+#define extern __extern // expected-warning {{keyword is hidden by macro definition}}
+#undef extern
+#define extern __extern__ // expected-warning {{keyword is hidden by macro definition}}
+#undef extern
+
+#define inline _inline // expected-warning {{keyword is hidden by macro definition}}
+#undef inline
+#define volatile // expected-warning {{keyword is hidden by macro definition}}
+#undef volatile
+
+#pragma clang diagnostic warning "-Wreserved-id-macro"
+
+#define switch if // expected-warning {{keyword is hidden by macro definition}}
+#define final 1
+#define __clusplus // expected-warning {{macro name is a reserved identifier}}
+#define __HAVE_X 0 // expected-warning {{macro name is a reserved identifier}}
+#define _HAVE_X 0 // expected-warning {{macro name is a reserved identifier}}
+#define X__Y
+
+#undef switch
+#undef final
+#undef __cplusplus // expected-warning {{macro name is a reserved identifier}}
+#undef _HAVE_X // expected-warning {{macro name is a reserved identifier}}
+#undef X__Y
+
+int x;
diff --git a/test/Preprocessor/macro-reserved.cpp b/test/Preprocessor/macro-reserved.cpp
new file mode 100644
index 000000000000..ba1594a0af49
--- /dev/null
+++ b/test/Preprocessor/macro-reserved.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
+
+#define for 0 // expected-warning {{keyword is hidden by macro definition}}
+#define final 1
+#define __HAVE_X 0
+#define _HAVE_X 0
+#define X__Y
+
+#undef for
+#undef final
+#undef __HAVE_X
+#undef _HAVE_X
+#undef X__Y
+
+#undef __cplusplus
+#define __cplusplus
+
+// whitelisted definitions
+#define while while
+#define const
+#define static
+#define extern
+#define inline
+
+#undef while
+#undef const
+#undef static
+#undef extern
+#undef inline
+
+#define inline __inline
+#undef inline
+#define inline __inline__
+#undef inline
+
+#define inline inline__ // expected-warning {{keyword is hidden by macro definition}}
+#undef inline
+#define extern __inline // expected-warning {{keyword is hidden by macro definition}}
+#undef extern
+#define extern __extern // expected-warning {{keyword is hidden by macro definition}}
+#undef extern
+#define extern __extern__ // expected-warning {{keyword is hidden by macro definition}}
+#undef extern
+
+#define inline _inline // expected-warning {{keyword is hidden by macro definition}}
+#undef inline
+#define volatile // expected-warning {{keyword is hidden by macro definition}}
+#undef volatile
+
+
+#pragma clang diagnostic warning "-Wreserved-id-macro"
+
+#define switch if // expected-warning {{keyword is hidden by macro definition}}
+#define final 1
+#define __HAVE_X 0 // expected-warning {{macro name is a reserved identifier}}
+#define _HAVE_X 0 // expected-warning {{macro name is a reserved identifier}}
+#define X__Y // expected-warning {{macro name is a reserved identifier}}
+
+#undef __cplusplus // expected-warning {{macro name is a reserved identifier}}
+#undef _HAVE_X // expected-warning {{macro name is a reserved identifier}}
+#undef X__Y // expected-warning {{macro name is a reserved identifier}}
+
+int x;
diff --git a/test/Preprocessor/macro_arg_directive.c b/test/Preprocessor/macro_arg_directive.c
index 5bc2236f0c45..21d1b20acf66 100644
--- a/test/Preprocessor/macro_arg_directive.c
+++ b/test/Preprocessor/macro_arg_directive.c
@@ -7,6 +7,11 @@ a(n =
a);
_Static_assert(n == 5, "");
+#define M(A)
+M(
+#pragma pack(pop) // expected-error {{embedding a #pragma directive within macro arguments is not supported}}
+)
+
// header1.h
void fail(const char *);
#define MUNCH(...) \
diff --git a/test/Preprocessor/macro_paste_bad.c b/test/Preprocessor/macro_paste_bad.c
index ec10006ae3d7..23777240cbf7 100644
--- a/test/Preprocessor/macro_paste_bad.c
+++ b/test/Preprocessor/macro_paste_bad.c
@@ -34,3 +34,11 @@ int VA; // expected-warning {{__VA_ARGS__ can only appear in the expansion of
#define LOG_ON_ERROR(x) x ## #y; // expected-error {{'#' is not followed by a macro parameter}}
LOG_ON_ERROR(0);
+
+#define PR21379A(x) printf ##x // expected-note {{macro 'PR21379A' defined here}}
+PR21379A(0 {, }) // expected-error {{too many arguments provided to function-like macro invocation}}
+ // expected-note@-1 {{parentheses are required around macro argument containing braced initializer list}}
+
+#define PR21379B(x) printf #x // expected-note {{macro 'PR21379B' defined here}}
+PR21379B(0 {, }) // expected-error {{too many arguments provided to function-like macro invocation}}
+ // expected-note@-1 {{parentheses are required around macro argument containing braced initializer list}}
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index cba458e7267f..5bdbdbc622b0 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -562,6 +562,70 @@
// CHECK_CORE_AVX2_M64: #define __x86_64 1
// CHECK_CORE_AVX2_M64: #define __x86_64__ 1
//
+// RUN: %clang -march=broadwell -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_BROADWELL_M32
+// CHECK_BROADWELL_M32: #define __ADX__ 1
+// CHECK_BROADWELL_M32: #define __AES__ 1
+// CHECK_BROADWELL_M32: #define __AVX2__ 1
+// CHECK_BROADWELL_M32: #define __AVX__ 1
+// CHECK_BROADWELL_M32: #define __BMI2__ 1
+// CHECK_BROADWELL_M32: #define __BMI__ 1
+// CHECK_BROADWELL_M32: #define __F16C__ 1
+// CHECK_BROADWELL_M32: #define __FMA__ 1
+// CHECK_BROADWELL_M32: #define __LZCNT__ 1
+// CHECK_BROADWELL_M32: #define __MMX__ 1
+// CHECK_BROADWELL_M32: #define __PCLMUL__ 1
+// CHECK_BROADWELL_M32: #define __POPCNT__ 1
+// CHECK_BROADWELL_M32: #define __RDRND__ 1
+// CHECK_BROADWELL_M32: #define __RDSEED__ 1
+// CHECK_BROADWELL_M32: #define __RTM__ 1
+// CHECK_BROADWELL_M32: #define __SSE2__ 1
+// CHECK_BROADWELL_M32: #define __SSE3__ 1
+// CHECK_BROADWELL_M32: #define __SSE4_1__ 1
+// CHECK_BROADWELL_M32: #define __SSE4_2__ 1
+// CHECK_BROADWELL_M32: #define __SSE__ 1
+// CHECK_BROADWELL_M32: #define __SSSE3__ 1
+// CHECK_BROADWELL_M32: #define __corei7 1
+// CHECK_BROADWELL_M32: #define __corei7__ 1
+// CHECK_BROADWELL_M32: #define __i386 1
+// CHECK_BROADWELL_M32: #define __i386__ 1
+// CHECK_BROADWELL_M32: #define __tune_corei7__ 1
+// CHECK_BROADWELL_M32: #define i386 1
+// RUN: %clang -march=broadwell -m64 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_BROADWELL_M64
+// CHECK_BROADWELL_M64: #define __ADX__ 1
+// CHECK_BROADWELL_M64: #define __AES__ 1
+// CHECK_BROADWELL_M64: #define __AVX2__ 1
+// CHECK_BROADWELL_M64: #define __AVX__ 1
+// CHECK_BROADWELL_M64: #define __BMI2__ 1
+// CHECK_BROADWELL_M64: #define __BMI__ 1
+// CHECK_BROADWELL_M64: #define __F16C__ 1
+// CHECK_BROADWELL_M64: #define __FMA__ 1
+// CHECK_BROADWELL_M64: #define __LZCNT__ 1
+// CHECK_BROADWELL_M64: #define __MMX__ 1
+// CHECK_BROADWELL_M64: #define __PCLMUL__ 1
+// CHECK_BROADWELL_M64: #define __POPCNT__ 1
+// CHECK_BROADWELL_M64: #define __RDRND__ 1
+// CHECK_BROADWELL_M64: #define __RDSEED__ 1
+// CHECK_BROADWELL_M64: #define __RTM__ 1
+// CHECK_BROADWELL_M64: #define __SSE2_MATH__ 1
+// CHECK_BROADWELL_M64: #define __SSE2__ 1
+// CHECK_BROADWELL_M64: #define __SSE3__ 1
+// CHECK_BROADWELL_M64: #define __SSE4_1__ 1
+// CHECK_BROADWELL_M64: #define __SSE4_2__ 1
+// CHECK_BROADWELL_M64: #define __SSE_MATH__ 1
+// CHECK_BROADWELL_M64: #define __SSE__ 1
+// CHECK_BROADWELL_M64: #define __SSSE3__ 1
+// CHECK_BROADWELL_M64: #define __amd64 1
+// CHECK_BROADWELL_M64: #define __amd64__ 1
+// CHECK_BROADWELL_M64: #define __corei7 1
+// CHECK_BROADWELL_M64: #define __corei7__ 1
+// CHECK_BROADWELL_M64: #define __tune_corei7__ 1
+// CHECK_BROADWELL_M64: #define __x86_64 1
+// CHECK_BROADWELL_M64: #define __x86_64__ 1
+//
// RUN: %clang -march=knl -m32 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_KNL_M32
@@ -594,6 +658,7 @@
// CHECK_KNL_M32: #define __knl__ 1
// CHECK_KNL_M32: #define __tune_knl__ 1
// CHECK_KNL_M32: #define i386 1
+
// RUN: %clang -march=knl -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_KNL_M64
@@ -630,6 +695,77 @@
// CHECK_KNL_M64: #define __x86_64 1
// CHECK_KNL_M64: #define __x86_64__ 1
//
+// RUN: %clang -march=skx -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_SKX_M32
+// CHECK_SKX_M32: #define __AES__ 1
+// CHECK_SKX_M32: #define __AVX2__ 1
+// CHECK_SKX_M32: #define __AVX512BW__ 1
+// CHECK_SKX_M32: #define __AVX512CD__ 1
+// CHECK_SKX_M32: #define __AVX512DQ__ 1
+// CHECK_SKX_M32: #define __AVX512F__ 1
+// CHECK_SKX_M32: #define __AVX512VL__ 1
+// CHECK_SKX_M32: #define __AVX__ 1
+// CHECK_SKX_M32: #define __BMI2__ 1
+// CHECK_SKX_M32: #define __BMI__ 1
+// CHECK_SKX_M32: #define __F16C__ 1
+// CHECK_SKX_M32: #define __FMA__ 1
+// CHECK_SKX_M32: #define __LZCNT__ 1
+// CHECK_SKX_M32: #define __MMX__ 1
+// CHECK_SKX_M32: #define __PCLMUL__ 1
+// CHECK_SKX_M32: #define __POPCNT__ 1
+// CHECK_SKX_M32: #define __RDRND__ 1
+// CHECK_SKX_M32: #define __RTM__ 1
+// CHECK_SKX_M32: #define __SSE2__ 1
+// CHECK_SKX_M32: #define __SSE3__ 1
+// CHECK_SKX_M32: #define __SSE4_1__ 1
+// CHECK_SKX_M32: #define __SSE4_2__ 1
+// CHECK_SKX_M32: #define __SSE__ 1
+// CHECK_SKX_M32: #define __SSSE3__ 1
+// CHECK_SKX_M32: #define __i386 1
+// CHECK_SKX_M32: #define __i386__ 1
+// CHECK_SKX_M32: #define __skx 1
+// CHECK_SKX_M32: #define __skx__ 1
+// CHECK_SKX_M32: #define __tune_skx__ 1
+// CHECK_SKX_M32: #define i386 1
+
+// RUN: %clang -march=skx -m64 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_SKX_M64
+// CHECK_SKX_M64: #define __AES__ 1
+// CHECK_SKX_M64: #define __AVX2__ 1
+// CHECK_SKX_M64: #define __AVX512BW__ 1
+// CHECK_SKX_M64: #define __AVX512CD__ 1
+// CHECK_SKX_M64: #define __AVX512DQ__ 1
+// CHECK_SKX_M64: #define __AVX512F__ 1
+// CHECK_SKX_M64: #define __AVX512VL__ 1
+// CHECK_SKX_M64: #define __AVX__ 1
+// CHECK_SKX_M64: #define __BMI2__ 1
+// CHECK_SKX_M64: #define __BMI__ 1
+// CHECK_SKX_M64: #define __F16C__ 1
+// CHECK_SKX_M64: #define __FMA__ 1
+// CHECK_SKX_M64: #define __LZCNT__ 1
+// CHECK_SKX_M64: #define __MMX__ 1
+// CHECK_SKX_M64: #define __PCLMUL__ 1
+// CHECK_SKX_M64: #define __POPCNT__ 1
+// CHECK_SKX_M64: #define __RDRND__ 1
+// CHECK_SKX_M64: #define __RTM__ 1
+// CHECK_SKX_M64: #define __SSE2_MATH__ 1
+// CHECK_SKX_M64: #define __SSE2__ 1
+// CHECK_SKX_M64: #define __SSE3__ 1
+// CHECK_SKX_M64: #define __SSE4_1__ 1
+// CHECK_SKX_M64: #define __SSE4_2__ 1
+// CHECK_SKX_M64: #define __SSE_MATH__ 1
+// CHECK_SKX_M64: #define __SSE__ 1
+// CHECK_SKX_M64: #define __SSSE3__ 1
+// CHECK_SKX_M64: #define __amd64 1
+// CHECK_SKX_M64: #define __amd64__ 1
+// CHECK_SKX_M64: #define __skx 1
+// CHECK_SKX_M64: #define __skx__ 1
+// CHECK_SKX_M64: #define __tune_skx__ 1
+// CHECK_SKX_M64: #define __x86_64 1
+// CHECK_SKX_M64: #define __x86_64__ 1
+//
// RUN: %clang -march=atom -m32 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_ATOM_M32
@@ -1206,8 +1342,11 @@
// CHECK_BTVER2_M32-NOT: #define __3dNOW__ 1
// CHECK_BTVER2_M32: #define __AES__ 1
// CHECK_BTVER2_M32: #define __AVX__ 1
+// CHECK_BTVER2_M32: #define __BMI__ 1
+// CHECK_BTVER2_M32: #define __F16C__ 1
// CHECK_BTVER2_M32: #define __LZCNT__ 1
// CHECK_BTVER2_M32: #define __MMX__ 1
+// CHECK_BTVER2_M32: #define __PCLMUL__ 1
// CHECK_BTVER2_M32: #define __POPCNT__ 1
// CHECK_BTVER2_M32: #define __PRFCHW__ 1
// CHECK_BTVER2_M32: #define __SSE2_MATH__ 1
@@ -1229,8 +1368,11 @@
// CHECK_BTVER2_M64-NOT: #define __3dNOW__ 1
// CHECK_BTVER2_M64: #define __AES__ 1
// CHECK_BTVER2_M64: #define __AVX__ 1
+// CHECK_BTVER2_M64: #define __BMI__ 1
+// CHECK_BTVER2_M64: #define __F16C__ 1
// CHECK_BTVER2_M64: #define __LZCNT__ 1
// CHECK_BTVER2_M64: #define __MMX__ 1
+// CHECK_BTVER2_M64: #define __PCLMUL__ 1
// CHECK_BTVER2_M64: #define __POPCNT__ 1
// CHECK_BTVER2_M64: #define __PRFCHW__ 1
// CHECK_BTVER2_M64: #define __SSE2_MATH__ 1
@@ -1382,6 +1524,7 @@
// CHECK_BDVER3_M32: #define __F16C__ 1
// CHECK_BDVER3_M32: #define __FMA4__ 1
// CHECK_BDVER3_M32: #define __FMA__ 1
+// CHECK_BDVER3_M32: #define __FSGSBASE__ 1
// CHECK_BDVER3_M32: #define __LZCNT__ 1
// CHECK_BDVER3_M32: #define __MMX__ 1
// CHECK_BDVER3_M32: #define __PCLMUL__ 1
@@ -1414,6 +1557,7 @@
// CHECK_BDVER3_M64: #define __F16C__ 1
// CHECK_BDVER3_M64: #define __FMA4__ 1
// CHECK_BDVER3_M64: #define __FMA__ 1
+// CHECK_BDVER3_M64: #define __FSGSBASE__ 1
// CHECK_BDVER3_M64: #define __LZCNT__ 1
// CHECK_BDVER3_M64: #define __MMX__ 1
// CHECK_BDVER3_M64: #define __PCLMUL__ 1
@@ -1450,6 +1594,7 @@
// CHECK_BDVER4_M32: #define __F16C__ 1
// CHECK_BDVER4_M32: #define __FMA4__ 1
// CHECK_BDVER4_M32: #define __FMA__ 1
+// CHECK_BDVER4_M32: #define __FSGSBASE__ 1
// CHECK_BDVER4_M32: #define __LZCNT__ 1
// CHECK_BDVER4_M32: #define __MMX__ 1
// CHECK_BDVER4_M32: #define __PCLMUL__ 1
@@ -1484,6 +1629,7 @@
// CHECK_BDVER4_M64: #define __F16C__ 1
// CHECK_BDVER4_M64: #define __FMA4__ 1
// CHECK_BDVER4_M64: #define __FMA__ 1
+// CHECK_BDVER4_M64: #define __FSGSBASE__ 1
// CHECK_BDVER4_M64: #define __LZCNT__ 1
// CHECK_BDVER4_M64: #define __MMX__ 1
// CHECK_BDVER4_M64: #define __PCLMUL__ 1
@@ -1516,3 +1662,10 @@
// RUN: | FileCheck %s -check-prefix=CHECK_PPC_VSX_M64
//
// CHECK_PPC_VSX_M64: #define __VSX__
+//
+// RUN: %clang -mpower8-vector -E -dM %s -o - 2>&1 \
+// RUN: -target powerpc64-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_PPC_POWER8_VECTOR_M64
+//
+// CHECK_PPC_POWER8_VECTOR_M64: #define __POWER8_VECTOR__
+//
diff --git a/test/Preprocessor/predefined-exceptions.m b/test/Preprocessor/predefined-exceptions.m
index c13f429e3763..0791075dfc75 100644
--- a/test/Preprocessor/predefined-exceptions.m
+++ b/test/Preprocessor/predefined-exceptions.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -x objective-c -fobjc-exceptions -fexceptions -E -dM %s | FileCheck -check-prefix=CHECK-OBJC-NOCXX %s
// CHECK-OBJC-NOCXX: #define OBJC_ZEROCOST_EXCEPTIONS 1
-// CHECK-OBJC-NOCXX-NOT: #define __EXCEPTIONS 1
+// CHECK-OBJC-NOCXX: #define __EXCEPTIONS 1
// RUN: %clang_cc1 -x objective-c++ -fobjc-exceptions -fexceptions -fcxx-exceptions -E -dM %s | FileCheck -check-prefix=CHECK-OBJC-CXX %s
// CHECK-OBJC-CXX: #define OBJC_ZEROCOST_EXCEPTIONS 1
diff --git a/test/Preprocessor/predefined-macros.c b/test/Preprocessor/predefined-macros.c
index 1db9080ac34c..a32f4a158c9b 100644
--- a/test/Preprocessor/predefined-macros.c
+++ b/test/Preprocessor/predefined-macros.c
@@ -28,59 +28,59 @@
//
// RUN: %clang_cc1 %s -E -dM -triple i686-pc-win32 -fms-compatibility \
// RUN: -o - | FileCheck %s --check-prefix=CHECK-MS-STDINT
-// CHECK-MS-STDINT-NOT:#define __INT16_MAX__ 32767
-// CHECK-MS-STDINT-NOT:#define __INT32_MAX__ 2147483647
-// CHECK-MS-STDINT-NOT:#define __INT64_MAX__ 9223372036854775807LL
-// CHECK-MS-STDINT-NOT:#define __INT8_MAX__ 127
-// CHECK-MS-STDINT-NOT:#define __INTPTR_MAX__ 2147483647
-// CHECK-MS-STDINT-NOT:#define __INT_FAST16_MAX__ 32767
-// CHECK-MS-STDINT-NOT:#define __INT_FAST16_TYPE__ short
-// CHECK-MS-STDINT-NOT:#define __INT_FAST32_MAX__ 2147483647
-// CHECK-MS-STDINT-NOT:#define __INT_FAST32_TYPE__ int
-// CHECK-MS-STDINT-NOT:#define __INT_FAST64_MAX__ 9223372036854775807LL
-// CHECK-MS-STDINT-NOT:#define __INT_FAST64_TYPE__ long long int
-// CHECK-MS-STDINT-NOT:#define __INT_FAST8_MAX__ 127
-// CHECK-MS-STDINT-NOT:#define __INT_FAST8_TYPE__ char
-// CHECK-MS-STDINT-NOT:#define __INT_LEAST16_MAX__ 32767
-// CHECK-MS-STDINT-NOT:#define __INT_LEAST16_TYPE__ short
-// CHECK-MS-STDINT-NOT:#define __INT_LEAST32_MAX__ 2147483647
-// CHECK-MS-STDINT-NOT:#define __INT_LEAST32_TYPE__ int
-// CHECK-MS-STDINT-NOT:#define __INT_LEAST64_MAX__ 9223372036854775807LL
-// CHECK-MS-STDINT-NOT:#define __INT_LEAST64_TYPE__ long long int
-// CHECK-MS-STDINT-NOT:#define __INT_LEAST8_MAX__ 127
-// CHECK-MS-STDINT-NOT:#define __INT_LEAST8_TYPE__ char
+// CHECK-MS-STDINT:#define __INT16_MAX__ 32767
+// CHECK-MS-STDINT:#define __INT32_MAX__ 2147483647
+// CHECK-MS-STDINT:#define __INT64_MAX__ 9223372036854775807LL
+// CHECK-MS-STDINT:#define __INT8_MAX__ 127
+// CHECK-MS-STDINT:#define __INTPTR_MAX__ 2147483647
+// CHECK-MS-STDINT:#define __INT_FAST16_MAX__ 32767
+// CHECK-MS-STDINT:#define __INT_FAST16_TYPE__ short
+// CHECK-MS-STDINT:#define __INT_FAST32_MAX__ 2147483647
+// CHECK-MS-STDINT:#define __INT_FAST32_TYPE__ int
+// CHECK-MS-STDINT:#define __INT_FAST64_MAX__ 9223372036854775807LL
+// CHECK-MS-STDINT:#define __INT_FAST64_TYPE__ long long int
+// CHECK-MS-STDINT:#define __INT_FAST8_MAX__ 127
+// CHECK-MS-STDINT:#define __INT_FAST8_TYPE__ signed char
+// CHECK-MS-STDINT:#define __INT_LEAST16_MAX__ 32767
+// CHECK-MS-STDINT:#define __INT_LEAST16_TYPE__ short
+// CHECK-MS-STDINT:#define __INT_LEAST32_MAX__ 2147483647
+// CHECK-MS-STDINT:#define __INT_LEAST32_TYPE__ int
+// CHECK-MS-STDINT:#define __INT_LEAST64_MAX__ 9223372036854775807LL
+// CHECK-MS-STDINT:#define __INT_LEAST64_TYPE__ long long int
+// CHECK-MS-STDINT:#define __INT_LEAST8_MAX__ 127
+// CHECK-MS-STDINT:#define __INT_LEAST8_TYPE__ signed char
// CHECK-MS-STDINT-NOT:#define __UINT16_C_SUFFIX__ U
-// CHECK-MS-STDINT-NOT:#define __UINT16_MAX__ 65535U
-// CHECK-MS-STDINT-NOT:#define __UINT16_TYPE__ unsigned short
-// CHECK-MS-STDINT-NOT:#define __UINT32_C_SUFFIX__ U
-// CHECK-MS-STDINT-NOT:#define __UINT32_MAX__ 4294967295U
-// CHECK-MS-STDINT-NOT:#define __UINT32_TYPE__ unsigned int
-// CHECK-MS-STDINT-NOT:#define __UINT64_C_SUFFIX__ ULL
-// CHECK-MS-STDINT-NOT:#define __UINT64_MAX__ 18446744073709551615ULL
-// CHECK-MS-STDINT-NOT:#define __UINT64_TYPE__ long long unsigned int
+// CHECK-MS-STDINT:#define __UINT16_MAX__ 65535
+// CHECK-MS-STDINT:#define __UINT16_TYPE__ unsigned short
+// CHECK-MS-STDINT:#define __UINT32_C_SUFFIX__ U
+// CHECK-MS-STDINT:#define __UINT32_MAX__ 4294967295U
+// CHECK-MS-STDINT:#define __UINT32_TYPE__ unsigned int
+// CHECK-MS-STDINT:#define __UINT64_C_SUFFIX__ ULL
+// CHECK-MS-STDINT:#define __UINT64_MAX__ 18446744073709551615ULL
+// CHECK-MS-STDINT:#define __UINT64_TYPE__ long long unsigned int
// CHECK-MS-STDINT-NOT:#define __UINT8_C_SUFFIX__ U
-// CHECK-MS-STDINT-NOT:#define __UINT8_MAX__ 255U
-// CHECK-MS-STDINT-NOT:#define __UINT8_TYPE__ unsigned char
-// CHECK-MS-STDINT-NOT:#define __UINTMAX_MAX__ 18446744073709551615ULL
-// CHECK-MS-STDINT-NOT:#define __UINTPTR_MAX__ 4294967295U
-// CHECK-MS-STDINT-NOT:#define __UINTPTR_TYPE__ unsigned int
-// CHECK-MS-STDINT-NOT:#define __UINTPTR_WIDTH__ 32
-// CHECK-MS-STDINT-NOT:#define __UINT_FAST16_MAX__ 65535U
-// CHECK-MS-STDINT-NOT:#define __UINT_FAST16_TYPE__ unsigned short
-// CHECK-MS-STDINT-NOT:#define __UINT_FAST32_MAX__ 4294967295U
-// CHECK-MS-STDINT-NOT:#define __UINT_FAST32_TYPE__ unsigned int
-// CHECK-MS-STDINT-NOT:#define __UINT_FAST64_MAX__ 18446744073709551615ULL
-// CHECK-MS-STDINT-NOT:#define __UINT_FAST64_TYPE__ long long unsigned int
-// CHECK-MS-STDINT-NOT:#define __UINT_FAST8_MAX__ 255U
-// CHECK-MS-STDINT-NOT:#define __UINT_FAST8_TYPE__ unsigned char
-// CHECK-MS-STDINT-NOT:#define __UINT_LEAST16_MAX__ 65535U
-// CHECK-MS-STDINT-NOT:#define __UINT_LEAST16_TYPE__ unsigned short
-// CHECK-MS-STDINT-NOT:#define __UINT_LEAST32_MAX__ 4294967295U
-// CHECK-MS-STDINT-NOT:#define __UINT_LEAST32_TYPE__ unsigned int
-// CHECK-MS-STDINT-NOT:#define __UINT_LEAST64_MAX__ 18446744073709551615ULL
-// CHECK-MS-STDINT-NOT:#define __UINT_LEAST64_TYPE__ long long unsigned int
-// CHECK-MS-STDINT-NOT:#define __UINT_LEAST8_MAX__ 255U
-// CHECK-MS-STDINT-NOT:#define __UINT_LEAST8_TYPE__ unsigned char
+// CHECK-MS-STDINT:#define __UINT8_MAX__ 255
+// CHECK-MS-STDINT:#define __UINT8_TYPE__ unsigned char
+// CHECK-MS-STDINT:#define __UINTMAX_MAX__ 18446744073709551615ULL
+// CHECK-MS-STDINT:#define __UINTPTR_MAX__ 4294967295U
+// CHECK-MS-STDINT:#define __UINTPTR_TYPE__ unsigned int
+// CHECK-MS-STDINT:#define __UINTPTR_WIDTH__ 32
+// CHECK-MS-STDINT:#define __UINT_FAST16_MAX__ 65535
+// CHECK-MS-STDINT:#define __UINT_FAST16_TYPE__ unsigned short
+// CHECK-MS-STDINT:#define __UINT_FAST32_MAX__ 4294967295U
+// CHECK-MS-STDINT:#define __UINT_FAST32_TYPE__ unsigned int
+// CHECK-MS-STDINT:#define __UINT_FAST64_MAX__ 18446744073709551615ULL
+// CHECK-MS-STDINT:#define __UINT_FAST64_TYPE__ long long unsigned int
+// CHECK-MS-STDINT:#define __UINT_FAST8_MAX__ 255
+// CHECK-MS-STDINT:#define __UINT_FAST8_TYPE__ unsigned char
+// CHECK-MS-STDINT:#define __UINT_LEAST16_MAX__ 65535
+// CHECK-MS-STDINT:#define __UINT_LEAST16_TYPE__ unsigned short
+// CHECK-MS-STDINT:#define __UINT_LEAST32_MAX__ 4294967295U
+// CHECK-MS-STDINT:#define __UINT_LEAST32_TYPE__ unsigned int
+// CHECK-MS-STDINT:#define __UINT_LEAST64_MAX__ 18446744073709551615ULL
+// CHECK-MS-STDINT:#define __UINT_LEAST64_TYPE__ long long unsigned int
+// CHECK-MS-STDINT:#define __UINT_LEAST8_MAX__ 255
+// CHECK-MS-STDINT:#define __UINT_LEAST8_TYPE__ unsigned char
//
// RUN: %clang_cc1 %s -E -dM -ffast-math -o - \
// RUN: | FileCheck %s --check-prefix=CHECK-FAST-MATH
diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c
index 94d5b0b0b337..c7189f607cfd 100644
--- a/test/Preprocessor/stdint.c
+++ b/test/Preprocessor/stdint.c
@@ -634,6 +634,113 @@
// PPC64:INTMAX_C_(0) 0L
// PPC64:UINTMAX_C_(0) 0UL
//
+// RUN: %clang_cc1 -E -ffreestanding -triple=powerpc64-none-netbsd %s | FileCheck -check-prefix PPC64-NETBSD %s
+//
+// PPC64-NETBSD:typedef long long int int64_t;
+// PPC64-NETBSD:typedef long long unsigned int uint64_t;
+// PPC64-NETBSD:typedef int64_t int_least64_t;
+// PPC64-NETBSD:typedef uint64_t uint_least64_t;
+// PPC64-NETBSD:typedef int64_t int_fast64_t;
+// PPC64-NETBSD:typedef uint64_t uint_fast64_t;
+//
+// PPC64-NETBSD:typedef int int32_t;
+// PPC64-NETBSD:typedef unsigned int uint32_t;
+// PPC64-NETBSD:typedef int32_t int_least32_t;
+// PPC64-NETBSD:typedef uint32_t uint_least32_t;
+// PPC64-NETBSD:typedef int32_t int_fast32_t;
+// PPC64-NETBSD:typedef uint32_t uint_fast32_t;
+//
+// PPC64-NETBSD:typedef short int16_t;
+// PPC64-NETBSD:typedef unsigned short uint16_t;
+// PPC64-NETBSD:typedef int16_t int_least16_t;
+// PPC64-NETBSD:typedef uint16_t uint_least16_t;
+// PPC64-NETBSD:typedef int16_t int_fast16_t;
+// PPC64-NETBSD:typedef uint16_t uint_fast16_t;
+//
+// PPC64-NETBSD:typedef signed char int8_t;
+// PPC64-NETBSD:typedef unsigned char uint8_t;
+// PPC64-NETBSD:typedef int8_t int_least8_t;
+// PPC64-NETBSD:typedef uint8_t uint_least8_t;
+// PPC64-NETBSD:typedef int8_t int_fast8_t;
+// PPC64-NETBSD:typedef uint8_t uint_fast8_t;
+//
+// PPC64-NETBSD:typedef int64_t intptr_t;
+// PPC64-NETBSD:typedef uint64_t uintptr_t;
+//
+// PPC64-NETBSD:typedef long long int intmax_t;
+// PPC64-NETBSD:typedef long long unsigned int uintmax_t;
+//
+// PPC64-NETBSD:INT8_MAX_ 127
+// PPC64-NETBSD:INT8_MIN_ (-127 -1)
+// PPC64-NETBSD:UINT8_MAX_ 255
+// PPC64-NETBSD:INT_LEAST8_MIN_ (-127 -1)
+// PPC64-NETBSD:INT_LEAST8_MAX_ 127
+// PPC64-NETBSD:UINT_LEAST8_MAX_ 255
+// PPC64-NETBSD:INT_FAST8_MIN_ (-127 -1)
+// PPC64-NETBSD:INT_FAST8_MAX_ 127
+// PPC64-NETBSD:UINT_FAST8_MAX_ 255
+//
+// PPC64-NETBSD:INT16_MAX_ 32767
+// PPC64-NETBSD:INT16_MIN_ (-32767 -1)
+// PPC64-NETBSD:UINT16_MAX_ 65535
+// PPC64-NETBSD:INT_LEAST16_MIN_ (-32767 -1)
+// PPC64-NETBSD:INT_LEAST16_MAX_ 32767
+// PPC64-NETBSD:UINT_LEAST16_MAX_ 65535
+// PPC64-NETBSD:INT_FAST16_MIN_ (-32767 -1)
+// PPC64-NETBSD:INT_FAST16_MAX_ 32767
+// PPC64-NETBSD:UINT_FAST16_MAX_ 65535
+//
+// PPC64-NETBSD:INT32_MAX_ 2147483647
+// PPC64-NETBSD:INT32_MIN_ (-2147483647 -1)
+// PPC64-NETBSD:UINT32_MAX_ 4294967295U
+// PPC64-NETBSD:INT_LEAST32_MIN_ (-2147483647 -1)
+// PPC64-NETBSD:INT_LEAST32_MAX_ 2147483647
+// PPC64-NETBSD:UINT_LEAST32_MAX_ 4294967295U
+// PPC64-NETBSD:INT_FAST32_MIN_ (-2147483647 -1)
+// PPC64-NETBSD:INT_FAST32_MAX_ 2147483647
+// PPC64-NETBSD:UINT_FAST32_MAX_ 4294967295U
+//
+// PPC64-NETBSD:INT64_MAX_ 9223372036854775807LL
+// PPC64-NETBSD:INT64_MIN_ (-9223372036854775807LL -1)
+// PPC64-NETBSD:UINT64_MAX_ 18446744073709551615ULL
+// PPC64-NETBSD:INT_LEAST64_MIN_ (-9223372036854775807LL -1)
+// PPC64-NETBSD:INT_LEAST64_MAX_ 9223372036854775807LL
+// PPC64-NETBSD:UINT_LEAST64_MAX_ 18446744073709551615ULL
+// PPC64-NETBSD:INT_FAST64_MIN_ (-9223372036854775807LL -1)
+// PPC64-NETBSD:INT_FAST64_MAX_ 9223372036854775807LL
+// PPC64-NETBSD:UINT_FAST64_MAX_ 18446744073709551615ULL
+//
+// PPC64-NETBSD:INTPTR_MIN_ (-9223372036854775807LL -1)
+// PPC64-NETBSD:INTPTR_MAX_ 9223372036854775807LL
+// PPC64-NETBSD:UINTPTR_MAX_ 18446744073709551615ULL
+// PPC64-NETBSD:PTRDIFF_MIN_ (-9223372036854775807LL -1)
+// PPC64-NETBSD:PTRDIFF_MAX_ 9223372036854775807LL
+// PPC64-NETBSD:SIZE_MAX_ 18446744073709551615ULL
+//
+// PPC64-NETBSD:INTMAX_MIN_ (-9223372036854775807LL -1)
+// PPC64-NETBSD:INTMAX_MAX_ 9223372036854775807LL
+// PPC64-NETBSD:UINTMAX_MAX_ 18446744073709551615ULL
+//
+// PPC64-NETBSD:SIG_ATOMIC_MIN_ (-2147483647 -1)
+// PPC64-NETBSD:SIG_ATOMIC_MAX_ 2147483647
+// PPC64-NETBSD:WINT_MIN_ (-2147483647 -1)
+// PPC64-NETBSD:WINT_MAX_ 2147483647
+//
+// PPC64-NETBSD:WCHAR_MAX_ 2147483647
+// PPC64-NETBSD:WCHAR_MIN_ (-2147483647 -1)
+//
+// PPC64-NETBSD:INT8_C_(0) 0
+// PPC64-NETBSD:UINT8_C_(0) 0U
+// PPC64-NETBSD:INT16_C_(0) 0
+// PPC64-NETBSD:UINT16_C_(0) 0U
+// PPC64-NETBSD:INT32_C_(0) 0
+// PPC64-NETBSD:UINT32_C_(0) 0U
+// PPC64-NETBSD:INT64_C_(0) 0LL
+// PPC64-NETBSD:UINT64_C_(0) 0ULL
+//
+// PPC64-NETBSD:INTMAX_C_(0) 0LL
+// PPC64-NETBSD:UINTMAX_C_(0) 0ULL
+//
// RUN: %clang_cc1 -E -ffreestanding -triple=powerpc-none-none %s | FileCheck -check-prefix PPC %s
//
//
diff --git a/test/Preprocessor/x86_target_features.c b/test/Preprocessor/x86_target_features.c
index 7bc5cd8b2c1b..806eeec961d6 100644
--- a/test/Preprocessor/x86_target_features.c
+++ b/test/Preprocessor/x86_target_features.c
@@ -114,6 +114,51 @@
// AVX512PF: #define __SSE__ 1
// AVX512PF: #define __SSSE3__ 1
+// RUN: %clang -target i386-unknown-unknown -march=atom -mavx512dq -x c -E -dM -o - %s | FileCheck --check-prefix=AVX512DQ %s
+
+// AVX512DQ: #define __AVX2__ 1
+// AVX512DQ: #define __AVX512DQ__ 1
+// AVX512DQ: #define __AVX512F__ 1
+// AVX512DQ: #define __AVX__ 1
+// AVX512DQ: #define __SSE2_MATH__ 1
+// AVX512DQ: #define __SSE2__ 1
+// AVX512DQ: #define __SSE3__ 1
+// AVX512DQ: #define __SSE4_1__ 1
+// AVX512DQ: #define __SSE4_2__ 1
+// AVX512DQ: #define __SSE_MATH__ 1
+// AVX512DQ: #define __SSE__ 1
+// AVX512DQ: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mavx512bw -x c -E -dM -o - %s | FileCheck --check-prefix=AVX512BW %s
+
+// AVX512BW: #define __AVX2__ 1
+// AVX512BW: #define __AVX512BW__ 1
+// AVX512BW: #define __AVX512F__ 1
+// AVX512BW: #define __AVX__ 1
+// AVX512BW: #define __SSE2_MATH__ 1
+// AVX512BW: #define __SSE2__ 1
+// AVX512BW: #define __SSE3__ 1
+// AVX512BW: #define __SSE4_1__ 1
+// AVX512BW: #define __SSE4_2__ 1
+// AVX512BW: #define __SSE_MATH__ 1
+// AVX512BW: #define __SSE__ 1
+// AVX512BW: #define __SSSE3__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mavx512vl -x c -E -dM -o - %s | FileCheck --check-prefix=AVX512VL %s
+
+// AVX512VL: #define __AVX2__ 1
+// AVX512VL: #define __AVX512F__ 1
+// AVX512VL: #define __AVX512VL__ 1
+// AVX512VL: #define __AVX__ 1
+// AVX512VL: #define __SSE2_MATH__ 1
+// AVX512VL: #define __SSE2__ 1
+// AVX512VL: #define __SSE3__ 1
+// AVX512VL: #define __SSE4_1__ 1
+// AVX512VL: #define __SSE4_2__ 1
+// AVX512VL: #define __SSE_MATH__ 1
+// AVX512VL: #define __SSE__ 1
+// AVX512VL: #define __SSSE3__ 1
+
// RUN: %clang -target i386-unknown-unknown -march=atom -mavx512pf -mno-avx512f -x c -E -dM -o - %s | FileCheck --check-prefix=AVX512F2 %s
// AVX512F2: #define __AVX2__ 1
@@ -236,3 +281,11 @@
// NO3DNOWPRFCHW: #define __PRFCHW__ 1
+// RUN: %clang -target i386-unknown-unknown -march=atom -madx -x c -E -dM -o - %s | FileCheck --check-prefix=ADX %s
+
+// ADX: #define __ADX__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mrdseed -x c -E -dM -o - %s | FileCheck --check-prefix=RDSEED %s
+
+// RDSEED: #define __RDSEED__ 1
+
diff --git a/test/Profile/Inputs/c-general.profdata.v1 b/test/Profile/Inputs/c-general.profdata.v1
new file mode 100644
index 000000000000..e7dedcbf97f7
--- /dev/null
+++ b/test/Profile/Inputs/c-general.profdata.v1
Binary files differ
diff --git a/test/Profile/c-captured.c b/test/Profile/c-captured.c
index ef7fb318508d..8a9e069ec535 100644
--- a/test/Profile/c-captured.c
+++ b/test/Profile/c-captured.c
@@ -4,8 +4,8 @@
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-captured.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE -check-prefix=PGOALL %s
// PGOGEN: @[[DCC:__llvm_profile_counters_debug_captured]] = hidden global [3 x i64] zeroinitializer
-// PGOGEN: @[[CSC:__llvm_profile_counters___captured_stmt]] = internal global [2 x i64] zeroinitializer
-// PGOGEN: @[[C1C:__llvm_profile_counters___captured_stmt1]] = internal global [3 x i64] zeroinitializer
+// PGOGEN: @[[CSC:"__llvm_profile_counters_c-captured.c:__captured_stmt"]] = internal global [2 x i64] zeroinitializer
+// PGOGEN: @[[C1C:"__llvm_profile_counters_c-captured.c:__captured_stmt1"]] = internal global [3 x i64] zeroinitializer
// PGOALL-LABEL: define void @debug_captured()
// PGOGEN: store {{.*}} @[[DCC]], i64 0, i64 0
@@ -47,11 +47,11 @@ void debug_captured() {
if (x) {} // This is DC2. Checked above.
}
-// PGOUSE-DAG: ![[DC1]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
-// PGOUSE-DAG: ![[DC2]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
-// PGOUSE-DAG: ![[CS1]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
-// PGOUSE-DAG: ![[C11]] = metadata !{metadata !"branch_weights", i32 11, i32 2}
-// PGOUSE-DAG: ![[C12]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[DC1]] = !{!"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[DC2]] = !{!"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[CS1]] = !{!"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[C11]] = !{!"branch_weights", i32 11, i32 2}
+// PGOUSE-DAG: ![[C12]] = !{!"branch_weights", i32 2, i32 1}
int main(int argc, const char *argv[]) {
debug_captured();
diff --git a/test/Profile/c-counter-overflows.c b/test/Profile/c-counter-overflows.c
index f6f8f73fd949..18a3d33d3ab9 100644
--- a/test/Profile/c-counter-overflows.c
+++ b/test/Profile/c-counter-overflows.c
@@ -44,6 +44,6 @@ int main(int argc, const char *argv[]) {
return 0;
}
-// CHECK-DAG: ![[FOR]] = metadata !{metadata !"branch_weights", i32 -252645135, i32 1}
-// CHECK-DAG: ![[IF]] = metadata !{metadata !"branch_weights", i32 -268435456, i32 268435456}
-// CHECK-DAG: ![[SWITCH]] = metadata !{metadata !"branch_weights", i32 715827883, i32 -715827883, i32 -715827883, i32 -715827883}
+// CHECK-DAG: ![[FOR]] = !{!"branch_weights", i32 -252645135, i32 1}
+// CHECK-DAG: ![[IF]] = !{!"branch_weights", i32 -268435456, i32 268435456}
+// CHECK-DAG: ![[SWITCH]] = !{!"branch_weights", i32 715827883, i32 -715827883, i32 -715827883, i32 -715827883}
diff --git a/test/Profile/c-general.c b/test/Profile/c-general.c
index 442fdd336c7c..981fd983582c 100644
--- a/test/Profile/c-general.c
+++ b/test/Profile/c-general.c
@@ -5,6 +5,9 @@
// RUN: llvm-profdata merge %S/Inputs/c-general.proftext -o %t.profdata
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE %s
+// Also check compatibility with older profiles.
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instr-use=%S/Inputs/c-general.profdata.v1 | FileCheck -check-prefix=PGOUSE %s
+
// PGOGEN: @[[SLC:__llvm_profile_counters_simple_loops]] = hidden global [4 x i64] zeroinitializer
// PGOGEN: @[[IFC:__llvm_profile_counters_conditionals]] = hidden global [11 x i64] zeroinitializer
// PGOGEN: @[[EEC:__llvm_profile_counters_early_exits]] = hidden global [9 x i64] zeroinitializer
@@ -15,7 +18,7 @@
// PGOGEN: @[[BLC:__llvm_profile_counters_boolop_loops]] = hidden global [9 x i64] zeroinitializer
// PGOGEN: @[[COC:__llvm_profile_counters_conditional_operator]] = hidden global [3 x i64] zeroinitializer
// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = hidden global [1 x i64] zeroinitializer
-// PGOGEN: @[[STC:__llvm_profile_counters_static_func]] = internal global [2 x i64] zeroinitializer
+// PGOGEN: @[[STC:"__llvm_profile_counters_c-general.c:static_func"]] = internal global [2 x i64] zeroinitializer
// PGOGEN-LABEL: @simple_loops()
// PGOUSE-LABEL: @simple_loops()
@@ -456,77 +459,77 @@ static void static_func() {
}
}
-// PGOUSE-DAG: ![[SL1]] = metadata !{metadata !"branch_weights", i32 101, i32 2}
-// PGOUSE-DAG: ![[SL2]] = metadata !{metadata !"branch_weights", i32 101, i32 2}
-// PGOUSE-DAG: ![[SL3]] = metadata !{metadata !"branch_weights", i32 76, i32 2}
-
-// PGOUSE-DAG: ![[EE1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
-// PGOUSE-DAG: ![[EE2]] = metadata !{metadata !"branch_weights", i32 52, i32 1}
-// PGOUSE-DAG: ![[EE3]] = metadata !{metadata !"branch_weights", i32 2, i32 51}
-// PGOUSE-DAG: ![[EE4]] = metadata !{metadata !"branch_weights", i32 26, i32 26}
-// PGOUSE-DAG: ![[EE5]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
-// PGOUSE-DAG: ![[EE6]] = metadata !{metadata !"branch_weights", i32 2, i32 26}
-// PGOUSE-DAG: ![[EE7]] = metadata !{metadata !"branch_weights", i32 26, i32 1}
-
-// PGOUSE-DAG: ![[IF1]] = metadata !{metadata !"branch_weights", i32 101, i32 2}
-// PGOUSE-DAG: ![[IF2]] = metadata !{metadata !"branch_weights", i32 51, i32 51}
-// PGOUSE-DAG: ![[IF3]] = metadata !{metadata !"branch_weights", i32 51, i32 1}
-// PGOUSE-DAG: ![[IF4]] = metadata !{metadata !"branch_weights", i32 34, i32 18}
-// PGOUSE-DAG: ![[IF5]] = metadata !{metadata !"branch_weights", i32 34, i32 1}
-// PGOUSE-DAG: ![[IF6]] = metadata !{metadata !"branch_weights", i32 17, i32 2}
-// PGOUSE-DAG: ![[IF7]] = metadata !{metadata !"branch_weights", i32 100, i32 2}
-// PGOUSE-DAG: ![[IF8]] = metadata !{metadata !"branch_weights", i32 100, i32 2}
-
-// PGOUSE-DAG: ![[JM1]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
-// PGOUSE-DAG: ![[JM2]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
-// PGOUSE-DAG: ![[JM3]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
-// PGOUSE-DAG: ![[JM4]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
-// PGOUSE-DAG: ![[JM5]] = metadata !{metadata !"branch_weights", i32 3, i32 2}
-// PGOUSE-DAG: ![[JM6]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
-// PGOUSE-DAG: ![[JM7]] = metadata !{metadata !"branch_weights", i32 1, i32 2, i32 2, i32 2}
-// PGOUSE-DAG: ![[JM8]] = metadata !{metadata !"branch_weights", i32 11, i32 2}
-// PGOUSE-DAG: ![[JM9]] = metadata !{metadata !"branch_weights", i32 10, i32 2}
-
-// PGOUSE-DAG: ![[SW1]] = metadata !{metadata !"branch_weights", i32 16, i32 1}
-// PGOUSE-DAG: ![[SW2]] = metadata !{metadata !"branch_weights", i32 6, i32 2, i32 3, i32 4, i32 5}
-// PGOUSE-DAG: ![[SW3]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
-// PGOUSE-DAG: ![[SW4]] = metadata !{metadata !"branch_weights", i32 3, i32 2}
-// PGOUSE-DAG: ![[SW5]] = metadata !{metadata !"branch_weights", i32 4, i32 1}
-// PGOUSE-DAG: ![[SW6]] = metadata !{metadata !"branch_weights", i32 5, i32 1}
-// PGOUSE-DAG: ![[SW7]] = metadata !{metadata !"branch_weights", i32 1, i32 2, i32 2, i32 2, i32 2}
-// PGOUSE-DAG: ![[SW8]] = metadata !{metadata !"branch_weights", i32 5, i32 1}
-// PGOUSE-DAG: ![[SW9]] = metadata !{metadata !"branch_weights", i32 2, i32 5}
-
-// PGOUSE-DAG: ![[BS1]] = metadata !{metadata !"branch_weights", i32 33, i32 2}
-// PGOUSE-DAG: ![[BS2]] = metadata !{metadata !"branch_weights", i32 29, i32 2, i32 2, i32 2, i32 2, i32 1}
-// PGOUSE-DAG: ![[BS3]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
-// PGOUSE-DAG: ![[BS4]] = metadata !{metadata !"branch_weights", i32 2, i32 2}
-// PGOUSE-DAG: ![[BS5]] = metadata !{metadata !"branch_weights", i32 12, i32 1}
-// PGOUSE-DAG: ![[BS6]] = metadata !{metadata !"branch_weights", i32 12, i32 3}
-// PGOUSE-DAG: ![[BS7]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
-// PGOUSE-DAG: ![[BS8]] = metadata !{metadata !"branch_weights", i32 16, i32 1}
-// PGOUSE-DAG: ![[BS9]] = metadata !{metadata !"branch_weights", i32 16, i32 14}
-// PGOUSE-DAG: ![[BS10]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
-// PGOUSE-DAG: ![[BS11]] = metadata !{metadata !"branch_weights", i32 3, i32 1}
-
-// PGOUSE-DAG: ![[BO1]] = metadata !{metadata !"branch_weights", i32 101, i32 2}
-// PGOUSE-DAG: ![[BO2]] = metadata !{metadata !"branch_weights", i32 67, i32 35}
-// PGOUSE-DAG: ![[BO3]] = metadata !{metadata !"branch_weights", i32 67, i32 35}
-// PGOUSE-DAG: ![[BO4]] = metadata !{metadata !"branch_weights", i32 67, i32 35}
-// PGOUSE-DAG: ![[BO5]] = metadata !{metadata !"branch_weights", i32 18, i32 18}
-// PGOUSE-DAG: ![[BO6]] = metadata !{metadata !"branch_weights", i32 51, i32 51}
-// PGOUSE-DAG: ![[BO7]] = metadata !{metadata !"branch_weights", i32 34, i32 18}
-// PGOUSE-DAG: ![[BL1]] = metadata !{metadata !"branch_weights", i32 52, i32 1}
-// PGOUSE-DAG: ![[BL2]] = metadata !{metadata !"branch_weights", i32 51, i32 2}
-// PGOUSE-DAG: ![[BL3]] = metadata !{metadata !"branch_weights", i32 26, i32 27}
-// PGOUSE-DAG: ![[BL4]] = metadata !{metadata !"branch_weights", i32 51, i32 2}
-// PGOUSE-DAG: ![[BL5]] = metadata !{metadata !"branch_weights", i32 52, i32 1}
-// PGOUSE-DAG: ![[BL6]] = metadata !{metadata !"branch_weights", i32 51, i32 2}
-// PGOUSE-DAG: ![[BL7]] = metadata !{metadata !"branch_weights", i32 26, i32 27}
-// PGOUSE-DAG: ![[BL8]] = metadata !{metadata !"branch_weights", i32 51, i32 2}
-// PGOUSE-DAG: ![[CO1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
-// PGOUSE-DAG: ![[CO2]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
-// PGOUSE-DAG: ![[ST1]] = metadata !{metadata !"branch_weights", i32 11, i32 2}
+// PGOUSE-DAG: ![[SL1]] = !{!"branch_weights", i32 101, i32 2}
+// PGOUSE-DAG: ![[SL2]] = !{!"branch_weights", i32 101, i32 2}
+// PGOUSE-DAG: ![[SL3]] = !{!"branch_weights", i32 76, i32 2}
+
+// PGOUSE-DAG: ![[EE1]] = !{!"branch_weights", i32 1, i32 2}
+// PGOUSE-DAG: ![[EE2]] = !{!"branch_weights", i32 52, i32 1}
+// PGOUSE-DAG: ![[EE3]] = !{!"branch_weights", i32 2, i32 51}
+// PGOUSE-DAG: ![[EE4]] = !{!"branch_weights", i32 26, i32 26}
+// PGOUSE-DAG: ![[EE5]] = !{!"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[EE6]] = !{!"branch_weights", i32 2, i32 26}
+// PGOUSE-DAG: ![[EE7]] = !{!"branch_weights", i32 26, i32 1}
+
+// PGOUSE-DAG: ![[IF1]] = !{!"branch_weights", i32 101, i32 2}
+// PGOUSE-DAG: ![[IF2]] = !{!"branch_weights", i32 51, i32 51}
+// PGOUSE-DAG: ![[IF3]] = !{!"branch_weights", i32 51, i32 1}
+// PGOUSE-DAG: ![[IF4]] = !{!"branch_weights", i32 34, i32 18}
+// PGOUSE-DAG: ![[IF5]] = !{!"branch_weights", i32 34, i32 1}
+// PGOUSE-DAG: ![[IF6]] = !{!"branch_weights", i32 17, i32 2}
+// PGOUSE-DAG: ![[IF7]] = !{!"branch_weights", i32 100, i32 2}
+// PGOUSE-DAG: ![[IF8]] = !{!"branch_weights", i32 100, i32 2}
+
+// PGOUSE-DAG: ![[JM1]] = !{!"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[JM2]] = !{!"branch_weights", i32 1, i32 2}
+// PGOUSE-DAG: ![[JM3]] = !{!"branch_weights", i32 1, i32 2}
+// PGOUSE-DAG: ![[JM4]] = !{!"branch_weights", i32 1, i32 2}
+// PGOUSE-DAG: ![[JM5]] = !{!"branch_weights", i32 3, i32 2}
+// PGOUSE-DAG: ![[JM6]] = !{!"branch_weights", i32 1, i32 2}
+// PGOUSE-DAG: ![[JM7]] = !{!"branch_weights", i32 1, i32 2, i32 2, i32 2}
+// PGOUSE-DAG: ![[JM8]] = !{!"branch_weights", i32 11, i32 2}
+// PGOUSE-DAG: ![[JM9]] = !{!"branch_weights", i32 10, i32 2}
+
+// PGOUSE-DAG: ![[SW1]] = !{!"branch_weights", i32 16, i32 1}
+// PGOUSE-DAG: ![[SW2]] = !{!"branch_weights", i32 6, i32 2, i32 3, i32 4, i32 5}
+// PGOUSE-DAG: ![[SW3]] = !{!"branch_weights", i32 1, i32 2}
+// PGOUSE-DAG: ![[SW4]] = !{!"branch_weights", i32 3, i32 2}
+// PGOUSE-DAG: ![[SW5]] = !{!"branch_weights", i32 4, i32 1}
+// PGOUSE-DAG: ![[SW6]] = !{!"branch_weights", i32 5, i32 1}
+// PGOUSE-DAG: ![[SW7]] = !{!"branch_weights", i32 1, i32 2, i32 2, i32 2, i32 2}
+// PGOUSE-DAG: ![[SW8]] = !{!"branch_weights", i32 5, i32 1}
+// PGOUSE-DAG: ![[SW9]] = !{!"branch_weights", i32 2, i32 5}
+
+// PGOUSE-DAG: ![[BS1]] = !{!"branch_weights", i32 33, i32 2}
+// PGOUSE-DAG: ![[BS2]] = !{!"branch_weights", i32 29, i32 2, i32 2, i32 2, i32 2, i32 1}
+// PGOUSE-DAG: ![[BS3]] = !{!"branch_weights", i32 1, i32 2}
+// PGOUSE-DAG: ![[BS4]] = !{!"branch_weights", i32 2, i32 2}
+// PGOUSE-DAG: ![[BS5]] = !{!"branch_weights", i32 12, i32 1}
+// PGOUSE-DAG: ![[BS6]] = !{!"branch_weights", i32 12, i32 3}
+// PGOUSE-DAG: ![[BS7]] = !{!"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[BS8]] = !{!"branch_weights", i32 16, i32 1}
+// PGOUSE-DAG: ![[BS9]] = !{!"branch_weights", i32 16, i32 14}
+// PGOUSE-DAG: ![[BS10]] = !{!"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[BS11]] = !{!"branch_weights", i32 3, i32 1}
+
+// PGOUSE-DAG: ![[BO1]] = !{!"branch_weights", i32 101, i32 2}
+// PGOUSE-DAG: ![[BO2]] = !{!"branch_weights", i32 67, i32 35}
+// PGOUSE-DAG: ![[BO3]] = !{!"branch_weights", i32 67, i32 35}
+// PGOUSE-DAG: ![[BO4]] = !{!"branch_weights", i32 67, i32 35}
+// PGOUSE-DAG: ![[BO5]] = !{!"branch_weights", i32 18, i32 18}
+// PGOUSE-DAG: ![[BO6]] = !{!"branch_weights", i32 51, i32 51}
+// PGOUSE-DAG: ![[BO7]] = !{!"branch_weights", i32 34, i32 18}
+// PGOUSE-DAG: ![[BL1]] = !{!"branch_weights", i32 52, i32 1}
+// PGOUSE-DAG: ![[BL2]] = !{!"branch_weights", i32 51, i32 2}
+// PGOUSE-DAG: ![[BL3]] = !{!"branch_weights", i32 26, i32 27}
+// PGOUSE-DAG: ![[BL4]] = !{!"branch_weights", i32 51, i32 2}
+// PGOUSE-DAG: ![[BL5]] = !{!"branch_weights", i32 52, i32 1}
+// PGOUSE-DAG: ![[BL6]] = !{!"branch_weights", i32 51, i32 2}
+// PGOUSE-DAG: ![[BL7]] = !{!"branch_weights", i32 26, i32 27}
+// PGOUSE-DAG: ![[BL8]] = !{!"branch_weights", i32 51, i32 2}
+// PGOUSE-DAG: ![[CO1]] = !{!"branch_weights", i32 1, i32 2}
+// PGOUSE-DAG: ![[CO2]] = !{!"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[ST1]] = !{!"branch_weights", i32 11, i32 2}
int main(int argc, const char *argv[]) {
simple_loops();
diff --git a/test/Profile/c-linkage-available_externally.c b/test/Profile/c-linkage-available_externally.c
index aa1080b2b443..e89632ad3604 100644
--- a/test/Profile/c-linkage-available_externally.c
+++ b/test/Profile/c-linkage-available_externally.c
@@ -2,8 +2,9 @@
// get thrown out.
// RUN: %clang_cc1 -O2 -triple x86_64-apple-macosx10.9 -main-file-name c-linkage-available_externally.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck %s
-// CHECK: @__llvm_profile_counters_foo = linkonce_odr hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name_foo = linkonce_odr hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1
+
+// CHECK: @__llvm_profile_counters_foo = linkonce_odr hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_data_foo = linkonce_odr hidden constant { i32, i32, i64, i8*, i64* } { i32 3, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_foo, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
inline int foo(void) { return 1; }
diff --git a/test/Profile/c-linkage.c b/test/Profile/c-linkage.c
index 3b0fa1a5a6ba..94393a42e0a0 100644
--- a/test/Profile/c-linkage.c
+++ b/test/Profile/c-linkage.c
@@ -1,20 +1,21 @@
// Check the data structures emitted by instrumentation.
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-linkage.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck %s
-// CHECK: @__llvm_profile_runtime = external global i32
-// CHECK: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1
+// CHECK: @__llvm_profile_name_foo_weak = weak hidden constant [8 x i8] c"foo_weak", section "__DATA,__llvm_prf_names", align 1
+// CHECK: @__llvm_profile_name_main = hidden constant [4 x i8] c"main", section "__DATA,__llvm_prf_names", align 1
+// CHECK: @"__llvm_profile_name_c-linkage.c:foo_internal" = internal constant [24 x i8] c"c-linkage.c:foo_internal", section "__DATA,__llvm_prf_names", align 1
+
+// CHECK: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_data_foo = hidden constant { i32, i32, i64, i8*, i64* } { i32 3, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_foo, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
void foo(void) { }
// CHECK: @__llvm_profile_counters_foo_weak = weak hidden global [5 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-// CHECK: @__llvm_profile_name_foo_weak = weak hidden constant [8 x i8] c"foo_weak", section "__DATA,__llvm_prf_names", align 1
// CHECK: @__llvm_profile_data_foo_weak = weak hidden constant { i32, i32, i64, i8*, i64* } { i32 8, i32 5, i64 {{[0-9]+}}, i8* getelementptr inbounds ([8 x i8]* @__llvm_profile_name_foo_weak, i32 0, i32 0), i64* getelementptr inbounds ([5 x i64]* @__llvm_profile_counters_foo_weak, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
void foo_weak(void) __attribute__((weak));
void foo_weak(void) { if (0){} if (0){} if (0){} if (0){} }
// CHECK: @__llvm_profile_counters_main = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-// CHECK: @__llvm_profile_name_main = hidden constant [4 x i8] c"main", section "__DATA,__llvm_prf_names", align 1
// CHECK: @__llvm_profile_data_main = hidden constant { i32, i32, i64, i8*, i64* } { i32 4, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([4 x i8]* @__llvm_profile_name_main, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_main, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
static void foo_internal(void);
int main(void) {
@@ -24,12 +25,12 @@ int main(void) {
return 0;
}
-// CHECK: @__llvm_profile_counters_foo_internal = internal global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-// CHECK: @__llvm_profile_name_foo_internal = internal constant [24 x i8] c"c-linkage.c:foo_internal", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_data_foo_internal = internal constant { i32, i32, i64, i8*, i64* } { i32 24, i32 3, i64 {{[0-9]+}}, i8* getelementptr inbounds ([24 x i8]* @__llvm_profile_name_foo_internal, i32 0, i32 0), i64* getelementptr inbounds ([3 x i64]* @__llvm_profile_counters_foo_internal, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @"__llvm_profile_counters_c-linkage.c:foo_internal" = internal global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
+// CHECK: @"__llvm_profile_data_c-linkage.c:foo_internal" = internal constant { i32, i32, i64, i8*, i64* } { i32 24, i32 3, i64 {{[0-9]+}}, i8* getelementptr inbounds ([24 x i8]* @"__llvm_profile_name_c-linkage.c:foo_internal", i32 0, i32 0), i64* getelementptr inbounds ([3 x i64]* @"__llvm_profile_counters_c-linkage.c:foo_internal", i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
static void foo_internal(void) { if (0){} if (0){} }
-// CHECK: @llvm.used = appending global [5 x i8*] [i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_weak to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_internal to i8*)], section "llvm.metadata"
+// CHECK: @__llvm_profile_runtime = external global i32
+// CHECK: @llvm.used = appending global [5 x i8*] [i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_weak to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @"__llvm_profile_data_c-linkage.c:foo_internal" to i8*), i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*)], section "llvm.metadata"
// CHECK: define linkonce_odr i32 @__llvm_profile_runtime_user() {{.*}} {
// CHECK: %[[REG:.*]] = load i32* @__llvm_profile_runtime
diff --git a/test/Profile/c-unreachable-after-switch.c b/test/Profile/c-unreachable-after-switch.c
new file mode 100644
index 000000000000..077043751058
--- /dev/null
+++ b/test/Profile/c-unreachable-after-switch.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -O3 -triple x86_64-apple-macosx10.10 -main-file-name c-unreachable-after-switch.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck %s
+
+// CHECK: @[[C:__llvm_profile_counters_foo]] = hidden global [3 x i64] zeroinitializer
+
+// CHECK-LABEL: @foo()
+// CHECK: store {{.*}} @[[C]], i64 0, i64 0
+void foo() {
+ // CHECK: store {{.*}} @[[C]], i64 0, i64 2
+ switch (0) {
+ default:
+ return;
+ }
+ // We shouldn't emit the unreachable counter. This used to crash in GlobalDCE.
+ // CHECK-NOT: store {{.*}} @[[SWC]], i64 0, i64 1}
+}
diff --git a/test/Profile/cxx-class.cpp b/test/Profile/cxx-class.cpp
index 1a0c84bdccea..21cbbd68320a 100644
--- a/test/Profile/cxx-class.cpp
+++ b/test/Profile/cxx-class.cpp
@@ -27,7 +27,7 @@ public:
// CTRUSE-NOT: br {{.*}} !prof ![0-9]+
// CTRUSE: ret
}
- // CTRUSE: ![[SC1]] = metadata !{metadata !"branch_weights", i32 100, i32 2}
+ // CTRUSE: ![[SC1]] = !{!"branch_weights", i32 100, i32 2}
// DTRGEN-LABEL: define {{.*}} @_ZN6SimpleD2Ev(
// DTRUSE-LABEL: define {{.*}} @_ZN6SimpleD2Ev(
@@ -40,7 +40,7 @@ public:
// DTRUSE-NOT: br {{.*}} !prof ![0-9]+
// DTRUSE: ret
}
- // DTRUSE: ![[SD1]] = metadata !{metadata !"branch_weights", i32 100, i32 2}
+ // DTRUSE: ![[SD1]] = !{!"branch_weights", i32 100, i32 2}
// MTHGEN-LABEL: define {{.*}} @_ZN6Simple6methodEv(
// MTHUSE-LABEL: define {{.*}} @_ZN6Simple6methodEv(
@@ -53,7 +53,7 @@ public:
// MTHUSE-NOT: br {{.*}} !prof ![0-9]+
// MTHUSE: ret
}
- // MTHUSE: ![[SM1]] = metadata !{metadata !"branch_weights", i32 100, i32 2}
+ // MTHUSE: ![[SM1]] = !{!"branch_weights", i32 100, i32 2}
};
// WRPGEN-LABEL: define {{.*}} @_Z14simple_wrapperv(
@@ -70,7 +70,7 @@ void simple_wrapper() {
// WRPUSE-NOT: br {{.*}} !prof ![0-9]+
// WRPUSE: ret
}
-// WRPUSE: ![[SW1]] = metadata !{metadata !"branch_weights", i32 101, i32 2}
+// WRPUSE: ![[SW1]] = !{!"branch_weights", i32 101, i32 2}
int main(int argc, const char *argv[]) {
simple_wrapper();
diff --git a/test/Profile/cxx-lambda.cpp b/test/Profile/cxx-lambda.cpp
index 6c37a863e5c1..ebf7f4c55f4d 100644
--- a/test/Profile/cxx-lambda.cpp
+++ b/test/Profile/cxx-lambda.cpp
@@ -11,7 +11,7 @@
// PGOGEN: @[[LWC:__llvm_profile_counters__Z7lambdasv]] = hidden global [4 x i64] zeroinitializer
// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = hidden global [1 x i64] zeroinitializer
-// LMBGEN: @[[LFC:"__llvm_profile_counters__ZZ7lambdasvENK3\$_0clEi"]] = internal global [3 x i64] zeroinitializer
+// LMBGEN: @[[LFC:"__llvm_profile_counters_cxx-lambda.cpp:_ZZ7lambdasvENK3\$_0clEi"]] = internal global [3 x i64] zeroinitializer
// PGOGEN-LABEL: define void @_Z7lambdasv()
// PGOUSE-LABEL: define void @_Z7lambdasv()
@@ -45,12 +45,12 @@ void lambdas() {
if (i) {}
}
-// PGOUSE-DAG: ![[LW1]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
-// PGOUSE-DAG: ![[LW2]] = metadata !{metadata !"branch_weights", i32 11, i32 2}
-// PGOUSE-DAG: ![[LW3]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[LW1]] = !{!"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[LW2]] = !{!"branch_weights", i32 11, i32 2}
+// PGOUSE-DAG: ![[LW3]] = !{!"branch_weights", i32 2, i32 1}
-// LMBUSE-DAG: ![[LF1]] = metadata !{metadata !"branch_weights", i32 10, i32 2}
-// LMBUSE-DAG: ![[LF2]] = metadata !{metadata !"branch_weights", i32 10, i32 2}
+// LMBUSE-DAG: ![[LF1]] = !{!"branch_weights", i32 10, i32 2}
+// LMBUSE-DAG: ![[LF2]] = !{!"branch_weights", i32 10, i32 2}
int main(int argc, const char *argv[]) {
lambdas();
diff --git a/test/Profile/cxx-linkage.cpp b/test/Profile/cxx-linkage.cpp
index df896e7a78f2..e410218c4826 100644
--- a/test/Profile/cxx-linkage.cpp
+++ b/test/Profile/cxx-linkage.cpp
@@ -1,19 +1,20 @@
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9.0 -emit-llvm -main-file-name cxx-linkage.cpp %s -o - -fprofile-instr-generate | FileCheck %s
-// CHECK: @__llvm_profile_runtime = external global i32
-// CHECK: @__llvm_profile_counters__Z3foov = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name__Z3foov = hidden constant [7 x i8] c"_Z3foov", section "__DATA,__llvm_prf_names", align 1
+// CHECK: @__llvm_profile_name__Z8foo_weakv = weak hidden constant [12 x i8] c"_Z8foo_weakv", section "__DATA,__llvm_prf_names", align 1
+// CHECK: @__llvm_profile_name_main = hidden constant [4 x i8] c"main", section "__DATA,__llvm_prf_names", align 1
+// CHECK: @__llvm_profile_name__Z10foo_inlinev = linkonce_odr hidden constant [15 x i8] c"_Z10foo_inlinev", section "__DATA,__llvm_prf_names", align 1
+
+// CHECK: @__llvm_profile_counters__Z3foov = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_data__Z3foov = hidden constant { i32, i32, i64, i8*, i64* } { i32 7, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([7 x i8]* @__llvm_profile_name__Z3foov, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters__Z3foov, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
void foo(void) { }
// CHECK: @__llvm_profile_counters__Z8foo_weakv = weak hidden global [5 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-// CHECK: @__llvm_profile_name__Z8foo_weakv = weak hidden constant [12 x i8] c"_Z8foo_weakv", section "__DATA,__llvm_prf_names", align 1
// CHECK: @__llvm_profile_data__Z8foo_weakv = weak hidden constant { i32, i32, i64, i8*, i64* } { i32 12, i32 5, i64 {{[0-9]+}}, i8* getelementptr inbounds ([12 x i8]* @__llvm_profile_name__Z8foo_weakv, i32 0, i32 0), i64* getelementptr inbounds ([5 x i64]* @__llvm_profile_counters__Z8foo_weakv, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
void foo_weak(void) __attribute__((weak));
void foo_weak(void) { if (0){} if (0){} if (0){} if (0){} }
// CHECK: @__llvm_profile_counters_main = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-// CHECK: @__llvm_profile_name_main = hidden constant [4 x i8] c"main", section "__DATA,__llvm_prf_names", align 1
// CHECK: @__llvm_profile_data_main = hidden constant { i32, i32, i64, i8*, i64* } { i32 4, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([4 x i8]* @__llvm_profile_name_main, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_main, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
inline void foo_inline(void);
int main(void) {
@@ -24,11 +25,11 @@ int main(void) {
}
// CHECK: @__llvm_profile_counters__Z10foo_inlinev = linkonce_odr hidden global [7 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-// CHECK: @__llvm_profile_name__Z10foo_inlinev = linkonce_odr hidden constant [15 x i8] c"_Z10foo_inlinev", section "__DATA,__llvm_prf_names", align 1
// CHECK: @__llvm_profile_data__Z10foo_inlinev = linkonce_odr hidden constant { i32, i32, i64, i8*, i64* } { i32 15, i32 7, i64 {{[0-9]+}}, i8* getelementptr inbounds ([15 x i8]* @__llvm_profile_name__Z10foo_inlinev, i32 0, i32 0), i64* getelementptr inbounds ([7 x i64]* @__llvm_profile_counters__Z10foo_inlinev, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
inline void foo_inline(void) { if (0){} if (0){} if (0){} if (0){} if (0){} if (0){}}
-// CHECK: @llvm.used = appending global [5 x i8*] [i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z3foov to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z8foo_weakv to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z10foo_inlinev to i8*)], section "llvm.metadata"
+// CHECK: @__llvm_profile_runtime = external global i32
+// CHECK: @llvm.used = appending global [5 x i8*] [i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z3foov to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z8foo_weakv to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z10foo_inlinev to i8*), i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*)], section "llvm.metadata"
// CHECK: define linkonce_odr i32 @__llvm_profile_runtime_user() {{.*}} {
// CHECK: %[[REG:.*]] = load i32* @__llvm_profile_runtime
diff --git a/test/Profile/cxx-templates.cpp b/test/Profile/cxx-templates.cpp
index 55ab36fe560d..ce5651a25006 100644
--- a/test/Profile/cxx-templates.cpp
+++ b/test/Profile/cxx-templates.cpp
@@ -32,8 +32,8 @@ template <unsigned N> void loop() {
// ALL: ret
}
-// T0USE-DAG: ![[T01]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
-// T100USE-DAG: ![[T1001]] = metadata !{metadata !"branch_weights", i32 101, i32 2}
+// T0USE-DAG: ![[T01]] = !{!"branch_weights", i32 1, i32 2}
+// T100USE-DAG: ![[T1001]] = !{!"branch_weights", i32 101, i32 2}
int main(int argc, const char *argv[]) {
loop<0>();
diff --git a/test/Profile/cxx-throws.cpp b/test/Profile/cxx-throws.cpp
index 9ea5ace4b74a..e28b37ded55f 100644
--- a/test/Profile/cxx-throws.cpp
+++ b/test/Profile/cxx-throws.cpp
@@ -60,12 +60,12 @@ void throws() {
// PGOUSE: ret void
}
-// PGOUSE-DAG: ![[TH1]] = metadata !{metadata !"branch_weights", i32 101, i32 2}
-// PGOUSE-DAG: ![[TH2]] = metadata !{metadata !"branch_weights", i32 67, i32 35}
-// PGOUSE-DAG: ![[TH3]] = metadata !{metadata !"branch_weights", i32 34, i32 34}
-// PGOUSE-DAG: ![[TH4]] = metadata !{metadata !"branch_weights", i32 18, i32 18}
-// PGOUSE-EXC: ![[TH5]] = metadata !{metadata !"branch_weights", i32 34, i32 18}
-// PGOUSE-DAG: ![[TH6]] = metadata !{metadata !"branch_weights", i32 101, i32 1}
+// PGOUSE-DAG: ![[TH1]] = !{!"branch_weights", i32 101, i32 2}
+// PGOUSE-DAG: ![[TH2]] = !{!"branch_weights", i32 67, i32 35}
+// PGOUSE-DAG: ![[TH3]] = !{!"branch_weights", i32 34, i32 34}
+// PGOUSE-DAG: ![[TH4]] = !{!"branch_weights", i32 18, i32 18}
+// PGOUSE-EXC: ![[TH5]] = !{!"branch_weights", i32 34, i32 18}
+// PGOUSE-DAG: ![[TH6]] = !{!"branch_weights", i32 101, i32 1}
int main(int argc, const char *argv[]) {
throws();
diff --git a/test/Profile/objc-general.m b/test/Profile/objc-general.m
index ba06f91a7f98..9a3666786672 100644
--- a/test/Profile/objc-general.m
+++ b/test/Profile/objc-general.m
@@ -31,8 +31,8 @@ struct NSFastEnumerationState;
@end;
#endif
-// PGOGEN: @[[FRC:"__llvm_profile_counters_\+\[A foreach:\]"]] = internal global [2 x i64] zeroinitializer
-// PGOGEN: @[[BLC:"__llvm_profile_counters___13\+\[A foreach:\]_block_invoke"]] = internal global [2 x i64] zeroinitializer
+// PGOGEN: @[[FRC:"__llvm_profile_counters_objc-general.m:\+\[A foreach:\]"]] = internal global [2 x i64] zeroinitializer
+// PGOGEN: @[[BLC:"__llvm_profile_counters_objc-general.m:__13\+\[A foreach:\]_block_invoke"]] = internal global [2 x i64] zeroinitializer
// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = hidden global [1 x i64] zeroinitializer
@interface A : NSObject
@@ -63,9 +63,9 @@ struct NSFastEnumerationState;
}
@end
-// PGOUSE-DAG: ![[FR1]] = metadata !{metadata !"branch_weights", i32 2, i32 3}
-// PGOUSE-DAG: ![[FR2]] = metadata !{metadata !"branch_weights", i32 3, i32 2}
-// PGOUSE-DAG: ![[BL1]] = metadata !{metadata !"branch_weights", i32 2, i32 2}
+// PGOUSE-DAG: ![[FR1]] = !{!"branch_weights", i32 2, i32 3}
+// PGOUSE-DAG: ![[FR2]] = !{!"branch_weights", i32 3, i32 2}
+// PGOUSE-DAG: ![[BL1]] = !{!"branch_weights", i32 2, i32 2}
int main(int argc, const char *argv[]) {
A *a = [[A alloc] init];
diff --git a/test/Rewriter/rewrite-block-literal.mm b/test/Rewriter/rewrite-block-literal.mm
index 43f581125ba0..cde6efcbf29d 100644
--- a/test/Rewriter/rewrite-block-literal.mm
+++ b/test/Rewriter/rewrite-block-literal.mm
@@ -70,7 +70,7 @@ static int global_x = 10;
void (^global_block)(void) = ^{ printf("global x is %d\n", global_x); };
// CHECK: static __global_block_block_impl_0 __global_global_block_block_impl_0((void *)__global_block_block_func_0, &__global_block_block_desc_0_DATA);
-// CHECK: void (*global_block)(void) = (void (*)())&__global_global_block_block_impl_0;
+// CHECK: void (*global_block)(void) = ((void (*)())&__global_global_block_block_impl_0);
typedef void (^void_block_t)(void);
diff --git a/test/Rewriter/rewrite-modern-block.mm b/test/Rewriter/rewrite-modern-block.mm
index 23029654c984..926ee36f1a4a 100644
--- a/test/Rewriter/rewrite-modern-block.mm
+++ b/test/Rewriter/rewrite-modern-block.mm
@@ -63,3 +63,6 @@ z w(int loc, int len);
options &= ~(1 | 2);
}
@end
+
+// rdar://18799145
+int Test18799145() { return ^(){return 0;}(); }
diff --git a/test/Rewriter/rewrite-modern-captured-nested-bvar.mm b/test/Rewriter/rewrite-modern-captured-nested-bvar.mm
index a8fd18073372..be7548c778ab 100644
--- a/test/Rewriter/rewrite-modern-captured-nested-bvar.mm
+++ b/test/Rewriter/rewrite-modern-captured-nested-bvar.mm
@@ -32,4 +32,4 @@ int main() {
// CHECK 2: (__Block_byref_BYREF_VAR_CHECK_0 *)BYREF_VAR_CHECK
// CHECK: {(void*)0,(__Block_byref_BYREF_VAR_CHECK_0 *)&BYREF_VAR_CHECK, 0, sizeof(__Block_byref_BYREF_VAR_CHECK_0), 'a'}
-// CHECK: __Block_byref_BYREF_VAR_CHECK_0 *)&BYREF_VAR_CHECK, (__Block_byref_d_1 *)&d, 570425344));
+// CHECK: __Block_byref_BYREF_VAR_CHECK_0 *)&BYREF_VAR_CHECK, (__Block_byref_d_1 *)&d, 570425344)));
diff --git a/test/Sema/128bitfloat.cc b/test/Sema/128bitfloat.cpp
index cb76dac96001..cb76dac96001 100644
--- a/test/Sema/128bitfloat.cc
+++ b/test/Sema/128bitfloat.cpp
diff --git a/test/Sema/128bitint.c b/test/Sema/128bitint.c
index 4272b2d1391e..6469d84c7cc5 100644
--- a/test/Sema/128bitint.c
+++ b/test/Sema/128bitint.c
@@ -16,10 +16,10 @@ __uint128_t b = (__uint128_t)-1;
__int128 i = (__int128)0;
unsigned __int128 u = (unsigned __int128)-1;
-long long SignedTooBig = 123456789012345678901234567890; // expected-error {{constant is larger than the largest unsigned integer type}}
+long long SignedTooBig = 123456789012345678901234567890; // expected-error {{integer literal is too large to be represented in any integer type}}
__int128_t Signed128 = 123456789012345678901234567890i128;
long long Signed64 = 123456789012345678901234567890i128; // expected-warning {{implicit conversion from '__int128' to 'long long' changes value from 123456789012345678901234567890 to -4362896299872285998}}
-unsigned long long UnsignedTooBig = 123456789012345678901234567890; // expected-error {{constant is larger than the largest unsigned integer type}}
+unsigned long long UnsignedTooBig = 123456789012345678901234567890; // expected-error {{integer literal is too large to be represented in any integer type}}
__uint128_t Unsigned128 = 123456789012345678901234567890Ui128;
unsigned long long Unsigned64 = 123456789012345678901234567890Ui128; // expected-warning {{implicit conversion from 'unsigned __int128' to 'unsigned long long' changes value from 123456789012345678901234567890 to 14083847773837265618}}
diff --git a/test/Sema/MicrosoftExtensions.c b/test/Sema/MicrosoftExtensions.c
index 429dd943a746..e7032305fc07 100644
--- a/test/Sema/MicrosoftExtensions.c
+++ b/test/Sema/MicrosoftExtensions.c
@@ -39,9 +39,26 @@ struct nested2 {
NESTED1; // expected-warning {{anonymous structs are a Microsoft extension}}
};
+struct nested2 PR20573 = { .a = 3 };
+
+struct nested3 {
+ long d;
+ struct nested4 { // expected-warning {{anonymous structs are a Microsoft extension}}
+ long e;
+ };
+ union nested5 { // expected-warning {{anonymous unions are a Microsoft extension}}
+ long f;
+ };
+};
+
+typedef union nested6 {
+ long f;
+} NESTED6;
+
struct test {
int c;
struct nested2; // expected-warning {{anonymous structs are a Microsoft extension}}
+ NESTED6; // expected-warning {{anonymous unions are a Microsoft extension}}
};
void foo()
@@ -87,6 +104,14 @@ typedef struct {
AA; // expected-warning {{anonymous structs are a Microsoft extension}}
} BB;
+struct anon_fault {
+ struct undefined; // expected-warning {{anonymous structs are a Microsoft extension}}
+ // expected-error@-1 {{field has incomplete type 'struct undefined'}}
+ // expected-note@-2 {{forward declaration of 'struct undefined'}}
+};
+
+const int anon_falt_size = sizeof(struct anon_fault);
+
__declspec(deprecated("This is deprecated")) enum DE1 { one, two } e1; // expected-note {{'e1' has been explicitly marked deprecated here}}
struct __declspec(deprecated) DS1 { int i; float f; }; // expected-note {{'DS1' has been explicitly marked deprecated here}}
diff --git a/test/Sema/align_value.c b/test/Sema/align_value.c
new file mode 100644
index 000000000000..92b84dbee165
--- /dev/null
+++ b/test/Sema/align_value.c
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef double * __attribute__((align_value(64))) aligned_double;
+
+void foo(aligned_double x, double * y __attribute__((align_value(32)))) { };
+
+// expected-error@+1 {{requested alignment is not a power of 2}}
+typedef double * __attribute__((align_value(63))) aligned_double1;
+
+// expected-error@+1 {{requested alignment is not a power of 2}}
+typedef double * __attribute__((align_value(-2))) aligned_double2;
+
+// expected-error@+1 {{attribute takes one argument}}
+typedef double * __attribute__((align_value(63, 4))) aligned_double3;
+
+// expected-error@+1 {{attribute takes one argument}}
+typedef double * __attribute__((align_value())) aligned_double3a;
+
+// expected-error@+1 {{attribute takes one argument}}
+typedef double * __attribute__((align_value)) aligned_double3b;
+
+// expected-error@+1 {{'align_value' attribute requires integer constant}}
+typedef double * __attribute__((align_value(4.5))) aligned_double4;
+
+// expected-warning@+1 {{'align_value' attribute only applies to a pointer or reference ('int' is invalid)}}
+typedef int __attribute__((align_value(32))) aligned_int;
+
+typedef double * __attribute__((align_value(32*2))) aligned_double5;
+
+// expected-warning@+1 {{'align_value' attribute only applies to variables and typedefs}}
+void foo() __attribute__((align_value(32)));
+
diff --git a/test/Sema/anonymous-struct-union-c11.c b/test/Sema/anonymous-struct-union-c11.c
index 229ee520575e..712e29e5496a 100644
--- a/test/Sema/anonymous-struct-union-c11.c
+++ b/test/Sema/anonymous-struct-union-c11.c
@@ -1,8 +1,8 @@
// Check for warnings in non-C11 mode:
-// RUN: %clang_cc1 -fsyntax-only -verify -Wc11-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -std=c99 -verify -Wc11-extensions %s
// Expect no warnings in C11 mode:
-// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -std=c11 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c11 -pedantic -Werror %s
struct s {
int a;
diff --git a/test/Sema/anonymous-struct-union.c b/test/Sema/anonymous-struct-union.c
index 35d31754162a..652383eabb72 100644
--- a/test/Sema/anonymous-struct-union.c
+++ b/test/Sema/anonymous-struct-union.c
@@ -37,7 +37,7 @@ void test_unqual_references(struct X x, const struct X xc) {
struct Redecl {
int x; // expected-note{{previous declaration is here}}
- struct y { };
+ struct y { }; // expected-warning{{declaration does not declare anything}}
union {
int x; // expected-error{{member of anonymous union redeclares 'x'}}
@@ -108,3 +108,13 @@ struct s {
struct { int i; };
int a[];
};
+
+// PR20930
+struct s3 {
+ struct { int A __attribute__((deprecated)); }; // expected-note {{'A' has been explicitly marked deprecated here}}
+};
+
+void deprecated_anonymous_struct_member(void) {
+ struct s3 s;
+ s.A = 1; // expected-warning {{'A' is deprecated}}
+}
diff --git a/test/Sema/arm-darwin-aapcs.cpp b/test/Sema/arm-darwin-aapcs.cpp
index 1359a1dc15aa..3a6082ae40e2 100644
--- a/test/Sema/arm-darwin-aapcs.cpp
+++ b/test/Sema/arm-darwin-aapcs.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -triple thumbv7-apple-ios -target-abi aapcs -verify -fsyntax-only
+// RUN: %clang_cc1 %s -triple thumbv7m-apple-macho -target-abi aapcs -verify -fsyntax-only
// expected-no-diagnostics
// ARM's AAPCS normally has size_t defined as unsigned int, but on Darwin
diff --git a/test/Sema/arm64-inline-asm.c b/test/Sema/arm64-inline-asm.c
index 08eb669265f7..d8e16a6872cc 100644
--- a/test/Sema/arm64-inline-asm.c
+++ b/test/Sema/arm64-inline-asm.c
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -triple arm64-apple-ios7.1 -fsyntax-only -verify %s
-// expected-no-diagnostics
void foo() {
asm volatile("USE(%0)" :: "z"(0LL));
asm volatile("USE(%x0)" :: "z"(0LL));
asm volatile("USE(%w0)" :: "z"(0));
+ asm volatile("USE(%0)" :: "z"(0)); // expected-warning {{value size does not match register size specified by the constraint and modifier}} expected-note {{use constraint modifier "w"}}
}
diff --git a/test/Sema/arm64-neon-args.c b/test/Sema/arm64-neon-args.c
index 315a7044040e..a6c4f13a4316 100644
--- a/test/Sema/arm64-neon-args.c
+++ b/test/Sema/arm64-neon-args.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-apple-darwin -target-feature +neon -fsyntax-only -ffreestanding -verify %s
-// RUN: %clang_cc1 -triple arm64_be-none-linux-gnu -target-feature +neon -fsyntax-only -ffreestanding -verify %s
+// RUN: %clang_cc1 -triple aarch64_be-none-linux-gnu -target-feature +neon -fsyntax-only -ffreestanding -verify %s
#include <arm_neon.h>
diff --git a/test/Sema/arm_acle.c b/test/Sema/arm_acle.c
index 866626fc38cb..ec0d55854eeb 100644
--- a/test/Sema/arm_acle.c
+++ b/test/Sema/arm_acle.c
@@ -30,3 +30,19 @@ int32_t test_ssat_const_diag(int32_t t, const int32_t v) {
int32_t test_usat_const_diag(int32_t t, const int32_t v) {
return __usat(t, v); // expected-error-re {{argument to {{.*}} must be a constant integer}}
}
+
+/*
+ * Prefetch intrinsics
+ */
+void test_pldx_const_diag(int32_t i) {
+ __pldx(i, 0, 0, 0); // expected-error-re {{argument to {{.*}} must be a constant integer}}
+}
+
+/*
+ * DBG intrinsic
+ * First argument for DBG intrinsic must be compile-time constant,
+ * otherwise an error should be raised.
+ */
+void test_dbg_const_diag(unsigned int t) {
+ __dbg(t); // expected-error-re {{argument to {{.*}} must be a constant integer}}
+}
diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c
index 4cc5e412c2d5..7cb48153168f 100644
--- a/test/Sema/array-init.c
+++ b/test/Sema/array-init.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wgnu -Wc11-extensions -verify %s
+// RUN: %clang_cc1 -std=gnu99 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -std=gnu99 -fsyntax-only -Wgnu -Wc11-extensions -verify %s
// REQUIRES: LP64
extern int foof() = 1; // expected-error{{illegal initializer (only variables can be initialized)}}
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
index 89c8c574eb5a..6c6f3f398e33 100644
--- a/test/Sema/asm.c
+++ b/test/Sema/asm.c
@@ -107,6 +107,7 @@ void test10(void){
register int r asm ("cx");
register int rr asm ("rr_asm"); // expected-error{{unknown register name 'rr_asm' in asm}}
+ register int rrr asm ("%"); // expected-error{{unknown register name '%' in asm}}
}
// This is just an assert because of the boolean conversion.
@@ -163,3 +164,43 @@ double f_output_constraint(void) {
__asm("foo1": "=f" (result)); // expected-error {{invalid output constraint '=f' in asm}}
return result;
}
+
+void fn1() {
+ int l;
+ __asm__(""
+ : [l] "=r"(l)
+ : "[l],m"(l)); // expected-error {{asm constraint has an unexpected number of alternatives: 1 vs 2}}
+}
+
+void fn2() {
+ int l;
+ __asm__(""
+ : "+&m"(l)); // expected-error {{invalid output constraint '+&m' in asm}}
+}
+
+void fn3() {
+ int l;
+ __asm__(""
+ : "+#r"(l)); // expected-error {{invalid output constraint '+#r' in asm}}
+}
+
+void fn4() {
+ int l;
+ __asm__(""
+ : "=r"(l)
+ : "m#"(l));
+}
+
+void fn5() {
+ int l;
+ __asm__(""
+ : [g] "+r"(l)
+ : "[g]"(l)); // expected-error {{invalid input constraint '[g]' in asm}}
+}
+
+void fn6() {
+ int a;
+ __asm__(""
+ : "=rm"(a), "=rm"(a)
+ : "11m"(a)) // expected-error {{invalid input constraint '11m' in asm}}
+}
diff --git a/test/Sema/ast-print.c b/test/Sema/ast-print.c
index 382f0d389627..4b2b43190d42 100644
--- a/test/Sema/ast-print.c
+++ b/test/Sema/ast-print.c
@@ -39,3 +39,9 @@ int rvarr(int n, int a[restrict static n]) {
return a[2];
}
+typedef struct {
+ int f;
+} T __attribute__ ((__aligned__));
+
+// CHECK: struct __attribute__((visibility("default"))) S;
+struct __attribute__((visibility("default"))) S;
diff --git a/test/Sema/atomic-ops.c b/test/Sema/atomic-ops.c
index 320abc5ad479..e21c3fd58e80 100644
--- a/test/Sema/atomic-ops.c
+++ b/test/Sema/atomic-ops.c
@@ -1,11 +1,8 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only -triple=i686-linux-gnu -std=c11
+// RUN: %clang_cc1 %s -verify -ffreestanding -fsyntax-only -triple=i686-linux-gnu -std=c11
// Basic parsing/Sema tests for __c11_atomic_*
-typedef enum memory_order {
- memory_order_relaxed, memory_order_consume, memory_order_acquire,
- memory_order_release, memory_order_acq_rel, memory_order_seq_cst
-} memory_order;
+#include <stdatomic.h>
struct S { char c[3]; };
@@ -40,6 +37,14 @@ _Static_assert(__atomic_is_lock_free(8, 0), "");
_Static_assert(__atomic_is_lock_free(16, 0), ""); // expected-error {{not an integral constant expression}}
_Static_assert(__atomic_is_lock_free(17, 0), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(atomic_is_lock_free((atomic_char*)0), "");
+_Static_assert(atomic_is_lock_free((atomic_short*)0), "");
+_Static_assert(atomic_is_lock_free((atomic_int*)0), "");
+_Static_assert(atomic_is_lock_free((atomic_long*)0), "");
+// expected-error@+1 {{__int128 is not supported on this target}}
+_Static_assert(atomic_is_lock_free((_Atomic(__int128)*)0), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(atomic_is_lock_free(0 + (atomic_char*)0), "");
+
char i8;
short i16;
int i32;
@@ -171,6 +176,62 @@ void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d,
__c11_atomic_init(&const_atomic, 0); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
__c11_atomic_store(&const_atomic, 0, memory_order_release); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
__c11_atomic_load(&const_atomic, memory_order_acquire); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
+
+ // Ensure the <stdatomic.h> macros behave appropriately.
+ atomic_int n = ATOMIC_VAR_INIT(123);
+ atomic_init(&n, 456);
+ atomic_init(&n, (void*)0); // expected-warning {{passing 'void *' to parameter of type 'int'}}
+
+ const atomic_wchar_t cawt;
+ atomic_init(&cawt, L'x'); // expected-error {{non-const}}
+ atomic_wchar_t awt;
+ atomic_init(&awt, L'x');
+
+ int x = kill_dependency(12);
+
+ atomic_thread_fence(); // expected-error {{too few arguments to function call}}
+ atomic_thread_fence(memory_order_seq_cst);
+ atomic_signal_fence(memory_order_seq_cst);
+ void (*pfn)(memory_order) = &atomic_thread_fence;
+ pfn = &atomic_signal_fence;
+
+ int k = atomic_load_explicit(&n, memory_order_relaxed);
+ atomic_store_explicit(&n, k, memory_order_relaxed);
+ atomic_store(&n, atomic_load(&n));
+
+ k = atomic_exchange(&n, 72);
+ k = atomic_exchange_explicit(&n, k, memory_order_release);
+
+ atomic_compare_exchange_strong(&n, k, k); // expected-warning {{take the address with &}}
+ atomic_compare_exchange_weak(&n, &k, k);
+ atomic_compare_exchange_strong_explicit(&n, &k, k, memory_order_seq_cst); // expected-error {{too few arguments}}
+ atomic_compare_exchange_weak_explicit(&n, &k, k, memory_order_seq_cst, memory_order_acquire);
+
+ atomic_fetch_add(&k, n); // expected-error {{must be a pointer to _Atomic}}
+ k = atomic_fetch_add(&n, k);
+ k = atomic_fetch_sub(&n, k);
+ k = atomic_fetch_and(&n, k);
+ k = atomic_fetch_or(&n, k);
+ k = atomic_fetch_xor(&n, k);
+ k = atomic_fetch_add_explicit(&n, k, memory_order_acquire);
+ k = atomic_fetch_sub_explicit(&n, k, memory_order_release);
+ k = atomic_fetch_and_explicit(&n, k, memory_order_acq_rel);
+ k = atomic_fetch_or_explicit(&n, k, memory_order_consume);
+ k = atomic_fetch_xor_explicit(&n, k, memory_order_relaxed);
+
+ // C11 7.17.1/4: atomic_flag is a structure type.
+ struct atomic_flag must_be_struct = ATOMIC_FLAG_INIT;
+ // C11 7.17.8/5 implies that it is also a typedef type.
+ atomic_flag guard = ATOMIC_FLAG_INIT;
+ _Bool old_val = atomic_flag_test_and_set(&guard);
+ if (old_val) atomic_flag_clear(&guard);
+
+ old_val = (atomic_flag_test_and_set)(&guard);
+ if (old_val) (atomic_flag_clear)(&guard);
+
+ const atomic_flag const_guard;
+ atomic_flag_test_and_set(&const_guard); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const atomic_bool *' (aka 'const _Atomic(_Bool) *') invalid)}}
+ atomic_flag_clear(&const_guard); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const atomic_bool *' (aka 'const _Atomic(_Bool) *') invalid)}}
}
_Atomic(int*) PR12527_a;
@@ -403,3 +464,5 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
(void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_acq_rel, memory_order_relaxed);
(void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, memory_order_relaxed);
}
+
+
diff --git a/test/Sema/attr-bounded.c b/test/Sema/attr-bounded.c
index bf71fedf2d3f..3108fbdc4015 100644
--- a/test/Sema/attr-bounded.c
+++ b/test/Sema/attr-bounded.c
@@ -1,15 +1,15 @@
-// RUN: %clang_cc1 -fsyntax-only %s
-// Make sure OpenBSD's bounded extension is accepted.
-
-typedef long ssize_t;
-typedef unsigned long size_t;
-typedef struct FILE FILE;
-
-ssize_t read(int, void *, size_t)
- __attribute__((__bounded__(__buffer__,2,3)));
-int readlink(const char *, char *, size_t)
- __attribute__((__bounded__(__string__,2,3)));
-size_t fread(void *, size_t, size_t, FILE *)
- __attribute__((__bounded__(__size__,1,3,2)));
-char *getwd(char *)
- __attribute__((__bounded__(__minbytes__,1,1024))); \ No newline at end of file
+// RUN: %clang_cc1 -fsyntax-only %s
+// Make sure OpenBSD's bounded extension is accepted.
+
+typedef long ssize_t;
+typedef unsigned long size_t;
+typedef struct FILE FILE;
+
+ssize_t read(int, void *, size_t)
+ __attribute__((__bounded__(__buffer__,2,3)));
+int readlink(const char *, char *, size_t)
+ __attribute__((__bounded__(__string__,2,3)));
+size_t fread(void *, size_t, size_t, FILE *)
+ __attribute__((__bounded__(__size__,1,3,2)));
+char *getwd(char *)
+ __attribute__((__bounded__(__minbytes__,1,1024)));
diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c
index c9e3dd546c58..2e3e722942a0 100644
--- a/test/Sema/attr-deprecated.c
+++ b/test/Sema/attr-deprecated.c
@@ -121,6 +121,6 @@ struct test22 {
__attribute((deprecated)) foo_dep e, f;
};
-typedef int test23_ty __attribute((deprecated)); // expected-note {{previous definition is here}}
-typedef int test23_ty; // expected-note {{'test23_ty' has been explicitly marked deprecated here}} expected-warning {{redefinition of typedef 'test23_ty' is a C11 feature}}
+typedef int test23_ty __attribute((deprecated));
+typedef int test23_ty; // expected-note {{'test23_ty' has been explicitly marked deprecated here}}
test23_ty test23_v; // expected-warning {{'test23_ty' is deprecated}}
diff --git a/test/Sema/attr-flag-enum.c b/test/Sema/attr-flag-enum.c
new file mode 100644
index 000000000000..a53c1dc8e7d1
--- /dev/null
+++ b/test/Sema/attr-flag-enum.c
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -std=c11 -Wassign-enum %s
+
+enum __attribute__((flag_enum)) flag {
+ ea = 0x1,
+ eb = 0x2,
+ ec = 0x8,
+};
+
+enum __attribute__((flag_enum)) flag2 {
+ ga = 0x1,
+ gb = 0x4,
+
+ gc = 0x5, // no-warning
+ gd = 0x7, // expected-warning {{enumeration value 'gd' is out of range}}
+ ge = ~0x2, // expected-warning {{enumeration value 'ge' is out of range}}
+ gf = ~0x4, // no-warning
+ gg = ~0x1, // no-warning
+ gh = ~0x5, // no-warning
+ gi = ~0x11, // expected-warning {{enumeration value 'gi' is out of range}}
+};
+
+enum __attribute__((flag_enum)) flag3 {
+ fa = 0x1,
+ fb = ~0x1u, // no-warning
+};
+
+// What happens here is that ~0x2 is negative, and so the enum must be signed.
+// But ~0x1u is unsigned and has the high bit set, so the enum must be 64-bit.
+// The result is that ~0x1u does not have high bits set, and so it is considered
+// to be an invalid value. See Sema::IsValueInFlagEnum in SemaDecl.cpp for more
+// discussion.
+enum __attribute__((flag_enum)) flag4 {
+ ha = 0x1,
+ hb = 0x2,
+
+ hc = ~0x1u, // expected-warning {{enumeration value 'hc' is out of range}}
+ hd = ~0x2, // no-warning
+};
+
+void f(void) {
+ enum flag e = 0; // no-warning
+ e = 0x1; // no-warning
+ e = 0x3; // no-warning
+ e = 0xa; // no-warning
+ e = 0x4; // expected-warning {{integer constant not in range of enumerated type}}
+ e = 0xf; // expected-warning {{integer constant not in range of enumerated type}}
+ e = ~0; // no-warning
+ e = ~0x1; // no-warning
+ e = ~0x2; // no-warning
+ e = ~0x3; // no-warning
+ e = ~0x4; // expected-warning {{integer constant not in range of enumerated type}}
+
+ switch (e) {
+ case 0: break; // no-warning
+ case 0x1: break; // no-warning
+ case 0x3: break; // no-warning
+ case 0xa: break; // no-warning
+ case 0x4: break; // expected-warning {{case value not in enumerated type}}
+ case 0xf: break; // expected-warning {{case value not in enumerated type}}
+ case ~0: break; // expected-warning {{case value not in enumerated type}}
+ case ~0x1: break; // expected-warning {{case value not in enumerated type}}
+ case ~0x2: break; // expected-warning {{case value not in enumerated type}}
+ case ~0x3: break; // expected-warning {{case value not in enumerated type}}
+ case ~0x4: break; // expected-warning {{case value not in enumerated type}}
+ default: break;
+ }
+
+ enum flag2 f = ~0x1; // no-warning
+ f = ~0x1u; // no-warning
+
+ enum flag4 h = ~0x1; // no-warning
+ h = ~0x1u; // expected-warning {{integer constant not in range of enumerated type}}
+}
diff --git a/test/Sema/attr-msp430.c b/test/Sema/attr-msp430.c
index d08cd8ecc9ef..26b2d8fcfd65 100644
--- a/test/Sema/attr-msp430.c
+++ b/test/Sema/attr-msp430.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple msp430-unknown-unknown -fsyntax-only -verify %s
-
-int i;
-void f(void) __attribute__((interrupt(i))); /* expected-error {{'interrupt' attribute requires an integer constant}} */
-
-void f2(void) __attribute__((interrupt(12)));
+// RUN: %clang_cc1 -triple msp430-unknown-unknown -fsyntax-only -verify %s
+
+int i;
+void f(void) __attribute__((interrupt(i))); /* expected-error {{'interrupt' attribute requires an integer constant}} */
+
+void f2(void) __attribute__((interrupt(12)));
diff --git a/test/Sema/attr-naked.c b/test/Sema/attr-naked.c
index 55c6b326ef15..6b1344a9860b 100644
--- a/test/Sema/attr-naked.c
+++ b/test/Sema/attr-naked.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -verify -fsyntax-only -triple i686-pc-linux
int a __attribute__((naked)); // expected-warning {{'naked' attribute only applies to functions}}
@@ -10,3 +10,41 @@ void t1() __attribute__((naked));
void t2() __attribute__((naked(2))); // expected-error {{'naked' attribute takes no arguments}}
+__attribute__((naked)) int t3() { // expected-note{{attribute is here}}
+ return 42; // expected-error{{non-ASM statement in naked function is not supported}}
+}
+
+__attribute__((naked)) int t4() {
+ asm("movl $42, %eax");
+ asm("retl");
+}
+
+__attribute__((naked)) int t5(int x) {
+ asm("movl x, %eax");
+ asm("retl");
+}
+
+__attribute__((naked)) void t6() {
+ ;
+}
+
+__attribute__((naked)) void t7() {
+ asm("movl $42, %eax");
+ ;
+}
+
+extern int x, y;
+
+__attribute__((naked)) void t8(int z) { // expected-note{{attribute is here}}
+ __asm__ ("movl $42, %1"
+ : "=r"(x),
+ "=r"(z) // expected-error{{parameter references not allowed in naked functions}}
+ );
+}
+
+__attribute__((naked)) void t9(int z) { // expected-note{{attribute is here}}
+ __asm__ ("movl %eax, %1"
+ : : "r"(x),
+ "r"(z) // expected-error{{parameter references not allowed in naked functions}}
+ );
+}
diff --git a/test/Sema/attr-nonnull.c b/test/Sema/attr-nonnull.c
new file mode 100644
index 000000000000..f8de31716a80
--- /dev/null
+++ b/test/Sema/attr-nonnull.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+void f1(int *a1, int *a2, int *a3, int *a4, int *a5, int *a6, int *a7,
+ int *a8, int *a9, int *a10, int *a11, int *a12, int *a13, int *a14,
+ int *a15, int *a16) __attribute__((nonnull(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)));
+
+void f2(void) __attribute__((nonnull())); // expected-warning {{'nonnull' attribute applied to function with no pointer arguments}}
diff --git a/test/Sema/attr-ownership.c b/test/Sema/attr-ownership.c
index 2aa9f9f27cc9..d2e48c65a23c 100644
--- a/test/Sema/attr-ownership.c
+++ b/test/Sema/attr-ownership.c
@@ -17,3 +17,8 @@ void *f12(float i, int k, int f, int *j) __attribute__((ownership_returns(foo, 4
void f13(int *i, int *j) __attribute__((ownership_holds(foo, 1))) __attribute__((ownership_takes(foo, 2)));
void f14(int i, int j, int *k) __attribute__((ownership_holds(foo, 3))) __attribute__((ownership_takes(foo, 3))); // expected-error {{'ownership_holds' and 'ownership_takes' attributes are not compatible}}
+
+void f15(int, int)
+ __attribute__((ownership_returns(foo, 1))) // expected-note {{declared with index 1 here}}
+ __attribute__((ownership_returns(foo, 2))); // expected-error {{'ownership_returns' attribute index does not match; here it is 2}}
+void f16(int *i, int *j) __attribute__((ownership_holds(foo, 1))) __attribute__((ownership_holds(foo, 1))); // OK, same index
diff --git a/test/Sema/big-endian-neon-initializers.c b/test/Sema/big-endian-neon-initializers.c
index ffe310903bcf..c706d007509c 100644
--- a/test/Sema/big-endian-neon-initializers.c
+++ b/test/Sema/big-endian-neon-initializers.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple arm64_be -target-feature +neon -verify -fsyntax-only -ffreestanding
+// RUN: %clang_cc1 %s -triple aarch64_be -target-feature +neon -verify -fsyntax-only -ffreestanding
// RUN: %clang_cc1 %s -triple armebv7 -target-cpu cortex-a8 -verify -fsyntax-only -ffreestanding
#include <arm_neon.h>
diff --git a/test/Sema/bitfield.c b/test/Sema/bitfield.c
index ab05a7773d94..fb72213475ae 100644
--- a/test/Sema/bitfield.c
+++ b/test/Sema/bitfield.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c11 -Wno-unused-value
+
enum e0; // expected-note{{forward declaration of 'enum e0'}}
struct a {
@@ -54,3 +55,22 @@ void test4(struct Test4 *t) {
(void) sizeof(t->var ? t->bitX : t->bitY); // not a bitfield designator in C
(void) sizeof(t->var ? t->bitX : t->bitX); // not a bitfield designator in C
}
+
+typedef unsigned Unsigned;
+typedef signed Signed;
+
+struct Test5 { unsigned n : 2; } t5;
+typedef __typeof__(t5.n) Unsigned; // Bitfield is unsigned
+typedef __typeof__(+t5.n) Signed; // ... but promotes to signed.
+
+typedef __typeof__(t5.n + 0) Signed; // Arithmetic promotes.
+
+typedef __typeof__(+(t5.n = 0)) Signed; // FIXME: Assignment should not; the result
+typedef __typeof__(+(t5.n += 0)) Signed; // is a non-bit-field lvalue of type unsigned.
+typedef __typeof__(+(t5.n *= 0)) Signed;
+
+typedef __typeof__(+(++t5.n)) Signed; // FIXME: Increment is equivalent to compound-assignment.
+typedef __typeof__(+(--t5.n)) Signed; // This should not promote to signed.
+
+typedef __typeof__(+(t5.n++)) Unsigned; // Post-increment is underspecified, but seems to
+typedef __typeof__(+(t5.n--)) Unsigned; // also act like compound-assignment.
diff --git a/test/Sema/block-misc.c b/test/Sema/block-misc.c
index b4732b599c85..0ca4f20f3695 100644
--- a/test/Sema/block-misc.c
+++ b/test/Sema/block-misc.c
@@ -190,7 +190,7 @@ void test18() {
// rdar://7072507
int test19() {
- goto L0; // expected-error {{goto into protected scope}}
+ goto L0; // expected-error {{cannot jump}}
__block int x; // expected-note {{jump bypasses setup of __block variable}}
L0:
diff --git a/test/Sema/builtin-assume-aligned.c b/test/Sema/builtin-assume-aligned.c
new file mode 100644
index 000000000000..33c1b74488e1
--- /dev/null
+++ b/test/Sema/builtin-assume-aligned.c
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int test1(int *a) {
+ a = __builtin_assume_aligned(a, 32, 0ull);
+ return a[0];
+}
+
+int test2(int *a) {
+ a = __builtin_assume_aligned(a, 32, 0);
+ return a[0];
+}
+
+int test3(int *a) {
+ a = __builtin_assume_aligned(a, 32);
+ return a[0];
+}
+
+int test4(int *a) {
+ a = __builtin_assume_aligned(a, -32); // expected-error {{requested alignment is not a power of 2}}
+ // FIXME: The line below produces {{requested alignment is not a power of 2}}
+ // on i386-freebsd, but not on x86_64-linux (for example).
+ // a = __builtin_assume_aligned(a, 1ULL << 63);
+ return a[0];
+}
+
+int test5(int *a, unsigned *b) {
+ a = __builtin_assume_aligned(a, 32, b); // expected-warning {{incompatible pointer to integer conversion passing 'unsigned int *' to parameter of type}}
+ return a[0];
+}
+
+int test6(int *a) {
+ a = __builtin_assume_aligned(a, 32, 0, 0); // expected-error {{too many arguments to function call, expected at most 3, have 4}}
+ return a[0];
+}
+
+int test7(int *a) {
+ a = __builtin_assume_aligned(a, 31); // expected-error {{requested alignment is not a power of 2}}
+ return a[0];
+}
+
+int test8(int *a, int j) {
+ a = __builtin_assume_aligned(a, j); // expected-error {{must be a constant integer}}
+ return a[0];
+}
+
+void test_void_assume_aligned(void) __attribute__((assume_aligned(32))); // expected-warning {{'assume_aligned' attribute only applies to return values that are pointers}}
+int test_int_assume_aligned(void) __attribute__((assume_aligned(16))); // expected-warning {{'assume_aligned' attribute only applies to return values that are pointers}}
+void *test_ptr_assume_aligned(void) __attribute__((assume_aligned(64))); // no-warning
+
+int j __attribute__((assume_aligned(8))); // expected-warning {{'assume_aligned' attribute only applies to functions and methods}}
+void *test_no_fn_proto() __attribute__((assume_aligned(32))); // no-warning
+void *test_with_fn_proto(void) __attribute__((assume_aligned(128))); // no-warning
+
+void *test_no_fn_proto() __attribute__((assume_aligned(31))); // expected-error {{requested alignment is not a power of 2}}
+void *test_no_fn_proto() __attribute__((assume_aligned(32, 73))); // no-warning
+
+void *test_no_fn_proto() __attribute__((assume_aligned)); // expected-error {{'assume_aligned' attribute takes at least 1 argument}}
+void *test_no_fn_proto() __attribute__((assume_aligned())); // expected-error {{'assume_aligned' attribute takes at least 1 argument}}
+void *test_no_fn_proto() __attribute__((assume_aligned(32, 45, 37))); // expected-error {{'assume_aligned' attribute takes no more than 2 arguments}}
+
diff --git a/test/Sema/builtin-assume.c b/test/Sema/builtin-assume.c
index 1f6a3a0cd910..512eeeccdc4a 100644
--- a/test/Sema/builtin-assume.c
+++ b/test/Sema/builtin-assume.c
@@ -1,11 +1,18 @@
// RUN: %clang_cc1 -triple i386-mingw32 -fms-extensions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
int foo(int *a, int i) {
+#ifdef _MSC_VER
__assume(i != 4);
- __assume(++i > 2); //expected-warning {{the argument to __assume has side effects that will be discarded}}
+ __assume(++i > 2); //expected-warning {{the argument to '__assume' has side effects that will be discarded}}
int test = sizeof(struct{char qq[(__assume(i != 5), 7)];});
+#else
+ __builtin_assume(i != 4);
+ __builtin_assume(++i > 2); //expected-warning {{the argument to '__builtin_assume' has side effects that will be discarded}}
+ int test = sizeof(struct{char qq[(__builtin_assume(i != 5), 7)];});
+#endif
return a[i];
}
diff --git a/test/Sema/builtin-object-size.c b/test/Sema/builtin-object-size.c
index 0abc27ba187a..b1bda0652c14 100644
--- a/test/Sema/builtin-object-size.c
+++ b/test/Sema/builtin-object-size.c
@@ -23,6 +23,32 @@ int f3() {
// rdar://6252231 - cannot call vsnprintf with va_list on x86_64
void f4(const char *fmt, ...) {
__builtin_va_list args;
- __builtin___vsnprintf_chk (0, 42, 0, 11, fmt, args);
+ __builtin___vsnprintf_chk (0, 42, 0, 11, fmt, args); // expected-warning {{'__builtin___vsnprintf_chk' will always overflow destination buffer}}
}
+// rdar://18334276
+typedef __typeof__(sizeof(int)) size_t;
+void * memcset(void *restrict dst, int src, size_t n);
+void * memcpy(void *restrict dst, const void *restrict src, size_t n);
+
+#define memset(dest, src, len) __builtin___memset_chk(dest, src, len, __builtin_object_size(dest, 0))
+#define memcpy(dest, src, len) __builtin___memcpy_chk(dest, src, len, __builtin_object_size(dest, 0))
+#define memcpy1(dest, src, len) __builtin___memcpy_chk(dest, src, len, __builtin_object_size(dest, 4))
+#define NULL ((void *)0)
+
+void f5(void)
+{
+ char buf[10];
+ memset((void *)0x100000000ULL, 0, 0x1000);
+ memcpy((char *)NULL + 0x10000, buf, 0x10);
+ memcpy1((char *)NULL + 0x10000, buf, 0x10); // expected-error {{argument should be a value from 0 to 3}}
+}
+
+// rdar://18431336
+void f6(void)
+{
+ char b[5];
+ char buf[10];
+ __builtin___memccpy_chk (buf, b, '\0', sizeof(b), __builtin_object_size (buf, 0));
+ __builtin___memccpy_chk (b, buf, '\0', sizeof(buf), __builtin_object_size (b, 0)); // expected-warning {{'__builtin___memccpy_chk' will always overflow destination buffer}}
+}
diff --git a/test/Sema/builtins-arm.c b/test/Sema/builtins-arm.c
index 6c367d35a5f5..37604dc8bd43 100644
--- a/test/Sema/builtins-arm.c
+++ b/test/Sema/builtins-arm.c
@@ -30,6 +30,7 @@ void test2() {
__builtin_va_list ptr = "x";
*ptr = '0'; // expected-error {{incomplete type 'void' is not assignable}}
}
+#endif
void test3() {
__builtin_arm_dsb(16); // expected-error {{argument should be a value from 0 to 15}}
@@ -37,4 +38,11 @@ void test3() {
__builtin_arm_isb(18); // expected-error {{argument should be a value from 0 to 15}}
}
-#endif
+void test4() {
+ __builtin_arm_prefetch(0, 2, 0); // expected-error {{argument should be a value from 0 to 1}}
+ __builtin_arm_prefetch(0, 0, 2); // expected-error {{argument should be a value from 0 to 1}}
+}
+
+void test5() {
+ __builtin_arm_dbg(16); // expected-error {{argument should be a value from 0 to 15}}
+}
diff --git a/test/Sema/builtins-arm64.c b/test/Sema/builtins-arm64.c
index 113f4fc302da..2779984680f4 100644
--- a/test/Sema/builtins-arm64.c
+++ b/test/Sema/builtins-arm64.c
@@ -22,3 +22,10 @@ void test_memory_barriers() {
__builtin_arm_dsb(17); // expected-error {{argument should be a value from 0 to 15}}
__builtin_arm_isb(18); // expected-error {{argument should be a value from 0 to 15}}
}
+
+void test_prefetch() {
+ __builtin_arm_prefetch(0, 2, 0, 0, 0); // expected-error {{argument should be a value from 0 to 1}}
+ __builtin_arm_prefetch(0, 0, 3, 0, 0); // expected-error {{argument should be a value from 0 to 2}}
+ __builtin_arm_prefetch(0, 0, 0, 2, 0); // expected-error {{argument should be a value from 0 to 1}}
+ __builtin_arm_prefetch(0, 0, 0, 0, 2); // expected-error {{argument should be a value from 0 to 1}}
+}
diff --git a/test/Sema/builtins-x86.c b/test/Sema/builtins-x86.c
new file mode 100644
index 000000000000..9929e6135c00
--- /dev/null
+++ b/test/Sema/builtins-x86.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -fsyntax-only -verify %s
+
+typedef float __m128 __attribute__((__vector_size__(16)));
+typedef double __m128d __attribute__((__vector_size__(16)));
+
+__m128 test__builtin_ia32_cmpps(__m128 __a, __m128 __b) {
+ __builtin_ia32_cmpps(__a, __b, 32); // expected-error {{argument should be a value from 0 to 31}}
+}
+
+__m128d test__builtin_ia32_cmppd(__m128d __a, __m128d __b) {
+ __builtin_ia32_cmppd(__a, __b, 32); // expected-error {{argument should be a value from 0 to 31}}
+}
+
+__m128 test__builtin_ia32_cmpss(__m128 __a, __m128 __b) {
+ __builtin_ia32_cmpss(__a, __b, 32); // expected-error {{argument should be a value from 0 to 31}}
+}
+
+__m128d test__builtin_ia32_cmpsd(__m128d __a, __m128d __b) {
+ __builtin_ia32_cmpsd(__a, __b, 32); // expected-error {{argument should be a value from 0 to 31}}
+}
diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
index 7647100bc270..0e2925e0748d 100644
--- a/test/Sema/builtins.c
+++ b/test/Sema/builtins.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wno-string-plus-int -triple=i686-apple-darwin9
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wstrlcpy-strlcat-size -Wno-string-plus-int -triple=i686-apple-darwin9
// This test needs to set the target because it uses __builtin_ia32_vec_ext_v4si
int test1(float a, int b) {
@@ -66,6 +66,11 @@ void test9_3(volatile int* ptr, int val) {
__sync_fetch_and_add_4(ptr, val);
}
+void test9_4(volatile int* ptr, int val) {
+ // expected-warning@+1 {{the semantics of this intrinsic changed with GCC version 4.4 - the newer semantics are provided here}}
+ __sync_fetch_and_nand(ptr, val);
+}
+
// rdar://7236819
void test10(void) __attribute__((noreturn));
@@ -184,12 +189,12 @@ void test18() {
void *ptr;
ptr = __builtin___memccpy_chk(dst, src, '\037', sizeof(src), sizeof(dst));
- result = __builtin___strlcpy_chk(dst, src, sizeof(src), sizeof(dst));
- result = __builtin___strlcat_chk(dst, src, sizeof(src), sizeof(dst));
+ result = __builtin___strlcpy_chk(dst, src, sizeof(dst), sizeof(dst));
+ result = __builtin___strlcat_chk(dst, src, sizeof(dst), sizeof(dst));
ptr = __builtin___memccpy_chk(dst, src, '\037', sizeof(src)); // expected-error {{too few arguments to function call}}
- ptr = __builtin___strlcpy_chk(dst, src, sizeof(src), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}}
- ptr = __builtin___strlcat_chk(dst, src, sizeof(src), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}}
+ ptr = __builtin___strlcpy_chk(dst, src, sizeof(dst), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}}
+ ptr = __builtin___strlcat_chk(dst, src, sizeof(dst), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}}
}
void no_ms_builtins() {
@@ -202,3 +207,44 @@ void unavailable() {
__builtin_operator_new(0); // expected-error {{'__builtin_operator_new' is only available in C++}}
__builtin_operator_delete(0); // expected-error {{'__builtin_operator_delete' is only available in C++}}
}
+
+// rdar://18259539
+size_t strlcpy(char * restrict dst, const char * restrict src, size_t size);
+size_t strlcat(char * restrict dst, const char * restrict src, size_t size);
+
+void Test19(void)
+{
+ static char b[40];
+ static char buf[20];
+
+ strlcpy(buf, b, sizeof(b)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} \\
+ // expected-note {{change size argument to be the size of the destination}}
+ __builtin___strlcpy_chk(buf, b, sizeof(b), __builtin_object_size(buf, 0)); // expected-warning {{size argument in '__builtin___strlcpy_chk' call appears to be size of the source; expected the size of the destination}} \
+ // expected-note {{change size argument to be the size of the destination}} \
+ // expected-warning {{'__builtin___strlcpy_chk' will always overflow destination buffer}}
+
+ strlcat(buf, b, sizeof(b)); // expected-warning {{size argument in 'strlcat' call appears to be size of the source; expected the size of the destination}} \
+ // expected-note {{change size argument to be the size of the destination}}
+
+ __builtin___strlcat_chk(buf, b, sizeof(b), __builtin_object_size(buf, 0)); // expected-warning {{size argument in '__builtin___strlcat_chk' call appears to be size of the source; expected the size of the destination}} \
+ // expected-note {{change size argument to be the size of the destination}} \
+ // expected-warning {{'__builtin___strlcat_chk' will always overflow destination buffer}}
+}
+
+// rdar://11076881
+char * Test20(char *p, const char *in, unsigned n)
+{
+ static char buf[10];
+
+ __builtin___memcpy_chk (&buf[6], in, 5, __builtin_object_size (&buf[6], 0)); // expected-warning {{'__builtin___memcpy_chk' will always overflow destination buffer}}
+
+ __builtin___memcpy_chk (p, "abcde", n, __builtin_object_size (p, 0));
+
+ __builtin___memcpy_chk (&buf[5], "abcde", 5, __builtin_object_size (&buf[5], 0));
+
+ __builtin___memcpy_chk (&buf[5], "abcde", n, __builtin_object_size (&buf[5], 0));
+
+ __builtin___memcpy_chk (&buf[6], "abcde", 5, __builtin_object_size (&buf[6], 0)); // expected-warning {{'__builtin___memcpy_chk' will always overflow destination buffer}}
+
+ return buf;
+}
diff --git a/test/Sema/call-with-static-chain.c b/test/Sema/call-with-static-chain.c
new file mode 100644
index 000000000000..4a076d2ecf9b
--- /dev/null
+++ b/test/Sema/call-with-static-chain.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+
+void f();
+
+void g() {
+ __builtin_call_with_static_chain(f(), f);
+ __builtin_call_with_static_chain(f, f); // expected-error {{first argument to __builtin_call_with_static_chain must be a non-member call expression}}
+ __builtin_call_with_static_chain(^{}(), f); // expected-error {{first argument to __builtin_call_with_static_chain must not be a block call}}
+ __builtin_call_with_static_chain(__builtin_unreachable(), f); // expected-error {{first argument to __builtin_call_with_static_chain must not be a builtin call}}
+ __builtin_call_with_static_chain(f(), 42); // expected-error {{second argument to __builtin_call_with_static_chain must be of pointer type}}
+}
diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c
index f9fa9fef2b36..6a8be5ae050f 100644
--- a/test/Sema/callingconv.c
+++ b/test/Sema/callingconv.c
@@ -10,7 +10,7 @@ void __attribute__((stdcall)) bar(float *a) {
void __attribute__((fastcall(1))) baz(float *a) { // expected-error {{'fastcall' attribute takes no arguments}}
}
-void __attribute__((fastcall)) test0() { // expected-error {{function with no prototype cannot use fastcall calling convention}}
+void __attribute__((fastcall)) test0() {
}
void __attribute__((fastcall)) test1(void) {
diff --git a/test/Sema/constructor-attribute.c b/test/Sema/constructor-attribute.c
index 1bb69fc4aa56..3a537d424ba0 100644
--- a/test/Sema/constructor-attribute.c
+++ b/test/Sema/constructor-attribute.c
@@ -5,6 +5,7 @@ int f() __attribute__((constructor));
int f() __attribute__((constructor(1)));
int f() __attribute__((constructor(1,2))); // expected-error {{'constructor' attribute takes no more than 1 argument}}
int f() __attribute__((constructor(1.0))); // expected-error {{'constructor' attribute requires an integer constant}}
+int f() __attribute__((constructor(0x100000000))); // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
int x __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to functions}}
int f() __attribute__((destructor));
diff --git a/test/Sema/decl-microsoft-call-conv.c b/test/Sema/decl-microsoft-call-conv.c
new file mode 100644
index 000000000000..5a83b38b192f
--- /dev/null
+++ b/test/Sema/decl-microsoft-call-conv.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple i686-pc-win32 -verify %s
+
+// It's important that this is a .c file.
+
+// This is fine, as CrcGenerateTable*() has a prototype.
+void __fastcall CrcGenerateTableFastcall(void);
+void __fastcall CrcGenerateTableFastcall();
+void __fastcall CrcGenerateTableFastcall() {}
+void __stdcall CrcGenerateTableStdcall(void);
+void __stdcall CrcGenerateTableStdcall();
+void __stdcall CrcGenerateTableStdcall() {}
+void __thiscall CrcGenerateTableThiscall(void);
+void __thiscall CrcGenerateTableThiscall();
+void __thiscall CrcGenerateTableThiscall() {}
+void __pascal CrcGenerateTablePascal(void);
+void __pascal CrcGenerateTablePascal();
+void __pascal CrcGenerateTablePascal() {}
+void __vectorcall CrcGenerateTableVectorcall(void);
+void __vectorcall CrcGenerateTableVectorcall();
+void __vectorcall CrcGenerateTableVectorcall() {}
+
+void __fastcall CrcGenerateTableNoProtoFastcall(); // expected-error{{function with no prototype cannot use the fastcall calling convention}}
+void __stdcall CrcGenerateTableNoProtoStdcall(); // expected-warning{{function with no prototype cannot use the stdcall calling convention}}
+void __thiscall CrcGenerateTableNoProtoThiscall(); // expected-error{{function with no prototype cannot use the thiscall calling convention}}
+void __pascal CrcGenerateTableNoProtoPascal(); // expected-error{{function with no prototype cannot use the pascal calling convention}}
+void __vectorcall CrcGenerateTableNoProtoVectorcall(); // expected-error{{function with no prototype cannot use the vectorcall calling convention}}
+
+void __fastcall CrcGenerateTableNoProtoDefFastcall() {}
+void __stdcall CrcGenerateTableNoProtoDefStdcall() {}
+void __thiscall CrcGenerateTableNoProtoDefThiscall() {}
+void __pascal CrcGenerateTableNoProtoDefPascal() {}
+void __vectorcall CrcGenerateTableNoProtoDefVectorcall() {}
+
+// Regular calling convention is fine.
+void CrcGenerateTableNoProto() {}
diff --git a/test/Sema/dllexport.c b/test/Sema/dllexport.c
index 6c71ad82987b..76b6f6dc5a0e 100644
--- a/test/Sema/dllexport.c
+++ b/test/Sema/dllexport.c
@@ -49,6 +49,9 @@ __declspec(dllexport) extern int GlobalRedecl4; // expected-warning{{redeclarati
// External linkage is required.
__declspec(dllexport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage when declared 'dllexport'}}
+// Thread local variables are invalid.
+__declspec(dllexport) __thread int ThreadLocalGlobal; // expected-error{{'ThreadLocalGlobal' cannot be thread local when declared 'dllexport'}}
+
// Export in local scope.
void functionScope() {
__declspec(dllexport) int LocalVarDecl; // expected-error{{'LocalVarDecl' must have external linkage when declared 'dllexport'}}
diff --git a/test/Sema/dllimport.c b/test/Sema/dllimport.c
index 706b0b697707..ac883822dea1 100644
--- a/test/Sema/dllimport.c
+++ b/test/Sema/dllimport.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i686-win32 -fsyntax-only -verify -std=c99 %s
-// RUN: %clang_cc1 -triple x86_64-win32 -fsyntax-only -verify -std=c11 %s
-// RUN: %clang_cc1 -triple i686-mingw32 -fsyntax-only -verify -std=c11 %s
-// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -verify -std=c99 %s
+// RUN: %clang_cc1 -triple i686-win32 -fsyntax-only -verify -std=c99 -DMS %s
+// RUN: %clang_cc1 -triple x86_64-win32 -fsyntax-only -verify -std=c11 -DMS %s
+// RUN: %clang_cc1 -triple i686-mingw32 -fsyntax-only -verify -std=c11 -DGNU %s
+// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -verify -std=c99 -DGNU %s
// Invalid usage.
__declspec(dllimport) typedef int typedef1; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
@@ -77,10 +77,14 @@ __declspec(dllimport) extern int GlobalRedecl5; // expected-warning{{redeclarati
// External linkage is required.
__declspec(dllimport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage when declared 'dllimport'}}
+// Thread local variables are invalid.
+__declspec(dllimport) __thread int ThreadLocalGlobal; // expected-error{{'ThreadLocalGlobal' cannot be thread local when declared 'dllimport'}}
+
// Import in local scope.
__declspec(dllimport) float LocalRedecl1; // expected-note{{previous definition is here}}
__declspec(dllimport) float LocalRedecl2; // expected-note{{previous definition is here}}
__declspec(dllimport) float LocalRedecl3; // expected-note{{previous definition is here}}
+__declspec(dllimport) float LocalRedecl4;
void functionScope() {
__declspec(dllimport) int LocalRedecl1; // expected-error{{redefinition of 'LocalRedecl1' with a different type: 'int' vs 'float'}}
int *__attribute__((dllimport)) LocalRedecl2; // expected-error{{redefinition of 'LocalRedecl2' with a different type: 'int *' vs 'float'}}
@@ -91,6 +95,9 @@ void functionScope() {
__declspec(dllimport) extern int ExternLocalVarDecl;
__declspec(dllimport) extern int ExternLocalVarDef = 1; // expected-error{{definition of dllimport data}}
__declspec(dllimport) static int StaticLocalVar; // expected-error{{'StaticLocalVar' must have external linkage when declared 'dllimport'}}
+
+ // Local extern redeclaration does not drop the attribute.
+ extern float LocalRedecl4;
}
@@ -115,6 +122,10 @@ void (*FunForInit)() = &decl2A;
__declspec(dllimport) void def() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
// Import inline function.
+#ifdef GNU
+// expected-warning@+3{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+3{{'dllimport' attribute ignored on inline function}}
+#endif
__declspec(dllimport) inline void inlineFunc1() {}
inline void __attribute__((dllimport)) inlineFunc2() {}
@@ -139,12 +150,21 @@ __declspec(dllimport) void redecl4(); // expected-error{{redeclaration of 'redec
__declspec(dllimport) void redecl5(); // expected-warning{{redeclaration of 'redecl5' should not add 'dllimport' attribute}}
-// Inline redeclarations are fine.
+// Inline redeclarations.
+#ifdef GNU
+// expected-warning@+3{{'redecl6' redeclared inline; 'dllimport' attribute ignored}}
+#endif
__declspec(dllimport) void redecl6();
inline void redecl6() {}
- void redecl7(); // expected-note{{previous declaration is here}}
-__declspec(dllimport) inline void redecl7() {} // expected-warning{{redeclaration of 'redecl7' should not add 'dllimport' attribute}}
+#ifdef MS
+// expected-note@+5{{previous declaration is here}}
+// expected-warning@+5{{redeclaration of 'redecl7' should not add 'dllimport' attribute}}
+#else
+// expected-warning@+3{{'dllimport' attribute ignored on inline function}}
+#endif
+ void redecl7();
+__declspec(dllimport) inline void redecl7() {}
// External linkage is required.
__declspec(dllimport) static int staticFunc(); // expected-error{{'staticFunc' must have external linkage when declared 'dllimport'}}
diff --git a/test/Sema/expr-comma-c99.c b/test/Sema/expr-comma-c99.c
index 02886bff053f..934c81cfa0b0 100644
--- a/test/Sema/expr-comma-c99.c
+++ b/test/Sema/expr-comma-c99.c
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c99 -Wno-sizeof-array-decay
-// expected-no-diagnostics
// rdar://6095180
struct s { char c[17]; };
@@ -14,5 +13,5 @@ int B[sizeof((a.c)) == 17 ? 1 : -1];
// comma does array/function promotion in c99.
int X[sizeof(0, (foo().c)) == sizeof(char*) ? 1 : -1];
int Y[sizeof(0, (a,b).c) == sizeof(char*) ? 1 : -1];
-int Z[sizeof(0, (a=b).c) == sizeof(char*) ? 1 : -1];
+int Z[sizeof(0, (a=b).c) == sizeof(char*) ? 1 : -1]; // expected-warning {{expression with side effects has no effect in an unevaluated context}}
diff --git a/test/Sema/expr-comma.c b/test/Sema/expr-comma.c
index e2beafe236c2..04e57dec3acc 100644
--- a/test/Sema/expr-comma.c
+++ b/test/Sema/expr-comma.c
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c89 -Wno-sizeof-array-decay
-// expected-no-diagnostics
// rdar://6095180
struct s { char c[17]; };
@@ -15,4 +14,4 @@ int B[sizeof((a.c)) == 17 ? 1 : -1];
int W[sizeof(0, a.c) == sizeof(char*) ? 1 : -1];
int X[sizeof(0, (foo().c)) == 17 ? 1 : -1];
int Y[sizeof(0, (a,b).c) == 17 ? 1 : -1];
-int Z[sizeof(0, (a=b).c) == 17 ? 1 : -1];
+int Z[sizeof(0, (a=b).c) == 17 ? 1 : -1]; // expected-warning {{expression with side effects has no effect in an unevaluated context}}
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index 2fb17e4880c6..17b1aa2851b0 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -244,6 +244,10 @@ void test22() {
if ("help")
(void) 0;
- if (test22)
+ if (test22) // expected-warning {{address of function 'test22' will always evaluate to 'true'}} \
+ // expected-note {{prefix with the address-of operator to silence this warning}}
+ (void) 0;
+
+ if (&test22)
(void) 0;
}
diff --git a/test/Sema/format-strings-gnu.c b/test/Sema/format-strings-gnu.c
index f4910856b00f..fc524e93ed48 100644
--- a/test/Sema/format-strings-gnu.c
+++ b/test/Sema/format-strings-gnu.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple i386-apple-darwin9 %s
// RUN: %clang_cc1 -fsyntax-only -verify -triple thumbv6-apple-ios4.0 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-mingw32 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-pc-win32 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-mingw32 -DMS %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-pc-win32 -DMS %s
// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux-gnu -DALLOWED %s
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-unknown-freebsd -DALLOWED %s
@@ -23,6 +23,10 @@ void test() {
// expected-warning@-6 {{length modifier 'L' results in undefined behavior or no effect with 'd' conversion specifier}}
// expected-note@-7 {{did you mean to use 'll'?}}
#endif
+
+#ifndef MS
+ printf("%Z\n", quiteLong); // expected-warning{{invalid conversion specifier 'Z'}}
+#endif
}
void testAlwaysInvalid() {
diff --git a/test/Sema/format-strings-ms.c b/test/Sema/format-strings-ms.c
index 2ad8eae033d5..42676e7a4e06 100644
--- a/test/Sema/format-strings-ms.c
+++ b/test/Sema/format-strings-ms.c
@@ -1,25 +1,88 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -triple=i386-pc-win32 -Wformat-non-iso %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -triple=i386-pc-win32 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -triple=i386-pc-win32 -Wformat-non-iso -DNON_ISO_WARNING %s
int printf(const char *format, ...) __attribute__((format(printf, 1, 2)));
+int scanf(const char * restrict, ...) ;
+typedef unsigned short wchar_t;
+
+#ifdef NON_ISO_WARNING
+
+// Split off this test to reduce the warning noise in the rest of the file.
+void non_iso_warning_test(__int32 i32, __int64 i64, wchar_t c, void *p) {
+ printf("%Id", i32); // expected-warning{{'I' length modifier is not supported by ISO C}}
+ printf("%I32d", i32); // expected-warning{{'I32' length modifier is not supported by ISO C}}
+ printf("%I64d", i64); // expected-warning{{'I64' length modifier is not supported by ISO C}}
+ printf("%wc", c); // expected-warning{{'w' length modifier is not supported by ISO C}}
+ printf("%Z", p); // expected-warning{{'Z' conversion specifier is not supported by ISO C}}
+}
+
+#else
void signed_test() {
short val = 30;
- printf("val = %I64d\n", val); // expected-warning{{'I64' length modifier is not supported by ISO C}} \
- // expected-warning{{format specifies type '__int64' (aka 'long long') but the argument has type 'short'}}
+ printf("val = %I64d\n", val); // expected-warning{{format specifies type '__int64' (aka 'long long') but the argument has type 'short'}}
long long bigval = 30;
- printf("val = %I32d\n", bigval); // expected-warning{{'I32' length modifier is not supported by ISO C}} \
- // expected-warning{{format specifies type '__int32' (aka 'int') but the argument has type 'long long'}}
- printf("val = %Id\n", bigval); // expected-warning{{'I' length modifier is not supported by ISO C}} \
- // expected-warning{{format specifies type '__int32' (aka 'int') but the argument has type 'long long'}}
+ printf("val = %I32d\n", bigval); // expected-warning{{format specifies type '__int32' (aka 'int') but the argument has type 'long long'}}
+ printf("val = %Id\n", bigval); // expected-warning{{format specifies type '__int32' (aka 'int') but the argument has type 'long long'}}
}
void unsigned_test() {
unsigned short val = 30;
- printf("val = %I64u\n", val); // expected-warning{{'I64' length modifier is not supported by ISO C}} \
- // expected-warning{{format specifies type 'unsigned __int64' (aka 'unsigned long long') but the argument has type 'unsigned short'}}
+ printf("val = %I64u\n", val); // expected-warning{{format specifies type 'unsigned __int64' (aka 'unsigned long long') but the argument has type 'unsigned short'}}
unsigned long long bigval = 30;
- printf("val = %I32u\n", bigval); // expected-warning{{'I32' length modifier is not supported by ISO C}} \
- // expected-warning{{format specifies type 'unsigned __int32' (aka 'unsigned int') but the argument has type 'unsigned long long'}}
- printf("val = %Iu\n", bigval); // expected-warning{{'I' length modifier is not supported by ISO C}} \
- // expected-warning{{format specifies type 'unsigned __int32' (aka 'unsigned int') but the argument has type 'unsigned long long'}}
+ printf("val = %I32u\n", bigval); // expected-warning{{format specifies type 'unsigned __int32' (aka 'unsigned int') but the argument has type 'unsigned long long'}}
+ printf("val = %Iu\n", bigval); // expected-warning{{format specifies type 'unsigned __int32' (aka 'unsigned int') but the argument has type 'unsigned long long'}}
}
+
+void w_test(wchar_t c, wchar_t *s) {
+ printf("%wc", c);
+ printf("%wC", c);
+ printf("%C", c);
+ printf("%ws", s);
+ printf("%wS", s);
+ printf("%S", s);
+ scanf("%wc", &c);
+ scanf("%wC", &c);
+ scanf("%C", &c);
+ scanf("%ws", s);
+ scanf("%wS", s);
+ scanf("%S", s);
+
+ double bad;
+ printf("%wc", bad); // expected-warning{{format specifies type 'wint_t' (aka 'int') but the argument has type 'double'}}
+ printf("%wC", bad); // expected-warning{{format specifies type 'wchar_t' (aka 'unsigned short') but the argument has type 'double'}}
+ printf("%C", bad); // expected-warning{{format specifies type 'wchar_t' (aka 'unsigned short') but the argument has type 'double'}}
+ printf("%ws", bad); // expected-warning{{format specifies type 'wchar_t *' (aka 'unsigned short *') but the argument has type 'double'}}
+ printf("%wS", bad); // expected-warning{{format specifies type 'wchar_t *' (aka 'unsigned short *') but the argument has type 'double'}}
+ printf("%S", bad); // expected-warning{{format specifies type 'wchar_t *' (aka 'unsigned short *') but the argument has type 'double'}}
+ scanf("%wc", &bad); // expected-warning{{format specifies type 'wchar_t *' (aka 'unsigned short *') but the argument has type 'double *'}}
+ scanf("%wC", &bad); // expected-warning{{format specifies type 'wchar_t *' (aka 'unsigned short *') but the argument has type 'double *'}}
+ scanf("%C", &bad); // expected-warning{{format specifies type 'wchar_t *' (aka 'unsigned short *') but the argument has type 'double *'}}
+ scanf("%ws", &bad); // expected-warning{{format specifies type 'wchar_t *' (aka 'unsigned short *') but the argument has type 'double *'}}
+ scanf("%wS", &bad); // expected-warning{{format specifies type 'wchar_t *' (aka 'unsigned short *') but the argument has type 'double *'}}
+ scanf("%S", &bad); // expected-warning{{format specifies type 'wchar_t *' (aka 'unsigned short *') but the argument has type 'double *'}}
+
+}
+
+void h_test(char c, char* s) {
+ double bad;
+ printf("%hc", bad); // expected-warning{{format specifies type 'int' but the argument has type 'double'}}
+ printf("%hC", bad); // expected-warning{{format specifies type 'int' but the argument has type 'double'}}
+ printf("%hs", bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double'}}
+ printf("%hS", bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double'}}
+ scanf("%hc", &bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double *'}}
+ scanf("%hC", &bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double *'}}
+ scanf("%hs", &bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double *'}}
+ scanf("%hS", &bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double *'}}
+}
+
+void z_test(void *p) {
+ printf("%Z", p);
+ printf("%hZ", p);
+ printf("%lZ", p);
+ printf("%wZ", p);
+ printf("%hhZ", p); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 'Z' conversion specifier}}
+ scanf("%Z", p); // expected-warning{{invalid conversion specifier 'Z'}}
+}
+
+#endif
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index e31644a98756..0d827e400d7e 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -217,7 +217,7 @@ void test10(int x, float f, int i, long long lli) {
printf("%**\n"); // expected-warning{{invalid conversion specifier '*'}}
printf("%d%d\n", x); // expected-warning{{more '%' conversions than data arguments}}
printf("%d\n", x, x); // expected-warning{{data argument not used by format string}}
- printf("%W%d%Z\n", x, x, x); // expected-warning{{invalid conversion specifier 'W'}} expected-warning{{invalid conversion specifier 'Z'}}
+ printf("%W%d\n", x, x); // expected-warning{{invalid conversion specifier 'W'}}
printf("%"); // expected-warning{{incomplete format specifier}}
printf("%.d", x); // no-warning
printf("%.", x); // expected-warning{{incomplete format specifier}}
diff --git a/test/Sema/gnu-attributes.c b/test/Sema/gnu-attributes.c
new file mode 100644
index 000000000000..653fae826a74
--- /dev/null
+++ b/test/Sema/gnu-attributes.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+struct s {};
+
+// FIXME: should warn that declaration attribute in type position is
+// being applied to the declaration instead?
+struct s __attribute__((used)) foo;
+
+// FIXME: Should warn that type attribute in declaration position is
+// being applied to the type instead?
+struct s *bar __attribute__((address_space(1)));
+
+// Should not warn because type attribute is in type position.
+struct s *__attribute__((address_space(1))) baz;
+
+// Should not warn because declaration attribute is in declaration position.
+struct s *quux __attribute__((used));
diff --git a/test/Sema/inline-asm-validate-aarch64.c b/test/Sema/inline-asm-validate-aarch64.c
new file mode 100644
index 000000000000..1364b6421eb0
--- /dev/null
+++ b/test/Sema/inline-asm-validate-aarch64.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple arm64-apple-darwin -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+typedef unsigned char uint8_t;
+
+uint8_t constraint_r(uint8_t *addr) {
+ uint8_t byte;
+
+ __asm__ volatile("ldrb %0, [%1]" : "=r" (byte) : "r" (addr) : "memory");
+// CHECK: warning: value size does not match register size specified by the constraint and modifier
+// CHECK: note: use constraint modifier "w"
+// CHECK: fix-it:{{.*}}:{8:26-8:28}:"%w0"
+
+ return byte;
+}
+
+uint8_t constraint_r_symbolic(uint8_t *addr) {
+ uint8_t byte;
+
+ __asm__ volatile("ldrb %[s0], [%[s1]]" : [s0] "=r" (byte) : [s1] "r" (addr) : "memory");
+// CHECK: warning: value size does not match register size specified by the constraint and modifier
+// CHECK: note: use constraint modifier "w"
+// CHECK: fix-it:{{.*}}:{19:26-19:31}:"%w[s0]"
+
+ return byte;
+}
+
+#define PERCENT "%"
+
+uint8_t constraint_r_symbolic_macro(uint8_t *addr) {
+ uint8_t byte;
+
+ __asm__ volatile("ldrb "PERCENT"[s0], [%[s1]]" : [s0] "=r" (byte) : [s1] "r" (addr) : "memory");
+// CHECK: warning: value size does not match register size specified by the constraint and modifier
+// CHECK: note: use constraint modifier "w"
+// CHECK-NOT: fix-it
+
+ return byte;
+}
diff --git a/test/Sema/inline-asm-validate-x86.c b/test/Sema/inline-asm-validate-x86.c
new file mode 100644
index 000000000000..174deca80b43
--- /dev/null
+++ b/test/Sema/inline-asm-validate-x86.c
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -triple i686 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify %s
+
+void I(int i, int j) {
+ static const int BelowMin = -1;
+ static const int AboveMax = 32;
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "I"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'I'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "I"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'I'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "I"(AboveMax)); // expected-error{{value '32' out of range for constraint 'I'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "I"(16)); // expected-no-error
+}
+
+void J(int i, int j) {
+ static const int BelowMin = -1;
+ static const int AboveMax = 64;
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "J"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'J'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "J"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'J'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "J"(AboveMax)); // expected-error{{value '64' out of range for constraint 'J'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "J"(32)); // expected-no-error
+}
+
+void K(int i, int j) {
+ static const int BelowMin = -129;
+ static const int AboveMax = 128;
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "K"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'K'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "K"(BelowMin)); // expected-error{{value '-129' out of range for constraint 'K'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "K"(AboveMax)); // expected-error{{value '128' out of range for constraint 'K'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "K"(96)); // expected-no-error
+}
+
+void M(int i, int j) {
+ static const int BelowMin = -1;
+ static const int AboveMax = 4;
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "M"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'M'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "M"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'M'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "M"(AboveMax)); // expected-error{{value '4' out of range for constraint 'M'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "M"(2)); // expected-no-error
+}
+
+void N(int i, int j) {
+ static const int BelowMin = -1;
+ static const int AboveMax = 256;
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "N"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'N'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "N"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'N'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "N"(AboveMax)); // expected-error{{value '256' out of range for constraint 'N'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "N"(128)); // expected-no-error
+}
+
+void O(int i, int j) {
+ static const int BelowMin = -1;
+ static const int AboveMax = 128;
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "O"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'O'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "O"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'O'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "O"(AboveMax)); // expected-error{{value '128' out of range for constraint 'O'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "O"(64)); // expected-no-error
+}
+
diff --git a/test/Sema/inline-asm-validate.c b/test/Sema/inline-asm-validate.c
index c32dedb65e8c..73335e76cd80 100644
--- a/test/Sema/inline-asm-validate.c
+++ b/test/Sema/inline-asm-validate.c
@@ -1,9 +1,8 @@
// RUN: %clang_cc1 -triple arm64-apple-macosx10.8.0 -fsyntax-only -verify %s
-// expected-no-diagnostics
unsigned t, r, *p;
int foo (void) {
- __asm__ __volatile__( "stxr %w[_t], %[_r], [%[_p]]" : [_t] "=&r" (t) : [_p] "p" (p), [_r] "r" (r) : "memory");
+ __asm__ __volatile__( "stxr %w[_t], %[_r], [%[_p]]" : [_t] "=&r" (t) : [_p] "p" (p), [_r] "r" (r) : "memory"); // expected-warning{{value size does not match register size specified by the constraint and modifier}} expected-note {{use constraint modifier "w"}}
return 1;
}
diff --git a/test/Sema/ms-inline-asm.c b/test/Sema/ms-inline-asm.c
index 66504aa08417..4c6948f4d45d 100644
--- a/test/Sema/ms-inline-asm.c
+++ b/test/Sema/ms-inline-asm.c
@@ -1,5 +1,5 @@
// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fasm-blocks -Wno-microsoft -verify -fsyntax-only
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fasm-blocks -Wno-microsoft -Wunused-label -verify -fsyntax-only
void t1(void) {
__asm __asm // expected-error {{__asm used with no assembly instructions}}
@@ -29,7 +29,7 @@ void f() {
}
f();
__asm {
- mov eax, TYPE bar // expected-error {{unable to lookup expression}}
+ mov eax, TYPE bar // expected-error {{unable to lookup expression}} expected-error {{use of undeclared label 'bar'}}
}
}
@@ -60,13 +60,13 @@ int t2(int *arr, int i) {
}
// expected-error@+1 {{cannot use base register with variable reference}}
- __asm mov eax, arr[ebp + 1 + (2 * 5) - 3 + 1<<1]
+ __asm { mov eax, arr[ebp + 1 + (2 * 5) - 3 + 1<<1] }
// expected-error@+1 {{cannot use index register with variable reference}}
- __asm mov eax, arr[esi * 4]
+ __asm { mov eax, arr[esi * 4] }
// expected-error@+1 {{cannot use more than one symbol in memory operand}}
- __asm mov eax, arr[i]
+ __asm { mov eax, arr[i] }
// expected-error@+1 {{cannot use more than one symbol in memory operand}}
- __asm mov eax, global[i]
+ __asm { mov eax, global[i] }
// FIXME: Why don't we diagnose this?
// expected-Xerror@+1 {{cannot reference multiple local variables in assembly operand}}
@@ -80,22 +80,77 @@ typedef struct {
} A;
void t3() {
- __asm mov eax, [eax] UndeclaredId // expected-error {{unknown token in expression}}
+ __asm { mov eax, [eax] UndeclaredId } // expected-error {{unknown token in expression}} expected-error {{use of undeclared label 'UndeclaredId'}}
// FIXME: Only emit one diagnostic here.
+ // expected-error@+3 {{use of undeclared label 'A'}}
// expected-error@+2 {{unexpected type name 'A': expected expression}}
// expected-error@+1 {{unknown token in expression}}
- __asm mov eax, [eax] A
+ __asm { mov eax, [eax] A }
}
void t4() {
// The dot in the "intel dot operator" is optional in MSVC. MSVC also does
// global field lookup, but we don't.
- __asm mov eax, [0] A.a
- __asm mov eax, [0].A.a
- __asm mov eax, [0].a // expected-error {{Unable to lookup field reference!}}
- __asm mov eax, fs:[0] A.a
- __asm mov eax, fs:[0].A.a
- __asm mov eax, fs:[0].a // expected-error {{Unable to lookup field reference!}}
- __asm mov eax, fs:[0]. A.a // expected-error {{Unexpected token type!}}
+ __asm { mov eax, [0] A.a }
+ __asm { mov eax, [0].A.a }
+ __asm { mov eax, [0].a } // expected-error {{Unable to lookup field reference!}}
+ __asm { mov eax, fs:[0] A.a }
+ __asm { mov eax, fs:[0].A.a }
+ __asm { mov eax, fs:[0].a } // expected-error {{Unable to lookup field reference!}}
+ __asm { mov eax, fs:[0]. A.a } // expected-error {{Unexpected token type!}}
+}
+
+void test_operand_size() {
+ __asm { call word t4 } // expected-error {{Expected 'PTR' or 'ptr' token!}}
+}
+
+__declspec(naked) int t5(int x) { // expected-note {{attribute is here}}
+ asm { movl eax, x } // expected-error {{parameter references not allowed in naked functions}} expected-error {{use of undeclared label 'x'}}
+ asm { retl }
+}
+
+int y;
+__declspec(naked) int t6(int x) {
+ asm { mov eax, y } // No error.
+ asm { ret }
+}
+
+void t7() {
+ __asm {
+ foo: // expected-note {{inline assembly label 'foo' declared here}}
+ mov eax, 0
+ }
+ goto foo; // expected-error {{cannot jump from this goto statement to label 'foo' inside an inline assembly block}}
+}
+
+void t8() {
+ __asm foo: // expected-note {{inline assembly label 'foo' declared here}}
+ __asm mov eax, 0
+ goto foo; // expected-error {{cannot jump from this goto statement to label 'foo' inside an inline assembly block}}
+}
+
+void t9() {
+ goto foo; // expected-error {{cannot jump from this goto statement to label 'foo' inside an inline assembly block}}
+ __asm {
+ foo: // expected-note {{inline assembly label 'foo' declared here}}
+ mov eax, 0
+ }
+}
+
+void t10() {
+ goto foo; // expected-error {{cannot jump from this goto statement to label 'foo' inside an inline assembly block}}
+ __asm foo: // expected-note {{inline assembly label 'foo' declared here}}
+ __asm mov eax, 0
+}
+
+void t11() {
+foo:
+ __asm mov eax, foo // expected-error {{use of undeclared label 'foo'}} expected-warning {{unused label 'foo'}}
+}
+
+void t12() {
+ __asm foo:
+ __asm bar: // expected-warning {{unused label 'bar'}}
+ __asm jmp foo
}
diff --git a/test/Sema/ms_bitfield_layout.c b/test/Sema/ms_bitfield_layout.c
index 8444f469d59d..293df770cd7e 100644
--- a/test/Sema/ms_bitfield_layout.c
+++ b/test/Sema/ms_bitfield_layout.c
@@ -1,265 +1,265 @@
-// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fms-extensions -fdump-record-layouts %s 2>/dev/null \
-// RUN: | FileCheck %s
-// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fms-extensions -fdump-record-layouts %s 2>/dev/null \
-// RUN: | FileCheck %s
-
-typedef struct A {
- char x;
- int a : 22;
- int : 0;
- int c : 10;
- char b : 3;
- char d: 4;
- short y;
-} A;
-
-// CHECK: Type: struct A
-// CHECK: Size:128
-// CHECK: Alignment:32
-// CHECK: FieldOffsets: [0, 32, 64, 64, 96, 99, 112]>
-
-typedef struct B {
- char x;
- int : 0;
- short a : 4;
- char y;
-} B;
-
-// CHECK: Type: struct B
-// CHECK: Size:48
-// CHECK: Alignment:16
-// CHECK: FieldOffsets: [0, 8, 16, 32]>
-
-typedef struct C {
- char x;
- short a : 4;
- int : 0;
- char y;
-} C;
-
-// CHECK: Type: struct C
-// CHECK: Size:64
-// CHECK: Alignment:32
-// CHECK: FieldOffsets: [0, 16, 32, 32]>
-
-typedef struct D {
- char x;
- short : 0;
- int : 0;
- char y;
-} D;
-
-// CHECK: Type: struct D
-// CHECK: Size:16
-// CHECK: Alignment:8
-// CHECK: FieldOffsets: [0, 8, 8, 8]>
-
-typedef union E {
- char x;
- long long a : 3;
- int b : 3;
- long long : 0;
- short y;
-} E;
-
-// CHECK: Type: union E
-// CHECK: Size:64
-// CHECK: Alignment:16
-// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
-
-typedef struct F {
- char x;
- char a : 3;
- char b : 3;
- char c : 3;
- short d : 6;
- short e : 6;
- short f : 6;
- short g : 11;
- short h : 11;
- short i : 11;
- short y;
-} F;
-
-// CHECK: Type: struct F
-// CHECK: Size:128
-// CHECK: Alignment:16
-// CHECK: FieldOffsets: [0, 8, 11, 16, 32, 38, 48, 64, 80, 96, 112]>
-
-typedef union G {
- char x;
- int a : 3;
- int : 0;
- long long : 0;
- short y;
-} G;
-
-// CHECK: Type: union G
-// CHECK: Size:32
-// CHECK: Alignment:16
-// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
-
-typedef struct H {
- unsigned short a : 1;
- unsigned char : 0;
- unsigned long : 0;
- unsigned short c : 1;
-} H;
-
-// CHECK: Type: struct H
-// CHECK: Size:32
-// CHECK: Alignment:16
-// CHECK: FieldOffsets: [0, 16, 16, 16]>
-
-typedef struct I {
- short : 8;
- __declspec(align(16)) short : 8;
-} I;
-
-// CHECK: Type: struct I
-// CHECK: Size:16
-// CHECK: Alignment:16
-// CHECK: FieldOffsets: [0, 8]
-
-#pragma pack(push, 1)
-
-typedef struct A1 {
- char x;
- int a : 22;
- int : 0;
- int c : 10;
- char b : 3;
- char d: 4;
- short y;
-} A1;
-
-// CHECK: Type: struct A1
-// CHECK: Size:96
-// CHECK: Alignment:8
-// CHECK: FieldOffsets: [0, 8, 40, 40, 72, 75, 80]>
-
-typedef struct B1 {
- char x;
- int : 0;
- short a : 4;
- char y;
-} B1;
-
-// CHECK: Type: struct B1
-// CHECK: Size:32
-// CHECK: Alignment:8
-// CHECK: FieldOffsets: [0, 8, 8, 24]>
-
-typedef struct C1 {
- char x;
- short a : 4;
- int : 0;
- char y;
-} C1;
-
-// CHECK: Type: struct C1
-// CHECK: Size:32
-// CHECK: Alignment:8
-// CHECK: FieldOffsets: [0, 8, 24, 24]>
-
-typedef struct D1 {
- char x;
- short : 0;
- int : 0;
- char y;
-} D1;
-
-// CHECK: Type: struct D1
-// CHECK: Size:16
-// CHECK: Alignment:8
-// CHECK: FieldOffsets: [0, 8, 8, 8]>
-
-typedef union E1 {
- char x;
- long long a : 3;
- int b : 3;
- long long : 0;
- short y;
-} E1;
-
-// CHECK: Type: union E1
-// CHECK: Size:64
-// CHECK: Alignment:8
-// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
-
-typedef struct F1 {
- char x;
- char a : 3;
- char b : 3;
- char c : 3;
- short d : 6;
- short e : 6;
- short f : 6;
- short g : 11;
- short h : 11;
- short i : 11;
- short y;
-} F1;
-
-// CHECK: Type: struct F1
-// CHECK: Size:120
-// CHECK: Alignment:8
-// CHECK: FieldOffsets: [0, 8, 11, 16, 24, 30, 40, 56, 72, 88, 104]>
-
-typedef union G1 {
- char x;
- int a : 3;
- int : 0;
- long long : 0;
- short y;
-} G1;
-
-// CHECK: Type: union G1
-// CHECK: Size:32
-// CHECK: Alignment:8
-// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
-
-typedef struct H1 {
- unsigned long a : 1;
- unsigned char : 0;
- unsigned long : 0;
- unsigned long c : 1;
-} H1;
-
-// CHECK: Type: struct H1
-// CHECK: Size:64
-// CHECK: Alignment:8
-// CHECK: FieldOffsets: [0, 32, 32, 32]>
-
-typedef struct I1 {
- short : 8;
- __declspec(align(16)) short : 8;
-} I1;
-
-// CHECK: Type: struct I1
-// CHECK: Size:16
-// CHECK: Alignment:8
-// CHECK: FieldOffsets: [0, 8]
-
-#pragma pack(pop)
-
-int x[
-sizeof(A ) +
-sizeof(B ) +
-sizeof(C ) +
-sizeof(D ) +
-sizeof(E ) +
-sizeof(F ) +
-sizeof(G ) +
-sizeof(H ) +
-sizeof(I ) +
-sizeof(A1) +
-sizeof(B1) +
-sizeof(C1) +
-sizeof(D1) +
-sizeof(E1) +
-sizeof(F1) +
-sizeof(G1) +
-sizeof(H1) +
-sizeof(I1) +
-0];
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fms-extensions -fdump-record-layouts %s 2>/dev/null \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fms-extensions -fdump-record-layouts %s 2>/dev/null \
+// RUN: | FileCheck %s
+
+typedef struct A {
+ char x;
+ int a : 22;
+ int : 0;
+ int c : 10;
+ char b : 3;
+ char d: 4;
+ short y;
+} A;
+
+// CHECK: Type: struct A
+// CHECK: Size:128
+// CHECK: Alignment:32
+// CHECK: FieldOffsets: [0, 32, 64, 64, 96, 99, 112]>
+
+typedef struct B {
+ char x;
+ int : 0;
+ short a : 4;
+ char y;
+} B;
+
+// CHECK: Type: struct B
+// CHECK: Size:48
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 8, 16, 32]>
+
+typedef struct C {
+ char x;
+ short a : 4;
+ int : 0;
+ char y;
+} C;
+
+// CHECK: Type: struct C
+// CHECK: Size:64
+// CHECK: Alignment:32
+// CHECK: FieldOffsets: [0, 16, 32, 32]>
+
+typedef struct D {
+ char x;
+ short : 0;
+ int : 0;
+ char y;
+} D;
+
+// CHECK: Type: struct D
+// CHECK: Size:16
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 8, 8]>
+
+typedef union E {
+ char x;
+ long long a : 3;
+ int b : 3;
+ long long : 0;
+ short y;
+} E;
+
+// CHECK: Type: union E
+// CHECK: Size:64
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
+
+typedef struct F {
+ char x;
+ char a : 3;
+ char b : 3;
+ char c : 3;
+ short d : 6;
+ short e : 6;
+ short f : 6;
+ short g : 11;
+ short h : 11;
+ short i : 11;
+ short y;
+} F;
+
+// CHECK: Type: struct F
+// CHECK: Size:128
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 8, 11, 16, 32, 38, 48, 64, 80, 96, 112]>
+
+typedef union G {
+ char x;
+ int a : 3;
+ int : 0;
+ long long : 0;
+ short y;
+} G;
+
+// CHECK: Type: union G
+// CHECK: Size:32
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
+
+typedef struct H {
+ unsigned short a : 1;
+ unsigned char : 0;
+ unsigned long : 0;
+ unsigned short c : 1;
+} H;
+
+// CHECK: Type: struct H
+// CHECK: Size:32
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 16, 16, 16]>
+
+typedef struct I {
+ short : 8;
+ __declspec(align(16)) short : 8;
+} I;
+
+// CHECK: Type: struct I
+// CHECK: Size:16
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 8]
+
+#pragma pack(push, 1)
+
+typedef struct A1 {
+ char x;
+ int a : 22;
+ int : 0;
+ int c : 10;
+ char b : 3;
+ char d: 4;
+ short y;
+} A1;
+
+// CHECK: Type: struct A1
+// CHECK: Size:96
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 40, 40, 72, 75, 80]>
+
+typedef struct B1 {
+ char x;
+ int : 0;
+ short a : 4;
+ char y;
+} B1;
+
+// CHECK: Type: struct B1
+// CHECK: Size:32
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 8, 24]>
+
+typedef struct C1 {
+ char x;
+ short a : 4;
+ int : 0;
+ char y;
+} C1;
+
+// CHECK: Type: struct C1
+// CHECK: Size:32
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 24, 24]>
+
+typedef struct D1 {
+ char x;
+ short : 0;
+ int : 0;
+ char y;
+} D1;
+
+// CHECK: Type: struct D1
+// CHECK: Size:16
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 8, 8]>
+
+typedef union E1 {
+ char x;
+ long long a : 3;
+ int b : 3;
+ long long : 0;
+ short y;
+} E1;
+
+// CHECK: Type: union E1
+// CHECK: Size:64
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
+
+typedef struct F1 {
+ char x;
+ char a : 3;
+ char b : 3;
+ char c : 3;
+ short d : 6;
+ short e : 6;
+ short f : 6;
+ short g : 11;
+ short h : 11;
+ short i : 11;
+ short y;
+} F1;
+
+// CHECK: Type: struct F1
+// CHECK: Size:120
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8, 11, 16, 24, 30, 40, 56, 72, 88, 104]>
+
+typedef union G1 {
+ char x;
+ int a : 3;
+ int : 0;
+ long long : 0;
+ short y;
+} G1;
+
+// CHECK: Type: union G1
+// CHECK: Size:32
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 0, 0, 0, 0]>
+
+typedef struct H1 {
+ unsigned long a : 1;
+ unsigned char : 0;
+ unsigned long : 0;
+ unsigned long c : 1;
+} H1;
+
+// CHECK: Type: struct H1
+// CHECK: Size:64
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 32, 32, 32]>
+
+typedef struct I1 {
+ short : 8;
+ __declspec(align(16)) short : 8;
+} I1;
+
+// CHECK: Type: struct I1
+// CHECK: Size:16
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8]
+
+#pragma pack(pop)
+
+int x[
+sizeof(A ) +
+sizeof(B ) +
+sizeof(C ) +
+sizeof(D ) +
+sizeof(E ) +
+sizeof(F ) +
+sizeof(G ) +
+sizeof(H ) +
+sizeof(I ) +
+sizeof(A1) +
+sizeof(B1) +
+sizeof(C1) +
+sizeof(D1) +
+sizeof(E1) +
+sizeof(F1) +
+sizeof(G1) +
+sizeof(H1) +
+sizeof(I1) +
+0];
diff --git a/test/Sema/nonnull.c b/test/Sema/nonnull.c
index b1f69208241b..4b3df8518cfc 100644
--- a/test/Sema/nonnull.c
+++ b/test/Sema/nonnull.c
@@ -15,7 +15,7 @@ __attribute__((nonnull(1))) void Class_init(Instance this, char *str) {
int main(void) {
Class *obj;
- Class_init(0, "Hello World"); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ Class_init(0, "Hello World"); // expected-warning {{null passed to a callee that requires a non-null argument}}
Class_init(obj, "Hello World");
}
@@ -27,7 +27,7 @@ void baz2(__attribute__((nonnull(1))) const char *str); // expected-warning {{'n
void baz3(__attribute__((nonnull)) int x); // expected-warning {{'nonnull' attribute only applies to pointer arguments}}
void test_baz() {
- baz(0); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ baz(0); // expected-warning {{null passed to a callee that requires a non-null argument}}
baz2(0); // no-warning
baz3(0); // no-warning
}
@@ -47,10 +47,109 @@ void *test_bad_returns_null(void) {
}
void PR18795(int (*g)(const char *h, ...) __attribute__((nonnull(1))) __attribute__((nonnull))) {
- g(0); // expected-warning{{null passed to a callee which requires a non-null argument}}
+ g(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
}
void PR18795_helper() {
- PR18795(0); // expected-warning{{null passed to a callee which requires a non-null argument}}
+ PR18795(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
}
+void vararg1(int n, ...) __attribute__((nonnull(2)));
+void vararg1_test() {
+ vararg1(0);
+ vararg1(1, (void*)0); // expected-warning{{null passed}}
+ vararg1(2, (void*)0, (void*)0); // expected-warning{{null passed}}
+ vararg1(2, (void*)&vararg1, (void*)0);
+}
+
+void vararg2(int n, ...) __attribute__((nonnull, nonnull, nonnull));
+void vararg2_test() {
+ vararg2(0);
+ vararg2(1, (void*)0); // expected-warning{{null passed}}
+ vararg2(2, (void*)0, (void*)0); // expected-warning 2{{null passed}}
+}
+
+void vararg3(int n, ...) __attribute__((nonnull, nonnull(2), nonnull(3)));
+void vararg3_test() {
+ vararg3(0);
+ vararg3(1, (void*)0); // expected-warning{{null passed}}
+ vararg3(2, (void*)0, (void*)0); // expected-warning 2{{null passed}}
+}
+
+void redecl(void *, void *);
+void redecl(void *, void *) __attribute__((nonnull(1)));
+void redecl(void *, void *) __attribute__((nonnull(2)));
+void redecl(void *, void *);
+void redecl_test(void *p) {
+ redecl(p, 0); // expected-warning{{null passed}}
+ redecl(0, p); // expected-warning{{null passed}}
+}
+
+// rdar://18712242
+#define NULL (void*)0
+__attribute__((__nonnull__))
+int evil_nonnull_func(int* pointer, void * pv)
+{
+ if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is false on first encounter}}
+ return 0;
+ } else {
+ return *pointer;
+ }
+
+ pointer = pv;
+ if (!pointer)
+ return 0;
+ else
+ return *pointer;
+
+ if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is false on first encounter}}
+}
+void set_param_to_null(int**);
+int another_evil_nonnull_func(int* pointer, char ch, void * pv) __attribute__((nonnull(1, 3)));
+int another_evil_nonnull_func(int* pointer, char ch, void * pv) {
+ if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is false on first encounter}}
+ return 0;
+ } else {
+ return *pointer;
+ }
+
+ set_param_to_null(&pointer);
+ if (!pointer)
+ return 0;
+ else
+ return *pointer;
+
+ if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is false on first encounter}}
+}
+
+extern void *returns_null(void**);
+extern void FOO();
+extern void FEE();
+
+extern void *pv;
+__attribute__((__nonnull__))
+void yet_another_evil_nonnull_func(int* pointer)
+{
+ while (pv) {
+ // This comparison will not be optimized away.
+ if (pointer) { // expected-warning {{nonnull parameter 'pointer' will evaluate to 'true' on first encounter}}
+ FOO();
+ } else {
+ FEE();
+ }
+ pointer = returns_null(&pv);
+ }
+}
+
+void pr21668_1(__attribute__((nonnull)) const char *p, const char *s) {
+ if (p) // expected-warning {{nonnull parameter 'p' will evaluate to 'true' on first encounter}}
+ ;
+ if (s) // No warning
+ ;
+}
+
+void pr21668_2(__attribute__((nonnull)) const char *p) {
+ p = 0;
+ if (p) // No warning
+ ;
+}
diff --git a/test/Sema/parentheses.cpp b/test/Sema/parentheses.cpp
index ac2694f72e10..324d9b5f1e41 100644
--- a/test/Sema/parentheses.cpp
+++ b/test/Sema/parentheses.cpp
@@ -47,7 +47,7 @@ void f(Stream& s, bool b) {
// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:15-[[@LINE-5]]:15}:"("
// CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:32-[[@LINE-6]]:32}:")"
- (void)(s << 5 == 1); // expected-warning {{overloaded operator << has lower precedence than comparison operator}} \
+ (void)(s << 5 == 1); // expected-warning {{overloaded operator << has higher precedence than comparison operator}} \
// expected-note {{place parentheses around the '<<' expression to silence this warning}} \
// expected-note {{place parentheses around comparison expression to evaluate it first}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:10}:"("
@@ -55,7 +55,7 @@ void f(Stream& s, bool b) {
// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:15-[[@LINE-5]]:15}:"("
// CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:21-[[@LINE-6]]:21}:")"
- (void)(s >> 5 == 1); // expected-warning {{overloaded operator >> has lower precedence than comparison operator}} \
+ (void)(s >> 5 == 1); // expected-warning {{overloaded operator >> has higher precedence than comparison operator}} \
// expected-note {{place parentheses around the '>>' expression to silence this warning}} \
// expected-note {{place parentheses around comparison expression to evaluate it first}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:10}:"("
@@ -113,3 +113,105 @@ namespace PR15628 {
(void)(i-- ? true : false); // no-warning
}
}
+
+namespace PR20735 {
+ struct X {
+ static int state;
+ static int get();
+ int get_num();
+ int num;
+ };
+ namespace ns {
+ int num = 0;
+ int get();
+ }
+ void test(X x) {
+ if (5 & x.get_num() != 0) {}
+ // expected-warning@-1 {{& has lower precedence than !=; != will be evaluated first}}
+ // expected-note@-2 {{place parentheses around the '!=' expression to silence this warning}}
+ // expected-note@-3 {{place parentheses around the & expression to evaluate it first}}
+ // CHECK: place parentheses around the '!=' expression to silence this warning
+ // fix-it:"{{.*}}":{[[@LINE-5]]:13-[[@LINE-5]]:13}:"("
+ // fix-it:"{{.*}}":{[[@LINE-6]]:29-[[@LINE-6]]:29}:")"
+ // CHECK: place parentheses around the & expression to evaluate it first
+ // fix-it:"{{.*}}":{[[@LINE-8]]:9-[[@LINE-8]]:9}:"("
+ // fix-it:"{{.*}}":{[[@LINE-9]]:24-[[@LINE-9]]:24}:")"
+
+ if (5 & x.num != 0) {}
+ // expected-warning@-1 {{& has lower precedence than !=; != will be evaluated first}}
+ // expected-note@-2 {{place parentheses around the '!=' expression to silence this warning}}
+ // expected-note@-3 {{place parentheses around the & expression to evaluate it first}}
+ // CHECK: place parentheses around the '!=' expression to silence this warning
+ // fix-it:"{{.*}}":{[[@LINE-5]]:13-[[@LINE-5]]:13}:"("
+ // fix-it:"{{.*}}":{[[@LINE-6]]:23-[[@LINE-6]]:23}:")"
+ // CHECK: place parentheses around the & expression to evaluate it first
+ // fix-it:"{{.*}}":{[[@LINE-8]]:9-[[@LINE-8]]:9}:"("
+ // fix-it:"{{.*}}":{[[@LINE-9]]:18-[[@LINE-9]]:18}:")"
+
+ if (5 & x.state != 0) {}
+ // expected-warning@-1 {{& has lower precedence than !=; != will be evaluated first}}
+ // expected-note@-2 {{place parentheses around the '!=' expression to silence this warning}}
+ // expected-note@-3 {{place parentheses around the & expression to evaluate it first}}
+ // CHECK: place parentheses around the '!=' expression to silence this warning
+ // fix-it:"{{.*}}":{[[@LINE-5]]:13-[[@LINE-5]]:13}:"("
+ // fix-it:"{{.*}}":{[[@LINE-6]]:25-[[@LINE-6]]:25}:")"
+ // CHECK: place parentheses around the & expression to evaluate it first
+ // fix-it:"{{.*}}":{[[@LINE-8]]:9-[[@LINE-8]]:9}:"("
+ // fix-it:"{{.*}}":{[[@LINE-9]]:20-[[@LINE-9]]:20}:")"
+
+ if (5 & x.get() != 0) {}
+ // expected-warning@-1 {{& has lower precedence than !=; != will be evaluated first}}
+ // expected-note@-2 {{place parentheses around the '!=' expression to silence this warning}}
+ // expected-note@-3 {{place parentheses around the & expression to evaluate it first}}
+ // CHECK: place parentheses around the '!=' expression to silence this warning
+ // fix-it:"{{.*}}":{[[@LINE-5]]:13-[[@LINE-5]]:13}:"("
+ // fix-it:"{{.*}}":{[[@LINE-6]]:25-[[@LINE-6]]:25}:")"
+ // CHECK: place parentheses around the & expression to evaluate it first
+ // fix-it:"{{.*}}":{[[@LINE-8]]:9-[[@LINE-8]]:9}:"("
+ // fix-it:"{{.*}}":{[[@LINE-9]]:20-[[@LINE-9]]:20}:")"
+
+ if (5 & X::state != 0) {}
+ // expected-warning@-1 {{& has lower precedence than !=; != will be evaluated first}}
+ // expected-note@-2 {{place parentheses around the '!=' expression to silence this warning}}
+ // expected-note@-3 {{place parentheses around the & expression to evaluate it first}}
+ // CHECK: place parentheses around the '!=' expression to silence this warning
+ // fix-it:"{{.*}}":{[[@LINE-5]]:13-[[@LINE-5]]:13}:"("
+ // fix-it:"{{.*}}":{[[@LINE-6]]:26-[[@LINE-6]]:26}:")"
+ // CHECK: place parentheses around the & expression to evaluate it first
+ // fix-it:"{{.*}}":{[[@LINE-8]]:9-[[@LINE-8]]:9}:"("
+ // fix-it:"{{.*}}":{[[@LINE-9]]:21-[[@LINE-9]]:21}:")"
+
+ if (5 & X::get() != 0) {}
+ // expected-warning@-1 {{& has lower precedence than !=; != will be evaluated first}}
+ // expected-note@-2 {{place parentheses around the '!=' expression to silence this warning}}
+ // expected-note@-3 {{place parentheses around the & expression to evaluate it first}}
+ // CHECK: place parentheses around the '!=' expression to silence this warning
+ // fix-it:"{{.*}}":{[[@LINE-5]]:13-[[@LINE-5]]:13}:"("
+ // fix-it:"{{.*}}":{[[@LINE-6]]:26-[[@LINE-6]]:26}:")"
+ // CHECK: place parentheses around the & expression to evaluate it first
+ // fix-it:"{{.*}}":{[[@LINE-8]]:9-[[@LINE-8]]:9}:"("
+ // fix-it:"{{.*}}":{[[@LINE-9]]:21-[[@LINE-9]]:21}:")"
+
+ if (5 & ns::get() != 0) {}
+ // expected-warning@-1 {{& has lower precedence than !=; != will be evaluated first}}
+ // expected-note@-2 {{place parentheses around the '!=' expression to silence this warning}}
+ // expected-note@-3 {{place parentheses around the & expression to evaluate it first}}
+ // CHECK: place parentheses around the '!=' expression to silence this warning
+ // fix-it:"{{.*}}":{[[@LINE-5]]:13-[[@LINE-5]]:13}:"("
+ // fix-it:"{{.*}}":{[[@LINE-6]]:27-[[@LINE-6]]:27}:")"
+ // CHECK: place parentheses around the & expression to evaluate it first
+ // fix-it:"{{.*}}":{[[@LINE-8]]:9-[[@LINE-8]]:9}:"("
+ // fix-it:"{{.*}}":{[[@LINE-9]]:22-[[@LINE-9]]:22}:")"
+
+ if (5 & ns::num != 0) {}
+ // expected-warning@-1 {{& has lower precedence than !=; != will be evaluated first}}
+ // expected-note@-2 {{place parentheses around the '!=' expression to silence this warning}}
+ // expected-note@-3 {{place parentheses around the & expression to evaluate it first}}
+ // CHECK: place parentheses around the '!=' expression to silence this warning
+ // fix-it:"{{.*}}":{[[@LINE-5]]:13-[[@LINE-5]]:13}:"("
+ // fix-it:"{{.*}}":{[[@LINE-6]]:25-[[@LINE-6]]:25}:")"
+ // CHECK: place parentheses around the & expression to evaluate it first
+ // fix-it:"{{.*}}":{[[@LINE-8]]:9-[[@LINE-8]]:9}:"("
+ // fix-it:"{{.*}}":{[[@LINE-9]]:20-[[@LINE-9]]:20}:")"
+ }
+}
diff --git a/test/Sema/scope-check.c b/test/Sema/scope-check.c
index a9494d3e3fb4..fa37d10d070b 100644
--- a/test/Sema/scope-check.c
+++ b/test/Sema/scope-check.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=gnu99 %s -Wno-unreachable-code
int test1(int x) {
- goto L; // expected-error{{goto into protected scope}}
+ goto L; // expected-error{{cannot jump from this goto statement to its label}}
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
int b[x]; // expected-note {{jump bypasses initialization of variable length array}}
L:
@@ -9,7 +9,7 @@ int test1(int x) {
}
int test2(int x) {
- goto L; // expected-error{{goto into protected scope}}
+ goto L; // expected-error{{cannot jump from this goto statement to its label}}
typedef int a[x]; // expected-note {{jump bypasses initialization of VLA typedef}}
L:
return sizeof(a);
@@ -18,14 +18,14 @@ int test2(int x) {
void test3clean(int*);
int test3() {
- goto L; // expected-error{{goto into protected scope}}
+ goto L; // expected-error{{cannot jump from this goto statement to its label}}
int a __attribute((cleanup(test3clean))); // expected-note {{jump bypasses initialization of variable with __attribute__((cleanup))}}
L:
return a;
}
int test4(int x) {
- goto L; // expected-error{{goto into protected scope}}
+ goto L; // expected-error{{cannot jump from this goto statement to its label}}
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
test4(x);
L:
@@ -50,7 +50,7 @@ void test7(int x) {
switch (x) {
case 1: ;
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
- case 2: // expected-error {{switch case is in protected scope}}
+ case 2: // expected-error {{cannot jump from switch statement to this case label}}
a[1] = 2;
break;
}
@@ -58,17 +58,17 @@ void test7(int x) {
int test8(int x) {
// For statement.
- goto L2; // expected-error {{goto into protected scope}}
+ goto L2; // expected-error {{cannot jump from this goto statement to its label}}
for (int arr[x]; // expected-note {{jump bypasses initialization of variable length array}}
; ++x)
L2:;
// Statement expressions.
- goto L3; // expected-error {{goto into protected scope}}
+ goto L3; // expected-error {{cannot jump from this goto statement to its label}}
int Y = ({ int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
L3: 4; });
- goto L4; // expected-error {{goto into protected scope}}
+ goto L4; // expected-error {{cannot jump from this goto statement to its label}}
{
int A[x], // expected-note {{jump bypasses initialization of variable length array}}
B[x]; // expected-note {{jump bypasses initialization of variable length array}}
@@ -91,7 +91,7 @@ int test8(int x) {
int A[x], B = ({ if (x)
goto L7;
else
- goto L8; // expected-error {{goto into protected scope}}
+ goto L8; // expected-error {{cannot jump from this goto statement to its label}}
4; }),
C[x]; // expected-note {{jump bypasses initialization of variable length array}}
L8:; // bad
@@ -103,7 +103,7 @@ int test8(int x) {
goto L9;
else
// FIXME:
- goto L10; // fixme-error {{goto into protected scope}}
+ goto L10; // fixme-error {{cannot jump from this goto statement to its label}}
4; })];
L10:; // bad
}
@@ -123,7 +123,7 @@ int test8(int x) {
}
// Statement expressions 2.
- goto L1; // expected-error {{goto into protected scope}}
+ goto L1; // expected-error {{cannot jump from this goto statement to its label}}
return x == ({
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
L1:
@@ -133,7 +133,7 @@ int test8(int x) {
void test9(int n, void *P) {
int Y;
int Z = 4;
- goto *P; // expected-error {{indirect goto might cross protected scopes}}
+ goto *P; // expected-error {{cannot jump from this indirect goto statement to one of its possible targets}}
L2: ;
int a[n]; // expected-note {{jump bypasses initialization of variable length array}}
@@ -151,14 +151,14 @@ L4:
}
void test10(int n, void *P) {
- goto L0; // expected-error {{goto into protected scope}}
+ goto L0; // expected-error {{cannot jump from this goto statement to its label}}
typedef int A[n]; // expected-note {{jump bypasses initialization of VLA typedef}}
L0:
- goto L1; // expected-error {{goto into protected scope}}
+ goto L1; // expected-error {{cannot jump from this goto statement to its label}}
A b, c[10]; // expected-note 2 {{jump bypasses initialization of variable length array}}
L1:
- goto L2; // expected-error {{goto into protected scope}}
+ goto L2; // expected-error {{cannot jump from this goto statement to its label}}
A d[n]; // expected-note {{jump bypasses initialization of variable length array}}
L2:
return;
@@ -171,7 +171,7 @@ void test11(int n) {
case 2:
case 3:;
int Arr[n]; // expected-note {{jump bypasses initialization of variable length array}}
- case 4: // expected-error {{switch case is in protected scope}}
+ case 4: // expected-error {{cannot jump from switch statement to this case label}}
return;
}
};
@@ -185,7 +185,7 @@ void test12(int n) {
L1:
goto L2;
L2:
- goto L3; // expected-error {{goto into protected scope}}
+ goto L3; // expected-error {{cannot jump from this goto statement to its label}}
int Arr[n]; // expected-note {{jump bypasses initialization of variable length array}}
L3:
goto L4;
@@ -220,7 +220,7 @@ int test14(int n) {
void test15(int n, void *pc) {
static const void *addrs[] = { &&L1, &&L2 };
- goto *pc; // expected-error {{indirect goto might cross protected scope}}
+ goto *pc; // expected-error {{cannot jump from this indirect goto statement to one of its possible targets}}
L1:
{
diff --git a/test/Sema/sentinel-attribute.c b/test/Sema/sentinel-attribute.c
index 46f135041c1f..1beae87a51de 100644
--- a/test/Sema/sentinel-attribute.c
+++ b/test/Sema/sentinel-attribute.c
@@ -1,7 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -fsyntax-only %s -fdiagnostics-parseable-fixits 2>&1 | \
+// RUN: FileCheck %s --check-prefix=C
+// RUN: not %clang_cc1 -fsyntax-only %s -fdiagnostics-parseable-fixits -x c++ -std=c++11 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CXX11
int x __attribute__((sentinel)); //expected-warning{{'sentinel' attribute only applies to functions, methods and blocks}}
-void f1(int a, ...) __attribute__ ((sentinel));
+void f1(int a, ...) __attribute__ ((sentinel)); // expected-note {{function has been explicitly marked sentinel here}}
void f2(int a, ...) __attribute__ ((sentinel(1)));
void f3(int a, ...) __attribute__ ((sentinel("hello"))); //expected-error{{'sentinel' attribute requires parameter 1 to be an integer constant}}
@@ -13,3 +17,10 @@ void f5(int a) __attribute__ ((sentinel)); //expected-warning{{'sentinel' attrib
void f6() __attribute__((__sentinel__)); // expected-warning {{'sentinel' attribute requires named arguments}}
+
+void g() {
+ // The integer literal zero is not a sentinel.
+ f1(1, 0); // expected-warning {{missing sentinel in function call}}
+// C: fix-it:{{.*}}:{23:10-23:10}:", (void*) 0"
+// CXX11: fix-it:{{.*}}:{23:10-23:10}:", nullptr"
+}
diff --git a/test/Sema/sizeof-struct-non-zero-as-member.cl b/test/Sema/sizeof-struct-non-zero-as-member.cl
new file mode 100644
index 000000000000..0e13c61503aa
--- /dev/null
+++ b/test/Sema/sizeof-struct-non-zero-as-member.cl
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -triple amdgcn -target-cpu verde -S -emit-llvm -o - %s
+// expected-no-diagnostics
+
+// Record lowering was crashing on SI and newer targets, because it
+// was using the wrong size for test::ptr. Since global memory
+// has 64-bit pointers, sizeof(test::ptr) should be 8.
+
+struct test_as0 {int *ptr;};
+constant int as0[sizeof(struct test_as0) == 4 ? 1 : -1] = { 0 };
+
+struct test_as1 {global int *ptr;};
+constant int as1[sizeof(struct test_as1) == 8 ? 1 : -1] = { 0 };
+
+struct test_as2 {constant int *ptr;};
+constant int as2[sizeof(struct test_as2) == 8 ? 1 : -1] = { 0 };
+
+struct test_as3 {local int *ptr;};
+constant int as3[sizeof(struct test_as3) == 4 ? 1 : -1] = { 0 };
diff --git a/test/Sema/statements.c b/test/Sema/statements.c
index 8cd30b0c93cd..9ab571521a3a 100644
--- a/test/Sema/statements.c
+++ b/test/Sema/statements.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -fsyntax-only -verify -triple x86_64-pc-linux-gnu
typedef unsigned __uint32_t;
diff --git a/test/Sema/static-array.c b/test/Sema/static-array.c
index 5ca693b2bf54..304485d5af9f 100644
--- a/test/Sema/static-array.c
+++ b/test/Sema/static-array.c
@@ -11,13 +11,13 @@ void f(int *p) {
cat0(0);
- cat(0); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ cat(0); // expected-warning {{null passed to a callee that requires a non-null argument}}
cat(a); // expected-warning {{array argument is too small; contains 2 elements, callee requires at least 3}}
cat(b);
cat(c);
cat(p);
- vat(1, 0); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ vat(1, 0); // expected-warning {{null passed to a callee that requires a non-null argument}}
vat(3, b);
}
diff --git a/test/Sema/stdcall-fastcall.c b/test/Sema/stdcall-fastcall.c
index dea1fc5e7af7..256f5588e6d2 100644
--- a/test/Sema/stdcall-fastcall.c
+++ b/test/Sema/stdcall-fastcall.c
@@ -6,7 +6,7 @@ int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' only applies
// Different CC qualifiers are not compatible
void __attribute__((stdcall, fastcall)) foo3(void); // expected-error{{fastcall and stdcall attributes are not compatible}}
-void __attribute__((stdcall)) foo4(); // expected-note{{previous declaration is here}}
+void __attribute__((stdcall)) foo4(); // expected-note{{previous declaration is here}} expected-warning{{function with no prototype cannot use the stdcall calling convention}}
void __attribute__((fastcall)) foo4(void); // expected-error{{function declared 'fastcall' here was previously declared 'stdcall'}}
// rdar://8876096
diff --git a/test/Sema/string-plus-char.c b/test/Sema/string-plus-char.c
index 322e8f5962be..66c1182eb046 100644
--- a/test/Sema/string-plus-char.c
+++ b/test/Sema/string-plus-char.c
@@ -1,5 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct AB{const char *a; const char*b;};
+
+const char *foo(const struct AB *ab) {
+ return ab->a + 'b'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+}
+
void f(const char *s) {
char *str = 0;
char *str2 = str + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
@@ -8,6 +14,15 @@ void f(const char *s) {
str = 'c' + str;// expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+ char strArr[] = "foo";
+ str = strArr + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+ char *strArr2[] = {"ac","dc"};
+ str = strArr2[0] + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+
+ struct AB ab;
+ constStr = foo(&ab) + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
// no-warning
char c = 'c';
str = str + c;
diff --git a/test/Sema/struct-packed-align.c b/test/Sema/struct-packed-align.c
index 166d5eb1ff8d..291de6762cd1 100644
--- a/test/Sema/struct-packed-align.c
+++ b/test/Sema/struct-packed-align.c
@@ -127,9 +127,11 @@ struct nS {
nt start_lba;
};
+#if defined(_WIN32) && !defined(__declspec) // _MSC_VER is unavailable in cc1.
+// Alignment doesn't affect packing in MS mode.
+extern int n1[sizeof(struct nS) == 16 ? 1 : -1];
+extern int n2[__alignof(struct nS) == 8 ? 1 : -1];
+#else
extern int n1[sizeof(struct nS) == 9 ? 1 : -1];
extern int n2[__alignof(struct nS) == 1 ? 1 : -1];
-
-
-
-
+#endif
diff --git a/test/Sema/switch-1.c b/test/Sema/switch-1.c
index ce1e7dc9433f..5191c92e714d 100644
--- a/test/Sema/switch-1.c
+++ b/test/Sema/switch-1.c
@@ -20,3 +20,8 @@ int f(int i) {
return (i, 65537) * 65537; // expected-warning {{overflow in expression; result is 131073 with type 'int'}} \
// expected-warning {{expression result unused}}
}
+
+// rdar://18405357
+unsigned long long l = 65536 * 65536; // expected-warning {{overflow in expression; result is 0 with type 'int'}}
+unsigned long long l2 = 65536 * (unsigned)65536;
+unsigned long long l3 = 65536 * 65536ULL;
diff --git a/test/Sema/switch.c b/test/Sema/switch.c
index 092378d48bc5..7aa695d7cb91 100644
--- a/test/Sema/switch.c
+++ b/test/Sema/switch.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wswitch-enum -Wcovered-switch-default %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wswitch-enum -Wcovered-switch-default -triple x86_64-linux-gnu %s
void f (int z) {
while (z) {
default: z--; // expected-error {{statement not in switch}}
@@ -375,3 +375,13 @@ void switch_on_ExtendedEnum1(enum ExtendedEnum1 e) {
}
}
+void PR11778(char c, int n, long long ll) {
+ // Do not reject this; we don't have duplicate case values because we
+ // check for duplicates in the promoted type.
+ switch (c) case 1: case 257: ; // expected-warning {{overflow}}
+
+ switch (n) case 0x100000001LL: case 1: ; // expected-warning {{overflow}} expected-error {{duplicate}} expected-note {{previous}}
+ switch ((int)ll) case 0x100000001LL: case 1: ; // expected-warning {{overflow}} expected-error {{duplicate}} expected-note {{previous}}
+ switch ((long long)n) case 0x100000001LL: case 1: ;
+ switch (ll) case 0x100000001LL: case 1: ;
+}
diff --git a/test/Sema/types.c b/test/Sema/types.c
index 0450de1c8e9b..5614d164a5f4 100644
--- a/test/Sema/types.c
+++ b/test/Sema/types.c
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 %s -pedantic -verify -triple=x86_64-apple-darwin9
-// RUN: %clang_cc1 %s -pedantic -verify -triple=mips64-linux-gnu
+// RUN: %clang_cc1 %s -fblocks -pedantic -verify -triple=x86_64-apple-darwin9
+// RUN: %clang_cc1 %s -fblocks -pedantic -verify -triple=mips64-linux-gnu
+// RUN: %clang_cc1 %s -fblocks -pedantic -verify -triple=x86_64-unknown-linux
+// RUN: %clang_cc1 %s -fblocks -pedantic -verify -triple=x86_64-unknown-linux-gnux32
// rdar://6097662
typedef int (*T)[2];
@@ -28,12 +30,12 @@ int c() {
int __int128; // expected-error {{cannot combine with previous}} expected-warning {{does not declare anything}}
}
// __int128_t is __int128; __uint128_t is unsigned __int128.
-typedef __int128 check_int_128; // expected-note {{here}}
-typedef __int128_t check_int_128; // expected-note {{here}} expected-warning {{redefinition}}
+typedef __int128 check_int_128;
+typedef __int128_t check_int_128; // expected-note {{here}}
typedef int check_int_128; // expected-error {{different types ('int' vs '__int128_t' (aka '__int128'))}}
-typedef unsigned __int128 check_uint_128; // expected-note {{here}}
-typedef __uint128_t check_uint_128; // expected-note {{here}} expected-warning {{redefinition}}
+typedef unsigned __int128 check_uint_128;
+typedef __uint128_t check_uint_128; // expected-note {{here}}
typedef int check_uint_128; // expected-error {{different types ('int' vs '__uint128_t' (aka 'unsigned __int128'))}}
// Array type merging should convert array size to whatever matches the target
@@ -82,3 +84,7 @@ void convert() {
uchar32 r = 0;
r.s[ 1234 ] = 1; // expected-error {{illegal vector component name 's'}}
}
+
+int &*_Atomic null_type_0; // expected-error {{expected identifier or '('}}
+int &*__restrict__ null_type_1; // expected-error {{expected identifier or '('}}
+int ^_Atomic null_type_2; // expected-error {{block pointer to non-function type is invalid}}
diff --git a/test/Sema/typo-correction.c b/test/Sema/typo-correction.c
new file mode 100644
index 000000000000..df7da797f050
--- /dev/null
+++ b/test/Sema/typo-correction.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+//
+// This file contains typo correction tests which hit different code paths in C
+// than in C++ and may exhibit different behavior as a result.
+
+__typeof__(struct F*) var[invalid]; // expected-error-re {{use of undeclared identifier 'invalid'{{$}}}}
+
+void PR21656() {
+ float x;
+ x = (float)arst; // expected-error-re {{use of undeclared identifier 'arst'{{$}}}}
+}
+
+a = b ? : 0; // expected-warning {{type specifier missing, defaults to 'int'}} \
+ // expected-error {{use of undeclared identifier 'b'}}
+
+struct ContainerStuct {
+ enum { SOME_ENUM }; // expected-note {{'SOME_ENUM' declared here}}
+};
+
+void func(int arg) {
+ switch (arg) {
+ case SOME_ENUM_: // expected-error {{use of undeclared identifier 'SOME_ENUM_'; did you mean 'SOME_ENUM'}}
+ ;
+ }
+}
diff --git a/test/Sema/var-redecl.c b/test/Sema/var-redecl.c
index 0e30aa271379..811e9f10bf20 100644
--- a/test/Sema/var-redecl.c
+++ b/test/Sema/var-redecl.c
@@ -4,7 +4,7 @@ int outer1; // expected-note{{previous definition is here}}
extern int outer2; // expected-note{{previous definition is here}}
int outer4;
int outer4; // expected-note{{previous definition is here}}
-int outer5; // expected-note{{previous definition is here}}
+int outer5;
int outer6(float); // expected-note{{previous definition is here}}
int outer7(float);
@@ -13,7 +13,7 @@ void outer_test() {
extern float outer2; // expected-error{{redefinition of 'outer2' with a different type}}
extern float outer3; // expected-note{{previous definition is here}}
double outer4;
- extern int outer5;
+ extern int outer5; // expected-note{{previous definition is here}}
extern int outer6; // expected-error{{redefinition of 'outer6' as different kind of symbol}}
int outer7;
extern int outer8; // expected-note{{previous definition is here}}
@@ -60,3 +60,11 @@ int *p=&g19; // expected-error{{use of undeclared identifier 'g19'}} \
static int a;
extern int a; // expected-note {{previous declaration is here}}
int a; // expected-error {{non-static declaration of 'a' follows static declaration}}
+
+void f(int x) { // expected-note {{previous definition is here}}
+ extern int x; // expected-error {{extern declaration of 'x' follows non-extern declaration}}
+}
+
+extern int b[];
+void g20() { extern int b[3]; } // expected-note{{previous definition is here}}
+void g21() { extern int b[4]; } // expected-error{{redefinition of 'b' with a different type: 'int [4]' vs 'int [3]'}}
diff --git a/test/Sema/warn-cast-qual.c b/test/Sema/warn-cast-qual.c
new file mode 100644
index 000000000000..dc11f5717ebe
--- /dev/null
+++ b/test/Sema/warn-cast-qual.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -Wcast-qual -verify %s
+
+#include <stdint.h>
+
+void foo() {
+ const char * const ptr = 0;
+ const char * const *ptrptr = 0;
+ char *y = (char *)ptr; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}}
+ char **y1 = (char **)ptrptr; // expected-warning {{cast from 'const char *const' to 'char *' drops const qualifier}}
+ const char **y2 = (const char **)ptrptr; // expected-warning {{cast from 'const char *const *' to 'const char **' drops const qualifier}}
+
+ char *z = (char *)(uintptr_t)(const void *)ptr; // no warning
+ char *z1 = (char *)(const void *)ptr; // expected-warning {{cast from 'const void *' to 'char *' drops const qualifier}}
+
+ volatile char *vol = 0;
+ char *vol2 = (char *)vol; // expected-warning {{cast from 'volatile char *' to 'char *' drops volatile qualifier}}
+ const volatile char *volc = 0;
+ char *volc2 = (char *)volc; // expected-warning {{cast from 'const volatile char *' to 'char *' drops const and volatile qualifiers}}
+
+ int **intptrptr;
+ const int **intptrptrc = (const int **)intptrptr; // expected-warning {{cast from 'int **' to 'const int **' must have all intermediate pointers const qualified}}
+ volatile int **intptrptrv = (volatile int **)intptrptr; // expected-warning {{cast from 'int **' to 'volatile int **' must have all intermediate pointers const qualified}}
+
+ int *intptr;
+ const int *intptrc = (const int *)intptr; // no warning
+
+ const char **charptrptrc;
+ char **charptrptr = (char **)charptrptrc; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}}
+}
diff --git a/test/Sema/warn-string-conversion.c b/test/Sema/warn-string-conversion.c
new file mode 100644
index 000000000000..708dd543e402
--- /dev/null
+++ b/test/Sema/warn-string-conversion.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wstring-conversion %s
+
+#define assert(EXPR) (void)(EXPR);
+
+// Expection for common assert form.
+void test1() {
+ assert(0 && "foo");
+ assert("foo" && 0);
+ assert(0 || "foo"); // expected-warning {{string literal}}
+}
+
+void test2() {
+ if ("hi") {} // expected-warning {{string literal}}
+ while ("hello") {} // expected-warning {{string literal}}
+ for (;"howdy";) {} // expected-warning {{string literal}}
+ do { } while ("hey"); // expected-warning {{string literal}}
+}
diff --git a/test/Sema/warn-tautological-compare.c b/test/Sema/warn-tautological-compare.c
new file mode 100644
index 000000000000..55de6179a31a
--- /dev/null
+++ b/test/Sema/warn-tautological-compare.c
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -verify %s
+// rdar://18716393
+
+extern int a[] __attribute__((weak));
+int b[] = {8,13,21};
+struct {
+ int x[10];
+} c;
+const char str[] = "text";
+
+void ignore() {
+ if (!a) {}
+}
+void test() {
+ if (!b) {} // expected-warning {{address of array 'b' will always evaluate to 'true'}}
+ if (b == 0) {} // expected-warning {{comparison of array 'b' equal to a null pointer is always false}}
+ if (!c.x) {} // expected-warning {{address of array 'c.x' will always evaluate to 'true'}}
+ if (c.x == 0) {} // expected-warning {{comparison of array 'c.x' equal to a null pointer is always false}}
+ if (!str) {} // expected-warning {{address of array 'str' will always evaluate to 'true'}}
+ if (0 == str) {} // expected-warning {{comparison of array 'str' equal to a null pointer is always false}}
+}
+
+int array[2];
+int test1()
+{
+ if (!array) { // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+ return array[0];
+ } else if (array != 0) { // expected-warning {{comparison of array 'array' not equal to a null pointer is always true}}
+ return array[1];
+ }
+ if (array == 0) // expected-warning {{comparison of array 'array' equal to a null pointer is always false}}
+ return 1;
+ return 0;
+}
+
+#define NULL (void*)0
+
+int test2(int* pointer, char ch, void * pv) {
+ if (!&pointer) { // expected-warning {{address of 'pointer' will always evaluate to 'true'}}
+ return 0;
+ }
+
+ if (&pointer) { // expected-warning {{address of 'pointer' will always evaluate to 'true'}}
+ return 0;
+ }
+
+ if (&pointer == NULL) {} // expected-warning {{comparison of address of 'pointer' equal to a null pointer is always false}}
+
+ if (&pointer != NULL) {} // expected-warning {{comparison of address of 'pointer' not equal to a null pointer is always true}}
+
+ return 1;
+}
+
+void test3() {
+ if (array) { } // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+ if (array != 0) {} // expected-warning {{comparison of array 'array' not equal to a null pointer is always true}}
+ if (!array) { } // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+ if (array == 0) {} // expected-warning {{comparison of array 'array' equal to a null pointer is always false}}
+
+ if (array[0] &&
+ array) {} // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+
+ if (array[0] ||
+ array) {} // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+
+ if (array[0] &&
+ !array) {} // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+ if (array[0] ||
+ !array) {} // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+
+ if (array && // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+ array[0]) {}
+ if (!array || // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+ array[0]) {}
+
+ if (array || // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+ (!array && array[0])) {} // expected-warning {{address of array 'array' will always evaluate to 'true'}}
+ }
+
+// rdar://19256338
+#define SAVE_READ(PTR) if( (PTR) && (&result) ) *result=*PTR;
+void _HTTPClientErrorHandler(int me)
+{
+ int *result;
+ SAVE_READ(&me);
+}
diff --git a/test/Sema/warn-thread-safety-analysis.c b/test/Sema/warn-thread-safety-analysis.c
index 6d41e40d303f..55e6e707f013 100644
--- a/test/Sema/warn-thread-safety-analysis.c
+++ b/test/Sema/warn-thread-safety-analysis.c
@@ -117,12 +117,12 @@ int main() {
mutex_unlock(foo_.mu_);
mutex_exclusive_lock(&mu1);
- mutex_shared_unlock(&mu1); // expected-warning {{releasing mutex 'mu1' using shared access, expected exclusive access}}
- mutex_exclusive_unlock(&mu1);
+ mutex_shared_unlock(&mu1); // expected-warning {{releasing mutex 'mu1' using shared access, expected exclusive access}}
+ mutex_exclusive_unlock(&mu1); // expected-warning {{releasing mutex 'mu1' that was not held}}
mutex_shared_lock(&mu1);
mutex_exclusive_unlock(&mu1); // expected-warning {{releasing mutex 'mu1' using exclusive access, expected shared access}}
- mutex_shared_unlock(&mu1);
+ mutex_shared_unlock(&mu1); // expected-warning {{releasing mutex 'mu1' that was not held}}
return 0;
}
diff --git a/test/Sema/warn-unsequenced.c b/test/Sema/warn-unsequenced.c
index a14d3281662b..70163dc0de94 100644
--- a/test/Sema/warn-unsequenced.c
+++ b/test/Sema/warn-unsequenced.c
@@ -29,6 +29,11 @@ void test() {
a = f(a++, 0); // ok
a = f(++a, a++); // expected-warning {{multiple unsequenced modifications}}
+ ++a + f(++a, 0); // expected-warning {{multiple unsequenced modifications}}
+ f(++a, 0) + ++a; // expected-warning {{multiple unsequenced modifications}}
+ a++ + f(a++, 0); // expected-warning {{multiple unsequenced modifications}}
+ f(a++, 0) + a++; // expected-warning {{multiple unsequenced modifications}}
+
a = ++a; // expected-warning {{multiple unsequenced modifications}}
a += ++a; // expected-warning {{unsequenced modification and access}}
@@ -48,7 +53,7 @@ void test() {
(1 ? a : ++a) + a; // ok
(xs[5] ? ++a : ++a) + a; // FIXME: warn here
- (++a, xs[6] ? ++a : 0) + a; // FIXME: warn here
+ (++a, xs[6] ? ++a : 0) + a; // expected-warning {{unsequenced modification and access}}
// Here, the read of the fourth 'a' might happen before or after the write to
// the second 'a'.
@@ -84,5 +89,8 @@ void test() {
(__builtin_classify_type(++a) ? 1 : 0) + ++a; // ok
(__builtin_constant_p(++a) ? 1 : 0) + ++a; // ok
- (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // FIXME: warn here
+ (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // expected-warning {{multiple unsequenced modifications}}
+ _Generic(++a, default: 0) + ++a; // ok
+ sizeof(++a) + ++a; // ok
+ _Alignof(++a) + ++a; // expected-warning {{extension}}
}
diff --git a/test/Sema/warn-unused-value.c b/test/Sema/warn-unused-value.c
index 95cd8fb70400..edf791593a42 100644
--- a/test/Sema/warn-unused-value.c
+++ b/test/Sema/warn-unused-value.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -Wunused-label %s
-// RUN: %clang_cc1 -fsyntax-only -verify -Wunused %s
-// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
+// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify -Wunused-value -Wunused-label %s
+// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify -Wunused %s
+// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify -Wall %s
int i = 0;
int j = 0;
@@ -88,3 +88,22 @@ void f1(struct s0 *a) {
// rdar://8139785
f0((int)(a->f0 + 1, 10)); // expected-warning {{expression result unused}}
}
+
+void blah(int a);
+#define GenTest(x) _Generic(x, default : blah)(x)
+
+void unevaluated_operands(void) {
+ int val = 0;
+
+ (void)sizeof(++val); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
+ (void)_Generic(val++, default : 0); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
+ (void)_Alignof(val++); // expected-warning {{expression with side effects has no effect in an unevaluated context}} expected-warning {{'_Alignof' applied to an expression is a GNU extension}}
+
+ // VLAs can have side effects so long as it's part of the type and not
+ // an expression.
+ (void)sizeof(int[++val]); // Ok
+ (void)_Alignof(int[++val]); // Ok
+
+ // Side effects as part of macro expansion are ok.
+ GenTest(val++);
+}
diff --git a/test/Sema/wchar.c b/test/Sema/wchar.c
index 74e482a2a0f8..a45a14daaef2 100644
--- a/test/Sema/wchar.c
+++ b/test/Sema/wchar.c
@@ -8,9 +8,9 @@ typedef __WCHAR_TYPE__ wchar_t;
#define WCHAR_T_TYPE unsigned short
#elif defined(__arm) || defined(__aarch64__)
#define WCHAR_T_TYPE unsigned int
-#elif defined(__sun) || defined(__AuroraUX__)
+#elif defined(__sun)
#define WCHAR_T_TYPE long
-#else /* Solaris or AuroraUX. */
+#else /* Solaris. */
#define WCHAR_T_TYPE int
#endif
diff --git a/test/SemaCUDA/amdgpu-num-gpr-attr.cu b/test/SemaCUDA/amdgpu-num-gpr-attr.cu
new file mode 100644
index 000000000000..83acbc5007ec
--- /dev/null
+++ b/test/SemaCUDA/amdgpu-num-gpr-attr.cu
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#include "Inputs/cuda.h"
+
+__attribute__((amdgpu_num_vgpr(64)))
+__global__ void test_num_vgpr() { } // expected-error {{'amdgpu_num_vgpr' attribute only applies to kernel functions}}
+
+__attribute__((amdgpu_num_sgpr(32)))
+__global__ void test_num_sgpr() { } // expected-error {{'amdgpu_num_sgpr' attribute only applies to kernel functions}}
+
+// fixme-expected-error@+3 {{'amdgpu_num_sgpr' attribute only applies to kernel functions}}
+// expected-error@+2 {{'amdgpu_num_vgpr' attribute only applies to kernel functions}}
+__attribute__((amdgpu_num_sgpr(32), amdgpu_num_vgpr(64)))
+__global__ void test_num_vgpr_num_sgpr() { }
diff --git a/test/SemaCUDA/function-target.cu b/test/SemaCUDA/function-target.cu
index 51bc8c9f559e..ca56030309de 100644
--- a/test/SemaCUDA/function-target.cu
+++ b/test/SemaCUDA/function-target.cu
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fcuda-is-device -verify %s
#include "Inputs/cuda.h"
@@ -31,14 +32,40 @@ __device__ void d1(void) {
d1g<<<1, 1>>>(); // expected-error {{reference to __global__ function 'd1g' in __device__ function}}
}
-__host__ void hd1h(void); // expected-note {{candidate function not viable: call to __host__ function from __host__ __device__ function}}
-__device__ void hd1d(void); // expected-note {{candidate function not viable: call to __device__ function from __host__ __device__ function}}
+// Expected 0-1 as in one of host/device side compilation it is an error, while
+// not in the other
+__host__ void hd1h(void); // expected-note 0-1 {{candidate function not viable: call to __host__ function from __host__ __device__ function}}
+__device__ void hd1d(void); // expected-note 0-1 {{candidate function not viable: call to __device__ function from __host__ __device__ function}}
+__host__ void hd1hg(void);
+__device__ void hd1dg(void);
+#ifdef __CUDA_ARCH__
+__host__ void hd1hig(void); // expected-note {{candidate function not viable: call to __host__ function from __host__ __device__ function}}
+#else
+__device__ void hd1dig(void); // expected-note {{candidate function not viable: call to __device__ function from __host__ __device__ function}}
+#endif
__host__ __device__ void hd1hd(void);
__global__ void hd1g(void); // expected-note {{'hd1g' declared here}}
__host__ __device__ void hd1(void) {
- hd1h(); // expected-error {{no matching function}}
- hd1d(); // expected-error {{no matching function}}
+ // Expected 0-1 as in one of host/device side compilation it is an error,
+ // while not in the other
+ hd1d(); // expected-error 0-1 {{no matching function}}
+ hd1h(); // expected-error 0-1 {{no matching function}}
+
+ // No errors as guarded
+#ifdef __CUDA_ARCH__
+ hd1d();
+#else
+ hd1h();
+#endif
+
+ // Errors as incorrectly guarded
+#ifndef __CUDA_ARCH__
+ hd1dig(); // expected-error {{no matching function}}
+#else
+ hd1hig(); // expected-error {{no matching function}}
+#endif
+
hd1hd();
hd1g<<<1, 1>>>(); // expected-error {{reference to __global__ function 'hd1g' in __host__ __device__ function}}
}
diff --git a/test/SemaCUDA/implicit-copy.cu b/test/SemaCUDA/implicit-copy.cu
new file mode 100644
index 000000000000..b1b4887f561b
--- /dev/null
+++ b/test/SemaCUDA/implicit-copy.cu
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -std=gnu++11 -triple nvptx64-unknown-unknown -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=gnu++11 -triple nvptx64-unknown-unknown -fcuda-is-device -fsyntax-only -verify %s
+
+struct CopyableH {
+ const CopyableH& operator=(const CopyableH& x) { return *this; }
+};
+struct CopyableD {
+ __attribute__((device)) const CopyableD& operator=(const CopyableD x) { return *this; }
+};
+
+struct SimpleH {
+ CopyableH b;
+};
+// expected-note@-3 2 {{candidate function (the implicit copy assignment operator) not viable: call to __host__ function from __device__ function}}
+// expected-note@-4 2 {{candidate function (the implicit move assignment operator) not viable: call to __host__ function from __device__ function}}
+
+struct SimpleD {
+ CopyableD b;
+};
+// expected-note@-3 2 {{candidate function (the implicit copy assignment operator) not viable: call to __device__ function from __host__ function}}
+// expected-note@-4 2 {{candidate function (the implicit move assignment operator) not viable: call to __device__ function from __host__ function}}
+
+void foo1hh() {
+ SimpleH a, b;
+ a = b;
+}
+__attribute__((device)) void foo1hd() {
+ SimpleH a, b;
+ a = b; // expected-error {{no viable overloaded}}
+}
+void foo1dh() {
+ SimpleD a, b;
+ a = b; // expected-error {{no viable overloaded}}
+}
+__attribute__((device)) void foo1dd() {
+ SimpleD a, b;
+ a = b;
+}
+
+void foo2hh(SimpleH &a, SimpleH &b) {
+ a = b;
+}
+__attribute__((device)) void foo2hd(SimpleH &a, SimpleH &b) {
+ a = b; // expected-error {{no viable overloaded}}
+}
+void foo2dh(SimpleD &a, SimpleD &b) {
+ a = b; // expected-error {{no viable overloaded}}
+}
+__attribute__((device)) void foo2dd(SimpleD &a, SimpleD &b) {
+ a = b;
+}
diff --git a/test/SemaCUDA/implicit-intrinsic.cu b/test/SemaCUDA/implicit-intrinsic.cu
new file mode 100644
index 000000000000..3d24aa719e57
--- /dev/null
+++ b/test/SemaCUDA/implicit-intrinsic.cu
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=gnu++11 -triple nvptx64-unknown-unknown -fsyntax-only -verify %s
+
+#include "Inputs/cuda.h"
+
+// expected-no-diagnostics
+__device__ void __threadfence_system() {
+ // This shouldn't produce an error, since __nvvm_membar_sys is inferred to
+ // be __host__ __device__ and thus callable from device code.
+ __nvvm_membar_sys();
+}
diff --git a/test/SemaCUDA/implicit-member-target-collision-cxx11.cu b/test/SemaCUDA/implicit-member-target-collision-cxx11.cu
new file mode 100644
index 000000000000..f038c376ff3c
--- /dev/null
+++ b/test/SemaCUDA/implicit-member-target-collision-cxx11.cu
@@ -0,0 +1,111 @@
+// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -verify %s
+
+#include "Inputs/cuda.h"
+
+//------------------------------------------------------------------------------
+// Test 1: collision between two bases
+
+struct A1_with_host_ctor {
+ A1_with_host_ctor() {}
+};
+
+struct B1_with_device_ctor {
+ __device__ B1_with_device_ctor() {}
+};
+
+struct C1_with_collision : A1_with_host_ctor, B1_with_device_ctor {
+};
+
+// expected-note@-3 {{candidate constructor (the implicit default constructor) not viable}}
+// expected-note@-4 {{implicit default constructor inferred target collision: call to both __host__ and __device__ members}}
+// expected-note@-5 {{candidate constructor (the implicit copy constructor) not viable}}
+// expected-note@-6 {{candidate constructor (the implicit move constructor) not viable}}
+
+void hostfoo1() {
+ C1_with_collision c; // expected-error {{no matching constructor}}
+}
+
+//------------------------------------------------------------------------------
+// Test 2: collision between two fields
+
+struct C2_with_collision {
+ A1_with_host_ctor aa;
+ B1_with_device_ctor bb;
+};
+
+// expected-note@-5 {{candidate constructor (the implicit default constructor}} not viable
+// expected-note@-6 {{implicit default constructor inferred target collision: call to both __host__ and __device__ members}}
+// expected-note@-7 {{candidate constructor (the implicit copy constructor}} not viable
+// expected-note@-8 {{candidate constructor (the implicit move constructor}} not viable
+
+void hostfoo2() {
+ C2_with_collision c; // expected-error {{no matching constructor}}
+}
+
+//------------------------------------------------------------------------------
+// Test 3: collision between a field and a base
+
+struct C3_with_collision : A1_with_host_ctor {
+ B1_with_device_ctor bb;
+};
+
+// expected-note@-4 {{candidate constructor (the implicit default constructor}} not viable
+// expected-note@-5 {{implicit default constructor inferred target collision: call to both __host__ and __device__ members}}
+// expected-note@-6 {{candidate constructor (the implicit copy constructor}} not viable
+// expected-note@-7 {{candidate constructor (the implicit move constructor}} not viable
+
+void hostfoo3() {
+ C3_with_collision c; // expected-error {{no matching constructor}}
+}
+
+//------------------------------------------------------------------------------
+// Test 4: collision on resolving a copy ctor
+
+struct A4_with_host_copy_ctor {
+ A4_with_host_copy_ctor() {}
+ A4_with_host_copy_ctor(const A4_with_host_copy_ctor&) {}
+};
+
+struct B4_with_device_copy_ctor {
+ B4_with_device_copy_ctor() {}
+ __device__ B4_with_device_copy_ctor(const B4_with_device_copy_ctor&) {}
+};
+
+struct C4_with_collision : A4_with_host_copy_ctor, B4_with_device_copy_ctor {
+};
+
+// expected-note@-3 {{candidate constructor (the implicit default constructor}} not viable
+// expected-note@-4 {{implicit copy constructor inferred target collision}}
+// expected-note@-5 {{candidate constructor (the implicit copy constructor}} not viable
+
+void hostfoo4() {
+ C4_with_collision c;
+ C4_with_collision c2 = c; // expected-error {{no matching constructor}}
+}
+
+//------------------------------------------------------------------------------
+// Test 5: collision on resolving a move ctor
+
+struct A5_with_host_move_ctor {
+ A5_with_host_move_ctor() {}
+ A5_with_host_move_ctor(A5_with_host_move_ctor&&) {}
+// expected-note@-1 {{copy constructor is implicitly deleted because 'A5_with_host_move_ctor' has a user-declared move constructor}}
+};
+
+struct B5_with_device_move_ctor {
+ B5_with_device_move_ctor() {}
+ __device__ B5_with_device_move_ctor(B5_with_device_move_ctor&&) {}
+};
+
+struct C5_with_collision : A5_with_host_move_ctor, B5_with_device_move_ctor {
+};
+// expected-note@-2 {{deleted}}
+
+void hostfoo5() {
+ C5_with_collision c;
+ // What happens here:
+ // This tries to find the move ctor. Since the move ctor is deleted due to
+ // collision, it then looks for a copy ctor. But copy ctors are implicitly
+ // deleted when move ctors are declared explicitly.
+ C5_with_collision c2(static_cast<C5_with_collision&&>(c)); // expected-error {{call to implicitly-deleted}}
+}
diff --git a/test/SemaCUDA/implicit-member-target-collision.cu b/test/SemaCUDA/implicit-member-target-collision.cu
new file mode 100644
index 000000000000..25cdccbfd35d
--- /dev/null
+++ b/test/SemaCUDA/implicit-member-target-collision.cu
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#include "Inputs/cuda.h"
+
+//------------------------------------------------------------------------------
+// Test 1: collision between two bases
+
+struct A1_with_host_ctor {
+ A1_with_host_ctor() {}
+};
+
+struct B1_with_device_ctor {
+ __device__ B1_with_device_ctor() {}
+};
+
+struct C1_with_collision : A1_with_host_ctor, B1_with_device_ctor {
+};
+
+// expected-note@-3 {{candidate constructor (the implicit default constructor}} not viable
+// expected-note@-4 {{implicit default constructor inferred target collision: call to both __host__ and __device__ members}}
+// expected-note@-5 {{candidate constructor (the implicit copy constructor}} not viable
+
+void hostfoo1() {
+ C1_with_collision c; // expected-error {{no matching constructor}}
+}
+
+//------------------------------------------------------------------------------
+// Test 2: collision between two fields
+
+struct C2_with_collision {
+ A1_with_host_ctor aa;
+ B1_with_device_ctor bb;
+};
+
+// expected-note@-5 {{candidate constructor (the implicit default constructor}} not viable
+// expected-note@-6 {{implicit default constructor inferred target collision: call to both __host__ and __device__ members}}
+// expected-note@-7 {{candidate constructor (the implicit copy constructor}} not viable
+
+void hostfoo2() {
+ C2_with_collision c; // expected-error {{no matching constructor}}
+
+}
+
+//------------------------------------------------------------------------------
+// Test 3: collision between a field and a base
+
+struct C3_with_collision : A1_with_host_ctor {
+ B1_with_device_ctor bb;
+};
+
+// expected-note@-4 {{candidate constructor (the implicit default constructor}} not viable
+// expected-note@-5 {{implicit default constructor inferred target collision: call to both __host__ and __device__ members}}
+// expected-note@-6 {{candidate constructor (the implicit copy constructor}} not viable
+
+void hostfoo3() {
+ C3_with_collision c; // expected-error {{no matching constructor}}
+}
diff --git a/test/SemaCUDA/implicit-member-target.cu b/test/SemaCUDA/implicit-member-target.cu
new file mode 100644
index 000000000000..6064560f2c6f
--- /dev/null
+++ b/test/SemaCUDA/implicit-member-target.cu
@@ -0,0 +1,186 @@
+// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -verify %s
+
+#include "Inputs/cuda.h"
+
+//------------------------------------------------------------------------------
+// Test 1: infer default ctor to be host.
+
+struct A1_with_host_ctor {
+ A1_with_host_ctor() {}
+};
+
+// The implicit default constructor is inferred to be host because it only needs
+// to invoke a single host constructor (A1_with_host_ctor's). So we'll encounter
+// an error when calling it from a __device__ function, but not from a __host__
+// function.
+struct B1_with_implicit_default_ctor : A1_with_host_ctor {
+};
+
+// expected-note@-3 {{call to __host__ function from __device__}}
+// expected-note@-4 {{candidate constructor (the implicit copy constructor) not viable}}
+// expected-note@-5 {{candidate constructor (the implicit move constructor) not viable}}
+
+void hostfoo() {
+ B1_with_implicit_default_ctor b;
+}
+
+__device__ void devicefoo() {
+ B1_with_implicit_default_ctor b; // expected-error {{no matching constructor}}
+}
+
+//------------------------------------------------------------------------------
+// Test 2: infer default ctor to be device.
+
+struct A2_with_device_ctor {
+ __device__ A2_with_device_ctor() {}
+};
+
+struct B2_with_implicit_default_ctor : A2_with_device_ctor {
+};
+
+// expected-note@-3 {{call to __device__ function from __host__}}
+// expected-note@-4 {{candidate constructor (the implicit copy constructor) not viable}}
+// expected-note@-5 {{candidate constructor (the implicit move constructor) not viable}}
+
+void hostfoo2() {
+ B2_with_implicit_default_ctor b; // expected-error {{no matching constructor}}
+}
+
+__device__ void devicefoo2() {
+ B2_with_implicit_default_ctor b;
+}
+
+//------------------------------------------------------------------------------
+// Test 3: infer copy ctor
+
+struct A3_with_device_ctors {
+ __host__ A3_with_device_ctors() {}
+ __device__ A3_with_device_ctors(const A3_with_device_ctors&) {}
+};
+
+struct B3_with_implicit_ctors : A3_with_device_ctors {
+};
+
+// expected-note@-3 {{copy constructor of 'B3_with_implicit_ctors' is implicitly deleted}}
+
+void hostfoo3() {
+ B3_with_implicit_ctors b; // this is OK because the inferred default ctor
+ // here is __host__
+ B3_with_implicit_ctors b2 = b; // expected-error {{call to implicitly-deleted copy constructor}}
+
+}
+
+//------------------------------------------------------------------------------
+// Test 4: infer default ctor from a field, not a base
+
+struct A4_with_host_ctor {
+ A4_with_host_ctor() {}
+};
+
+struct B4_with_implicit_default_ctor {
+ A4_with_host_ctor field;
+};
+
+// expected-note@-4 {{call to __host__ function from __device__}}
+// expected-note@-5 {{candidate constructor (the implicit copy constructor) not viable}}
+// expected-note@-6 {{candidate constructor (the implicit move constructor) not viable}}
+
+void hostfoo4() {
+ B4_with_implicit_default_ctor b;
+}
+
+__device__ void devicefoo4() {
+ B4_with_implicit_default_ctor b; // expected-error {{no matching constructor}}
+}
+
+//------------------------------------------------------------------------------
+// Test 5: copy ctor with non-const param
+
+struct A5_copy_ctor_constness {
+ __host__ A5_copy_ctor_constness() {}
+ __host__ A5_copy_ctor_constness(A5_copy_ctor_constness&) {}
+};
+
+struct B5_copy_ctor_constness : A5_copy_ctor_constness {
+};
+
+// expected-note@-3 {{candidate constructor (the implicit copy constructor) not viable: call to __host__ function from __device__ function}}
+// expected-note@-4 {{candidate constructor (the implicit default constructor) not viable}}
+
+void hostfoo5(B5_copy_ctor_constness& b_arg) {
+ B5_copy_ctor_constness b = b_arg;
+}
+
+__device__ void devicefoo5(B5_copy_ctor_constness& b_arg) {
+ B5_copy_ctor_constness b = b_arg; // expected-error {{no matching constructor}}
+}
+
+//------------------------------------------------------------------------------
+// Test 6: explicitly defaulted ctor: since they are spelled out, they have
+// a host/device designation explicitly so no inference needs to be done.
+
+struct A6_with_device_ctor {
+ __device__ A6_with_device_ctor() {}
+};
+
+struct B6_with_defaulted_ctor : A6_with_device_ctor {
+ __host__ B6_with_defaulted_ctor() = default;
+};
+
+// expected-note@-3 {{candidate constructor not viable: call to __host__ function from __device__ function}}
+// expected-note@-5 {{candidate constructor (the implicit copy constructor) not viable}}
+// expected-note@-6 {{candidate constructor (the implicit move constructor) not viable}}
+
+__device__ void devicefoo6() {
+ B6_with_defaulted_ctor b; // expected-error {{no matching constructor}}
+}
+
+//------------------------------------------------------------------------------
+// Test 7: copy assignment operator
+
+struct A7_with_copy_assign {
+ A7_with_copy_assign() {}
+ __device__ A7_with_copy_assign& operator=(const A7_with_copy_assign&) {}
+};
+
+struct B7_with_copy_assign : A7_with_copy_assign {
+};
+
+// expected-note@-3 {{candidate function (the implicit copy assignment operator) not viable: call to __device__ function from __host__ function}}
+// expected-note@-4 {{candidate function (the implicit move assignment operator) not viable: call to __device__ function from __host__ function}}
+
+void hostfoo7() {
+ B7_with_copy_assign b1, b2;
+ b1 = b2; // expected-error {{no viable overloaded '='}}
+}
+
+//------------------------------------------------------------------------------
+// Test 8: move assignment operator
+
+// definitions for std::move
+namespace std {
+inline namespace foo {
+template <class T> struct remove_reference { typedef T type; };
+template <class T> struct remove_reference<T&> { typedef T type; };
+template <class T> struct remove_reference<T&&> { typedef T type; };
+
+template <class T> typename remove_reference<T>::type&& move(T&& t);
+}
+}
+
+struct A8_with_move_assign {
+ A8_with_move_assign() {}
+ __device__ A8_with_move_assign& operator=(A8_with_move_assign&&) {}
+ __device__ A8_with_move_assign& operator=(const A8_with_move_assign&) {}
+};
+
+struct B8_with_move_assign : A8_with_move_assign {
+};
+
+// expected-note@-3 {{candidate function (the implicit copy assignment operator) not viable: call to __device__ function from __host__ function}}
+// expected-note@-4 {{candidate function (the implicit move assignment operator) not viable: call to __device__ function from __host__ function}}
+
+void hostfoo8() {
+ B8_with_move_assign b1, b2;
+ b1 = std::move(b2); // expected-error {{no viable overloaded '='}}
+}
diff --git a/test/SemaCUDA/launch_bounds.cu b/test/SemaCUDA/launch_bounds.cu
index bed7658aed59..8edc41b6ce91 100644
--- a/test/SemaCUDA/launch_bounds.cu
+++ b/test/SemaCUDA/launch_bounds.cu
@@ -6,9 +6,6 @@ __launch_bounds__(128, 7) void Test1(void);
__launch_bounds__(128) void Test2(void);
__launch_bounds__(1, 2, 3) void Test3(void); // expected-error {{'launch_bounds' attribute takes no more than 2 arguments}}
-
-// FIXME: the error should read that the attribute takes exactly one or two arguments, but there
-// is no support for such a diagnostic currently.
-__launch_bounds__() void Test4(void); // expected-error {{'launch_bounds' attribute takes no more than 2 arguments}}
+__launch_bounds__() void Test4(void); // expected-error {{'launch_bounds' attribute takes at least 1 argument}}
int Test5 __launch_bounds__(128, 7); // expected-warning {{'launch_bounds' attribute only applies to functions and methods}}
diff --git a/test/SemaCUDA/method-target.cu b/test/SemaCUDA/method-target.cu
new file mode 100644
index 000000000000..4fa290719cc1
--- /dev/null
+++ b/test/SemaCUDA/method-target.cu
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#include "Inputs/cuda.h"
+
+//------------------------------------------------------------------------------
+// Test 1: host method called from device function
+
+struct S1 {
+ void method() {}
+};
+
+__device__ void foo1(S1& s) {
+ s.method(); // expected-error {{reference to __host__ function 'method' in __device__ function}}
+}
+
+//------------------------------------------------------------------------------
+// Test 2: host method called from device function, for overloaded method
+
+struct S2 {
+ void method(int) {} // expected-note {{candidate function not viable: call to __host__ function from __device__ function}}
+ void method(float) {} // expected-note {{candidate function not viable: call to __host__ function from __device__ function}}
+};
+
+__device__ void foo2(S2& s, int i, float f) {
+ s.method(f); // expected-error {{no matching member function}}
+}
+
+//------------------------------------------------------------------------------
+// Test 3: device method called from host function
+
+struct S3 {
+ __device__ void method() {}
+};
+
+void foo3(S3& s) {
+ s.method(); // expected-error {{reference to __device__ function 'method' in __host__ function}}
+}
+
+//------------------------------------------------------------------------------
+// Test 4: device method called from host&device function
+
+struct S4 {
+ __device__ void method() {}
+};
+
+__host__ __device__ void foo4(S4& s) {
+ s.method(); // expected-error {{reference to __device__ function 'method' in __host__ __device__ function}}
+}
+
+//------------------------------------------------------------------------------
+// Test 5: overloaded operators
+
+struct S5 {
+ S5() {}
+ S5& operator=(const S5&) {return *this;} // expected-note {{candidate function not viable}}
+};
+
+__device__ void foo5(S5& s, S5& t) {
+ s = t; // expected-error {{no viable overloaded '='}}
+}
+
+//------------------------------------------------------------------------------
+// Test 6: call method through pointer
+
+struct S6 {
+ void method() {}
+};
+
+__device__ void foo6(S6* s) {
+ s->method(); // expected-error {{reference to __host__ function 'method' in __device__ function}}
+}
diff --git a/test/SemaCXX/Inputs/header-with-pragma-optimize-off.h b/test/SemaCXX/Inputs/header-with-pragma-optimize-off.h
new file mode 100644
index 000000000000..ac5020697eba
--- /dev/null
+++ b/test/SemaCXX/Inputs/header-with-pragma-optimize-off.h
@@ -0,0 +1,5 @@
+
+// Open an "off" region in this header.
+#pragma clang optimize off
+
+// Let the "off" region fall through to anything including this header.
diff --git a/test/SemaCXX/Inputs/override-system-header.h b/test/SemaCXX/Inputs/override-system-header.h
new file mode 100644
index 000000000000..9831ab7952b1
--- /dev/null
+++ b/test/SemaCXX/Inputs/override-system-header.h
@@ -0,0 +1,6 @@
+// override-system-header.h to test out 'override' warning.
+// rdar://18295240
+#define END_COM_MAP virtual unsigned AddRef(void) = 0;
+
+#define STDMETHOD(method) virtual void method
+#define IFACEMETHOD(method) STDMETHOD(method)
diff --git a/test/SemaCXX/MicrosoftCompatibility.cpp b/test/SemaCXX/MicrosoftCompatibility.cpp
index fb7d9751d1a5..56486b8f049a 100644
--- a/test/SemaCXX/MicrosoftCompatibility.cpp
+++ b/test/SemaCXX/MicrosoftCompatibility.cpp
@@ -34,7 +34,7 @@ namespace ms_protected_scope {
int jump_over_variable_init(bool b) {
if (b)
- goto foo; // expected-warning {{goto into protected scope}}
+ goto foo; // expected-warning {{jump from this goto statement to its label is a Microsoft extension}}
C c; // expected-note {{jump bypasses variable initialization}}
foo:
return 1;
@@ -45,7 +45,7 @@ struct Y {
};
void jump_over_var_with_dtor() {
- goto end; // expected-warning{{goto into protected scope}}
+ goto end; // expected-warning{{jump from this goto statement to its label is a Microsoft extension}}
Y y; // expected-note {{jump bypasses variable with a non-trivial destructor}}
end:
;
@@ -55,14 +55,14 @@ void jump_over_var_with_dtor() {
switch (c) {
case 0:
int x = 56; // expected-note {{jump bypasses variable initialization}}
- case 1: // expected-error {{switch case is in protected scope}}
+ case 1: // expected-error {{cannot jump}}
x = 10;
}
}
void exception_jump() {
- goto l2; // expected-error {{goto into protected scope}}
+ goto l2; // expected-error {{cannot jump}}
try { // expected-note {{jump bypasses initialization of try block}}
l2: ;
} catch(int) {
@@ -71,7 +71,7 @@ void exception_jump() {
int jump_over_indirect_goto() {
static void *ps[] = { &&a0 };
- goto *&&a0; // expected-warning {{goto into protected scope}}
+ goto *&&a0; // expected-warning {{jump from this goto statement to its label is a Microsoft extension}}
int a = 3; // expected-note {{jump bypasses variable initialization}}
a0:
return 0;
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index 6d221a409e7b..57d6f0d6bef2 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -79,6 +79,7 @@ struct M {
// __unaligned handling
typedef char __unaligned *aligned_type;
+typedef struct UnalignedTag { int f; } __unaligned *aligned_type2;
template<typename T> void h1(T (__stdcall M::* const )()) { }
@@ -372,14 +373,15 @@ struct SomeBase {
// expected-note@+2 {{overridden virtual function is here}}
// expected-warning@+1 {{'sealed' keyword is a Microsoft extension}}
- virtual void SealedFunction() sealed;
+ virtual void SealedFunction() sealed; // expected-note {{overridden virtual function is here}}
};
// expected-note@+2 {{'SealedType' declared here}}
// expected-warning@+1 {{'sealed' keyword is a Microsoft extension}}
struct SealedType sealed : SomeBase {
- // expected-error@+1 {{declaration of 'SealedFunction' overrides a 'sealed' function}}
- virtual void SealedFunction();
+ // expected-error@+2 {{declaration of 'SealedFunction' overrides a 'sealed' function}}
+ // FIXME. warning can be suppressed if we're also issuing error for overriding a 'final' function.
+ virtual void SealedFunction(); // expected-warning {{'SealedFunction' overrides a member function but is not marked 'override'}}
// expected-warning@+1 {{'override' keyword is a C++11 extension}}
virtual void OverrideMe() override;
diff --git a/test/SemaCXX/MicrosoftSuper.cpp b/test/SemaCXX/MicrosoftSuper.cpp
new file mode 100644
index 000000000000..cb21656ab762
--- /dev/null
+++ b/test/SemaCXX/MicrosoftSuper.cpp
@@ -0,0 +1,149 @@
+// RUN: %clang_cc1 %s -fsyntax-only -fms-extensions -std=c++11 -verify
+
+struct Errors {
+ using __super::foo; // expected-error {{'__super' cannot be used with a using declaration}}
+ __super::XXX x; // expected-error {{invalid use of '__super', Errors has no base classes}} expected-error {{expected}}
+
+ void foo() {
+ // expected-note@+4 {{replace parentheses with an initializer to declare a variable}}
+ // expected-warning@+3 {{empty parentheses interpreted as a function declaration}}
+ // expected-error@+2 {{C++ requires a type specifier for all declarations}}
+ // expected-error@+1 {{use of '__super' inside a lambda is unsupported}}
+ auto lambda = []{ __super::foo(); };
+ }
+};
+
+struct Base1 {
+ void foo(int) {}
+
+ static void static_foo() {}
+
+ typedef int XXX;
+};
+
+struct Derived : Base1 {
+ __super::XXX x;
+ typedef __super::XXX Type;
+
+ enum E {
+ X = sizeof(__super::XXX)
+ };
+
+ void foo() {
+ __super::foo(1);
+
+ if (true) {
+ __super::foo(1);
+ }
+
+ return __super::foo(1);
+ }
+
+ static void bar() {
+ __super::static_foo();
+ }
+};
+
+struct Outer {
+ struct Inner : Base1 {
+ static const int x = sizeof(__super::XXX);
+ };
+};
+
+struct Base2 {
+ void foo(char) {}
+};
+
+struct MemberFunctionInMultipleBases : Base1, Base2 {
+ void foo() {
+ __super::foo('x');
+ }
+};
+
+struct Base3 {
+ void foo(int) {}
+ void foo(char) {}
+};
+
+struct OverloadedMemberFunction : Base3 {
+ void foo() {
+ __super::foo('x');
+ }
+};
+
+struct PointerToMember : Base1 {
+ template <void (Base1::*MP)(int)>
+ struct Wrapper {
+ static void bar() {}
+ };
+
+ void baz();
+};
+
+void PointerToMember::baz() {
+ Wrapper<&__super::foo>::bar();
+}
+
+template <typename T>
+struct BaseTemplate {
+ typedef int XXX;
+
+ int foo() { return 0; }
+};
+
+struct DerivedFromKnownSpecialization : BaseTemplate<int> {
+ __super::XXX a;
+ typedef __super::XXX b;
+
+ void foo() {
+ __super::XXX c;
+ typedef __super::XXX d;
+
+ __super::foo();
+ }
+};
+
+template <typename T>
+struct DerivedFromDependentBase : BaseTemplate<T> {
+ typename __super::XXX a;
+ typedef typename __super::XXX b;
+
+ __super::XXX c; // expected-error {{missing 'typename'}}
+ typedef __super::XXX d; // expected-error {{missing 'typename'}}
+
+ void foo() {
+ typename __super::XXX e;
+ typedef typename __super::XXX f;
+
+ __super::XXX g; // expected-error {{missing 'typename'}}
+ typedef __super::XXX h; // expected-error {{missing 'typename'}}
+
+ int x = __super::foo();
+ }
+};
+
+template <typename T>
+struct DerivedFromTemplateParameter : T {
+ typename __super::XXX a;
+ typedef typename __super::XXX b;
+
+ __super::XXX c; // expected-error {{missing 'typename'}}
+ typedef __super::XXX d; // expected-error {{missing 'typename'}}
+
+ void foo() {
+ typename __super::XXX e;
+ typedef typename __super::XXX f;
+
+ __super::XXX g; // expected-error {{missing 'typename'}}
+ typedef __super::XXX h; // expected-error {{missing 'typename'}}
+
+ __super::foo(1);
+ }
+};
+
+void instantiate() {
+ DerivedFromDependentBase<int> d;
+ d.foo();
+ DerivedFromTemplateParameter<Base1> t;
+ t.foo();
+}
diff --git a/test/SemaCXX/PR10177.cpp b/test/SemaCXX/PR10177.cpp
index 8d745de0a6a1..e361ff37bc03 100644
--- a/test/SemaCXX/PR10177.cpp
+++ b/test/SemaCXX/PR10177.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y -verify %s -DCXX1Y
+
+#ifndef CXX1Y
template<typename T, typename U, U> using alias_ref = T;
template<typename T, typename U, U> void func_ref() {}
@@ -9,22 +12,29 @@ struct U {
static int a;
};
-template<int N> struct S; // expected-note 2{{here}}
+template<int N> struct S; // expected-note 6{{here}}
template<int N>
-int U<N>::a = S<N>::kError; // expected-error 2{{undefined}}
+int U<N>::a = S<N>::kError; // expected-error 6{{undefined}}
template<typename T>
void f() {
- // FIXME: The standard suggests that U<0>::a is odr-used by this expression,
- // but it's not entirely clear that's the right behaviour.
- (void)alias_ref<int, int&, U<0>::a>();
+ (void)alias_ref<int, int&, U<0>::a>(); // expected-note {{here}}
(void)func_ref<int, int&, U<1>::a>(); // expected-note {{here}}
(void)class_ref<int, int&, U<2>::a>(); // expected-note {{here}}
};
+
+template<int N>
+void fi() {
+ (void)alias_ref<int, int&, U<N>::a>(); // expected-note {{here}}
+ (void)func_ref<int, int&, U<N+1>::a>(); // expected-note {{here}}
+ (void)class_ref<int, int&, U<N+2>::a>(); // expected-note {{here}}
+};
+
int main() {
- f<int>(); // expected-note 2{{here}}
+ f<int>(); // NOTE: Non-dependent name uses are type-checked at template definition time.
+ fi<10>(); // expected-note 3{{here}}
}
namespace N {
@@ -38,3 +48,12 @@ namespace N {
}
int j = f<int>();
}
+
+#else
+// expected-no-diagnostics
+
+namespace { template<typename> extern int n; }
+template<typename T> int g() { return n<int>; }
+
+#endif
+
diff --git a/test/SemaCXX/PR20705.cpp b/test/SemaCXX/PR20705.cpp
new file mode 100644
index 000000000000..be2676e56356
--- /dev/null
+++ b/test/SemaCXX/PR20705.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+template <typename T>
+struct X {};
+auto b = []() {
+ struct S {
+ static typename X<decltype(int)>::type Run(){};
+ // expected-error@-1 4{{}}
+ };
+ return 5;
+}();
+
+template <typename T1, typename T2>
+class PC {
+};
+
+template <typename T>
+class P {
+ static typename PC<T, Invalid>::Type Foo();
+ // expected-error@-1 4{{}}
+};
diff --git a/test/SemaCXX/align_value.cpp b/test/SemaCXX/align_value.cpp
new file mode 100644
index 000000000000..519868201f99
--- /dev/null
+++ b/test/SemaCXX/align_value.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef double * __attribute__((align_value(64))) aligned_double;
+
+void foo(aligned_double x, double * y __attribute__((align_value(32))),
+ double & z __attribute__((align_value(128)))) { };
+
+template <typename T, int Q>
+struct x {
+ typedef T* aligned_int __attribute__((align_value(32+8*Q)));
+ aligned_int V;
+
+ void foo(aligned_int a, T &b __attribute__((align_value(sizeof(T)*4))));
+};
+
+x<float, 4> y;
+
+template <typename T, int Q>
+struct nope {
+ // expected-error@+1 {{requested alignment is not a power of 2}}
+ void foo(T &b __attribute__((align_value(sizeof(T)+1))));
+};
+
+// expected-note@+1 {{in instantiation of template class 'nope<long double, 4>' requested here}}
+nope<long double, 4> y2;
+
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index fde27b049d88..46d426cf0c0f 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -80,10 +80,14 @@ union { // expected-error{{anonymous unions at namespace or global scope must be
};
static union {
- int int_val2;
+ int int_val2; // expected-note{{previous definition is here}}
float float_val2;
};
+void PR21858() {
+ void int_val2(); // expected-error{{redefinition of 'int_val2' as different kind of symbol}}
+}
+
void f() {
int_val2 = 0;
float_val2 = 0.0;
diff --git a/test/SemaCXX/arrow-operator.cpp b/test/SemaCXX/arrow-operator.cpp
index 173ff729fc1b..3e32a6ba33eb 100644
--- a/test/SemaCXX/arrow-operator.cpp
+++ b/test/SemaCXX/arrow-operator.cpp
@@ -52,14 +52,15 @@ class wrapped_ptr {
class Worker {
public:
- void DoSomething();
+ void DoSomething(); // expected-note {{'DoSomething' declared here}}
void Chuck();
};
void test() {
wrapped_ptr<Worker> worker(new Worker);
worker.DoSomething(); // expected-error {{no member named 'DoSomething' in 'arrow_suggest::wrapped_ptr<arrow_suggest::Worker>'; did you mean to use '->' instead of '.'?}}
- worker.DoSamething(); // expected-error {{no member named 'DoSamething' in 'arrow_suggest::wrapped_ptr<arrow_suggest::Worker>'}}
+ worker.DoSamething(); // expected-error {{no member named 'DoSamething' in 'arrow_suggest::wrapped_ptr<arrow_suggest::Worker>'; did you mean to use '->' instead of '.'?}} \
+ // expected-error {{no member named 'DoSamething' in 'arrow_suggest::Worker'; did you mean 'DoSomething'?}}
worker.Chuck(); // expected-error {{no member named 'Chuck' in 'arrow_suggest::wrapped_ptr<arrow_suggest::Worker>'; did you mean 'Check'?}}
}
diff --git a/test/SemaCXX/ast-print.cpp b/test/SemaCXX/ast-print.cpp
index 4851571283f4..baece3c2b320 100644
--- a/test/SemaCXX/ast-print.cpp
+++ b/test/SemaCXX/ast-print.cpp
@@ -208,3 +208,8 @@ void test(int i) {
}
}
}
+
+namespace {
+// CHECK: struct {{\[\[gnu::visibility\(\"hidden\"\)\]\]}} S;
+struct [[gnu::visibility("hidden")]] S;
+}
diff --git a/test/SemaCXX/atomic-type.cpp b/test/SemaCXX/atomic-type.cpp
index ae18eab5b4a9..779b0671cad6 100644
--- a/test/SemaCXX/atomic-type.cpp
+++ b/test/SemaCXX/atomic-type.cpp
@@ -83,3 +83,7 @@ namespace copy_init {
// allows extraneous braces around initializers.
Y y3 = { { X(0) }, { 4 } }; // expected-error 2{{illegal initializer type}}
}
+
+bool PR21836(_Atomic(int) *x) {
+ return *x;
+}
diff --git a/test/SemaCXX/attr-cxx0x-fixit.cpp b/test/SemaCXX/attr-cxx0x-fixit.cpp
new file mode 100644
index 000000000000..69eb22399607
--- /dev/null
+++ b/test/SemaCXX/attr-cxx0x-fixit.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++11 %s 2>&1 | FileCheck %s
+
+[[noreturn()]] void f(); // expected-error {{attribute 'noreturn' cannot have an argument list}} \
+// CHECK: fix-it:"{{.*}}":{4:11-4:13}:""
diff --git a/test/SemaCXX/attr-flag-enum-reject.cpp b/test/SemaCXX/attr-flag-enum-reject.cpp
new file mode 100644
index 000000000000..f28d60c0c295
--- /dev/null
+++ b/test/SemaCXX/attr-flag-enum-reject.cpp
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -Wassign-enum %s
+
+enum __attribute__((flag_enum)) flag { // expected-warning {{ignored}}
+};
diff --git a/test/SemaCXX/attr-gnu.cpp b/test/SemaCXX/attr-gnu.cpp
new file mode 100644
index 000000000000..b4e9f4609f67
--- /dev/null
+++ b/test/SemaCXX/attr-gnu.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -fms-compatibility -verify %s
+
+void f() {
+ // GNU-style attributes are prohibited in this position.
+ auto P = new int * __attribute__((vector_size(8))); // expected-error {{an attribute list cannot appear here}} \
+ // expected-error {{invalid vector element type 'int *'}}
+
+ // Ensure that MS type attribute keywords are still supported in this
+ // position.
+ auto P2 = new int * __sptr; // Ok
+}
+
+void g(int a[static [[]] 5]); // expected-error {{static array size is a C99 feature, not permitted in C++}}
+
+namespace {
+class B {
+public:
+ virtual void test() {}
+ virtual void test2() {}
+ virtual void test3() {}
+};
+
+class D : public B {
+public:
+ void test() __attribute__((deprecated)) final {} // expected-warning {{GCC does not allow an attribute in this position on a function declaration}}
+ void test2() [[]] override {} // Ok
+ void test3() __attribute__((cf_unknown_transfer)) override {} // Ok, not known to GCC.
+};
+}
diff --git a/test/SemaCXX/attr-nodebug.cpp b/test/SemaCXX/attr-nodebug.cpp
index b441da21f8e7..fd35722f62b1 100644
--- a/test/SemaCXX/attr-nodebug.cpp
+++ b/test/SemaCXX/attr-nodebug.cpp
@@ -1,7 +1,9 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -std=c++11 -verify -fsyntax-only
// Note: most of the 'nodebug' tests are in attr-nodebug.c.
// expected-no-diagnostics
class c {
void t3() __attribute__((nodebug));
};
+
+[[gnu::nodebug]] void f() {}
diff --git a/test/SemaCXX/attr-nonnull.cpp b/test/SemaCXX/attr-nonnull.cpp
index 8af49d9d29e6..8fce99759b6a 100644
--- a/test/SemaCXX/attr-nonnull.cpp
+++ b/test/SemaCXX/attr-nonnull.cpp
@@ -27,8 +27,8 @@ namespace rdar8769025 {
__attribute__((nonnull(2))) void f2(int i, int * const &p);
void test_f1() {
- f1(0); // expected-warning{{null passed to a callee which requires a non-null argument}}
- f2(0, 0); // expected-warning{{null passed to a callee which requires a non-null argument}}
+ f1(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+ f2(0, 0); // expected-warning{{null passed to a callee that requires a non-null argument}}
}
}
diff --git a/test/SemaCXX/attr-optnone.cpp b/test/SemaCXX/attr-optnone.cpp
index eaa50004047c..58776caf7ae6 100644
--- a/test/SemaCXX/attr-optnone.cpp
+++ b/test/SemaCXX/attr-optnone.cpp
@@ -3,11 +3,37 @@
int foo() __attribute__((optnone));
int bar() __attribute__((optnone)) __attribute__((noinline));
-int baz() __attribute__((always_inline)) __attribute__((optnone)); // expected-error{{'always_inline' and 'optnone' attributes are not compatible}}
-int quz() __attribute__((optnone)) __attribute__((always_inline)); // expected-error{{'optnone' and 'always_inline' attributes are not compatible}}
+int baz() __attribute__((always_inline)) __attribute__((optnone)); // expected-warning{{'always_inline' attribute ignored}} expected-note{{conflicting attribute is here}}
+int quz() __attribute__((optnone)) __attribute__((always_inline)); // expected-warning{{'always_inline' attribute ignored}} expected-note{{conflicting attribute is here}}
-__forceinline __attribute__((optnone)) int bax(); // expected-error{{'__forceinline' and 'optnone' attributes are not compatible}}
-__attribute__((optnone)) __forceinline int qux(); // expected-error{{'optnone' and '__forceinline' attributes are not compatible}}
+__attribute__((always_inline)) int baz1(); // expected-warning{{'always_inline' attribute ignored}}
+__attribute__((optnone)) int baz1() { return 1; } // expected-note{{conflicting attribute is here}}
+
+__attribute__((optnone)) int quz1(); // expected-note{{conflicting attribute is here}}
+__attribute__((always_inline)) int quz1() { return 1; } // expected-warning{{'always_inline' attribute ignored}}
+
+int bay() __attribute__((minsize)) __attribute__((optnone)); // expected-warning{{'minsize' attribute ignored}} expected-note{{conflicting}}
+int quy() __attribute__((optnone)) __attribute__((minsize)); // expected-warning{{'minsize' attribute ignored}} expected-note{{conflicting}}
+
+__attribute__((minsize)) int bay1(); // expected-warning{{'minsize' attribute ignored}}
+__attribute__((optnone)) int bay1() { return 1; } // expected-note{{conflicting attribute is here}}
+
+__attribute__((optnone)) int quy1(); // expected-note{{conflicting attribute is here}}
+__attribute__((minsize)) int quy1() { return 1; } // expected-warning{{'minsize' attribute ignored}}
+
+__attribute__((always_inline)) // expected-warning{{'always_inline' attribute ignored}}
+ __attribute__((minsize)) // expected-warning{{'minsize' attribute ignored}}
+void bay2();
+__attribute__((optnone)) // expected-note 2 {{conflicting}}
+void bay2() {}
+
+__forceinline __attribute__((optnone)) int bax(); // expected-warning{{'__forceinline' attribute ignored}} expected-note{{conflicting}}
+__attribute__((optnone)) __forceinline int qux(); // expected-warning{{'__forceinline' attribute ignored}} expected-note{{conflicting}}
+
+__forceinline int bax2(); // expected-warning{{'__forceinline' attribute ignored}}
+__attribute__((optnone)) int bax2() { return 1; } // expected-note{{conflicting}}
+__attribute__((optnone)) int qux2(); // expected-note{{conflicting}}
+__forceinline int qux2() { return 1; } // expected-warning{{'__forceinline' attribute ignored}}
int globalVar __attribute__((optnone)); // expected-warning{{'optnone' attribute only applies to functions}}
@@ -29,8 +55,8 @@ int foo2();
[[clang::optnone]]
int bar2() __attribute__((noinline));
-[[clang::optnone]]
-int baz2() __attribute__((always_inline)); // expected-error{{'always_inline' and 'optnone' attributes are not compatible}}
+[[clang::optnone]] // expected-note {{conflicting}}
+int baz2() __attribute__((always_inline)); // expected-warning{{'always_inline' attribute ignored}}
[[clang::optnone]] int globalVar2; //expected-warning{{'optnone' attribute only applies to functions}}
diff --git a/test/SemaCXX/attr-print.cpp b/test/SemaCXX/attr-print.cpp
index a07eeff5646e..337a6fb69ba3 100644
--- a/test/SemaCXX/attr-print.cpp
+++ b/test/SemaCXX/attr-print.cpp
@@ -22,3 +22,12 @@ typedef int Small1 __attribute__((mode(byte)));
// CHECK: int small __attribute__((mode(byte)));
int small __attribute__((mode(byte)));
+
+// CHECK: int v __attribute__((visibility("hidden")));
+int v __attribute__((visibility("hidden")));
+
+// CHECK: class __attribute__((consumable("unknown"))) AttrTester1
+class __attribute__((consumable(unknown))) AttrTester1 {
+ // CHECK: void callableWhen() __attribute__((callable_when("unconsumed", "consumed")));
+ void callableWhen() __attribute__((callable_when("unconsumed", "consumed")));
+};
diff --git a/test/SemaCXX/attributed-auto-deduction.cpp b/test/SemaCXX/attributed-auto-deduction.cpp
new file mode 100644
index 000000000000..b0cae187e8e3
--- /dev/null
+++ b/test/SemaCXX/attributed-auto-deduction.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple armv7 -std=c++14 -x c++ %s -fsyntax-only
+// expected-no-diagnostics
+
+void deduce() {
+ auto single_int = [](int i) __attribute__ (( pcs("aapcs") )) {
+ return i;
+ };
+ auto multiple_int = [](int i) __attribute__ (( pcs("aapcs") ))
+ __attribute__ (( pcs("aapcs") )) {
+ return i;
+ };
+
+ auto single_void = []() __attribute__ (( pcs("aapcs") )) { };
+ auto multiple_void = []() __attribute__ (( pcs("aapcs") ))
+ __attribute__ (( pcs("aapcs") )) { };
+}
+
+auto ( __attribute__ (( pcs("aapcs") )) single_attribute() ) { }
+auto ( ( __attribute__ (( pcs("aapcs") )) ( ( __attribute__ (( pcs("aapcs") )) multiple_attributes() ) ) ) ) { }
+
diff --git a/test/SemaCXX/bitfield.cpp b/test/SemaCXX/bitfield.cpp
new file mode 100644
index 000000000000..083c28ffbb3d
--- /dev/null
+++ b/test/SemaCXX/bitfield.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 %s -verify
+
+// expected-no-diagnostics
+
+namespace PromotionVersusMutation {
+ typedef unsigned Unsigned;
+ typedef signed Signed;
+
+ struct T { unsigned n : 2; } t;
+
+ typedef __typeof__(t.n) Unsigned; // Bitfield is unsigned
+ typedef __typeof__(+t.n) Signed; // ... but promotes to signed.
+
+ typedef __typeof__(t.n + 0) Signed; // Arithmetic promotes.
+
+ typedef __typeof__(t.n = 0) Unsigned; // Assignment produces an lvalue...
+ typedef __typeof__(t.n += 0) Unsigned;
+ typedef __typeof__(t.n *= 0) Unsigned;
+ typedef __typeof__(+(t.n = 0)) Signed; // ... which is a bit-field.
+ typedef __typeof__(+(t.n += 0)) Signed;
+ typedef __typeof__(+(t.n *= 0)) Signed;
+
+ typedef __typeof__(++t.n) Unsigned; // Increment is equivalent to compound-assignment.
+ typedef __typeof__(--t.n) Unsigned;
+ typedef __typeof__(+(++t.n)) Signed;
+ typedef __typeof__(+(--t.n)) Signed;
+
+ typedef __typeof__(t.n++) Unsigned; // Post-increment's result has the type
+ typedef __typeof__(t.n--) Unsigned; // of the operand...
+ typedef __typeof__(+(t.n++)) Unsigned; // ... and is not a bit-field (because
+ typedef __typeof__(+(t.n--)) Unsigned; // it's not a glvalue).
+}
diff --git a/test/SemaCXX/blocks.cpp b/test/SemaCXX/blocks.cpp
index a2672d13b72d..0521802172f9 100644
--- a/test/SemaCXX/blocks.cpp
+++ b/test/SemaCXX/blocks.cpp
@@ -100,3 +100,48 @@ namespace test5 {
});
}
}
+
+
+// rdar://16356628
+//
+// Ensure that we can end function bodies while parsing an
+// expression that requires an explicitly-tracked cleanup object
+// (i.e. a block literal).
+
+// The nested function body in this test case is a template
+// instantiation. The template function has to be constexpr because
+// we'll otherwise delay its instantiation to the end of the
+// translation unit.
+namespace test6a {
+ template <class T> constexpr int func() { return 0; }
+ void run(void (^)(), int);
+
+ void test() {
+ int aCapturedVar = 0;
+ run(^{ (void) aCapturedVar; }, func<int>());
+ }
+}
+
+// The nested function body in this test case is a method of a local
+// class.
+namespace test6b {
+ void run(void (^)(), void (^)());
+ void test() {
+ int aCapturedVar = 0;
+ run(^{ (void) aCapturedVar; },
+ ^{ struct A { static void foo() {} };
+ A::foo(); });
+ }
+}
+
+// The nested function body in this test case is a lambda invocation
+// function.
+namespace test6c {
+ void run(void (^)(), void (^)());
+ void test() {
+ int aCapturedVar = 0;
+ run(^{ (void) aCapturedVar; },
+ ^{ struct A { static void foo() {} };
+ A::foo(); });
+ }
+}
diff --git a/test/SemaCXX/builtin-assume-aligned-tmpl.cpp b/test/SemaCXX/builtin-assume-aligned-tmpl.cpp
new file mode 100644
index 000000000000..0909070c5e11
--- /dev/null
+++ b/test/SemaCXX/builtin-assume-aligned-tmpl.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<int z>
+int test9(int *a) {
+ a = (int *) __builtin_assume_aligned(a, z + 1); // expected-error {{requested alignment is not a power of 2}}
+ return a[0];
+}
+
+void test9i(int *a) {
+ test9<42>(a); // expected-note {{in instantiation of function template specialization 'test9<42>' requested here}}
+}
+
+template<typename T>
+int test10(int *a, T z) {
+ a = (int *) __builtin_assume_aligned(a, z + 1); // expected-error {{must be a constant integer}}
+ return a[0];
+}
+
+int test10i(int *a) {
+ return test10(a, 42); // expected-note {{in instantiation of function template specialization 'test10<int>' requested here}}
+}
+
+template <int q>
+void *atest() __attribute__((assume_aligned(q))); // expected-error {{requested alignment is not a power of 2}}
+
+template <int q, int o>
+void *atest2() __attribute__((assume_aligned(q, o))); // expected-error {{requested alignment is not a power of 2}}
+
+void test20() {
+ atest<31>(); // expected-note {{in instantiation of function template specialization 'atest<31>' requested here}}
+ atest<32>();
+
+ atest2<31, 5>(); // expected-note {{in instantiation of function template specialization 'atest2<31, 5>' requested here}}
+ atest2<32, 4>();
+}
+
+// expected-error@+1 {{invalid application of 'sizeof' to a function type}}
+template<typename T> __attribute__((assume_aligned(sizeof(int(T()))))) T *f();
+void test21() {
+ void *p = f<void>(); // expected-note {{in instantiation of function template specialization 'f<void>' requested here}}
+}
+
+// expected-error@+1 {{functional-style cast from 'void' to 'int' is not allowed}}
+template<typename T> __attribute__((assume_aligned(sizeof((int(T())))))) T *g();
+void test23() {
+ void *p = g<void>(); // expected-note {{in instantiation of function template specialization 'g<void>' requested here}}
+}
+
+template <typename T, int o>
+T *atest3() __attribute__((assume_aligned(31, o))); // expected-error {{requested alignment is not a power of 2}}
+
+template <typename T, int o>
+T *atest4() __attribute__((assume_aligned(32, o)));
+
+void test22() {
+ atest3<int, 5>();
+ atest4<int, 5>();
+}
+
+// expected-warning@+1 {{'assume_aligned' attribute only applies to functions and methods}}
+class __attribute__((assume_aligned(32))) x {
+ int y;
+};
+
+// expected-warning@+1 {{'assume_aligned' attribute only applies to return values that are pointers or references}}
+x foo() __attribute__((assume_aligned(32)));
+
+struct s1 {
+ static const int x = 32;
+};
+
+struct s2 {
+ static const int x = 64;
+};
+
+struct s3 {
+ static const int x = 63;
+};
+
+template <typename X>
+void *atest5() __attribute__((assume_aligned(X::x))); // expected-error {{requested alignment is not a power of 2}}
+void test24() {
+ atest5<s1>();
+ atest5<s2>();
+ atest5<s3>(); // expected-note {{in instantiation of function template specialization 'atest5<s3>' requested here}}
+}
+
diff --git a/test/SemaCXX/builtin-assume-aligned.cpp b/test/SemaCXX/builtin-assume-aligned.cpp
new file mode 100644
index 000000000000..48bd8414fc50
--- /dev/null
+++ b/test/SemaCXX/builtin-assume-aligned.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -triple x86_64-linux-gnu %s
+
+int n;
+constexpr int *p = 0;
+// expected-error@+1 {{must be initialized by a constant expression}}
+constexpr int *k = (int *) __builtin_assume_aligned(p, 16, n = 5);
+
+constexpr void *l = __builtin_assume_aligned(p, 16);
+
+// expected-error@+2 {{must be initialized by a constant expression}}
+// expected-note@+1 {{cast from 'void *' is not allowed in a constant expression}}
+constexpr int *c = (int *) __builtin_assume_aligned(p, 16);
+
+// expected-error@+2 {{must be initialized by a constant expression}}
+// expected-note@+1 {{alignment of the base pointee object (4 bytes) is less than the asserted 16 bytes}}
+constexpr void *m = __builtin_assume_aligned(&n, 16);
+
+// expected-error@+2 {{must be initialized by a constant expression}}
+// expected-note@+1 {{offset of the aligned pointer from the base pointee object (-2 bytes) is not a multiple of the asserted 4 bytes}}
+constexpr void *q1 = __builtin_assume_aligned(&n, 4, 2);
+// expected-error@+2 {{must be initialized by a constant expression}}
+// expected-note@+1 {{offset of the aligned pointer from the base pointee object (2 bytes) is not a multiple of the asserted 4 bytes}}
+constexpr void *q2 = __builtin_assume_aligned(&n, 4, -2);
+constexpr void *q3 = __builtin_assume_aligned(&n, 4, 4);
+constexpr void *q4 = __builtin_assume_aligned(&n, 4, -4);
+
+static char ar1[6];
+// expected-error@+2 {{must be initialized by a constant expression}}
+// expected-note@+1 {{alignment of the base pointee object (1 byte) is less than the asserted 16 bytes}}
+constexpr void *r1 = __builtin_assume_aligned(&ar1[2], 16);
+
+static char ar2[6] __attribute__((aligned(32)));
+// expected-error@+2 {{must be initialized by a constant expression}}
+// expected-note@+1 {{offset of the aligned pointer from the base pointee object (2 bytes) is not a multiple of the asserted 16 bytes}}
+constexpr void *r2 = __builtin_assume_aligned(&ar2[2], 16);
+constexpr void *r3 = __builtin_assume_aligned(&ar2[2], 16, 2);
+// expected-error@+2 {{must be initialized by a constant expression}}
+// expected-note@+1 {{offset of the aligned pointer from the base pointee object (1 byte) is not a multiple of the asserted 16 bytes}}
+constexpr void *r4 = __builtin_assume_aligned(&ar2[2], 16, 1);
+
+constexpr int* x = __builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF;
+// expected-error@+2 {{must be initialized by a constant expression}}
+// expected-note@+1 {{value of the aligned pointer (255) is not a multiple of the asserted 32 bytes}}
+constexpr void *s1 = __builtin_assume_aligned(x, 32);
+// expected-error@+2 {{must be initialized by a constant expression}}
+// expected-note@+1 {{value of the aligned pointer (250) is not a multiple of the asserted 32 bytes}}
+constexpr void *s2 = __builtin_assume_aligned(x, 32, 5);
+constexpr void *s3 = __builtin_assume_aligned(x, 32, -1);
+
diff --git a/test/SemaCXX/call-with-static-chain.cpp b/test/SemaCXX/call-with-static-chain.cpp
new file mode 100644
index 000000000000..45fe2ac29472
--- /dev/null
+++ b/test/SemaCXX/call-with-static-chain.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int &f();
+
+struct A {
+ void f();
+};
+
+typedef int I;
+
+void g() {
+ __builtin_call_with_static_chain(f(), f) = 42;
+ __builtin_call_with_static_chain(A().f(), f); // expected-error {{first argument to __builtin_call_with_static_chain must be a non-member call expression}}
+ __builtin_call_with_static_chain((42).~I(), f); // expected-error {{first argument to __builtin_call_with_static_chain must not be a pseudo-destructor call}}
+}
diff --git a/test/SemaCXX/complex-folding.cpp b/test/SemaCXX/complex-folding.cpp
new file mode 100644
index 000000000000..1c2f9c73eb31
--- /dev/null
+++ b/test/SemaCXX/complex-folding.cpp
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 %s -std=c++1z -fsyntax-only -verify
+//
+// Test the constant folding of builtin complex numbers.
+
+static_assert((0.0 + 0.0j) == (0.0 + 0.0j));
+static_assert((0.0 + 0.0j) != (0.0 + 0.0j)); // expected-error {{static_assert}}
+
+static_assert((0.0 + 0.0j) == 0.0);
+static_assert(0.0 == (0.0 + 0.0j));
+static_assert(0.0 == 0.0j);
+static_assert((0.0 + 1.0j) != 0.0);
+static_assert(1.0 != (0.0 + 0.0j));
+static_assert(0.0 != 1.0j);
+
+// Walk around the complex plane stepping between angular differences and
+// equality.
+static_assert((1.0 + 0.0j) == (0.0 + 0.0j)); // expected-error {{static_assert}}
+static_assert((1.0 + 0.0j) == (1.0 + 0.0j));
+static_assert((1.0 + 1.0j) == (1.0 + 0.0j)); // expected-error {{static_assert}}
+static_assert((1.0 + 1.0j) == (1.0 + 1.0j));
+static_assert((0.0 + 1.0j) == (1.0 + 1.0j)); // expected-error {{static_assert}}
+static_assert((0.0 + 1.0j) == (0.0 + 1.0j));
+static_assert((-1.0 + 1.0j) == (0.0 + 1.0j)); // expected-error {{static_assert}}
+static_assert((-1.0 + 1.0j) == (-1.0 + 1.0j));
+static_assert((-1.0 + 0.0j) == (-1.0 + 1.0j)); // expected-error {{static_assert}}
+static_assert((-1.0 + 0.0j) == (-1.0 + 0.0j));
+static_assert((-1.0 - 1.0j) == (-1.0 + 0.0j)); // expected-error {{static_assert}}
+static_assert((-1.0 - 1.0j) == (-1.0 - 1.0j));
+static_assert((0.0 - 1.0j) == (-1.0 - 1.0j)); // expected-error {{static_assert}}
+static_assert((0.0 - 1.0j) == (0.0 - 1.0j));
+static_assert((1.0 - 1.0j) == (0.0 - 1.0j)); // expected-error {{static_assert}}
+static_assert((1.0 - 1.0j) == (1.0 - 1.0j));
+
+// Test basic mathematical folding of both complex and real operands.
+static_assert(((1.0 + 0.5j) + (0.25 - 0.75j)) == (1.25 - 0.25j));
+static_assert(((1.0 + 0.5j) + 0.25) == (1.25 + 0.5j));
+static_assert((1.0 + (0.25 - 0.75j)) == (1.25 - 0.75j));
+
+static_assert(((1.0 + 0.5j) - (0.25 - 0.75j)) == (0.75 + 1.25j));
+static_assert(((1.0 + 0.5j) - 0.25) == (0.75 + 0.5j));
+static_assert((1.0 - (0.25 - 0.75j)) == (0.75 + 0.75j));
+
+static_assert(((1.25 + 0.5j) * (0.25 - 0.75j)) == (0.6875 - 0.8125j));
+static_assert(((1.25 + 0.5j) * 0.25) == (0.3125 + 0.125j));
+static_assert((1.25 * (0.25 - 0.75j)) == (0.3125 - 0.9375j));
+
+static_assert(((1.25 + 0.5j) / (0.25 - 0.75j)) == (-0.1 + 1.7j));
+static_assert(((1.25 + 0.5j) / 0.25) == (5.0 + 2.0j));
+static_assert((1.25 / (0.25 - 0.75j)) == (0.5 + 1.5j));
+
+// Test that infinities are preserved, don't turn into NaNs, and do form zeros
+// when the divisor.
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * 1.0)) == 1);
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * 1.0)) == 1);
+static_assert(__builtin_isinf_sign(__real__(1.0 * (__builtin_inf() + 1.0j))) == 1);
+static_assert(__builtin_isinf_sign(__imag__(1.0 * (1.0 + __builtin_inf() * 1.0j))) == 1);
+
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * (1.0 + 1.0j))) == 1);
+static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (__builtin_inf() + 1.0j))) == 1);
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * (__builtin_inf() + 1.0j))) == 1);
+
+static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * (1.0 + 1.0j))) == -1);
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * (1.0 + 1.0j))) == 1);
+static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == -1);
+static_assert(__builtin_isinf_sign(__imag__((1.0 + 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == 1);
+
+static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == -1);
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + __builtin_inf() * 1.0j) * (__builtin_inf() + __builtin_inf() * 1.0j))) == -1);
+
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / (1.0 + 1.0j))) == 1);
+static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / (1.0 + 1.0j))) == 1);
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / (1.0 + 1.0j))) == 1);
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 1.0)) == 1);
+static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / 1.0)) == 1);
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / 1.0)) == 1);
+
+static_assert(((1.0 + 1.0j) / (__builtin_inf() + 1.0j)) == (0.0 + 0.0j));
+static_assert(((1.0 + 1.0j) / (1.0 + __builtin_inf() * 1.0j)) == (0.0 + 0.0j));
+static_assert(((1.0 + 1.0j) / (__builtin_inf() + __builtin_inf() * 1.0j)) == (0.0 + 0.0j));
+static_assert(((1.0 + 1.0j) / __builtin_inf()) == (0.0 + 0.0j));
+
+static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / (0.0 + 0.0j))) == 1);
+static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / 0.0)) == 1);
+
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / (0.0 + 0.0j))) == 1);
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / (0.0 + 0.0j))) == 1);
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / (0.0 + 0.0j))) == 1);
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 0.0)) == 1);
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / 0.0)) == 1);
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / 0.0)) == 1);
diff --git a/test/SemaCXX/const-cast.cpp b/test/SemaCXX/const-cast.cpp
index cb9937c50d50..330e18661b19 100644
--- a/test/SemaCXX/const-cast.cpp
+++ b/test/SemaCXX/const-cast.cpp
@@ -64,3 +64,6 @@ short *bad_const_cast_test(char const *volatile *const volatile *var)
(void)const_cast<int&&>(0); // expected-error {{const_cast from rvalue to reference type 'int &&'}} expected-warning {{C++11}}
return **var3;
}
+
+template <typename T>
+char *PR21845() { return const_cast<char *>((void)T::x); } // expected-error {{const_cast from 'void' to 'char *' is not allowed}}
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 09d93fa73af1..14c0ae320d77 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -95,11 +95,13 @@ namespace TemplateArgumentConversion {
}
namespace CaseStatements {
+ int x;
void f(int n) {
switch (n) {
case MemberZero().zero: // expected-error {{did you mean to call it with no arguments?}} expected-note {{previous}}
case id(0): // expected-error {{duplicate case value '0'}}
return;
+ case __builtin_constant_p(true) ? (__SIZE_TYPE__)&x : 0:; // expected-error {{constant}}
}
}
}
@@ -602,7 +604,7 @@ struct A { constexpr A(int a, int b) : k(a + b) {} int k; };
constexpr int fn(const A &a) { return a.k; }
static_assert(fn(A(4,5)) == 9, "");
-struct B { int n; int m; } constexpr b = { 0, b.n }; // expected-warning {{uninitialized}}
+struct B { int n; int m; } constexpr b = { 0, b.n };
struct C {
constexpr C(C *this_) : m(42), n(this_->m) {} // ok
int m, n;
@@ -1177,7 +1179,7 @@ namespace ExternConstexpr {
void f() {
extern constexpr int i; // expected-error {{constexpr variable declaration must be a definition}}
constexpr int j = 0;
- constexpr int k; // expected-error {{default initialization of an object of const type}}
+ constexpr int k; // expected-error {{default initialization of an object of const type}} expected-note{{add an explicit initializer to initialize 'k'}}
}
}
@@ -1326,6 +1328,49 @@ namespace MutableMembers {
struct C { B b; };
constexpr C c[3] = {};
constexpr int k = c[1].b.a.n; // expected-error {{constant expression}} expected-note {{mutable}}
+
+ struct D { int x; mutable int y; }; // expected-note {{here}}
+ constexpr D d1 = { 1, 2 };
+ int l = ++d1.y;
+ constexpr D d2 = d1; // expected-error {{constant}} expected-note {{mutable}} expected-note {{in call}}
+
+ struct E {
+ union {
+ int a;
+ mutable int b; // expected-note {{here}}
+ };
+ };
+ constexpr E e1 = {{1}};
+ constexpr E e2 = e1; // expected-error {{constant}} expected-note {{mutable}} expected-note {{in call}}
+
+ struct F {
+ union U { };
+ mutable U u;
+ struct X { };
+ mutable X x;
+ struct Y : X { X x; U u; };
+ mutable Y y;
+ int n;
+ };
+ // This is OK; we don't actually read any mutable state here.
+ constexpr F f1 = {};
+ constexpr F f2 = f1;
+
+ struct G {
+ struct X {};
+ union U { X a; };
+ mutable U u; // expected-note {{here}}
+ };
+ constexpr G g1 = {};
+ constexpr G g2 = g1; // expected-error {{constant}} expected-note {{mutable}} expected-note {{in call}}
+ constexpr G::U gu1 = {};
+ constexpr G::U gu2 = gu1;
+
+ union H {
+ mutable G::X gx; // expected-note {{here}}
+ };
+ constexpr H h1 = {};
+ constexpr H h2 = h1; // expected-error {{constant}} expected-note {{mutable}} expected-note {{in call}}
}
namespace Fold {
@@ -1443,7 +1488,7 @@ namespace InvalidClasses {
namespace NamespaceAlias {
constexpr int f() {
- namespace NS = NamespaceAlias; // expected-warning {{use of this statement in a constexpr function is a C++1y extension}}
+ namespace NS = NamespaceAlias; // expected-warning {{use of this statement in a constexpr function is a C++14 extension}}
return &NS::f != nullptr;
}
}
@@ -1568,7 +1613,8 @@ namespace TypeId {
A &g();
constexpr auto &x = typeid(f());
constexpr auto &y = typeid(g()); // expected-error{{constant expression}} \
- // expected-note{{typeid applied to expression of polymorphic type 'TypeId::A' is not allowed in a constant expression}}
+ // expected-note{{typeid applied to expression of polymorphic type 'TypeId::A' is not allowed in a constant expression}} \
+ // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
}
namespace PR14203 {
@@ -1667,6 +1713,9 @@ namespace InitializerList {
return sum(ints.begin(), ints.end());
}
static_assert(sum({1, 2, 3, 4, 5}) == 15, "");
+
+ static_assert(*std::initializer_list<int>{1, 2, 3}.begin() == 1, "");
+ static_assert(std::initializer_list<int>{1, 2, 3}.begin()[2] == 3, "");
}
namespace StmtExpr {
@@ -1700,7 +1749,7 @@ namespace VirtualFromBase {
template <typename T> struct X : T {
constexpr X() {}
double d = 0.0;
- constexpr int f() { return sizeof(T); } // expected-warning {{will not be implicitly 'const' in C++1y}}
+ constexpr int f() { return sizeof(T); } // expected-warning {{will not be implicitly 'const' in C++14}}
};
// Virtual f(), not OK.
@@ -1715,17 +1764,17 @@ namespace VirtualFromBase {
}
namespace ConstexprConstructorRecovery {
- class X {
- public:
- enum E : short {
- headers = 0x1,
- middlefile = 0x2,
- choices = 0x4
- };
- constexpr X() noexcept {};
- protected:
+ class X {
+ public:
+ enum E : short {
+ headers = 0x1,
+ middlefile = 0x2,
+ choices = 0x4
+ };
+ constexpr X() noexcept {};
+ protected:
E val{0}; // expected-error {{cannot initialize a member subobject of type 'ConstexprConstructorRecovery::X::E' with an rvalue of type 'int'}}
- };
+ };
constexpr X x{};
}
@@ -1799,8 +1848,9 @@ namespace ZeroSizeTypes {
namespace BadDefaultInit {
template<int N> struct X { static const int n = N; };
- struct A { // expected-note {{subexpression}}
- int k = X<A().k>::n; // expected-error {{defaulted default constructor of 'A' cannot be used}} expected-error {{not a constant expression}} expected-note {{in call to 'A()'}}
+ struct A {
+ int k = // expected-error {{cannot use defaulted default constructor of 'A' within the class outside of member functions because 'k' has an initializer}}
+ X<A().k>::n; // expected-error {{not a constant expression}} expected-note {{implicit default constructor for 'BadDefaultInit::A' first required here}}
};
// FIXME: The "constexpr constructor must initialize all members" diagnostic
@@ -1892,3 +1942,45 @@ namespace PR19010 {
};
void test() { constexpr Test t; }
}
+
+void PR21327(int a, int b) {
+ static_assert(&a + 1 != &b, ""); // expected-error {{constant expression}}
+}
+
+namespace EmptyClass {
+ struct E1 {} e1;
+ union E2 {} e2; // expected-note {{here}}
+ struct E3 : E1 {} e3;
+
+ // The defaulted copy constructor for an empty class does not read any
+ // members. The defaulted copy constructor for an empty union reads the
+ // object representation.
+ constexpr E1 e1b(e1);
+ constexpr E2 e2b(e2); // expected-error {{constant expression}} expected-note{{read of non-const}} expected-note {{in call}}
+ constexpr E3 e3b(e3);
+}
+
+namespace PR21786 {
+ extern void (*start[])();
+ extern void (*end[])();
+ static_assert(&start != &end, ""); // expected-error {{constant expression}}
+ static_assert(&start != nullptr, "");
+
+ struct Foo;
+ struct Bar {
+ static const Foo x;
+ static const Foo y;
+ };
+ static_assert(&Bar::x != nullptr, "");
+ static_assert(&Bar::x != &Bar::y, "");
+}
+
+namespace PR21859 {
+ constexpr int Fun() { return; } // expected-error {{non-void constexpr function 'Fun' should return a value}}
+ constexpr int Var = Fun(); // expected-error {{constexpr variable 'Var' must be initialized by a constant expression}}
+}
+
+struct InvalidRedef {
+ int f; // expected-note{{previous definition is here}}
+ constexpr int f(void); // expected-error{{redefinition of 'f'}} expected-warning{{will not be implicitly 'const'}}
+};
diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp
index 521526ddba44..e8925f3f84aa 100644
--- a/test/SemaCXX/constant-expression-cxx1y.cpp
+++ b/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -719,8 +719,7 @@ namespace deduced_return_type {
namespace modify_temporary_during_construction {
struct A { int &&temporary; int x; int y; };
constexpr int f(int &r) { r *= 9; return r - 12; }
- // FIXME: The 'uninitialized' warning here is bogus.
- constexpr A a = { 6, f(a.temporary), a.temporary }; // expected-warning {{uninitialized}} expected-note {{temporary created here}}
+ constexpr A a = { 6, f(a.temporary), a.temporary }; // expected-note {{temporary created here}}
static_assert(a.x == 42, "");
static_assert(a.y == 54, "");
constexpr int k = a.temporary++; // expected-error {{constant expression}} expected-note {{outside the expression that created the temporary}}
@@ -911,3 +910,31 @@ namespace PR17331 {
constexpr int ARR[] = { 1, 2, 3, 4, 5 };
static_assert(sum(ARR) == 15, "");
}
+
+namespace EmptyClass {
+ struct E1 {} e1;
+ union E2 {} e2; // expected-note 4{{here}}
+ struct E3 : E1 {} e3;
+
+ template<typename E>
+ constexpr int f(E &a, int kind) {
+ switch (kind) {
+ case 0: { E e(a); return 0; } // expected-note {{read}} expected-note {{in call}}
+ case 1: { E e(static_cast<E&&>(a)); return 0; } // expected-note {{read}} expected-note {{in call}}
+ case 2: { E e; e = a; return 0; } // expected-note {{read}} expected-note {{in call}}
+ case 3: { E e; e = static_cast<E&&>(a); return 0; } // expected-note {{read}} expected-note {{in call}}
+ }
+ }
+ constexpr int test1 = f(e1, 0);
+ constexpr int test2 = f(e2, 0); // expected-error {{constant expression}} expected-note {{in call}}
+ constexpr int test3 = f(e3, 0);
+ constexpr int test4 = f(e1, 1);
+ constexpr int test5 = f(e2, 1); // expected-error {{constant expression}} expected-note {{in call}}
+ constexpr int test6 = f(e3, 1);
+ constexpr int test7 = f(e1, 2);
+ constexpr int test8 = f(e2, 2); // expected-error {{constant expression}} expected-note {{in call}}
+ constexpr int test9 = f(e3, 2);
+ constexpr int testa = f(e1, 3);
+ constexpr int testb = f(e2, 3); // expected-error {{constant expression}} expected-note {{in call}}
+ constexpr int testc = f(e3, 3);
+}
diff --git a/test/SemaCXX/constexpr-value-init.cpp b/test/SemaCXX/constexpr-value-init.cpp
index 9ad11290190f..3657c18ddbac 100644
--- a/test/SemaCXX/constexpr-value-init.cpp
+++ b/test/SemaCXX/constexpr-value-init.cpp
@@ -14,7 +14,7 @@ void f() {
constexpr A a; // expected-error {{constant expression}} expected-note {{in call to 'A()'}}
}
-constexpr B b1; // expected-error {{requires a user-provided default constructor}}
+constexpr B b1; // expected-error {{without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'b1'}}
constexpr B b2 = B(); // ok
static_assert(b2.a.a == 1, "");
static_assert(b2.a.b == 2, "");
@@ -23,9 +23,9 @@ struct C {
int c;
};
struct D : C { int d; };
-constexpr C c1; // expected-error {{requires a user-provided default constructor}}
+constexpr C c1; // expected-error {{without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 'c1'}}
constexpr C c2 = C(); // ok
-constexpr D d1; // expected-error {{requires a user-provided default constructor}}
+constexpr D d1; // expected-error {{without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 'd1'}}
constexpr D d2 = D(); // ok with DR1452
static_assert(D().c == 0, "");
static_assert(D().d == 0, "");
diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp
index 40ac33b8eb0d..077e4d9f3cce 100644
--- a/test/SemaCXX/conversion-function.cpp
+++ b/test/SemaCXX/conversion-function.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wbind-to-temporary-copy -verify %s
class X {
public:
operator bool();
@@ -172,12 +172,10 @@ namespace source_locations {
namespace crazy_declarators {
struct A {
- (&operator bool())(); // expected-error {{must use a typedef to declare a conversion to 'bool (&)()'}}
-
- // FIXME: This diagnostic is misleading (the correct spelling
- // would be 'operator int*'), but it's a corner case of a
- // rarely-used syntax extension.
- *operator int(); // expected-error {{must use a typedef to declare a conversion to 'int *'}}
+ (&operator bool())(); // expected-error {{use a typedef to declare a conversion to 'bool (&)()'}}
+ *operator int(); // expected-error {{put the complete type after 'operator'}}
+ // No suggestion of using a typedef here; that's not possible.
+ template<typename T> (&operator T())(); // expected-error-re {{cannot specify any part of a return type in the declaration of a conversion function{{$}}}}
};
}
diff --git a/test/SemaCXX/conversion.cpp b/test/SemaCXX/conversion.cpp
index 852bbba7efa1..b8f0e076a2bc 100644
--- a/test/SemaCXX/conversion.cpp
+++ b/test/SemaCXX/conversion.cpp
@@ -90,6 +90,18 @@ void test3() {
;
do ;
while(NULL_COND(true));
+
+#define NULL_WRAPPER NULL_COND(false)
+ if (NULL_WRAPPER)
+ ;
+ while (NULL_WRAPPER)
+ ;
+ for (; NULL_WRAPPER;)
+ ;
+ do
+ ;
+ while (NULL_WRAPPER);
+
int *ip = NULL;
int (*fp)() = NULL;
struct foo {
@@ -137,3 +149,11 @@ namespace test6 {
return NULL;
}
}
+
+namespace test7 {
+ bool fun() {
+ bool x = nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
+ if (nullptr) {} // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
+ return nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
+ }
+}
diff --git a/test/SemaCXX/crashes.cpp b/test/SemaCXX/crashes.cpp
index 1570d12eeb2f..6ae476f7080c 100644
--- a/test/SemaCXX/crashes.cpp
+++ b/test/SemaCXX/crashes.cpp
@@ -231,3 +231,9 @@ namespace pr16989 {
};
void C2::f() {}
}
+
+namespace pr20660 {
+ appendList(int[]...); // expected-error {{C++ requires a type specifier for all declarations}}
+ appendList(int[]...) { } // expected-error {{C++ requires a type specifier for all declarations}}
+}
+
diff --git a/test/SemaCXX/cxx-deprecated.cpp b/test/SemaCXX/cxx-deprecated.cpp
new file mode 100644
index 000000000000..47accd4ae1d5
--- /dev/null
+++ b/test/SemaCXX/cxx-deprecated.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
+
+namespace [[deprecated]] {} // expected-warning {{'deprecated' attribute on anonymous namespace ignored}}
+
+namespace [[deprecated]] N { // expected-note 4{{'N' has been explicitly marked deprecated here}}
+ int X;
+ int Y = X; // Ok
+ int f();
+}
+
+int N::f() { // Ok
+ return Y; // Ok
+}
+
+void f() {
+ int Y = N::f(); // expected-warning {{'N' is deprecated}}
+ using N::X; // expected-warning {{'N' is deprecated}}
+ int Z = X; //Ok
+}
+
+void g() {
+ using namespace N; // expected-warning {{'N' is deprecated}}
+ int Z = Y; // Ok
+}
+
+namespace M = N; // expected-warning {{'N' is deprecated}}
diff --git a/test/SemaCXX/cxx0x-compat.cpp b/test/SemaCXX/cxx0x-compat.cpp
index a58a7f875cdb..bcf0cf11dc18 100644
--- a/test/SemaCXX/cxx0x-compat.cpp
+++ b/test/SemaCXX/cxx0x-compat.cpp
@@ -41,9 +41,15 @@ void h(size_t foo, size_t bar) {
#define _x + 1
char c = 'x'_x; // expected-warning {{will be treated as a user-defined literal suffix}}
+template<int ...N> int f() { // expected-warning {{C++11 extension}}
+ return (N + ...); // expected-warning {{C++1z extension}}
+}
+
#else
-auto init_capture = [a(0)] {}; // expected-warning {{initialized lambda captures are incompatible with C++ standards before C++1y}}
+auto init_capture = [a(0)] {}; // expected-warning {{initialized lambda captures are incompatible with C++ standards before C++14}}
static_assert(true); // expected-warning {{incompatible with C++ standards before C++1z}}
+template<int ...N> int f() { return (N + ...); } // expected-warning {{incompatible with C++ standards before C++1z}}
+
#endif
diff --git a/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
index 07a784226640..375cf4a1ac5c 100644
--- a/test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -25,7 +25,7 @@ void fn1 () {
non_const_copy ncc2 = ncc;
ncc = ncc2;
const non_const_copy cncc{};
- const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' requires a user-provided default constructor}}
+ const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'cncc1'}}
non_const_copy ncc3 = cncc; // expected-error {{no matching}}
ncc = cncc; // expected-error {{no viable overloaded}}
};
diff --git a/test/SemaCXX/cxx0x-initializer-references.cpp b/test/SemaCXX/cxx0x-initializer-references.cpp
index 9096c8a1c2d5..d1a9ed30076f 100644
--- a/test/SemaCXX/cxx0x-initializer-references.cpp
+++ b/test/SemaCXX/cxx0x-initializer-references.cpp
@@ -118,3 +118,9 @@ namespace inner_init {
F f2 { { 0 } }; // expected-error {{chosen constructor is explicit}}
F f3 { { { 0 } } }; // expected-error {{chosen constructor is explicit}}
}
+
+namespace PR20844 {
+ struct A {};
+ struct B { operator A&(); } b;
+ A &a{b}; // expected-error {{excess elements}} expected-note {{in initialization of temporary of type 'PR20844::A'}}
+}
diff --git a/test/SemaCXX/cxx11-ast-print.cpp b/test/SemaCXX/cxx11-ast-print.cpp
index f7bfc1123a7f..5604374c5610 100644
--- a/test/SemaCXX/cxx11-ast-print.cpp
+++ b/test/SemaCXX/cxx11-ast-print.cpp
@@ -15,7 +15,7 @@ decltype(4.5_baz) operator"" _baz(char);
// CHECK: const char *operator "" _quux(const char *);
const char *operator"" _quux(const char *);
-// CHECK: template <char...> const char *operator "" _fritz();
+// CHECK: template <char ...> const char *operator "" _fritz();
template<char...> const char *operator"" _fritz();
// CHECK: const char *p1 = "bar1"_foo;
diff --git a/test/SemaCXX/cxx11-thread-unsupported.cpp b/test/SemaCXX/cxx11-thread-unsupported.cpp
new file mode 100644
index 000000000000..d3fcf82ef415
--- /dev/null
+++ b/test/SemaCXX/cxx11-thread-unsupported.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-apple-macosx10.6 -verify %s
+
+void f() {
+ thread_local int x; // expected-error {{thread-local storage is not supported for the current target}}
+}
diff --git a/test/SemaCXX/cxx1y-constexpr-not-const.cpp b/test/SemaCXX/cxx1y-constexpr-not-const.cpp
index 3f100b8b691e..071b39c7fb39 100644
--- a/test/SemaCXX/cxx1y-constexpr-not-const.cpp
+++ b/test/SemaCXX/cxx1y-constexpr-not-const.cpp
@@ -14,5 +14,5 @@ struct X {
// expected-error@6 {{non-constexpr declaration of 'f' follows constexpr declaration}}
// expected-note@5 {{previous}}
#else
-// expected-warning@5 {{'constexpr' non-static member function will not be implicitly 'const' in C++1y; add 'const' to avoid a change in behavior}}
+// expected-warning@5 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const' to avoid a change in behavior}}
#endif
diff --git a/test/SemaCXX/cxx1y-deduced-return-type.cpp b/test/SemaCXX/cxx1y-deduced-return-type.cpp
index 60864165954a..50e0cf79c57b 100644
--- a/test/SemaCXX/cxx1y-deduced-return-type.cpp
+++ b/test/SemaCXX/cxx1y-deduced-return-type.cpp
@@ -483,3 +483,16 @@ namespace OverloadedOperators {
int g = a - a;
}
}
+
+namespace TrailingReturnTypeForConversionOperator {
+ struct X {
+ operator auto() -> int { return 0; } // expected-error {{cannot specify any part of a return type in the declaration of a conversion function; put the complete type after 'operator'}}
+ } x;
+ int k = x.operator auto();
+
+ struct Y {
+ operator auto() -> int & { // expected-error {{cannot specify}}
+ return 0; // expected-error {{cannot bind to}}
+ }
+ };
+};
diff --git a/test/SemaCXX/cxx1y-generic-lambdas.cpp b/test/SemaCXX/cxx1y-generic-lambdas.cpp
index dc8574825dd9..90ecf6904e54 100644
--- a/test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ b/test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -859,11 +859,13 @@ namespace ns1 {
struct X1 {
struct X2 {
enum { E = [](auto i) { return i; }(3) }; //expected-error{{inside of a constant expression}}\
- //expected-error{{not an integral constant}}
+ //expected-error{{not an integral constant}}\
+ //expected-note{{non-literal type}}
int L = ([] (int i) { return i; })(2);
void foo(int i = ([] (int i) { return i; })(2)) { }
int B : ([](int i) { return i; })(3); //expected-error{{inside of a constant expression}}\
- //expected-error{{not an integral constant}}
+ //expected-error{{not an integral constant}}\
+ //expected-note{{non-literal type}}
int arr[([](int i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
//expected-error{{must have a constant size}}
int (*fp)(int) = [](int i) { return i; };
@@ -871,9 +873,10 @@ struct X1 {
int L2 = ([](auto i) { return i; })(2);
void fooG(int i = ([] (auto i) { return i; })(2)) { }
int BG : ([](auto i) { return i; })(3); //expected-error{{inside of a constant expression}} \
- //expected-error{{not an integral constant}}
+ //expected-error{{not an integral constant}}\
+ //expected-note{{non-literal type}}
int arrG[([](auto i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
- //expected-error{{must have a constant size}}
+ //expected-error{{must have a constant size}}
int (*fpG)(int) = [](auto i) { return i; };
void fooptrG(int (*fp)(char) = [](auto c) { return 0; }) { }
};
@@ -887,14 +890,16 @@ struct X1 {
int L = ([] (T i) { return i; })(2);
void foo(int i = ([] (int i) { return i; })(2)) { }
int B : ([](T i) { return i; })(3); //expected-error{{inside of a constant expression}}\
- //expected-error{{not an integral constant}}
+ //expected-error{{not an integral constant}}\
+ //expected-note{{non-literal type}}
int arr[([](T i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
- //expected-error{{must have a constant size}}
+ //expected-error{{must have a constant size}}
int (*fp)(T) = [](T i) { return i; };
void fooptr(T (*fp)(char) = [](char c) { return 0; }) { }
int L2 = ([](auto i) { return i; })(2);
void fooG(T i = ([] (auto i) { return i; })(2)) { }
- int BG : ([](auto i) { return i; })(3); //expected-error{{not an integral constant}}
+ int BG : ([](auto i) { return i; })(3); //expected-error{{not an integral constant}}\
+ //expected-note{{non-literal type}}
int arrG[([](auto i) { return i; })(3)]; //expected-error{{must have a constant size}}
int (*fpG)(T) = [](auto i) { return i; };
void fooptrG(T (*fp)(char) = [](auto c) { return 0; }) { }
@@ -913,3 +918,16 @@ int run2 = x2.fooG3();
} //end ns inclass_lambdas_within_nested_classes
+
+namespace pr21684_disambiguate_auto_followed_by_ellipsis_no_id {
+int a = [](auto ...) { return 0; }();
+}
+
+namespace PR22117 {
+ int x = [](auto) {
+ return [](auto... run_args) {
+ using T = int(decltype(run_args)...);
+ return 0;
+ };
+ }(0)(0);
+}
diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
index 1e5e834b6d2a..93a2095c9b8c 100644
--- a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
+++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
@@ -58,13 +58,13 @@ namespace out_of_line {
template<typename T, typename T0> static CONST T b = T(100);
template<typename T> static CONST T b<T,int>;
};
- template<typename T, typename T0> CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}}
+ template<typename T, typename T0> CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'a<int, char>'}}
template<typename T> CONST T B4::a<T,int>;
template CONST int B4::a<int,char>; // expected-note {{in instantiation of}}
template CONST int B4::a<int,int>;
template<typename T, typename T0> CONST T B4::b;
- template<typename T> CONST T B4::b<T,int>; // expected-error {{default initialization of an object of const type 'const int'}}
+ template<typename T> CONST T B4::b<T,int>; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'b<int, int>'}}
template CONST int B4::b<int,char>;
template CONST int B4::b<int,int>; // expected-note {{in instantiation of}}
}
@@ -321,3 +321,9 @@ namespace in_nested_classes {
// TODO:
}
+namespace bitfield {
+struct S {
+ template <int I>
+ static int f : I; // expected-error {{static member 'f' cannot be a bit-field}}
+};
+}
diff --git a/test/SemaCXX/cxx98-compat-flags.cpp b/test/SemaCXX/cxx98-compat-flags.cpp
index 6dc24be6bbfa..f90ad345e975 100644
--- a/test/SemaCXX/cxx98-compat-flags.cpp
+++ b/test/SemaCXX/cxx98-compat-flags.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -Wno-bind-to-temporary-copy -Wno-unnamed-type-template-args -Wno-local-type-template-args -Werror %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -Wno-bind-to-temporary-copy -Wno-unnamed-type-template-args -Wno-local-type-template-args -Werror %s
template<typename T> int TemplateFn(T) { return 0; }
void LocalTemplateArg() {
diff --git a/test/SemaCXX/cxx98-compat-pedantic.cpp b/test/SemaCXX/cxx98-compat-pedantic.cpp
index b74dcb4238ae..38bc341e83ce 100644
--- a/test/SemaCXX/cxx98-compat-pedantic.cpp
+++ b/test/SemaCXX/cxx98-compat-pedantic.cpp
@@ -2,7 +2,7 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++1y -DCXX1Y -Wc++98-compat -Werror %s -DCXX1Y2
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -Werror %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror %s -DCXX98
// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++98-compat-pedantic -verify %s -Wno-c++98-c++11-compat-pedantic -DCXX1Y2
@@ -49,5 +49,32 @@ unsigned long long ull1 = // expected-warning {{'long long' is incompatible with
int k = 0b1001;
#ifdef CXX1Y
-// expected-warning@-2 {{binary integer literals are incompatible with C++ standards before C++1y}}
+// expected-warning@-2 {{binary integer literals are incompatible with C++ standards before C++14}}
#endif
+
+namespace CopyCtorIssues {
+ struct Private {
+ Private();
+ private:
+ Private(const Private&); // expected-note {{declared private here}}
+ };
+ struct NoViable {
+ NoViable();
+ NoViable(NoViable&); // expected-note {{not viable}}
+ };
+ struct Ambiguous {
+ Ambiguous();
+ Ambiguous(const Ambiguous &, int = 0); // expected-note {{candidate}}
+ Ambiguous(const Ambiguous &, double = 0); // expected-note {{candidate}}
+ };
+ struct Deleted {
+ Private p; // expected-note {{implicitly deleted}}
+ };
+
+ const Private &a = Private(); // expected-warning {{copying variable of type 'CopyCtorIssues::Private' when binding a reference to a temporary would invoke an inaccessible constructor in C++98}}
+ const NoViable &b = NoViable(); // expected-warning {{copying variable of type 'CopyCtorIssues::NoViable' when binding a reference to a temporary would find no viable constructor in C++98}}
+#if !CXX98
+ const Ambiguous &c = Ambiguous(); // expected-warning {{copying variable of type 'CopyCtorIssues::Ambiguous' when binding a reference to a temporary would find ambiguous constructors in C++98}}
+#endif
+ const Deleted &d = Deleted(); // expected-warning {{copying variable of type 'CopyCtorIssues::Deleted' when binding a reference to a temporary would invoke a deleted constructor in C++98}}
+}
diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp
index 96af95425aec..029e90989628 100644
--- a/test/SemaCXX/cxx98-compat.cpp
+++ b/test/SemaCXX/cxx98-compat.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++98-compat -verify %s -DCXX1YCOMPAT
+// RUN: %clang_cc1 -fsyntax-only -std=c++14 -Wc++98-compat -verify %s -DCXX14COMPAT
namespace std {
struct type_info;
@@ -225,31 +225,6 @@ template<typename T> typename T::ImPrivate SFINAEAccessControl(T t) { // expecte
int SFINAEAccessControl(...) { return 0; }
int CheckSFINAEAccessControl = SFINAEAccessControl(PrivateMember()); // expected-note {{while substituting deduced template arguments into function template 'SFINAEAccessControl' [with T = PrivateMember]}}
-namespace CopyCtorIssues {
- struct Private {
- Private();
- private:
- Private(const Private&); // expected-note {{declared private here}}
- };
- struct NoViable {
- NoViable();
- NoViable(NoViable&); // expected-note {{not viable}}
- };
- struct Ambiguous {
- Ambiguous();
- Ambiguous(const Ambiguous &, int = 0); // expected-note {{candidate}}
- Ambiguous(const Ambiguous &, double = 0); // expected-note {{candidate}}
- };
- struct Deleted {
- Private p; // expected-note {{implicitly deleted}}
- };
-
- const Private &a = Private(); // expected-warning {{copying variable of type 'CopyCtorIssues::Private' when binding a reference to a temporary would invoke an inaccessible constructor in C++98}}
- const NoViable &b = NoViable(); // expected-warning {{copying variable of type 'CopyCtorIssues::NoViable' when binding a reference to a temporary would find no viable constructor in C++98}}
- const Ambiguous &c = Ambiguous(); // expected-warning {{copying variable of type 'CopyCtorIssues::Ambiguous' when binding a reference to a temporary would find ambiguous constructors in C++98}}
- const Deleted &d = Deleted(); // expected-warning {{copying variable of type 'CopyCtorIssues::Deleted' when binding a reference to a temporary would invoke a deleted constructor in C++98}}
-}
-
namespace UnionOrAnonStructMembers {
struct NonTrivCtor {
NonTrivCtor(); // expected-note 2{{user-provided default constructor}}
@@ -286,18 +261,18 @@ template<typename T> void EnumNNSFn() {
template void EnumNNSFn<Enum>(); // expected-note {{in instantiation}}
void JumpDiagnostics(int n) {
- goto DirectJump; // expected-warning {{goto would jump into protected scope in C++98}}
+ goto DirectJump; // expected-warning {{jump from this goto statement to its label is incompatible with C++98}}
TrivialButNonPOD tnp1; // expected-note {{jump bypasses initialization of non-POD variable}}
DirectJump:
void *Table[] = {&&DirectJump, &&Later};
- goto *Table[n]; // expected-warning {{indirect goto might cross protected scopes in C++98}}
+ goto *Table[n]; // expected-warning {{jump from this indirect goto statement to one of its possible targets is incompatible with C++98}}
TrivialButNonPOD tnp2; // expected-note {{jump bypasses initialization of non-POD variable}}
-Later: // expected-note {{possible target of indirect goto}}
+Later: // expected-note {{possible target of indirect goto statement}}
switch (n) {
TrivialButNonPOD tnp3; // expected-note {{jump bypasses initialization of non-POD variable}}
- default: // expected-warning {{switch case would be in a protected scope in C++98}}
+ default: // expected-warning {{jump from switch statement to this case label is incompatible with C++98}}
return;
}
}
@@ -373,10 +348,10 @@ namespace rdar11736429 {
}
template<typename T> T var = T(10);
-#ifdef CXX1YCOMPAT
-// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#ifdef CXX14COMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++14}}
#else
-// expected-warning@-4 {{variable templates are a C++1y extension}}
+// expected-warning@-4 {{variable templates are a C++14 extension}}
#endif
// No diagnostic for specializations of variable templates; we will have
@@ -388,27 +363,27 @@ float fvar = var<float>;
class A {
template<typename T> static T var = T(10);
-#ifdef CXX1YCOMPAT
-// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#ifdef CXX14COMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++14}}
#else
-// expected-warning@-4 {{variable templates are a C++1y extension}}
+// expected-warning@-4 {{variable templates are a C++14 extension}}
#endif
- template<typename T> static T* var<T*> = new T();
+ template<typename T> static T* var<T*> = new T();
};
struct B { template<typename T> static T v; };
-#ifdef CXX1YCOMPAT
-// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#ifdef CXX14COMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++14}}
#else
-// expected-warning@-4 {{variable templates are a C++1y extension}}
+// expected-warning@-4 {{variable templates are a C++14 extension}}
#endif
template<typename T> T B::v = T();
-#ifdef CXX1YCOMPAT
-// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#ifdef CXX14COMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++14}}
#else
-// expected-warning@-4 {{variable templates are a C++1y extension}}
+// expected-warning@-4 {{variable templates are a C++14 extension}}
#endif
template<typename T> T* B::v<T*> = new T();
@@ -416,6 +391,6 @@ template<> int B::v<int> = 10;
template int B::v<int>;
float fsvar = B::v<float>;
-#ifdef CXX1YCOMPAT
-int digit_seps = 123'456; // expected-warning {{digit separators are incompatible with C++ standards before C++1y}}
+#ifdef CXX14COMPAT
+int digit_seps = 123'456; // expected-warning {{digit separators are incompatible with C++ standards before C++14}}
#endif
diff --git a/test/SemaCXX/decl-init-ref.cpp b/test/SemaCXX/decl-init-ref.cpp
index 2d0c9cb4ffbe..42b9286852c7 100644
--- a/test/SemaCXX/decl-init-ref.cpp
+++ b/test/SemaCXX/decl-init-ref.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-uninitialized
struct A {};
diff --git a/test/SemaCXX/decl-microsoft-call-conv.cpp b/test/SemaCXX/decl-microsoft-call-conv.cpp
index eb6c8507eddc..a4b68cdbc7d4 100644
--- a/test/SemaCXX/decl-microsoft-call-conv.cpp
+++ b/test/SemaCXX/decl-microsoft-call-conv.cpp
@@ -10,6 +10,7 @@ void free_func_default(); // expected-note 2 {{previous declaration i
void __cdecl free_func_cdecl(); // expected-note 2 {{previous declaration is here}}
void __stdcall free_func_stdcall(); // expected-note 2 {{previous declaration is here}}
void __fastcall free_func_fastcall(); // expected-note 2 {{previous declaration is here}}
+void __vectorcall free_func_vectorcall(); // expected-note 2 {{previous declaration is here}}
void __cdecl free_func_default();
void __stdcall free_func_default(); // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
@@ -27,6 +28,10 @@ void __cdecl free_func_fastcall(); // expected-error {{function declared 'cde
void __stdcall free_func_fastcall(); // expected-error {{function declared 'stdcall' here was previously declared 'fastcall'}}
void free_func_fastcall();
+void __cdecl free_func_vectorcall(); // expected-error {{function declared 'cdecl' here was previously declared 'vectorcall'}}
+void __stdcall free_func_vectorcall(); // expected-error {{function declared 'stdcall' here was previously declared 'vectorcall'}}
+void free_func_vectorcall();
+
// Overloaded functions may have different calling conventions
void __fastcall free_func_default(int);
void __cdecl free_func_default(int *);
@@ -45,6 +50,8 @@ struct S {
void __cdecl member_cdecl2(); // expected-note {{previous declaration is here}}
void __thiscall member_thiscall1();
void __thiscall member_thiscall2(); // expected-note {{previous declaration is here}}
+ void __vectorcall member_vectorcall1();
+ void __vectorcall member_vectorcall2(); // expected-note {{previous declaration is here}}
// Typedefs carrying the __cdecl convention are adjusted to __thiscall.
void_fun_t member_typedef_default; // expected-note {{previous declaration is here}}
@@ -83,6 +90,9 @@ void __thiscall S::member_cdecl2() {} // expected-error {{function declared 'thi
void S::member_thiscall1() {}
void __cdecl S::member_thiscall2() {} // expected-error {{function declared 'cdecl' here was previously declared 'thiscall'}}
+void S::member_vectorcall1() {}
+void __cdecl S::member_vectorcall2() {} // expected-error {{function declared 'cdecl' here was previously declared 'vectorcall'}}
+
void S::static_member_default1() {}
void __cdecl S::static_member_default2() {}
void __stdcall S::static_member_default3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
@@ -143,9 +153,10 @@ void __attribute__((noreturn)) __stdcall __attribute__((regparm(1))) multi_attri
void multi_attribute(int x) { __builtin_unreachable(); }
+// expected-error@+3 {{vectorcall and cdecl attributes are not compatible}}
// expected-error@+2 {{stdcall and cdecl attributes are not compatible}}
// expected-error@+1 {{fastcall and cdecl attributes are not compatible}}
-void __cdecl __cdecl __stdcall __cdecl __fastcall multi_cc(int x);
+void __cdecl __cdecl __stdcall __cdecl __fastcall __vectorcall multi_cc(int x);
template <typename T> void __stdcall StdcallTemplate(T) {}
template <> void StdcallTemplate<int>(int) {}
diff --git a/test/SemaCXX/default1.cpp b/test/SemaCXX/default1.cpp
index 23466fac62aa..6001001b11eb 100644
--- a/test/SemaCXX/default1.cpp
+++ b/test/SemaCXX/default1.cpp
@@ -65,3 +65,9 @@ int i2() {
int pr20055_f(int x = 0, int y = UNDEFINED); // expected-error{{use of undeclared identifier}}
int pr20055_v = pr20055_f(0);
+
+void PR20769() { void PR20769(int = 1); }
+void PR20769(int = 2);
+
+void PR20769_b(int = 1);
+void PR20769_b() { void PR20769_b(int = 2); }
diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp
index 16260449d4be..c4d40b4280e9 100644
--- a/test/SemaCXX/default2.cpp
+++ b/test/SemaCXX/default2.cpp
@@ -122,3 +122,9 @@ class XX {
void A(int length = -1 ) { }
void B() { A(); }
};
+
+template <int I = (1 * I)> struct S {}; // expected-error-re {{use of undeclared identifier 'I'{{$}}}}
+S<1> s;
+
+template <int I1 = I2, int I2 = 1> struct T {}; // expected-error-re {{use of undeclared identifier 'I2'{{$}}}}
+T<0, 1> t;
diff --git a/test/SemaCXX/dependent-noexcept-unevaluated.cpp b/test/SemaCXX/dependent-noexcept-unevaluated.cpp
index 0a3a8bb250bc..fad8d0918d53 100644
--- a/test/SemaCXX/dependent-noexcept-unevaluated.cpp
+++ b/test/SemaCXX/dependent-noexcept-unevaluated.cpp
@@ -23,7 +23,7 @@ struct array
{
T data[N];
- void swap(array& a) noexcept(noexcept(swap(declval<T&>(), declval<T&>())));
+ void swap(array& a) noexcept(noexcept(::swap(declval<T&>(), declval<T&>())));
};
struct DefaultOnly
@@ -38,3 +38,4 @@ int main()
{
array<DefaultOnly, 1> a, b;
}
+
diff --git a/test/SemaCXX/deprecated.cpp b/test/SemaCXX/deprecated.cpp
index 2fe6d59861ac..5fcf2130d36f 100644
--- a/test/SemaCXX/deprecated.cpp
+++ b/test/SemaCXX/deprecated.cpp
@@ -35,7 +35,7 @@ void stuff() {
#endif
}
-struct S { int n; };
+struct S { int n; void operator+(int); };
struct T : private S {
S::n;
#if __cplusplus < 201103L
@@ -43,6 +43,12 @@ struct T : private S {
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
+ S::operator+;
+#if __cplusplus < 201103L
+ // expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
+#else
+ // expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
+#endif
};
#if __cplusplus >= 201103L
diff --git a/test/SemaCXX/devirtualize-vtable-marking.cpp b/test/SemaCXX/devirtualize-vtable-marking.cpp
new file mode 100644
index 000000000000..fc3e8ce7704c
--- /dev/null
+++ b/test/SemaCXX/devirtualize-vtable-marking.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+template <typename T> struct OwnPtr {
+ T *p;
+ ~OwnPtr() {
+ // expected-error@+1 {{invalid application of 'sizeof'}}
+ static_assert(sizeof(T) > 0, "incomplete T");
+ delete p;
+ }
+};
+
+namespace use_vtable_for_vcall {
+struct Incomplete; // expected-note {{forward declaration}}
+struct A {
+ virtual ~A() {}
+ virtual void m() {}
+};
+struct B : A { // expected-note {{in instantiation}}
+ B();
+ virtual void m() { }
+ virtual void m2() { static_cast<A *>(this)->m(); }
+ OwnPtr<Incomplete> m_sqlError;
+};
+
+B *f() {
+ return new B();
+}
+}
+
+namespace dont_mark_qualified_vcall {
+struct Incomplete;
+struct A {
+ virtual ~A() {}
+ virtual void m() {}
+};
+struct B : A {
+ B();
+ // Previously we would mark B's vtable referenced to devirtualize this call to
+ // A::m, even though it's not a virtual call.
+ virtual void m() { A::m(); }
+ OwnPtr<Incomplete> m_sqlError;
+};
+
+B *f() {
+ return new B();
+}
+}
diff --git a/test/SemaCXX/dllexport.cpp b/test/SemaCXX/dllexport.cpp
index 668553b5c500..5d002ac81e5c 100644
--- a/test/SemaCXX/dllexport.cpp
+++ b/test/SemaCXX/dllexport.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i686-win32 -fsyntax-only -verify -std=c++11 -DMS %s
-// RUN: %clang_cc1 -triple x86_64-win32 -fsyntax-only -verify -std=c++1y -DMS %s
-// RUN: %clang_cc1 -triple i686-mingw32 -fsyntax-only -verify -std=c++1y %s
-// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple i686-win32 -fsyntax-only -verify -std=c++11 -Wunsupported-dll-base-class-template -DMS %s
+// RUN: %clang_cc1 -triple x86_64-win32 -fsyntax-only -verify -std=c++1y -Wunsupported-dll-base-class-template -DMS %s
+// RUN: %clang_cc1 -triple i686-mingw32 -fsyntax-only -verify -std=c++1y -Wunsupported-dll-base-class-template %s
+// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -verify -std=c++11 -Wunsupported-dll-base-class-template %s
// Helper structs to make templates more expressive.
struct ImplicitInst_Exported {};
@@ -69,6 +69,9 @@ namespace ns { __declspec(dllexport) int ExternalGlobal; }
__declspec(dllexport) auto InternalAutoTypeGlobal = Internal(); // expected-error{{'InternalAutoTypeGlobal' must have external linkage when declared 'dllexport'}}
__declspec(dllexport) auto ExternalAutoTypeGlobal = External();
+// Thread local variables are invalid.
+__declspec(dllexport) __thread int ThreadLocalGlobal; // expected-error{{'ThreadLocalGlobal' cannot be thread local when declared 'dllexport'}}
+
// Export in local scope.
void functionScope() {
__declspec(dllexport) int LocalVarDecl; // expected-error{{'LocalVarDecl' must have external linkage when declared 'dllexport'}}
@@ -324,6 +327,10 @@ template<> __declspec(dllexport) inline void funcTmpl<ExplicitSpec_InlineDef_Exp
// Classes
//===----------------------------------------------------------------------===//
+namespace {
+ struct __declspec(dllexport) AnonymousClass {}; // expected-error{{(anonymous namespace)::AnonymousClass' must have external linkage when declared 'dllexport'}}
+}
+
class __declspec(dllexport) ClassDecl;
class __declspec(dllexport) ClassDef {};
@@ -337,6 +344,49 @@ template <typename T> struct __declspec(dllexport) PartiallySpecializedClassTemp
template <typename T> struct ExpliciallySpecializedClassTemplate {};
template <> struct __declspec(dllexport) ExpliciallySpecializedClassTemplate<int> { void f() {} };
+// Don't instantiate class members of implicitly instantiated templates, even if they are exported.
+struct IncompleteType;
+template <typename T> struct __declspec(dllexport) ImplicitlyInstantiatedExportedTemplate {
+ int f() { return sizeof(T); } // no-error
+};
+ImplicitlyInstantiatedExportedTemplate<IncompleteType> implicitlyInstantiatedExportedTemplate;
+
+// Don't instantiate class members of templates with explicit instantiation declarations, even if they are exported.
+struct IncompleteType2;
+template <typename T> struct __declspec(dllexport) ExportedTemplateWithExplicitInstantiationDecl {
+ int f() { return sizeof(T); } // no-error
+};
+extern template struct ExportedTemplateWithExplicitInstantiationDecl<IncompleteType2>;
+
+// Instantiate class members for explicitly instantiated exported templates.
+struct IncompleteType3; // expected-note{{forward declaration of 'IncompleteType3'}}
+template <typename T> struct __declspec(dllexport) ExplicitlyInstantiatedExportedTemplate {
+ int f() { return sizeof(T); } // expected-error{{invalid application of 'sizeof' to an incomplete type 'IncompleteType3'}}
+};
+template struct ExplicitlyInstantiatedExportedTemplate<IncompleteType3>; // expected-note{{in instantiation of member function 'ExplicitlyInstantiatedExportedTemplate<IncompleteType3>::f' requested here}}
+
+// In MS mode, instantiate members of class templates that are base classes of exported classes.
+#ifdef MS
+ // expected-note@+3{{forward declaration of 'IncompleteType4'}}
+ // expected-note@+3{{in instantiation of member function 'BaseClassTemplateOfExportedClass<IncompleteType4>::f' requested here}}
+#endif
+struct IncompleteType4;
+template <typename T> struct BaseClassTemplateOfExportedClass {
+#ifdef MS
+ // expected-error@+2{{invalid application of 'sizeof' to an incomplete type 'IncompleteType4'}}
+#endif
+ int f() { return sizeof(T); };
+};
+struct __declspec(dllexport) ExportedBaseClass : public BaseClassTemplateOfExportedClass<IncompleteType4> {};
+
+// Don't instantiate members of explicitly exported class templates that are base classes of exported classes.
+struct IncompleteType5;
+template <typename T> struct __declspec(dllexport) ExportedBaseClassTemplateOfExportedClass {
+ int f() { return sizeof(T); }; // no-error
+};
+struct __declspec(dllexport) ExportedBaseClass2 : public ExportedBaseClassTemplateOfExportedClass<IncompleteType5> {};
+
+
//===----------------------------------------------------------------------===//
// Classes with template base classes
diff --git a/test/SemaCXX/dllimport.cpp b/test/SemaCXX/dllimport.cpp
index 889b7b9a8068..eb6a554522ba 100644
--- a/test/SemaCXX/dllimport.cpp
+++ b/test/SemaCXX/dllimport.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i686-win32 -fsyntax-only -verify -std=c++11 -DMS %s
-// RUN: %clang_cc1 -triple x86_64-win32 -fsyntax-only -verify -std=c++1y -DMS %s
-// RUN: %clang_cc1 -triple i686-mingw32 -fsyntax-only -verify -std=c++1y %s
-// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple i686-win32 -fsyntax-only -verify -std=c++11 -Wunsupported-dll-base-class-template -DMS %s
+// RUN: %clang_cc1 -triple x86_64-win32 -fsyntax-only -verify -std=c++1y -Wunsupported-dll-base-class-template -DMS %s
+// RUN: %clang_cc1 -triple i686-mingw32 -fsyntax-only -verify -std=c++1y -Wunsupported-dll-base-class-template -DGNU %s
+// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -verify -std=c++11 -Wunsupported-dll-base-class-template -DGNU %s
// Helper structs to make templates more expressive.
struct ImplicitInst_Imported {};
@@ -91,6 +91,9 @@ namespace ns { __declspec(dllimport) int ExternalGlobal; }
__declspec(dllimport) auto InternalAutoTypeGlobal = Internal(); // expected-error{{'InternalAutoTypeGlobal' must have external linkage when declared 'dllimport'}}
// expected-error@-1{{definition of dllimport data}}
+// Thread local variables are invalid.
+__declspec(dllimport) __thread int ThreadLocalGlobal; // expected-error{{'ThreadLocalGlobal' cannot be thread local when declared 'dllimport'}}
+
// Import in local scope.
__declspec(dllimport) float LocalRedecl1; // expected-note{{previous definition is here}}
__declspec(dllimport) float LocalRedecl2; // expected-note{{previous definition is here}}
@@ -188,7 +191,6 @@ template<> __declspec(dllimport) int VarTmpl<ExplicitSpec_Def_Imported> = 1; //
#endif // __has_feature(cxx_variable_templates)
-
//===----------------------------------------------------------------------===//
// Functions
//===----------------------------------------------------------------------===//
@@ -207,13 +209,23 @@ __declspec(dllimport) void def() {} // expected-error{{dllimport cannot be appli
extern "C" __declspec(dllimport) void externC();
// Import inline function.
+#ifdef GNU
+// expected-warning@+3{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+3{{'dllimport' attribute ignored on inline function}}
+#endif
__declspec(dllimport) inline void inlineFunc1() {}
inline void __attribute__((dllimport)) inlineFunc2() {}
+#ifdef GNU
+// expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
__declspec(dllimport) inline void inlineDecl();
void inlineDecl() {}
__declspec(dllimport) void inlineDef();
+#ifdef GNU
+// expected-warning@+2{{'inlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#endif
inline void inlineDef() {}
// Redeclarations
@@ -236,8 +248,13 @@ extern "C" {
__declspec(dllimport) void redecl5(); // expected-warning{{redeclaration of 'redecl5' should not add 'dllimport' attribute}}
}
+#ifdef MS
void redecl6(); // expected-note{{previous declaration is here}}
__declspec(dllimport) inline void redecl6() {} // expected-warning{{redeclaration of 'redecl6' should not add 'dllimport' attribute}}
+#else
+ void redecl6();
+__declspec(dllimport) inline void redecl6() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+#endif
// Friend functions
struct FuncFriend {
@@ -245,13 +262,28 @@ struct FuncFriend {
friend __declspec(dllimport) void friend2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
friend __declspec(dllimport) void friend3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
friend void friend4(); // expected-note{{previous declaration is here}}
- friend void friend5(); // expected-note{{previous declaration is here}}
+#ifdef MS
+// expected-note@+2{{previous declaration is here}}
+#endif
+ friend void friend5();
};
__declspec(dllimport) void friend1();
void friend2(); // expected-warning{{'friend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
void friend3() {} // expected-warning{{'friend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
__declspec(dllimport) void friend4(); // expected-warning{{redeclaration of 'friend4' should not add 'dllimport' attribute}}
+#ifdef MS
__declspec(dllimport) inline void friend5() {} // expected-warning{{redeclaration of 'friend5' should not add 'dllimport' attribute}}
+#else
+__declspec(dllimport) inline void friend5() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+#endif
+
+
+void __declspec(dllimport) friend6(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+void __declspec(dllimport) friend7();
+struct FuncFriend2 {
+ friend void friend6(); // expected-warning{{'friend6' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+ friend void ::friend7();
+};
// Implicit declarations can be redeclared with dllimport.
__declspec(dllimport) void* operator new(__SIZE_TYPE__ n);
@@ -267,7 +299,11 @@ namespace ns { __declspec(dllimport) void externalFunc(); }
// here which is irrelevant. But because the delete keyword is parsed later
// there is currently no straight-forward way to avoid this diagnostic.
__declspec(dllimport) void deletedFunc() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}} expected-error{{dllimport cannot be applied to non-inline function definition}}
+#ifdef MS
__declspec(dllimport) inline void deletedInlineFunc() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
+#else
+__declspec(dllimport) inline void deletedInlineFunc() = delete; // expected-warning{{'dllimport' attribute ignored on inline function}}
+#endif
@@ -283,6 +319,12 @@ template<typename T> void __declspec(dllimport) funcTmplDecl2();
template<typename T> __declspec(dllimport) void funcTmplDef() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
// Import inline function template.
+#ifdef GNU
+// expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+6{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+9{{'inlineFuncTmplDef' redeclared inline; 'dllimport' attribute ignored}}
+#endif
template<typename T> __declspec(dllimport) inline void inlineFuncTmpl1() {}
template<typename T> inline void __attribute__((dllimport)) inlineFuncTmpl2() {}
@@ -305,8 +347,10 @@ template<typename T> void funcTmplRedecl3() {} // expected
template<typename T> void funcTmplRedecl4(); // expected-note{{previous declaration is here}}
template<typename T> __declspec(dllimport) void funcTmplRedecl4(); // expected-error{{redeclaration of 'funcTmplRedecl4' cannot add 'dllimport' attribute}}
+#ifdef MS
template<typename T> void funcTmplRedecl5(); // expected-note{{previous declaration is here}}
template<typename T> __declspec(dllimport) inline void funcTmplRedecl5() {} // expected-error{{redeclaration of 'funcTmplRedecl5' cannot add 'dllimport' attribute}}
+#endif
// Function template friends
struct FuncTmplFriend {
@@ -314,6 +358,9 @@ struct FuncTmplFriend {
template<typename T> friend __declspec(dllimport) void funcTmplFriend2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
template<typename T> friend __declspec(dllimport) void funcTmplFriend3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
template<typename T> friend void funcTmplFriend4(); // expected-note{{previous declaration is here}}
+#ifdef GNU
+// expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
template<typename T> friend __declspec(dllimport) inline void funcTmplFriend5();
};
template<typename T> __declspec(dllimport) void funcTmplFriend1();
@@ -332,6 +379,9 @@ namespace ns { template<typename T> __declspec(dllimport) void externalFuncTmpl(
template<typename T> void funcTmpl() {}
template<typename T> inline void inlineFuncTmpl() {}
template<typename T> __declspec(dllimport) void importedFuncTmplDecl();
+#ifdef GNU
+// expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
template<typename T> __declspec(dllimport) inline void importedFuncTmpl() {}
// Import implicit instantiation of an imported function template.
@@ -350,7 +400,9 @@ template void importedFuncTmpl<ExplicitInst_Imported>();
// declared inline.
template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Imported>();
template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Def_Imported>() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
+#ifdef MS
template<> __declspec(dllimport) inline void importedFuncTmpl<ExplicitSpec_InlineDef_Imported>() {}
+#endif
// Not importing specialization of an imported function template without
// explicit dllimport.
@@ -359,16 +411,25 @@ template<> void importedFuncTmpl<ExplicitSpec_NotImported>() {}
// Import explicit instantiation declaration of a non-imported function template.
extern template __declspec(dllimport) void funcTmpl<ExplicitDecl_Imported>();
+#ifdef GNU
+// expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
extern template __declspec(dllimport) void inlineFuncTmpl<ExplicitDecl_Imported>();
// Import explicit instantiation definition of a non-imported function template.
template __declspec(dllimport) void funcTmpl<ExplicitInst_Imported>();
+#ifdef GNU
+// expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
template __declspec(dllimport) void inlineFuncTmpl<ExplicitInst_Imported>();
// Import specialization of a non-imported function template. A definition must
// be declared inline.
template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Imported>();
template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Def_Imported>() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
+#ifdef GNU
+// expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
template<> __declspec(dllimport) inline void funcTmpl<ExplicitSpec_InlineDef_Imported>() {}
@@ -383,16 +444,28 @@ struct ImportMembers {
__declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
};
+#ifdef GNU
+// expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+6{{'dllimport' attribute ignored on inline function}}
+#endif
__declspec(dllimport) void normalDecl();
__declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
__declspec(dllimport) void normalInclass() {}
__declspec(dllimport) void normalInlineDef();
__declspec(dllimport) inline void normalInlineDecl();
+#ifdef GNU
+// expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+6{{'dllimport' attribute ignored on inline function}}
+#endif
__declspec(dllimport) virtual void virtualDecl();
__declspec(dllimport) virtual void virtualDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
__declspec(dllimport) virtual void virtualInclass() {}
__declspec(dllimport) virtual void virtualInlineDef();
__declspec(dllimport) virtual inline void virtualInlineDecl();
+#ifdef GNU
+// expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+6{{'dllimport' attribute ignored on inline function}}
+#endif
__declspec(dllimport) static void staticDecl();
__declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
__declspec(dllimport) static void staticInclass() {}
@@ -418,12 +491,21 @@ public:
void ImportMembers::Nested::normalDef() {} // expected-warning{{'ImportMembers::Nested::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
void ImportMembers::normalDef() {} // expected-warning{{'ImportMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#ifdef GNU
+// expected-warning@+2{{'ImportMembers::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#endif
inline void ImportMembers::normalInlineDef() {}
void ImportMembers::normalInlineDecl() {}
void ImportMembers::virtualDef() {} // expected-warning{{'ImportMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#ifdef GNU
+// expected-warning@+2{{'ImportMembers::virtualInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#endif
inline void ImportMembers::virtualInlineDef() {}
void ImportMembers::virtualInlineDecl() {}
void ImportMembers::staticDef() {} // expected-warning{{'ImportMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#ifdef GNU
+// expected-warning@+2{{'ImportMembers::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#endif
inline void ImportMembers::staticInlineDef() {}
void ImportMembers::staticInlineDecl() {}
@@ -436,13 +518,15 @@ constexpr int ImportMembers::ConstexprFieldDef; // expected-error{{definition of
struct ImportMemberDefs {
__declspec(dllimport) void normalDef();
__declspec(dllimport) void normalInlineDef();
- __declspec(dllimport) inline void normalInlineDecl();
__declspec(dllimport) virtual void virtualDef();
__declspec(dllimport) virtual void virtualInlineDef();
- __declspec(dllimport) virtual inline void virtualInlineDecl();
__declspec(dllimport) static void staticDef();
__declspec(dllimport) static void staticInlineDef();
+#ifdef MS
+ __declspec(dllimport) inline void normalInlineDecl();
+ __declspec(dllimport) virtual inline void virtualInlineDecl();
__declspec(dllimport) static inline void staticInlineDecl();
+#endif
__declspec(dllimport) static int StaticField;
__declspec(dllimport) static const int StaticConstField;
@@ -450,14 +534,16 @@ struct ImportMemberDefs {
};
__declspec(dllimport) void ImportMemberDefs::normalDef() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
+__declspec(dllimport) void ImportMemberDefs::virtualDef() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
+__declspec(dllimport) void ImportMemberDefs::staticDef() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
+#ifdef MS
__declspec(dllimport) inline void ImportMemberDefs::normalInlineDef() {}
__declspec(dllimport) void ImportMemberDefs::normalInlineDecl() {}
-__declspec(dllimport) void ImportMemberDefs::virtualDef() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
__declspec(dllimport) inline void ImportMemberDefs::virtualInlineDef() {}
__declspec(dllimport) void ImportMemberDefs::virtualInlineDecl() {}
-__declspec(dllimport) void ImportMemberDefs::staticDef() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
__declspec(dllimport) inline void ImportMemberDefs::staticInlineDef() {}
__declspec(dllimport) void ImportMemberDefs::staticInlineDecl() {}
+#endif
__declspec(dllimport) int ImportMemberDefs::StaticField; // expected-error{{definition of dllimport static field not allowed}} expected-note{{attribute is here}}
__declspec(dllimport) const int ImportMemberDefs::StaticConstField = 1; // expected-error{{definition of dllimport static field not allowed}} expected-note{{attribute is here}}
@@ -477,6 +563,7 @@ struct ImportSpecials {
// Import deleted member functions.
struct ImportDeleted {
+#ifdef MS
__declspec(dllimport) ImportDeleted() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
__declspec(dllimport) ~ImportDeleted() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
__declspec(dllimport) ImportDeleted(const ImportDeleted&) = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
@@ -484,6 +571,15 @@ struct ImportDeleted {
__declspec(dllimport) ImportDeleted(ImportDeleted&&) = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
__declspec(dllimport) ImportDeleted& operator=(ImportDeleted&&) = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
__declspec(dllimport) void deleted() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
+#else
+ __declspec(dllimport) ImportDeleted() = delete; // expected-warning{{'dllimport' attribute ignored on inline function}}
+ __declspec(dllimport) ~ImportDeleted() = delete; // expected-warning{{'dllimport' attribute ignored on inline function}}
+ __declspec(dllimport) ImportDeleted(const ImportDeleted&) = delete; // expected-warning{{'dllimport' attribute ignored on inline function}}
+ __declspec(dllimport) ImportDeleted& operator=(const ImportDeleted&) = delete; // expected-warning{{'dllimport' attribute ignored on inline function}}
+ __declspec(dllimport) ImportDeleted(ImportDeleted&&) = delete; // expected-warning{{'dllimport' attribute ignored on inline function}}
+ __declspec(dllimport) ImportDeleted& operator=(ImportDeleted&&) = delete; // expected-warning{{'dllimport' attribute ignored on inline function}}
+ __declspec(dllimport) void deleted() = delete; // expected-warning{{'dllimport' attribute ignored on inline function}}
+#endif
};
@@ -498,6 +594,14 @@ struct ImportAlloc {
// Import defaulted member functions.
struct ImportDefaulted {
+#ifdef GNU
+ // expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+#endif
__declspec(dllimport) ImportDefaulted() = default;
__declspec(dllimport) ~ImportDefaulted() = default;
__declspec(dllimport) ImportDefaulted(const ImportDefaulted&) = default;
@@ -512,6 +616,10 @@ struct ImportDefaultedDefs {
__declspec(dllimport) ImportDefaultedDefs();
__declspec(dllimport) ~ImportDefaultedDefs(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+#ifdef GNU
+// expected-warning@+3{{'dllimport' attribute ignored on inline function}}
+// expected-note@+2{{previous declaration is here}}
+#endif
__declspec(dllimport) inline ImportDefaultedDefs(const ImportDefaultedDefs&);
__declspec(dllimport) ImportDefaultedDefs& operator=(const ImportDefaultedDefs&);
@@ -526,6 +634,10 @@ __declspec(dllimport) ImportDefaultedDefs::ImportDefaultedDefs() = default; // e
ImportDefaultedDefs::~ImportDefaultedDefs() = default; // expected-warning{{'ImportDefaultedDefs::~ImportDefaultedDefs' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
// Import inline declaration and definition.
+#ifdef GNU
+// expected-error@+3{{redeclaration of 'ImportDefaultedDefs::ImportDefaultedDefs' cannot add 'dllimport' attribute}}
+// expected-warning@+3{{'ImportDefaultedDefs::operator=' redeclared inline; 'dllimport' attribute ignored}}
+#endif
__declspec(dllimport) ImportDefaultedDefs::ImportDefaultedDefs(const ImportDefaultedDefs&) = default;
inline ImportDefaultedDefs& ImportDefaultedDefs::operator=(const ImportDefaultedDefs&) = default;
@@ -536,15 +648,21 @@ ImportDefaultedDefs& ImportDefaultedDefs::operator=(ImportDefaultedDefs&&) = def
// Redeclarations cannot add dllimport.
struct MemberRedecl {
void normalDef(); // expected-note{{previous declaration is here}}
- void normalInlineDef(); // expected-note{{previous declaration is here}}
inline void normalInlineDecl(); // expected-note{{previous declaration is here}}
virtual void virtualDef(); // expected-note{{previous declaration is here}}
- virtual void virtualInlineDef(); // expected-note{{previous declaration is here}}
virtual inline void virtualInlineDecl(); // expected-note{{previous declaration is here}}
static void staticDef(); // expected-note{{previous declaration is here}}
- static void staticInlineDef(); // expected-note{{previous declaration is here}}
static inline void staticInlineDecl(); // expected-note{{previous declaration is here}}
+#ifdef MS
+ // expected-note@+4{{previous declaration is here}}
+ // expected-note@+4{{previous declaration is here}}
+ // expected-note@+4{{previous declaration is here}}
+#endif
+ void normalInlineDef();
+ virtual void virtualInlineDef();
+ static void staticInlineDef();
+
static int StaticField; // expected-note{{previous declaration is here}}
static const int StaticConstField; // expected-note{{previous declaration is here}}
constexpr static int ConstexprField = 1; // expected-note{{previous declaration is here}}
@@ -552,17 +670,26 @@ struct MemberRedecl {
__declspec(dllimport) void MemberRedecl::normalDef() {} // expected-error{{redeclaration of 'MemberRedecl::normalDef' cannot add 'dllimport' attribute}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
-__declspec(dllimport) inline void MemberRedecl::normalInlineDef() {} // expected-error{{redeclaration of 'MemberRedecl::normalInlineDef' cannot add 'dllimport' attribute}}
__declspec(dllimport) void MemberRedecl::normalInlineDecl() {} // expected-error{{redeclaration of 'MemberRedecl::normalInlineDecl' cannot add 'dllimport' attribute}}
__declspec(dllimport) void MemberRedecl::virtualDef() {} // expected-error{{redeclaration of 'MemberRedecl::virtualDef' cannot add 'dllimport' attribute}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
-__declspec(dllimport) inline void MemberRedecl::virtualInlineDef() {} // expected-error{{redeclaration of 'MemberRedecl::virtualInlineDef' cannot add 'dllimport' attribute}}
__declspec(dllimport) void MemberRedecl::virtualInlineDecl() {} // expected-error{{redeclaration of 'MemberRedecl::virtualInlineDecl' cannot add 'dllimport' attribute}}
__declspec(dllimport) void MemberRedecl::staticDef() {} // expected-error{{redeclaration of 'MemberRedecl::staticDef' cannot add 'dllimport' attribute}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
-__declspec(dllimport) inline void MemberRedecl::staticInlineDef() {} // expected-error{{redeclaration of 'MemberRedecl::staticInlineDef' cannot add 'dllimport' attribute}}
__declspec(dllimport) void MemberRedecl::staticInlineDecl() {} // expected-error{{redeclaration of 'MemberRedecl::staticInlineDecl' cannot add 'dllimport' attribute}}
+#ifdef MS
+__declspec(dllimport) inline void MemberRedecl::normalInlineDef() {} // expected-error{{redeclaration of 'MemberRedecl::normalInlineDef' cannot add 'dllimport' attribute}}
+__declspec(dllimport) inline void MemberRedecl::virtualInlineDef() {} // expected-error{{redeclaration of 'MemberRedecl::virtualInlineDef' cannot add 'dllimport' attribute}}
+__declspec(dllimport) inline void MemberRedecl::staticInlineDef() {} // expected-error{{redeclaration of 'MemberRedecl::staticInlineDef' cannot add 'dllimport' attribute}}
+#else
+__declspec(dllimport) inline void MemberRedecl::normalInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+__declspec(dllimport) inline void MemberRedecl::virtualInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+__declspec(dllimport) inline void MemberRedecl::staticInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+#endif
+
+
+
__declspec(dllimport) int MemberRedecl::StaticField = 1; // expected-error{{redeclaration of 'MemberRedecl::StaticField' cannot add 'dllimport' attribute}}
// expected-error@-1{{definition of dllimport static field not allowed}}
// expected-note@-2{{attribute is here}}
@@ -582,13 +709,20 @@ __declspec(dllimport) constexpr int MemberRedecl::ConstexprField; // expect
struct ImportMemberTmpl {
template<typename T> __declspec(dllimport) void normalDecl();
template<typename T> __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
- template<typename T> __declspec(dllimport) void normalInclass() {}
template<typename T> __declspec(dllimport) void normalInlineDef();
- template<typename T> __declspec(dllimport) inline void normalInlineDecl();
template<typename T> __declspec(dllimport) static void staticDecl();
template<typename T> __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
- template<typename T> __declspec(dllimport) static void staticInclass() {}
template<typename T> __declspec(dllimport) static void staticInlineDef();
+
+#ifdef GNU
+ // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+#endif
+ template<typename T> __declspec(dllimport) void normalInclass() {}
+ template<typename T> __declspec(dllimport) inline void normalInlineDecl();
+ template<typename T> __declspec(dllimport) static void staticInclass() {}
template<typename T> __declspec(dllimport) static inline void staticInlineDecl();
#if __has_feature(cxx_variable_templates)
@@ -604,12 +738,17 @@ struct ImportMemberTmpl {
};
template<typename T> void ImportMemberTmpl::normalDef() {} // expected-warning{{'ImportMemberTmpl::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
-template<typename T> inline void ImportMemberTmpl::normalInlineDef() {}
template<typename T> void ImportMemberTmpl::normalInlineDecl() {}
template<typename T> void ImportMemberTmpl::staticDef() {} // expected-warning{{'ImportMemberTmpl::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
-template<typename T> inline void ImportMemberTmpl::staticInlineDef() {}
template<typename T> void ImportMemberTmpl::staticInlineDecl() {}
+#ifdef GNU
+// expected-warning@+3{{ImportMemberTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+// expected-warning@+3{{ImportMemberTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#endif
+template<typename T> inline void ImportMemberTmpl::normalInlineDef() {}
+template<typename T> inline void ImportMemberTmpl::staticInlineDef() {}
+
#if __has_feature(cxx_variable_templates)
template<typename T> int ImportMemberTmpl::StaticFieldDef; // expected-error{{definition of dllimport static field not allowed}}
template<typename T> const int ImportMemberTmpl::StaticConstFieldDef = 1; // expected-error{{definition of dllimport static field not allowed}}
@@ -620,12 +759,17 @@ template<typename T> constexpr int ImportMemberTmpl::ConstexprFieldDef; // expec
// Redeclarations cannot add dllimport.
struct MemTmplRedecl {
template<typename T> void normalDef(); // expected-note{{previous declaration is here}}
- template<typename T> void normalInlineDef(); // expected-note{{previous declaration is here}}
template<typename T> inline void normalInlineDecl(); // expected-note{{previous declaration is here}}
template<typename T> static void staticDef(); // expected-note{{previous declaration is here}}
- template<typename T> static void staticInlineDef(); // expected-note{{previous declaration is here}}
template<typename T> static inline void staticInlineDecl(); // expected-note{{previous declaration is here}}
+#ifdef MS
+// expected-note@+3{{previous declaration is here}}
+// expected-note@+3{{previous declaration is here}}
+#endif
+ template<typename T> void normalInlineDef();
+ template<typename T> static void staticInlineDef();
+
#if __has_feature(cxx_variable_templates)
template<typename T> static int StaticField; // expected-note{{previous declaration is here}}
template<typename T> static const int StaticConstField; // expected-note{{previous declaration is here}}
@@ -635,11 +779,19 @@ struct MemTmplRedecl {
template<typename T> __declspec(dllimport) void MemTmplRedecl::normalDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::normalDef' cannot add 'dllimport' attribute}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
+#ifdef MS
template<typename T> __declspec(dllimport) inline void MemTmplRedecl::normalInlineDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::normalInlineDef' cannot add 'dllimport' attribute}}
+#else
+template<typename T> __declspec(dllimport) inline void MemTmplRedecl::normalInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+#endif
template<typename T> __declspec(dllimport) void MemTmplRedecl::normalInlineDecl() {} // expected-error{{redeclaration of 'MemTmplRedecl::normalInlineDecl' cannot add 'dllimport' attribute}}
template<typename T> __declspec(dllimport) void MemTmplRedecl::staticDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::staticDef' cannot add 'dllimport' attribute}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
+#ifdef MS
template<typename T> __declspec(dllimport) inline void MemTmplRedecl::staticInlineDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::staticInlineDef' cannot add 'dllimport' attribute}}
+#else
+template<typename T> __declspec(dllimport) inline void MemTmplRedecl::staticInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+#endif
template<typename T> __declspec(dllimport) void MemTmplRedecl::staticInlineDecl() {} // expected-error{{redeclaration of 'MemTmplRedecl::staticInlineDecl' cannot add 'dllimport' attribute}}
#if __has_feature(cxx_variable_templates)
@@ -658,8 +810,14 @@ template<typename T> __declspec(dllimport) constexpr int MemTmplRedecl::Constexp
struct MemFunTmpl {
template<typename T> void normalDef() {}
+#ifdef GNU
+ // expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
template<typename T> __declspec(dllimport) void importedNormal() {}
template<typename T> static void staticDef() {}
+#ifdef GNU
+ // expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
template<typename T> __declspec(dllimport) static void importedStatic() {}
};
@@ -683,16 +841,24 @@ template void MemFunTmpl::importedStatic<ExplicitInst_Imported>();
// Import specialization of an imported member function template.
template<> __declspec(dllimport) void MemFunTmpl::importedNormal<ExplicitSpec_Imported>();
template<> __declspec(dllimport) void MemFunTmpl::importedNormal<ExplicitSpec_Def_Imported>() {} // error on mingw
+#ifdef GNU
+ // expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
template<> __declspec(dllimport) inline void MemFunTmpl::importedNormal<ExplicitSpec_InlineDef_Imported>() {}
-#ifndef MSABI
-// expected-error@-3{{dllimport cannot be applied to non-inline function definition}}
+#if 1
+// FIXME: This should not be an error when targeting MSVC. (PR21406)
+// expected-error@-7{{dllimport cannot be applied to non-inline function definition}}
#endif
template<> __declspec(dllimport) void MemFunTmpl::importedStatic<ExplicitSpec_Imported>();
template<> __declspec(dllimport) void MemFunTmpl::importedStatic<ExplicitSpec_Def_Imported>() {} // error on mingw
+#ifdef GNU
+ // expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
template<> __declspec(dllimport) inline void MemFunTmpl::importedStatic<ExplicitSpec_InlineDef_Imported>() {}
-#ifndef MSABI
-// expected-error@-3{{dllimport cannot be applied to non-inline function definition}}
+#if 1
+// FIXME: This should not be an error when targeting MSVC. (PR21406)
+// expected-error@-7{{dllimport cannot be applied to non-inline function definition}}
#endif
// Not importing specialization of an imported member function template without
@@ -703,27 +869,43 @@ template<> void MemFunTmpl::importedStatic<ExplicitSpec_NotImported>() {}
// Import explicit instantiation declaration of a non-imported member function
// template.
+#ifdef GNU
+// expected-warning@+3{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+3{{'dllimport' attribute ignored on inline function}}
+#endif
extern template __declspec(dllimport) void MemFunTmpl::normalDef<ExplicitDecl_Imported>();
extern template __declspec(dllimport) void MemFunTmpl::staticDef<ExplicitDecl_Imported>();
// Import explicit instantiation definition of a non-imported member function
// template.
+#ifdef GNU
+// expected-warning@+3{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+3{{'dllimport' attribute ignored on inline function}}
+#endif
template __declspec(dllimport) void MemFunTmpl::normalDef<ExplicitInst_Imported>();
template __declspec(dllimport) void MemFunTmpl::staticDef<ExplicitInst_Imported>();
// Import specialization of a non-imported member function template.
template<> __declspec(dllimport) void MemFunTmpl::normalDef<ExplicitSpec_Imported>();
template<> __declspec(dllimport) void MemFunTmpl::normalDef<ExplicitSpec_Def_Imported>() {} // error on mingw
+#ifdef GNU
+ // expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
template<> __declspec(dllimport) inline void MemFunTmpl::normalDef<ExplicitSpec_InlineDef_Imported>() {}
-#ifndef MSABI
-// expected-error@-3{{dllimport cannot be applied to non-inline function definition}}
+#if 1
+// FIXME: This should not be an error when targeting MSVC. (PR21406)
+// expected-error@-7{{dllimport cannot be applied to non-inline function definition}}
#endif
template<> __declspec(dllimport) void MemFunTmpl::staticDef<ExplicitSpec_Imported>();
template<> __declspec(dllimport) void MemFunTmpl::staticDef<ExplicitSpec_Def_Imported>() {} // error on mingw
+#ifdef GNU
+ // expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
template<> __declspec(dllimport) inline void MemFunTmpl::staticDef<ExplicitSpec_InlineDef_Imported>() {}
-#ifndef MSABI
-// expected-error@-3{{dllimport cannot be applied to non-inline function definition}}
+#if 1
+// FIXME: This should not be an error when targeting MSVC. (PR21406)
+// expected-error@-7{{dllimport cannot be applied to non-inline function definition}}
#endif
@@ -783,18 +965,27 @@ template<typename T>
struct ImportClassTmplMembers {
__declspec(dllimport) void normalDecl();
__declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
- __declspec(dllimport) void normalInclass() {}
__declspec(dllimport) void normalInlineDef();
- __declspec(dllimport) inline void normalInlineDecl();
__declspec(dllimport) virtual void virtualDecl();
__declspec(dllimport) virtual void virtualDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
- __declspec(dllimport) virtual void virtualInclass() {}
__declspec(dllimport) virtual void virtualInlineDef();
- __declspec(dllimport) virtual inline void virtualInlineDecl();
__declspec(dllimport) static void staticDecl();
__declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
- __declspec(dllimport) static void staticInclass() {}
__declspec(dllimport) static void staticInlineDef();
+
+#ifdef GNU
+// expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+7{{'dllimport' attribute ignored on inline function}}
+#endif
+ __declspec(dllimport) void normalInclass() {}
+ __declspec(dllimport) inline void normalInlineDecl();
+ __declspec(dllimport) virtual void virtualInclass() {}
+ __declspec(dllimport) virtual inline void virtualInlineDecl();
+ __declspec(dllimport) static void staticInclass() {}
__declspec(dllimport) static inline void staticInlineDecl();
protected:
@@ -817,12 +1008,21 @@ public:
// NB: MSVC is inconsistent here and disallows *InlineDef on class templates,
// but allows it on classes. We allow both.
template<typename T> void ImportClassTmplMembers<T>::normalDef() {} // expected-warning{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#ifdef GNU
+// expected-warning@+2{{'ImportClassTmplMembers::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#endif
template<typename T> inline void ImportClassTmplMembers<T>::normalInlineDef() {}
template<typename T> void ImportClassTmplMembers<T>::normalInlineDecl() {}
template<typename T> void ImportClassTmplMembers<T>::virtualDef() {} // expected-warning{{'ImportClassTmplMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#ifdef GNU
+// expected-warning@+2{{'ImportClassTmplMembers::virtualInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#endif
template<typename T> inline void ImportClassTmplMembers<T>::virtualInlineDef() {}
template<typename T> void ImportClassTmplMembers<T>::virtualInlineDecl() {}
template<typename T> void ImportClassTmplMembers<T>::staticDef() {} // expected-warning{{'ImportClassTmplMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#ifdef GNU
+// expected-warning@+2{{'ImportClassTmplMembers::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#endif
template<typename T> inline void ImportClassTmplMembers<T>::staticInlineDef() {}
template<typename T> void ImportClassTmplMembers<T>::staticInlineDecl() {}
@@ -835,15 +1035,21 @@ template<typename T> constexpr int ImportClassTmplMembers<T>::ConstexprFieldDef;
template<typename T>
struct CTMR /*ClassTmplMemberRedecl*/ {
void normalDef(); // expected-note{{previous declaration is here}}
- void normalInlineDef(); // expected-note{{previous declaration is here}}
inline void normalInlineDecl(); // expected-note{{previous declaration is here}}
virtual void virtualDef(); // expected-note{{previous declaration is here}}
- virtual void virtualInlineDef(); // expected-note{{previous declaration is here}}
virtual inline void virtualInlineDecl(); // expected-note{{previous declaration is here}}
static void staticDef(); // expected-note{{previous declaration is here}}
- static void staticInlineDef(); // expected-note{{previous declaration is here}}
static inline void staticInlineDecl(); // expected-note{{previous declaration is here}}
+#ifdef MS
+// expected-note@+4{{previous declaration is here}}
+// expected-note@+4{{previous declaration is here}}
+// expected-note@+4{{previous declaration is here}}
+#endif
+ void normalInlineDef();
+ virtual void virtualInlineDef();
+ static void staticInlineDef();
+
static int StaticField; // expected-note{{previous declaration is here}}
static const int StaticConstField; // expected-note{{previous declaration is here}}
constexpr static int ConstexprField = 1; // expected-note{{previous declaration is here}}
@@ -851,17 +1057,24 @@ struct CTMR /*ClassTmplMemberRedecl*/ {
template<typename T> __declspec(dllimport) void CTMR<T>::normalDef() {} // expected-error{{redeclaration of 'CTMR::normalDef' cannot add 'dllimport' attribute}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
-template<typename T> __declspec(dllimport) inline void CTMR<T>::normalInlineDef() {} // expected-error{{redeclaration of 'CTMR::normalInlineDef' cannot add 'dllimport' attribute}}
template<typename T> __declspec(dllimport) void CTMR<T>::normalInlineDecl() {} // expected-error{{redeclaration of 'CTMR::normalInlineDecl' cannot add 'dllimport' attribute}}
template<typename T> __declspec(dllimport) void CTMR<T>::virtualDef() {} // expected-error{{redeclaration of 'CTMR::virtualDef' cannot add 'dllimport' attribute}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
-template<typename T> __declspec(dllimport) inline void CTMR<T>::virtualInlineDef() {} // expected-error{{redeclaration of 'CTMR::virtualInlineDef' cannot add 'dllimport' attribute}}
template<typename T> __declspec(dllimport) void CTMR<T>::virtualInlineDecl() {} // expected-error{{redeclaration of 'CTMR::virtualInlineDecl' cannot add 'dllimport' attribute}}
template<typename T> __declspec(dllimport) void CTMR<T>::staticDef() {} // expected-error{{redeclaration of 'CTMR::staticDef' cannot add 'dllimport' attribute}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
-template<typename T> __declspec(dllimport) inline void CTMR<T>::staticInlineDef() {} // expected-error{{redeclaration of 'CTMR::staticInlineDef' cannot add 'dllimport' attribute}}
template<typename T> __declspec(dllimport) void CTMR<T>::staticInlineDecl() {} // expected-error{{redeclaration of 'CTMR::staticInlineDecl' cannot add 'dllimport' attribute}}
+#ifdef MS
+template<typename T> __declspec(dllimport) inline void CTMR<T>::normalInlineDef() {} // expected-error{{redeclaration of 'CTMR::normalInlineDef' cannot add 'dllimport' attribute}}
+template<typename T> __declspec(dllimport) inline void CTMR<T>::virtualInlineDef() {} // expected-error{{redeclaration of 'CTMR::virtualInlineDef' cannot add 'dllimport' attribute}}
+template<typename T> __declspec(dllimport) inline void CTMR<T>::staticInlineDef() {} // expected-error{{redeclaration of 'CTMR::staticInlineDef' cannot add 'dllimport' attribute}}
+#else
+template<typename T> __declspec(dllimport) inline void CTMR<T>::normalInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+template<typename T> __declspec(dllimport) inline void CTMR<T>::virtualInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+template<typename T> __declspec(dllimport) inline void CTMR<T>::staticInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+#endif
+
template<typename T> __declspec(dllimport) int CTMR<T>::StaticField = 1; // expected-error{{redeclaration of 'CTMR::StaticField' cannot add 'dllimport' attribute}}
// expected-warning@-1{{definition of dllimport static field}}
// expected-note@-2{{attribute is here}}
@@ -882,13 +1095,20 @@ template<typename T>
struct ImportClsTmplMemTmpl {
template<typename U> __declspec(dllimport) void normalDecl();
template<typename U> __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
- template<typename U> __declspec(dllimport) void normalInclass() {}
template<typename U> __declspec(dllimport) void normalInlineDef();
- template<typename U> __declspec(dllimport) inline void normalInlineDecl();
template<typename U> __declspec(dllimport) static void staticDecl();
template<typename U> __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
- template<typename U> __declspec(dllimport) static void staticInclass() {}
template<typename U> __declspec(dllimport) static void staticInlineDef();
+
+#ifdef GNU
+ // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+#endif
+ template<typename U> __declspec(dllimport) void normalInclass() {}
+ template<typename U> __declspec(dllimport) inline void normalInlineDecl();
+ template<typename U> __declspec(dllimport) static void staticInclass() {}
template<typename U> __declspec(dllimport) static inline void staticInlineDecl();
#if __has_feature(cxx_variable_templates)
@@ -904,12 +1124,17 @@ struct ImportClsTmplMemTmpl {
};
template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::normalDef() {} // expected-warning{{'ImportClsTmplMemTmpl::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
-template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::normalInlineDef() {}
template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::normalInlineDecl() {}
template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::staticDef() {} // expected-warning{{'ImportClsTmplMemTmpl::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
-template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::staticInlineDef() {}
template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::staticInlineDecl() {}
+#ifdef GNU
+// expected-warning@+3{{'ImportClsTmplMemTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+// expected-warning@+3{{'ImportClsTmplMemTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#endif
+template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::normalInlineDef() {}
+template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::staticInlineDef() {}
+
#if __has_feature(cxx_variable_templates)
template<typename T> template<typename U> int ImportClsTmplMemTmpl<T>::StaticFieldDef; // expected-warning{{definition of dllimport static field}}
template<typename T> template<typename U> const int ImportClsTmplMemTmpl<T>::StaticConstFieldDef = 1; // expected-warning{{definition of dllimport static field}}
@@ -921,12 +1146,17 @@ template<typename T> template<typename U> constexpr int ImportClsTmplMemTmpl<T>:
template<typename T>
struct CTMTR /*ClassTmplMemberTmplRedecl*/ {
template<typename U> void normalDef(); // expected-note{{previous declaration is here}}
- template<typename U> void normalInlineDef(); // expected-note{{previous declaration is here}}
template<typename U> inline void normalInlineDecl(); // expected-note{{previous declaration is here}}
template<typename U> static void staticDef(); // expected-note{{previous declaration is here}}
- template<typename U> static void staticInlineDef(); // expected-note{{previous declaration is here}}
template<typename U> static inline void staticInlineDecl(); // expected-note{{previous declaration is here}}
+#ifdef MS
+ // expected-note@+3{{previous declaration is here}}
+ // expected-note@+3{{previous declaration is here}}
+#endif
+ template<typename U> void normalInlineDef();
+ template<typename U> static void staticInlineDef();
+
#if __has_feature(cxx_variable_templates)
template<typename U> static int StaticField; // expected-note{{previous declaration is here}}
template<typename U> static const int StaticConstField; // expected-note{{previous declaration is here}}
@@ -936,13 +1166,19 @@ struct CTMTR /*ClassTmplMemberTmplRedecl*/ {
template<typename T> template<typename U> __declspec(dllimport) void CTMTR<T>::normalDef() {} // expected-error{{redeclaration of 'CTMTR::normalDef' cannot add 'dllimport' attribute}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
-template<typename T> template<typename U> __declspec(dllimport) inline void CTMTR<T>::normalInlineDef() {} // expected-error{{redeclaration of 'CTMTR::normalInlineDef' cannot add 'dllimport' attribute}}
template<typename T> template<typename U> __declspec(dllimport) void CTMTR<T>::normalInlineDecl() {} // expected-error{{redeclaration of 'CTMTR::normalInlineDecl' cannot add 'dllimport' attribute}}
template<typename T> template<typename U> __declspec(dllimport) void CTMTR<T>::staticDef() {} // expected-error{{redeclaration of 'CTMTR::staticDef' cannot add 'dllimport' attribute}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
-template<typename T> template<typename U> __declspec(dllimport) inline void CTMTR<T>::staticInlineDef() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDef' cannot add 'dllimport' attribute}}
template<typename T> template<typename U> __declspec(dllimport) void CTMTR<T>::staticInlineDecl() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDecl' cannot add 'dllimport' attribute}}
+#ifdef MS
+template<typename T> template<typename U> __declspec(dllimport) inline void CTMTR<T>::normalInlineDef() {} // expected-error{{redeclaration of 'CTMTR::normalInlineDef' cannot add 'dllimport' attribute}}
+template<typename T> template<typename U> __declspec(dllimport) inline void CTMTR<T>::staticInlineDef() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDef' cannot add 'dllimport' attribute}}
+#else
+template<typename T> template<typename U> __declspec(dllimport) inline void CTMTR<T>::normalInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+template<typename T> template<typename U> __declspec(dllimport) inline void CTMTR<T>::staticInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+#endif
+
#if __has_feature(cxx_variable_templates)
template<typename T> template<typename U> __declspec(dllimport) int CTMTR<T>::StaticField = 1; // expected-error{{redeclaration of 'CTMTR::StaticField' cannot add 'dllimport' attribute}}
// expected-warning@-1{{definition of dllimport static field}}
@@ -961,6 +1197,10 @@ template<typename T> template<typename U> __declspec(dllimport) constexpr int CT
// Classes
//===----------------------------------------------------------------------===//
+namespace {
+ struct __declspec(dllimport) AnonymousClass {}; // expected-error{{(anonymous namespace)::AnonymousClass' must have external linkage when declared 'dllimport'}}
+}
+
class __declspec(dllimport) ClassDecl;
class __declspec(dllimport) ClassDef { };
@@ -984,7 +1224,7 @@ class __declspec(dllimport) ImportClassWithDllMember {
// expected-error@+4{{attribute 'dllimport' cannot be applied to member of 'dllexport' class}}
// expected-error@+4{{attribute 'dllexport' cannot be applied to member of 'dllexport' class}}
#endif
-class __declspec(dllexport) ExportClassWithDllMember {
+template <typename T> class __declspec(dllexport) ExportClassWithDllMember {
void __declspec(dllimport) foo();
void __declspec(dllexport) bar();
};
diff --git a/test/SemaCXX/enable_if.cpp b/test/SemaCXX/enable_if.cpp
index e9dc24254f20..99545e09820e 100644
--- a/test/SemaCXX/enable_if.cpp
+++ b/test/SemaCXX/enable_if.cpp
@@ -77,3 +77,44 @@ void test() {
typedep(1);
typedep(n); // expected-note{{in instantiation of function template specialization 'typedep<Nothing>' requested here}}
}
+
+template <typename T> class C {
+ void f() __attribute__((enable_if(T::expr == 0, ""))) {}
+ void g() { f(); }
+};
+
+int fn3(bool b) __attribute__((enable_if(b, "")));
+template <class T> void test3() {
+ fn3(sizeof(T) == 1);
+}
+
+// FIXME: issue an error (without instantiation) because ::h(T()) is not
+// convertible to bool, because return types aren't overloadable.
+void h(int);
+template <typename T> void outer() {
+ void local_function() __attribute__((enable_if(::h(T()), "")));
+ local_function();
+};
+
+namespace PR20988 {
+ struct Integer {
+ Integer(int);
+ };
+
+ int fn1(const Integer &) __attribute__((enable_if(true, "")));
+ template <class T> void test1() {
+ int &expr = T::expr();
+ fn1(expr);
+ }
+
+ int fn2(const Integer &) __attribute__((enable_if(false, ""))); // expected-note{{candidate disabled}}
+ template <class T> void test2() {
+ int &expr = T::expr();
+ fn2(expr); // expected-error{{no matching function for call to 'fn2'}}
+ }
+
+ int fn3(bool b) __attribute__((enable_if(b, "")));
+ template <class T> void test3() {
+ fn3(sizeof(T) == 1);
+ }
+}
diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp
index 1eed2281e935..909802335e46 100644
--- a/test/SemaCXX/enum-scoped.cpp
+++ b/test/SemaCXX/enum-scoped.cpp
@@ -301,3 +301,11 @@ namespace PR18044 {
using E::a; // ok!
E b = a;
}
+
+namespace test11 {
+ enum class E { a };
+ typedef E E2;
+ E2 f1() { return E::a; }
+
+ bool f() { return !f1(); } // expected-error {{invalid argument type 'E2' (aka 'test11::E') to unary expression}}
+}
diff --git a/test/SemaCXX/exceptions.cpp b/test/SemaCXX/exceptions.cpp
index c2ca9f952b22..9646a9c3b31a 100644
--- a/test/SemaCXX/exceptions.cpp
+++ b/test/SemaCXX/exceptions.cpp
@@ -35,37 +35,37 @@ void throws() {
void jumps() {
l1:
goto l5;
- goto l4; // expected-error {{goto into protected scope}}
- goto l3; // expected-error {{goto into protected scope}}
- goto l2; // expected-error {{goto into protected scope}}
+ goto l4; // expected-error {{cannot jump}}
+ goto l3; // expected-error {{cannot jump}}
+ goto l2; // expected-error {{cannot jump}}
goto l1;
try { // expected-note 4 {{jump bypasses initialization of try block}}
l2:
goto l5;
- goto l4; // expected-error {{goto into protected scope}}
- goto l3; // expected-error {{goto into protected scope}}
+ goto l4; // expected-error {{cannot jump}}
+ goto l3; // expected-error {{cannot jump}}
goto l2;
goto l1;
} catch(int) { // expected-note 4 {{jump bypasses initialization of catch block}}
l3:
goto l5;
- goto l4; // expected-error {{goto into protected scope}}
+ goto l4; // expected-error {{cannot jump}}
goto l3;
- goto l2; // expected-error {{goto into protected scope}}
+ goto l2; // expected-error {{cannot jump}}
goto l1;
} catch(...) { // expected-note 4 {{jump bypasses initialization of catch block}}
l4:
goto l5;
goto l4;
- goto l3; // expected-error {{goto into protected scope}}
- goto l2; // expected-error {{goto into protected scope}}
+ goto l3; // expected-error {{cannot jump}}
+ goto l2; // expected-error {{cannot jump}}
goto l1;
}
l5:
goto l5;
- goto l4; // expected-error {{goto into protected scope}}
- goto l3; // expected-error {{goto into protected scope}}
- goto l2; // expected-error {{goto into protected scope}}
+ goto l4; // expected-error {{cannot jump}}
+ goto l3; // expected-error {{cannot jump}}
+ goto l2; // expected-error {{cannot jump}}
goto l1;
}
diff --git a/test/SemaCXX/explicit.cpp b/test/SemaCXX/explicit.cpp
index aa28bd85af46..155141c058c4 100644
--- a/test/SemaCXX/explicit.cpp
+++ b/test/SemaCXX/explicit.cpp
@@ -86,7 +86,7 @@ namespace Conversion {
// Y is an aggregate, so aggregate-initialization is performed and the
// conversion function is not considered.
const Y y10{z}; // expected-error {{excess elements}}
- const Y& y11{z}; // expected-error {{no viable conversion from 'Z' to 'const Y'}}
+ const Y& y11{z}; // expected-error {{excess elements}} expected-note {{in initialization of temporary of type 'const Y'}}
const int& y12{z};
// X is not an aggregate, so constructors are considered.
diff --git a/test/SemaCXX/flexible-array-test.cpp b/test/SemaCXX/flexible-array-test.cpp
index e58f19a62eca..2d74fa52452e 100644
--- a/test/SemaCXX/flexible-array-test.cpp
+++ b/test/SemaCXX/flexible-array-test.cpp
@@ -14,6 +14,12 @@ void QMap<Key, T>::insert(const Key &, const T &avalue)
v = avalue;
}
+struct Rec {
+ union { // expected-warning-re {{variable sized type '{{.*}}' not at the end of a struct or class is a GNU extension}}
+ int u0[];
+ };
+ int x;
+} rec;
struct inotify_event
{
diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
index 2f777fb46df0..d07331c51e29 100644
--- a/test/SemaCXX/for-range-examples.cpp
+++ b/test/SemaCXX/for-range-examples.cpp
@@ -214,17 +214,19 @@ namespace test6 {
namespace test7 {
void f() {
int arr[5], b;
- for (a : arr) {} // expected-warning {{extension}}
- // FIXME: Give a -Wshadow for this by default?
- for (b : arr) {} // expected-warning {{extension}}
- for (arr : arr) {} // expected-warning {{extension}}
- for (c alignas(8) : arr) { // expected-warning {{extension}}
+ for (a : arr) {} // expected-error {{requires type for loop variable}}
+ // FIXME: Give a different error in this case?
+ for (b : arr) {} // expected-error {{requires type for loop variable}}
+ for (arr : arr) {} // expected-error {{requires type for loop variable}}
+ for (c alignas(8) : arr) { // expected-error {{requires type for loop variable}}
static_assert(alignof(c) == 8, ""); // expected-warning {{extension}}
}
- // FIXME: We should reject this, but don't, because we only check the
- // attribute before we deduce the 'auto' type.
- for (d alignas(1) : arr) {} // expected-warning {{extension}}
- for (e [[deprecated]] : arr) { e = 0; } // expected-warning {{deprecated}} expected-note {{here}} expected-warning {{extension}}
+ // FIXME: The fix-it hint here is not sufficient to fix the error.
+ // We fail to diagnose that d is underaligned for its type, because
+ // we check the alignment attribute before we perform the auto
+ // deduction.
+ for (d alignas(1) : arr) {} // expected-error {{requires type for loop variable}}
+ for (e [[deprecated]] : arr) { e = 0; } // expected-warning {{deprecated}} expected-note {{here}} expected-error {{requires type for loop variable}}
}
}
diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp
index 03589101e1b8..55aa069803bf 100644
--- a/test/SemaCXX/friend.cpp
+++ b/test/SemaCXX/friend.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
friend class A; // expected-error {{'friend' used outside of class}}
void f() { friend class A; } // expected-error {{'friend' used outside of class}}
@@ -296,3 +296,56 @@ namespace test11 {
friend class __attribute__((visibility("hidden"), noreturn)) B; // expected-warning {{'noreturn' attribute only applies to functions and methods}}
};
}
+
+namespace pr21851 {
+// PR21851 was a problem where we assumed that when the friend function redecl
+// lookup found a C++ method, it would necessarily have a qualifier. Below we
+// have some test cases where unqualified lookup finds C++ methods without using
+// qualifiers. Unfortunately, we can't exercise the case of an access check
+// failure because nested classes always have access to the members of outer
+// classes.
+
+void friend_own_method() {
+ class A {
+ void m() {}
+ friend void m();
+ };
+}
+
+void friend_enclosing_method() {
+ class A;
+ class C {
+ int p;
+ friend class A;
+ };
+ class A {
+ void enclosing_friend() {
+ (void)b->p;
+ (void)c->p;
+ }
+ class B {
+ void b(A *a) {
+ (void)a->c->p;
+ }
+ int p;
+ friend void enclosing_friend();
+ };
+ B *b;
+ C *c;
+ };
+}
+
+static auto friend_file_func() {
+ extern void file_scope_friend();
+ class A {
+ int p;
+ friend void file_scope_friend();
+ };
+ return A();
+}
+
+void file_scope_friend() {
+ auto a = friend_file_func();
+ (void)a.p;
+}
+}
diff --git a/test/SemaCXX/goto.cpp b/test/SemaCXX/goto.cpp
index 042ec3cd8035..2d37ea9099a2 100644
--- a/test/SemaCXX/goto.cpp
+++ b/test/SemaCXX/goto.cpp
@@ -109,7 +109,7 @@ namespace PR10620 {
~S() {}
};
void g(const S& s) {
- goto done; // expected-error {{goto into protected scope}}
+ goto done; // expected-error {{cannot jump}}
const S s2(s); // expected-note {{jump bypasses variable initialization}}
done:
;
@@ -119,7 +119,7 @@ namespace PR10620 {
namespace test12 {
struct A { A(); A(const A&); ~A(); };
void test(A a) { // expected-note {{jump enters lifetime of block}} FIXME: weird location
- goto lbl; // expected-error {{goto into protected scope}}
+ goto lbl; // expected-error {{cannot jump}}
(void) ^{ (void) a; };
lbl:
return;
diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp
index e26f985f0d0a..ff3d685d912e 100644
--- a/test/SemaCXX/implicit-exception-spec.cpp
+++ b/test/SemaCXX/implicit-exception-spec.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 -Wall %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 -Wall -Wno-unused-local-typedefs %s
template<bool b> struct ExceptionIf { static int f(); };
template<> struct ExceptionIf<false> { typedef int f; };
@@ -17,42 +17,43 @@ namespace InClassInitializers {
// is false.
bool ThrowSomething() noexcept(false);
struct ConstExpr {
- bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{cannot be used by non-static data member initializer}}
+ bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{cannot use defaulted default constructor of 'ConstExpr' within the class outside of member functions}}
+ // expected-note@-1 {{implicit default constructor for 'InClassInitializers::ConstExpr' first required here}}
};
- // 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 {{cannot be used by non-static data member initializer}}
+ int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{cannot use defaulted default constructor of 'TemplateArg' within the class outside of member functions}}
+ // expected-note@-1 {{implicit default constructor for 'InClassInitializers::TemplateArg' first required here}}
};
- bool x = noexcept(TemplateArg());
// And within a nested class.
- struct Nested { // expected-error {{cannot be used by non-static data member initializer}}
+ struct Nested { // expected-note {{implicit default constructor for 'InClassInitializers::Nested::Inner' first required here}}
struct Inner {
+ // expected-error@+1 {{cannot use defaulted default constructor of 'Inner' within 'Nested' outside of member functions}}
int n = ExceptionIf<noexcept(Nested())>::f(); // expected-note {{implicit default constructor for 'InClassInitializers::Nested' first required here}}
} inner;
};
- struct Nested2 {
+ struct Nested2 { // expected-error {{implicit default constructor for 'InClassInitializers::Nested2' must explicitly initialize the member 'inner' which does not have a default constructor}}
struct Inner;
- int n = Inner().n; // expected-error {{cannot be used by non-static data member initializer}}
- struct Inner {
+ int n = Inner().n; // expected-note {{implicit default constructor for 'InClassInitializers::Nested2::Inner' first required here}}
+ struct Inner { // expected-note {{declared here}}
+ // expected-error@+1 {{cannot use defaulted default constructor of 'Inner' within 'Nested2' outside of member functions}}
int n = ExceptionIf<noexcept(Nested2())>::f();
- } inner;
+ // expected-note@-1 {{implicit default constructor for 'InClassInitializers::Nested2' first required here}}
+ } inner; // expected-note {{member is declared here}}
};
}
namespace ExceptionSpecification {
- // A type is permitted to be used in a dynamic exception specification when it
- // is still being defined, but isn't complete within such an exception
- // specification.
- struct Nested { // expected-note {{not complete}}
+ // FIXME: This diagnostic is quite useless; we should indicate whose
+ // exception specification we were looking for and why.
+ struct Nested {
struct T {
- T() noexcept(!noexcept(Nested())); // expected-error{{incomplete type}}
- } t;
+ T() noexcept(!noexcept(Nested()));
+ } t; // expected-error{{exception specification is not available until end of class definition}}
};
}
diff --git a/test/SemaCXX/issue547.cpp b/test/SemaCXX/issue547.cpp
index bfec6e080ba5..2a9dd13adf4e 100644
--- a/test/SemaCXX/issue547.cpp
+++ b/test/SemaCXX/issue547.cpp
@@ -27,32 +27,32 @@ struct classify_function<R(Args...) const volatile> {
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......)> {
+struct classify_function<R(Args..., ...)> {
static const unsigned value = 5;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......) const> {
+struct classify_function<R(Args..., ...) const> {
static const unsigned value = 6;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......) volatile> {
+struct classify_function<R(Args..., ...) volatile> {
static const unsigned value = 7;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......) const volatile> {
+struct classify_function<R(Args..., ...) const volatile> {
static const unsigned value = 8;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......) &&> {
+struct classify_function<R(Args..., ...) &&> {
static const unsigned value = 9;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......) const &> {
+struct classify_function<R(Args..., ...) const &> {
static const unsigned value = 10;
};
diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp
index 9a53e4604f76..cad322ab52fe 100644
--- a/test/SemaCXX/lambda-expressions.cpp
+++ b/test/SemaCXX/lambda-expressions.cpp
@@ -258,9 +258,7 @@ namespace TypeDeduction {
void f() {
const S s {};
S &&t = [&] { return s; } ();
-#if __cplusplus <= 201103L
- // expected-error@-2 {{drops qualifiers}}
-#else
+#if __cplusplus > 201103L
S &&u = [&] () -> auto { return s; } ();
#endif
}
@@ -363,3 +361,79 @@ namespace PR18473 {
void PR19249() {
auto x = [&x]{}; // expected-error {{cannot appear in its own init}}
}
+
+namespace PR20731 {
+template <class L, int X = sizeof(L)>
+void Job(L l);
+
+template <typename... Args>
+void Logger(Args &&... args) {
+ auto len = Invalid_Function((args)...);
+ // expected-error@-1 {{use of undeclared identifier 'Invalid_Function'}}
+ Job([len]() {});
+}
+
+void GetMethod() {
+ Logger();
+ // expected-note@-1 {{in instantiation of function template specialization 'PR20731::Logger<>' requested here}}
+}
+
+template <typename T>
+struct A {
+ T t;
+ // expected-error@-1 {{field has incomplete type 'void'}}
+};
+
+template <typename F>
+void g(F f) {
+ auto a = A<decltype(f())>{};
+ // expected-note@-1 {{in instantiation of template class 'PR20731::A<void>' requested here}}
+ auto xf = [a, f]() {};
+ int x = sizeof(xf);
+};
+void f() {
+ g([] {});
+ // expected-note-re@-1 {{in instantiation of function template specialization 'PR20731::g<(lambda at {{.*}}>' requested here}}
+}
+
+template <class _Rp> struct function {
+ template <class _Fp>
+ function(_Fp) {
+ static_assert(sizeof(_Fp) > 0, "Type must be complete.");
+ }
+};
+
+template <typename T> void p(T t) {
+ auto l = some_undefined_function(t);
+ // expected-error@-1 {{use of undeclared identifier 'some_undefined_function'}}
+ function<void()>(([l]() {}));
+}
+void q() { p(0); }
+// expected-note@-1 {{in instantiation of function template specialization 'PR20731::p<int>' requested here}}
+}
+
+namespace lambda_in_default_mem_init {
+ template<typename T> void f() {
+ struct S { int n = []{ return 0; }(); };
+ }
+ template void f<int>();
+
+ template<typename T> void g() {
+ struct S { int n = [](int n){ return n; }(0); };
+ }
+ template void g<int>();
+}
+
+namespace error_in_transform_prototype {
+ template<class T>
+ void f(T t) {
+ // expected-error@+2 {{type 'int' cannot be used prior to '::' because it has no members}}
+ // expected-error@+1 {{no member named 'ns' in 'error_in_transform_prototype::S'}}
+ auto x = [](typename T::ns::type &k) {};
+ }
+ class S {};
+ void foo() {
+ f(5); // expected-note {{requested here}}
+ f(S()); // expected-note {{requested here}}
+ }
+}
diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist-system-header.cpp b/test/SemaCXX/libstdcxx_explicit_init_list_hack.cpp
index 774745777c17..774745777c17 100644
--- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist-system-header.cpp
+++ b/test/SemaCXX/libstdcxx_explicit_init_list_hack.cpp
diff --git a/test/SemaCXX/libstdcxx_is_pod_hack.cpp b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
index 1ba3721c8c2e..8d187124f013 100644
--- a/test/SemaCXX/libstdcxx_is_pod_hack.cpp
+++ b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// This is a test for an egregious hack in Clang that works around
// issues with GCC's evolution. libstdc++ 4.2.x uses __is_pod as an
@@ -7,7 +7,7 @@
// a keyword *unless* it is introduced following the struct keyword.
template<typename T>
-struct __is_pod {
+struct __is_pod { // expected-warning {{keyword '__is_pod' will be made available as an identifier}}
__is_pod() {}
};
@@ -15,7 +15,7 @@ __is_pod<int> ipi;
// Ditto for __is_same.
template<typename T>
-struct __is_same {
+struct __is_same { // expected-warning {{keyword '__is_same' will be made available as an identifier}}
};
__is_same<int> isi;
@@ -24,7 +24,7 @@ __is_same<int> isi;
// trait in Embarcadero's compiler but is used as an identifier in
// libstdc++.
struct test_is_signed {
- static const bool __is_signed = true;
+ static const bool __is_signed = true; // expected-warning {{keyword '__is_signed' will be made available as an identifier}}
};
bool check_signed = test_is_signed::__is_signed;
@@ -36,6 +36,13 @@ void foo() {
bool b = __is_pod(int);
must_be_true<__is_pod(int)> mbt;
}
+
+// expected-warning@+1 {{declaration does not declare anything}}
+struct // expected-error {{declaration of anonymous struct must be a definition}}
+#pragma pack(pop)
+ S {
+};
+
#if !__has_feature(is_pod)
# error __is_pod should still be available.
#endif
diff --git a/test/SemaCXX/libstdcxx_pair_swap_hack.cpp b/test/SemaCXX/libstdcxx_pair_swap_hack.cpp
new file mode 100644
index 000000000000..02431e02e48d
--- /dev/null
+++ b/test/SemaCXX/libstdcxx_pair_swap_hack.cpp
@@ -0,0 +1,74 @@
+// This is a test for an egregious hack in Clang that works around
+// an issue with GCC's <utility> implementation. std::pair::swap
+// has an exception specification that makes an unqualified call to
+// swap. This is invalid, because it ends up calling itself with
+// the wrong number of arguments.
+//
+// The same problem afflicts a bunch of other class templates. Those
+// affected are array, pair, priority_queue, stack, and queue.
+
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=pair
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=priority_queue
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=stack
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=queue
+
+// MSVC's standard library uses a very similar pattern that relies on delayed
+// parsing of exception specifications.
+//
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array -DMSVC
+
+#ifdef BE_THE_HEADER
+
+#pragma GCC system_header
+namespace std {
+ template<typename T> void swap(T &, T &);
+ template<typename T> void do_swap(T &a, T &b) noexcept(noexcept(swap(a, b))) {
+ swap(a, b);
+ }
+
+ template<typename A, typename B> struct CLASS {
+#ifdef MSVC
+ void swap(CLASS &other) noexcept(noexcept(do_swap(member, other.member)));
+#endif
+ A member;
+#ifndef MSVC
+ void swap(CLASS &other) noexcept(noexcept(swap(member, other.member)));
+#endif
+ };
+
+// template<typename T> void do_swap(T &, T &);
+// template<typename A> struct vector {
+// void swap(vector &other) noexcept(noexcept(do_swap(member, other.member)));
+// A member;
+// };
+}
+
+#else
+
+#define BE_THE_HEADER
+#include __FILE__
+
+struct X {};
+using PX = std::CLASS<X, X>;
+using PI = std::CLASS<int, int>;
+void swap(X &, X &) noexcept;
+PX px;
+PI pi;
+
+static_assert(noexcept(px.swap(px)), "");
+static_assert(!noexcept(pi.swap(pi)), "");
+
+namespace sad {
+ template<typename T> void swap(T &, T &);
+
+ template<typename A, typename B> struct CLASS {
+ void swap(CLASS &other) noexcept(noexcept(swap(*this, other))); // expected-error {{too many arguments}} expected-note {{declared here}}
+ };
+
+ CLASS<int, int> pi;
+
+ static_assert(!noexcept(pi.swap(pi)), ""); // expected-note {{in instantiation of}}
+}
+
+#endif
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
index d8a00b3b1e24..b3ee30b456ec 100644
--- a/test/SemaCXX/member-init.cpp
+++ b/test/SemaCXX/member-init.cpp
@@ -14,7 +14,10 @@ public:
bool b();
int k;
struct Recurse {
- int &n = b() ? Recurse().n : k; // expected-error {{defaulted default constructor of 'Recurse' cannot be used by non-static data member initializer which appears before end of class definition}}
+ int &n = // expected-error {{cannot use defaulted default constructor of 'Recurse' within the class outside of member functions because 'n' has an initializer}}
+ b() ?
+ Recurse().n : // expected-note {{implicit default constructor for 'Recurse' first required here}}
+ k;
};
struct UnknownBound {
@@ -110,3 +113,82 @@ namespace PR18560 {
struct Y { int b = f(); };
}
+
+namespace template_valid {
+// Valid, we shouldn't build a CXXDefaultInitExpr until A's ctor definition.
+struct A {
+ A();
+ template <typename T>
+ struct B { int m1 = sizeof(A) + sizeof(T); };
+ B<int> m2;
+};
+A::A() {}
+}
+
+namespace template_default_ctor {
+struct A {
+ template <typename T>
+ struct B {
+ int m1 = 0; // expected-error {{cannot use defaulted default constructor of 'B' within 'A' outside of member functions because 'm1' has an initializer}}
+ };
+ // expected-note@+1 {{implicit default constructor for 'template_default_ctor::A::B<int>' first required here}}
+ enum { NOE = noexcept(B<int>()) };
+};
+}
+
+namespace default_ctor {
+struct A {
+ struct B {
+ int m1 = 0; // expected-error {{cannot use defaulted default constructor of 'B' within 'A' outside of member functions because 'm1' has an initializer}}
+ };
+ // expected-note@+1 {{implicit default constructor for 'default_ctor::A::B' first required here}}
+ enum { NOE = noexcept(B()) };
+};
+}
+
+namespace member_template {
+struct A {
+ template <typename T>
+ struct B {
+ struct C {
+ int m1 = 0; // expected-error {{cannot use defaulted default constructor of 'C' within 'A' outside of member functions because 'm1' has an initializer}}
+ };
+ template <typename U>
+ struct D {
+ int m1 = 0; // expected-error {{cannot use defaulted default constructor of 'D' within 'A' outside of member functions because 'm1' has an initializer}}
+ };
+ };
+ enum {
+ // expected-note@+1 {{implicit default constructor for 'member_template::A::B<int>::C' first required here}}
+ NOE1 = noexcept(B<int>::C()),
+ // expected-note@+1 {{implicit default constructor for 'member_template::A::B<int>::D<int>' first required here}}
+ NOE2 = noexcept(B<int>::D<int>())
+ };
+};
+}
+
+namespace explicit_instantiation {
+template<typename T> struct X {
+ X(); // expected-note {{in instantiation of default member initializer 'explicit_instantiation::X<float>::n' requested here}}
+ int n = T::error; // expected-error {{type 'float' cannot be used prior to '::' because it has no members}}
+};
+template struct X<int>; // ok
+template<typename T> X<T>::X() {}
+template struct X<float>; // expected-note {{in instantiation of member function 'explicit_instantiation::X<float>::X' requested here}}
+}
+
+namespace local_class {
+template<typename T> void f() {
+ struct X { // expected-note {{in instantiation of default member initializer 'local_class::f()::X::n' requested here}}
+ int n = T::error; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
+ };
+}
+void g() { f<int>(); } // expected-note {{in instantiation of function template specialization 'local_class::f<int>' requested here}}
+}
+
+namespace PR22056 {
+template <int N>
+struct S {
+ int x[3] = {[N] = 3};
+};
+}
diff --git a/test/SemaCXX/member-pointer-ms.cpp b/test/SemaCXX/member-pointer-ms.cpp
index e7c4ae9409e0..39cf601dc956 100644
--- a/test/SemaCXX/member-pointer-ms.cpp
+++ b/test/SemaCXX/member-pointer-ms.cpp
@@ -249,6 +249,25 @@ struct __virtual_inheritance D;
struct D : virtual B {};
}
#ifdef VMB
+
+namespace PR20017 {
+template <typename T>
+struct A {
+ int T::*f();
+};
+
+struct B;
+
+auto a = &A<B>::f;
+
+struct B {};
+
+void q() {
+ A<B> b;
+ (b.*a)();
+}
+}
+
#pragma pointers_to_members(full_generality, multiple_inheritance)
struct TrulySingleInheritance;
static_assert(sizeof(int TrulySingleInheritance::*) == kMultipleDataSize, "");
diff --git a/test/SemaCXX/namespace-alias.cpp b/test/SemaCXX/namespace-alias.cpp
index e18b58b4d441..63615ecbd352 100644
--- a/test/SemaCXX/namespace-alias.cpp
+++ b/test/SemaCXX/namespace-alias.cpp
@@ -35,12 +35,12 @@ namespace H {
namespace A2 { }
// These all point to A1.
- namespace B = A1; // expected-note {{previous definition is here}}
+ namespace B = A1;
namespace B = A1;
namespace C = B;
- namespace B = C;
+ namespace B = C; // expected-note {{previously defined as an alias for 'A1'}}
- namespace B = A2; // expected-error {{redefinition of 'B' as different kind of symbol}}
+ namespace B = A2; // expected-error {{redefinition of 'B' as an alias for a different namespace}}
}
namespace I {
diff --git a/test/SemaCXX/nonnull.cpp b/test/SemaCXX/nonnull.cpp
index 9ff6d115bd16..97b54553427d 100644
--- a/test/SemaCXX/nonnull.cpp
+++ b/test/SemaCXX/nonnull.cpp
@@ -13,3 +13,8 @@ struct TS {
}
};
+namespace Template {
+ template<typename T> __attribute__((nonnull)) void f(T t);
+ void g() { f((void*)0); } // expected-warning {{null passed to a callee that requires a non-null argument}}
+ void h() { f(0); }
+}
diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp
index 28798a4f8ce8..7d765b482c73 100644
--- a/test/SemaCXX/nullptr.cpp
+++ b/test/SemaCXX/nullptr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding -Wno-null-conversion %s
#include <stdint.h>
typedef decltype(nullptr) nullptr_t;
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index feb7c716ff00..369e9eb802a5 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -519,3 +519,15 @@ namespace ConversionVersusTemplateOrdering {
int x = a;
int y = b;
}
+
+namespace NoADLForMemberOnlyOperators {
+ template<typename T> struct A { typename T::error e; }; // expected-error {{type 'char' cannot be used prior to '::'}}
+ template<typename T> struct B { int n; };
+
+ void f(B<A<void> > b1, B<A<int> > b2, B<A<char> > b3) {
+ b1 = b1; // ok, does not instantiate A<void>.
+ (void)b1->n; // expected-error {{is not a pointer}}
+ b2[3]; // expected-error {{does not provide a subscript}}
+ b3 / 0; // expected-note {{in instantiation of}} expected-error {{invalid operands to}}
+ }
+}
diff --git a/test/SemaCXX/override-in-system-header.cpp b/test/SemaCXX/override-in-system-header.cpp
new file mode 100644
index 000000000000..689585e0cf12
--- /dev/null
+++ b/test/SemaCXX/override-in-system-header.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++11 -isystem %S/Inputs %s -verify
+// expected-no-diagnostics
+// rdar://18295240
+
+#include <override-system-header.h>
+
+struct A
+{
+ virtual void x();
+ END_COM_MAP;
+ IFACEMETHOD(Initialize)();
+};
+
+struct B : A
+{
+ virtual void x() override;
+ END_COM_MAP;
+ IFACEMETHOD(Initialize)();
+};
diff --git a/test/SemaCXX/pragma-optimize.cpp b/test/SemaCXX/pragma-optimize.cpp
index 0f03b81f5fff..48a15460fc96 100644
--- a/test/SemaCXX/pragma-optimize.cpp
+++ b/test/SemaCXX/pragma-optimize.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -x c++ -std=c++11 -triple x86_64-unknown-linux -emit-llvm -O2 < %s | FileCheck %s
+// RUN: %clang_cc1 -I %S/Inputs -x c++ -std=c++11 -triple x86_64-unknown-linux -emit-llvm -O2 < %s | FileCheck %s
+// RUN: %clang_cc1 -I %S/Inputs -x c++ -std=c++11 -triple x86_64-unknown-linux -emit-llvm -Os < %s | FileCheck %s
+// RUN: %clang_cc1 -I %S/Inputs -x c++ -std=c++11 -triple x86_64-unknown-linux -emit-llvm -Oz < %s | FileCheck %s
#pragma clang optimize off
@@ -55,6 +57,13 @@ int __attribute__((always_inline)) baz(int z) {
}
// CHECK-DAG: @_Z3bazi{{.*}} [[ATTRBAZ:#[0-9]+]]
+// This function definition will not be decorated with `optnone` because the
+// attribute would conflict with `minsize`.
+int __attribute__((minsize)) bax(int z) {
+ return foo(z, 2);
+}
+// CHECK-DAG: @_Z3baxi{{.*}} [[ATTRBAX:#[0-9]+]]
+
#pragma clang optimize on
// The function "int wombat(int param)" created by the macro is not
@@ -96,18 +105,60 @@ int container3 (int par) {
// CHECK-DAG: @_Z6thriceIiET_S0_{{.*}} [[ATTRTHRICEINT:#[0-9]+]]
+// Test that we can re-open and re-close an "off" region after the first one,
+// and that this works as expected.
+
+#pragma clang optimize off
+
+int another_optnone(int x) {
+ return x << 1;
+}
+// CHECK-DAG: @_Z15another_optnonei{{.*}} [[ATTRANOTHEROPTNONE:#[0-9]+]]
+
+#pragma clang optimize on
+
+int another_normal(int x) {
+ return x << 2;
+}
+// CHECK-DAG: @_Z14another_normali{{.*}} [[ATTRANOTHERNORMAL:#[0-9]+]]
+
+
+// Test that we can re-open an "off" region by including a header with the
+// pragma and that this works as expected (i.e. the off region "falls through"
+// the end of the header into this file).
+
+#include <header-with-pragma-optimize-off.h>
+
+int yet_another_optnone(int x) {
+ return x << 3;
+}
+// CHECK-DAG: @_Z19yet_another_optnonei{{.*}} [[ATTRYETANOTHEROPTNONE:#[0-9]+]]
+
+#pragma clang optimize on
+
+int yet_another_normal(int x) {
+ return x << 4;
+}
+// CHECK-DAG: @_Z18yet_another_normali{{.*}} [[ATTRYETANOTHERNORMAL:#[0-9]+]]
+
+
// Check for both noinline and optnone on each function that should have them.
// CHECK-DAG: attributes [[ATTRBAR]] = { {{.*}}noinline{{.*}}optnone{{.*}} }
// CHECK-DAG: attributes [[ATTRCREATED]] = { {{.*}}noinline{{.*}}optnone{{.*}} }
// CHECK-DAG: attributes [[ATTRMETHOD]] = { {{.*}}noinline{{.*}}optnone{{.*}} }
// CHECK-DAG: attributes [[ATTRTHRICEFLOAT]] = { {{.*}}noinline{{.*}}optnone{{.*}} }
+// CHECK-DAG: attributes [[ATTRANOTHEROPTNONE]] = { {{.*}}noinline{{.*}}optnone{{.*}} }
+// CHECK-DAG: attributes [[ATTRYETANOTHEROPTNONE]] = { {{.*}}noinline{{.*}}optnone{{.*}} }
// Check that the other functions do NOT have optnone.
// CHECK-DAG-NOT: attributes [[ATTRFOO]] = { {{.*}}optnone{{.*}} }
// CHECK-DAG-NOT: attributes [[ATTRBAZ]] = { {{.*}}optnone{{.*}} }
+// CHECK-DAG-NOT: attributes [[ATTRBAX]] = { {{.*}}optnone{{.*}} }
// CHECK-DAG-NOT: attributes [[ATTRWOMBAT]] = { {{.*}}optnone{{.*}} }
// CHECK-DAG-NOT: attributes [[ATTRCONTAINER]] = { {{.*}}optnone{{.*}} }
// CHECK-DAG-NOT: attributes [[ATTRTWICE]] = { {{.*}}optnone{{.*}} }
// CHECK-DAG-NOT: attributes [[ATTRCONTAINER2]] = { {{.*}}optnone{{.*}} }
// CHECK-DAG-NOT: attributes [[ATTRCONTAINER3]] = { {{.*}}optnone{{.*}} }
// CHECK-DAG-NOT: attributes [[ATTRTHRICEINT]] = { {{.*}}optnone{{.*}} }
+// CHECK-DAG-NOT: attributes [[ATTRANOTHERNORMAL]] = { {{.*}}optnone{{.*}} }
+// CHECK-DAG-NOT: attributes [[ATTRYETANOTHERNORMAL]] = { {{.*}}optnone{{.*}} }
diff --git a/test/SemaCXX/predefined-expr.cpp b/test/SemaCXX/predefined-expr.cpp
index 257d44c60069..f4a155da6678 100644
--- a/test/SemaCXX/predefined-expr.cpp
+++ b/test/SemaCXX/predefined-expr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++1y -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++ -std=c++1y -fblocks -fsyntax-only -triple %itanium_abi_triple -verify %s
// PR16946
// expected-no-diagnostics
@@ -33,10 +33,9 @@ int baz() {
();
^{
- // FIXME: This is obviously wrong.
- static_assert(sizeof(__func__) == 1, "__baz_block_invoke");
- static_assert(sizeof(__FUNCTION__) == 1, "__baz_block_invoke");
- static_assert(sizeof(__PRETTY_FUNCTION__) == 1, "__baz_block_invoke");
+ static_assert(sizeof(__func__) == 27, "___Z3bazIiEiv_block_invoke");
+ static_assert(sizeof(__FUNCTION__) == 27, "___Z3bazIiEiv_block_invoke");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 27, "___Z3bazIiEiv_block_invoke");
}
();
@@ -65,10 +64,9 @@ int main() {
();
^{
- // FIXME: This is obviously wrong.
- static_assert(sizeof(__func__) == 1, "__main_block_invoke");
- static_assert(sizeof(__FUNCTION__) == 1, "__main_block_invoke");
- static_assert(sizeof(__PRETTY_FUNCTION__) == 1, "__main_block_invoke");
+ static_assert(sizeof(__func__) == 20, "__main_block_invoke");
+ static_assert(sizeof(__FUNCTION__) == 20, "__main_block_invoke");
+ static_assert(sizeof(__PRETTY_FUNCTION__) == 20, "__main_block_invoke");
}
();
diff --git a/test/SemaCXX/return-noreturn.cpp b/test/SemaCXX/return-noreturn.cpp
index 531dc23995d2..cdd96e6a9ec4 100644
--- a/test/SemaCXX/return-noreturn.cpp
+++ b/test/SemaCXX/return-noreturn.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-covered-switch-default
-// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-covered-switch-default
+// RUN: %clang_cc1 %s -fsyntax-only -fcxx-exceptions -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-covered-switch-default
+// RUN: %clang_cc1 %s -fsyntax-only -fcxx-exceptions -std=c++11 -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-covered-switch-default
// A destructor may be marked noreturn and should still influence the CFG.
void pr6884_abort() __attribute__((noreturn));
@@ -143,7 +143,84 @@ template <PR9412_MatchType type> int PR9412_t() {
} // expected-warning {{control reaches end of non-void function}}
void PR9412_f() {
- PR9412_t<PR9412_Exact>(); // expected-note {{in instantiation of function template specialization 'PR9412_t<0>' requested here}}
+ PR9412_t<PR9412_Exact>(); // expected-note {{in instantiation of function template specialization 'PR9412_t<PR9412_MatchType::PR9412_Exact>' requested here}}
+}
+
+struct NoReturn {
+ ~NoReturn() __attribute__((noreturn));
+ operator bool() const;
+};
+struct Return {
+ ~Return();
+ operator bool() const;
+};
+
+int testTernaryUnconditionalNoreturn() {
+ true ? NoReturn() : NoReturn();
+}
+
+int testTernaryStaticallyConditionalNoretrunOnTrue() {
+ true ? NoReturn() : Return();
+}
+
+int testTernaryStaticallyConditionalRetrunOnTrue() {
+ true ? Return() : NoReturn();
+} // expected-warning {{control reaches end of non-void function}}
+
+int testTernaryStaticallyConditionalNoretrunOnFalse() {
+ false ? Return() : NoReturn();
+}
+
+int testTernaryStaticallyConditionalRetrunOnFalse() {
+ false ? NoReturn() : Return();
+} // expected-warning {{control reaches end of non-void function}}
+
+int testTernaryConditionalNoreturnTrueBranch(bool value) {
+ value ? (NoReturn() || NoReturn()) : Return();
+} // expected-warning {{control may reach end of non-void function}}
+
+int testTernaryConditionalNoreturnFalseBranch(bool value) {
+ value ? Return() : (NoReturn() || NoReturn());
+} // expected-warning {{control may reach end of non-void function}}
+
+int testConditionallyExecutedComplexTernaryTrueBranch(bool value) {
+ value || (true ? NoReturn() : true);
+} // expected-warning {{control may reach end of non-void function}}
+
+int testConditionallyExecutedComplexTernaryFalseBranch(bool value) {
+ value || (false ? true : NoReturn());
+} // expected-warning {{control may reach end of non-void function}}
+
+int testStaticallyExecutedLogicalOrBranch() {
+ false || NoReturn();
+}
+
+int testStaticallyExecutedLogicalAndBranch() {
+ true && NoReturn();
+}
+
+int testStaticallySkippedLogicalOrBranch() {
+ true || NoReturn();
+} // expected-warning {{control reaches end of non-void function}}
+
+int testStaticallySkppedLogicalAndBranch() {
+ false && NoReturn();
+} // expected-warning {{control reaches end of non-void function}}
+
+int testConditionallyExecutedComplexLogicalBranch(bool value) {
+ value || (true && NoReturn());
+} // expected-warning {{control may reach end of non-void function}}
+
+int testConditionallyExecutedComplexLogicalBranch2(bool value) {
+ (true && value) || (true && NoReturn());
+} // expected-warning {{control may reach end of non-void function}}
+
+int testConditionallyExecutedComplexLogicalBranch3(bool value) {
+ (false && (Return() || true)) || (true && NoReturn());
+}
+
+int testConditionallyExecutedComplexLogicalBranch4(bool value) {
+ false || ((Return() || true) && (true && NoReturn()));
}
#if __cplusplus >= 201103L
@@ -168,3 +245,20 @@ namespace LambdaVsTemporaryDtor {
} // ok, initialization of lambda does not return
}
#endif
+
+// Ensure that function-try-blocks also check for return values properly.
+int functionTryBlock1(int s) try {
+ return 0;
+} catch (...) {
+} // expected-warning {{control may reach end of non-void function}}
+
+int functionTryBlock2(int s) try {
+} catch (...) {
+ return 0;
+} // expected-warning {{control may reach end of non-void function}}
+
+int functionTryBlock3(int s) try {
+ return 0;
+} catch (...) {
+ return 0;
+} // ok, both paths return.
diff --git a/test/SemaCXX/return.cpp b/test/SemaCXX/return.cpp
index 98dbd51f5806..8c1664516a71 100644
--- a/test/SemaCXX/return.cpp
+++ b/test/SemaCXX/return.cpp
@@ -112,3 +112,11 @@ namespace ctor_returns_void {
~S() { return f(); } // expected-error {{destructor '~S' must not return void expression}}
};
}
+
+void cxx_unresolved_expr() {
+ // The use of an undeclared variable tricks clang into building a
+ // CXXUnresolvedConstructExpr, and the missing ')' gives it an invalid source
+ // location for its rparen. Check that emitting a diag on the range of the
+ // expr doesn't assert.
+ return int(undeclared, 4; // expected-error {{expected ')'}} expected-note{{to match this '('}} expected-error {{void function 'cxx_unresolved_expr' should not return a value}} expected-error {{use of undeclared identifier 'undeclared'}}
+}
diff --git a/test/SemaCXX/runtimediag-ppe.cpp b/test/SemaCXX/runtimediag-ppe.cpp
index 0e8451b472e7..2788963b6c1b 100644
--- a/test/SemaCXX/runtimediag-ppe.cpp
+++ b/test/SemaCXX/runtimediag-ppe.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-value %s
// Make sure diagnostics that we don't print based on runtime control
// flow are delayed correctly in cases where we can't immediately tell whether
diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp
index dc15dc8b3e60..ac700999c284 100644
--- a/test/SemaCXX/scope-check.cpp
+++ b/test/SemaCXX/scope-check.cpp
@@ -32,7 +32,7 @@ namespace test1 {
int f(bool b) {
if (b)
- goto foo; // expected-error {{goto into protected scope}}
+ goto foo; // expected-error {{cannot jump}}
C c; // expected-note {{jump bypasses variable initialization}}
foo:
return 1;
@@ -79,7 +79,7 @@ namespace test4 {
C c0;
- goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+ goto *ip; // expected-error {{cannot jump}}
C c1; // expected-note {{jump bypasses variable initialization}}
lbl1: // expected-note {{possible target of indirect goto}}
return 0;
@@ -103,7 +103,7 @@ namespace test5 {
if (ip[1]) {
D d; // expected-note {{jump exits scope of variable with non-trivial destructor}}
ip += 2;
- goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+ goto *ip; // expected-error {{cannot jump}}
}
return 1;
}
@@ -153,13 +153,13 @@ namespace test8 {
switch (c) {
case 0:
int x = 56; // expected-note {{jump bypasses variable initialization}}
- case 1: // expected-error {{switch case is in protected scope}}
+ case 1: // expected-error {{cannot jump}}
x = 10;
}
}
void test2() {
- goto l2; // expected-error {{goto into protected scope}}
+ goto l2; // expected-error {{cannot jump}}
l1: int x = 5; // expected-note {{jump bypasses variable initialization}}
l2: x++;
}
@@ -208,7 +208,7 @@ namespace PR10462 {
namespace test10 {
int test() {
static void *ps[] = { &&a0 };
- goto *&&a0; // expected-error {{goto into protected scope}}
+ goto *&&a0; // expected-error {{cannot jump}}
int a = 3; // expected-note {{jump bypasses variable initialization}}
a0:
return 0;
@@ -225,7 +225,7 @@ namespace test11 {
static void *ips[] = { &&l0 };
l0: // expected-note {{possible target of indirect goto}}
C c0 = 42; // expected-note {{jump exits scope of variable with non-trivial destructor}}
- goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+ goto *ip; // expected-error {{cannot jump}}
}
}
@@ -240,7 +240,7 @@ namespace test12 {
l0: // expected-note {{possible target of indirect goto}}
const C &c1 = 42; // expected-note {{jump exits scope of lifetime-extended temporary with non-trivial destructor}}
const C &c2 = c0;
- goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+ goto *ip; // expected-error {{cannot jump}}
}
}
@@ -254,7 +254,7 @@ namespace test13 {
static void *ips[] = { &&l0 };
l0: // expected-note {{possible target of indirect goto}}
const int &c1 = C(1).i; // expected-note {{jump exits scope of lifetime-extended temporary with non-trivial destructor}}
- goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+ goto *ip; // expected-error {{cannot jump}}
}
}
@@ -276,21 +276,21 @@ namespace test14 {
// PR14225
namespace test15 {
void f1() try {
- goto x; // expected-error {{goto into protected scope}}
+ goto x; // expected-error {{cannot jump}}
} catch(...) { // expected-note {{jump bypasses initialization of catch block}}
x: ;
}
void f2() try { // expected-note {{jump bypasses initialization of try block}}
x: ;
} catch(...) {
- goto x; // expected-error {{goto into protected scope}}
+ goto x; // expected-error {{cannot jump}}
}
}
namespace test16 {
struct S { int n; };
int f() {
- goto x; // expected-error {{goto into protected scope}}
+ goto x; // expected-error {{cannot jump}}
const S &s = S(); // expected-note {{jump bypasses variable initialization}}
x: return s.n;
}
@@ -300,7 +300,7 @@ x: return s.n;
namespace test17 {
struct S { int get(); private: int n; };
int f() {
- goto x; // expected-error {{goto into protected scope}}
+ goto x; // expected-error {{cannot jump}}
S s = {}; // expected-note {{jump bypasses variable initialization}}
x: return s.get();
}
@@ -321,7 +321,7 @@ namespace test18 {
void *p = &&x;
x: // expected-note {{possible target of indirect goto}}
B b = { 0, A() }; // expected-note {{jump exits scope of lifetime-extended temporary with non-trivial destructor}}
- goto *p; // expected-error {{indirect goto might cross protected scopes}}
+ goto *p; // expected-error {{cannot jump}}
}
}
@@ -342,7 +342,7 @@ namespace test19 {
A a;
x: // expected-note {{possible target of indirect goto}}
std::initializer_list<A> il = { a }; // expected-note {{jump exits scope of lifetime-extended temporary with non-trivial destructor}}
- goto *p; // expected-error {{indirect goto might cross protected scopes}}
+ goto *p; // expected-error {{cannot jump}}
}
}
@@ -370,14 +370,14 @@ namespace test20 {
a,
{ A() } // expected-note {{jump exits scope of lifetime-extended temporary with non-trivial destructor}}
};
- goto *p; // expected-error {{indirect goto might cross protected scopes}}
+ goto *p; // expected-error {{cannot jump}}
}
}
#endif
namespace test21 {
template<typename T> void f() {
- goto x; // expected-error {{protected scope}}
+ goto x; // expected-error {{cannot jump}}
T t; // expected-note {{bypasses}}
x: return;
}
@@ -428,7 +428,7 @@ namespace test_recovery {
void test(nexist, int c) { // expected-error {{}}
nexist_fn(); // expected-error {{}}
goto nexist_label; // expected-error {{use of undeclared label}}
- goto a0; // expected-error {{goto into protected scope}}
+ goto a0; // expected-error {{cannot jump}}
int a = 0; // expected-note {{jump bypasses variable initialization}}
a0:;
@@ -436,7 +436,7 @@ namespace test_recovery {
case $: // expected-error {{}}
case 0:
int x = 56; // expected-note {{jump bypasses variable initialization}}
- case 1: // expected-error {{switch case is in protected scope}}
+ case 1: // expected-error {{cannot jump}}
x = 10;
}
}
diff --git a/test/SemaCXX/statements.cpp b/test/SemaCXX/statements.cpp
index 6d04c84a6752..15b0b50ddc75 100644
--- a/test/SemaCXX/statements.cpp
+++ b/test/SemaCXX/statements.cpp
@@ -10,7 +10,7 @@ struct X {
};
void test2() {
- goto later; // expected-error {{goto into protected scope}}
+ goto later; // expected-error {{cannot jump}}
X x; // expected-note {{jump bypasses variable initialization}}
later:
;
@@ -20,3 +20,20 @@ namespace PR6536 {
struct A {};
void a() { goto out; A x; out: return; }
}
+
+void test3() {
+ __asm__ ("":"+r" (test3)); // expected-error{{invalid lvalue in asm output}}
+}
+
+void test4(); // expected-note{{possible target for call}}
+void test4(int) { // expected-note{{possible target for call}}
+ // expected-error@+1{{overloaded function could not be resolved}}
+ __asm__ ("":"+r" (test4)); // expected-error{{invalid lvalue in asm output}}
+}
+void test5() {
+ char buf[1];
+ __asm__ ("":"+r" (buf));
+}
+
+struct MMX_t {};
+void test6() { __asm__("" : "=m"(*(MMX_t *)0)); }
diff --git a/test/SemaCXX/string-plus-int.cpp b/test/SemaCXX/string-plus-int.cpp
index 5752f8f96631..fe9c71949698 100644
--- a/test/SemaCXX/string-plus-int.cpp
+++ b/test/SemaCXX/string-plus-int.cpp
@@ -64,3 +64,8 @@ void f(int index) {
consume(A B + sizeof(A) - 1);
}
+template <typename T>
+void PR21848() {
+ (void)(sizeof(T) + ""); // expected-warning {{to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
+}
+template void PR21848<int>(); // expected-note {{in instantiation of function template specialization 'PR21848<int>' requested here}}
diff --git a/test/SemaCXX/struct-class-redecl.cpp b/test/SemaCXX/struct-class-redecl.cpp
index e1b95ba8d63c..706ec5688ba5 100644
--- a/test/SemaCXX/struct-class-redecl.cpp
+++ b/test/SemaCXX/struct-class-redecl.cpp
@@ -7,6 +7,12 @@ union X { int x; float y; }; // expected-error{{use of 'X' with tag type that do
template<typename T> struct Y; // expected-note{{did you mean class here?}}
template<class U> class Y { }; // expected-warning{{previously declared}}
+template <typename>
+struct Z { // expected-note{{previous definition is here}}
+ struct Z { // expected-error{{nested redefinition of 'Z'}}
+ };
+};
+
class A;
class A; // expected-note{{previous use is here}}
struct A; // expected-warning{{struct 'A' was previously declared as a class}}
diff --git a/test/SemaCXX/trailing-return-0x.cpp b/test/SemaCXX/trailing-return-0x.cpp
index cf5e659660eb..c6b22c54be0c 100644
--- a/test/SemaCXX/trailing-return-0x.cpp
+++ b/test/SemaCXX/trailing-return-0x.cpp
@@ -17,8 +17,8 @@ auto f() -> int
return 0;
}
-auto g(); // expected-error{{return without trailing return type; deduced return types are a C++1y extension}}
-decltype(auto) g2(); // expected-warning{{extension}} expected-error-re{{{{^}}deduced return types are a C++1y extension}}
+auto g(); // expected-error{{return without trailing return type; deduced return types are a C++14 extension}}
+decltype(auto) g2(); // expected-warning{{extension}} expected-error-re{{{{^}}deduced return types are a C++14 extension}}
auto badness = g2();
int h() -> int; // expected-error{{trailing return type must specify return type 'auto', not 'int'}}
@@ -75,14 +75,14 @@ only<double> p4 = xx.get_nested<double>().h(0L, 1.0, 3.14f);
namespace PR12053 {
template <typename T>
auto f1(T t) -> decltype(f1(t)) {} // expected-note{{candidate template ignored}}
-
+
void test_f1() {
f1(0); // expected-error{{no matching function for call to 'f1'}}
}
-
+
template <typename T>
auto f2(T t) -> decltype(f2(&t)) {} // expected-note{{candidate template ignored}}
-
+
void test_f2() {
f2(0); // expected-error{{no matching function for call to 'f2'}}
}
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index 3b94ef0951eb..4833c14b30be 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -146,6 +146,10 @@ struct ThreeArgCtor {
ThreeArgCtor(int*, char*, int);
};
+struct VariadicCtor {
+ template<typename...T> VariadicCtor(T...);
+};
+
void is_pod()
{
{ int arr[T(__is_pod(int))]; }
@@ -1968,6 +1972,10 @@ void constructible_checks() {
// PR19178
{ int arr[F(__is_constructible(Abstract))]; }
{ int arr[F(__is_nothrow_constructible(Abstract))]; }
+
+ // PR20228
+ { int arr[T(__is_constructible(VariadicCtor,
+ int, int, int, int, int, int, int, int, int))]; }
}
// Instantiation of __is_trivially_constructible
diff --git a/test/SemaCXX/typeid.cpp b/test/SemaCXX/typeid.cpp
index d3a2a28deb8b..48fcce0b4924 100644
--- a/test/SemaCXX/typeid.cpp
+++ b/test/SemaCXX/typeid.cpp
@@ -21,3 +21,9 @@ void g1(X &x) {
(void)typeid(X&); // expected-error{{'typeid' of incomplete type 'X'}}
(void)typeid(x); // expected-error{{'typeid' of incomplete type 'X'}}
}
+
+void h(int i) {
+ char V[i];
+ typeid(V); // expected-error{{'typeid' of variably modified type 'char [i]'}}
+ typeid(char [i]); // expected-error{{'typeid' of variably modified type 'char [i]'}}
+}
diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp
new file mode 100644
index 000000000000..e028faad2510
--- /dev/null
+++ b/test/SemaCXX/typo-correction-delayed.cpp
@@ -0,0 +1,159 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s
+
+struct A {};
+struct B {};
+struct D {
+ A fizbin; // expected-note 2 {{declared here}}
+ A foobar; // expected-note 2 {{declared here}}
+ B roxbin; // expected-note 2 {{declared here}}
+ B toobad; // expected-note 2 {{declared here}}
+ void BooHoo();
+ void FoxBox();
+};
+
+void something(A, B);
+void test() {
+ D obj;
+ something(obj.fixbin, // expected-error {{did you mean 'fizbin'?}}
+ obj.toobat); // expected-error {{did you mean 'toobad'?}}
+ something(obj.toobat, // expected-error {{did you mean 'foobar'?}}
+ obj.fixbin); // expected-error {{did you mean 'roxbin'?}}
+ something(obj.fixbin, // expected-error {{did you mean 'fizbin'?}}
+ obj.fixbin); // expected-error {{did you mean 'roxbin'?}}
+ something(obj.toobat, // expected-error {{did you mean 'foobar'?}}
+ obj.toobat); // expected-error {{did you mean 'toobad'?}}
+ // Both members could be corrected to methods, but that isn't valid.
+ something(obj.boohoo, // expected-error-re {{no member named 'boohoo' in 'D'{{$}}}}
+ obj.foxbox); // expected-error-re {{no member named 'foxbox' in 'D'{{$}}}}
+ // The first argument has a usable correction but the second doesn't.
+ something(obj.boobar, // expected-error-re {{no member named 'boobar' in 'D'{{$}}}}
+ obj.foxbox); // expected-error-re {{no member named 'foxbox' in 'D'{{$}}}}
+}
+
+// Ensure the delayed typo correction does the right thing when trying to
+// recover using a seemingly-valid correction for which a valid expression to
+// replace the TypoExpr cannot be created (but which does have a second
+// correction candidate that would be a valid and usable correction).
+class Foo {
+public:
+ template <> void testIt(); // expected-error {{no function template matches}}
+ void textIt(); // expected-note {{'textIt' declared here}}
+};
+void testMemberExpr(Foo *f) {
+ f->TestIt(); // expected-error {{no member named 'TestIt' in 'Foo'; did you mean 'textIt'?}}
+}
+
+void callee(double, double);
+void testNoCandidates() {
+ callee(xxxxxx, // expected-error-re {{use of undeclared identifier 'xxxxxx'{{$}}}}
+ zzzzzz); // expected-error-re {{use of undeclared identifier 'zzzzzz'{{$}}}}
+}
+
+class string {};
+struct Item {
+ void Nest();
+ string text();
+ Item* next(); // expected-note {{'next' declared here}}
+};
+void testExprFilter(Item *i) {
+ Item *j;
+ j = i->Next(); // expected-error {{no member named 'Next' in 'Item'; did you mean 'next'?}}
+}
+
+// Test that initializer expressions are handled correctly and that the type
+// being initialized is taken into account when choosing a correction.
+namespace initializerCorrections {
+struct Node {
+ string text() const;
+ // Node* Next() is not implemented yet
+};
+void f(Node *node) {
+ // text is only an edit distance of 1 from Next, but would trigger type
+ // conversion errors if used in this initialization expression.
+ Node *next = node->Next(); // expected-error-re {{no member named 'Next' in 'initializerCorrections::Node'{{$}}}}
+}
+
+struct LinkedNode {
+ LinkedNode* next(); // expected-note {{'next' declared here}}
+ string text() const;
+};
+void f(LinkedNode *node) {
+ // text and next are equidistant from Next, but only one results in a valid
+ // initialization expression.
+ LinkedNode *next = node->Next(); // expected-error {{no member named 'Next' in 'initializerCorrections::LinkedNode'; did you mean 'next'?}}
+}
+
+struct NestedNode {
+ NestedNode* Nest();
+ NestedNode* next();
+ string text() const;
+};
+void f(NestedNode *node) {
+ // There are two equidistant, usable corrections for Next: next and Nest
+ NestedNode *next = node->Next(); // expected-error-re {{no member named 'Next' in 'initializerCorrections::NestedNode'{{$}}}}
+}
+}
+
+namespace PR21669 {
+void f(int *i) {
+ // Check that arguments to a builtin with custom type checking are corrected
+ // properly, since calls to such builtins bypass much of the normal code path
+ // for building and checking the call.
+ __atomic_load(i, i, something_something); // expected-error-re {{use of undeclared identifier 'something_something'{{$}}}}
+}
+}
+
+const int DefaultArg = 9; // expected-note {{'DefaultArg' declared here}}
+template <int I = defaultArg> struct S {}; // expected-error {{use of undeclared identifier 'defaultArg'; did you mean 'DefaultArg'?}}
+S<1> s;
+
+namespace foo {}
+void test_paren_suffix() {
+ foo::bar({5, 6}); // expected-error-re {{no member named 'bar' in namespace 'foo'{{$}}}} \
+ // expected-error {{expected expression}}
+}
+
+const int kNum = 10; // expected-note {{'kNum' declared here}}
+class SomeClass {
+ int Kind;
+public:
+ explicit SomeClass() : Kind(kSum) {} // expected-error {{use of undeclared identifier 'kSum'; did you mean 'kNum'?}}
+};
+
+// There used to be an issue with typo resolution inside overloads.
+struct AssertionResult { ~AssertionResult(); };
+AssertionResult Overload(const char *a);
+AssertionResult Overload(int a);
+void UseOverload() {
+ // expected-note@+1 {{'result' declared here}}
+ const char *result;
+ // expected-error@+1 {{use of undeclared identifier 'resulta'; did you mean 'result'?}}
+ Overload(resulta);
+}
+
+namespace PR21925 {
+struct X {
+ int get() { return 7; } // expected-note {{'get' declared here}}
+};
+void test() {
+ X variable; // expected-note {{'variable' declared here}}
+
+ // expected-error@+2 {{use of undeclared identifier 'variableX'; did you mean 'variable'?}}
+ // expected-error@+1 {{no member named 'getX' in 'PR21925::X'; did you mean 'get'?}}
+ int x = variableX.getX();
+}
+}
+
+namespace PR21905 {
+int (*a) () = (void)Z; // expected-error-re {{use of undeclared identifier 'Z'{{$}}}}
+}
+
+namespace PR21947 {
+int blue; // expected-note {{'blue' declared here}}
+__typeof blur y; // expected-error {{use of undeclared identifier 'blur'; did you mean 'blue'?}}
+}
+
+namespace PR22092 {
+a = b ? : 0; // expected-error {{C++ requires a type specifier for all declarations}} \
+ // expected-error-re {{use of undeclared identifier 'b'{{$}}}}
+}
diff --git a/test/SemaCXX/typo-correction-pt2.cpp b/test/SemaCXX/typo-correction-pt2.cpp
deleted file mode 100644
index 88a7073f9946..000000000000
--- a/test/SemaCXX/typo-correction-pt2.cpp
+++ /dev/null
@@ -1,302 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s
-//
-// FIXME: This file is overflow from test/SemaCXX/typo-correction.cpp due to a
-// hard-coded limit of 20 different typo corrections Sema::CorrectTypo will
-// attempt within a single file (which is to avoid having very broken files take
-// minutes to finally be rejected by the parser).
-
-namespace PR12951 {
-// If there are two corrections that have the same identifier and edit distance
-// and only differ by their namespaces, don't suggest either as a correction
-// since both are equally likely corrections.
-namespace foobar { struct Thing {}; }
-namespace bazquux { struct Thing {}; }
-void f() { Thing t; } // expected-error{{unknown type name 'Thing'}}
-}
-
-namespace bogus_keyword_suggestion {
-void test() {
- status = "OK"; // expected-error-re {{use of undeclared identifier 'status'{{$}}}}
- return status; // expected-error-re {{use of undeclared identifier 'status'{{$}}}}
- }
-}
-
-namespace PR13387 {
-struct A {
- void CreateFoo(float, float);
- void CreateBar(float, float);
-};
-struct B : A {
- using A::CreateFoo;
- void CreateFoo(int, int);
-};
-void f(B &x) {
- x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}}
-}
-}
-
-struct DataStruct {void foo();};
-struct T {
- DataStruct data_struct;
- void f();
-};
-// should be void T::f();
-void f() {
- data_struct->foo(); // expected-error-re{{use of undeclared identifier 'data_struct'{{$}}}}
-}
-
-namespace PR12287 {
-class zif {
- void nab(int);
-};
-void nab(); // expected-note{{'::PR12287::nab' declared here}}
-void zif::nab(int) {
- nab(); // expected-error{{too few arguments to function call, expected 1, have 0; did you mean '::PR12287::nab'?}}
-}
-}
-
-namespace TemplateFunction {
-template <class T>
-void A(T) { } // expected-note {{'::TemplateFunction::A' declared here}}
-
-template <class T>
-void B(T) { } // expected-note {{'::TemplateFunction::B' declared here}}
-
-class Foo {
- public:
- void A(int, int) {}
- void B() {}
-};
-
-void test(Foo F, int num) {
- F.A(num); // expected-error {{too few arguments to function call, expected 2, have 1; did you mean '::TemplateFunction::A'?}}
- F.B(num); // expected-error {{too many arguments to function call, expected 0, have 1; did you mean '::TemplateFunction::B'?}}
-}
-}
-namespace using_suggestion_val_dropped_specifier {
-void FFF() {} // expected-note {{'::using_suggestion_val_dropped_specifier::FFF' declared here}}
-namespace N { }
-using N::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_specifier::N'; did you mean '::using_suggestion_val_dropped_specifier::FFF'?}}
-}
-
-namespace class_member_typo_corrections {
-class Outer {
-public:
- class Inner {}; // expected-note {{'Outer::Inner' declared here}}
- Inner MyMethod(Inner arg);
-};
-
-Inner Outer::MyMethod(Inner arg) { // expected-error {{unknown type name 'Inner'; did you mean 'Outer::Inner'?}}
- return Inner();
-}
-
-class Result {
-public:
- enum ResultType {
- ENTITY, // expected-note {{'Result::ENTITY' declared here}}
- PREDICATE, // expected-note {{'Result::PREDICATE' declared here}}
- LITERAL // expected-note {{'Result::LITERAL' declared here}}
- };
-
- ResultType type();
-};
-
-void test() {
- Result result_cell;
- switch (result_cell.type()) {
- case ENTITY: // expected-error {{use of undeclared identifier 'ENTITY'; did you mean 'Result::ENTITY'?}}
- case LITERAL: // expected-error {{use of undeclared identifier 'LITERAL'; did you mean 'Result::LITERAL'?}}
- case PREDICAT: // expected-error {{use of undeclared identifier 'PREDICAT'; did you mean 'Result::PREDICATE'?}}
- break;
- }
-}
-
-class Figure {
- enum ResultType {
- SQUARE,
- TRIANGLE,
- CIRCLE
- };
-
-public:
- ResultType type();
-};
-
-void testAccess() {
- Figure obj;
- switch (obj.type()) { // expected-warning {{enumeration values 'SQUARE', 'TRIANGLE', and 'CIRCLE' not handled in switch}}
- case SQUARE: // expected-error-re {{use of undeclared identifier 'SQUARE'{{$}}}}
- case TRIANGLE: // expected-error-re {{use of undeclared identifier 'TRIANGLE'{{$}}}}
- case CIRCE: // expected-error-re {{use of undeclared identifier 'CIRCE'{{$}}}}
- break;
- }
-}
-}
-
-long readline(const char *, char *, unsigned long);
-void assign_to_unknown_var() {
- deadline_ = 1; // expected-error-re {{use of undeclared identifier 'deadline_'{{$}}}}
-}
-
-namespace no_ns_before_dot {
-namespace re2 {}
-void test() {
- req.set_check(false); // expected-error-re {{use of undeclared identifier 'req'{{$}}}}
-}
-}
-
-namespace PR17394 {
- class A {
- protected:
- long zzzzzzzzzz;
- };
- class B : private A {};
- B zzzzzzzzzy<>; // expected-error {{expected ';' after top level declarator}}{}
-}
-
-namespace correct_fields_in_member_funcs {
-struct S {
- int my_member; // expected-note {{'my_member' declared here}}
- void f() { my_menber = 1; } // expected-error {{use of undeclared identifier 'my_menber'; did you mean 'my_member'?}}
-};
-}
-
-namespace PR17019 {
- template<class F>
- struct evil {
- evil(F de) { // expected-note {{'de' declared here}}
- de_; // expected-error {{use of undeclared identifier 'de_'; did you mean 'de'?}} \
- // expected-warning {{expression result unused}}
- }
- ~evil() {
- de_->bar() // expected-error {{use of undeclared identifier 'de_'}}
- }
- };
-
- void meow() {
- evil<int> Q(0); // expected-note {{in instantiation of member function}}
- }
-}
-
-namespace fix_class_name_qualifier {
-class MessageHeaders {};
-class MessageUtils {
- public:
- static void ParseMessageHeaders(int, int); // expected-note {{'MessageUtils::ParseMessageHeaders' declared here}}
-};
-
-void test() {
- // No, we didn't mean to call MessageHeaders::MessageHeaders.
- MessageHeaders::ParseMessageHeaders(5, 4); // expected-error {{no member named 'ParseMessageHeaders' in 'fix_class_name_qualifier::MessageHeaders'; did you mean 'MessageUtils::ParseMessageHeaders'?}}
-}
-}
-
-namespace PR18213 { // expected-note {{'PR18213' declared here}}
-struct WrapperInfo {
- int i;
-};
-
-template <typename T> struct Wrappable {
- static WrapperInfo kWrapperInfo;
-};
-
-// Note the space before "::PR18213" is intended and needed, as it highlights
-// the actual typo, which is the leading "::".
-// TODO: Suggest removing the "::" from "::PR18213" (the right correction)
-// instead of incorrectly suggesting dropping "PR18213::WrapperInfo::".
-template <>
-PR18213::WrapperInfo ::PR18213::Wrappable<int>::kWrapperInfo = { 0 }; // expected-error {{no member named 'PR18213' in 'PR18213::WrapperInfo'; did you mean simply 'PR18213'?}} \
- // expected-error {{C++ requires a type specifier for all declarations}}
-}
-
-namespace PR18651 {
-struct {
- int x;
-} a, b;
-
-int y = x; // expected-error-re {{use of undeclared identifier 'x'{{$}}}}
-}
-
-namespace PR18685 {
-template <class C, int I, int J>
-class SetVector {
- public:
- SetVector() {}
-};
-
-template <class C, int I>
-class SmallSetVector : public SetVector<C, I, 8> {};
-
-class foo {};
-SmallSetVector<foo*, 2> fooSet;
-}
-
-PR18685::BitVector Map; // expected-error-re {{no type named 'BitVector' in namespace 'PR18685'{{$}}}}
-
-namespace shadowed_template {
-template <typename T> class Fizbin {}; // expected-note {{'::shadowed_template::Fizbin' declared here}}
-class Baz {
- int Fizbin();
- // TODO: Teach the parser to recover from the typo correction instead of
- // continuing to treat the template name as an implicit-int declaration.
- Fizbin<int> qux; // expected-error {{unknown type name 'Fizbin'; did you mean '::shadowed_template::Fizbin'?}} \
- // expected-error {{expected member name or ';' after declaration specifiers}}
-};
-}
-
-namespace PR18852 {
-void func() {
- struct foo {
- void bar() {}
- };
- bar(); // expected-error-re {{use of undeclared identifier 'bar'{{$}}}}
-}
-
-class Thread {
- public:
- void Start();
- static void Stop(); // expected-note {{'Thread::Stop' declared here}}
-};
-
-class Manager {
- public:
- void Start(int); // expected-note {{'Start' declared here}}
- void Stop(int); // expected-note {{'Stop' declared here}}
-};
-
-void test(Manager *m) {
- // Don't suggest Thread::Start as a correction just because it has the same
- // (unqualified) name and accepts the right number of args; this is a method
- // call on an object in an unrelated class.
- m->Start(); // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}}
- m->Stop(); // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}}
- Stop(); // expected-error {{use of undeclared identifier 'Stop'; did you mean 'Thread::Stop'?}}
-}
-
-}
-
-namespace std {
-class bernoulli_distribution {
- public:
- double p() const;
-};
-}
-void test() {
- // Make sure that typo correction doesn't suggest changing 'p' to
- // 'std::bernoulli_distribution::p' as that is most likely wrong.
- if (p) // expected-error-re {{use of undeclared identifier 'p'{{$}}}}
- return;
-}
-
-namespace PR19681 {
- struct TypoA {};
- struct TypoB {
- void test();
- private:
- template<typename T> void private_memfn(T); // expected-note{{declared here}}
- };
- void TypoB::test() {
- // FIXME: should suggest 'PR19681::TypoB::private_memfn' instead of '::PR19681::TypoB::private_memfn'
- (void)static_cast<void(TypoB::*)(int)>(&TypoA::private_memfn); // expected-error{{no member named 'private_memfn' in 'PR19681::TypoA'; did you mean '::PR19681::TypoB::private_memfn'?}}
- }
-}
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index e8160b066de4..324900150c7f 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -1,8 +1,9 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s
-//
-// WARNING: Do not add more typo correction test cases to this file lest you run
-// afoul the hard-coded limit (escape hatch) of 20 different typos whose
-// correction was attempted by Sema::CorrectTypo
+// RUN: %clang_cc1 -fspell-checking-limit 0 -verify -Wno-c++11-extensions %s
+
+namespace PR21817{
+int a(-rsing[2]); // expected-error {{undeclared identifier 'rsing'; did you mean 'using'?}}
+ // expected-error@-1 {{expected expression}}
+}
struct errc {
int v_;
@@ -97,7 +98,7 @@ unknown_type_test::stream_out out; // expected-error{{no type named 'stream_out'
// Demonstrate a case where using only the cached value returns the wrong thing
// when the cached value was the result of a previous callback object that only
// accepts a subset of the current callback object.
-namespace {
+namespace cache_invalidation_test {
using namespace unknown_type_test;
void bar(long i);
void before_caching_classname() {
@@ -209,11 +210,12 @@ namespace PR13051 {
};
void foo(); // expected-note{{'foo' declared here}}
- void g(void(*)());
- void g(bool(S<int>::*)() const);
+ void g(void(*)()); // expected-note{{candidate function not viable}}
+ void g(bool(S<int>::*)() const); // expected-note{{candidate function not viable}}
void test() {
- g(&S<int>::tempalte f<int>); // expected-error{{did you mean 'template'?}}
+ g(&S<int>::tempalte f<int>); // expected-error{{did you mean 'template'?}} \
+ // expected-error{{no matching function for call to 'g'}}
g(&S<int>::opeartor bool); // expected-error{{did you mean 'operator'?}}
g(&S<int>::foo); // expected-error{{no member named 'foo' in 'PR13051::S<int>'; did you mean simply 'foo'?}}
}
@@ -247,7 +249,7 @@ namespace b6956809_test1 {
struct S1 {
void method(A*); // no note here
- void method(B*);
+ void method(B*); // expected-note{{'method' declared here}}
};
void test1() {
@@ -258,15 +260,15 @@ namespace b6956809_test1 {
struct S2 {
S2();
- void method(A*) const; // expected-note{{candidate function not viable}}
+ void method(A*) const;
private:
- void method(B*); // expected-note{{candidate function not viable}}
+ void method(B*);
};
void test2() {
B b;
const S2 s;
- s.methodd(&b); // expected-error{{no member named 'methodd' in 'b6956809_test1::S2'; did you mean 'method'}} expected-error{{no matching member function for call to 'method'}}
+ s.methodd(&b); // expected-error-re{{no member named 'methodd' in 'b6956809_test1::S2'{{$}}}}
}
}
@@ -274,7 +276,7 @@ namespace b6956809_test2 {
template<typename T> struct Err { typename T::error n; }; // expected-error{{type 'void *' cannot be used prior to '::' because it has no members}}
struct S {
template<typename T> typename Err<T>::type method(T); // expected-note{{in instantiation of template class 'b6956809_test2::Err<void *>' requested here}}
- template<typename T> int method(T *);
+ template<typename T> int method(T *); // expected-note{{'method' declared here}}
};
void test() {
@@ -283,13 +285,352 @@ namespace b6956809_test2 {
}
}
-// This test should have one correction, followed by an error without a
-// suggestion due to exceeding the maximum number of typos for which correction
-// is attempted.
-namespace CorrectTypo_has_reached_its_limit {
-int flibberdy(); // expected-note{{'flibberdy' declared here}}
-int no_correction() {
- return hibberdy() + // expected-error{{use of undeclared identifier 'hibberdy'; did you mean 'flibberdy'?}}
- gibberdy(); // expected-error-re{{use of undeclared identifier 'gibberdy'{{$}}}}
+namespace PR12951 {
+// If there are two corrections that have the same identifier and edit distance
+// and only differ by their namespaces, don't suggest either as a correction
+// since both are equally likely corrections.
+namespace foobar { struct Thing {}; }
+namespace bazquux { struct Thing {}; }
+void f() { Thing t; } // expected-error{{unknown type name 'Thing'}}
+}
+
+namespace bogus_keyword_suggestion {
+void test() {
+ status = "OK"; // expected-error-re {{use of undeclared identifier 'status'{{$}}}}
+ return status; // expected-error-re {{use of undeclared identifier 'status'{{$}}}}
+ }
+}
+
+namespace PR13387 {
+struct A {
+ void CreateFoo(float, float);
+ void CreateBar(float, float);
+};
+struct B : A {
+ using A::CreateFoo;
+ void CreateFoo(int, int); // expected-note {{'CreateFoo' declared here}}
+};
+void f(B &x) {
+ x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}}
+}
+}
+
+struct DataStruct {void foo();};
+struct T {
+ DataStruct data_struct;
+ void f();
+};
+// should be void T::f();
+void f() {
+ data_struct->foo(); // expected-error-re{{use of undeclared identifier 'data_struct'{{$}}}}
+}
+
+namespace PR12287 {
+class zif {
+ void nab(int);
+};
+void nab(); // expected-note{{'::PR12287::nab' declared here}}
+void zif::nab(int) {
+ nab(); // expected-error{{too few arguments to function call, expected 1, have 0; did you mean '::PR12287::nab'?}}
+}
+}
+
+namespace TemplateFunction {
+template <class T>
+void A(T) { } // expected-note {{'::TemplateFunction::A' declared here}}
+
+template <class T>
+void B(T) { } // expected-note {{'::TemplateFunction::B' declared here}}
+
+class Foo {
+ public:
+ void A(int, int) {}
+ void B() {}
+};
+
+void test(Foo F, int num) {
+ F.A(num); // expected-error {{too few arguments to function call, expected 2, have 1; did you mean '::TemplateFunction::A'?}}
+ F.B(num); // expected-error {{too many arguments to function call, expected 0, have 1; did you mean '::TemplateFunction::B'?}}
+}
+}
+namespace using_suggestion_val_dropped_specifier {
+void FFF() {} // expected-note {{'::using_suggestion_val_dropped_specifier::FFF' declared here}}
+namespace N { }
+using N::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_specifier::N'; did you mean '::using_suggestion_val_dropped_specifier::FFF'?}}
+}
+
+namespace class_member_typo_corrections {
+class Outer {
+public:
+ class Inner {}; // expected-note {{'Outer::Inner' declared here}}
+ Inner MyMethod(Inner arg);
+};
+
+Inner Outer::MyMethod(Inner arg) { // expected-error {{unknown type name 'Inner'; did you mean 'Outer::Inner'?}}
+ return Inner();
+}
+
+class Result {
+public:
+ enum ResultType {
+ ENTITY, // expected-note {{'Result::ENTITY' declared here}}
+ PREDICATE, // expected-note {{'Result::PREDICATE' declared here}}
+ LITERAL // expected-note {{'Result::LITERAL' declared here}}
+ };
+
+ ResultType type();
+};
+
+void test() {
+ Result result_cell;
+ switch (result_cell.type()) {
+ case ENTITY: // expected-error {{use of undeclared identifier 'ENTITY'; did you mean 'Result::ENTITY'?}}
+ case LITERAL: // expected-error {{use of undeclared identifier 'LITERAL'; did you mean 'Result::LITERAL'?}}
+ case PREDICAT: // expected-error {{use of undeclared identifier 'PREDICAT'; did you mean 'Result::PREDICATE'?}}
+ break;
+ }
+}
+
+class Figure {
+ enum ResultType {
+ SQUARE,
+ TRIANGLE,
+ CIRCLE
+ };
+
+public:
+ ResultType type();
+};
+
+void testAccess() {
+ Figure obj;
+ switch (obj.type()) { // expected-warning {{enumeration values 'SQUARE', 'TRIANGLE', and 'CIRCLE' not handled in switch}}
+ case SQUARE: // expected-error-re {{use of undeclared identifier 'SQUARE'{{$}}}}
+ case TRIANGLE: // expected-error-re {{use of undeclared identifier 'TRIANGLE'{{$}}}}
+ case CIRCE: // expected-error-re {{use of undeclared identifier 'CIRCE'{{$}}}}
+ break;
+ }
+}
+}
+
+long readline(const char *, char *, unsigned long);
+void assign_to_unknown_var() {
+ deadline_ = 1; // expected-error-re {{use of undeclared identifier 'deadline_'{{$}}}}
+}
+
+namespace no_ns_before_dot {
+namespace re2 {}
+void test() {
+ req.set_check(false); // expected-error-re {{use of undeclared identifier 'req'{{$}}}}
+}
+}
+
+namespace PR17394 {
+ class A {
+ protected:
+ long zzzzzzzzzz;
+ };
+ class B : private A {};
+ B zzzzzzzzzy<>; // expected-error {{expected ';' after top level declarator}}{}
+}
+
+namespace correct_fields_in_member_funcs {
+struct S {
+ int my_member; // expected-note {{'my_member' declared here}}
+ void f() { my_menber = 1; } // expected-error {{use of undeclared identifier 'my_menber'; did you mean 'my_member'?}}
+};
+}
+
+namespace PR17019 {
+ template<class F>
+ struct evil {
+ evil(F de) { // expected-note {{'de' declared here}}
+ de_; // expected-error {{use of undeclared identifier 'de_'; did you mean 'de'?}} \
+ // expected-warning {{expression result unused}}
+ }
+ ~evil() {
+ de_->bar() // expected-error {{use of undeclared identifier 'de_'}}
+ }
+ };
+
+ void meow() {
+ evil<int> Q(0); // expected-note {{in instantiation of member function}}
+ }
+}
+
+namespace fix_class_name_qualifier {
+class MessageHeaders {};
+class MessageUtils {
+ public:
+ static void ParseMessageHeaders(int, int); // expected-note {{'MessageUtils::ParseMessageHeaders' declared here}}
+};
+
+void test() {
+ // No, we didn't mean to call MessageHeaders::MessageHeaders.
+ MessageHeaders::ParseMessageHeaders(5, 4); // expected-error {{no member named 'ParseMessageHeaders' in 'fix_class_name_qualifier::MessageHeaders'; did you mean 'MessageUtils::ParseMessageHeaders'?}}
+}
+}
+
+namespace PR18213 { // expected-note {{'PR18213' declared here}}
+struct WrapperInfo {
+ int i;
+};
+
+template <typename T> struct Wrappable {
+ static WrapperInfo kWrapperInfo;
+};
+
+// Note the space before "::PR18213" is intended and needed, as it highlights
+// the actual typo, which is the leading "::".
+// TODO: Suggest removing the "::" from "::PR18213" (the right correction)
+// instead of incorrectly suggesting dropping "PR18213::WrapperInfo::".
+template <>
+PR18213::WrapperInfo ::PR18213::Wrappable<int>::kWrapperInfo = { 0 }; // expected-error {{no member named 'PR18213' in 'PR18213::WrapperInfo'; did you mean simply 'PR18213'?}} \
+ // expected-error {{C++ requires a type specifier for all declarations}}
+}
+
+namespace PR18651 {
+struct {
+ int x;
+} a, b;
+
+int y = x; // expected-error-re {{use of undeclared identifier 'x'{{$}}}}
+}
+
+namespace PR18685 {
+template <class C, int I, int J>
+class SetVector {
+ public:
+ SetVector() {}
+};
+
+template <class C, int I>
+class SmallSetVector : public SetVector<C, I, 8> {};
+
+class foo {};
+SmallSetVector<foo*, 2> fooSet;
+}
+
+PR18685::BitVector Map; // expected-error-re {{no type named 'BitVector' in namespace 'PR18685'{{$}}}}
+
+namespace shadowed_template {
+template <typename T> class Fizbin {}; // expected-note {{'::shadowed_template::Fizbin' declared here}}
+class Baz {
+ int Fizbin();
+ // TODO: Teach the parser to recover from the typo correction instead of
+ // continuing to treat the template name as an implicit-int declaration.
+ Fizbin<int> qux; // expected-error {{unknown type name 'Fizbin'; did you mean '::shadowed_template::Fizbin'?}} \
+ // expected-error {{expected member name or ';' after declaration specifiers}}
+};
+}
+
+namespace PR18852 {
+void func() {
+ struct foo {
+ void bar() {}
+ };
+ bar(); // expected-error-re {{use of undeclared identifier 'bar'{{$}}}}
+}
+
+class Thread {
+ public:
+ void Start();
+ static void Stop(); // expected-note {{'Thread::Stop' declared here}}
+};
+
+class Manager {
+ public:
+ void Start(int); // expected-note {{'Start' declared here}}
+ void Stop(int); // expected-note {{'Stop' declared here}}
+};
+
+void test(Manager *m) {
+ // Don't suggest Thread::Start as a correction just because it has the same
+ // (unqualified) name and accepts the right number of args; this is a method
+ // call on an object in an unrelated class.
+ m->Start(); // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}}
+ m->Stop(); // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}}
+ Stop(); // expected-error {{use of undeclared identifier 'Stop'; did you mean 'Thread::Stop'?}}
+}
+
+}
+
+namespace std {
+class bernoulli_distribution {
+ public:
+ double p() const;
+};
+}
+void test() {
+ // Make sure that typo correction doesn't suggest changing 'p' to
+ // 'std::bernoulli_distribution::p' as that is most likely wrong.
+ if (p) // expected-error-re {{use of undeclared identifier 'p'{{$}}}}
+ return;
+}
+
+namespace PR19681 {
+ struct TypoA {};
+ struct TypoB {
+ void test();
+ private:
+ template<typename T> void private_memfn(T); // expected-note{{declared here}}
+ };
+ void TypoB::test() {
+ // FIXME: should suggest 'PR19681::TypoB::private_memfn' instead of '::PR19681::TypoB::private_memfn'
+ (void)static_cast<void(TypoB::*)(int)>(&TypoA::private_memfn); // expected-error{{no member named 'private_memfn' in 'PR19681::TypoA'; did you mean '::PR19681::TypoB::private_memfn'?}}
+ }
+}
+
+namespace testWantFunctionLikeCasts {
+ long test(bool a) {
+ if (a)
+ return struc(5.7); // expected-error-re {{use of undeclared identifier 'struc'{{$}}}}
+ else
+ return lon(8.0); // expected-error {{use of undeclared identifier 'lon'; did you mean 'long'?}}
+ }
+}
+
+namespace testCXXDeclarationSpecifierParsing {
+namespace test {
+ struct SomeSettings {}; // expected-note {{'test::SomeSettings' declared here}}
+}
+class Test {};
+int bar() {
+ Test::SomeSettings some_settings; // expected-error {{no type named 'SomeSettings' in 'testCXXDeclarationSpecifierParsing::Test'; did you mean 'test::SomeSettings'?}}
+}
+}
+
+namespace testNonStaticMemberHandling {
+struct Foo {
+ bool usesMetadata; // expected-note {{'usesMetadata' declared here}}
+};
+int test(Foo f) {
+ if (UsesMetadata) // expected-error-re {{use of undeclared identifier 'UsesMetadata'{{$}}}}
+ return 5;
+ if (f.UsesMetadata) // expected-error {{no member named 'UsesMetadata' in 'testNonStaticMemberHandling::Foo'; did you mean 'usesMetadata'?}}
+ return 11;
+ return 0;
+}
};
+
+namespace testMemberExprDeclarationNameInfo {
+ // The AST should only have the corrected name with no mention of 'data_'.
+ void f(int);
+ struct S {
+ int data; // expected-note 2{{'data' declared here}}
+ void m_fn1() {
+ data_ // expected-error {{use of undeclared identifier 'data_'}}
+ [] = // expected-error {{expected expression}}
+ f(data_); // expected-error {{use of undeclared identifier 'data_'}}
+ }
+ };
+}
+
+namespace testArraySubscriptIndex {
+ struct S {
+ int data; // expected-note {{'data' declared here}}
+ void m_fn1() {
+ (+)[data_]; // expected-error{{expected expression}} expected-error {{use of undeclared identifier 'data_'; did you mean 'data'}}
+ }
+ };
}
diff --git a/test/SemaCXX/undefined-internal.cpp b/test/SemaCXX/undefined-internal.cpp
index f32036a025f4..0138967ef80c 100644
--- a/test/SemaCXX/undefined-internal.cpp
+++ b/test/SemaCXX/undefined-internal.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wbind-to-temporary-copy %s
// Make sure we don't produce invalid IR.
// RUN: %clang_cc1 -emit-llvm-only %s
@@ -163,7 +163,7 @@ namespace cxx11_odr_rules {
// Check that the checks work with unevaluated contexts
(void)sizeof(p(A::used1));
- (void)typeid(p(A::used1)); // xpected-note {{used here}}
+ (void)typeid(p(A::used1)); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}} xpected-note {{used here}}
// Misc other testing
a(A::unused, 1 ? A::used2 : A::used2); // xpected-note {{used here}}
diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp
index 677a141f3ec3..018b1feba96b 100644
--- a/test/SemaCXX/uninitialized.cpp
+++ b/test/SemaCXX/uninitialized.cpp
@@ -1,9 +1,22 @@
// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value -std=c++11 -verify %s
+// definitions for std::move
+namespace std {
+inline namespace foo {
+template <class T> struct remove_reference { typedef T type; };
+template <class T> struct remove_reference<T&> { typedef T type; };
+template <class T> struct remove_reference<T&&> { typedef T type; };
+
+template <class T> typename remove_reference<T>::type&& move(T&& t);
+}
+}
+
int foo(int x);
int bar(int* x);
int boo(int& x);
int far(const int& x);
+int moved(int&& x);
+int &ref(int x);
// Test self-references within initializers which are guaranteed to be
// uninitialized.
@@ -24,6 +37,20 @@ int k = __alignof__(k);
int l = k ? l : l; // expected-warning 2{{variable 'l' is uninitialized when used within its own initialization}}
int m = 1 + (k ? m : m); // expected-warning 2{{variable 'm' is uninitialized when used within its own initialization}}
int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
+int o = std::move(o); // expected-warning {{variable 'o' is uninitialized when used within its own initialization}}
+const int p = std::move(p); // expected-warning {{variable 'p' is uninitialized when used within its own initialization}}
+int q = moved(std::move(q)); // expected-warning {{variable 'q' is uninitialized when used within its own initialization}}
+int r = std::move((p ? q : (18, r))); // expected-warning {{variable 'r' is uninitialized when used within its own initialization}}
+int s = r ?: s; // expected-warning {{variable 's' is uninitialized when used within its own initialization}}
+int t = t ?: s; // expected-warning {{variable 't' is uninitialized when used within its own initialization}}
+int u = (foo(u), s); // expected-warning {{variable 'u' is uninitialized when used within its own initialization}}
+int v = (u += v); // expected-warning {{variable 'v' is uninitialized when used within its own initialization}}
+int w = (w += 10); // expected-warning {{variable 'w' is uninitialized when used within its own initialization}}
+int x = x++; // expected-warning {{variable 'x' is uninitialized when used within its own initialization}}
+int y = ((s ? (y, v) : (77, y))++, sizeof(y)); // expected-warning {{variable 'y' is uninitialized when used within its own initialization}}
+int z = ++ref(z); // expected-warning {{variable 'z' is uninitialized when used within its own initialization}}
+int aa = (ref(aa) += 10); // expected-warning {{variable 'aa' is uninitialized when used within its own initialization}}
+int bb = bb ? x : y; // expected-warning {{variable 'bb' is uninitialized when used within its own initialization}}
void test_stuff () {
int a = a; // no-warning: used to signal intended lack of initialization.
@@ -44,6 +71,21 @@ void test_stuff () {
int l = k ? l : l; // expected-warning {{variable 'l' is uninitialized when used within its own initialization}}
int m = 1 + (k ? m : m); // expected-warning {{'m' is uninitialized when used within its own initialization}}
int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
+ int o = std::move(o); // expected-warning {{variable 'o' is uninitialized when used within its own initialization}}
+ const int p = std::move(p); // expected-warning {{variable 'p' is uninitialized when used within its own initialization}}
+ int q = moved(std::move(q)); // expected-warning {{variable 'q' is uninitialized when used within its own initialization}}
+ int r = std::move((p ? q : (18, r))); // expected-warning {{variable 'r' is uninitialized when used within its own initialization}}
+ int s = r ?: s; // expected-warning {{variable 's' is uninitialized when used within its own initialization}}
+ int t = t ?: s; // expected-warning {{variable 't' is uninitialized when used within its own initialization}}
+ int u = (foo(u), s); // expected-warning {{variable 'u' is uninitialized when used within its own initialization}}
+ int v = (u += v); // expected-warning {{variable 'v' is uninitialized when used within its own initialization}}
+ int w = (w += 10); // expected-warning {{variable 'w' is uninitialized when used within its own initialization}}
+ int x = x++; // expected-warning {{variable 'x' is uninitialized when used within its own initialization}}
+ int y = ((s ? (y, v) : (77, y))++, sizeof(y)); // expected-warning {{variable 'y' is uninitialized when used within its own initialization}}
+ int z = ++ref(z); // expected-warning {{variable 'z' is uninitialized when used within its own initialization}}
+ int aa = (ref(aa) += 10); // expected-warning {{variable 'aa' is uninitialized when used within its own initialization}}
+ int bb = bb ? x : y; // expected-warning {{variable 'bb' is uninitialized when used within its own initialization}}
+
for (;;) {
int a = a; // no-warning: used to signal intended lack of initialization.
@@ -64,9 +106,64 @@ void test_stuff () {
int l = k ? l : l; // expected-warning {{variable 'l' is uninitialized when used within its own initialization}}
int m = 1 + (k ? m : m); // expected-warning {{'m' is uninitialized when used within its own initialization}}
int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
+ int o = std::move(o); // expected-warning {{variable 'o' is uninitialized when used within its own initialization}}
+ const int p = std::move(p); // expected-warning {{variable 'p' is uninitialized when used within its own initialization}}
+ int q = moved(std::move(q)); // expected-warning {{variable 'q' is uninitialized when used within its own initialization}}
+ int r = std::move((p ? q : (18, r))); // expected-warning {{variable 'r' is uninitialized when used within its own initialization}}
+ int s = r ?: s; // expected-warning {{variable 's' is uninitialized when used within its own initialization}}
+ int t = t ?: s; // expected-warning {{variable 't' is uninitialized when used within its own initialization}}
+ int u = (foo(u), s); // expected-warning {{variable 'u' is uninitialized when used within its own initialization}}
+ int v = (u += v); // expected-warning {{variable 'v' is uninitialized when used within its own initialization}}
+ int w = (w += 10); // expected-warning {{variable 'w' is uninitialized when used within its own initialization}}
+ int x = x++; // expected-warning {{variable 'x' is uninitialized when used within its own initialization}}
+ int y = ((s ? (y, v) : (77, y))++, sizeof(y)); // expected-warning {{variable 'y' is uninitialized when used within its own initialization}}
+ int z = ++ref(z); // expected-warning {{variable 'z' is uninitialized when used within its own initialization}}
+ int aa = (ref(aa) += 10); // expected-warning {{variable 'aa' is uninitialized when used within its own initialization}}
+ int bb = bb ? x : y; // expected-warning {{variable 'bb' is uninitialized when used within its own initialization}}
+
}
}
+// Also test similar constructs in a field's initializer.
+struct S {
+ int x;
+ int y;
+ const int z = 5;
+ void *ptr;
+
+ S(bool (*)[1]) : x(x) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(bool (*)[2]) : x(x + 1) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(bool (*)[3]) : x(x + x) {} // expected-warning 2{{field 'x' is uninitialized when used here}}
+ S(bool (*)[4]) : x(static_cast<long>(x) + 1) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(bool (*)[5]) : x(foo(x)) {} // expected-warning {{field 'x' is uninitialized when used here}}
+
+ // These don't actually require the value of x and so shouldn't warn.
+ S(char (*)[1]) : x(sizeof(x)) {} // rdar://8610363
+ S(char (*)[2]) : ptr(&ptr) {}
+ S(char (*)[3]) : x(bar(&x)) {}
+ S(char (*)[4]) : x(boo(x)) {}
+ S(char (*)[5]) : x(far(x)) {}
+ S(char (*)[6]) : x(__alignof__(x)) {}
+
+ S(int (*)[1]) : x(0), y(x ? y : y) {} // expected-warning 2{{field 'y' is uninitialized when used here}}
+ S(int (*)[2]) : x(0), y(1 + (x ? y : y)) {} // expected-warning 2{{field 'y' is uninitialized when used here}}
+ S(int (*)[3]) : x(-x) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(int (*)[4]) : x(std::move(x)) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(int (*)[5]) : z(std::move(z)) {} // expected-warning {{field 'z' is uninitialized when used here}}
+ S(int (*)[6]) : x(moved(std::move(x))) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(int (*)[7]) : x(0), y(std::move((x ? x : (18, y)))) {} // expected-warning {{field 'y' is uninitialized when used here}}
+ S(int (*)[8]) : x(0), y(x ?: y) {} // expected-warning {{field 'y' is uninitialized when used here}}
+ S(int (*)[9]) : x(0), y(y ?: x) {} // expected-warning {{field 'y' is uninitialized when used here}}
+ S(int (*)[10]) : x(0), y((foo(y), x)) {} // expected-warning {{field 'y' is uninitialized when used here}}
+ S(int (*)[11]) : x(0), y(x += y) {} // expected-warning {{field 'y' is uninitialized when used here}}
+ S(int (*)[12]) : x(x += 10) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(int (*)[13]) : x(x++) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(int (*)[14]) : x(0), y(((x ? (y, x) : (77, y))++, sizeof(y))) {} // expected-warning {{field 'y' is uninitialized when used here}}
+ S(int (*)[15]) : x(++ref(x)) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(int (*)[16]) : x((ref(x) += 10)) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(int (*)[17]) : x(0), y(y ? x : x) {} // expected-warning {{field 'y' is uninitialized when used here}}
+};
+
// Test self-references with record types.
class A {
// Non-POD class.
@@ -76,7 +173,7 @@ class A {
static int count;
int get() const { return num; }
int get2() { return num; }
- void set(int x) { num = x; }
+ int set(int x) { num = x; return num; }
static int zero() { return 0; }
A() {}
@@ -84,13 +181,20 @@ class A {
A(int x) {}
A(int *x) {}
A(A *a) {}
+ A(A &&a) {}
~A();
+ bool operator!();
+ bool operator!=(const A&);
};
+bool operator!=(int, const A&);
+
A getA() { return A(); }
A getA(int x) { return A(); }
A getA(A* a) { return A(); }
A getA(A a) { return A(); }
+A moveA(A&& a) { return A(); }
+A const_refA(const A& a) { return A(); }
void setupA(bool x) {
A a1;
@@ -127,9 +231,36 @@ void setupA(bool x) {
A *a26 = new A(a26->get()); // expected-warning {{variable 'a26' is uninitialized when used within its own initialization}}
A *a27 = new A(a27->get2()); // expected-warning {{variable 'a27' is uninitialized when used within its own initialization}}
A *a28 = new A(a28->num); // expected-warning {{variable 'a28' is uninitialized when used within its own initialization}}
+
+ const A a29(a29); // expected-warning {{variable 'a29' is uninitialized when used within its own initialization}}
+ const A a30 = a30; // expected-warning {{variable 'a30' is uninitialized when used within its own initialization}}
+
+ A a31 = std::move(a31); // expected-warning {{variable 'a31' is uninitialized when used within its own initialization}}
+ A a32 = moveA(std::move(a32)); // expected-warning {{variable 'a32' is uninitialized when used within its own initialization}}
+ A a33 = A(std::move(a33)); // expected-warning {{variable 'a33' is uninitialized when used within its own initialization}}
+ A a34(std::move(a34)); // expected-warning {{variable 'a34' is uninitialized when used within its own initialization}}
+ A a35 = std::move(x ? a34 : (37, a35)); // expected-warning {{variable 'a35' is uninitialized when used within its own initialization}}
+
+ A a36 = const_refA(a36);
+ A a37(const_refA(a37));
+
+ A a38({a38}); // expected-warning {{variable 'a38' is uninitialized when used within its own initialization}}
+ A a39 = {a39}; // expected-warning {{variable 'a39' is uninitialized when used within its own initialization}}
+ A a40 = A({a40}); // expected-warning {{variable 'a40' is uninitialized when used within its own initialization}}
+
+ A a41 = !a41; // expected-warning {{variable 'a41' is uninitialized when used within its own initialization}}
+ A a42 = !(a42); // expected-warning {{variable 'a42' is uninitialized when used within its own initialization}}
+ A a43 = a43 != a42; // expected-warning {{variable 'a43' is uninitialized when used within its own initialization}}
+ A a44 = a43 != a44; // expected-warning {{variable 'a44' is uninitialized when used within its own initialization}}
+ A a45 = a45 != a45; // expected-warning 2{{variable 'a45' is uninitialized when used within its own initialization}}
+ A a46 = 0 != a46; // expected-warning {{variable 'a46' is uninitialized when used within its own initialization}}
+
+ A a47(a47.set(a47.num)); // expected-warning 2{{variable 'a47' is uninitialized when used within its own initialization}}
+ A a48(a47.set(a48.num)); // expected-warning {{variable 'a48' is uninitialized when used within its own initialization}}
+ A a49(a47.set(a48.num));
}
-bool x;
+bool cond;
A a1;
A a2(a1.get());
@@ -149,8 +280,8 @@ A a14 = A(a14); // expected-warning {{variable 'a14' is uninitialized when used
A a15 = getA(a15.num); // expected-warning {{variable 'a15' is uninitialized when used within its own initialization}}
A a16(&a16.num); // expected-warning {{variable 'a16' is uninitialized when used within its own initialization}}
A a17(a17.get2()); // expected-warning {{variable 'a17' is uninitialized when used within its own initialization}}
-A a18 = x ? a18 : a17; // expected-warning {{variable 'a18' is uninitialized when used within its own initialization}}
-A a19 = getA(x ? a19 : a17); // expected-warning {{variable 'a19' is uninitialized when used within its own initialization}}
+A a18 = cond ? a18 : a17; // expected-warning {{variable 'a18' is uninitialized when used within its own initialization}}
+A a19 = getA(cond ? a19 : a17); // expected-warning {{variable 'a19' is uninitialized when used within its own initialization}}
A a20{a20}; // expected-warning {{variable 'a20' is uninitialized when used within its own initialization}}
A a21 = {a21}; // expected-warning {{variable 'a21' is uninitialized when used within its own initialization}}
@@ -163,6 +294,101 @@ A *a26 = new A(a26->get()); // expected-warning {{variable 'a26' is uninitial
A *a27 = new A(a27->get2()); // expected-warning {{variable 'a27' is uninitialized when used within its own initialization}}
A *a28 = new A(a28->num); // expected-warning {{variable 'a28' is uninitialized when used within its own initialization}}
+const A a29(a29); // expected-warning {{variable 'a29' is uninitialized when used within its own initialization}}
+const A a30 = a30; // expected-warning {{variable 'a30' is uninitialized when used within its own initialization}}
+
+A a31 = std::move(a31); // expected-warning {{variable 'a31' is uninitialized when used within its own initialization}}
+A a32 = moveA(std::move(a32)); // expected-warning {{variable 'a32' is uninitialized when used within its own initialization}}
+A a33 = A(std::move(a33)); // expected-warning {{variable 'a33' is uninitialized when used within its own initialization}}
+A a34(std::move(a34)); // expected-warning {{variable 'a34' is uninitialized when used within its own initialization}}
+A a35 = std::move(x ? a34 : (37, a35)); // expected-warning {{variable 'a35' is uninitialized when used within its own initialization}}
+
+A a36 = const_refA(a36);
+A a37(const_refA(a37));
+
+A a38({a38}); // expected-warning {{variable 'a38' is uninitialized when used within its own initialization}}
+A a39 = {a39}; // expected-warning {{variable 'a39' is uninitialized when used within its own initialization}}
+A a40 = A({a40}); // expected-warning {{variable 'a40' is uninitialized when used within its own initialization}}
+
+A a41 = !a41; // expected-warning {{variable 'a41' is uninitialized when used within its own initialization}}
+A a42 = !(a42); // expected-warning {{variable 'a42' is uninitialized when used within its own initialization}}
+A a43 = a43 != a42; // expected-warning {{variable 'a43' is uninitialized when used within its own initialization}}
+A a44 = a43 != a44; // expected-warning {{variable 'a44' is uninitialized when used within its own initialization}}
+A a45 = a45 != a45; // expected-warning 2{{variable 'a45' is uninitialized when used within its own initialization}}
+
+A a46 = 0 != a46; // expected-warning {{variable 'a46' is uninitialized when used within its own initialization}}
+
+A a47(a47.set(a47.num)); // expected-warning 2{{variable 'a47' is uninitialized when used within its own initialization}}
+A a48(a47.set(a48.num)); // expected-warning {{variable 'a48' is uninitialized when used within its own initialization}}
+A a49(a47.set(a48.num));
+
+class T {
+ A a, a2;
+ const A c_a;
+ A* ptr_a;
+
+ T() {}
+ T(bool (*)[1]) : a() {}
+ T(bool (*)[2]) : a2(a.get()) {}
+ T(bool (*)[3]) : a2(a) {}
+ T(bool (*)[4]) : a(&a) {}
+ T(bool (*)[5]) : a(a.zero()) {}
+ T(bool (*)[6]) : a(a.ONE) {}
+ T(bool (*)[7]) : a(getA()) {}
+ T(bool (*)[8]) : a2(getA(a.TWO)) {}
+ T(bool (*)[9]) : a(getA(&a)) {}
+ T(bool (*)[10]) : a(a.count) {}
+
+ T(bool (*)[11]) : a(a) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[12]) : a(a.get()) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[13]) : a(a.num) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[14]) : a(A(a)) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[15]) : a(getA(a.num)) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[16]) : a(&a.num) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[17]) : a(a.get2()) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[18]) : a2(cond ? a2 : a) {} // expected-warning {{field 'a2' is uninitialized when used here}}
+ T(bool (*)[19]) : a2(cond ? a2 : a) {} // expected-warning {{field 'a2' is uninitialized when used here}}
+ T(bool (*)[20]) : a{a} {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[21]) : a({a}) {} // expected-warning {{field 'a' is uninitialized when used here}}
+
+ T(bool (*)[22]) : ptr_a(new A(ptr_a->count)) {}
+ T(bool (*)[23]) : ptr_a(new A(ptr_a->ONE)) {}
+ T(bool (*)[24]) : ptr_a(new A(ptr_a->TWO)) {}
+ T(bool (*)[25]) : ptr_a(new A(ptr_a->zero())) {}
+
+ T(bool (*)[26]) : ptr_a(new A(ptr_a->get())) {} // expected-warning {{field 'ptr_a' is uninitialized when used here}}
+ T(bool (*)[27]) : ptr_a(new A(ptr_a->get2())) {} // expected-warning {{field 'ptr_a' is uninitialized when used here}}
+ T(bool (*)[28]) : ptr_a(new A(ptr_a->num)) {} // expected-warning {{field 'ptr_a' is uninitialized when used here}}
+
+ T(bool (*)[29]) : c_a(c_a) {} // expected-warning {{field 'c_a' is uninitialized when used here}}
+ T(bool (*)[30]) : c_a(A(c_a)) {} // expected-warning {{field 'c_a' is uninitialized when used here}}
+
+ T(bool (*)[31]) : a(std::move(a)) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[32]) : a(moveA(std::move(a))) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[33]) : a(A(std::move(a))) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[34]) : a(A(std::move(a))) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[35]) : a2(std::move(x ? a : (37, a2))) {} // expected-warning {{field 'a2' is uninitialized when used here}}
+
+ T(bool (*)[36]) : a(const_refA(a)) {}
+ T(bool (*)[37]) : a(A(const_refA(a))) {}
+
+ T(bool (*)[38]) : a({a}) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[39]) : a{a} {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[40]) : a({a}) {} // expected-warning {{field 'a' is uninitialized when used here}}
+
+ T(bool (*)[41]) : a(!a) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[42]) : a(!(a)) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ T(bool (*)[43]) : a(), a2(a2 != a) {} // expected-warning {{field 'a2' is uninitialized when used here}}
+ T(bool (*)[44]) : a(), a2(a != a2) {} // expected-warning {{field 'a2' is uninitialized when used here}}
+ T(bool (*)[45]) : a(a != a) {} // expected-warning 2{{field 'a' is uninitialized when used here}}
+ T(bool (*)[46]) : a(0 != a) {} // expected-warning {{field 'a' is uninitialized when used here}}
+
+ T(bool (*)[47]) : a2(a2.set(a2.num)) {} // expected-warning 2{{field 'a2' is uninitialized when used here}}
+ T(bool (*)[48]) : a2(a.set(a2.num)) {} // expected-warning {{field 'a2' is uninitialized when used here}}
+ T(bool (*)[49]) : a2(a.set(a.num)) {}
+
+};
+
struct B {
// POD struct.
int x;
@@ -173,13 +399,14 @@ B getB() { return B(); };
B getB(int x) { return B(); };
B getB(int *x) { return B(); };
B getB(B *b) { return B(); };
+B moveB(B &&b) { return B(); };
B* getPtrB() { return 0; };
B* getPtrB(int x) { return 0; };
B* getPtrB(int *x) { return 0; };
B* getPtrB(B **b) { return 0; };
-void setupB() {
+void setupB(bool x) {
B b1;
B b2(b1);
B b3 = { 5, &b3.x };
@@ -209,6 +436,14 @@ void setupB() {
B b17 = { b17.x = 5, b17.y = 0 };
B b18 = { b18.x + 1, b18.y }; // expected-warning 2{{variable 'b18' is uninitialized when used within its own initialization}}
+
+ const B b19 = b19; // expected-warning {{variable 'b19' is uninitialized when used within its own initialization}}
+ const B b20(b20); // expected-warning {{variable 'b20' is uninitialized when used within its own initialization}}
+
+ B b21 = std::move(b21); // expected-warning {{variable 'b21' is uninitialized when used within its own initialization}}
+ B b22 = moveB(std::move(b22)); // expected-warning {{variable 'b22' is uninitialized when used within its own initialization}}
+ B b23 = B(std::move(b23)); // expected-warning {{variable 'b23' is uninitialized when used within its own initialization}}
+ B b24 = std::move(x ? b23 : (18, b24)); // expected-warning {{variable 'b24' is uninitialized when used within its own initialization}}
}
B b1;
@@ -234,25 +469,50 @@ B* b16 = getPtrB(b16->y); // expected-warning {{variable 'b16' is uninitialized
B b17 = { b17.x = 5, b17.y = 0 };
B b18 = { b18.x + 1, b18.y }; // expected-warning 2{{variable 'b18' is uninitialized when used within its own initialization}}
-
-// Also test similar constructs in a field's initializer.
-struct S {
- int x;
- void *ptr;
-
- S(bool (*)[1]) : x(x) {} // expected-warning {{field 'x' is uninitialized when used here}}
- S(bool (*)[2]) : x(x + 1) {} // expected-warning {{field 'x' is uninitialized when used here}}
- S(bool (*)[3]) : x(x + x) {} // expected-warning 2{{field 'x' is uninitialized when used here}}
- S(bool (*)[4]) : x(static_cast<long>(x) + 1) {} // expected-warning {{field 'x' is uninitialized when used here}}
- S(bool (*)[5]) : x(foo(x)) {} // expected-warning {{field 'x' is uninitialized when used here}}
-
- // These don't actually require the value of x and so shouldn't warn.
- S(char (*)[1]) : x(sizeof(x)) {} // rdar://8610363
- S(char (*)[2]) : ptr(&ptr) {}
- S(char (*)[3]) : x(__alignof__(x)) {}
- S(char (*)[4]) : x(bar(&x)) {}
- S(char (*)[5]) : x(boo(x)) {}
- S(char (*)[6]) : x(far(x)) {}
+const B b19 = b19; // expected-warning {{variable 'b19' is uninitialized when used within its own initialization}}
+const B b20(b20); // expected-warning {{variable 'b20' is uninitialized when used within its own initialization}}
+
+B b21 = std::move(b21); // expected-warning {{variable 'b21' is uninitialized when used within its own initialization}}
+B b22 = moveB(std::move(b22)); // expected-warning {{variable 'b22' is uninitialized when used within its own initialization}}
+B b23 = B(std::move(b23)); // expected-warning {{variable 'b23' is uninitialized when used within its own initialization}}
+B b24 = std::move(x ? b23 : (18, b24)); // expected-warning {{variable 'b24' is uninitialized when used within its own initialization}}
+
+class U {
+ B b1, b2;
+ B *ptr1, *ptr2;
+ const B constb = {};
+
+ U() {}
+ U(bool (*)[1]) : b1() {}
+ U(bool (*)[2]) : b2(b1) {}
+ U(bool (*)[3]) : b1{ 5, &b1.x } {}
+ U(bool (*)[4]) : b1(getB()) {}
+ U(bool (*)[5]) : b1(getB(&b1)) {}
+ U(bool (*)[6]) : b1(getB(&b1.x)) {}
+
+ U(bool (*)[7]) : b1(b1) {} // expected-warning {{field 'b1' is uninitialized when used here}}
+ U(bool (*)[8]) : b1(getB(b1.x)) {} // expected-warning {{field 'b1' is uninitialized when used here}}
+ U(bool (*)[9]) : b1(getB(b1.y)) {} // expected-warning {{field 'b1' is uninitialized when used here}}
+ U(bool (*)[10]) : b1(getB(-b1.x)) {} // expected-warning {{field 'b1' is uninitialized when used here}}
+
+ U(bool (*)[11]) : ptr1(0) {}
+ U(bool (*)[12]) : ptr1(0), ptr2(ptr1) {}
+ U(bool (*)[13]) : ptr1(getPtrB()) {}
+ U(bool (*)[14]) : ptr1(getPtrB(&ptr1)) {}
+
+ U(bool (*)[15]) : ptr1(getPtrB(ptr1->x)) {} // expected-warning {{field 'ptr1' is uninitialized when used here}}
+ U(bool (*)[16]) : ptr2(getPtrB(ptr2->y)) {} // expected-warning {{field 'ptr2' is uninitialized when used here}}
+
+ U(bool (*)[17]) : b1 { b1.x = 5, b1.y = 0 } {}
+ U(bool (*)[18]) : b1 { b1.x + 1, b1.y } {} // expected-warning 2{{field 'b1' is uninitialized when used here}}
+
+ U(bool (*)[19]) : constb(constb) {} // expected-warning {{field 'constb' is uninitialized when used here}}
+ U(bool (*)[20]) : constb(B(constb)) {} // expected-warning {{field 'constb' is uninitialized when used here}}
+
+ U(bool (*)[21]) : b1(std::move(b1)) {} // expected-warning {{field 'b1' is uninitialized when used here}}
+ U(bool (*)[22]) : b1(moveB(std::move(b1))) {} // expected-warning {{field 'b1' is uninitialized when used here}}
+ U(bool (*)[23]) : b1(B(std::move(b1))) {} // expected-warning {{field 'b1' is uninitialized when used here}}
+ U(bool (*)[24]) : b2(std::move(x ? b1 : (18, b2))) {} // expected-warning {{field 'b2' is uninitialized when used here}}
};
struct C { char a[100], *e; } car = { .e = car.a };
@@ -360,6 +620,8 @@ namespace {
E(char (*)[12]) : a((b + c, c, a)) {} // expected-warning {{field 'a' is uninitialized when used here}}
E(char (*)[13]) : a((a, a, a, a)) {} // expected-warning {{field 'a' is uninitialized when used here}}
E(char (*)[14]) : a((b, c, c)) {}
+ E(char (*)[15]) : a(b ?: a) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ E(char (*)[16]) : a(a ?: b) {} // expected-warning {{field 'a' is uninitialized when used here}}
};
struct F {
@@ -385,6 +647,11 @@ namespace {
G(char (*)[7]) : f3(f3->*f_ptr) {} // expected-warning {{field 'f3' is uninitialized when used here}}
G(char (*)[8]) : f3(new F(f3->*ptr)) {} // expected-warning {{field 'f3' is uninitialized when used here}}
};
+
+ struct H {
+ H() : a(a) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ const A a;
+ };
}
namespace statics {
@@ -406,6 +673,21 @@ namespace statics {
static int l = k ? l : l; // expected-warning 2{{variable 'l' is uninitialized when used within its own initialization}}
static int m = 1 + (k ? m : m); // expected-warning 2{{variable 'm' is uninitialized when used within its own initialization}}
static int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
+ static int o = std::move(o); // expected-warning {{variable 'o' is uninitialized when used within its own initialization}}
+ static const int p = std::move(p); // expected-warning {{variable 'p' is uninitialized when used within its own initialization}}
+ static int q = moved(std::move(q)); // expected-warning {{variable 'q' is uninitialized when used within its own initialization}}
+ static int r = std::move((p ? q : (18, r))); // expected-warning {{variable 'r' is uninitialized when used within its own initialization}}
+ static int s = r ?: s; // expected-warning {{variable 's' is uninitialized when used within its own initialization}}
+ static int t = t ?: s; // expected-warning {{variable 't' is uninitialized when used within its own initialization}}
+ static int u = (foo(u), s); // expected-warning {{variable 'u' is uninitialized when used within its own initialization}}
+ static int v = (u += v); // expected-warning {{variable 'v' is uninitialized when used within its own initialization}}
+ static int w = (w += 10); // expected-warning {{variable 'w' is uninitialized when used within its own initialization}}
+ static int x = x++; // expected-warning {{variable 'x' is uninitialized when used within its own initialization}}
+ static int y = ((s ? (y, v) : (77, y))++, sizeof(y)); // expected-warning {{variable 'y' is uninitialized when used within its own initialization}}
+ static int z = ++ref(z); // expected-warning {{variable 'z' is uninitialized when used within its own initialization}}
+ static int aa = (ref(aa) += 10); // expected-warning {{variable 'aa' is uninitialized when used within its own initialization}}
+ static int bb = bb ? x : y; // expected-warning {{variable 'bb' is uninitialized when used within its own initialization}}
+
void test() {
static int a = a; // no-warning: used to signal intended lack of initialization.
@@ -426,7 +708,22 @@ namespace statics {
static int l = k ? l : l; // expected-warning 2{{static variable 'l' is suspiciously used within its own initialization}}
static int m = 1 + (k ? m : m); // expected-warning 2{{static variable 'm' is suspiciously used within its own initialization}}
static int n = -n; // expected-warning {{static variable 'n' is suspiciously used within its own initialization}}
- for (;;) {
+ static int o = std::move(o); // expected-warning {{static variable 'o' is suspiciously used within its own initialization}}
+ static const int p = std::move(p); // expected-warning {{static variable 'p' is suspiciously used within its own initialization}}
+ static int q = moved(std::move(q)); // expected-warning {{static variable 'q' is suspiciously used within its own initialization}}
+ static int r = std::move((p ? q : (18, r))); // expected-warning {{static variable 'r' is suspiciously used within its own initialization}}
+ static int s = r ?: s; // expected-warning {{static variable 's' is suspiciously used within its own initialization}}
+ static int t = t ?: s; // expected-warning {{static variable 't' is suspiciously used within its own initialization}}
+ static int u = (foo(u), s); // expected-warning {{static variable 'u' is suspiciously used within its own initialization}}
+ static int v = (u += v); // expected-warning {{static variable 'v' is suspiciously used within its own initialization}}
+ static int w = (w += 10); // expected-warning {{static variable 'w' is suspiciously used within its own initialization}}
+ static int x = x++; // expected-warning {{static variable 'x' is suspiciously used within its own initialization}}
+ static int y = ((s ? (y, v) : (77, y))++, sizeof(y)); // expected-warning {{static variable 'y' is suspiciously used within its own initialization}}
+ static int z = ++ref(z); // expected-warning {{static variable 'z' is suspiciously used within its own initialization}}
+ static int aa = (ref(aa) += 10); // expected-warning {{static variable 'aa' is suspiciously used within its own initialization}}
+ static int bb = bb ? x : y; // expected-warning {{static variable 'bb' is suspiciously used within its own initialization}}
+
+ for (;;) {
static int a = a; // no-warning: used to signal intended lack of initialization.
static int b = b + 1; // expected-warning {{static variable 'b' is suspiciously used within its own initialization}}
static int c = (c + c); // expected-warning 2{{static variable 'c' is suspiciously used within its own initialization}}
@@ -445,6 +742,20 @@ namespace statics {
static int l = k ? l : l; // expected-warning 2{{static variable 'l' is suspiciously used within its own initialization}}
static int m = 1 + (k ? m : m); // expected-warning 2{{static variable 'm' is suspiciously used within its own initialization}}
static int n = -n; // expected-warning {{static variable 'n' is suspiciously used within its own initialization}}
+ static int o = std::move(o); // expected-warning {{static variable 'o' is suspiciously used within its own initialization}}
+ static const int p = std::move(p); // expected-warning {{static variable 'p' is suspiciously used within its own initialization}}
+ static int q = moved(std::move(q)); // expected-warning {{static variable 'q' is suspiciously used within its own initialization}}
+ static int r = std::move((p ? q : (18, r))); // expected-warning {{static variable 'r' is suspiciously used within its own initialization}}
+ static int s = r ?: s; // expected-warning {{static variable 's' is suspiciously used within its own initialization}}
+ static int t = t ?: s; // expected-warning {{static variable 't' is suspiciously used within its own initialization}}
+ static int u = (foo(u), s); // expected-warning {{static variable 'u' is suspiciously used within its own initialization}}
+ static int v = (u += v); // expected-warning {{static variable 'v' is suspiciously used within its own initialization}}
+ static int w = (w += 10); // expected-warning {{static variable 'w' is suspiciously used within its own initialization}}
+ static int x = x++; // expected-warning {{static variable 'x' is suspiciously used within its own initialization}}
+ static int y = ((s ? (y, v) : (77, y))++, sizeof(y)); // expected-warning {{static variable 'y' is suspiciously used within its own initialization}}
+ static int z = ++ref(z); // expected-warning {{static variable 'z' is suspiciously used within its own initialization}}
+ static int aa = (ref(aa) += 10); // expected-warning {{static variable 'aa' is suspiciously used within its own initialization}}
+ static int bb = bb ? x : y; // expected-warning {{static variable 'bb' is suspiciously used within its own initialization}}
}
}
}
@@ -473,13 +784,21 @@ namespace references {
int &b(b); // expected-warning{{reference 'b' is not yet bound to a value when used within its own initialization}}
int &c = a ? b : c; // expected-warning{{reference 'c' is not yet bound to a value when used within its own initialization}}
int &d{d}; // expected-warning{{reference 'd' is not yet bound to a value when used within its own initialization}}
+ int &e = d ?: e; // expected-warning{{reference 'e' is not yet bound to a value when used within its own initialization}}
+ int &f = f ?: d; // expected-warning{{reference 'f' is not yet bound to a value when used within its own initialization}}
+
+ int &return_ref1(int);
+ int &return_ref2(int&);
+
+ int &g = return_ref1(g); // expected-warning{{reference 'g' is not yet bound to a value when used within its own initialization}}
+ int &h = return_ref2(h); // expected-warning{{reference 'h' is not yet bound to a value when used within its own initialization}}
struct S {
S() : a(a) {} // expected-warning{{reference 'a' is not yet bound to a value when used here}}
int &a;
};
- void f() {
+ void test() {
int &a = a; // expected-warning{{reference 'a' is not yet bound to a value when used within its own initialization}}
int &b(b); // expected-warning{{reference 'b' is not yet bound to a value when used within its own initialization}}
int &c = a ? b : c; // expected-warning{{reference 'c' is not yet bound to a value when used within its own initialization}}
@@ -529,6 +848,7 @@ namespace lambdas {
}
namespace record_fields {
+ bool x;
struct A {
A() {}
A get();
@@ -541,6 +861,7 @@ namespace record_fields {
A const_ref(const A&);
A pointer(A*);
A normal(A);
+ A rref(A&&);
struct B {
A a;
@@ -553,9 +874,13 @@ namespace record_fields {
B(char (*)[7]) : a(const_ref(a)) {}
B(char (*)[8]) : a(pointer(&a)) {}
B(char (*)[9]) : a(normal(a)) {} // expected-warning {{uninitialized}}
+ B(char (*)[10]) : a(std::move(a)) {} // expected-warning {{uninitialized}}
+ B(char (*)[11]) : a(A(std::move(a))) {} // expected-warning {{uninitialized}}
+ B(char (*)[12]) : a(rref(std::move(a))) {} // expected-warning {{uninitialized}}
+ B(char (*)[13]) : a(std::move(x ? a : (25, a))) {} // expected-warning 2{{uninitialized}}
};
struct C {
- C() {} // expected-note4{{in this constructor}}
+ C() {} // expected-note9{{in this constructor}}
A a1 = a1; // expected-warning {{uninitialized}}
A a2 = a2.get(); // expected-warning {{uninitialized}}
A a3 = a3.num();
@@ -565,8 +890,13 @@ namespace record_fields {
A a7 = const_ref(a7);
A a8 = pointer(&a8);
A a9 = normal(a9); // expected-warning {{uninitialized}}
+ const A a10 = a10; // expected-warning {{uninitialized}}
+ A a11 = std::move(a11); // expected-warning {{uninitialized}}
+ A a12 = A(std::move(a12)); // expected-warning {{uninitialized}}
+ A a13 = rref(std::move(a13)); // expected-warning {{uninitialized}}
+ A a14 = std::move(x ? a13 : (22, a14)); // expected-warning {{uninitialized}}
};
- struct D { // expected-note4{{in the implicit default constructor}}
+ struct D { // expected-note9{{in the implicit default constructor}}
A a1 = a1; // expected-warning {{uninitialized}}
A a2 = a2.get(); // expected-warning {{uninitialized}}
A a3 = a3.num();
@@ -576,6 +906,11 @@ namespace record_fields {
A a7 = const_ref(a7);
A a8 = pointer(&a8);
A a9 = normal(a9); // expected-warning {{uninitialized}}
+ const A a10 = a10; // expected-warning {{uninitialized}}
+ A a11 = std::move(a11); // expected-warning {{uninitialized}}
+ A a12 = A(std::move(a12)); // expected-warning {{uninitialized}}
+ A a13 = rref(std::move(a13)); // expected-warning {{uninitialized}}
+ A a14 = std::move(x ? a13 : (22, a14)); // expected-warning {{uninitialized}}
};
D d;
struct E {
@@ -588,6 +923,11 @@ namespace record_fields {
A a7 = const_ref(a7);
A a8 = pointer(&a8);
A a9 = normal(a9);
+ const A a10 = a10;
+ A a11 = std::move(a11);
+ A a12 = A(std::move(a12));
+ A a13 = rref(std::move(a13));
+ A a14 = std::move(x ? a13 : (22, a14));
};
}
@@ -710,6 +1050,20 @@ namespace cross_field_warnings {
int d = a + b + c;
R() : a(c = 5), b(c), c(a) {}
};
+
+ // FIXME: Use the CFG-based analysis to give a sometimes uninitialized
+ // warning on y.
+ struct T {
+ int x;
+ int y;
+ T(bool b)
+ : x(b ? (y = 5) : (1 + y)), // expected-warning{{field 'y' is uninitialized when used here}}
+ y(y + 1) {}
+ T(int b)
+ : x(!b ? (1 + y) : (y = 5)), // expected-warning{{field 'y' is uninitialized when used here}}
+ y(y + 1) {}
+ };
+
}
namespace base_class {
@@ -728,3 +1082,306 @@ namespace base_class {
C() : A(y = 4), x(y) {}
};
}
+
+namespace delegating_constructor {
+ struct A {
+ A(int);
+ A(int&, int);
+
+ A(char (*)[1]) : A(x) {}
+ // expected-warning@-1 {{field 'x' is uninitialized when used here}}
+ A(char (*)[2]) : A(x, x) {}
+ // expected-warning@-1 {{field 'x' is uninitialized when used here}}
+
+ A(char (*)[3]) : A(x, 0) {}
+
+ int x;
+ };
+}
+
+namespace init_list {
+ int num = 5;
+ struct A { int i1, i2; };
+ struct B { A a1, a2; };
+
+ A a1{1,2};
+ A a2{a2.i1 + 2}; // expected-warning{{uninitialized}}
+ A a3 = {a3.i1 + 2}; // expected-warning{{uninitialized}}
+ A a4 = A{a4.i2 + 2}; // expected-warning{{uninitialized}}
+
+ B b1 = { {}, {} };
+ B b2 = { {}, b2.a1 };
+ B b3 = { b3.a1 }; // expected-warning{{uninitialized}}
+ B b4 = { {}, b4.a2} ; // expected-warning{{uninitialized}}
+ B b5 = { b5.a2 }; // expected-warning{{uninitialized}}
+
+ B b6 = { {b6.a1.i1} }; // expected-warning{{uninitialized}}
+ B b7 = { {0, b7.a1.i1} };
+ B b8 = { {}, {b8.a1.i1} };
+ B b9 = { {}, {0, b9.a1.i1} };
+
+ B b10 = { {b10.a1.i2} }; // expected-warning{{uninitialized}}
+ B b11 = { {0, b11.a1.i2} }; // expected-warning{{uninitialized}}
+ B b12 = { {}, {b12.a1.i2} };
+ B b13 = { {}, {0, b13.a1.i2} };
+
+ B b14 = { {b14.a2.i1} }; // expected-warning{{uninitialized}}
+ B b15 = { {0, b15.a2.i1} }; // expected-warning{{uninitialized}}
+ B b16 = { {}, {b16.a2.i1} }; // expected-warning{{uninitialized}}
+ B b17 = { {}, {0, b17.a2.i1} };
+
+ B b18 = { {b18.a2.i2} }; // expected-warning{{uninitialized}}
+ B b19 = { {0, b19.a2.i2} }; // expected-warning{{uninitialized}}
+ B b20 = { {}, {b20.a2.i2} }; // expected-warning{{uninitialized}}
+ B b21 = { {}, {0, b21.a2.i2} }; // expected-warning{{uninitialized}}
+
+ B b22 = { {b18.a2.i2 + 5} };
+
+ struct C {int a; int& b; int c; };
+ C c1 = { 0, num, 0 };
+ C c2 = { 1, num, c2.b };
+ C c3 = { c3.b, num }; // expected-warning{{uninitialized}}
+ C c4 = { 0, c4.b, 0 }; // expected-warning{{uninitialized}}
+ C c5 = { 0, c5.c, 0 };
+ C c6 = { c6.b, num, 0 }; // expected-warning{{uninitialized}}
+ C c7 = { 0, c7.a, 0 };
+
+ struct D {int &a; int &b; };
+ D d1 = { num, num };
+ D d2 = { num, d2.a };
+ D d3 = { d3.b, num }; // expected-warning{{uninitialized}}
+
+ // Same as above in member initializer form.
+ struct Awrapper {
+ A a1{1,2};
+ A a2{a2.i1 + 2}; // expected-warning{{uninitialized}}
+ A a3 = {a3.i1 + 2}; // expected-warning{{uninitialized}}
+ A a4 = A{a4.i2 + 2}; // expected-warning{{uninitialized}}
+ Awrapper() {} // expected-note 3{{in this constructor}}
+ Awrapper(int) :
+ a1{1,2},
+ a2{a2.i1 + 2}, // expected-warning{{uninitialized}}
+ a3{a3.i1 + 2}, // expected-warning{{uninitialized}}
+ a4{a4.i2 + 2} // expected-warning{{uninitialized}}
+ {}
+ };
+
+ struct Bwrapper {
+ B b1 = { {}, {} };
+ B b2 = { {}, b2.a1 };
+ B b3 = { b3.a1 }; // expected-warning{{uninitialized}}
+ B b4 = { {}, b4.a2} ; // expected-warning{{uninitialized}}
+ B b5 = { b5.a2 }; // expected-warning{{uninitialized}}
+
+ B b6 = { {b6.a1.i1} }; // expected-warning{{uninitialized}}
+ B b7 = { {0, b7.a1.i1} };
+ B b8 = { {}, {b8.a1.i1} };
+ B b9 = { {}, {0, b9.a1.i1} };
+
+ B b10 = { {b10.a1.i2} }; // expected-warning{{uninitialized}}
+ B b11 = { {0, b11.a1.i2} }; // expected-warning{{uninitialized}}
+ B b12 = { {}, {b12.a1.i2} };
+ B b13 = { {}, {0, b13.a1.i2} };
+
+ B b14 = { {b14.a2.i1} }; // expected-warning{{uninitialized}}
+ B b15 = { {0, b15.a2.i1} }; // expected-warning{{uninitialized}}
+ B b16 = { {}, {b16.a2.i1} }; // expected-warning{{uninitialized}}
+ B b17 = { {}, {0, b17.a2.i1} };
+
+ B b18 = { {b18.a2.i2} }; // expected-warning{{uninitialized}}
+ B b19 = { {0, b19.a2.i2} }; // expected-warning{{uninitialized}}
+ B b20 = { {}, {b20.a2.i2} }; // expected-warning{{uninitialized}}
+ B b21 = { {}, {0, b21.a2.i2} }; // expected-warning{{uninitialized}}
+
+ B b22 = { {b18.a2.i2 + 5} };
+ Bwrapper() {} // expected-note 13{{in this constructor}}
+ Bwrapper(int) :
+ b1{ {}, {} },
+ b2{ {}, b2.a1 },
+ b3{ b3.a1 }, // expected-warning{{uninitialized}}
+ b4{ {}, b4.a2}, // expected-warning{{uninitialized}}
+ b5{ b5.a2 }, // expected-warning{{uninitialized}}
+
+ b6{ {b6.a1.i1} }, // expected-warning{{uninitialized}}
+ b7{ {0, b7.a1.i1} },
+ b8{ {}, {b8.a1.i1} },
+ b9{ {}, {0, b9.a1.i1} },
+
+ b10{ {b10.a1.i2} }, // expected-warning{{uninitialized}}
+ b11{ {0, b11.a1.i2} }, // expected-warning{{uninitialized}}
+ b12{ {}, {b12.a1.i2} },
+ b13{ {}, {0, b13.a1.i2} },
+
+ b14{ {b14.a2.i1} }, // expected-warning{{uninitialized}}
+ b15{ {0, b15.a2.i1} }, // expected-warning{{uninitialized}}
+ b16{ {}, {b16.a2.i1} }, // expected-warning{{uninitialized}}
+ b17{ {}, {0, b17.a2.i1} },
+
+ b18{ {b18.a2.i2} }, // expected-warning{{uninitialized}}
+ b19{ {0, b19.a2.i2} }, // expected-warning{{uninitialized}}
+ b20{ {}, {b20.a2.i2} }, // expected-warning{{uninitialized}}
+ b21{ {}, {0, b21.a2.i2} }, // expected-warning{{uninitialized}}
+
+ b22{ {b18.a2.i2 + 5} }
+ {}
+ };
+
+ struct Cwrapper {
+ C c1 = { 0, num, 0 };
+ C c2 = { 1, num, c2.b };
+ C c3 = { c3.b, num }; // expected-warning{{uninitialized}}
+ C c4 = { 0, c4.b, 0 }; // expected-warning{{uninitialized}}
+ C c5 = { 0, c5.c, 0 };
+ C c6 = { c6.b, num, 0 }; // expected-warning{{uninitialized}}
+ C c7 = { 0, c7.a, 0 };
+
+ Cwrapper() {} // expected-note 3{{in this constructor}}
+ Cwrapper(int) :
+ c1{ 0, num, 0 },
+ c2{ 1, num, c2.b },
+ c3{ c3.b, num }, // expected-warning{{uninitialized}}
+ c4{ 0, c4.b, 0 }, // expected-warning{{uninitialized}}
+ c5{ 0, c5.c, 0 },
+ c6{ c6.b, num, 0 }, // expected-warning{{uninitialized}}
+ c7{ 0, c7.a, 0 }
+ {}
+ };
+
+ struct Dwrapper {
+ D d1 = { num, num };
+ D d2 = { num, d2.a };
+ D d3 = { d3.b, num }; // expected-warning{{uninitialized}}
+ Dwrapper() {} // expected-note{{in this constructor}}
+ Dwrapper(int) :
+ d1{ num, num },
+ d2{ num, d2.a },
+ d3{ d3.b, num } // expected-warning{{uninitialized}}
+ {}
+ };
+}
+
+namespace template_class {
+class Foo {
+ public:
+ int *Create() { return nullptr; }
+};
+
+template <typename T>
+class A {
+public:
+ // Don't warn on foo here.
+ A() : ptr(foo->Create()) {}
+
+private:
+ Foo *foo = new Foo;
+ int *ptr;
+};
+
+template <typename T>
+class B {
+public:
+ // foo is uninitialized here, but class B is never instantiated.
+ B() : ptr(foo->Create()) {}
+
+private:
+ Foo *foo;
+ int *ptr;
+};
+
+template <typename T>
+class C {
+public:
+ C() : ptr(foo->Create()) {}
+ // expected-warning@-1 {{field 'foo' is uninitialized when used here}}
+private:
+ Foo *foo;
+ int *ptr;
+};
+
+C<int> c;
+// expected-note@-1 {{in instantiation of member function 'template_class::C<int>::C' requested here}}
+
+}
+
+namespace base_class_access {
+struct A {
+ A();
+ A(int);
+
+ int i;
+ int foo();
+
+ static int bar();
+};
+
+struct B : public A {
+ B(int (*)[1]) : A() {}
+ B(int (*)[2]) : A(bar()) {}
+
+ B(int (*)[3]) : A(i) {}
+ // expected-warning@-1 {{base class 'base_class_access::A' is uninitialized when used here to access 'base_class_access::A::i'}}
+
+ B(int (*)[4]) : A(foo()) {}
+ // expected-warning@-1 {{base_class_access::A' is uninitialized when used here to access 'base_class_access::A::foo'}}
+};
+
+struct C {
+ C(int) {}
+};
+
+struct D : public C, public A {
+ D(int (*)[1]) : C(0) {}
+ D(int (*)[2]) : C(bar()) {}
+
+ D(int (*)[3]) : C(i) {}
+ // expected-warning@-1 {{base class 'base_class_access::A' is uninitialized when used here to access 'base_class_access::A::i'}}
+
+ D(int (*)[4]) : C(foo()) {}
+ // expected-warning@-1 {{base_class_access::A' is uninitialized when used here to access 'base_class_access::A::foo'}}
+};
+
+}
+
+namespace value {
+template <class T> T move(T t);
+template <class T> T notmove(T t);
+}
+namespace lvalueref {
+template <class T> T move(T& t);
+template <class T> T notmove(T& t);
+}
+namespace rvalueref {
+template <class T> T move(T&& t);
+template <class T> T notmove(T&& t);
+}
+
+namespace move_test {
+int a1 = std::move(a1); // expected-warning {{uninitialized}}
+int a2 = value::move(a2); // expected-warning {{uninitialized}}
+int a3 = value::notmove(a3); // expected-warning {{uninitialized}}
+int a4 = lvalueref::move(a4);
+int a5 = lvalueref::notmove(a5);
+int a6 = rvalueref::move(a6);
+int a7 = rvalueref::notmove(a7);
+
+void test() {
+ int a1 = std::move(a1); // expected-warning {{uninitialized}}
+ int a2 = value::move(a2); // expected-warning {{uninitialized}}
+ int a3 = value::notmove(a3); // expected-warning {{uninitialized}}
+ int a4 = lvalueref::move(a4);
+ int a5 = lvalueref::notmove(a5);
+ int a6 = rvalueref::move(a6);
+ int a7 = rvalueref::notmove(a7);
+}
+
+class A {
+ int a;
+ A(int (*) [1]) : a(std::move(a)) {} // expected-warning {{uninitialized}}
+ A(int (*) [2]) : a(value::move(a)) {} // expected-warning {{uninitialized}}
+ A(int (*) [3]) : a(value::notmove(a)) {} // expected-warning {{uninitialized}}
+ A(int (*) [4]) : a(lvalueref::move(a)) {}
+ A(int (*) [5]) : a(lvalueref::notmove(a)) {}
+ A(int (*) [6]) : a(rvalueref::move(a)) {}
+ A(int (*) [7]) : a(rvalueref::notmove(a)) {}
+};
+}
diff --git a/test/SemaCXX/unknown-type-name.cpp b/test/SemaCXX/unknown-type-name.cpp
index f2c84df242ff..9d28c310ed97 100644
--- a/test/SemaCXX/unknown-type-name.cpp
+++ b/test/SemaCXX/unknown-type-name.cpp
@@ -27,7 +27,7 @@ int var(zepelin); // expected-error{{did you mean 'zeppelin'?}}
template<typename T>
struct A {
typedef T type;
-
+
type f();
type g();
@@ -93,14 +93,14 @@ template<typename T> int A<T>::h(T::type x, char) {} // expected-error{{missing
template<typename T> int h(T::type, int); // expected-error{{missing 'typename'}}
template<typename T> int h(T::type x, char); // expected-error{{missing 'typename'}}
-template<typename T> int junk1(T::junk); // expected-warning{{variable templates are a C++1y extension}}
+template<typename T> int junk1(T::junk); // expected-warning{{variable templates are a C++14 extension}}
template<typename T> int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
template<typename T> int junk3(T::junk) = delete; // expected-error{{missing 'typename'}} expected-warning{{C++11}}
template<typename T> int junk4(T::junk j); // expected-error{{missing 'typename'}}
// FIXME: We can tell this was intended to be a function because it does not
// have a dependent nested name specifier.
-template<typename T> int i(T::type, int()); // expected-warning{{variable templates are a C++1y extension}}
+template<typename T> int i(T::type, int()); // expected-warning{{variable templates are a C++14 extension}}
// FIXME: We know which type specifier should have been specified here. Provide
// a fix-it to add 'typename A<T>::type'
diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp
index 40f80a70ef37..e730c9d63a20 100644
--- a/test/SemaCXX/using-decl-1.cpp
+++ b/test/SemaCXX/using-decl-1.cpp
@@ -255,3 +255,11 @@ namespace TypoCorrectTemplateMember {
using A::goobar; // expected-error {{no member named 'goobar' in 'TypoCorrectTemplateMember::A'; did you mean 'foobar'?}}
};
}
+
+namespace use_instance_in_static {
+struct A { int n; };
+struct B : A {
+ using A::n;
+ static int f() { return n; } // expected-error {{invalid use of member 'n' in static member function}}
+};
+}
diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp
index 56dafc41f132..39d4cccacd35 100644
--- a/test/SemaCXX/vararg-non-pod.cpp
+++ b/test/SemaCXX/vararg-non-pod.cpp
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-error=non-pod-varargs
+// Check that the warning is still there under -fms-compatibility.
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-error=non-pod-varargs -fms-compatibility
+
extern char version[];
class C {
@@ -100,7 +103,7 @@ Base &get_base(...);
int eat_base(...);
void test_typeid(Base &base) {
- (void)typeid(get_base(base)); // expected-warning{{cannot pass object of non-POD type 'Base' through variadic function; call will abort at runtime}}
+ (void)typeid(get_base(base)); // expected-warning{{cannot pass object of non-POD type 'Base' through variadic function; call will abort at runtime}} expected-warning{{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
(void)typeid(eat_base(base)); // okay
}
diff --git a/test/SemaCXX/vtable-instantiation.cc b/test/SemaCXX/vtable-instantiation.cpp
index 2a1b98900647..78f2b3ed1a2a 100644
--- a/test/SemaCXX/vtable-instantiation.cc
+++ b/test/SemaCXX/vtable-instantiation.cpp
@@ -41,7 +41,7 @@ namespace PR9325 {
void f()
{
- Target<int*>* traits = &Provider<int*>::Instance;
+ Target<int*>* traits = &Provider<int*>::Instance; // expected-note{{requested here}}
}
}
@@ -60,7 +60,7 @@ namespace PR10020 {
};
template <typename Type>
- GMG<Type> GMG<Type>::singleton;
+ GMG<Type> GMG<Type>::singleton; // expected-note{{requested here}}
void test(void) {
GMG<int>::Method(); // expected-note{{in instantiation of}}
diff --git a/test/SemaCXX/warn-bool-conversion.cpp b/test/SemaCXX/warn-bool-conversion.cpp
index b4628947f06e..b0c8d0d19d14 100644
--- a/test/SemaCXX/warn-bool-conversion.cpp
+++ b/test/SemaCXX/warn-bool-conversion.cpp
@@ -118,3 +118,30 @@ namespace Pointer {
// expected-warning@-1{{address of 'S::a' will always evaluate to 'true'}}
}
}
+
+namespace macros {
+ #define assert(x) if (x) {}
+ #define zero_on_null(x) ((x) ? *(x) : 0)
+
+ int array[5];
+ void fun();
+ int x;
+
+ void test() {
+ assert(array);
+ assert(array && "expecting null pointer");
+ // expected-warning@-1{{address of array 'array' will always evaluate to 'true'}}
+
+ assert(fun);
+ assert(fun && "expecting null pointer");
+ // expected-warning@-1{{address of function 'fun' will always evaluate to 'true'}}
+ // expected-note@-2 {{prefix with the address-of operator to silence this warning}}
+
+ // TODO: warn on assert(&x) while not warning on zero_on_null(&x)
+ zero_on_null(&x);
+ assert(zero_on_null(&x));
+ assert(&x);
+ assert(&x && "expecting null pointer");
+ // expected-warning@-1{{address of 'x' will always evaluate to 'true'}}
+ }
+}
diff --git a/test/SemaCXX/warn-consumed-parsing.cpp b/test/SemaCXX/warn-consumed-parsing.cpp
index 5c0a04fffe36..179604141b7b 100644
--- a/test/SemaCXX/warn-consumed-parsing.cpp
+++ b/test/SemaCXX/warn-consumed-parsing.cpp
@@ -37,6 +37,7 @@ class CONSUMABLE(unknown) AttrTester1 {
void callableWhen0() CALLABLE_WHEN("unconsumed");
void callableWhen1() CALLABLE_WHEN(42); // expected-error {{'callable_when' attribute requires a string}}
void callableWhen2() CALLABLE_WHEN("foo"); // expected-warning {{'callable_when' attribute argument not supported: foo}}
+ void callableWhen3() CALLABLE_WHEN(unconsumed);
void consumes() SET_TYPESTATE(consumed);
bool testUnconsumed() TEST_TYPESTATE(consumed);
};
diff --git a/test/SemaCXX/warn-global-constructors.cpp b/test/SemaCXX/warn-global-constructors.cpp
index 90d8558666c3..856826414a8b 100644
--- a/test/SemaCXX/warn-global-constructors.cpp
+++ b/test/SemaCXX/warn-global-constructors.cpp
@@ -120,3 +120,9 @@ namespace pr19253 {
};
E e;
}
+
+namespace pr20420 {
+// No warning is expected. This used to crash.
+void *array_storage[1];
+const int &global_reference = *(int *)array_storage;
+}
diff --git a/test/SemaCXX/warn-overloaded-virtual.cpp b/test/SemaCXX/warn-overloaded-virtual.cpp
index 629d59dee537..6204826192d7 100644
--- a/test/SemaCXX/warn-overloaded-virtual.cpp
+++ b/test/SemaCXX/warn-overloaded-virtual.cpp
@@ -48,8 +48,8 @@ struct Base {
void Base::foo(int) { }
struct Derived : public Base {
- virtual void foo(int);
- void foo(int, int);
+ virtual void foo(int);
+ void foo(int, int);
};
}
@@ -138,3 +138,21 @@ namespace {
// expected-warning@-1{{hides overloaded virtual functions}}
};
}
+
+namespace {
+struct base {
+ void f(char) {}
+};
+
+struct derived : base {
+ void f(int) {}
+};
+
+void foo(derived &d) {
+ d.f('1'); // FIXME: this should warn about calling (anonymous namespace)::derived::f(int)
+ // instead of (anonymous namespace)::base::f(char).
+ // Note: this should be under a new diagnostic flag and eventually moved to a
+ // new test case since it's not strictly related to virtual functions.
+ d.f(12); // This should not warn.
+}
+}
diff --git a/test/SemaCXX/warn-self-move.cpp b/test/SemaCXX/warn-self-move.cpp
new file mode 100644
index 000000000000..23778c187113
--- /dev/null
+++ b/test/SemaCXX/warn-self-move.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fsyntax-only -Wself-move -std=c++11 -verify %s
+
+// definitions for std::move
+namespace std {
+inline namespace foo {
+template <class T> struct remove_reference { typedef T type; };
+template <class T> struct remove_reference<T&> { typedef T type; };
+template <class T> struct remove_reference<T&&> { typedef T type; };
+
+template <class T> typename remove_reference<T>::type &&move(T &&t);
+}
+}
+
+void int_test() {
+ int x = 5;
+ x = std::move(x); // expected-warning{{explicitly moving}}
+ (x) = std::move(x); // expected-warning{{explicitly moving}}
+
+ using std::move;
+ x = move(x); // expected-warning{{explicitly moving}}
+}
+
+int global;
+void global_int_test() {
+ global = std::move(global); // expected-warning{{explicitly moving}}
+ (global) = std::move(global); // expected-warning{{explicitly moving}}
+
+ using std::move;
+ global = move(global); // expected-warning{{explicitly moving}}
+}
+
+class field_test {
+ int x;
+ field_test(field_test&& other) {
+ x = std::move(x); // expected-warning{{explicitly moving}}
+ x = std::move(other.x);
+ other.x = std::move(x);
+ other.x = std::move(other.x); // expected-warning{{explicitly moving}}
+ }
+};
+
+struct A {};
+struct B { A a; };
+struct C { C() {}; ~C() {} };
+void struct_test() {
+ A a;
+ a = std::move(a); // expected-warning{{explicitly moving}}
+
+ B b;
+ b = std::move(b); // expected-warning{{explicitly moving}}
+ b.a = std::move(b.a); // expected-warning{{explicitly moving}}
+
+ C c;
+ c = std::move(c); // expected-warning{{explicitly moving}}
+}
diff --git a/test/SemaCXX/warn-tautological-compare.cpp b/test/SemaCXX/warn-tautological-compare.cpp
index b44f3f9d8fa3..7d5b4b14e998 100644
--- a/test/SemaCXX/warn-tautological-compare.cpp
+++ b/test/SemaCXX/warn-tautological-compare.cpp
@@ -136,3 +136,43 @@ namespace PointerCompare {
// expected-warning@-1{{comparison of address of 'S::a' equal to a null pointer is always false}}
}
}
+
+namespace macros {
+ #define assert(x) if (x) {}
+ int array[5];
+ void fun();
+ int x;
+
+ void test() {
+ assert(array == 0);
+ // expected-warning@-1{{comparison of array 'array' equal to a null pointer is always false}}
+ assert(array != 0);
+ // expected-warning@-1{{comparison of array 'array' not equal to a null pointer is always true}}
+ assert(array == 0 && "expecting null pointer");
+ // expected-warning@-1{{comparison of array 'array' equal to a null pointer is always false}}
+ assert(array != 0 && "expecting non-null pointer");
+ // expected-warning@-1{{comparison of array 'array' not equal to a null pointer is always true}}
+
+ assert(fun == 0);
+ // expected-warning@-1{{comparison of function 'fun' equal to a null pointer is always false}}
+ // expected-note@-2{{prefix with the address-of operator to silence this warning}}
+ assert(fun != 0);
+ // expected-warning@-1{{comparison of function 'fun' not equal to a null pointer is always true}}
+ // expected-note@-2{{prefix with the address-of operator to silence this warning}}
+ assert(fun == 0 && "expecting null pointer");
+ // expected-warning@-1{{comparison of function 'fun' equal to a null pointer is always false}}
+ // expected-note@-2{{prefix with the address-of operator to silence this warning}}
+ assert(fun != 0 && "expecting non-null pointer");
+ // expected-warning@-1{{comparison of function 'fun' not equal to a null pointer is always true}}
+ // expected-note@-2{{prefix with the address-of operator to silence this warning}}
+
+ assert(&x == 0);
+ // expected-warning@-1{{comparison of address of 'x' equal to a null pointer is always false}}
+ assert(&x != 0);
+ // expected-warning@-1{{comparison of address of 'x' not equal to a null pointer is always true}}
+ assert(&x == 0 && "expecting null pointer");
+ // expected-warning@-1{{comparison of address of 'x' equal to a null pointer is always false}}
+ assert(&x != 0 && "expecting non-null pointer");
+ // expected-warning@-1{{comparison of address of 'x' not equal to a null pointer is always true}}
+ }
+}
diff --git a/test/SemaCXX/warn-tautological-undefined-compare.cpp b/test/SemaCXX/warn-tautological-undefined-compare.cpp
index ce05bfc14d17..9321c0edbd3a 100644
--- a/test/SemaCXX/warn-tautological-undefined-compare.cpp
+++ b/test/SemaCXX/warn-tautological-undefined-compare.cpp
@@ -110,3 +110,31 @@ namespace function_return_reference {
// expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
}
}
+
+namespace macros {
+ #define assert(x) if (x) {}
+
+ void test(int &x) {
+ assert(&x != 0);
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ assert(&x == 0);
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+ assert(&x != 0 && "Expecting valid reference");
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ assert(&x == 0 && "Expecting invalid reference");
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+ }
+
+ class S {
+ void test() {
+ assert(this != 0);
+ // expected-warning@-1{{'this' pointer cannot be null in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ assert(this == 0);
+ // expected-warning@-1{{'this' pointer cannot be null in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+ assert(this != 0 && "Expecting valid reference");
+ // expected-warning@-1{{'this' pointer cannot be null in well-defined C++ code; comparison may be assumed to always evaluate to true}}
+ assert(this == 0 && "Expecting invalid reference");
+ // expected-warning@-1{{'this' pointer cannot be null in well-defined C++ code; comparison may be assumed to always evaluate to false}}
+ }
+ };
+}
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index 34a33aab42d2..091e47335b57 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions %s
// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 -Wc++98-compat %s
// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
@@ -36,6 +36,9 @@ class __attribute__((lockable)) Mutex {
bool ReaderTryLock() __attribute__((shared_trylock_function(true)));
void LockWhen(const int &cond) __attribute__((exclusive_lock_function));
+ // for negative capabilities
+ const Mutex& operator!() const { return *this; }
+
void AssertHeld() ASSERT_EXCLUSIVE_LOCK();
void AssertReaderHeld() ASSERT_SHARED_LOCK();
};
@@ -60,6 +63,12 @@ class SCOPED_LOCKABLE ReleasableMutexLock {
void Release() UNLOCK_FUNCTION();
};
+class __attribute__((scoped_lockable)) DoubleMutexLock {
+public:
+ DoubleMutexLock(Mutex *mu1, Mutex *mu2)
+ __attribute__((exclusive_lock_function(mu1, mu2)));
+ ~DoubleMutexLock() __attribute__((unlock_function));
+};
// The universal lock, written "*", allows checking to be selectively turned
// off for a particular piece of code.
@@ -95,6 +104,37 @@ public:
};
+// For testing operator overloading
+template <class K, class T>
+class MyMap {
+public:
+ T& operator[](const K& k);
+};
+
+
+// For testing handling of containers.
+template <class T>
+class MyContainer {
+public:
+ MyContainer();
+
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+ T* begin();
+ T* end();
+
+ const T* cbegin();
+ const T* cend();
+
+ T& operator[](int i);
+ const T& operator[](int i) const;
+
+private:
+ T* ptr_;
+};
+
+
Mutex sls_mu;
@@ -1628,6 +1668,12 @@ struct TestScopedLockable {
a = b+1;
b = a+1;
}
+
+ void foo5() {
+ DoubleMutexLock mulock(&mu1, &mu2);
+ a = b + 1;
+ b = a + 1;
+ }
};
} // end namespace test_scoped_lockable
@@ -2280,6 +2326,15 @@ void test() {
(a > 0 ? fooArray[1] : fooArray[b]).mu_.Lock();
(a > 0 ? fooArray[1] : fooArray[b]).a = 0;
(a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock();
+}
+
+
+void test2() {
+ Foo *fooArray;
+ Bar bar;
+ int a;
+ int b;
+ int c;
bar.getFoo().mu_.Lock();
bar.getFooey().a = 0; // \
@@ -2295,20 +2350,20 @@ void test() {
bar.getFoo3(a, b).mu_.Lock();
bar.getFoo3(a, c).a = 0; // \
- // expected-warning {{writing variable 'a' requires holding mutex 'bar.getFoo3(a,c).mu_' exclusively}} \
- // expected-note {{'bar.getFoo3(a,b).mu_'}}
+ // expected-warning {{writing variable 'a' requires holding mutex 'bar.getFoo3(a, c).mu_' exclusively}} \
+ // expected-note {{found near match 'bar.getFoo3(a, b).mu_'}}
bar.getFoo3(a, b).mu_.Unlock();
getBarFoo(bar, a).mu_.Lock();
getBarFoo(bar, b).a = 0; // \
- // expected-warning {{writing variable 'a' requires holding mutex 'getBarFoo(bar,b).mu_' exclusively}} \
- // expected-note {{'getBarFoo(bar,a).mu_'}}
+ // expected-warning {{writing variable 'a' requires holding mutex 'getBarFoo(bar, b).mu_' exclusively}} \
+ // expected-note {{found near match 'getBarFoo(bar, a).mu_'}}
getBarFoo(bar, a).mu_.Unlock();
(a > 0 ? fooArray[1] : fooArray[b]).mu_.Lock();
(a > 0 ? fooArray[b] : fooArray[c]).a = 0; // \
- // expected-warning {{writing variable 'a' requires holding mutex '((a#_)#_#fooArray[b]).mu_' exclusively}} \
- // expected-note {{'((a#_)#_#fooArray[_]).mu_'}}
+ // expected-warning {{writing variable 'a' requires holding mutex '((0 < a) ? fooArray[b] : fooArray[c]).mu_' exclusively}} \
+ // expected-note {{found near match '((0 < a) ? fooArray[1] : fooArray[b]).mu_'}}
(a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock();
}
@@ -4378,3 +4433,418 @@ class Foo {
};
} // end namespace ThreadAttributesOnLambdas
+
+
+
+namespace AttributeExpressionCornerCases {
+
+class Foo {
+ int a GUARDED_BY(getMu());
+
+ Mutex* getMu() LOCK_RETURNED("");
+ Mutex* getUniv() LOCK_RETURNED("*");
+
+ void test1() {
+ a = 0;
+ }
+
+ void test2() EXCLUSIVE_LOCKS_REQUIRED(getUniv()) {
+ a = 0;
+ }
+
+ void foo(Mutex* mu) EXCLUSIVE_LOCKS_REQUIRED(mu);
+
+ void test3() {
+ foo(nullptr);
+ }
+};
+
+
+class MapTest {
+ struct MuCell { Mutex* mu; };
+
+ MyMap<MyString, Mutex*> map;
+ MyMap<MyString, MuCell> mapCell;
+
+ int a GUARDED_BY(map["foo"]);
+ int b GUARDED_BY(mapCell["foo"].mu);
+
+ void test() {
+ map["foo"]->Lock();
+ a = 0;
+ map["foo"]->Unlock();
+ }
+
+ void test2() {
+ mapCell["foo"].mu->Lock();
+ b = 0;
+ mapCell["foo"].mu->Unlock();
+ }
+};
+
+
+class PreciseSmartPtr {
+ SmartPtr<Mutex> mu;
+ int val GUARDED_BY(mu);
+
+ static bool compare(PreciseSmartPtr& a, PreciseSmartPtr &b) {
+ a.mu->Lock();
+ bool result = (a.val == b.val); // expected-warning {{reading variable 'val' requires holding mutex 'b.mu'}} \
+ // expected-note {{found near match 'a.mu'}}
+ a.mu->Unlock();
+ return result;
+ }
+};
+
+
+class SmartRedeclare {
+ SmartPtr<Mutex> mu;
+ int val GUARDED_BY(mu);
+
+ void test() EXCLUSIVE_LOCKS_REQUIRED(mu);
+ void test2() EXCLUSIVE_LOCKS_REQUIRED(mu.get());
+ void test3() EXCLUSIVE_LOCKS_REQUIRED(mu.get());
+};
+
+
+void SmartRedeclare::test() EXCLUSIVE_LOCKS_REQUIRED(mu.get()) {
+ val = 0;
+}
+
+void SmartRedeclare::test2() EXCLUSIVE_LOCKS_REQUIRED(mu) {
+ val = 0;
+}
+
+void SmartRedeclare::test3() {
+ val = 0;
+}
+
+
+namespace CustomMutex {
+
+
+class LOCKABLE BaseMutex { };
+class DerivedMutex : public BaseMutex { };
+
+void customLock(const BaseMutex *m) EXCLUSIVE_LOCK_FUNCTION(m);
+void customUnlock(const BaseMutex *m) UNLOCK_FUNCTION(m);
+
+static struct DerivedMutex custMu;
+
+static void doSomethingRequiringLock() EXCLUSIVE_LOCKS_REQUIRED(custMu) { }
+
+void customTest() {
+ customLock(reinterpret_cast<BaseMutex*>(&custMu)); // ignore casts
+ doSomethingRequiringLock();
+ customUnlock(reinterpret_cast<BaseMutex*>(&custMu));
+}
+
+} // end namespace CustomMutex
+
+} // end AttributeExpressionCornerCases
+
+
+namespace ScopedLockReturnedInvalid {
+
+class Opaque;
+
+Mutex* getMutex(Opaque* o) LOCK_RETURNED("");
+
+void test(Opaque* o) {
+ MutexLock lock(getMutex(o));
+}
+
+} // end namespace ScopedLockReturnedInvalid
+
+
+namespace NegativeRequirements {
+
+class Bar {
+ Mutex mu;
+ int a GUARDED_BY(mu);
+
+public:
+ void baz() EXCLUSIVE_LOCKS_REQUIRED(!mu) {
+ mu.Lock();
+ a = 0;
+ mu.Unlock();
+ }
+};
+
+
+class Foo {
+ Mutex mu;
+ int a GUARDED_BY(mu);
+
+public:
+ void foo() {
+ mu.Lock(); // warning? needs !mu?
+ baz(); // expected-warning {{cannot call function 'baz' while mutex 'mu' is held}}
+ bar();
+ mu.Unlock();
+ }
+
+ void bar() {
+ bar2(); // expected-warning {{calling function 'bar2' requires holding '!mu'}}
+ }
+
+ void bar2() EXCLUSIVE_LOCKS_REQUIRED(!mu) {
+ baz();
+ }
+
+ void baz() EXCLUSIVE_LOCKS_REQUIRED(!mu) {
+ mu.Lock();
+ a = 0;
+ mu.Unlock();
+ }
+
+ void test() {
+ Bar b;
+ b.baz(); // no warning -- in different class.
+ }
+};
+
+} // end namespace NegativeRequirements
+
+
+namespace NegativeThreadRoles {
+
+typedef int __attribute__((capability("role"))) ThreadRole;
+
+void acquire(ThreadRole R) __attribute__((exclusive_lock_function(R))) __attribute__((no_thread_safety_analysis)) {}
+void release(ThreadRole R) __attribute__((unlock_function(R))) __attribute__((no_thread_safety_analysis)) {}
+
+ThreadRole FlightControl, Logger;
+
+extern void enque_log_msg(const char *msg);
+void log_msg(const char *msg) {
+ enque_log_msg(msg);
+}
+
+void dispatch_log(const char *msg) __attribute__((requires_capability(!FlightControl))) {}
+void dispatch_log2(const char *msg) __attribute__((requires_capability(Logger))) {}
+
+void flight_control_entry(void) __attribute__((requires_capability(FlightControl))) {
+ dispatch_log("wrong"); /* expected-warning {{cannot call function 'dispatch_log' while mutex 'FlightControl' is held}} */
+ dispatch_log2("also wrong"); /* expected-warning {{calling function 'dispatch_log2' requires holding role 'Logger' exclusively}} */
+}
+
+void spawn_fake_flight_control_thread(void) {
+ acquire(FlightControl);
+ flight_control_entry();
+ release(FlightControl);
+}
+
+extern const char *deque_log_msg(void) __attribute__((requires_capability(Logger)));
+void logger_entry(void) __attribute__((requires_capability(Logger))) {
+ const char *msg;
+
+ while ((msg = deque_log_msg())) {
+ dispatch_log(msg);
+ }
+}
+
+void spawn_fake_logger_thread(void) {
+ acquire(Logger);
+ logger_entry();
+ release(Logger);
+}
+
+int main(void) {
+ spawn_fake_flight_control_thread();
+ spawn_fake_logger_thread();
+
+ for (;;)
+ ; /* Pretend to dispatch things. */
+
+ return 0;
+}
+
+} // end namespace NegativeThreadRoles
+
+
+namespace AssertSharedExclusive {
+
+void doSomething();
+
+class Foo {
+ Mutex mu;
+ int a GUARDED_BY(mu);
+
+ void test() SHARED_LOCKS_REQUIRED(mu) {
+ mu.AssertHeld();
+ if (a > 0)
+ doSomething();
+ }
+};
+
+} // end namespace AssertSharedExclusive
+
+
+namespace RangeBasedForAndReferences {
+
+class Foo {
+ struct MyStruct {
+ int a;
+ };
+
+ Mutex mu;
+ int a GUARDED_BY(mu);
+ MyContainer<int> cntr GUARDED_BY(mu);
+ MyStruct s GUARDED_BY(mu);
+ int arr[10] GUARDED_BY(mu);
+
+ void nonref_test() {
+ int b = a; // expected-warning {{reading variable 'a' requires holding mutex 'mu'}}
+ b = 0; // no warning
+ }
+
+ void auto_test() {
+ auto b = a; // expected-warning {{reading variable 'a' requires holding mutex 'mu'}}
+ b = 0; // no warning
+ auto &c = a; // no warning
+ c = 0; // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
+ }
+
+ void ref_test() {
+ int &b = a;
+ int &c = b;
+ int &d = c;
+ b = 0; // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
+ c = 0; // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
+ d = 0; // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
+
+ MyStruct &rs = s;
+ rs.a = 0; // expected-warning {{writing variable 's' requires holding mutex 'mu' exclusively}}
+
+ int (&rarr)[10] = arr;
+ rarr[2] = 0; // expected-warning {{writing variable 'arr' requires holding mutex 'mu' exclusively}}
+ }
+
+ void ptr_test() {
+ int *b = &a;
+ *b = 0; // no expected warning yet
+ }
+
+ void for_test() {
+ int total = 0;
+ for (int i : cntr) { // expected-warning2 {{reading variable 'cntr' requires holding mutex 'mu'}}
+ total += i;
+ }
+ }
+};
+
+
+} // end namespace RangeBasedForAndReferences
+
+
+
+namespace PassByRefTest {
+
+class Foo {
+public:
+ Foo() : a(0), b(0) { }
+
+ int a;
+ int b;
+
+ void operator+(const Foo& f);
+
+ void operator[](const Foo& g);
+};
+
+template<class T>
+T&& mymove(T& f);
+
+
+// test top-level functions
+void copy(Foo f);
+void write1(Foo& f);
+void write2(int a, Foo& f);
+void read1(const Foo& f);
+void read2(int a, const Foo& f);
+void destroy(Foo&& f);
+
+void operator/(const Foo& f, const Foo& g);
+void operator*(const Foo& f, const Foo& g);
+
+
+
+
+class Bar {
+public:
+ Mutex mu;
+ Foo foo GUARDED_BY(mu);
+ Foo foo2 GUARDED_BY(mu);
+ Foo* foop PT_GUARDED_BY(mu);
+ SmartPtr<Foo> foosp PT_GUARDED_BY(mu);
+
+ // test methods.
+ void mwrite1(Foo& f);
+ void mwrite2(int a, Foo& f);
+ void mread1(const Foo& f);
+ void mread2(int a, const Foo& f);
+
+ // static methods
+ static void smwrite1(Foo& f);
+ static void smwrite2(int a, Foo& f);
+ static void smread1(const Foo& f);
+ static void smread2(int a, const Foo& f);
+
+ void operator<<(const Foo& f);
+
+ void test1() {
+ copy(foo); // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}}
+ write1(foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+ write2(10, foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+ read1(foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+ read2(10, foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+ destroy(mymove(foo)); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+
+ mwrite1(foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+ mwrite2(10, foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+ mread1(foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+ mread2(10, foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+
+ smwrite1(foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+ smwrite2(10, foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+ smread1(foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+ smread2(10, foo); // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+
+ foo + foo2; // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}} \
+ // expected-warning {{passing variable 'foo2' by reference requires holding mutex 'mu'}}
+ foo / foo2; // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}} \
+ // expected-warning {{passing variable 'foo2' by reference requires holding mutex 'mu'}}
+ foo * foo2; // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}} \
+ // expected-warning {{passing variable 'foo2' by reference requires holding mutex 'mu'}}
+ foo[foo2]; // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}} \
+ // expected-warning {{passing variable 'foo2' by reference requires holding mutex 'mu'}}
+ (*this) << foo; // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
+
+ copy(*foop); // expected-warning {{reading the value pointed to by 'foop' requires holding mutex 'mu'}}
+ write1(*foop); // expected-warning {{passing the value that 'foop' points to by reference requires holding mutex 'mu'}}
+ write2(10, *foop); // expected-warning {{passing the value that 'foop' points to by reference requires holding mutex 'mu'}}
+ read1(*foop); // expected-warning {{passing the value that 'foop' points to by reference requires holding mutex 'mu'}}
+ read2(10, *foop); // expected-warning {{passing the value that 'foop' points to by reference requires holding mutex 'mu'}}
+ destroy(mymove(*foop)); // expected-warning {{passing the value that 'foop' points to by reference requires holding mutex 'mu'}}
+
+ copy(*foosp); // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
+ write1(*foosp); // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
+ write2(10, *foosp); // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
+ read1(*foosp); // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
+ read2(10, *foosp); // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
+ destroy(mymove(*foosp)); // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
+
+ // TODO -- these requires better smart pointer handling.
+ copy(*foosp.get());
+ write1(*foosp.get());
+ write2(10, *foosp.get());
+ read1(*foosp.get());
+ read2(10, *foosp.get());
+ destroy(mymove(*foosp.get()));
+ }
+};
+
+
+} // end namespace PassByRefTest
+
diff --git a/test/SemaCXX/warn-thread-safety-negative.cpp b/test/SemaCXX/warn-thread-safety-negative.cpp
new file mode 100644
index 000000000000..f88233a60b27
--- /dev/null
+++ b/test/SemaCXX/warn-thread-safety-negative.cpp
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wthread-safety-negative -fcxx-exceptions %s
+
+// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 -Wc++98-compat %s
+// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
+
+#define LOCKABLE __attribute__ ((lockable))
+#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
+#define GUARDED_BY(x) __attribute__ ((guarded_by(x)))
+#define GUARDED_VAR __attribute__ ((guarded_var))
+#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x)))
+#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
+#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
+#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__)))
+#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__ ((assert_exclusive_lock(__VA_ARGS__)))
+#define ASSERT_SHARED_LOCK(...) __attribute__ ((assert_shared_lock(__VA_ARGS__)))
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))
+#define SHARED_TRYLOCK_FUNCTION(...) __attribute__ ((shared_trylock_function(__VA_ARGS__)))
+#define UNLOCK_FUNCTION(...) __attribute__ ((unlock_function(__VA_ARGS__)))
+#define LOCK_RETURNED(x) __attribute__ ((lock_returned(x)))
+#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__)))
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+ __attribute__ ((exclusive_locks_required(__VA_ARGS__)))
+#define SHARED_LOCKS_REQUIRED(...) \
+ __attribute__ ((shared_locks_required(__VA_ARGS__)))
+#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
+
+
+class __attribute__((lockable)) Mutex {
+ public:
+ void Lock() __attribute__((exclusive_lock_function));
+ void ReaderLock() __attribute__((shared_lock_function));
+ void Unlock() __attribute__((unlock_function));
+ bool TryLock() __attribute__((exclusive_trylock_function(true)));
+ bool ReaderTryLock() __attribute__((shared_trylock_function(true)));
+ void LockWhen(const int &cond) __attribute__((exclusive_lock_function));
+
+ // for negative capabilities
+ const Mutex& operator!() const { return *this; }
+
+ void AssertHeld() ASSERT_EXCLUSIVE_LOCK();
+ void AssertReaderHeld() ASSERT_SHARED_LOCK();
+};
+
+
+namespace SimpleTest {
+
+class Bar {
+ Mutex mu;
+ int a GUARDED_BY(mu);
+
+public:
+ void baz() EXCLUSIVE_LOCKS_REQUIRED(!mu) {
+ mu.Lock();
+ a = 0;
+ mu.Unlock();
+ }
+};
+
+
+class Foo {
+ Mutex mu;
+ int a GUARDED_BY(mu);
+
+public:
+ void foo() {
+ mu.Lock(); // expected-warning {{acquiring mutex 'mu' requires negative capability '!mu'}}
+ baz(); // expected-warning {{cannot call function 'baz' while mutex 'mu' is held}}
+ bar();
+ mu.Unlock();
+ }
+
+ void bar() {
+ baz(); // expected-warning {{calling function 'baz' requires holding '!mu'}}
+ }
+
+ void baz() EXCLUSIVE_LOCKS_REQUIRED(!mu) {
+ mu.Lock();
+ a = 0;
+ mu.Unlock();
+ }
+
+ void test() {
+ Bar b;
+ b.baz(); // no warning -- in different class.
+ }
+
+ void test2() {
+ mu.Lock(); // expected-warning {{acquiring mutex 'mu' requires negative capability '!mu'}}
+ a = 0;
+ mu.Unlock();
+ baz(); // no warning -- !mu in set.
+ }
+
+ void test3() EXCLUSIVE_LOCKS_REQUIRED(!mu) {
+ mu.Lock();
+ a = 0;
+ mu.Unlock();
+ baz(); // no warning -- !mu in set.
+ }
+};
+
+} // end namespace SimpleTest
diff --git a/test/SemaCXX/warn-thread-safety-verbose.cpp b/test/SemaCXX/warn-thread-safety-verbose.cpp
new file mode 100644
index 000000000000..4e19f30bf2c3
--- /dev/null
+++ b/test/SemaCXX/warn-thread-safety-verbose.cpp
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wthread-safety-verbose -Wno-thread-safety-negative -fcxx-exceptions %s
+
+#define LOCKABLE __attribute__ ((lockable))
+#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
+#define GUARDED_BY(x) __attribute__ ((guarded_by(x)))
+#define GUARDED_VAR __attribute__ ((guarded_var))
+#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x)))
+#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
+#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
+#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__)))
+#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__ ((assert_exclusive_lock(__VA_ARGS__)))
+#define ASSERT_SHARED_LOCK(...) __attribute__ ((assert_shared_lock(__VA_ARGS__)))
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))
+#define SHARED_TRYLOCK_FUNCTION(...) __attribute__ ((shared_trylock_function(__VA_ARGS__)))
+#define UNLOCK_FUNCTION(...) __attribute__ ((unlock_function(__VA_ARGS__)))
+#define LOCK_RETURNED(x) __attribute__ ((lock_returned(x)))
+#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__)))
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+ __attribute__ ((exclusive_locks_required(__VA_ARGS__)))
+#define SHARED_LOCKS_REQUIRED(...) \
+ __attribute__ ((shared_locks_required(__VA_ARGS__)))
+#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
+
+
+class __attribute__((lockable)) Mutex {
+ public:
+ void Lock() __attribute__((exclusive_lock_function));
+ void ReaderLock() __attribute__((shared_lock_function));
+ void Unlock() __attribute__((unlock_function));
+ bool TryLock() __attribute__((exclusive_trylock_function(true)));
+ bool ReaderTryLock() __attribute__((shared_trylock_function(true)));
+ void LockWhen(const int &cond) __attribute__((exclusive_lock_function));
+
+ // for negative capabilities
+ const Mutex& operator!() const { return *this; }
+
+ void AssertHeld() ASSERT_EXCLUSIVE_LOCK();
+ void AssertReaderHeld() ASSERT_SHARED_LOCK();
+};
+
+
+class Test {
+ Mutex mu;
+ int a GUARDED_BY(mu); // expected-note3 {{Guarded_by declared here.}}
+
+ void foo1() EXCLUSIVE_LOCKS_REQUIRED(mu);
+ void foo2() SHARED_LOCKS_REQUIRED(mu);
+ void foo3() LOCKS_EXCLUDED(mu);
+
+ void test1() { // expected-note {{Thread warning in function 'test1'}}
+ a = 0; // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
+ }
+
+ void test2() { // expected-note {{Thread warning in function 'test2'}}
+ int b = a; // expected-warning {{reading variable 'a' requires holding mutex 'mu'}}
+ }
+
+ void test3() { // expected-note {{Thread warning in function 'test3'}}
+ foo1(); // expected-warning {{calling function 'foo1' requires holding mutex 'mu' exclusively}}
+ }
+
+ void test4() { // expected-note {{Thread warning in function 'test4'}}
+ foo2(); // expected-warning {{calling function 'foo2' requires holding mutex 'mu'}}
+ }
+
+ void test5() { // expected-note {{Thread warning in function 'test5'}}
+ mu.ReaderLock();
+ foo1(); // expected-warning {{calling function 'foo1' requires holding mutex 'mu' exclusively}}
+ mu.Unlock();
+ }
+
+ void test6() { // expected-note {{Thread warning in function 'test6'}}
+ mu.ReaderLock();
+ a = 0; // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
+ mu.Unlock();
+ }
+
+ void test7() { // expected-note {{Thread warning in function 'test7'}}
+ mu.Lock();
+ foo3(); // expected-warning {{cannot call function 'foo3' while mutex 'mu' is held}}
+ mu.Unlock();
+ }
+};
+
diff --git a/test/SemaCXX/warn-undefined-bool-conversion.cpp b/test/SemaCXX/warn-undefined-bool-conversion.cpp
index 1f8baa0e8d8a..24099f79adc5 100644
--- a/test/SemaCXX/warn-undefined-bool-conversion.cpp
+++ b/test/SemaCXX/warn-undefined-bool-conversion.cpp
@@ -95,3 +95,27 @@ namespace function_return_reference {
// expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
}
}
+
+namespace macros {
+ #define assert(x) if (x) {}
+ #define zero_on_null(x) ((x) ? *(x) : 0)
+
+ void test(int &x) {
+ // TODO: warn on assert(&x) but not on zero_on_null(&x)
+ zero_on_null(&x);
+ assert(zero_on_null(&x));
+ assert(&x);
+
+ assert(&x && "Expecting valid reference");
+ // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true}}
+ }
+
+ class S {
+ void test() {
+ assert(this);
+
+ assert(this && "Expecting invalid reference");
+ // expected-warning@-1{{'this' pointer cannot be null in well-defined C++ code; pointer may be assumed to always convert to true}}
+ }
+ };
+}
diff --git a/test/SemaCXX/warn-unused-comparison.cpp b/test/SemaCXX/warn-unused-comparison.cpp
index 3afad585b668..a24b5a29a3df 100644
--- a/test/SemaCXX/warn-unused-comparison.cpp
+++ b/test/SemaCXX/warn-unused-comparison.cpp
@@ -83,6 +83,8 @@ void test() {
#define EQ(x,y) (x) == (y)
EQ(x, 5);
#undef EQ
+
+ (void)sizeof(1 < 2, true); // No warning; unevaluated context.
}
namespace PR10291 {
diff --git a/test/SemaCXX/warn-unused-filescoped.cpp b/test/SemaCXX/warn-unused-filescoped.cpp
index df4c47e71787..18defee7d04a 100644
--- a/test/SemaCXX/warn-unused-filescoped.cpp
+++ b/test/SemaCXX/warn-unused-filescoped.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -Wno-c++11-extensions -std=c++98 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -Wno-unused-local-typedefs -Wno-c++11-extensions -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -Wno-unused-local-typedefs -std=c++11 %s
#ifdef HEADER
diff --git a/test/SemaCXX/warn-unused-local-typedef-serialize.cpp b/test/SemaCXX/warn-unused-local-typedef-serialize.cpp
new file mode 100644
index 000000000000..aa2c48bb5719
--- /dev/null
+++ b/test/SemaCXX/warn-unused-local-typedef-serialize.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang -x c++-header -c -Wunused-local-typedef %s -o %t.gch -Werror
+// RUN: %clang -DBE_THE_SOURCE -c -Wunused-local-typedef -include %t %s -o /dev/null 2>&1 | FileCheck %s
+// RUN: %clang -DBE_THE_SOURCE -c -Wunused-local-typedef -include %t %s -o /dev/null 2>&1 | FileCheck %s
+
+#ifndef BE_THE_SOURCE
+inline void myfun() {
+// The warning should fire every time the pch file is used, not when it's built.
+// CHECK: warning: unused typedef
+ typedef int a;
+}
+#endif
diff --git a/test/SemaCXX/warn-unused-local-typedef-x86asm.cpp b/test/SemaCXX/warn-unused-local-typedef-x86asm.cpp
new file mode 100644
index 000000000000..d7792c0e11eb
--- /dev/null
+++ b/test/SemaCXX/warn-unused-local-typedef-x86asm.cpp
@@ -0,0 +1,16 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -std=c++11 -Wunused-local-typedef -verify -fasm-blocks %s
+// expected-no-diagnostics
+void use_in_asm() {
+ typedef struct {
+ int a;
+ int b;
+ } A;
+ __asm mov eax, [eax].A.b
+
+ using Alias = struct {
+ int a;
+ int b;
+ };
+ __asm mov eax, [eax].Alias.b
+}
diff --git a/test/SemaCXX/warn-unused-local-typedef.cpp b/test/SemaCXX/warn-unused-local-typedef.cpp
new file mode 100644
index 000000000000..a9406531d2d7
--- /dev/null
+++ b/test/SemaCXX/warn-unused-local-typedef.cpp
@@ -0,0 +1,242 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-local-typedef -verify -std=c++1y %s
+
+struct S {
+ typedef int Foo; // no diag
+};
+
+namespace N {
+ typedef int Foo; // no diag
+ typedef int Foo2; // no diag
+}
+
+template <class T> class Vec {};
+
+typedef int global_foo; // no diag
+
+void f() {
+ typedef int foo0; // expected-warning {{unused typedef 'foo0'}}
+ using foo0alias = int ; // expected-warning {{unused type alias 'foo0alias'}}
+
+ typedef int foo1 __attribute__((unused)); // no diag
+
+ typedef int foo2;
+ {
+ typedef int foo2; // expected-warning {{unused typedef 'foo2'}}
+ }
+ typedef foo2 foo3; // expected-warning {{unused typedef 'foo3'}}
+
+ typedef int foo2_2; // expected-warning {{unused typedef 'foo2_2'}}
+ {
+ typedef int foo2_2;
+ typedef foo2_2 foo3_2; // expected-warning {{unused typedef 'foo3_2'}}
+ }
+
+ typedef int foo4;
+ foo4 the_thing;
+
+ typedef int* foo5;
+ typedef foo5* foo6; // no diag
+ foo6 *myptr;
+
+ struct S2 {
+ typedef int Foo; // no diag
+ typedef int Foo2; // expected-warning {{unused typedef 'Foo2'}}
+
+ struct Deeper {
+ typedef int DeepFoo; // expected-warning {{unused typedef 'DeepFoo'}}
+ };
+ };
+
+ S2::Foo s2foo;
+
+ typedef struct {} foostruct; // expected-warning {{unused typedef 'foostruct'}}
+
+ typedef struct {} foostruct2; // no diag
+ foostruct2 fs2;
+
+ typedef int vecint; // no diag
+ Vec<vecint> v;
+
+ N::Foo nfoo;
+
+ typedef int ConstExprInt;
+ static constexpr int a = (ConstExprInt)4;
+}
+
+int printf(char const *, ...);
+
+void test() {
+ typedef signed long int superint; // no diag
+ printf("%f", (superint) 42);
+
+ typedef signed long int superint2; // no diag
+ printf("%f", static_cast<superint2>(42));
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-local-typedef"
+ typedef int trungl_bot_was_here; // no diag
+#pragma clang diagnostic pop
+
+ typedef int foo; // expected-warning {{unused typedef 'foo'}}
+}
+
+template <class T>
+void template_fun(T t) {
+ typedef int foo; // expected-warning {{unused typedef 'foo'}}
+ typedef int bar; // no-diag
+ bar asdf;
+
+ struct S2 {
+ typedef int Foo; // no diag
+
+ typedef int Foo2; // expected-warning {{unused typedef 'Foo2'}}
+
+ typedef int Foo3; // no diag
+ };
+
+ typename S2::Foo s2foo;
+ typename T::Foo s3foo;
+
+ typedef typename S2::Foo3 TTSF; // expected-warning {{unused typedef 'TTSF'}}
+}
+void template_fun_user() {
+ struct Local {
+ typedef int Foo; // no-diag
+ typedef int Bar; // expected-warning {{unused typedef 'Bar'}}
+ } p;
+ template_fun(p);
+}
+
+void typedef_in_nested_name() {
+ typedef struct {
+ typedef int Foo;
+ } A;
+ A::Foo adsf;
+
+ using A2 = struct {
+ typedef int Foo;
+ };
+ A2::Foo adsf2;
+}
+
+auto sneaky() {
+ struct S {
+ // Local typedefs can be used after the scope they were in has closed:
+ typedef int t;
+
+ // Even if they aren't, this could be an inline function that could be used
+ // in another TU, so this shouldn't warn either:
+ typedef int s;
+
+ private:
+ typedef int p; // expected-warning{{unused typedef 'p'}}
+ };
+ return S();
+}
+auto x = sneaky();
+decltype(x)::t y;
+
+static auto static_sneaky() {
+ struct S {
+ typedef int t;
+ // This function has internal linkage, so we can warn:
+ typedef int s; // expected-warning {{unused typedef 's'}}
+ };
+ return S();
+}
+auto sx = static_sneaky();
+decltype(sx)::t sy;
+
+auto sneaky_with_friends() {
+ struct S {
+ private:
+ friend class G;
+ // Can't warn if we have friends:
+ typedef int p;
+ };
+ return S();
+}
+
+namespace {
+auto nstatic_sneaky() {
+ struct S {
+ typedef int t;
+ // This function has internal linkage, so we can warn:
+ typedef int s; // expected-warning {{unused typedef 's'}}
+ };
+ return S();
+}
+auto nsx = nstatic_sneaky();
+decltype(nsx)::t nsy;
+}
+
+// Like sneaky(), but returning pointer to local type
+template<typename T>
+struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T&> { typedef T type; };
+auto pointer_sneaky() {
+ struct S {
+ typedef int t;
+ typedef int s;
+ };
+ return (S*)nullptr;
+}
+remove_reference<decltype(*pointer_sneaky())>::type::t py;
+
+// Like sneaky(), but returning templated struct referencing local type.
+template <class T> struct container { int a; T t; };
+auto template_sneaky() {
+ struct S {
+ typedef int t;
+ typedef int s;
+ };
+ return container<S>();
+}
+auto tx = template_sneaky();
+decltype(tx.t)::t ty;
+
+// Like sneaky(), but doing its sneakiness by returning a member function
+// pointer.
+auto sneaky_memfun() {
+ struct S {
+ typedef int type;
+ int n;
+ };
+ return &S::n;
+}
+
+template <class T> void sneaky_memfun_g(int T::*p) {
+ typename T::type X;
+}
+
+void sneaky_memfun_h() {
+ sneaky_memfun_g(sneaky_memfun());
+}
+
+void typedefs_in_constructors() {
+ struct A {};
+ struct B : public A {
+ // Neither of these two should warn:
+ typedef A INHERITED;
+ B() : INHERITED() {}
+
+ typedef B SELF;
+ B(int) : SELF() {}
+ };
+}
+
+void *operator new(__SIZE_TYPE__, void *p) throw() { return p; }
+void placement_new_and_delete() {
+ struct MyStruct { };
+ char memory[sizeof(MyStruct)];
+ void *p = memory;
+
+ typedef MyStruct A_t1;
+ MyStruct *a = new (p) A_t1();
+
+ typedef MyStruct A_t2;
+ a->~A_t2();
+}
+
+// This should not disable any warnings:
+#pragma clang diagnostic ignored "-Wunused-local-typedef"
diff --git a/test/SemaCXX/warn-unused-private-field-delayed-template.cpp b/test/SemaCXX/warn-unused-private-field-delayed-template.cpp
new file mode 100644
index 000000000000..7cafcca643f5
--- /dev/null
+++ b/test/SemaCXX/warn-unused-private-field-delayed-template.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -fdelayed-template-parsing -Wunused-private-field -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++11 %s
+// expected-no-diagnostics
+
+class EverythingMayBeUsed {
+ int x;
+public:
+ template <class T>
+ void f() {
+ x = 0;
+ }
+};
diff --git a/test/SemaCXX/warn-unused-result.cpp b/test/SemaCXX/warn-unused-result.cpp
index 581af09080db..7bdb4245a95a 100644
--- a/test/SemaCXX/warn-unused-result.cpp
+++ b/test/SemaCXX/warn-unused-result.cpp
@@ -94,3 +94,50 @@ void Bar() {
};
}
+
+namespace PR18571 {
+// Unevaluated contexts should not trigger unused result warnings.
+template <typename T>
+auto foo(T) -> decltype(f(), bool()) { // Should not warn.
+ return true;
+}
+
+void g() {
+ foo(1);
+}
+}
+
+namespace std {
+class type_info { };
+}
+
+namespace {
+// The typeid expression operand is evaluated only when the expression type is
+// a glvalue of polymorphic class type.
+
+struct B {
+ virtual void f() {}
+};
+
+struct D : B {
+ void f() override {}
+};
+
+struct C {};
+
+void g() {
+ // The typeid expression operand is evaluated only when the expression type is
+ // a glvalue of polymorphic class type; otherwise the expression operand is not
+ // evaluated and should not trigger a diagnostic.
+ D d;
+ C c;
+ (void)typeid(f(), c); // Should not warn.
+ (void)typeid(f(), d); // expected-warning {{ignoring return value}} expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
+
+ // The sizeof expression operand is never evaluated.
+ (void)sizeof(f(), c); // Should not warn.
+
+ // The noexcept expression operand is never evaluated.
+ (void)noexcept(f(), false); // Should not warn.
+}
+}
diff --git a/test/SemaCXX/warn-unused-value-cxx11.cpp b/test/SemaCXX/warn-unused-value-cxx11.cpp
new file mode 100644
index 000000000000..d929b4fd12fb
--- /dev/null
+++ b/test/SemaCXX/warn-unused-value-cxx11.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wunused-value %s
+
+void f() __attribute__((const));
+
+namespace PR18571 {
+// Unevaluated contexts should not trigger unused result warnings.
+template <typename T>
+auto foo(T) -> decltype(f(), bool()) { // Should not warn.
+ return true;
+}
+
+void g() {
+ foo(1);
+}
+
+void h() {
+ int i = 0;
+ (void)noexcept(++i); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
+ decltype(i++) j = 0; // expected-warning {{expression with side effects has no effect in an unevaluated context}}
+}
+
+struct S {
+ S operator++(int);
+ S(int i);
+ S();
+
+ int& f();
+ S g();
+};
+
+void j() {
+ S s;
+ int i = 0;
+ (void)noexcept(s++); // Ok
+ (void)noexcept(i++); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
+ (void)noexcept(i = 5); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
+ (void)noexcept(s = 5); // Ok
+
+ (void)sizeof(s.f()); // Ok
+ (void)sizeof(s.f() = 5); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
+ (void)noexcept(s.g() = 5); // Ok
+}
+
+} \ No newline at end of file
diff --git a/test/SemaCXX/warn-unused-value.cpp b/test/SemaCXX/warn-unused-value.cpp
index 4e1347cc307a..efabd5063068 100644
--- a/test/SemaCXX/warn-unused-value.cpp
+++ b/test/SemaCXX/warn-unused-value.cpp
@@ -39,13 +39,13 @@ namespace test2 {
void method() const {
X* x;
&x[0]; // expected-warning {{expression result unused}}
- }
+ }
};
typedef basic_string<char> string;
- void func(const std::string& str) {
+ void func(const std::string& str) {
str.method(); // expected-note {{in instantiation of member function}}
}
- }
+ }
}
}
@@ -69,3 +69,31 @@ void f() {
Unused(1, 1); // expected-warning {{expression result unused}}
}
}
+
+namespace std {
+ struct type_info {};
+}
+
+namespace test4 {
+struct Good { Good &f(); };
+struct Bad { virtual Bad& f(); };
+
+void f() {
+ int i = 0;
+ (void)typeid(++i); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
+
+ Good g;
+ (void)typeid(g.f()); // Ok; not a polymorphic use of a glvalue.
+
+ // This is a polymorphic use of a glvalue, which results in the typeid being
+ // evaluated instead of unevaluated.
+ Bad b;
+ (void)typeid(b.f()); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
+
+ // A dereference of a volatile pointer is a side effecting operation, however
+ // since it is idiomatic code, and the alternatives induce higher maintenance
+ // costs, it is allowed.
+ int * volatile x;
+ (void)sizeof(*x); // Ok
+}
+}
diff --git a/test/SemaObjC/access-property-getter.m b/test/SemaObjC/access-property-getter.m
index afaf82e73106..41827bb3c8a4 100644
--- a/test/SemaObjC/access-property-getter.m
+++ b/test/SemaObjC/access-property-getter.m
@@ -34,3 +34,20 @@
return 0;
}
@end
+
+// rdar://19137815
+#pragma clang diagnostic ignored "-Wunused-getter-return-value"
+
+@interface NSObject @end
+
+@interface I : NSObject
+@property (copy) id window;
+@end
+
+@implementation I
+- (void) Meth {
+ [self window];
+ self.window;
+}
+@end
+
diff --git a/test/SemaObjC/arc-jump-block.m b/test/SemaObjC/arc-jump-block.m
index 9b06c5a780cc..418d296452b4 100644
--- a/test/SemaObjC/arc-jump-block.m
+++ b/test/SemaObjC/arc-jump-block.m
@@ -21,15 +21,15 @@ extern __attribute__((visibility("default"))) struct dispatch_queue_s _dispatch_
case 0:
dispatch_async((&_dispatch_main_q), ^{ [self pageLeft]; }); // expected-note 3 {{jump enters lifetime of block which strongly captures a variable}}
break;
- case 2: // expected-error {{switch case is in protected scope}}
+ case 2: // expected-error {{cannot jump}}
dispatch_async((&_dispatch_main_q), ^{ [self pageRight]; }); // expected-note 2 {{jump enters lifetime of block which strongly captures a variable}}
break;
- case 3: // expected-error {{switch case is in protected scope}}
+ case 3: // expected-error {{cannot jump}}
{
dispatch_async((&_dispatch_main_q), ^{ [self pageRight]; });
break;
}
- case 4: // expected-error {{switch case is in protected scope}}
+ case 4: // expected-error {{cannot jump}}
break;
}
@@ -90,7 +90,7 @@ int test2(id obj, int state) { // expected-note {{jump enters lifetime of block}
(void) ^{ (void) obj; };
return 0;
- default: // expected-error {{switch case is in protected scope}}
+ default: // expected-error {{cannot jump}}
return 1;
}
}
diff --git a/test/SemaObjC/arc-repeated-weak.mm b/test/SemaObjC/arc-repeated-weak.mm
index 64df92a9afa9..264c598942ae 100644
--- a/test/SemaObjC/arc-repeated-weak.mm
+++ b/test/SemaObjC/arc-repeated-weak.mm
@@ -425,3 +425,17 @@ void doubleLevelAccessIvar(Test *a, Test *b) {
}
@end
+// rdar://19053620
+@interface NSNull
++ (NSNull *)null;
+@end
+
+@interface INTF @end
+
+@implementation INTF
+- (void) Meth : (id) data
+{
+ data = data ?: NSNull.null;
+}
+@end
+
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
index ba7c09f4f9d7..54a7db7b11b1 100644
--- a/test/SemaObjC/arc.m
+++ b/test/SemaObjC/arc.m
@@ -129,7 +129,7 @@ void test6(unsigned cond) {
;
id x; // expected-note {{jump bypasses initialization of retaining variable}}
- case 1: // expected-error {{switch case is in protected scope}}
+ case 1: // expected-error {{cannot jump}}
break;
}
}
diff --git a/test/SemaObjC/attr-availability-1.m b/test/SemaObjC/attr-availability-1.m
new file mode 100644
index 000000000000..063407adaeee
--- /dev/null
+++ b/test/SemaObjC/attr-availability-1.m
@@ -0,0 +1,116 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9.0.0 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -std=c++11 -triple x86_64-apple-darwin9.0.0 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -std=c++03 -triple x86_64-apple-darwin9.0.0 -fsyntax-only -verify %s
+// rdar://18490958
+
+@protocol P
+- (void)proto_method __attribute__((availability(macosx,introduced=10_1,deprecated=10_2))); // expected-note 2 {{'proto_method' has been explicitly marked deprecated here}}
+@end
+
+@interface A <P>
+- (void)method __attribute__((availability(macosx,introduced=10_1,deprecated=10_2))); // expected-note {{'method' has been explicitly marked deprecated here}}
+
+- (void)overridden __attribute__((availability(macosx,introduced=10_3))); // expected-note{{overridden method is here}}
+- (void)overridden2 __attribute__((availability(macosx,introduced=10_3)));
+- (void)overridden3 __attribute__((availability(macosx,deprecated=10_3)));
+- (void)overridden4 __attribute__((availability(macosx,deprecated=10_3))); // expected-note{{overridden method is here}}
+- (void)overridden5 __attribute__((availability(macosx,unavailable)));
+- (void)overridden6 __attribute__((availability(macosx,introduced=10_3))); // expected-note{{overridden method is here}}
+@end
+
+// rdar://11475360
+@interface B : A
+- (void)method; // NOTE: we expect 'method' to *not* inherit availability.
+- (void)overridden __attribute__((availability(macosx,introduced=10_4))); // expected-warning{{overriding method introduced after overridden method on OS X (10_4 vs. 10_3)}}
+- (void)overridden2 __attribute__((availability(macosx,introduced=10_2)));
+- (void)overridden3 __attribute__((availability(macosx,deprecated=10_4)));
+- (void)overridden4 __attribute__((availability(macosx,deprecated=10_2))); // expected-warning{{overriding method deprecated before overridden method on OS X (10_3 vs. 10_2)}}
+- (void)overridden5 __attribute__((availability(macosx,introduced=10_3)));
+- (void)overridden6 __attribute__((availability(macosx,unavailable))); // expected-warning{{overriding method cannot be unavailable on OS X when its overridden method is available}}
+@end
+
+void f(A *a, B *b) {
+ [a method]; // expected-warning{{'method' is deprecated: first deprecated in OS X 10.2}}
+ [b method]; // no-warning
+ [a proto_method]; // expected-warning{{'proto_method' is deprecated: first deprecated in OS X 10.2}}
+ [b proto_method]; // expected-warning{{'proto_method' is deprecated: first deprecated in OS X 10.2}}
+}
+
+// Test case for <rdar://problem/11627873>. Warn about
+// using a deprecated method when that method is re-implemented in a
+// subclass where the redeclared method is not deprecated.
+@interface C
+- (void) method __attribute__((availability(macosx,introduced=10_1,deprecated=10_2))); // expected-note {{'method' has been explicitly marked deprecated here}}
+@end
+
+@interface D : C
+- (void) method;
+@end
+
+@interface E : D
+- (void) method;
+@end
+
+@implementation D
+- (void) method {
+ [super method]; // expected-warning {{'method' is deprecated: first deprecated in OS X 10.2}}
+}
+@end
+
+@implementation E
+- (void) method {
+ [super method]; // no-warning
+}
+@end
+
+// rdar://18059669
+@class NSMutableArray;
+
+@interface NSDictionary
++ (instancetype)dictionaryWithObjectsAndKeys:(id)firstObject, ... __attribute__((sentinel(0,1)));
+@end
+
+@class NSString;
+
+extern NSString *NSNibTopLevelObjects __attribute__((availability(macosx,introduced=10_0 ,deprecated=10_8,message="" )));
+id NSNibOwner, topNibObjects;
+
+@interface AppDelegate (SIEImport) // expected-error {{cannot find interface declaration for 'AppDelegate'}}
+
+-(void)__attribute__((ibaction))importFromSIE:(id)sender;
+
+@end
+
+@implementation AppDelegate (SIEImport) // expected-error {{cannot find interface declaration for 'AppDelegate'}}
+
+-(void)__attribute__((ibaction))importFromSIE:(id)sender {
+
+ NSMutableArray *topNibObjects;
+ NSDictionary *nibLoadDict = [NSDictionary dictionaryWithObjectsAndKeys:self, NSNibOwner, topNibObjects, NSNibTopLevelObjects, ((void *)0)];
+}
+
+@end
+
+@interface Mixed
+- (void)Meth1 __attribute__((availability(macosx,introduced=10.3_0))); // expected-warning {{use same version number separators '_' or '.'}}
+- (void)Meth2 __attribute__((availability(macosx,introduced=10_3.1))); // expected-warning {{use same version number separators '_' or '.'}}
+@end
+
+// rdar://18804883
+@protocol P18804883
+- (void)proto_method __attribute__((availability(macosx,introduced=10_1,deprecated=NA))); // means nothing (not deprecated)
+@end
+
+@interface A18804883 <P18804883>
+- (void)interface_method __attribute__((availability(macosx,introduced=NA))); // expected-note {{'interface_method' has been explicitly marked unavailable here}}
+- (void)strange_method __attribute__((availability(macosx,introduced=NA,deprecated=NA))); // expected-note {{'strange_method' has been explicitly marked unavailable here}}
+- (void) always_available __attribute__((availability(macosx,deprecated=NA)));
+@end
+
+void foo (A18804883* pa) {
+ [pa interface_method]; // expected-error {{'interface_method' is unavailable: not available on OS X}}
+ [pa proto_method];
+ [pa strange_method]; // expected-error {{'strange_method' is unavailable: not available on OS X}}
+ [pa always_available];
+}
+
diff --git a/test/SemaObjC/attr-availability.m b/test/SemaObjC/attr-availability.m
index 7990b1202e8f..c455bc7acce6 100644
--- a/test/SemaObjC/attr-availability.m
+++ b/test/SemaObjC/attr-availability.m
@@ -60,3 +60,30 @@ void f(A *a, B *b) {
}
@end
+// rdar://18059669
+@class NSMutableArray;
+
+@interface NSDictionary
++ (instancetype)dictionaryWithObjectsAndKeys:(id)firstObject, ... __attribute__((sentinel(0,1)));
+@end
+
+@class NSString;
+
+extern NSString *NSNibTopLevelObjects __attribute__((availability(macosx,introduced=10.0 ,deprecated=10.8,message="" )));
+id NSNibOwner, topNibObjects;
+
+@interface AppDelegate (SIEImport) // expected-error {{cannot find interface declaration for 'AppDelegate'}}
+
+-(void)__attribute__((ibaction))importFromSIE:(id)sender;
+
+@end
+
+@implementation AppDelegate (SIEImport) // expected-error {{cannot find interface declaration for 'AppDelegate'}}
+
+-(void)__attribute__((ibaction))importFromSIE:(id)sender {
+
+ NSMutableArray *topNibObjects;
+ NSDictionary *nibLoadDict = [NSDictionary dictionaryWithObjectsAndKeys:self, NSNibOwner, topNibObjects, NSNibTopLevelObjects, ((void *)0)];
+}
+
+@end
diff --git a/test/SemaObjC/attr-deprecated-pch.m b/test/SemaObjC/attr-deprecated-pch.m
new file mode 100644
index 000000000000..2b48aea379a0
--- /dev/null
+++ b/test/SemaObjC/attr-deprecated-pch.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -DBOTH -verify %s
+// If the decls come from a pch, the behavior shouldn't change:
+// RUN: %clang_cc1 -x objective-c-header %s -emit-pch -o %t
+// RUN: %clang_cc1 -DUSES -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// The slightly strange ifdefs are so that the command that builds the gch file
+// doesn't need any -D switches, for these would get embedded in the gch.
+
+#ifndef USES
+@interface Interface1
+- (void)partiallyUnavailableMethod;
+@end
+@interface Interface2
+- (void)partiallyUnavailableMethod __attribute__((unavailable));
+@end
+#endif
+
+#if defined(USES) || defined(BOTH)
+void f(id a) {
+ [a partiallyUnavailableMethod]; // no warning, `a` could be an Interface1.
+}
+#endif
diff --git a/test/SemaObjC/attr-deprecated.m b/test/SemaObjC/attr-deprecated.m
index ca30d0a27d88..13ba68db58e6 100644
--- a/test/SemaObjC/attr-deprecated.m
+++ b/test/SemaObjC/attr-deprecated.m
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10.4 -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple x86_64-apple-darwin10.4 -verify -Wno-objc-root-class %s
@interface A {
int X __attribute__((deprecated)); // expected-note 2 {{'X' has been explicitly marked deprecated here}}
}
+ (void)F __attribute__((deprecated)); // expected-note 2 {{'F' has been explicitly marked deprecated here}}
-- (void)f __attribute__((deprecated)); // expected-note 4 {{'f' has been explicitly marked deprecated here}}
+- (void)f __attribute__((deprecated)); // expected-note 5 {{'f' has been explicitly marked deprecated here}}
@end
@implementation A
@@ -54,7 +54,7 @@ void t1(A *a)
void t2(id a)
{
- [a f];
+ [a f]; // expected-warning {{'f' is deprecated}}
}
void t3(A<P>* a)
@@ -197,18 +197,19 @@ __attribute__((deprecated))
@interface TestBase
@property (nonatomic, strong) id object __attribute__((deprecated("deprecated"))); // expected-note {{'object' has been explicitly marked deprecated here}} \
expected-note {{property 'object' is declared deprecated here}} \
-expected-note {{'setObject:' has been explicitly marked deprecated here}}
+expected-note {{'setObject:' has been explicitly marked deprecated here}} \
+expected-note {{property declared here}}
@end
@interface TestDerived : TestBase
-@property (nonatomic, strong) id object;
+@property (nonatomic, strong) id object; //expected-warning {{auto property synthesis will not synthesize property 'object'; it will be implemented by its superclass}}
@end
@interface TestUse @end
@implementation TestBase @end
-@implementation TestDerived @end
+@implementation TestDerived @end // expected-note {{detected while default synthesizing properties in class implementation}}
@implementation TestUse
@@ -227,3 +228,59 @@ expected-note {{'setObject:' has been explicitly marked deprecated here}}
@end
+// rdar://18848183
+@interface NSString
+- (const char *)cString __attribute__((availability(macosx,introduced=10.0 ,deprecated=10.4,message="" ))); // expected-note {{'cString' has been explicitly marked deprecated here}}
+@end
+
+id PID = 0;
+const char * func() {
+ return [PID cString]; // expected-warning {{'cString' is deprecated: first deprecated in OS X 10.4}}
+}
+
+// rdar://18960378
+@interface NSObject
++ (instancetype)alloc;
+- (instancetype)init;
+@end
+
+@interface NSLocale
+- (instancetype)init __attribute__((unavailable));
+@end
+
+@interface PLBatteryProperties : NSObject
++ (id)properties;
+@end
+
+@implementation PLBatteryProperties
++ (id)properties {
+ return [[self alloc] init];
+}
+@end
+
+@implementation UndeclaredImpl // expected-warning{{cannot find interface declaration}}
+- (void)partiallyUnavailableMethod {}
+@end
+
+@interface InterfaceWithSameMethodAsUndeclaredImpl
+- (void)partiallyUnavailableMethod __attribute__((unavailable));
+@end
+
+void f(id a) {
+ [a partiallyUnavailableMethod]; // no warning, `a` could be an UndeclaredImpl.
+}
+
+@interface InterfaceWithImplementation
+- (void)anotherPartiallyUnavailableMethod;
+@end
+@implementation InterfaceWithImplementation
+- (void)anotherPartiallyUnavailableMethod {}
+@end
+
+@interface InterfaceWithSameMethodAsInterfaceWithImplementation
+- (void)anotherPartiallyUnavailableMethod __attribute__((unavailable));
+@end
+
+void g(id a) {
+ [a anotherPartiallyUnavailableMethod]; // no warning, `a` could be an InterfaceWithImplementation.
+}
diff --git a/test/SemaObjC/autoreleasepool.m b/test/SemaObjC/autoreleasepool.m
index 45c749e570c1..c88f1bacca63 100644
--- a/test/SemaObjC/autoreleasepool.m
+++ b/test/SemaObjC/autoreleasepool.m
@@ -7,7 +7,7 @@ void autoreleasepool_pop(void*);
@implementation AUTORP
- (void) unregisterTask:(id) task {
- goto L; // expected-error {{goto into protected scope}}
+ goto L; // expected-error {{cannot jump}}
@autoreleasepool { // expected-note {{jump bypasses auto release push of @autoreleasepool block}}
void *tmp = objc_autoreleasepool_push();
diff --git a/test/SemaObjC/compare-qualified-class.m b/test/SemaObjC/compare-qualified-class.m
index 60ef851e1f3f..a52561521444 100644
--- a/test/SemaObjC/compare-qualified-class.m
+++ b/test/SemaObjC/compare-qualified-class.m
@@ -28,3 +28,38 @@ int main () {
classA == classD; // expected-warning {{comparison of distinct pointer types ('Class<SomeProtocol>' and 'Class<SomeProtocol1>')}}
}
+// rdar://18491222
+@protocol NSObject @end
+
+@interface NSObject @end
+@protocol ProtocolX <NSObject>
+@end
+
+@protocol ProtocolY <NSObject>
+@end
+
+@interface ClassA : NSObject
+@end
+
+@interface ClassB : ClassA <ProtocolY, ProtocolX>
+@end
+
+@interface OtherClass : NSObject
+@property (nonatomic, copy) ClassB<ProtocolX> *aProperty;
+- (ClassA<ProtocolY> *)aMethod;
+- (ClassA<ProtocolY> *)anotherMethod;
+@end
+
+@implementation OtherClass
+- (ClassA<ProtocolY> *)aMethod {
+ // This does not work, even though ClassB subclasses from A and conforms to Y
+ // because the property type explicity adds ProtocolX conformance
+ // even though ClassB already conforms to ProtocolX
+ return self.aProperty;
+}
+- (ClassA<ProtocolY> *)anotherMethod {
+ // This works, even though all it is doing is removing an explicit
+ // protocol conformance that ClassB already conforms to
+ return (ClassB *)self.aProperty;
+}
+@end
diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m
index d8862c584a0d..71e108cce673 100644
--- a/test/SemaObjC/conditional-expr.m
+++ b/test/SemaObjC/conditional-expr.m
@@ -101,10 +101,10 @@ int f8(int a, A<P0> *x, A *y) {
}
void f9(int a, A<P0> *x, A<P1> *y) {
- id l0 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
- A<P0> *l1 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
- A<P1> *l2 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
- [ (a ? x : y ) intProp ]; // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
+ id l0 = (a ? x : y ); // Ok. y is of A<P1> object type and A is qualified by P0.
+ A<P0> *l1 = (a ? x : y ); // Ok. y is of A<P1> object type and A is qualified by P0.
+ A<P1> *l2 = (a ? x : y ); // expected-warning {{incompatible pointer types initializing 'A<P1> *' with an expression of type 'A<P0> *'}}
+ (void)[ (a ? x : y ) intProp ]; // Ok. Common type is A<P0> * and P0's property intProp is accessed.
}
void f10(int a, id<P0> x, id y) {
@@ -116,5 +116,5 @@ void f11(int a, id<P0> x, id<P1> y) {
}
void f12(int a, A<P0> *x, A<P1> *y) {
- A<P1>* l0 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
+ A<P1>* l0 = (a ? x : y ); // expected-warning {{incompatible pointer types initializing 'A<P1> *' with an expression of type 'A<P0> *'}}
}
diff --git a/test/SemaObjC/debugger-support.m b/test/SemaObjC/debugger-support.m
index 21c096edad43..5dbc3eebfa2c 100644
--- a/test/SemaObjC/debugger-support.m
+++ b/test/SemaObjC/debugger-support.m
@@ -9,6 +9,6 @@ void test0(id x) {
// CHECK-NEXT: [[RESULT:%.*]] = alloca [[A:%.*]], align 4
// CHECK-NEXT: store i8* {{%.*}}, i8** [[X]],
// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]],
- // CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_"
+ // CHECK-NEXT: [[T1:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T2:%.*]] = call { i64, i64 } bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to { i64, i64 } (i8*, i8*)*)(i8* [[T0]], i8* [[T1]])
}
diff --git a/test/SemaObjC/default-synthesize-1.m b/test/SemaObjC/default-synthesize-1.m
index f9f2e72eaf94..731aa863e103 100644
--- a/test/SemaObjC/default-synthesize-1.m
+++ b/test/SemaObjC/default-synthesize-1.m
@@ -124,3 +124,20 @@
// expected-note {{detected while default synthesizing properties in class implementation}}
@synthesize x; // expected-error {{cannot synthesize property 'x' with incomplete type 'enum A'}}
@end
+
+// rdar://17774815
+@interface ZXParsedResult
+@property (nonatomic, copy, readonly) NSString *description; // expected-note {{property declared here}}
+@end
+
+@interface ZXCalendarParsedResult : ZXParsedResult
+
+@property (nonatomic, copy, readonly) NSString *description; // expected-warning {{auto property synthesis will not synthesize property 'description'; it will be implemented by its superclass}}
+
+@end
+
+@implementation ZXCalendarParsedResult // expected-note {{detected while default synthesizing properties in class implementation}}
+- (NSString *) Meth {
+ return _description; // expected-error {{use of undeclared identifier '_description'}}
+}
+@end
diff --git a/test/SemaObjC/default-synthesize-3.m b/test/SemaObjC/default-synthesize-3.m
index c91597462d91..dce9edabb90d 100644
--- a/test/SemaObjC/default-synthesize-3.m
+++ b/test/SemaObjC/default-synthesize-3.m
@@ -44,7 +44,7 @@ __attribute ((objc_requires_property_definitions)) // expected-error {{'objc_req
@interface NSObject @end
@protocol Foo
@property (readonly) char isFoo; // expected-note {{property declared here}}
-@property (readonly) char isNotFree;
+@property (readonly) char isNotFree; // expected-note {{property declared here}}
@end
@interface Bar : NSObject <Foo>
@@ -66,10 +66,10 @@ __attribute ((objc_requires_property_definitions)) // expected-error {{'objc_req
@property (readwrite) char isFoo; // expected-warning {{auto property synthesis will not synthesize property 'isFoo' because it is 'readwrite' but it will be synthesized 'readonly' via another property}}
@property char Property1; // expected-warning {{auto property synthesis will not synthesize property 'Property1' because it cannot share an ivar with another synthesized property}}
@property char Property2;
-@property (readwrite) char isNotFree;
+@property (readwrite) char isNotFree; // expected-warning {{auto property synthesis will not synthesize property 'isNotFree'}}
@end
-@implementation Baz {
+@implementation Baz { // expected-note {{detected while default synthesizing properties in class implementation}}
char _isFoo;
char _isNotFree;
}
@@ -90,9 +90,9 @@ __attribute ((objc_requires_property_definitions)) // expected-error {{'objc_req
@end
@interface B
-@property (readonly) id prop;
-@property (readonly) id prop1;
-@property (readonly) id prop2;
+@property (readonly) id prop; // expected-note {{property declared here}}
+@property (readonly) id prop1; // expected-note {{property declared here}}
+@property (readonly) id prop2; // expected-note {{property declared here}}
@end
@interface B()
@@ -104,12 +104,12 @@ __attribute ((objc_requires_property_definitions)) // expected-error {{'objc_req
@end
@interface S : B<P1>
-@property (assign,readwrite) id prop;
-@property (assign,readwrite) id prop1;
-@property (assign,readwrite) id prop2;
+@property (assign,readwrite) id prop; // expected-warning {{auto property synthesis will not synthesize property 'prop'}}
+@property (assign,readwrite) id prop1; // expected-warning {{auto property synthesis will not synthesize property 'prop1'}}
+@property (assign,readwrite) id prop2; // expected-warning {{auto property synthesis will not synthesize property 'prop2'}}
@end
-@implementation S
+@implementation S // expected-note 3 {{detected while default synthesizing properties in class implementation}}
@end
// rdar://14085456
diff --git a/test/SemaObjC/default-synthesize.m b/test/SemaObjC/default-synthesize.m
index 9356b9f5b3a3..3f0ae0261daf 100644
--- a/test/SemaObjC/default-synthesize.m
+++ b/test/SemaObjC/default-synthesize.m
@@ -97,10 +97,10 @@
}
@end
-@interface SubClass : TopClass <TopProtocol>
+@interface SubClass : TopClass <TopProtocol>
@end
-@implementation SubClass @end
+@implementation SubClass @end
// rdar://7920807
@interface C @end
@@ -138,3 +138,39 @@
@implementation MyClass // expected-warning {{auto property synthesis will not synthesize property 'requiredString' declared in protocol 'MyProtocol'}}
@end
+
+// rdar://18152478
+@protocol NSObject @end
+@protocol TMSourceManagerDelegate<NSObject>
+@end
+
+@protocol TMSourceManager <NSObject>
+@property (nonatomic, assign) id <TMSourceManagerDelegate> delegate;
+@end
+
+@interface TMSourceManager
+@property (nonatomic, assign) id <TMSourceManagerDelegate> delegate;
+@end
+
+@protocol TMTimeZoneManager <TMSourceManager>
+@end
+
+@interface TimeZoneManager : TMSourceManager <TMTimeZoneManager>
+@end
+
+@implementation TimeZoneManager
+@end
+
+// rdar://18179833
+@protocol BaseProt
+@property (assign) id prot;
+@end
+
+@interface Base<BaseProt>
+@end
+
+@interface I : Base<BaseProt>
+@end
+
+@implementation I
+@end
diff --git a/test/SemaObjC/encode-typeof-test.m b/test/SemaObjC/encode-typeof-test.m
index 2cda9739681b..fe8f29c3b972 100644
--- a/test/SemaObjC/encode-typeof-test.m
+++ b/test/SemaObjC/encode-typeof-test.m
@@ -24,3 +24,22 @@ int main()
int i;
typeof(@encode(typeof(i))) e = @encode(typeof(Intf)); // expected-warning {{initializer-string for char array is too long}}
}
+
+// rdar://9255564
+typedef short short8 __attribute__((ext_vector_type(8)));
+
+struct foo {
+ char a;
+ int b;
+ long c;
+ short8 d;
+ int array[4];
+ short int bitfield1:5;
+ unsigned short bitfield2:11;
+ char *string;
+};
+
+const char *RetEncode () {
+ return @encode(struct foo); // expected-warning {{encoding of 'struct foo' type is incomplete because 'short8' (vector of 8 'short' values) component has unknown encoding}}
+}
+
diff --git a/test/SemaObjC/format-cstrings-warning.m b/test/SemaObjC/format-cstrings-warning.m
new file mode 100644
index 000000000000..28fa7ce0dcd8
--- /dev/null
+++ b/test/SemaObjC/format-cstrings-warning.m
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -Wcstring-format-directive -verify -fsyntax-only %s
+// rdar://18182443
+
+typedef __builtin_va_list __darwin_va_list;
+typedef __builtin_va_list va_list;
+
+@interface NSString
+@end
+
+va_list argList;
+
+@interface NSString (NSStringExtensionMethods)
+- (NSString *)stringByAppendingFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
+- (instancetype)initWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note 2 {{method 'initWithFormat:' declared here}}
+- (instancetype)initWithFormat:(NSString *)format arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0)));
+- (instancetype)initWithFormat:(NSString *)format locale:(id)locale, ... __attribute__((format(__NSString__, 1, 3)));
+- (instancetype)initWithFormat:(NSString *)format locale:(id)locale arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0)));
++ (instancetype)stringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note {{method 'stringWithFormat:' declared here}}
++ (instancetype)localizedStringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note {{method 'localizedStringWithFormat:' declared here}}
+- (void)MyRandomMethod:(NSString *)format locale:(id)locale arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0))); // expected-note {{method 'MyRandomMethod:locale:arguments:' declared here}}
+@end
+
+@interface NSMutableString : NSString
+@end
+
+@interface NSMutableString (NSMutableStringExtensionMethods)
+
+- (void)appendFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
+
+@end
+
+NSString *ns(NSString *pns) {
+ [pns initWithFormat: @"Number %d length %c name %s", 1, 'a', "something"]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+ [NSString localizedStringWithFormat : @"Hello%s", " There"]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+ [pns initWithFormat : @"Hello%s %d %d", "Hello", 1, 2]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+ [pns MyRandomMethod : @"Hello%s %d %d" locale:0 arguments: argList]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+ return [NSString stringWithFormat : @"Hello%s", " There"]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+}
+
+
+typedef const struct __CFString * CFStringRef;
+typedef struct __CFString * CFMutableStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+
+
+typedef const struct __CFDictionary * CFDictionaryRef;
+
+
+extern
+CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...) __attribute__((format(CFString, 3, 4)));
+
+extern
+CFStringRef CFStringCreateWithFormatAndArguments(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, va_list arguments) __attribute__((format(CFString, 3, 0))); // expected-note {{'CFStringCreateWithFormatAndArguments' declared here}}
+
+extern
+void CFStringAppendFormat(CFMutableStringRef theString, CFDictionaryRef formatOptions, CFStringRef format, ...) __attribute__((format(CFString, 3, 4)));
+
+extern
+void CFStringAppendFormatAndArguments(CFMutableStringRef theString, CFDictionaryRef formatOptions, CFStringRef format, va_list arguments) __attribute__((format(CFString, 3, 0))); // expected-note {{'CFStringAppendFormatAndArguments' declared here}}
+
+void Test1(va_list argList) {
+ CFAllocatorRef alloc;
+ CFStringCreateWithFormatAndArguments (alloc, 0, (CFStringRef)@"%s\n", argList); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+ CFStringAppendFormatAndArguments ((CFMutableStringRef)@"AAAA", 0, (CFStringRef)"Hello %s there %d\n", argList); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+ CFStringCreateWithFormatAndArguments (alloc, 0, (CFStringRef)@"%c\n", argList);
+ CFStringAppendFormatAndArguments ((CFMutableStringRef)@"AAAA", 0, (CFStringRef)"%d\n", argList);
+}
+
+extern void MyNSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); // expected-note {{'MyNSLog' declared here}}
+extern void MyCFStringCreateWithFormat(CFStringRef format, ...) __attribute__((format(__CFString__, 1, 2))); // expected-note {{'MyCFStringCreateWithFormat' declared here}}
+extern void XMyNSLog(int, NSString *format, ...) __attribute__((format(__NSString__, 2, 3))); // expected-note {{'XMyNSLog' declared here}}
+
+void Test2() {
+ MyNSLog(@"%s\n", "Hello"); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+
+ MyCFStringCreateWithFormat((CFStringRef)@"%s", "Hello"); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+ XMyNSLog(4, @"%s\n", "Hello"); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+}
+
diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m
index 49567a710c3a..f4c528cc7ac0 100644
--- a/test/SemaObjC/format-strings-objc.m
+++ b/test/SemaObjC/format-strings-objc.m
@@ -243,7 +243,7 @@ void testByValueObjectInFormat(Foo *obj) {
// <rdar://problem/13557053>
void testTypeOf(NSInteger dW, NSInteger dH) {
- NSLog(@"dW %d dH %d",({ __typeof__(dW) __a = (dW); __a < 0 ? -__a : __a; }),({ __typeof__(dH) __a = (dH); __a < 0 ? -__a : __a; })); // expected-warning 2 {{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ NSLog(@"dW %d dH %d",({ __typeof__(dW) __a = (dW); __a < 0 ? -__a : __a; }),({ __typeof__(dH) __a = (dH); __a < 0 ? -__a : __a; })); // expected-warning 2 {{format specifies type 'int' but the argument has type 'long'}}
}
void testUnicode() {
diff --git a/test/SemaObjC/iboutlet.m b/test/SemaObjC/iboutlet.m
index 63eac9af8a52..7d656a51684a 100644
--- a/test/SemaObjC/iboutlet.m
+++ b/test/SemaObjC/iboutlet.m
@@ -6,12 +6,10 @@
@class NSView;
-#define IBOutlet __attribute__((iboutlet))
-
-@interface I
+IB_DESIGNABLE @interface I
@property (getter = MyGetter, readonly, assign) IBOutlet NSView *myView; // expected-warning {{readonly IBOutlet property 'myView' when auto-synthesized may not work correctly with 'nib' loader}} expected-note {{property should be changed to be readwrite}}
-@property (readonly) IBOutlet NSView *myView1; // expected-warning {{readonly IBOutlet property 'myView1' when auto-synthesized may not work correctly with 'nib' loader}} expected-note {{property should be changed to be readwrite}}
+IBInspectable @property (readonly) IBOutlet NSView *myView1; // expected-warning {{readonly IBOutlet property 'myView1' when auto-synthesized may not work correctly with 'nib' loader}} expected-note {{property should be changed to be readwrite}}
@property (getter = MyGetter, READONLY) IBOutlet NSView *myView2; // expected-warning {{readonly IBOutlet property 'myView2' when auto-synthesized may not work correctly with 'nib' loader}}
diff --git a/test/SemaObjC/ivar-lookup.m b/test/SemaObjC/ivar-lookup.m
index 938c8eb189a5..57f432c717a1 100644
--- a/test/SemaObjC/ivar-lookup.m
+++ b/test/SemaObjC/ivar-lookup.m
@@ -99,9 +99,9 @@ extern struct foo x;
};
struct S {
__typeof(myStatus) __in; // fails.
- struct S1 {
+ struct S1 { // expected-warning {{declaration does not declare anything}}
__typeof(myStatus) __in; // fails.
- struct S {
+ struct S { // expected-warning {{declaration does not declare anything}}
__typeof(myStatus) __in; // fails.
};
};
diff --git a/test/SemaObjC/method-lookup-3.m b/test/SemaObjC/method-lookup-3.m
index b3d9c46484c3..ff2c4898a411 100644
--- a/test/SemaObjC/method-lookup-3.m
+++ b/test/SemaObjC/method-lookup-3.m
@@ -71,3 +71,29 @@ struct test4b { float x, y; };
void test4(id x) {
(void) [x test4]; //expected-warning {{multiple methods named 'test4' found}}
}
+
+// rdar://19265296
+#pragma clang diagnostic ignored "-Wobjc-multiple-method-names"
+@interface NSObject
++ (id)alloc;
++ (id)class;
+- (id) init;
+@end
+
+@class NSString;
+@interface A : NSObject
+- (instancetype)initWithType:(NSString *)whatever;
+@end
+
+@interface Test : NSObject @end
+
+@implementation Test
++ (instancetype)foo
+{
+ return [[[self class] alloc] initWithType:3];
+}
+- (instancetype)initWithType:(int)whatever
+{
+ return [super init];
+}
+@end
diff --git a/test/SemaObjC/nonnull.m b/test/SemaObjC/nonnull.m
index a345eddbf1e4..cacca07240f6 100644
--- a/test/SemaObjC/nonnull.m
+++ b/test/SemaObjC/nonnull.m
@@ -31,16 +31,16 @@ foo (int i1, int i2, int i3, void (^cp1)(), void (^cp2)(), void (^cp3)())
{
func1(cp1, cp2, i1);
- func1(0, cp2, i1); // expected-warning {{null passed to a callee which requires a non-null argument}}
- func1(cp1, 0, i1); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ func1(0, cp2, i1); // expected-warning {{null passed to a callee that requires a non-null argument}}
+ func1(cp1, 0, i1); // expected-warning {{null passed to a callee that requires a non-null argument}}
func1(cp1, cp2, 0);
- func3(0, i2, cp3, i3); // expected-warning {{null passed to a callee which requires a non-null argument}}
- func3(cp3, i2, 0, i3); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ func3(0, i2, cp3, i3); // expected-warning {{null passed to a callee that requires a non-null argument}}
+ func3(cp3, i2, 0, i3); // expected-warning {{null passed to a callee that requires a non-null argument}}
- func4(0, cp1); // expected-warning {{null passed to a callee which requires a non-null argument}}
- func4(cp1, 0); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ func4(0, cp1); // expected-warning {{null passed to a callee that requires a non-null argument}}
+ func4(cp1, 0); // expected-warning {{null passed to a callee that requires a non-null argument}}
// Shouldn't these emit warnings? Clang doesn't, and neither does GCC. It
// seems that the checking should handle Objective-C pointers.
@@ -64,7 +64,7 @@ __attribute__((nonnull))
void _dispatch_queue_push_list(dispatch_object_t _head); // no warning
void func6(dispatch_object_t _head) {
- _dispatch_queue_push_list(0); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ _dispatch_queue_push_list(0); // expected-warning {{null passed to a callee that requires a non-null argument}}
_dispatch_queue_push_list(_head._do); // no warning
}
@@ -91,10 +91,10 @@ extern void DoSomethingNotNull(void *db) __attribute__((nonnull(1)));
@implementation IMP
- (void) Meth {
NSObject *object;
- [object doSomethingWithNonNullPointer:NULL:1:NULL]; // expected-warning 2 {{null passed to a callee which requires a non-null argument}}
- [object doSomethingWithNonNullPointer:vp:1:NULL]; // expected-warning {{null passed to a callee which requires a non-null argument}}
- [NSObject doSomethingClassyWithNonNullPointer:NULL]; // expected-warning {{null passed to a callee which requires a non-null argument}}
- DoSomethingNotNull(NULL); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ [object doSomethingWithNonNullPointer:NULL:1:NULL]; // expected-warning 2 {{null passed to a callee that requires a non-null argument}}
+ [object doSomethingWithNonNullPointer:vp:1:NULL]; // expected-warning {{null passed to a callee that requires a non-null argument}}
+ [NSObject doSomethingClassyWithNonNullPointer:NULL]; // expected-warning {{null passed to a callee that requires a non-null argument}}
+ DoSomethingNotNull(NULL); // expected-warning {{null passed to a callee that requires a non-null argument}}
[object doSomethingWithNonNullPointer:vp:1:vp];
}
- (void*) testRetNull {
@@ -111,15 +111,15 @@ __attribute__((objc_root_class))
@end
void test(TestNonNullParameters *f) {
- [f doNotPassNullParameter:0]; // expected-warning {{null passed to a callee which requires a non-null argument}}
+ [f doNotPassNullParameter:0]; // expected-warning {{null passed to a callee that requires a non-null argument}}
[f doNotPassNullParameterArgIndex:0]; // no-warning
- [f doNotPassNullOnMethod:0]; // expected-warning {{null passed to a callee which requires a non-null argument}}
+ [f doNotPassNullOnMethod:0]; // expected-warning {{null passed to a callee that requires a non-null argument}}
}
void PR18795(int (^g)(const char *h, ...) __attribute__((nonnull(1))) __attribute__((nonnull))) {
- g(0); // expected-warning{{null passed to a callee which requires a non-null argument}}
+ g(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
}
void PR18795_helper() {
- PR18795(0); // expected-warning{{null passed to a callee which requires a non-null argument}}
+ PR18795(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
}
diff --git a/test/SemaObjC/objc-cf-audited-warning.m b/test/SemaObjC/objc-cf-audited-warning.m
new file mode 100644
index 000000000000..db782299b8ab
--- /dev/null
+++ b/test/SemaObjC/objc-cf-audited-warning.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fobjc-arc -verify %s
+// rdar://18222007
+
+#if __has_feature(arc_cf_code_audited)
+#define CF_IMPLICIT_BRIDGING_ENABLED _Pragma("clang arc_cf_code_audited begin")
+#define CF_IMPLICIT_BRIDGING_DISABLED _Pragma("clang arc_cf_code_audited end")
+#endif
+#define CF_BRIDGED_TYPE(T) __attribute__((objc_bridge(T)))
+
+typedef const struct CF_BRIDGED_TYPE(NSURL) __CFURL * CFURLRef;
+typedef signed long long CFIndex;
+typedef unsigned char Boolean;
+typedef unsigned char UInt8;
+typedef const struct __CFAllocator * CFAllocatorRef;
+const CFAllocatorRef kCFAllocatorDefault;
+
+CF_IMPLICIT_BRIDGING_ENABLED
+CFURLRef CFURLCreateFromFileSystemRepresentation(CFAllocatorRef allocator, const UInt8 *buffer, CFIndex bufLen, Boolean isDirectory); // expected-note {{passing argument to parameter 'buffer' here}}
+CF_IMPLICIT_BRIDGING_DISABLED
+
+void saveImageToJPG(const char *filename)
+{
+ CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, filename, 10, 0); // expected-warning {{passing 'const char *' to parameter of type 'const UInt8 *' (aka 'const unsigned char *') converts between pointers to integer types with different sign}}
+}
diff --git a/test/SemaObjC/objc-dictionary-literal.m b/test/SemaObjC/objc-dictionary-literal.m
index 9d86d88bcbec..f9fd57f2dae2 100644
--- a/test/SemaObjC/objc-dictionary-literal.m
+++ b/test/SemaObjC/objc-dictionary-literal.m
@@ -3,6 +3,8 @@
// RUN: %clang_cc1 -fsyntax-only -triple i386-apple-macosx10.9.0 -fobjc-runtime=macosx-fragile-10.9.0 -fobjc-subscripting-legacy-runtime -verify %s
// rdar://15363492
+#define nil ((void *)0)
+
@interface NSNumber
+ (NSNumber *)numberWithChar:(char)value;
+ (NSNumber *)numberWithInt:(int)value;
@@ -15,6 +17,7 @@ typedef long NSInteger;
@interface NSDictionary
+ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt;
- (void)setObject:(id)object forKeyedSubscript:(id)key;
+- (id)objectForKeyedSubscript:(id)key;
@end
@interface NSString<NSCopying>
@@ -25,12 +28,24 @@ typedef long NSInteger;
- (void)setObject:(id)object atIndexedSubscript:(NSInteger)index;
@end
+void *pvoid;
int main() {
NSDictionary *dict = @{ @"name":@666 };
dict[@"name"] = @666;
dict["name"] = @666; // expected-error {{indexing expression is invalid because subscript type 'char *' is not an Objective-C pointer}}
+ // rdar://18254621
+ [@{@"foo" : @"bar"} objectForKeyedSubscript:nil];
+ (void)@{@"foo" : @"bar"}[nil];
+ [@{@"foo" : @"bar"} objectForKeyedSubscript:pvoid];
+ (void)@{@"foo" : @"bar"}[pvoid];
+
+ [@{@"foo" : @"bar"} setObject:nil forKeyedSubscript:@"gorf"];
+ @{@"foo" : @"bar"}[nil] = @"gorf";
+ [@{@"foo" : @"bar"} setObject:pvoid forKeyedSubscript:@"gorf"];
+ @{@"foo" : @"bar"}[pvoid] = @"gorf";
+
return 0;
}
diff --git a/test/SemaObjC/objcbridge-attribute-arc.m b/test/SemaObjC/objcbridge-attribute-arc.m
index ee2bf07ed47e..ab8cab8d1919 100644
--- a/test/SemaObjC/objcbridge-attribute-arc.m
+++ b/test/SemaObjC/objcbridge-attribute-arc.m
@@ -221,3 +221,19 @@ void Test9(CFErrorRef2 cf, NSError *ns, NSString *str, Class c, CFUColor2Ref cf2
(void)(__bridge Class)cf; // expected-warning {{'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, not 'Class'}}
(void)(__bridge CFErrorRef)c; // expected-warning {{'__unsafe_unretained Class' cannot bridge to 'CFErrorRef' (aka 'struct __CFErrorRef *')}}
}
+
+// rdar://19157264
+#if __has_feature(objc_bridge_id)
+typedef struct __attribute__((objc_bridge(id))) __CFFoo *CFFooRef;
+#endif
+
+id convert(CFFooRef obj) {
+ (void)(NSError *)obj; // expected-error {{cast of C pointer type 'CFFooRef' (aka 'struct __CFFoo *') to Objective-C pointer type 'NSError *' requires a bridged cast}} \
+ // expected-note {{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFFooRef' (aka 'struct __CFFoo *') into ARC}}
+ (void) (__bridge NSError *)obj;
+ (void) (id)obj; // expected-error {{cast of C pointer type 'CFFooRef' (aka 'struct __CFFoo *') to Objective-C pointer type 'id' requires a bridged cast}} \
+ // expected-note {{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFFooRef' (aka 'struct __CFFoo *') into ARC}}
+ return (__bridge id)obj;
+}
diff --git a/test/SemaObjC/property-user-setter.m b/test/SemaObjC/property-user-setter.m
index e84fad2394ab..7674c2b3a2cd 100644
--- a/test/SemaObjC/property-user-setter.m
+++ b/test/SemaObjC/property-user-setter.m
@@ -124,15 +124,16 @@ int main (void) {
@synthesize t, T;
@synthesize Pxyz, pxyz;
- (id) Meth {
- self.P = 0;
- self.q = 0;
+ self.P = 0; // expected-warning {{property 'P' not found on object of type 'rdar11363363 *'; did you mean to access property p?}}
+ self.q = 0; // expected-warning {{property 'q' not found on object of type 'rdar11363363 *'; did you mean to access property Q?}}
// rdar://11528439
self.t = 0; // expected-error {{synthesized properties 't' and 'T' both claim setter 'setT:'}}
self.T = 0; // expected-error {{synthesized properties 'T' and 't' both claim setter 'setT:'}}
self.Pxyz = 0; // expected-error {{synthesized properties 'Pxyz' and 'pxyz' both claim setter 'setPxyz:'}}
self.pxyz = 0; // expected-error {{synthesized properties 'pxyz' and 'Pxyz' both claim setter 'setPxyz:'}}
- self.R = 0;
- return self.R; // expected-error {{no getter method for read from property}}
+ self.r = 0;
+ return self.R; // expected-error {{no getter method for read from property}} \
+ // expected-warning {{property 'R' not found on object of type 'rdar11363363 *'; did you mean to access property r?}}
}
@end
diff --git a/test/SemaObjC/protocol-expr-1.m b/test/SemaObjC/protocol-expr-1.m
index 94a0d9e3e8b5..5ff3db474c75 100644
--- a/test/SemaObjC/protocol-expr-1.m
+++ b/test/SemaObjC/protocol-expr-1.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// expected-no-diagnostics
-@protocol fproto;
+@protocol fproto @end
@protocol p1
@end
diff --git a/test/SemaObjC/protocol-expr-neg-1.m b/test/SemaObjC/protocol-expr-neg-1.m
index 58ac8c0ca322..aed56c016b08 100644
--- a/test/SemaObjC/protocol-expr-neg-1.m
+++ b/test/SemaObjC/protocol-expr-neg-1.m
@@ -2,7 +2,7 @@
@class Protocol;
-@protocol fproto;
+@protocol fproto; // expected-note {{'fproto' declared here}}
@protocol p1
@end
@@ -12,8 +12,23 @@
int main()
{
Protocol *proto = @protocol(p1);
- Protocol *fproto = @protocol(fproto);
+ Protocol *fproto = @protocol(fproto); // expected-warning {{@protocol is using a forward protocol declaration of fproto}}
Protocol *pp = @protocol(i); // expected-error {{cannot find protocol declaration for 'i'}}
Protocol *p1p = @protocol(cl); // expected-error {{cannot find protocol declaration for 'cl'}}
}
+// rdar://17768630
+@protocol SuperProtocol; // expected-note {{'SuperProtocol' declared here}}
+@protocol TestProtocol; // expected-note {{'TestProtocol' declared here}}
+
+@interface I
+- (int) conformsToProtocol : (Protocol *)protocl;
+@end
+
+int doesConform(id foo) {
+ return [foo conformsToProtocol:@protocol(TestProtocol)]; // expected-warning {{@protocol is using a forward protocol declaration of TestProtocol}}
+}
+
+int doesConformSuper(id foo) {
+ return [foo conformsToProtocol:@protocol(SuperProtocol)]; // expected-warning {{@protocol is using a forward protocol declaration of SuperProtocol}}
+}
diff --git a/test/SemaObjC/protocols-suppress-conformance.m b/test/SemaObjC/protocols-suppress-conformance.m
index 299e44e8074e..a6604b7ff958 100644
--- a/test/SemaObjC/protocols-suppress-conformance.m
+++ b/test/SemaObjC/protocols-suppress-conformance.m
@@ -5,7 +5,7 @@
__attribute__((objc_protocol_requires_explicit_implementation))
@protocol Protocol
- (void) theBestOfTimes; // expected-note {{method 'theBestOfTimes' declared here}}
-@property (readonly) id theWorstOfTimes; // expected-note {{property declared here}}
+@property (readonly) id theWorstOfTimes; // expected-note {{property declared here}}
@end
// In this example, ClassA adopts the protocol. We won't
@@ -13,14 +13,14 @@ __attribute__((objc_protocol_requires_explicit_implementation))
// be adopted later by a subclass.
@interface ClassA <Protocol>
- (void) theBestOfTimes;
-@property (readonly) id theWorstOfTimes;
+@property (readonly) id theWorstOfTimes; // expected-note {{property declared here}}
@end
// This class subclasses ClassA (which also adopts 'Protocol').
@interface ClassB : ClassA <Protocol>
@end
-@implementation ClassB // expected-warning {{property 'theWorstOfTimes' requires method 'theWorstOfTimes' to be defined - use @synthesize, @dynamic or provide a method implementation in this class implementation}}
+@implementation ClassB // expected-warning {{property 'theWorstOfTimes' requires method 'theWorstOfTimes' to be defined - use @synthesize, @dynamic or provide a method implementation in this class implementation}}
@end
@interface ClassB_Good : ClassA <Protocol>
@@ -32,7 +32,7 @@ __attribute__((objc_protocol_requires_explicit_implementation))
@end
@interface ClassB_AlsoGood : ClassA <Protocol>
-@property (readonly) id theWorstOfTimes;
+@property (readonly) id theWorstOfTimes; // expected-warning {{auto property synthesis will not synthesize property 'theWorstOfTimes'; it will be implemented by its superclass}}
@end
// Default synthesis acts as if @dynamic
@@ -40,7 +40,7 @@ __attribute__((objc_protocol_requires_explicit_implementation))
// it is declared in ClassA. This is okay, since
// the author of ClassB_AlsoGood needs explicitly
// write @property in the @interface.
-@implementation ClassB_AlsoGood // no-warning
+@implementation ClassB_AlsoGood // expected-note {{detected while default synthesizing properties in class implementation}}
- (void) theBestOfTimes {}
@end
diff --git a/test/SemaObjC/resolve-method-in-global-pool.m b/test/SemaObjC/resolve-method-in-global-pool.m
new file mode 100644
index 000000000000..523856d663f6
--- /dev/null
+++ b/test/SemaObjC/resolve-method-in-global-pool.m
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
+// expected-no-diagnostics
+
+// rdar://16808765
+
+@interface NSObject
++ (void)clsMethod:(int*)arg;
+@end
+
+@class NSDictionary;
+@class NSError;
+
+@interface Foo : NSObject
+- (void)getDonuts:(void (^)(NSDictionary *, NSError *))replyBlock;
+- (void)getCake:(int*)arg, ...;
+@end
+
+@protocol Protocol
+@required
+- (void)getDonuts:(void (^)(NSDictionary *))replyBlock;
+- (void)getCake:(float*)arg, ...;
++ (void)clsMethod:(float*)arg;
+@end
+
+@implementation Foo
+{
+ float g;
+}
+
+- (void)getDonuts:(void (^)(NSDictionary *, NSError *))replyBlock {
+ [(id) 0 getDonuts:^(NSDictionary *replyDict) { }];
+}
+
+- (void) getCake:(int*)arg, ... {
+ [(id)0 getCake: &g, 1,3.14];
+}
+@end
+
+void func( Class c, float g ) {
+ [c clsMethod: &g];
+}
+
+// rdar://18095772
+@protocol NSKeyedArchiverDelegate @end
+
+@interface NSKeyedArchiver
+@property (assign) id <NSKeyedArchiverDelegate> delegate;
+@end
+
+@interface NSConnection
+@property (assign) id delegate;
+@end
+
+extern id NSApp;
+
+@interface AppDelegate
+@end
+
+AppDelegate* GetDelegate()
+{
+ return [NSApp delegate];
+}
diff --git a/test/SemaObjC/scope-check.m b/test/SemaObjC/scope-check.m
index e19ba47ad272..b52e7a06ffc2 100644
--- a/test/SemaObjC/scope-check.m
+++ b/test/SemaObjC/scope-check.m
@@ -3,9 +3,9 @@
@class A, B, C;
void test1() {
- goto L; // expected-error{{goto into protected scope}}
- goto L2; // expected-error{{goto into protected scope}}
- goto L3; // expected-error{{goto into protected scope}}
+ goto L; // expected-error{{cannot jump}}
+ goto L2; // expected-error{{cannot jump}}
+ goto L3; // expected-error{{cannot jump}}
@try { // expected-note {{jump bypasses initialization of @try block}}
L: ;
} @catch (A *x) { // expected-note {{jump bypasses initialization of @catch block}}
@@ -17,11 +17,11 @@ L3: ;
}
@try {
- goto L4; // expected-error{{goto into protected scope}}
- goto L5; // expected-error{{goto into protected scope}}
+ goto L4; // expected-error{{cannot jump}}
+ goto L5; // expected-error{{cannot jump}}
} @catch (C *c) { // expected-note {{jump bypasses initialization of @catch block}}
L5: ;
- goto L6; // expected-error{{goto into protected scope}}
+ goto L6; // expected-error{{cannot jump}}
} @catch (B *c) { // expected-note {{jump bypasses initialization of @catch block}}
L6: ;
} @finally { // expected-note {{jump bypasses initialization of @finally block}}
@@ -32,12 +32,12 @@ L3: ;
@try { // expected-note 2 {{jump bypasses initialization of @try block}}
L7: ;
} @catch (C *c) {
- goto L7; // expected-error{{goto into protected scope}}
+ goto L7; // expected-error{{cannot jump}}
} @finally {
- goto L7; // expected-error{{goto into protected scope}}
+ goto L7; // expected-error{{cannot jump}}
}
- goto L8; // expected-error{{goto into protected scope}}
+ goto L8; // expected-error{{cannot jump}}
@try {
} @catch (A *c) {
} @catch (B *c) {
@@ -47,7 +47,7 @@ L3: ;
// rdar://6810106
id X;
- goto L9; // expected-error{{goto into protected scope}}
+ goto L9; // expected-error{{cannot jump}}
goto L10; // ok
@synchronized // expected-note {{jump bypasses initialization of @synchronized block}}
( ({ L10: ; X; })) {
@@ -79,7 +79,7 @@ void test3() {
+ (void) hello {
@try {
- goto blargh; // expected-error {{goto into protected scope}}
+ goto blargh; // expected-error {{cannot jump}}
} @catch (...) { // expected-note {{jump bypasses initialization of @catch block}}
blargh: ;
}
@@ -87,14 +87,14 @@ void test3() {
+ (void)meth2 {
int n; void *P;
- goto L0; // expected-error {{goto into protected scope}}
+ goto L0; // expected-error {{cannot jump}}
typedef int A[n]; // expected-note {{jump bypasses initialization of VLA typedef}}
L0:
- goto L1; // expected-error {{goto into protected scope}}
+ goto L1; // expected-error {{cannot jump}}
A b, c[10]; // expected-note 2 {{jump bypasses initialization of variable length array}}
L1:
- goto L2; // expected-error {{goto into protected scope}}
+ goto L2; // expected-error {{cannot jump}}
A d[n]; // expected-note {{jump bypasses initialization of variable length array}}
L2:
return;
diff --git a/test/SemaObjC/super-property-notation.m b/test/SemaObjC/super-property-notation.m
index aa67f0af39dc..2b13a5c0f87c 100644
--- a/test/SemaObjC/super-property-notation.m
+++ b/test/SemaObjC/super-property-notation.m
@@ -30,7 +30,7 @@ void f0() {
// rdar://13349296
__attribute__((objc_root_class)) @interface ClassBase
-@property (nonatomic, retain) ClassBase * foo;
+@property (nonatomic, retain) ClassBase * foo; // expected-note {{property declared here}}
@end
@implementation ClassBase
@@ -41,10 +41,10 @@ __attribute__((objc_root_class)) @interface ClassBase
@end
@interface ClassDerived : ClassBase
-@property (nonatomic, retain) ClassDerived * foo;
+@property (nonatomic, retain) ClassDerived * foo; // expected-warning {{auto property synthesis will not synthesize property 'foo'; it will be implemented by its superclass}}
@end
-@implementation ClassDerived
+@implementation ClassDerived // expected-note {{detected while default synthesizing properties in class implementation}}
- (void) Meth:(ClassBase*)foo {
super.foo = foo; // must work with no warning
[super setFoo:foo]; // works with no warning
diff --git a/test/SemaObjC/warn-category-method-deprecated.m b/test/SemaObjC/warn-category-method-deprecated.m
new file mode 100644
index 000000000000..349a27a795c2
--- /dev/null
+++ b/test/SemaObjC/warn-category-method-deprecated.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-objc-root-class -verify %s
+// rdar://18013929
+
+@protocol P
+- (void)meth;
+@end
+
+@interface I <P>
+@end
+
+@interface I(cat)
+- (void)meth __attribute__((deprecated)); // expected-note {{'meth' has been explicitly marked deprecated here}}
+@end
+
+void foo(I *i) {
+ [i meth]; // expected-warning {{'meth' is deprecated}}
+}
diff --git a/test/SemaObjC/warn-explicit-call-initialize.m b/test/SemaObjC/warn-explicit-call-initialize.m
new file mode 100644
index 000000000000..99fdf530afd8
--- /dev/null
+++ b/test/SemaObjC/warn-explicit-call-initialize.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -verify %s
+// rdar://16628028
+
+@interface NSObject
++ (void)initialize; // expected-note 2 {{method 'initialize' declared here}}
+@end
+
+@interface I : NSObject
++ (void)initialize; // expected-note {{method 'initialize' declared here}}
++ (void)SomeRandomMethod;
+@end
+
+@implementation I
+- (void) Meth {
+ [I initialize]; // expected-warning {{explicit call to +initialize results in duplicate call to +initialize}}
+ [NSObject initialize]; // expected-warning {{explicit call to +initialize results in duplicate call to +initialize}}
+}
++ (void)initialize {
+ [super initialize];
+}
++ (void)SomeRandomMethod { // expected-note {{method 'SomeRandomMethod' declared here}}
+ [super initialize]; // expected-warning {{explicit call to [super initialize] should only be in implementation of +initialize}}
+}
+@end
+
diff --git a/test/SemaObjC/warn-strict-selector-match.m b/test/SemaObjC/warn-strict-selector-match.m
index 34f1712f8b58..9f22e73edc69 100644
--- a/test/SemaObjC/warn-strict-selector-match.m
+++ b/test/SemaObjC/warn-strict-selector-match.m
@@ -29,8 +29,7 @@ id foo(void) {
}
@protocol MyObject
-- (id)initWithData:(Object *)data; // expected-note {{using}} \
- // expected-note {{passing argument to parameter 'data' here}}
+- (id)initWithData:(Object *)data; // expected-note {{using}}
@end
@protocol SomeOther
@@ -54,8 +53,7 @@ id foo(void) {
}
+ (NTGridDataObject*)dataObject:(id<MyObject, MyCoding>)data
{
- NTGridDataObject *result = [(id)0 initWithData:data]; // expected-warning {{multiple methods named 'initWithData:' found}} \
- expected-warning {{sending 'id<MyObject,MyCoding>' to parameter of incompatible type 'Object *'}}
+ NTGridDataObject *result = [(id)0 initWithData:data]; // expected-warning {{multiple methods named 'initWithData:' found}}
return result;
}
@end
diff --git a/test/SemaObjCXX/arc-ppe.mm b/test/SemaObjCXX/arc-ppe.mm
index c9ff81110ddb..193f27316703 100644
--- a/test/SemaObjCXX/arc-ppe.mm
+++ b/test/SemaObjCXX/arc-ppe.mm
@@ -13,4 +13,4 @@ void test1() { (void)typeid(NP((void*)(id*)0)); }
class Poly { virtual ~Poly(); };
Poly& P(void*);
-void test2() { (void)typeid(P((void*)(id*)0)); } // expected-error {{pointer to non-const type 'id'}}
+void test2() { (void)typeid(P((void*)(id*)0)); } // expected-error {{pointer to non-const type 'id'}} expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
diff --git a/test/SemaObjCXX/synchronized.mm b/test/SemaObjCXX/synchronized.mm
new file mode 100644
index 000000000000..37305c5cca8c
--- /dev/null
+++ b/test/SemaObjCXX/synchronized.mm
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+
+@interface PBXTrackableTaskManager @end
+@implementation PBXTrackableTaskManager @end
+
+struct x {
+ operator PBXTrackableTaskManager *() const { return 0; }
+} a;
+
+struct y {
+ operator int *() const { return 0; }
+} b;
+
+void test1() {
+ @synchronized (a) {
+ }
+
+ @synchronized (b) { // expected-error {{@synchronized requires an Objective-C object type ('struct y' invalid)}}
+ }
+}
diff --git a/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl b/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
new file mode 100644
index 000000000000..50363f23a900
--- /dev/null
+++ b/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
@@ -0,0 +1,227 @@
+// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DCONSTANT -cl-std=CL2.0
+// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGLOBAL -cl-std=CL2.0
+// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGENERIC -cl-std=CL2.0
+
+/* OpenCLC v2.0 adds a set of restrictions for conversions between pointers to
+* different address spaces, mainly described in Sections 6.5.5 and 6.5.6.
+*
+* It adds notion of overlapping address spaces. The main differention is that
+* an unnamed address space is added, called '__generic'. Pointers to the
+* generic address space can be interchangabley used with pointers to any
+* other address space except for __constant address space (Section 6.5.5).
+*
+* Based on this there are 3 sets of tests: __generic, named (__global in this
+* case), and __constant, that should cover all program paths for CL address
+* space conversions used in initialisations, assignments, casts, comparisons
+* and arithmetic operations.
+*/
+
+#ifdef GENERIC
+#define AS generic
+#endif
+
+#ifdef GLOBAL
+#define AS global
+#endif
+
+#ifdef CONSTANT
+#define AS constant
+#endif
+
+void f_glob(global int *arg_glob) {}
+#ifndef GLOBAL
+// expected-note@-2{{passing argument to parameter 'arg_glob' here}}
+#endif
+
+void f_loc(local int *arg_loc) {
+} // expected-note@-1{{passing argument to parameter 'arg_loc' here}}
+
+void f_const(constant int *arg_const) {}
+#ifndef CONSTANT
+// expected-note@-2{{passing argument to parameter 'arg_const' here}}
+#endif
+
+void f_priv(private int *arg_priv) {
+} // expected-note@-1{{passing argument to parameter 'arg_priv' here}}
+
+void f_gen(generic int *arg_gen) {}
+#ifdef CONSTANT
+// expected-note@-2{{passing argument to parameter 'arg_gen' here}}
+#endif
+
+void test_conversion(global int *arg_glob, local int *arg_loc,
+ constant int *arg_const, private int *arg_priv,
+ generic int *arg_gen) {
+
+ AS int *var_init1 = arg_glob;
+#ifdef CONSTANT
+// expected-error@-2{{initializing '__constant int *' with an expression of type '__global int *' changes address space of pointer}}
+#endif
+
+ AS int *var_init2 = arg_loc;
+#ifndef GENERIC
+// expected-error-re@-2{{initializing '__{{global|constant}} int *' with an expression of type '__local int *' changes address space of pointer}}
+#endif
+
+ AS int *var_init3 = arg_const;
+#ifndef CONSTANT
+// expected-error-re@-2{{initializing '__{{global|generic}} int *' with an expression of type '__constant int *' changes address space of pointer}}
+#endif
+
+ AS int *var_init4 = arg_priv;
+#ifndef GENERIC
+// expected-error-re@-2{{initializing '__{{global|constant}} int *' with an expression of type 'int *' changes address space of pointer}}
+#endif
+
+ AS int *var_init5 = arg_gen;
+#ifndef GENERIC
+// expected-error-re@-2{{initializing '__{{global|constant}} int *' with an expression of type '__generic int *' changes address space of pointer}}
+#endif
+
+ AS int *var_cast1 = (AS int *)arg_glob;
+#ifdef CONSTANT
+// expected-error@-2{{casting '__global int *' to type '__constant int *' changes address space of pointer}}
+#endif
+
+ AS int *var_cast2 = (AS int *)arg_loc;
+#ifndef GENERIC
+// expected-error-re@-2{{casting '__local int *' to type '__{{global|constant}} int *' changes address space of pointer}}
+#endif
+
+ AS int *var_cast3 = (AS int *)arg_const;
+#ifndef CONSTANT
+// expected-error-re@-2{{casting '__constant int *' to type '__{{global|generic}} int *' changes address space of pointer}}
+#endif
+
+ AS int *var_cast4 = (AS int *)arg_priv;
+#ifndef GENERIC
+// expected-error-re@-2{{casting 'int *' to type '__{{global|constant}} int *' changes address space of pointer}}
+#endif
+
+ AS int *var_cast5 = (AS int *)arg_gen;
+#ifdef CONSTANT
+// expected-error@-2{{casting '__generic int *' to type '__constant int *' changes address space of pointer}}
+#endif
+
+ AS int *var_impl;
+ var_impl = arg_glob;
+#ifdef CONSTANT
+// expected-error@-2{{assigning '__global int *' to '__constant int *' changes address space of pointer}}
+#endif
+
+ var_impl = arg_loc;
+#ifndef GENERIC
+// expected-error-re@-2{{assigning '__local int *' to '__{{global|constant}} int *' changes address space of pointer}}
+#endif
+
+ var_impl = arg_const;
+#ifndef CONSTANT
+// expected-error-re@-2{{assigning '__constant int *' to '__{{global|generic}} int *' changes address space of pointer}}
+#endif
+
+ var_impl = arg_priv;
+#ifndef GENERIC
+// expected-error-re@-2{{assigning 'int *' to '__{{global|constant}} int *' changes address space of pointer}}
+#endif
+
+ var_impl = arg_gen;
+#ifndef GENERIC
+// expected-error-re@-2{{assigning '__generic int *' to '__{{global|constant}} int *' changes address space of pointer}}
+#endif
+
+ var_cast1 = (AS int *)arg_glob;
+#ifdef CONSTANT
+// expected-error@-2{{casting '__global int *' to type '__constant int *' changes address space of pointer}}
+#endif
+
+ var_cast2 = (AS int *)arg_loc;
+#ifndef GENERIC
+// expected-error-re@-2{{casting '__local int *' to type '__{{global|constant}} int *' changes address space of pointer}}
+#endif
+
+ var_cast3 = (AS int *)arg_const;
+#ifndef CONSTANT
+// expected-error-re@-2{{casting '__constant int *' to type '__{{global|generic}} int *' changes address space of pointer}}
+#endif
+
+ var_cast4 = (AS int *)arg_priv;
+#ifndef GENERIC
+// expected-error-re@-2{{casting 'int *' to type '__{{global|constant}} int *' changes address space of pointer}}
+#endif
+
+ var_cast5 = (AS int *)arg_gen;
+#ifdef CONSTANT
+// expected-error@-2{{casting '__generic int *' to type '__constant int *' changes address space of pointer}}
+#endif
+
+ AS int *var_cmp;
+ int b = var_cmp != arg_glob;
+#ifdef CONSTANT
+// expected-error@-2{{comparison between ('__constant int *' and '__global int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ b = var_cmp != arg_loc;
+#ifndef GENERIC
+// expected-error-re@-2{{comparison between ('__{{global|constant}} int *' and '__local int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ b = var_cmp == arg_const;
+#ifndef CONSTANT
+// expected-error-re@-2{{comparison between ('__{{global|generic}} int *' and '__constant int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ b = var_cmp <= arg_priv;
+#ifndef GENERIC
+// expected-error-re@-2{{comparison between ('__{{global|constant}} int *' and 'int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ b = var_cmp >= arg_gen;
+#ifdef CONSTANT
+// expected-error@-2{{comparison between ('__constant int *' and '__generic int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ AS int *var_sub;
+ b = var_sub - arg_glob;
+#ifdef CONSTANT
+// expected-error@-2{{arithmetic operation with operands of type ('__constant int *' and '__global int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ b = var_sub - arg_loc;
+#ifndef GENERIC
+// expected-error-re@-2{{arithmetic operation with operands of type ('__{{global|constant}} int *' and '__local int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ b = var_sub - arg_const;
+#ifndef CONSTANT
+// expected-error-re@-2{{arithmetic operation with operands of type ('__{{global|generic}} int *' and '__constant int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ b = var_sub - arg_priv;
+#ifndef GENERIC
+// expected-error-re@-2{{arithmetic operation with operands of type ('__{{global|constant}} int *' and 'int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ b = var_sub - arg_gen;
+#ifdef CONSTANT
+// expected-error@-2{{arithmetic operation with operands of type ('__constant int *' and '__generic int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ f_glob(var_sub);
+#ifndef GLOBAL
+// expected-error-re@-2{{passing '__{{constant|generic}} int *' to parameter of type '__global int *' changes address space of pointer}}
+#endif
+
+ f_loc(var_sub); // expected-error-re{{passing '__{{global|constant|generic}} int *' to parameter of type '__local int *' changes address space of pointer}}
+
+ f_const(var_sub);
+#ifndef CONSTANT
+// expected-error-re@-2{{passing '__{{global|generic}} int *' to parameter of type '__constant int *' changes address space of pointer}}
+#endif
+
+ f_priv(var_sub); // expected-error-re{{passing '__{{global|constant|generic}} int *' to parameter of type 'int *' changes address space of pointer}}
+
+ f_gen(var_sub);
+#ifdef CONSTANT
+// expected-error@-2{{passing '__constant int *' to parameter of type '__generic int *' changes address space of pointer}}
+#endif
+}
diff --git a/test/SemaOpenCL/address-spaces.cl b/test/SemaOpenCL/address-spaces.cl
index b188ea4576f1..7026d1bc086d 100644
--- a/test/SemaOpenCL/address-spaces.cl
+++ b/test/SemaOpenCL/address-spaces.cl
@@ -12,14 +12,16 @@ __kernel void foo(__global int *gip) {
ip = &ci; // expected-error {{assigning '__constant int *' to 'int *' changes address space of pointer}}
}
-void explicit_cast(global int* g, local int* l, constant int* c, private int* p)
+void explicit_cast(global int* g, local int* l, constant int* c, private int* p, const constant int *cc)
{
g = (global int*) l; // expected-error {{casting '__local int *' to type '__global int *' changes address space of pointer}}
g = (global int*) c; // expected-error {{casting '__constant int *' to type '__global int *' changes address space of pointer}}
+ g = (global int*) cc; // expected-error {{casting 'const __constant int *' to type '__global int *' changes address space of pointer}}
g = (global int*) p; // expected-error {{casting 'int *' to type '__global int *' changes address space of pointer}}
l = (local int*) g; // expected-error {{casting '__global int *' to type '__local int *' changes address space of pointer}}
l = (local int*) c; // expected-error {{casting '__constant int *' to type '__local int *' changes address space of pointer}}
+ l = (local int*) cc; // expected-error {{casting 'const __constant int *' to type '__local int *' changes address space of pointer}}
l = (local int*) p; // expected-error {{casting 'int *' to type '__local int *' changes address space of pointer}}
c = (constant int*) g; // expected-error {{casting '__global int *' to type '__constant int *' changes address space of pointer}}
@@ -29,6 +31,7 @@ void explicit_cast(global int* g, local int* l, constant int* c, private int* p)
p = (private int*) g; // expected-error {{casting '__global int *' to type 'int *' changes address space of pointer}}
p = (private int*) l; // expected-error {{casting '__local int *' to type 'int *' changes address space of pointer}}
p = (private int*) c; // expected-error {{casting '__constant int *' to type 'int *' changes address space of pointer}}
+ p = (private int*) cc; // expected-error {{casting 'const __constant int *' to type 'int *' changes address space of pointer}}
}
void ok_explicit_casts(global int *g, global int* g2, local int* l, local int* l2, private int* p, private int* p2)
diff --git a/test/SemaOpenCL/amdgpu-num-register-attrs.cl b/test/SemaOpenCL/amdgpu-num-register-attrs.cl
new file mode 100644
index 000000000000..ec8f8c072a23
--- /dev/null
+++ b/test/SemaOpenCL/amdgpu-num-register-attrs.cl
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple r600-- -verify -fsyntax-only %s
+
+typedef __attribute__((amdgpu_num_vgpr(128))) struct FooStruct { // expected-error {{'amdgpu_num_vgpr' attribute only applies to kernel functions}}
+ int x;
+ float y;
+} FooStruct;
+
+
+__attribute__((amdgpu_num_vgpr("ABC"))) kernel void foo2() {} // expected-error {{'amdgpu_num_vgpr' attribute requires an integer constant}}
+__attribute__((amdgpu_num_sgpr("ABC"))) kernel void foo3() {} // expected-error {{'amdgpu_num_sgpr' attribute requires an integer constant}}
+
+
+__attribute__((amdgpu_num_vgpr(40))) void foo4() {} // expected-error {{'amdgpu_num_vgpr' attribute only applies to kernel functions}}
+__attribute__((amdgpu_num_sgpr(64))) void foo5() {} // expected-error {{'amdgpu_num_sgpr' attribute only applies to kernel functions}}
+
+__attribute__((amdgpu_num_vgpr(40))) kernel void foo7() {}
+__attribute__((amdgpu_num_sgpr(64))) kernel void foo8() {}
+__attribute__((amdgpu_num_vgpr(40), amdgpu_num_sgpr(64))) kernel void foo9() {}
+
+// Check 0 VGPR is accepted.
+__attribute__((amdgpu_num_vgpr(0))) kernel void foo10() {}
+
+// Check 0 SGPR is accepted.
+__attribute__((amdgpu_num_sgpr(0))) kernel void foo11() {}
+
+// Check both 0 SGPR and VGPR is accepted.
+__attribute__((amdgpu_num_vgpr(0), amdgpu_num_sgpr(0))) kernel void foo12() {}
+
+// Too large VGPR value.
+__attribute__((amdgpu_num_vgpr(4294967296))) kernel void foo13() {} // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
+
+__attribute__((amdgpu_num_sgpr(4294967296))) kernel void foo14() {} // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
+
+__attribute__((amdgpu_num_sgpr(4294967296), amdgpu_num_vgpr(4294967296))) kernel void foo15() {} // expected-error 2 {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
+
+
+// Make sure it is accepted with kernel keyword before the attribute.
+kernel __attribute__((amdgpu_num_vgpr(40))) void foo16() {}
+
+kernel __attribute__((amdgpu_num_sgpr(40))) void foo17() {}
diff --git a/test/SemaOpenCL/extern.cl b/test/SemaOpenCL/extern.cl
index ee5e07237f06..b2e4857e28da 100644
--- a/test/SemaOpenCL/extern.cl
+++ b/test/SemaOpenCL/extern.cl
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -x cl -cl-std=CL1.2 -emit-llvm %s -o - -verify | FileCheck %s
+// RUN: %clang_cc1 -x cl -cl-std=CL1.2 -emit-llvm -ffake-address-space-map %s -o - -verify | FileCheck %s
// expected-no-diagnostics
-// CHECK: @foo = external global float
+// CHECK: @foo = external addrspace(3) constant float
extern constant float foo;
kernel void test(global float* buf) {
diff --git a/test/SemaTemplate/canonical-expr-type.cpp b/test/SemaTemplate/canonical-expr-type.cpp
index 4770c4fa3ed6..f8d7d7ec1a27 100644
--- a/test/SemaTemplate/canonical-expr-type.cpp
+++ b/test/SemaTemplate/canonical-expr-type.cpp
@@ -47,3 +47,11 @@ struct X2 {
void f0(type2);
void f0(type3); // expected-error{{redeclared}}
};
+
+// Test canonicalization doesn't conflate different literal suffixes.
+template<typename T> void literal_suffix(int (&)[sizeof(T() + 0)]) {}
+template<typename T> void literal_suffix(int (&)[sizeof(T() + 0L)]) {}
+template<typename T> void literal_suffix(int (&)[sizeof(T() + 0LL)]) {}
+template<typename T> void literal_suffix(int (&)[sizeof(T() + 0.f)]) {}
+template<typename T> void literal_suffix(int (&)[sizeof(T() + 0.)]) {}
+template<typename T> void literal_suffix(int (&)[sizeof(T() + 0.l)]) {}
diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp
index b721aab35464..c67361bfeafb 100644
--- a/test/SemaTemplate/class-template-decl.cpp
+++ b/test/SemaTemplate/class-template-decl.cpp
@@ -57,7 +57,7 @@ void f() {
template<typename T> class X; // expected-error{{expression}}
}
-template<typename T> class X1 var; // expected-warning{{variable templates are a C++1y extension}} \
+template<typename T> class X1 var; // expected-warning{{variable templates are a C++14 extension}} \
// expected-error {{variable has incomplete type 'class X1'}} \
// expected-note {{forward declaration of 'X1'}}
diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp
index cf3fdfb7c1ea..c5306a6e32f4 100644
--- a/test/SemaTemplate/constructor-template.cpp
+++ b/test/SemaTemplate/constructor-template.cpp
@@ -54,7 +54,7 @@ struct B { A<int> x; B(B& a) : x(a.x) {} };
struct X2 {
X2(); // expected-note{{candidate constructor}}
X2(X2&); // expected-note {{candidate constructor}}
- template<typename T> X2(T);
+ template<typename T> X2(T); // expected-note {{candidate template ignored: instantiation would take its own class type by value}}
};
X2 test(bool Cond, X2 x2) {
@@ -126,3 +126,51 @@ namespace PR8182 {
}
}
+
+// Don't blow out the stack trying to call an illegal constructor
+// instantiation. We intentionally allow implicit instantiations to
+// exist, so make sure they're unusable.
+//
+// rdar://19199836
+namespace self_by_value {
+ template <class T, class U> struct A {
+ A() {}
+ A(const A<T,U> &o) {}
+ A(A<T,T> o) {}
+ };
+
+ void helper(A<int,float>);
+
+ void test1(A<int,int> a) {
+ helper(a);
+ }
+ void test2() {
+ helper(A<int,int>());
+ }
+}
+
+namespace self_by_value_2 {
+ template <class T, class U> struct A {
+ A() {} // expected-note {{not viable: requires 0 arguments}}
+ A(A<T,U> &o) {} // expected-note {{not viable: expects an l-value}}
+ A(A<T,T> o) {} // expected-note {{ignored: instantiation takes its own class type by value}}
+ };
+
+ void helper_A(A<int,int>); // expected-note {{passing argument to parameter here}}
+ void test_A() {
+ helper_A(A<int,int>()); // expected-error {{no matching constructor}}
+ }
+}
+
+namespace self_by_value_3 {
+ template <class T, class U> struct A {
+ A() {}
+ A(A<T,U> &o) {}
+ A(A<T,T> o) {}
+ };
+
+ void helper_A(A<int,int>);
+ void test_A(A<int,int> b) {
+ helper_A(b);
+ }
+}
diff --git a/test/SemaTemplate/crash.cpp b/test/SemaTemplate/crash.cpp
new file mode 100644
index 000000000000..428e95ccf96e
--- /dev/null
+++ b/test/SemaTemplate/crash.cpp
@@ -0,0 +1,11 @@
+// RUN: not %clang_cc1 -verify %s -std=c++11
+
+// PR17730
+template <typename T>
+void S<T>::mem1();
+
+template <typename T>
+void S<T>::mem2() {
+ const int I = sizeof(T);
+ (void)I;
+}
diff --git a/test/SemaTemplate/cxx1z-fold-expressions.cpp b/test/SemaTemplate/cxx1z-fold-expressions.cpp
new file mode 100644
index 000000000000..8bb79113fa9d
--- /dev/null
+++ b/test/SemaTemplate/cxx1z-fold-expressions.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+template<typename ...T> constexpr auto sum(T ...t) { return (... + t); }
+template<typename ...T> constexpr auto product(T ...t) { return (t * ...); }
+template<typename ...T> constexpr auto all(T ...t) { return (true && ... && t); }
+template<typename ...T> constexpr auto dumb(T ...t) { return (false && ... && t); }
+
+static_assert(sum(1, 2, 3, 4, 5) == 15);
+static_assert(product(1, 2, 3, 4, 5) == 120);
+static_assert(!all(true, true, false, true, false));
+static_assert(all(true, true, true, true, true));
+static_assert(!dumb(true, true, true, true, true));
+
+struct S {
+ int a, b, c, d, e;
+};
+template<typename ...T> constexpr auto increment_all(T &...t) {
+ (++t, ...);
+}
+constexpr bool check() {
+ S s = { 1, 2, 3, 4, 5 };
+ increment_all(s.a, s.b, s.c, s.d, s.e);
+ return s.a == 2 && s.b == 3 && s.c == 4 && s.d == 5 && s.e == 6;
+}
+static_assert(check());
+
+template<int ...N> void empty() {
+ static_assert((N + ...) == 0);
+ static_assert((N * ...) == 1);
+ static_assert((N | ...) == 0);
+ static_assert((N & ...) == -1);
+ static_assert((N || ...) == false);
+ static_assert((N && ...) == true);
+ (N, ...);
+}
+template void empty<>();
+
+// An empty fold-expression isn't a null pointer just because it's an integer
+// with value 0.
+template<int ...N> void null_ptr() {
+ void *p = (N + ...); // expected-error {{rvalue of type 'int'}}
+ void *q = (N | ...); // expected-error {{rvalue of type 'int'}}
+}
+template void null_ptr<>(); // expected-note {{in instantiation of}}
+
+template<int ...N> void bad_empty() {
+ (N - ...); // expected-error {{empty expansion for operator '-' with no fallback}}
+ (N / ...); // expected-error {{empty expansion for operator '/' with no fallback}}
+ (N % ...); // expected-error {{empty expansion for operator '%' with no fallback}}
+ (N = ...); // expected-error {{empty expansion for operator '=' with no fallback}}
+}
+template void bad_empty<>(); // expected-note {{in instantiation of}}
+
+template<int ...N> void empty_with_base() {
+ extern int k;
+ (k = ... = N); // expected-warning{{unused}}
+
+ void (k = ... = N); // expected-error {{expected ')'}} expected-note {{to match}}
+ void ((k = ... = N));
+ (void) (k = ... = N);
+}
+template void empty_with_base<>(); // expected-note {{in instantiation of}}
+template void empty_with_base<1>();
+
+struct A {
+ struct B {
+ struct C {
+ struct D {
+ int e;
+ } d;
+ } c;
+ } b;
+} a;
+template<typename T, typename ...Ts> constexpr decltype(auto) apply(T &t, Ts ...ts) {
+ return (t.*....*ts);
+}
+static_assert(&apply(a, &A::b, &A::B::c, &A::B::C::d, &A::B::C::D::e) == &a.b.c.d.e);
diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp
index e9422898c07d..c59f10dbb12e 100644
--- a/test/SemaTemplate/deduction.cpp
+++ b/test/SemaTemplate/deduction.cpp
@@ -107,7 +107,7 @@ namespace PR7463 {
}
namespace test0 {
- template <class T> void make(const T *(*fn)()); // expected-note {{candidate template ignored: can't deduce a type for 'T' which would make 'const T' equal 'char'}}
+ template <class T> void make(const T *(*fn)()); // expected-note {{candidate template ignored: can't deduce a type for 'T' that would make 'const T' equal 'char'}}
char *char_maker();
void test() {
make(char_maker); // expected-error {{no matching function for call to 'make'}}
@@ -191,4 +191,14 @@ namespace PR19372 {
using U = BindBack<Z, int, int>::apply<char>;
using U = Z<char, int, int>;
+
+ namespace BetterReduction {
+ template<typename ...> struct S;
+ template<typename ...A> using X = S<A...>; // expected-note {{parameter}}
+ template<typename ...A> using Y = X<A..., A...>;
+ template<typename ...A> using Z = X<A..., 1, 2, 3>; // expected-error {{must be a type}}
+
+ using T = Y<int>;
+ using T = S<int, int>;
+ }
}
diff --git a/test/SemaTemplate/dependent-type-identity.cpp b/test/SemaTemplate/dependent-type-identity.cpp
index a796834ce01a..5b9da5d89258 100644
--- a/test/SemaTemplate/dependent-type-identity.cpp
+++ b/test/SemaTemplate/dependent-type-identity.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// This test concerns the identity of dependent types within the
// canonical type system. This corresponds to C++ [temp.type], which
@@ -122,3 +122,24 @@ namespace PR18275 {
template struct A<int>;
template struct A<int[1]>;
}
+
+namespace PR21289 {
+ template<typename T> using X = int;
+ template<typename T, decltype(sizeof(0))> using Y = int;
+ template<typename ...Ts> struct S {};
+ template<typename ...Ts> void f() {
+ // This is a dependent type. It is *not* S<int>, even though it canonically
+ // contains no template parameters.
+ using Type = S<X<Ts>...>;
+ Type s;
+ using Type = S<int, int, int>;
+ }
+ void g() { f<void, void, void>(); }
+
+ template<typename ...Ts> void h(S<int>) {}
+ // Pending a core issue, it's not clear if these are redeclarations, but they
+ // are probably intended to be... even though substitution can succeed for one
+ // of them but fail for the other!
+ template<typename ...Ts> void h(S<X<Ts>...>) {} // expected-note {{previous}}
+ template<typename ...Ts> void h(S<Y<Ts, sizeof(Ts)>...>) {} // expected-error {{redefinition}}
+}
diff --git a/test/SemaTemplate/derived.cpp b/test/SemaTemplate/derived.cpp
index ce20cea7dcc5..cbd004cf6195 100644
--- a/test/SemaTemplate/derived.cpp
+++ b/test/SemaTemplate/derived.cpp
@@ -4,8 +4,8 @@
template<typename T> class vector2 {};
template<typename T> class vector : vector2<T> {};
-template<typename T> void Foo2(vector2<const T*> V) {} // expected-note{{candidate template ignored: can't deduce a type for 'T' which would make 'const T' equal 'int'}}
-template<typename T> void Foo(vector<const T*> V) {} // expected-note {{candidate template ignored: can't deduce a type for 'T' which would make 'const T' equal 'int'}}
+template<typename T> void Foo2(vector2<const T*> V) {} // expected-note{{candidate template ignored: can't deduce a type for 'T' that would make 'const T' equal 'int'}}
+template<typename T> void Foo(vector<const T*> V) {} // expected-note {{candidate template ignored: can't deduce a type for 'T' that would make 'const T' equal 'int'}}
void test() {
Foo2(vector2<int*>()); // expected-error{{no matching function for call to 'Foo2'}}
diff --git a/test/SemaTemplate/enum-bool.cpp b/test/SemaTemplate/enum-bool.cpp
new file mode 100644
index 000000000000..31a96e3488ed
--- /dev/null
+++ b/test/SemaTemplate/enum-bool.cpp
@@ -0,0 +1,11 @@
+// %RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o %t
+
+enum E : bool { A };
+template <E>
+struct S {
+ struct Inner {
+ Inner() {}
+ };
+};
+
+template class S<A>;
diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp
index c28c5d183150..040a932e9720 100644
--- a/test/SemaTemplate/explicit-instantiation.cpp
+++ b/test/SemaTemplate/explicit-instantiation.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fcxx-exceptions -std=c++11 %s
template void *; // expected-error{{expected unqualified-id}}
@@ -13,8 +14,8 @@ struct X0 {
T f0(T x) {
return x + 1; // expected-error{{invalid operands}}
- }
- T* f0(T*, T*) { return T(); } // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}}
+ }
+ T *f0(T *, T *) { return T(); } // expected-warning 0-1 {{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} expected-error 0-1 {{cannot initialize return object of type 'int *' with an rvalue of type 'int'}}
template <typename U> T f0(T, U) { return T(); } // expected-note-re {{candidate template ignored: could not match 'int (int, U){{( __attribute__\(\(thiscall\)\))?}}' against 'int (int){{( __attribute__\(\(thiscall\)\))?}} const'}} \
// expected-note {{candidate template ignored: could not match 'int' against 'int *'}}
@@ -25,7 +26,7 @@ T X0<T>::value; // expected-error{{no matching constructor}}
template int X0<int>::value;
-struct NotDefaultConstructible { // expected-note{{candidate constructor (the implicit copy constructor)}}
+struct NotDefaultConstructible { // expected-note{{candidate constructor (the implicit copy constructor)}} expected-note 0-1 {{candidate constructor (the implicit move constructor)}}
NotDefaultConstructible(int); // expected-note{{candidate constructor}}
};
@@ -149,3 +150,33 @@ namespace undefined_static_data_member {
template int C<int>::b<int>;
template int D::c<int>;
}
+
+// expected-note@+1 3-4 {{explicit instantiation refers here}}
+template <class T> void Foo(T i) throw(T) { throw i; }
+// expected-error@+1 {{exception specification in explicit instantiation does not match instantiated one}}
+template void Foo(int a) throw(char);
+// expected-error@+1 {{exception specification in explicit instantiation does not match instantiated one}}
+template void Foo(double a) throw();
+// expected-error@+1 1 {{exception specification in explicit instantiation does not match instantiated one}}
+template void Foo(long a) throw(long, char);
+template void Foo(float a);
+#if __cplusplus >= 201103L
+// expected-error@+1 0-1 {{exception specification in explicit instantiation does not match instantiated one}}
+template void Foo(double a) noexcept;
+#endif
+
+#if __cplusplus >= 201103L
+namespace PR21942 {
+template <int>
+struct A {
+ virtual void foo() final;
+};
+
+template <>
+void A<0>::foo() {} // expected-note{{overridden virtual function is here}}
+
+struct B : A<0> {
+ virtual void foo() override; // expected-error{{declaration of 'foo' overrides a 'final' function}}
+};
+}
+#endif
diff --git a/test/SemaTemplate/function-template-specialization-noreturn.cpp b/test/SemaTemplate/function-template-specialization-noreturn.cpp
index 3e1f61855a50..672da2725470 100644
--- a/test/SemaTemplate/function-template-specialization-noreturn.cpp
+++ b/test/SemaTemplate/function-template-specialization-noreturn.cpp
@@ -6,3 +6,15 @@
template <int N> void __attribute__((noreturn)) f3() { __builtin_unreachable(); }
template <> void f3<1>() { } // expected-warning {{function declared 'noreturn' should not return}}
+
+#if __cplusplus >= 201103L
+namespace PR21942 {
+template <int>
+struct A {
+ void foo[[noreturn]]();
+};
+
+template <>
+void A<0>::foo() {} // expected-warning{{function declared 'noreturn' should not return}}
+}
+#endif
diff --git a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
index a376f0e5fd5b..f62ef61758a4 100644
--- a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
+++ b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
@@ -58,6 +58,13 @@ namespace dr1330_example {
S().f<S>(); // ok
S().f<int>(); // expected-note {{instantiation of exception spec}}
}
+
+ template<typename T>
+ struct U {
+ void f() noexcept(T::error);
+ void (g)() noexcept(T::error);
+ };
+ U<int> uint; // ok
}
namespace core_19754_example {
@@ -137,3 +144,37 @@ namespace PR12763 {
};
void X::g() {} // expected-note {{in instantiation of}}
}
+
+namespace Variadic {
+ template<bool B> void check() { static_assert(B, ""); }
+ template<bool B, bool B2, bool ...Bs> void check() { static_assert(B, ""); check<B2, Bs...>(); }
+
+ template<typename ...T> void consume(T...);
+
+ template<typename ...T> void f(void (*...p)() throw (T)) {
+ void (*q[])() = { p... };
+ consume((p(),0)...);
+ }
+ template<bool ...B> void g(void (*...p)() noexcept (B)) {
+ consume((p(),0)...);
+ check<noexcept(p()) == B ...>();
+ }
+ template<typename ...T> void i() {
+ consume([]() throw(T) {} ...);
+ consume([]() noexcept(sizeof(T) == 4) {} ...);
+ }
+ template<bool ...B> void j() {
+ consume([](void (*p)() noexcept(B)) {
+ void (*q)() noexcept = p; // expected-error {{not superset of source}}
+ } ...);
+ }
+
+ void z() {
+ f<int, char, double>(nullptr, nullptr, nullptr);
+ g<true, false, true>(nullptr, nullptr, nullptr);
+ i<int, long, short>();
+ j<true, true>();
+ j<true, false>(); // expected-note {{in instantiation of}}
+ }
+
+}
diff --git a/test/SemaTemplate/instantiate-exception-spec.cpp b/test/SemaTemplate/instantiate-exception-spec.cpp
index 993ee8dfae1f..d3411722283c 100644
--- a/test/SemaTemplate/instantiate-exception-spec.cpp
+++ b/test/SemaTemplate/instantiate-exception-spec.cpp
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -verify %s -DERRORS
+// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -emit-llvm-only %s
+#ifdef ERRORS
template<typename T> void f1(T*) throw(T); // expected-error{{incomplete type 'Incomplete' is not allowed in exception specification}}
struct Incomplete; // expected-note{{forward}}
@@ -7,3 +9,20 @@ void test_f1(Incomplete *incomplete_p, int *int_p) {
f1(int_p);
f1(incomplete_p); // expected-note{{instantiation of}}
}
+#endif
+
+template<typename T> void f(void (*p)() throw(T)) {
+#ifdef ERRORS
+ void (*q)() throw(char) = p; // expected-error {{target exception spec}}
+
+ extern void (*p2)() throw(T);
+ void (*q2)() throw(char) = p2; // expected-error {{target exception spec}}
+
+ extern void (*p3)() throw(char);
+ void (*q3)() throw(T) = p3; // expected-error {{target exception spec}}
+
+ void (*q4)() throw(T) = p2; // ok
+#endif
+ p();
+}
+void g() { f<int>(0); } // expected-note {{instantiation of}}
diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp
index e7772435865d..820ee38e3eab 100644
--- a/test/SemaTemplate/instantiate-expr-1.cpp
+++ b/test/SemaTemplate/instantiate-expr-1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-pc-linux-gnu
template<int I, int J>
struct Bitfields {
int simple : I; // expected-error{{bit-field 'simple' has zero width}}
diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp
index 22c70be3a8dc..e9be60d16c1f 100644
--- a/test/SemaTemplate/instantiate-init.cpp
+++ b/test/SemaTemplate/instantiate-init.cpp
@@ -115,6 +115,7 @@ namespace PR13064 {
struct A { explicit A(int); }; // expected-note{{here}}
template<typename T> struct B { T a { 0 }; };
B<A> b;
+ // expected-note@+1 {{in instantiation of default member initializer}}
template<typename T> struct C { T a = { 0 }; }; // expected-error{{explicit}}
C<A> c; // expected-note{{here}}
}
@@ -133,3 +134,12 @@ namespace PR16903 {
fun(in);
}
}
+
+namespace ReturnStmtIsInitialization {
+ struct X {
+ X() {}
+ X(const X &) = delete;
+ };
+ template<typename T> X f() { return {}; }
+ auto &&x = f<void>();
+}
diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp
index 58cb89795558..961884417b54 100644
--- a/test/SemaTemplate/instantiate-method.cpp
+++ b/test/SemaTemplate/instantiate-method.cpp
@@ -182,3 +182,28 @@ namespace SameSignatureAfterInstantiation {
};
S<const int> s; // expected-note {{instantiation}}
}
+
+namespace PR22040 {
+ template <typename T> struct Foobar {
+ template <> void bazqux(typename T::type) {} // expected-error {{cannot specialize a function 'bazqux' within class scope}} expected-error 2{{cannot be used prior to '::' because it has no members}}
+ };
+
+ void test() {
+ // FIXME: we should suppress the "no member" errors
+ Foobar<void>::bazqux(); // expected-error{{no member named 'bazqux' in }} expected-note{{in instantiation of template class }}
+ Foobar<int>::bazqux(); // expected-error{{no member named 'bazqux' in }} expected-note{{in instantiation of template class }}
+ Foobar<int>::bazqux(3); // expected-error{{no member named 'bazqux' in }}
+ }
+}
+
+template <typename>
+struct SpecializationOfGlobalFnInClassScope {
+ template <>
+ void ::Fn(); // expected-error{{cannot have a qualified name}}
+};
+
+class AbstractClassWithGlobalFn {
+ template <typename>
+ void ::f(); // expected-error{{cannot have a qualified name}}
+ virtual void f1() = 0;
+};
diff --git a/test/SemaTemplate/instantiate-non-dependent-types.cpp b/test/SemaTemplate/instantiate-non-dependent-types.cpp
index a0005c56675a..432b9053bdca 100644
--- a/test/SemaTemplate/instantiate-non-dependent-types.cpp
+++ b/test/SemaTemplate/instantiate-non-dependent-types.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T>
struct X1 {
static void member() { T* x = 1; } // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}}
@@ -11,4 +12,41 @@ struct X2 {
typedef instantiate<&X1<int>::member> i; // expected-note{{in instantiation of}}
};
-X2<int> x;
+X2<int> x;
+
+template <class T, class A> class C {
+public:
+ int i;
+ void f(T &t) {
+ T *q = new T();
+ t.T::~T();
+ q->~T();
+ // expected-error@+2 {{'int' is not a class, namespace, or scoped enumeration}}
+ // expected-error@+1 {{no member named '~Colors' in 'Colors'}}
+ q->A::~A();
+ // expected-error@+2 {{no member named '~int' in 'Q'}}
+ // expected-error@+1 {{no member named '~Colors' in 'Q'}}
+ q->~A();
+
+ delete q;
+ }
+};
+
+class Q {
+public:
+ Q() {}
+ ~Q() {}
+};
+
+enum Colors {red, green, blue};
+
+C<Q, int> dummy;
+C<Q, Colors> dummyColors;
+int main() {
+ Q qinst;
+ // expected-note@+1 {{in instantiation of member function 'C<Q, int>::f' requested here}}
+ dummy.f(qinst);
+ // expected-note@+1 {{in instantiation of member function 'C<Q, Colors>::f' requested here}}
+ dummyColors.f(qinst);
+}
+
diff --git a/test/SemaTemplate/instantiate-scope.cpp b/test/SemaTemplate/instantiate-scope.cpp
new file mode 100644
index 000000000000..733105674b7a
--- /dev/null
+++ b/test/SemaTemplate/instantiate-scope.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<typename ...T> struct X {
+ void f(int);
+ void f(...);
+ static int n;
+};
+
+template<typename T, typename U> using A = T;
+
+// These definitions are OK, X<A<T, decltype(...)>...> is equivalent to X<T...>
+// so this defines the member of the primary template.
+template<typename ...T>
+void X<A<T, decltype(f(T()))>...>::f(int) {} // expected-error {{undeclared}}
+
+template<typename ...T>
+int X<A<T, decltype(f(T()))>...>::n = 0; // expected-error {{undeclared}}
+
+struct Y {}; void f(Y);
+
+void g() {
+ // OK, substitution succeeds.
+ X<Y>().f(0);
+ X<Y>::n = 1;
+
+ // Error, substitution fails; this should not be treated as a SFINAE-able
+ // condition, so we don't select X<void>::f(...).
+ X<void>().f(0); // expected-note {{instantiation of}}
+ X<void>::n = 1; // expected-note {{instantiation of}}
+}
diff --git a/test/SemaTemplate/instantiate-typeof.cpp b/test/SemaTemplate/instantiate-typeof.cpp
index 92873cb4b0b6..f4d7847e4fa6 100644
--- a/test/SemaTemplate/instantiate-typeof.cpp
+++ b/test/SemaTemplate/instantiate-typeof.cpp
@@ -1,10 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
// Make sure we correctly treat __typeof as potentially-evaluated when appropriate
template<typename T> void f(T n) {
- int buffer[n]; // expected-note {{declared here}}
- [] { __typeof(buffer) x; }(); // expected-error {{variable 'buffer' with variably modified type cannot be captured in a lambda expression}}
+ int buffer[n];
+ [&buffer] { __typeof(buffer) x; }();
}
int main() {
- f<int>(1); // expected-note {{in instantiation}}
+ f<int>(1);
}
diff --git a/test/SemaTemplate/lookup-dependent-bases.cpp b/test/SemaTemplate/lookup-dependent-bases.cpp
index 61fca4a2a45f..f7867d8339bb 100644
--- a/test/SemaTemplate/lookup-dependent-bases.cpp
+++ b/test/SemaTemplate/lookup-dependent-bases.cpp
@@ -1,20 +1,55 @@
// RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s
-// expected-no-diagnostics
-class C {
-public:
- static void foo2() { }
+namespace basic {
+struct C {
+ static void foo2() {}
};
-template <class T>
-class A {
-public:
- typedef C D;
+template <typename T>
+struct A {
+ typedef C D;
};
-template <class T>
-class B : public A<T> {
-public:
- void foo() {
- D::foo2();
- }
+template <typename T>
+struct B : A<T> {
+ void foo() {
+ D::foo2(); // expected-warning {{use of undeclared identifier 'D'; unqualified lookup into dependent bases of class template 'B' is a Microsoft extension}}
+ }
};
+
+template struct B<int>; // Instantiation has no warnings.
+}
+
+namespace nested_nodep_base {
+// There are limits to our hacks, MSVC accepts this, but we don't.
+struct A {
+ struct D { static void foo2(); };
+};
+template <typename T>
+struct B : T {
+ struct C {
+ void foo() {
+ D::foo2(); // expected-error {{use of undeclared identifier 'D'}}
+ }
+ };
+};
+
+template struct B<A>; // Instantiation has no warnings.
+}
+
+namespace nested_dep_base {
+// We actually accept this because the inner class has a dependent base even
+// though it isn't a template.
+struct A {
+ struct D { static void foo2(); };
+};
+template <typename T>
+struct B {
+ struct C : T {
+ void foo() {
+ D::foo2(); // expected-warning {{use of undeclared identifier 'D'; unqualified lookup into dependent bases of class template 'C' is a Microsoft extension}}
+ }
+ };
+};
+
+template struct B<A>; // Instantiation has no warnings.
+}
diff --git a/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
index 40f73c0d9e64..979782f1cba8 100644
--- a/test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -220,7 +220,8 @@ template <typename T> struct C : T {
int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} expected-warning {{lookup into dependent bases}}
int baz() { return T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}}
int T::*qux() { return &T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}}
- int T::*fuz() { return &U::a; } // expected-error {{use of undeclared identifier 'U'}}
+ int T::*fuz() { return &U::a; } // expected-error {{use of undeclared identifier 'U'}} \
+ // expected-warning {{unqualified lookup into dependent bases of class template 'C'}}
};
template struct B<A>;
@@ -249,7 +250,8 @@ struct A : T {
::UndefClass::undef(); // expected-error {{no member named 'UndefClass' in the global namespace}}
}
void baz() {
- B::qux(); // expected-error {{use of undeclared identifier 'B'}}
+ B::qux(); // expected-error {{use of undeclared identifier 'B'}} \
+ // expected-warning {{unqualified lookup into dependent bases of class template 'A'}}
}
};
@@ -460,3 +462,31 @@ template <typename T> struct D : C<T> {
int x = f<NameFromBase>();
};
}
+
+namespace function_template_undef_impl {
+template<class T>
+void f() {
+ Undef::staticMethod(); // expected-error {{use of undeclared identifier 'Undef'}}
+ UndefVar.method(); // expected-error {{use of undeclared identifier 'UndefVar'}}
+}
+}
+
+namespace PR20716 {
+template <template <typename T> class A>
+struct B : A<int>
+{
+ XXX x; // expected-error {{unknown type name}}
+};
+
+template <typename T>
+struct C {};
+
+template <typename T>
+using D = C<T>;
+
+template <typename T>
+struct E : D<T>
+{
+ XXX x; // expected-error {{unknown type name}}
+};
+}
diff --git a/test/SemaTemplate/pack-deduction.cpp b/test/SemaTemplate/pack-deduction.cpp
index f3f969e9af00..84eefa63d215 100644
--- a/test/SemaTemplate/pack-deduction.cpp
+++ b/test/SemaTemplate/pack-deduction.cpp
@@ -37,3 +37,31 @@ namespace RetainExprPacks {
template<typename ...Ts> int g(X<Ts...>, decltype(f(Ts()...)));
int n = g<int, int>(X<int, int, int>(), 0);
}
+
+namespace PR14615 {
+ namespace comment0 {
+ template <class A, class...> struct X {};
+ template <class... B> struct X<int, B...> {
+ typedef int type;
+ struct valid {};
+ };
+ template <typename A, typename... B, typename T = X<A, B...>,
+ typename = typename T::valid>
+ typename T::type check(int);
+ int i = check<int, char>(1);
+ }
+
+ namespace comment2 {
+ template <class...> struct X;
+ template <typename... B, typename X<B...>::type I = 0>
+ char check(B...); // expected-note {{undefined template 'PR14615::comment2::X<char, int>'}}
+ void f() { check<char>(1, 2); } // expected-error {{no matching function}}
+ }
+
+ namespace comment3 {
+ template <class...> struct X;
+ template <typename... B, typename X<B...>::type I = (typename X<B...>::type)0>
+ char check(B...); // expected-note {{undefined template 'PR14615::comment3::X<char, int>'}}
+ void f() { check<char>(1, 2); } // expected-error {{no matching function}}
+ }
+}
diff --git a/test/SemaTemplate/temp_arg_enum_printing.cpp b/test/SemaTemplate/temp_arg_enum_printing.cpp
new file mode 100644
index 000000000000..a788975b20dd
--- /dev/null
+++ b/test/SemaTemplate/temp_arg_enum_printing.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -ast-print %s | FileCheck %s
+
+namespace NamedEnumNS
+{
+
+enum NamedEnum
+{
+ Val0,
+ Val1
+};
+
+template <NamedEnum E>
+void foo();
+
+void test() {
+ // CHECK: template <NamedEnumNS::NamedEnum E = NamedEnumNS::NamedEnum::Val0>
+ NamedEnumNS::foo<Val0>();
+ // CHECK: template <NamedEnumNS::NamedEnum E = NamedEnumNS::NamedEnum::Val1>
+ NamedEnumNS::foo<(NamedEnum)1>();
+ // CHECK: template <NamedEnumNS::NamedEnum E = 2>
+ NamedEnumNS::foo<(NamedEnum)2>();
+}
+
+} // NamedEnumNS
diff --git a/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
new file mode 100644
index 000000000000..5000927d8941
--- /dev/null
+++ b/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
@@ -0,0 +1,150 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
+
+template<typename T, T val> struct A {};
+
+template<typename T, typename U> constexpr bool is_same = false; // expected-note +{{here}}
+template<typename T> constexpr bool is_same<T, T> = true;
+
+namespace String {
+ A<const char*, "test"> a; // expected-error {{does not refer to any declaration}}
+ A<const char (&)[5], "test"> b; // expected-error {{does not refer to any declaration}}
+}
+
+namespace Array {
+ char arr[3];
+ char x;
+ A<const char*, arr> a;
+ A<const char(&)[3], arr> b;
+ A<const char*, &arr[0]> c;
+ A<const char*, &arr[1]> d; // expected-error {{refers to subobject '&arr[1]'}}
+ A<const char*, (&arr)[0]> e;
+ A<const char*, &x> f;
+ A<const char*, &(&x)[0]> g;
+ A<const char*, &(&x)[1]> h; // expected-error {{refers to subobject '&x + 1'}}
+ A<const char*, 0> i; // expected-error {{not allowed in a converted constant}}
+ A<const char*, nullptr> j;
+}
+
+namespace Function {
+ void f();
+ void g() noexcept;
+ void h();
+ void h(int);
+ template<typename...T> void i(T...);
+ typedef A<void (*)(), f> a;
+ typedef A<void (*)(), &f> a;
+ typedef A<void (*)(), g> b;
+ typedef A<void (*)(), &g> b;
+ typedef A<void (*)(), h> c;
+ typedef A<void (*)(), &h> c;
+ typedef A<void (*)(), i> d;
+ typedef A<void (*)(), &i> d;
+ typedef A<void (*)(), i<>> d;
+ typedef A<void (*)(), i<int>> e; // expected-error {{is not implicitly convertible}}
+
+ typedef A<void (*)(), 0> x; // expected-error {{not allowed in a converted constant}}
+ typedef A<void (*)(), nullptr> y;
+}
+
+void Func() {
+ A<const char*, __func__> a; // expected-error {{does not refer to any declaration}}
+}
+
+namespace LabelAddrDiff {
+ void f() {
+ a: b: A<int, __builtin_constant_p(true) ? (__INTPTR_TYPE__)&&b - (__INTPTR_TYPE__)&&a : 0> s; // expected-error {{label address difference}}
+ };
+}
+
+namespace Temp {
+ struct S { int n; };
+ constexpr S &addr(S &&s) { return s; }
+ A<S &, addr({})> a; // expected-error {{constant}} expected-note 2{{temporary}}
+ A<S *, &addr({})> b; // expected-error {{constant}} expected-note 2{{temporary}}
+ A<int &, addr({}).n> c; // expected-error {{constant}} expected-note 2{{temporary}}
+ A<int *, &addr({}).n> d; // expected-error {{constant}} expected-note 2{{temporary}}
+}
+
+namespace std { struct type_info; }
+
+namespace RTTI {
+ A<const std::type_info&, typeid(int)> a; // expected-error {{does not refer to any declaration}}
+ A<const std::type_info*, &typeid(int)> b; // expected-error {{does not refer to any declaration}}
+}
+
+namespace PtrMem {
+ struct B { int b; };
+ struct C : B {};
+ struct D : B {};
+ struct E : C, D { int e; };
+
+ constexpr int B::*b = &B::b;
+ constexpr int C::*cb = b;
+ constexpr int D::*db = b;
+ constexpr int E::*ecb = cb; // expected-note +{{here}}
+ constexpr int E::*edb = db; // expected-note +{{here}}
+
+ constexpr int E::*e = &E::e;
+ constexpr int D::*de = (int D::*)e;
+ constexpr int C::*ce = (int C::*)e;
+ constexpr int B::*bde = (int B::*)de; // expected-note +{{here}}
+ constexpr int B::*bce = (int B::*)ce; // expected-note +{{here}}
+
+ // FIXME: This should all be accepted, but we don't yet have a representation
+ // nor mangling for this form of template argument.
+ using Ab = A<int B::*, b>;
+ using Ab = A<int B::*, &B::b>;
+ using Abce = A<int B::*, bce>; // expected-error {{not supported}}
+ using Abde = A<int B::*, bde>; // expected-error {{not supported}}
+ static_assert(!is_same<Ab, Abce>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
+ static_assert(!is_same<Ab, Abde>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
+ static_assert(!is_same<Abce, Abde>, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}}
+ static_assert(is_same<Abce, A<int B::*, (int B::*)(int C::*)&E::e>, ""); // expected-error {{undeclared}} expected-error {{not supported}}
+
+ using Ae = A<int E::*, e>;
+ using Ae = A<int E::*, &E::e>;
+ using Aecb = A<int E::*, ecb>; // expected-error {{not supported}}
+ using Aedb = A<int E::*, edb>; // expected-error {{not supported}}
+ static_assert(!is_same<Ae, Aecb>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
+ static_assert(!is_same<Ae, Aedb>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
+ static_assert(!is_same<Aecb, Aedb>, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}}
+ static_assert(is_same<Aecb, A<int E::*, (int E::*)(int C::*)&B::b>, ""); // expected-error {{undeclared}} expected-error {{not supported}}
+
+ using An = A<int E::*, nullptr>;
+ using A0 = A<int E::*, (int E::*)0>;
+ static_assert(is_same<An, A0>);
+}
+
+namespace DeduceDifferentType {
+ template<int N> struct A {};
+ template<long N> int a(A<N>); // expected-note {{does not have the same type}}
+ int a_imp = a(A<3>()); // expected-error {{no matching function}}
+ int a_exp = a<3>(A<3>());
+
+ template<decltype(nullptr)> struct B {};
+ template<int *P> int b(B<P>); // expected-note {{could not match}} expected-note {{not implicitly convertible}}
+ int b_imp = b(B<nullptr>()); // expected-error {{no matching function}}
+ int b_exp = b<nullptr>(B<nullptr>()); // expected-error {{no matching function}}
+
+ struct X { constexpr operator int() { return 0; } } x;
+ template<X &> struct C {};
+ template<int N> int c(C<N>); // expected-note {{does not have the same type}} expected-note {{not implicitly convertible}}
+ int c_imp = c(C<x>()); // expected-error {{no matching function}}
+ int c_exp = c<x>(C<x>()); // expected-error {{no matching function}}
+
+ struct Z;
+ struct Y { constexpr operator Z&(); } y;
+ struct Z { constexpr operator Y&() { return y; } } z;
+ constexpr Y::operator Z&() { return z; }
+ template<Y &> struct D {};
+ template<Z &z> int d(D<z>); // expected-note {{does not have the same type}}
+ int d_imp = d(D<y>()); // expected-error {{no matching function}}
+ int d_exp = d<y>(D<y>());
+}
+
+namespace DeclMatch {
+ template<typename T, T> int f();
+ template<typename T> class X { friend int f<T, 0>(); static int n; };
+ template<typename T, T> int f() { return X<T>::n; }
+ int k = f<int, 0>(); // ok, friend
+}
diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp
index a23bf4e3ee5e..c2fc2634edd6 100644
--- a/test/SemaTemplate/virtual-member-functions.cpp
+++ b/test/SemaTemplate/virtual-member-functions.cpp
@@ -3,19 +3,17 @@
namespace PR5557 {
template <class T> struct A {
- A();
- virtual void anchor();
+ A(); // expected-note{{instantiation}}
virtual int a(T x);
};
template<class T> A<T>::A() {}
-template<class T> void A<T>::anchor() { }
template<class T> int A<T>::a(T x) {
return *x; // expected-error{{requires pointer operand}}
}
-void f(A<int> x) {
- x.anchor(); // expected-note{{instantiation}}
+void f() {
+ A<int> x; // expected-note{{instantiation}}
}
template<typename T>
@@ -27,6 +25,24 @@ template<>
void X<int>::f() { }
}
+// Like PR5557, but with a defined destructor instead of a defined constructor.
+namespace PR5557_dtor {
+template <class T> struct A {
+ A(); // Don't have an implicit constructor.
+ ~A(); // expected-note{{instantiation}}
+ virtual int a(T x);
+};
+template<class T> A<T>::~A() {}
+
+template<class T> int A<T>::a(T x) {
+ return *x; // expected-error{{requires pointer operand}}
+}
+
+void f() {
+ A<int> x; // expected-note{{instantiation}}
+}
+}
+
template<typename T>
struct Base {
virtual ~Base() {
diff --git a/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp b/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
index d7ec3f60ac7c..6a97f310ff32 100644
--- a/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
+++ b/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
@@ -11,6 +11,3 @@
invalid;
// REQUIRES: shell
-// PR15590
-// XFAIL: win64
-// XFAIL: mingw
diff --git a/test/Tooling/auto-detect-from-source-parent.cpp b/test/Tooling/auto-detect-from-source-parent.cpp
index 5f27d5ab8051..830d09d6a0e0 100644
--- a/test/Tooling/auto-detect-from-source-parent.cpp
+++ b/test/Tooling/auto-detect-from-source-parent.cpp
@@ -1,12 +1,8 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t/abc/def/ijk/qwe
-// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/abc/def/ijk/qwe/test.cpp\",\"file\":\"%t/abc/def/ijk/qwe/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
+// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %/t/abc/def/ijk/qwe/test.cpp\",\"file\":\"%/t/abc/def/ijk/qwe/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
// RUN: cp "%s" "%t/abc/def/ijk/qwe/test.cpp"
// RUN: not clang-check "%t/abc/def/ijk/qwe/test.cpp" 2>&1 | FileCheck %s
// CHECK: C++ requires
invalid;
-
-// REQUIRES: shell
-// PR15590
-// XFAIL: win64
diff --git a/test/Tooling/auto-detect-from-source.cpp b/test/Tooling/auto-detect-from-source.cpp
index 6ff39acdc8c2..12a660d585a9 100644
--- a/test/Tooling/auto-detect-from-source.cpp
+++ b/test/Tooling/auto-detect-from-source.cpp
@@ -1,12 +1,8 @@
// RUN: rm -rf %t
// RUN: mkdir %t
-// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/test.cpp\",\"file\":\"%t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
+// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
// RUN: cp "%s" "%t/test.cpp"
// RUN: not clang-check "%t/test.cpp" 2>&1 | FileCheck %s
// CHECK: C++ requires
invalid;
-
-// REQUIRES: shell
-// PR15590
-// XFAIL: win64
diff --git a/test/Tooling/clang-check-autodetect-dir.cpp b/test/Tooling/clang-check-autodetect-dir.cpp
index 8ef3f3d01734..b84f3fede888 100644
--- a/test/Tooling/clang-check-autodetect-dir.cpp
+++ b/test/Tooling/clang-check-autodetect-dir.cpp
@@ -1,13 +1,9 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t/abc/def
-// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/test.cpp\",\"file\":\"%t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
+// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
// RUN: cp "%s" "%t/test.cpp"
// RUN: not clang-check -p "%t/abc/def" "%t/test.cpp" 2>&1|FileCheck %s
// FIXME: Make the above easier.
// CHECK: C++ requires
invalid;
-
-// REQUIRES: shell
-// PR15590
-// XFAIL: win64
diff --git a/test/Tooling/clang-check-pwd.cpp b/test/Tooling/clang-check-pwd.cpp
index d85b9b1ae472..3ce196be3eec 100644
--- a/test/Tooling/clang-check-pwd.cpp
+++ b/test/Tooling/clang-check-pwd.cpp
@@ -12,6 +12,3 @@
invalid;
// REQUIRES: shell
-// PR15590
-// XFAIL: win64
-// XFAIL: mingw
diff --git a/test/Tooling/pch.cpp b/test/Tooling/pch.cpp
index 40bc1e9731c1..5da49eaea9c1 100644
--- a/test/Tooling/pch.cpp
+++ b/test/Tooling/pch.cpp
@@ -9,7 +9,6 @@
// the test file with an unrelated include as second translation unit.
// Test for an non-empty file after clang-check is executed.
// RUN: clang-check -ast-dump "%S/Inputs/pch.cpp" "%s" -- -include-pch %t1 -I "%S" -c >%t2 2>&1
-// REQUIRES: shell
// RUN: test -s %t2
#include "Inputs/pch-fail.h"
diff --git a/test/VFS/external-names.c b/test/VFS/external-names.c
index aa0bd6745309..81ec4ec50b3e 100644
--- a/test/VFS/external-names.c
+++ b/test/VFS/external-names.c
@@ -28,8 +28,8 @@
// Debug info
// RUN: %clang_cc1 -I %t -ivfsoverlay %t.external.yaml -triple %itanium_abi_triple -g -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-DEBUG-EXTERNAL %s
-// CHECK-DEBUG-EXTERNAL: ![[Num:[0-9]*]] = metadata !{metadata !"{{.*}}Inputs{{.}}external-names.h
-// CHECK-DEBUG-EXTERNAL: metadata !{i32 {{[0-9]*}}, metadata ![[Num]]{{.*}}DW_TAG_file_type
+// CHECK-DEBUG-EXTERNAL: ![[Num:[0-9]*]] = !{!"{{.*}}Inputs{{.}}external-names.h
+// CHECK-DEBUG-EXTERNAL: !{!"0x29", ![[Num]]{{.*}}DW_TAG_file_type
// RUN: %clang_cc1 -I %t -ivfsoverlay %t.yaml -triple %itanium_abi_triple -g -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-DEBUG %s
// CHECK-DEBUG-NOT: Inputs
diff --git a/test/VFS/umbrella-mismatch.m b/test/VFS/umbrella-mismatch.m
index c73129448c55..f3a4ab34e065 100644
--- a/test/VFS/umbrella-mismatch.m
+++ b/test/VFS/umbrella-mismatch.m
@@ -1,6 +1,5 @@
// RUN: rm -rf %t
-// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%S/Inputs:g" %S/Inputs/vfsoverlay.yaml > %t.yaml
-// REQUIRES: shell
+// RUN: sed -e "s;INPUT_DIR;%/S/Inputs;g" -e "s;OUT_DIR;%/S/Inputs;g" %S/Inputs/vfsoverlay.yaml > %t.yaml
// RUN: %clang_cc1 -Werror -fmodules -fmodules-cache-path=%t -ivfsoverlay %t.yaml -F %S/Inputs -fsyntax-only %s -verify
// RUN: %clang_cc1 -Werror -fmodules -fmodules-cache-path=%t -F %S/Inputs -fsyntax-only %s -verify
diff --git a/test/lit.cfg b/test/lit.cfg
index ccefb70f7300..846a6e92ca51 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -73,7 +73,6 @@ config.llvm_obj_root = getattr(config, 'llvm_obj_root', None)
# safe_env_vars = ('TMPDIR', 'TEMP', 'TMP', 'USERPROFILE', 'PWD',
# 'MACOSX_DEPLOYMENT_TARGET', 'IPHONEOS_DEPLOYMENT_TARGET',
-# 'IOS_SIMULATOR_DEPLOYMENT_TARGET',
# 'VCINSTALLDIR', 'VC100COMNTOOLS', 'VC90COMNTOOLS',
# 'VC80COMNTOOLS')
possibly_dangerous_env_vars = ['COMPILER_PATH', 'RC_DEBUG_OPTIONS',
@@ -115,11 +114,6 @@ for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']:
if symbolizer in os.environ:
config.environment[symbolizer] = os.environ[symbolizer]
-# Propagate options for sanitizers.
-for options in ['ASAN_OPTIONS']:
- if options in os.environ:
- config.environment[options] = os.environ[options]
-
###
# Check that the object root is known.
@@ -223,7 +217,8 @@ def getClangBuiltinIncludeDir(clang):
# FIXME: Rather than just getting the version, we should have clang print
# out its resource dir here in an easy to scrape form.
cmd = subprocess.Popen([clang, '-print-file-name=include'],
- stdout=subprocess.PIPE)
+ stdout=subprocess.PIPE,
+ env=config.environment)
if not cmd.stdout:
lit_config.fatal("Couldn't find the include dir for Clang ('%s')" % clang)
dir = cmd.stdout.read().strip()
@@ -258,7 +253,8 @@ def makeMSABITriple(triple):
# -win32 is not supported for non-x86 targets; use a default.
return 'i686-pc-win32'
-config.substitutions.append( ('%clang_cc1', '%s -cc1 -internal-isystem %s'
+config.substitutions.append( ('%clang_cc1',
+ '%s -cc1 -internal-isystem %s -nostdsysteminc'
% (config.clang,
getClangBuiltinIncludeDir(config.clang))) )
config.substitutions.append( ('%clang_cpp', ' ' + config.clang +
@@ -310,14 +306,14 @@ tool_dirs = os.path.pathsep.join((clang_tools_dir, llvm_tools_dir))
# For example, don't match 'clang-check-' or '.clang-format'.
NoPreHyphenDot = r"(?<!(-|\.))"
NoPostHyphenDot = r"(?!(-|\.))"
+NoPostBar = r"(?!(/|\\))"
for pattern in [r"\bFileCheck\b",
r"\bc-index-test\b",
NoPreHyphenDot + r"\bclang-check\b" + NoPostHyphenDot,
NoPreHyphenDot + r"\bclang-format\b" + NoPostHyphenDot,
NoPreHyphenDot + r"\bclang-interpreter\b" + NoPostHyphenDot,
- # FIXME: Some clang test uses opt?
- NoPreHyphenDot + r"\bopt\b" + NoPostHyphenDot,
+ NoPreHyphenDot + r"\bopt\b" + NoPostBar + NoPostHyphenDot,
# Handle these specially as they are strings searched
# for during testing.
r"\| \bcount\b",
@@ -408,11 +404,11 @@ if not re.match(r'.*-win32$', config.target_triple):
config.available_features.add('non-ms-sdk')
# [PR8833] LLP64-incompatible tests
-if not re.match(r'^x86_64.*-(win32|mingw32)$', config.target_triple):
+if not re.match(r'^x86_64.*-(win32|mingw32|windows-gnu)$', config.target_triple):
config.available_features.add('LP64')
# [PR12920] "clang-driver" -- set if gcc driver is not used.
-if not re.match(r'.*-(cygwin|mingw32)$', config.target_triple):
+if not re.match(r'.*-(cygwin|mingw32|windows-gnu)$', config.target_triple):
config.available_features.add('clang-driver')
# [PR18856] Depends to remove opened file. On win32, a file could be removed
@@ -430,7 +426,8 @@ def get_llvm_config_props():
'--assertion-mode',
'--targets-built',
],
- stdout=subprocess.PIPE
+ stdout=subprocess.PIPE,
+ env=config.environment
)
# 1st line corresponds to --assertion-mode, "ON" or "OFF".
line = cmd.stdout.readline().strip().decode('ascii')
@@ -457,6 +454,10 @@ else:
if (config.llvm_use_sanitizer == "Memory" or
config.llvm_use_sanitizer == "MemoryWithOrigins"):
config.available_features.add("msan")
+if config.llvm_use_sanitizer == "Undefined":
+ config.available_features.add("ubsan")
+else:
+ config.available_features.add("not_ubsan")
# Check if we should run long running tests.
if lit_config.params.get("run_long_tests", None) == "true":
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index a59a869c225c..7be4ed6e2a21 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -269,14 +269,11 @@ static bool verifyTransformedFiles(ArrayRef<std::string> resultFiles) {
return true;
}
- bool exists = false;
- sys::fs::exists(It->second, exists);
- if (!exists) {
+ if (!sys::fs::exists(It->second)) {
errs() << "error: '" << It->second << "' does not exist\n";
return true;
}
- sys::fs::exists(inputResultFname, exists);
- if (!exists) {
+ if (!sys::fs::exists(inputResultFname)) {
errs() << "error: '" << inputResultFname << "' does not exist\n";
return true;
}
diff --git a/tools/c-arcmt-test/CMakeLists.txt b/tools/c-arcmt-test/CMakeLists.txt
index 9014ccc309f2..8914607358fc 100644
--- a/tools/c-arcmt-test/CMakeLists.txt
+++ b/tools/c-arcmt-test/CMakeLists.txt
@@ -2,9 +2,15 @@ add_clang_executable(c-arcmt-test
c-arcmt-test.c
)
-target_link_libraries(c-arcmt-test
- libclang
- )
+if (LLVM_BUILD_STATIC)
+ target_link_libraries(c-arcmt-test
+ libclang_static
+ )
+else()
+ target_link_libraries(c-arcmt-test
+ libclang
+ )
+endif()
set_target_properties(c-arcmt-test
PROPERTIES
diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile
index e7d5be7658b8..fff05f828254 100644
--- a/tools/c-arcmt-test/Makefile
+++ b/tools/c-arcmt-test/Makefile
@@ -30,6 +30,7 @@ USEDLIBS = clang.a \
clangIndex.a \
clangFormat.a \
clangTooling.a \
+ clangToolingCore.a \
clangRewriteFrontend.a \
clangRewrite.a \
clangFrontend.a clangDriver.a \
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index 113172ad157c..d0872fd2eff3 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -9,9 +9,15 @@ if(NOT MSVC)
)
endif()
-target_link_libraries(c-index-test
- libclang
+if (LLVM_BUILD_STATIC)
+ target_link_libraries(c-index-test
+ libclang_static
)
+else()
+ target_link_libraries(c-index-test
+ libclang
+ )
+endif()
set_target_properties(c-index-test
PROPERTIES
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 42bfbb05839c..62bc9348dbf5 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -30,6 +30,7 @@ USEDLIBS = clang.a \
clangIndex.a clangFormat.a clangRewrite.a \
clangFrontend.a clangDriver.a \
clangTooling.a \
+ clangToolingCore.a \
clangSerialization.a clangParse.a clangSema.a \
clangAnalysis.a clangEdit.a clangAST.a clangLex.a \
clangBasic.a
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 07be22a5e940..56e4101399a5 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -796,15 +796,42 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
printf(" [access=%s isVirtual=%s]", accessStr,
isVirtual ? "true" : "false");
}
-
+
SpecializationOf = clang_getSpecializedCursorTemplate(Cursor);
if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) {
CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf);
CXString Name = clang_getCursorSpelling(SpecializationOf);
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
- printf(" [Specialization of %s:%d:%d]",
+ printf(" [Specialization of %s:%d:%d]",
clang_getCString(Name), line, column);
clang_disposeString(Name);
+
+ if (Cursor.kind == CXCursor_FunctionDecl) {
+ /* Collect the template parameter kinds from the base template. */
+ unsigned NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
+ unsigned I;
+ for (I = 0; I < NumTemplateArgs; I++) {
+ enum CXTemplateArgumentKind TAK =
+ clang_Cursor_getTemplateArgumentKind(Cursor, I);
+ switch(TAK) {
+ case CXTemplateArgumentKind_Type:
+ {
+ CXType T = clang_Cursor_getTemplateArgumentType(Cursor, I);
+ CXString S = clang_getTypeSpelling(T);
+ printf(" [Template arg %d: kind: %d, type: %s]",
+ I, TAK, clang_getCString(S));
+ clang_disposeString(S);
+ }
+ break;
+ case CXTemplateArgumentKind_Integral:
+ printf(" [Template arg %d: kind: %d, intval: %lld]",
+ I, TAK, clang_Cursor_getTemplateArgumentValue(Cursor, I));
+ break;
+ default:
+ printf(" [Template arg %d: kind: %d]\n", I, TAK);
+ }
+ }
+ }
}
clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
@@ -1363,6 +1390,20 @@ static enum CXChildVisitResult PrintTypeSize(CXCursor cursor, CXCursor p,
}
/******************************************************************************/
+/* Mangling testing. */
+/******************************************************************************/
+
+static enum CXChildVisitResult PrintMangledName(CXCursor cursor, CXCursor p,
+ CXClientData d) {
+ CXString MangledName;
+ PrintCursor(cursor, NULL);
+ MangledName = clang_Cursor_getMangling(cursor);
+ printf(" [mangled=%s]\n", clang_getCString(MangledName));
+ clang_disposeString(MangledName);
+ return CXChildVisit_Continue;
+}
+
+/******************************************************************************/
/* Bitwidth testing. */
/******************************************************************************/
@@ -1629,6 +1670,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
if ((fp = fopen(source_file, "r")) == NULL) {
fprintf(stderr, "Could not open '%s'\n", source_file);
+ clang_disposeTranslationUnit(TU);
return 1;
}
@@ -4081,6 +4123,8 @@ int cindextest_main(int argc, const char **argv) {
else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all",
PrintBitWidth, 0);
+ else if (argc > 2 && strcmp(argv[1], "-test-print-mangle") == 0)
+ return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL);
else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
if (argc > 2)
return print_usrs(argv + 2, argv + argc);
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index cc8d43cec221..7992026a7ccf 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -25,6 +25,7 @@
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
@@ -77,15 +78,6 @@ static cl::opt<bool> FixWhatYouCan(
cl::desc(Options->getOptionHelpText(options::OPT_fix_what_you_can)),
cl::cat(ClangCheckCategory));
-static cl::list<std::string> ArgsAfter(
- "extra-arg",
- cl::desc("Additional argument to append to the compiler command line"),
- cl::cat(ClangCheckCategory));
-static cl::list<std::string> ArgsBefore(
- "extra-arg-before",
- cl::desc("Additional argument to prepend to the compiler command line"),
- cl::cat(ClangCheckCategory));
-
namespace {
// FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp
@@ -139,57 +131,21 @@ public:
}
};
-class InsertAdjuster: public clang::tooling::ArgumentsAdjuster {
-public:
- enum Position { BEGIN, END };
-
- InsertAdjuster(const CommandLineArguments &Extra, Position Pos)
- : Extra(Extra), Pos(Pos) {
- }
-
- InsertAdjuster(const char *Extra, Position Pos)
- : Extra(1, std::string(Extra)), Pos(Pos) {
- }
-
- virtual CommandLineArguments
- Adjust(const CommandLineArguments &Args) override {
- CommandLineArguments Return(Args);
-
- CommandLineArguments::iterator I;
- if (Pos == END) {
- I = Return.end();
- } else {
- I = Return.begin();
- ++I; // To leave the program name in place
- }
-
- Return.insert(I, Extra.begin(), Extra.end());
- return Return;
- }
-
-private:
- const CommandLineArguments Extra;
- const Position Pos;
-};
-
-} // namespace
-
-// Anonymous namespace here causes problems with gcc <= 4.4 on MacOS 10.6.
-// "Non-global symbol: ... can't be a weak_definition"
-namespace clang_check {
class ClangCheckActionFactory {
public:
- clang::ASTConsumer *newASTConsumer() {
+ std::unique_ptr<clang::ASTConsumer> newASTConsumer() {
if (ASTList)
return clang::CreateASTDeclNodeLister();
if (ASTDump)
- return clang::CreateASTDumper(ASTDumpFilter);
+ return clang::CreateASTDumper(ASTDumpFilter, /*DumpDecls=*/true,
+ /*DumpLookups=*/false);
if (ASTPrint)
return clang::CreateASTPrinter(&llvm::outs(), ASTDumpFilter);
- return new clang::ASTConsumer();
+ return llvm::make_unique<clang::ASTConsumer>();
}
};
-}
+
+} // namespace
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
@@ -199,22 +155,14 @@ int main(int argc, const char **argv) {
// Clear adjusters because -fsyntax-only is inserted by the default chain.
Tool.clearArgumentsAdjusters();
- Tool.appendArgumentsAdjuster(new ClangStripOutputAdjuster());
- if (ArgsAfter.size() > 0) {
- Tool.appendArgumentsAdjuster(new InsertAdjuster(ArgsAfter,
- InsertAdjuster::END));
- }
- if (ArgsBefore.size() > 0) {
- Tool.appendArgumentsAdjuster(new InsertAdjuster(ArgsBefore,
- InsertAdjuster::BEGIN));
- }
+ Tool.appendArgumentsAdjuster(getClangStripOutputAdjuster());
// Running the analyzer requires --analyze. Other modes can work with the
// -fsyntax-only option.
- Tool.appendArgumentsAdjuster(new InsertAdjuster(
- Analyze ? "--analyze" : "-fsyntax-only", InsertAdjuster::BEGIN));
+ Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster(
+ Analyze ? "--analyze" : "-fsyntax-only", ArgumentInsertPosition::BEGIN));
- clang_check::ClangCheckActionFactory CheckFactory;
+ ClangCheckActionFactory CheckFactory;
std::unique_ptr<FrontendActionFactory> FrontendFactory;
// Choose the correct factory based on the selected mode.
diff --git a/tools/clang-format-vs/CMakeLists.txt b/tools/clang-format-vs/CMakeLists.txt
index b1101928aa51..0a50a6a8c426 100644
--- a/tools/clang-format-vs/CMakeLists.txt
+++ b/tools/clang-format-vs/CMakeLists.txt
@@ -6,6 +6,11 @@ if (BUILD_CLANG_FORMAT_VS_PLUGIN)
"${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/clang-format.exe"
DEPENDS clang-format)
+ add_custom_target(clang_format_license
+ ${CMAKE_COMMAND} -E copy_if_different
+ "${CLANG_SOURCE_DIR}/LICENSE.TXT"
+ "${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/license.txt")
+
if (NOT CLANG_FORMAT_VS_VERSION)
set(CLANG_FORMAT_VS_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
endif()
@@ -19,5 +24,5 @@ if (BUILD_CLANG_FORMAT_VS_PLUGIN)
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/bin/Release/ClangFormat.vsix"
"${LLVM_TOOLS_BINARY_DIR}/${CMAKE_CFG_INTDIR}/ClangFormat.vsix"
- DEPENDS clang_format_exe_for_vsix)
+ DEPENDS clang_format_exe_for_vsix clang_format_license)
endif()
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormat.csproj b/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
index 2f49221d14b3..709b33d6fa22 100644
--- a/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
+++ b/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
@@ -181,6 +181,9 @@
<Content Include="clang-format.exe">
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
+ <Content Include="license.txt">
+ <IncludeInVSIX>true</IncludeInVSIX>
+ </Content>
<Content Include="Resources\Package.ico" />
</ItemGroup>
<ItemGroup>
@@ -227,4 +230,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/tools/clang-format-vs/README.txt b/tools/clang-format-vs/README.txt
index b87df6e92379..636b89f3c673 100644
--- a/tools/clang-format-vs/README.txt
+++ b/tools/clang-format-vs/README.txt
@@ -6,8 +6,11 @@ Build prerequisites are:
- Visual Studio 2010 Professional
- Visual Studio 2010 SDK.
-clang-format.exe must be copied into the ClangFormat/ directory before building.
-It will be bundled into the .vsix file.
+The extension is built using CMake by setting BUILD_CLANG_FORMAT_VS_PLUGIN=ON
+when configuring a Clang build, and building the clang_format_vsix target.
-The extension can be built manually from ClangFormat.sln (e.g. by opening it in
-Visual Studio), or with cmake by setting the BUILD_CLANG_FORMAT_VS_PLUGIN flag.
+The CMake build will copy clang-format.exe and LICENSE.TXT into the ClangFormat/
+directory so they can be bundled with the plug-in, as well as creating
+ClangFormat/source.extension.vsixmanifest. Once the plug-in has been built with
+CMake once, it can be built manually from the ClangFormat.sln solution in Visual
+Studio.
diff --git a/tools/clang-format-vs/source.extension.vsixmanifest.in b/tools/clang-format-vs/source.extension.vsixmanifest.in
index ed0e72e35512..496fa40063b7 100644
--- a/tools/clang-format-vs/source.extension.vsixmanifest.in
+++ b/tools/clang-format-vs/source.extension.vsixmanifest.in
@@ -6,6 +6,8 @@
<Version>@CLANG_FORMAT_VS_VERSION@</Version>
<Description xml:space="preserve">A tool to format C/C++/Obj-C code.</Description>
<Locale>1033</Locale>
+ <MoreInfoUrl>http://clang.llvm.org/docs/ClangFormat.html</MoreInfoUrl>
+ <License>license.txt</License>
<InstalledByMsi>false</InstalledByMsi>
<SupportedProducts>
<VisualStudio Version="10.0">
@@ -17,6 +19,9 @@
<VisualStudio Version="12.0">
<Edition>Pro</Edition>
</VisualStudio>
+ <VisualStudio Version="14.0">
+ <Edition>Pro</Edition>
+ </VisualStudio>
</SupportedProducts>
<SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="4.0" />
</Identifier>
diff --git a/tools/clang-format/CMakeLists.txt b/tools/clang-format/CMakeLists.txt
index f80a3ec9c91f..6a24e138efcf 100644
--- a/tools/clang-format/CMakeLists.txt
+++ b/tools/clang-format/CMakeLists.txt
@@ -7,9 +7,8 @@ add_clang_executable(clang-format
target_link_libraries(clang-format
clangBasic
clangFormat
- clangLex
clangRewrite
- clangTooling
+ clangToolingCore
)
install(TARGETS clang-format RUNTIME DESTINATION bin)
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp
index cebb2757d4da..d44d407aa86c 100644
--- a/tools/clang-format/ClangFormat.cpp
+++ b/tools/clang-format/ClangFormat.cpp
@@ -19,9 +19,9 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/Format/Format.h"
-#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"
@@ -76,7 +76,7 @@ static cl::opt<std::string>
AssumeFilename("assume-filename",
cl::desc("When reading from stdin, clang-format assumes this\n"
"filename to look for a style config file (with\n"
- "-style=file)."),
+ "-style=file) and to determine the language."),
cl::cat(ClangFormatCategory));
static cl::opt<bool> Inplace("i",
@@ -225,12 +225,14 @@ static bool format(StringRef FileName) {
FormatStyle FormatStyle = getStyle(
Style, (FileName == "-") ? AssumeFilename : FileName, FallbackStyle);
- Lexer Lex(ID, Sources.getBuffer(ID), Sources,
- getFormattingLangOpts(FormatStyle.Standard));
- tooling::Replacements Replaces = reformat(FormatStyle, Lex, Sources, Ranges);
+ tooling::Replacements Replaces = reformat(FormatStyle, Sources, ID, Ranges);
if (OutputXML) {
llvm::outs()
<< "<?xml version='1.0'?>\n<replacements xml:space='preserve'>\n";
+ if (Cursor.getNumOccurrences() != 0)
+ llvm::outs() << "<cursor>"
+ << tooling::shiftedCodePosition(Replaces, Cursor)
+ << "</cursor>\n";
for (tooling::Replacements::const_iterator I = Replaces.begin(),
E = Replaces.end();
I != E; ++I) {
diff --git a/tools/clang-format/Makefile b/tools/clang-format/Makefile
index a26ef59822be..76e31cc1a072 100644
--- a/tools/clang-format/Makefile
+++ b/tools/clang-format/Makefile
@@ -16,9 +16,7 @@ TOOL_NO_EXPORTS = 1
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
-USEDLIBS = clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
- clangDriver.a clangParse.a clangSema.a clangAnalysis.a \
- clangRewriteFrontend.a clangRewrite.a clangEdit.a clangAST.a \
+USEDLIBS = clangFormat.a clangToolingCore.a clangDriver.a clangRewrite.a \
clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/clang-format/clang-format-diff.py b/tools/clang-format/clang-format-diff.py
index d6d0d44a06bb..23adb077c953 100755
--- a/tools/clang-format/clang-format-diff.py
+++ b/tools/clang-format/clang-format-diff.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
#
#===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===#
#
@@ -49,9 +49,11 @@ def main():
'(case sensitive, overrides -iregex)')
parser.add_argument('-iregex', metavar='PATTERN', default=
r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc|js|proto'
- r'|protodevel)',
+ r'|protodevel|java)',
help='custom pattern selecting file paths to reformat '
'(case insensitive, overridden by -regex)')
+ parser.add_argument('-v', '--verbose', action='store_true',
+ help='be more verbose, ineffective without -i')
parser.add_argument(
'-style',
help=
@@ -89,6 +91,8 @@ def main():
# Reformat files containing changes in place.
for filename, lines in lines_by_file.iteritems():
+ if args.i and args.verbose:
+ print 'Formatting', filename
command = [binary, filename]
if args.i:
command.append('-i')
diff --git a/tools/clang-format/clang-format.el b/tools/clang-format/clang-format.el
index 520a3e250cf5..ab0991b2df1c 100644
--- a/tools/clang-format/clang-format.el
+++ b/tools/clang-format/clang-format.el
@@ -1,56 +1,167 @@
-;;; Clang-format emacs integration for use with C/Objective-C/C++.
+;;; clang-format.el --- Format code using clang-format
-;; This defines a function clang-format-region that you can bind to a key.
-;; A minimal .emacs would contain:
+;; Keywords: tools, c
+;; Package-Requires: ((cl-lib "0.3"))
+
+;;; Commentary:
+
+;; This package allows to filter code through clang-format to fix its formatting.
+;; clang-format is a tool that formats C/C++/Obj-C code according to a set of
+;; style options, see <http://clang.llvm.org/docs/ClangFormatStyleOptions.html>.
+;; Note that clang-format 3.4 or newer is required.
+
+;; clang-format.el is available via MELPA and can be installed via
;;
-;; (load "<path-to-clang>/tools/clang-format/clang-format.el")
-;; (global-set-key [C-M-tab] 'clang-format-region)
+;; M-x package-install clang-format
+;;
+;; when ("melpa" . "http://melpa.org/packages/") is included in
+;; `package-archives'. Alternatively, ensure the directory of this
+;; file is in your `load-path' and add
+;;
+;; (require 'clang-format)
+;;
+;; to your .emacs configuration.
+
+;; You may also want to bind `clang-format-region' to a key:
;;
-;; Depending on your configuration and coding style, you might need to modify
-;; 'style' in clang-format, below.
+;; (global-set-key [C-M-tab] 'clang-format-region)
-(require 'json)
+;;; Code:
-;; *Location of the clang-format binary. If it is on your PATH, a full path name
-;; need not be specified.
-(defvar clang-format-binary "clang-format")
+(require 'cl-lib)
+(require 'xml)
-(defun clang-format-region ()
- "Use clang-format to format the currently active region."
- (interactive)
- (let ((beg (if mark-active
- (region-beginning)
- (min (line-beginning-position) (1- (point-max)))))
- (end (if mark-active
- (region-end)
- (line-end-position))))
- (clang-format beg end)))
-
-(defun clang-format-buffer ()
- "Use clang-format to format the current buffer."
- (interactive)
- (clang-format (point-min) (point-max)))
-
-(defun clang-format (begin end)
- "Use clang-format to format the code between BEGIN and END."
- (let* ((orig-windows (get-buffer-window-list (current-buffer)))
- (orig-window-starts (mapcar #'window-start orig-windows))
- (orig-point (point))
- (style "file"))
+(defgroup clang-format nil
+ "Format code using clang-format."
+ :group 'tools)
+
+(defcustom clang-format-executable
+ (or (executable-find "clang-format")
+ "clang-format")
+ "Location of the clang-format executable.
+
+A string containing the name or the full path of the executable."
+ :group 'clang-format
+ :type 'string
+ :risky t)
+
+(defcustom clang-format-style "file"
+ "Style argument to pass to clang-format.
+
+By default clang-format will load the style configuration from
+a file named .clang-format located in one of the parent directories
+of the buffer."
+ :group 'clang-format
+ :type 'string
+ :safe #'stringp)
+(make-variable-buffer-local 'clang-format-style)
+
+(defun clang-format--extract (xml-node)
+ "Extract replacements and cursor information from XML-NODE."
+ (unless (and (listp xml-node) (eq (xml-node-name xml-node) 'replacements))
+ (error "Expected <replacements> node"))
+ (let ((nodes (xml-node-children xml-node))
+ replacements
+ cursor)
+ (dolist (node nodes)
+ (when (listp node)
+ (let* ((children (xml-node-children node))
+ (text (car children)))
+ (cl-case (xml-node-name node)
+ ('replacement
+ (let* ((offset (xml-get-attribute-or-nil node 'offset))
+ (length (xml-get-attribute-or-nil node 'length)))
+ (when (or (null offset) (null length))
+ (error "<replacement> node does not have offset and length attributes"))
+ (when (cdr children)
+ (error "More than one child node in <replacement> node"))
+
+ (setq offset (1+ (string-to-number offset)))
+ (setq length (string-to-number length))
+ (push (list offset length text) replacements)))
+ ('cursor
+ (setq cursor (1+ (string-to-number text))))))))
+
+ ;; Sort by decreasing offset, length.
+ (setq replacements (sort (delq nil replacements)
+ (lambda (a b)
+ (or (> (car a) (car b))
+ (and (= (car a) (car b))
+ (> (cadr a) (cadr b)))))))
+
+ (cons replacements cursor)))
+
+(defun clang-format--replace (offset length &optional text)
+ (goto-char offset)
+ (delete-char length)
+ (when text
+ (insert text)))
+
+;;;###autoload
+(defun clang-format-region (start end &optional style)
+ "Use clang-format to format the code between START and END according to STYLE.
+If called interactively uses the region or the current statement if there
+is no active region. If no style is given uses `clang-format-style'."
+ (interactive
+ (if (use-region-p)
+ (list (region-beginning) (region-end))
+ (list (point) (point))))
+
+ (unless style
+ (setq style clang-format-style))
+
+ (let ((temp-buffer (generate-new-buffer " *clang-format-temp*"))
+ (temp-file (make-temp-file "clang-format")))
(unwind-protect
- (call-process-region (point-min) (point-max) clang-format-binary
- t (list t nil) nil
- "-offset" (number-to-string (1- begin))
- "-length" (number-to-string (- end begin))
- "-cursor" (number-to-string (1- (point)))
- "-assume-filename" (buffer-file-name)
- "-style" style)
- (goto-char (point-min))
- (let ((json-output (json-read-from-string
- (buffer-substring-no-properties
- (point-min) (line-beginning-position 2)))))
- (delete-region (point-min) (line-beginning-position 2))
- (goto-char (1+ (cdr (assoc 'Cursor json-output))))
- (dotimes (index (length orig-windows))
- (set-window-start (nth index orig-windows)
- (nth index orig-window-starts)))))))
+ (let (status stderr operations)
+ (setq status
+ (call-process-region
+ (point-min) (point-max) clang-format-executable
+ nil `(,temp-buffer ,temp-file) nil
+
+ "-output-replacements-xml"
+ "-assume-filename" (or (buffer-file-name) "")
+ "-style" style
+ "-offset" (number-to-string (1- start))
+ "-length" (number-to-string (- end start))
+ "-cursor" (number-to-string (1- (point)))))
+ (setq stderr
+ (with-temp-buffer
+ (insert-file-contents temp-file)
+ (when (> (point-max) (point-min))
+ (insert ": "))
+ (buffer-substring-no-properties
+ (point-min) (line-end-position))))
+
+ (cond
+ ((stringp status)
+ (error "(clang-format killed by signal %s%s)" status stderr))
+ ((not (equal 0 status))
+ (error "(clang-format failed with code %d%s)" status stderr))
+ (t (message "(clang-format succeeded%s)" stderr)))
+
+ (with-current-buffer temp-buffer
+ (setq operations (clang-format--extract (car (xml-parse-region)))))
+
+ (let ((replacements (car operations))
+ (cursor (cdr operations)))
+ (save-excursion
+ (mapc (lambda (rpl)
+ (apply #'clang-format--replace rpl))
+ replacements))
+ (when cursor
+ (goto-char cursor))))
+ (delete-file temp-file)
+ (when (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
+
+;;;###autoload
+(defun clang-format-buffer (&optional style)
+ "Use clang-format to format the current buffer according to STYLE."
+ (interactive)
+ (clang-format-region (point-min) (point-max) style))
+
+;;;###autoload
+(defalias 'clang-format 'clang-format-region)
+
+(provide 'clang-format)
+;;; clang-format.el ends here
diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py
index 16a187910832..a79205a6dfe8 100644
--- a/tools/clang-format/clang-format.py
+++ b/tools/clang-format/clang-format.py
@@ -2,8 +2,8 @@
# - Change 'binary' if clang-format is not on the path (see below).
# - Add to your .vimrc:
#
-# map <C-I> :pyf <path-to-this-file>/clang-format.py<CR>
-# imap <C-I> <ESC>:pyf <path-to-this-file>/clang-format.py<CR>i
+# map <C-I> :pyf <path-to-this-file>/clang-format.py<cr>
+# imap <C-I> <c-o>:pyf <path-to-this-file>/clang-format.py<cr>
#
# The first line enables clang-format for NORMAL and VISUAL mode, the second
# line adds support for INSERT mode. Change "C-I" to another binding if you
@@ -23,8 +23,11 @@ import subprocess
import sys
import vim
+# set g:clang_format_path to the path to clang-format if it is not on the path
# Change this to the full path if clang-format is not on the path.
binary = 'clang-format'
+if vim.eval('exists("g:clang_format_path")') == "1":
+ binary = vim.eval('g:clang_format_path')
# Change this to format according to other formatting styles. See the output of
# 'clang-format --help' for a list of supported styles. The default looks for
diff --git a/tools/clang-format/git-clang-format b/tools/clang-format/git-clang-format
index c40b74dae4ba..6a0db27fa9f6 100755
--- a/tools/clang-format/git-clang-format
+++ b/tools/clang-format/git-clang-format
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
#
#===- git-clang-format - ClangFormat Git Integration ---------*- python -*--===#
#
diff --git a/tools/diagtool/DiagTool.cpp b/tools/diagtool/DiagTool.cpp
index 44bc83e5455f..0e4d8088c6c2 100644
--- a/tools/diagtool/DiagTool.cpp
+++ b/tools/diagtool/DiagTool.cpp
@@ -36,7 +36,7 @@ DiagTool *DiagTools::getTool(llvm::StringRef toolCmd) {
}
void DiagTools::registerTool(DiagTool *tool) {
- getTools(tools)->GetOrCreateValue(tool->getName(), tool);
+ (*getTools(tools))[tool->getName()] = tool;
}
void DiagTools::printCommands(llvm::raw_ostream &out) {
diff --git a/tools/diagtool/DiagTool.h b/tools/diagtool/DiagTool.h
index b1e69f38c323..04b926df3b60 100644
--- a/tools/diagtool/DiagTool.h
+++ b/tools/diagtool/DiagTool.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef DIAGTOOL_DIAGTOOL_H
-#define DIAGTOOL_DIAGTOOL_H
+#ifndef LLVM_CLANG_TOOLS_DIAGTOOL_DIAGTOOL_H
+#define LLVM_CLANG_TOOLS_DIAGTOOL_DIAGTOOL_H
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ManagedStatic.h"
diff --git a/tools/diagtool/DiagnosticNames.h b/tools/diagtool/DiagnosticNames.h
index 2571b1996918..ac1a09857952 100644
--- a/tools/diagtool/DiagnosticNames.h
+++ b/tools/diagtool/DiagnosticNames.h
@@ -7,6 +7,9 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_DIAGTOOL_DIAGNOSTICNAMES_H
+#define LLVM_CLANG_TOOLS_DIAGTOOL_DIAGNOSTICNAMES_H
+
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
@@ -112,3 +115,4 @@ namespace diagtool {
}
} // end namespace diagtool
+#endif
diff --git a/tools/diagtool/ListWarnings.cpp b/tools/diagtool/ListWarnings.cpp
index 16837a158495..3e6e88306e24 100644
--- a/tools/diagtool/ListWarnings.cpp
+++ b/tools/diagtool/ListWarnings.cpp
@@ -73,7 +73,7 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
Unflagged.push_back(entry);
else {
Flagged.push_back(entry);
- flagHistogram.GetOrCreateValue(entry.Flag).getValue().push_back(diagID);
+ flagHistogram[entry.Flag].push_back(diagID);
}
}
@@ -97,11 +97,10 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
double avgDiagsPerFlag = (double) Flagged.size() / flagHistogram.size();
out << " Average number of diagnostics per flag: "
<< llvm::format("%.4g", avgDiagsPerFlag) << '\n';
-
+
out << " Number in -Wpedantic (not covered by other -W flags): "
- << flagHistogram.GetOrCreateValue("pedantic").getValue().size()
- << '\n';
-
+ << flagHistogram["pedantic"].size() << '\n';
+
out << '\n';
return 0;
diff --git a/tools/diagtool/ShowEnabledWarnings.cpp b/tools/diagtool/ShowEnabledWarnings.cpp
index 903d1f16f992..06f74320b7fc 100644
--- a/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/tools/diagtool/ShowEnabledWarnings.cpp
@@ -65,7 +65,7 @@ createDiagnostics(unsigned int argc, char **argv) {
// Try to build a CompilerInvocation.
std::unique_ptr<CompilerInvocation> Invocation(
- createInvocationFromCommandLine(ArrayRef<const char *>(argv, argc),
+ createInvocationFromCommandLine(llvm::makeArrayRef(argv, argc),
InterimDiags));
if (!Invocation)
return nullptr;
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 990c4fc3c84e..fa1a10e96356 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -63,8 +63,7 @@ void initializePollyPasses(llvm::PassRegistry &Registry);
}
#endif
-int cc1_main(const char **ArgBegin, const char **ArgEnd,
- const char *Argv0, void *MainAddr) {
+int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
@@ -84,9 +83,8 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
- bool Success;
- Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
- ArgBegin, ArgEnd, Diags);
+ bool Success = CompilerInvocation::CreateFromArgs(
+ Clang->getInvocation(), Argv.begin(), Argv.end(), Diags);
// Infer the builtin include path if unspecified.
if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
@@ -124,7 +122,7 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
if (Clang->getFrontendOpts().DisableFree) {
if (llvm::AreStatisticsEnabled() || Clang->getFrontendOpts().ShowStats)
llvm::PrintStatistics();
- BuryPointer(Clang.release());
+ BuryPointer(std::move(Clang));
return !Success;
}
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index e41bc9f824e8..55c9fe602fa3 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -123,6 +123,7 @@ struct AssemblerInvocation {
unsigned RelaxAll : 1;
unsigned NoExecStack : 1;
+ unsigned FatalWarnings : 1;
/// @}
@@ -138,18 +139,19 @@ public:
ShowEncoding = 0;
RelaxAll = 0;
NoExecStack = 0;
+ FatalWarnings = 0;
DwarfVersion = 3;
}
- static bool CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin,
- const char **ArgEnd, DiagnosticsEngine &Diags);
+ static bool CreateFromArgs(AssemblerInvocation &Res,
+ ArrayRef<const char *> Argv,
+ DiagnosticsEngine &Diags);
};
}
bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
- const char **ArgBegin,
- const char **ArgEnd,
+ ArrayRef<const char *> Argv,
DiagnosticsEngine &Diags) {
bool Success = true;
@@ -159,7 +161,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
const unsigned IncludedFlagsBitmask = options::CC1AsOption;
unsigned MissingArgIndex, MissingArgCount;
std::unique_ptr<InputArgList> Args(
- OptTbl->ParseArgs(ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount,
+ OptTbl->ParseArgs(Argv.begin(), Argv.end(), MissingArgIndex, MissingArgCount,
IncludedFlagsBitmask));
// Check for missing argument error.
@@ -246,7 +248,8 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Assemble Options
Opts.RelaxAll = Args->hasArg(OPT_mrelax_all);
- Opts.NoExecStack = Args->hasArg(OPT_mno_exec_stack);
+ Opts.NoExecStack = Args->hasArg(OPT_mno_exec_stack);
+ Opts.FatalWarnings = Args->hasArg(OPT_massembler_fatal_warnings);
return Success;
}
@@ -262,13 +265,12 @@ static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
if (Opts.OutputPath != "-")
sys::RemoveFileOnSignal(Opts.OutputPath);
- std::string Error;
- raw_fd_ostream *Out =
- new raw_fd_ostream(Opts.OutputPath.c_str(), Error,
- (Binary ? sys::fs::F_None : sys::fs::F_Text));
- if (!Error.empty()) {
- Diags.Report(diag::err_fe_unable_to_open_output)
- << Opts.OutputPath << Error;
+ std::error_code EC;
+ raw_fd_ostream *Out = new raw_fd_ostream(
+ Opts.OutputPath, EC, (Binary ? sys::fs::F_None : sys::fs::F_Text));
+ if (EC) {
+ Diags.Report(diag::err_fe_unable_to_open_output) << Opts.OutputPath
+ << EC.message();
delete Out;
return nullptr;
}
@@ -295,7 +297,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
SourceMgr SrcMgr;
// Tell SrcMgr about this buffer, which is what the parser will pick up.
- SrcMgr.AddNewSourceBuffer(Buffer->release(), SMLoc());
+ SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc());
// Record the location of the include directories so that the lexer can find
// it later.
@@ -378,9 +380,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple,
Opts.CPU);
Str.reset(TheTarget->createMCObjectStreamer(Opts.Triple, Ctx, *MAB, *Out,
- CE, *STI, Opts.RelaxAll,
- Opts.NoExecStack));
- Str.get()->InitSections();
+ CE, *STI, Opts.RelaxAll));
+ Str.get()->InitSections(Opts.NoExecStack);
}
bool Failed = false;
@@ -420,11 +421,10 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message,
exit(1);
}
-int cc1as_main(const char **ArgBegin, const char **ArgEnd,
- const char *Argv0, void *MainAddr) {
+int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();
- PrettyStackTraceProgram X(ArgEnd - ArgBegin, ArgBegin);
+ PrettyStackTraceProgram X(Argv.size(), Argv.data());
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
// Initialize targets and assembly printers/parsers.
@@ -447,7 +447,7 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
// Parse the arguments.
AssemblerInvocation Asm;
- if (!AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags))
+ if (!AssemblerInvocation::CreateFromArgs(Asm, Argv, Diags))
return 1;
if (Asm.ShowHelp) {
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 9f93837c2c75..e1f9367b0f5c 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -18,7 +18,9 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
+#include "clang/Frontend/ChainedDiagnosticConsumer.h"
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "llvm/ADT/ArrayRef.h"
@@ -61,8 +63,8 @@ std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
return llvm::sys::fs::getMainExecutable(Argv0, P);
}
-static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
- StringRef S) {
+static const char *GetStableCStr(std::set<std::string> &SavedStrings,
+ StringRef S) {
return SavedStrings.insert(S).first->c_str();
}
@@ -101,12 +103,12 @@ static void ApplyOneQAOverride(raw_ostream &OS,
if (Edit[0] == '^') {
const char *Str =
- SaveStringInSet(SavedStrings, Edit.substr(1));
+ GetStableCStr(SavedStrings, Edit.substr(1));
OS << "### Adding argument " << Str << " at beginning\n";
Args.insert(Args.begin() + 1, Str);
} else if (Edit[0] == '+') {
const char *Str =
- SaveStringInSet(SavedStrings, Edit.substr(1));
+ GetStableCStr(SavedStrings, Edit.substr(1));
OS << "### Adding argument " << Str << " at end\n";
Args.push_back(Str);
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
@@ -116,11 +118,14 @@ static void ApplyOneQAOverride(raw_ostream &OS,
ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
+ // Ignore end-of-line response file markers
+ if (Args[i] == nullptr)
+ continue;
std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
if (Repl != Args[i]) {
OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
- Args[i] = SaveStringInSet(SavedStrings, Repl);
+ Args[i] = GetStableCStr(SavedStrings, Repl);
}
}
} else if (Edit[0] == 'x' || Edit[0] == 'X') {
@@ -142,6 +147,9 @@ static void ApplyOneQAOverride(raw_ostream &OS,
} else if (Edit[0] == 'O') {
for (unsigned i = 1; i < Args.size();) {
const char *A = Args[i];
+ // Ignore end-of-line response file markers
+ if (A == nullptr)
+ continue;
if (A[0] == '-' && A[1] == 'O' &&
(A[2] == '\0' ||
(A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
@@ -152,7 +160,7 @@ static void ApplyOneQAOverride(raw_ostream &OS,
++i;
}
OS << "### Adding argument " << Edit << " at end\n";
- Args.push_back(SaveStringInSet(SavedStrings, '-' + Edit.str()));
+ Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
} else {
OS << "### Unrecognized edit: " << Edit << "\n";
}
@@ -187,97 +195,98 @@ static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
}
}
-extern int cc1_main(const char **ArgBegin, const char **ArgEnd,
- const char *Argv0, void *MainAddr);
-extern int cc1as_main(const char **ArgBegin, const char **ArgEnd,
- const char *Argv0, void *MainAddr);
+extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
+ void *MainAddr);
+extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
+ void *MainAddr);
+
+struct DriverSuffix {
+ const char *Suffix;
+ const char *ModeFlag;
+};
+
+static const DriverSuffix *FindDriverSuffix(StringRef ProgName) {
+ // A list of known driver suffixes. Suffixes are compared against the
+ // program name in order. If there is a match, the frontend type if updated as
+ // necessary by applying the ModeFlag.
+ static const DriverSuffix DriverSuffixes[] = {
+ {"clang", nullptr},
+ {"clang++", "--driver-mode=g++"},
+ {"clang-c++", "--driver-mode=g++"},
+ {"clang-cc", nullptr},
+ {"clang-cpp", "--driver-mode=cpp"},
+ {"clang-g++", "--driver-mode=g++"},
+ {"clang-gcc", nullptr},
+ {"clang-cl", "--driver-mode=cl"},
+ {"cc", nullptr},
+ {"cpp", "--driver-mode=cpp"},
+ {"cl", "--driver-mode=cl"},
+ {"++", "--driver-mode=g++"},
+ };
+
+ for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i)
+ if (ProgName.endswith(DriverSuffixes[i].Suffix))
+ return &DriverSuffixes[i];
+ return nullptr;
+}
static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
- std::set<std::string> &SavedStrings,
- Driver &TheDriver)
-{
- // Try to infer frontend type and default target from the program name.
-
- // suffixes[] contains the list of known driver suffixes.
- // Suffixes are compared against the program name in order.
- // If there is a match, the frontend type is updated as necessary (CPP/C++).
- // If there is no match, a second round is done after stripping the last
- // hyphen and everything following it. This allows using something like
- // "clang++-2.9".
-
- // If there is a match in either the first or second round,
- // the function tries to identify a target as prefix. E.g.
- // "x86_64-linux-clang" as interpreted as suffix "clang" with
- // target prefix "x86_64-linux". If such a target prefix is found,
- // is gets added via -target as implicit first argument.
- static const struct {
- const char *Suffix;
- const char *ModeFlag;
- } suffixes [] = {
- { "clang", nullptr },
- { "clang++", "--driver-mode=g++" },
- { "clang-c++", "--driver-mode=g++" },
- { "clang-cc", nullptr },
- { "clang-cpp", "--driver-mode=cpp" },
- { "clang-g++", "--driver-mode=g++" },
- { "clang-gcc", nullptr },
- { "clang-cl", "--driver-mode=cl" },
- { "cc", nullptr },
- { "cpp", "--driver-mode=cpp" },
- { "cl" , "--driver-mode=cl" },
- { "++", "--driver-mode=g++" },
- };
- std::string ProgName(llvm::sys::path::stem(ArgVector[0]));
+ std::set<std::string> &SavedStrings) {
+ // Try to infer frontend type and default target from the program name by
+ // comparing it against DriverSuffixes in order.
+
+ // If there is a match, the function tries to identify a target as prefix.
+ // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target
+ // prefix "x86_64-linux". If such a target prefix is found, is gets added via
+ // -target as implicit first argument.
+
+ std::string ProgName =llvm::sys::path::stem(ArgVector[0]);
#ifdef LLVM_ON_WIN32
// Transform to lowercase for case insensitive file systems.
- std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(),
- toLowercase);
+ ProgName = StringRef(ProgName).lower();
#endif
- StringRef ProgNameRef(ProgName);
- StringRef Prefix;
-
- for (int Components = 2; Components; --Components) {
- bool FoundMatch = false;
- size_t i;
-
- for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
- if (ProgNameRef.endswith(suffixes[i].Suffix)) {
- FoundMatch = true;
- SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
- if (it != ArgVector.end())
- ++it;
- if (suffixes[i].ModeFlag)
- ArgVector.insert(it, suffixes[i].ModeFlag);
- break;
- }
- }
- if (FoundMatch) {
- StringRef::size_type LastComponent = ProgNameRef.rfind('-',
- ProgNameRef.size() - strlen(suffixes[i].Suffix));
- if (LastComponent != StringRef::npos)
- Prefix = ProgNameRef.slice(0, LastComponent);
- break;
- }
+ StringRef ProgNameRef = ProgName;
+ const DriverSuffix *DS = FindDriverSuffix(ProgNameRef);
- StringRef::size_type LastComponent = ProgNameRef.rfind('-');
- if (LastComponent == StringRef::npos)
- break;
- ProgNameRef = ProgNameRef.slice(0, LastComponent);
+ if (!DS) {
+ // Try again after stripping any trailing version number:
+ // clang++3.5 -> clang++
+ ProgNameRef = ProgNameRef.rtrim("0123456789.");
+ DS = FindDriverSuffix(ProgNameRef);
}
- if (Prefix.empty())
- return;
-
- std::string IgnoredError;
- if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
- SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
- if (it != ArgVector.end())
- ++it;
- const char* Strings[] =
- { SaveStringInSet(SavedStrings, std::string("-target")),
- SaveStringInSet(SavedStrings, Prefix) };
- ArgVector.insert(it, Strings, Strings + llvm::array_lengthof(Strings));
+ if (!DS) {
+ // Try again after stripping trailing -component.
+ // clang++-tot -> clang++
+ ProgNameRef = ProgNameRef.slice(0, ProgNameRef.rfind('-'));
+ DS = FindDriverSuffix(ProgNameRef);
+ }
+
+ if (DS) {
+ if (const char *Flag = DS->ModeFlag) {
+ // Add Flag to the arguments.
+ auto it = ArgVector.begin();
+ if (it != ArgVector.end())
+ ++it;
+ ArgVector.insert(it, Flag);
+ }
+
+ StringRef::size_type LastComponent = ProgNameRef.rfind(
+ '-', ProgNameRef.size() - strlen(DS->Suffix));
+ if (LastComponent == StringRef::npos)
+ return;
+
+ // Infer target from the prefix.
+ StringRef Prefix = ProgNameRef.slice(0, LastComponent);
+ std::string IgnoredError;
+ if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
+ auto it = ArgVector.begin();
+ if (it != ArgVector.end())
+ ++it;
+ const char *arr[] = { "-target", GetStableCStr(SavedStrings, Prefix) };
+ ArgVector.insert(it, std::begin(arr), std::end(arr));
+ }
}
}
@@ -286,21 +295,97 @@ namespace {
public:
StringSetSaver(std::set<std::string> &Storage) : Storage(Storage) {}
const char *SaveString(const char *Str) override {
- return SaveStringInSet(Storage, Str);
+ return GetStableCStr(Storage, Str);
}
private:
std::set<std::string> &Storage;
};
}
+static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
+ // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
+ TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
+ if (TheDriver.CCPrintOptions)
+ TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
+
+ // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE.
+ TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS");
+ if (TheDriver.CCPrintHeaders)
+ TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
+
+ // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
+ TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
+ if (TheDriver.CCLogDiagnostics)
+ TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
+}
+
+static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
+ const std::string &Path) {
+ // If the clang binary happens to be named cl.exe for compatibility reasons,
+ // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
+ StringRef ExeBasename(llvm::sys::path::filename(Path));
+ if (ExeBasename.equals_lower("cl.exe"))
+ ExeBasename = "clang-cl.exe";
+ DiagClient->setPrefix(ExeBasename);
+}
+
+// This lets us create the DiagnosticsEngine with a properly-filled-out
+// DiagnosticOptions instance.
+static DiagnosticOptions *
+CreateAndPopulateDiagOpts(SmallVectorImpl<const char *> &argv) {
+ auto *DiagOpts = new DiagnosticOptions;
+ std::unique_ptr<OptTable> Opts(createDriverOptTable());
+ unsigned MissingArgIndex, MissingArgCount;
+ std::unique_ptr<InputArgList> Args(Opts->ParseArgs(
+ argv.begin() + 1, argv.end(), MissingArgIndex, MissingArgCount));
+ // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
+ // Any errors that would be diagnosed here will also be diagnosed later,
+ // when the DiagnosticsEngine actually exists.
+ (void) ParseDiagnosticArgs(*DiagOpts, *Args);
+ return DiagOpts;
+}
+
+static void SetInstallDir(SmallVectorImpl<const char *> &argv,
+ Driver &TheDriver) {
+ // Attempt to find the original path used to invoke the driver, to determine
+ // the installed path. We do this manually, because we want to support that
+ // path being a symlink.
+ SmallString<128> InstalledPath(argv[0]);
+
+ // Do a PATH lookup, if there are no directory components.
+ if (llvm::sys::path::filename(InstalledPath) == InstalledPath)
+ if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName(
+ llvm::sys::path::filename(InstalledPath.str())))
+ InstalledPath = *Tmp;
+ llvm::sys::fs::make_absolute(InstalledPath);
+ InstalledPath = llvm::sys::path::parent_path(InstalledPath);
+ if (llvm::sys::fs::exists(InstalledPath.c_str()))
+ TheDriver.setInstalledDir(InstalledPath);
+}
+
+static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
+ void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath;
+ if (Tool == "")
+ return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP);
+ if (Tool == "as")
+ return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP);
+
+ // Reject unknown tools.
+ llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n";
+ return 1;
+}
+
int main(int argc_, const char **argv_) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc_, argv_);
+ if (llvm::sys::Process::FixupStandardFileDescriptors())
+ return 1;
+
SmallVector<const char *, 256> argv;
llvm::SpecificBumpPtrAllocator<char> ArgAllocator;
std::error_code EC = llvm::sys::Process::GetArgumentVector(
- argv, ArrayRef<const char *>(argv_, argc_), ArgAllocator);
+ argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator);
if (EC) {
llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n';
return 1;
@@ -308,26 +393,33 @@ int main(int argc_, const char **argv_) {
std::set<std::string> SavedStrings;
StringSetSaver Saver(SavedStrings);
- llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv);
-
- // Handle -cc1 integrated tools.
- if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) {
- StringRef Tool = argv[1] + 4;
-
- if (Tool == "")
- return cc1_main(argv.data()+2, argv.data()+argv.size(), argv[0],
- (void*) (intptr_t) GetExecutablePath);
- if (Tool == "as")
- return cc1as_main(argv.data()+2, argv.data()+argv.size(), argv[0],
- (void*) (intptr_t) GetExecutablePath);
- // Reject unknown tools.
- llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n";
- return 1;
+ // Determines whether we want nullptr markers in argv to indicate response
+ // files end-of-lines. We only use this for the /LINK driver argument.
+ bool MarkEOLs = true;
+ if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1"))
+ MarkEOLs = false;
+ llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv,
+ MarkEOLs);
+
+ // Handle -cc1 integrated tools, even if -cc1 was expanded from a response
+ // file.
+ auto FirstArg = std::find_if(argv.begin() + 1, argv.end(),
+ [](const char *A) { return A != nullptr; });
+ if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) {
+ // If -cc1 came from a response file, remove the EOL sentinels.
+ if (MarkEOLs) {
+ auto newEnd = std::remove(argv.begin(), argv.end(), nullptr);
+ argv.resize(newEnd - argv.begin());
+ }
+ return ExecuteCC1Tool(argv, argv[1] + 4);
}
bool CanonicalPrefixes = true;
for (int i = 1, size = argv.size(); i < size; ++i) {
+ // Skip end-of-line response file markers
+ if (argv[i] == nullptr)
+ continue;
if (StringRef(argv[i]) == "-no-canonical-prefixes") {
CanonicalPrefixes = false;
break;
@@ -343,73 +435,34 @@ int main(int argc_, const char **argv_) {
std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes);
- IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
- {
- std::unique_ptr<OptTable> Opts(createDriverOptTable());
- unsigned MissingArgIndex, MissingArgCount;
- std::unique_ptr<InputArgList> Args(Opts->ParseArgs(
- argv.begin() + 1, argv.end(), MissingArgIndex, MissingArgCount));
- // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
- // Any errors that would be diagnosed here will also be diagnosed later,
- // when the DiagnosticsEngine actually exists.
- (void) ParseDiagnosticArgs(*DiagOpts, *Args);
- }
- // Now we can create the DiagnosticsEngine with a properly-filled-out
- // DiagnosticOptions instance.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
+ CreateAndPopulateDiagOpts(argv);
+
TextDiagnosticPrinter *DiagClient
= new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
-
- // If the clang binary happens to be named cl.exe for compatibility reasons,
- // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
- StringRef ExeBasename(llvm::sys::path::filename(Path));
- if (ExeBasename.equals_lower("cl.exe"))
- ExeBasename = "clang-cl.exe";
- DiagClient->setPrefix(ExeBasename);
+ FixupDiagPrefixExeName(DiagClient, Path);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
- ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
-
- Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
- // Attempt to find the original path used to invoke the driver, to determine
- // the installed path. We do this manually, because we want to support that
- // path being a symlink.
- {
- SmallString<128> InstalledPath(argv[0]);
-
- // Do a PATH lookup, if there are no directory components.
- if (llvm::sys::path::filename(InstalledPath) == InstalledPath) {
- std::string Tmp = llvm::sys::FindProgramByName(
- llvm::sys::path::filename(InstalledPath.str()));
- if (!Tmp.empty())
- InstalledPath = Tmp;
- }
- llvm::sys::fs::make_absolute(InstalledPath);
- InstalledPath = llvm::sys::path::parent_path(InstalledPath);
- bool exists;
- if (!llvm::sys::fs::exists(InstalledPath.str(), exists) && exists)
- TheDriver.setInstalledDir(InstalledPath);
+ if (!DiagOpts->DiagnosticSerializationFile.empty()) {
+ auto SerializedConsumer =
+ clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
+ &*DiagOpts, /*MergeChildRecords=*/true);
+ Diags.setClient(new ChainedDiagnosticConsumer(
+ Diags.takeClient(), std::move(SerializedConsumer)));
}
- llvm::InitializeAllTargets();
- ParseProgName(argv, SavedStrings, TheDriver);
+ ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
- // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
- TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
- if (TheDriver.CCPrintOptions)
- TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
+ Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
+ SetInstallDir(argv, TheDriver);
- // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE.
- TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS");
- if (TheDriver.CCPrintHeaders)
- TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
+ llvm::InitializeAllTargets();
+ ParseProgName(argv, SavedStrings);
- // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
- TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
- if (TheDriver.CCLogDiagnostics)
- TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
+ SetBackdoorDriverOutputsFromEnvVars(TheDriver);
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
int Res = 0;
@@ -420,14 +473,17 @@ int main(int argc_, const char **argv_) {
// Force a crash to test the diagnostics.
if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) {
Diags.Report(diag::err_drv_force_crash) << "FORCE_CLANG_DIAGNOSTICS_CRASH";
- const Command *FailingCommand = nullptr;
- FailingCommands.push_back(std::make_pair(-1, FailingCommand));
+
+ // Pretend that every command failed.
+ FailingCommands.clear();
+ for (const auto &J : C->getJobs())
+ if (const Command *C = dyn_cast<Command>(&J))
+ FailingCommands.push_back(std::make_pair(-1, C));
}
- for (SmallVectorImpl< std::pair<int, const Command *> >::iterator it =
- FailingCommands.begin(), ie = FailingCommands.end(); it != ie; ++it) {
- int CommandRes = it->first;
- const Command *FailingCommand = it->second;
+ for (const auto &P : FailingCommands) {
+ int CommandRes = P.first;
+ const Command *FailingCommand = P.second;
if (!Res)
Res = CommandRes;
@@ -440,15 +496,17 @@ int main(int argc_, const char **argv_) {
DiagnoseCrash |= CommandRes == 3;
#endif
if (DiagnoseCrash) {
- TheDriver.generateCompilationDiagnostics(*C, FailingCommand);
+ TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
break;
}
}
+ Diags.getClient()->finish();
+
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
llvm::TimerGroup::printAll(llvm::errs());
-
+
llvm::llvm_shutdown();
#ifdef LLVM_ON_WIN32
diff --git a/tools/libclang/ARCMigrate.cpp b/tools/libclang/ARCMigrate.cpp
index 375c5f40c21b..b0b869ba900b 100644
--- a/tools/libclang/ARCMigrate.cpp
+++ b/tools/libclang/ARCMigrate.cpp
@@ -47,9 +47,7 @@ CXRemapping clang_getRemappings(const char *migrate_dir_path) {
return nullptr;
}
- bool exists = false;
- llvm::sys::fs::exists(migrate_dir_path, exists);
- if (!exists) {
+ if (!llvm::sys::fs::exists(migrate_dir_path)) {
if (Logging) {
llvm::errs() << "Error by clang_getRemappings(\"" << migrate_dir_path
<< "\")\n";
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index fc8703aface1..00ef8c0bf424 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -22,10 +22,12 @@
#include "CXType.h"
#include "CursorVisitor.h"
#include "clang/AST/Attr.h"
+#include "clang/AST/Mangle.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -40,6 +42,8 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Mangler.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Format.h"
@@ -1256,6 +1260,7 @@ bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS,
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Super:
break;
}
@@ -1297,6 +1302,7 @@ CursorVisitor::VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) {
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Super:
break;
}
}
@@ -1828,6 +1834,7 @@ public:
void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *E);
void VisitCXXUuidofExpr(const CXXUuidofExpr *E);
void VisitCXXCatchStmt(const CXXCatchStmt *S);
+ void VisitCXXForRangeStmt(const CXXForRangeStmt *S);
void VisitDeclRefExpr(const DeclRefExpr *D);
void VisitDeclStmt(const DeclStmt *S);
void VisitDependentScopeDeclRefExpr(const DependentScopeDeclRefExpr *E);
@@ -1856,21 +1863,28 @@ public:
void VisitOpaqueValueExpr(const OpaqueValueExpr *E);
void VisitLambdaExpr(const LambdaExpr *E);
void VisitOMPExecutableDirective(const OMPExecutableDirective *D);
+ void VisitOMPLoopDirective(const OMPLoopDirective *D);
void VisitOMPParallelDirective(const OMPParallelDirective *D);
void VisitOMPSimdDirective(const OMPSimdDirective *D);
void VisitOMPForDirective(const OMPForDirective *D);
+ void VisitOMPForSimdDirective(const OMPForSimdDirective *D);
void VisitOMPSectionsDirective(const OMPSectionsDirective *D);
void VisitOMPSectionDirective(const OMPSectionDirective *D);
void VisitOMPSingleDirective(const OMPSingleDirective *D);
void VisitOMPMasterDirective(const OMPMasterDirective *D);
void VisitOMPCriticalDirective(const OMPCriticalDirective *D);
void VisitOMPParallelForDirective(const OMPParallelForDirective *D);
+ void VisitOMPParallelForSimdDirective(const OMPParallelForSimdDirective *D);
void VisitOMPParallelSectionsDirective(const OMPParallelSectionsDirective *D);
void VisitOMPTaskDirective(const OMPTaskDirective *D);
void VisitOMPTaskyieldDirective(const OMPTaskyieldDirective *D);
void VisitOMPBarrierDirective(const OMPBarrierDirective *D);
void VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D);
void VisitOMPFlushDirective(const OMPFlushDirective *D);
+ void VisitOMPOrderedDirective(const OMPOrderedDirective *D);
+ void VisitOMPAtomicDirective(const OMPAtomicDirective *D);
+ void VisitOMPTargetDirective(const OMPTargetDirective *D);
+ void VisitOMPTeamsDirective(const OMPTeamsDirective *D);
private:
void AddDeclarationNameInfo(const Stmt *S);
@@ -1979,14 +1993,28 @@ void OMPClauseEnqueue::VisitOMPUntiedClause(const OMPUntiedClause *) {}
void OMPClauseEnqueue::VisitOMPMergeableClause(const OMPMergeableClause *) {}
+void OMPClauseEnqueue::VisitOMPReadClause(const OMPReadClause *) {}
+
+void OMPClauseEnqueue::VisitOMPWriteClause(const OMPWriteClause *) {}
+
+void OMPClauseEnqueue::VisitOMPUpdateClause(const OMPUpdateClause *) {}
+
+void OMPClauseEnqueue::VisitOMPCaptureClause(const OMPCaptureClause *) {}
+
+void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
+
template<typename T>
void OMPClauseEnqueue::VisitOMPClauseList(T *Node) {
- for (const auto *I : Node->varlists())
+ for (const auto *I : Node->varlists()) {
Visitor->AddStmt(I);
+ }
}
void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) {
VisitOMPClauseList(C);
+ for (const auto *E : C->private_copies()) {
+ Visitor->AddStmt(E);
+ }
}
void OMPClauseEnqueue::VisitOMPFirstprivateClause(
const OMPFirstprivateClause *C) {
@@ -2127,6 +2155,12 @@ void EnqueueVisitor::VisitCXXCatchStmt(const CXXCatchStmt *S) {
AddDecl(S->getExceptionDecl());
}
+void EnqueueVisitor::VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
+ AddStmt(S->getBody());
+ AddStmt(S->getRangeInit());
+ AddDecl(S->getLoopVariable());
+}
+
void EnqueueVisitor::VisitDeclRefExpr(const DeclRefExpr *DR) {
if (DR->hasExplicitTemplateArgs()) {
AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs());
@@ -2309,16 +2343,24 @@ void EnqueueVisitor::VisitOMPExecutableDirective(
EnqueueChildren(*I);
}
+void EnqueueVisitor::VisitOMPLoopDirective(const OMPLoopDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
void EnqueueVisitor::VisitOMPParallelDirective(const OMPParallelDirective *D) {
VisitOMPExecutableDirective(D);
}
void EnqueueVisitor::VisitOMPSimdDirective(const OMPSimdDirective *D) {
- VisitOMPExecutableDirective(D);
+ VisitOMPLoopDirective(D);
}
void EnqueueVisitor::VisitOMPForDirective(const OMPForDirective *D) {
- VisitOMPExecutableDirective(D);
+ VisitOMPLoopDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPForSimdDirective(const OMPForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
}
void EnqueueVisitor::VisitOMPSectionsDirective(const OMPSectionsDirective *D) {
@@ -2344,7 +2386,12 @@ void EnqueueVisitor::VisitOMPCriticalDirective(const OMPCriticalDirective *D) {
void
EnqueueVisitor::VisitOMPParallelForDirective(const OMPParallelForDirective *D) {
- VisitOMPExecutableDirective(D);
+ VisitOMPLoopDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPParallelForSimdDirective(
+ const OMPParallelForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
}
void EnqueueVisitor::VisitOMPParallelSectionsDirective(
@@ -2373,6 +2420,22 @@ void EnqueueVisitor::VisitOMPFlushDirective(const OMPFlushDirective *D) {
VisitOMPExecutableDirective(D);
}
+void EnqueueVisitor::VisitOMPOrderedDirective(const OMPOrderedDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPAtomicDirective(const OMPAtomicDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPTargetDirective(const OMPTargetDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPTeamsDirective(const OMPTeamsDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) {
EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
}
@@ -2755,13 +2818,14 @@ enum CXErrorCode clang_createTranslationUnit2(CXIndex CIdx,
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
FileSystemOptions FileSystemOpts;
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
- ASTUnit *AU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts,
- CXXIdx->getOnlyLocalDecls(), None,
- /*CaptureDiagnostics=*/true,
- /*AllowPCHWithCompilerErrors=*/true,
- /*UserFilesAreVolatile=*/true);
- *out_TU = MakeCXTranslationUnit(CXXIdx, AU);
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ CompilerInstance::createDiagnostics(new DiagnosticOptions());
+ std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
+ ast_filename, Diags, FileSystemOpts, CXXIdx->getOnlyLocalDecls(), None,
+ /*CaptureDiagnostics=*/true,
+ /*AllowPCHWithCompilerErrors=*/true,
+ /*UserFilesAreVolatile=*/true);
+ *out_TU = MakeCXTranslationUnit(CXXIdx, AU.release());
return *out_TU ? CXError_Success : CXError_Failure;
}
@@ -2847,9 +2911,9 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get());
for (auto &UF : PTUI->unsaved_files) {
- llvm::MemoryBuffer *MB =
+ std::unique_ptr<llvm::MemoryBuffer> MB =
llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename);
- RemappedFiles->push_back(std::make_pair(UF.Filename, MB));
+ RemappedFiles->push_back(std::make_pair(UF.Filename, MB.release()));
}
std::unique_ptr<std::vector<const char *>> Args(
@@ -3131,9 +3195,9 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) {
std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get());
for (auto &UF : RTUI->unsaved_files) {
- llvm::MemoryBuffer *MB =
+ std::unique_ptr<llvm::MemoryBuffer> MB =
llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename);
- RemappedFiles->push_back(std::make_pair(UF.Filename, MB));
+ RemappedFiles->push_back(std::make_pair(UF.Filename, MB.release()));
}
if (!CXXUnit->Reparse(*RemappedFiles.get()))
@@ -3259,6 +3323,18 @@ int clang_getFileUniqueID(CXFile file, CXFileUniqueID *outID) {
return 0;
}
+int clang_File_isEqual(CXFile file1, CXFile file2) {
+ if (file1 == file2)
+ return true;
+
+ if (!file1 || !file2)
+ return false;
+
+ FileEntry *FEnt1 = static_cast<FileEntry *>(file1);
+ FileEntry *FEnt2 = static_cast<FileEntry *>(file2);
+ return FEnt1->getUniqueID() == FEnt2->getUniqueID();
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -3628,6 +3704,18 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
return clang_getNullRange();
}
+ if (C.kind == CXCursor_CXXMethod || C.kind == CXCursor_Destructor ||
+ C.kind == CXCursor_ConversionFunction) {
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+ if (const FunctionDecl *FD =
+ dyn_cast_or_null<FunctionDecl>(getCursorDecl(C))) {
+ DeclarationNameInfo FunctionName = FD->getNameInfo();
+ return cxloc::translateSourceRange(Ctx, FunctionName.getSourceRange());
+ }
+ return clang_getNullRange();
+ }
+
// FIXME: A CXCursor_InclusionDirective should give the location of the
// filename, but we don't keep track of this.
@@ -3647,6 +3735,37 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
return cxloc::translateSourceRange(Ctx, Loc);
}
+CXString clang_Cursor_getMangling(CXCursor C) {
+ if (clang_isInvalid(C.kind) || !clang_isDeclaration(C.kind))
+ return cxstring::createEmpty();
+
+ // Mangling only works for functions and variables.
+ const Decl *D = getCursorDecl(C);
+ if (!D || !(isa<FunctionDecl>(D) || isa<VarDecl>(D)))
+ return cxstring::createEmpty();
+
+ // First apply frontend mangling.
+ const NamedDecl *ND = cast<NamedDecl>(D);
+ ASTContext &Ctx = ND->getASTContext();
+ std::unique_ptr<MangleContext> MC(Ctx.createMangleContext());
+
+ std::string FrontendBuf;
+ llvm::raw_string_ostream FrontendBufOS(FrontendBuf);
+ MC->mangleName(ND, FrontendBufOS);
+
+ // Now apply backend mangling.
+ std::unique_ptr<llvm::DataLayout> DL(
+ new llvm::DataLayout(Ctx.getTargetInfo().getTargetDescription()));
+ llvm::Mangler BackendMangler(DL.get());
+
+ std::string FinalBuf;
+ llvm::raw_string_ostream FinalBufOS(FinalBuf);
+ BackendMangler.getNameWithPrefix(FinalBufOS,
+ llvm::Twine(FrontendBufOS.str()));
+
+ return cxstring::createDup(FinalBufOS.str());
+}
+
CXString clang_getCursorDisplayName(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getCursorSpelling(C);
@@ -3997,6 +4116,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("attribute(global)");
case CXCursor_CUDAHostAttr:
return cxstring::createRef("attribute(host)");
+ case CXCursor_CUDASharedAttr:
+ return cxstring::createRef("attribute(shared)");
case CXCursor_PreprocessingDirective:
return cxstring::createRef("preprocessing directive");
case CXCursor_MacroDefinition:
@@ -4051,6 +4172,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPSimdDirective");
case CXCursor_OMPForDirective:
return cxstring::createRef("OMPForDirective");
+ case CXCursor_OMPForSimdDirective:
+ return cxstring::createRef("OMPForSimdDirective");
case CXCursor_OMPSectionsDirective:
return cxstring::createRef("OMPSectionsDirective");
case CXCursor_OMPSectionDirective:
@@ -4063,6 +4186,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPCriticalDirective");
case CXCursor_OMPParallelForDirective:
return cxstring::createRef("OMPParallelForDirective");
+ case CXCursor_OMPParallelForSimdDirective:
+ return cxstring::createRef("OMPParallelForSimdDirective");
case CXCursor_OMPParallelSectionsDirective:
return cxstring::createRef("OMPParallelSectionsDirective");
case CXCursor_OMPTaskDirective:
@@ -4075,6 +4200,14 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPTaskwaitDirective");
case CXCursor_OMPFlushDirective:
return cxstring::createRef("OMPFlushDirective");
+ case CXCursor_OMPOrderedDirective:
+ return cxstring::createRef("OMPOrderedDirective");
+ case CXCursor_OMPAtomicDirective:
+ return cxstring::createRef("OMPAtomicDirective");
+ case CXCursor_OMPTargetDirective:
+ return cxstring::createRef("OMPTargetDirective");
+ case CXCursor_OMPTeamsDirective:
+ return cxstring::createRef("OMPTeamsDirective");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -6296,6 +6429,40 @@ static const Decl *maybeGetTemplateCursor(const Decl *D) {
return D;
}
+
+enum CX_StorageClass clang_Cursor_getStorageClass(CXCursor C) {
+ StorageClass sc = SC_None;
+ const Decl *D = getCursorDecl(C);
+ if (D) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ sc = FD->getStorageClass();
+ } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ sc = VD->getStorageClass();
+ } else {
+ return CX_SC_Invalid;
+ }
+ } else {
+ return CX_SC_Invalid;
+ }
+ switch (sc) {
+ case SC_None:
+ return CX_SC_None;
+ case SC_Extern:
+ return CX_SC_Extern;
+ case SC_Static:
+ return CX_SC_Static;
+ case SC_PrivateExtern:
+ return CX_SC_PrivateExtern;
+ case SC_OpenCLWorkGroupLocal:
+ return CX_SC_OpenCLWorkGroupLocal;
+ case SC_Auto:
+ return CX_SC_Auto;
+ case SC_Register:
+ return CX_SC_Register;
+ }
+ llvm_unreachable("Unhandled storage class!");
+}
+
CXCursor clang_getCursorSemanticParent(CXCursor cursor) {
if (clang_isDeclaration(cursor.kind)) {
if (const Decl *D = getCursorDecl(cursor)) {
@@ -6490,11 +6657,7 @@ CXModule clang_getModuleForFile(CXTranslationUnit TU, CXFile File) {
HeaderSearch &HS = Unit.getPreprocessor().getHeaderSearchInfo();
ModuleMap::KnownHeader Header = HS.findModuleForHeader(FE);
- if (Module *Mod = Header.getModule()) {
- if (Header.getRole() != ModuleMap::ExcludedHeader)
- return Mod;
- }
- return nullptr;
+ return Header.getModule();
}
CXFile clang_Module_getASTFile(CXModule CXMod) {
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 0d88003a1f6c..b6f71d20de2b 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -692,9 +692,9 @@ void clang_codeCompleteAt_Impl(void *UserData) {
SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
for (auto &UF : CCAI->unsaved_files) {
- llvm::MemoryBuffer *MB =
+ std::unique_ptr<llvm::MemoryBuffer> MB =
llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename);
- RemappedFiles.push_back(std::make_pair(UF.Filename, MB));
+ RemappedFiles.push_back(std::make_pair(UF.Filename, MB.release()));
}
if (EnableLogging) {
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index 0d97ebd9335b..4d646f0cf828 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -30,13 +30,11 @@ using namespace clang::cxloc;
using namespace clang::cxdiag;
using namespace llvm;
+CXDiagnosticSetImpl::~CXDiagnosticSetImpl() {}
-CXDiagnosticSetImpl::~CXDiagnosticSetImpl() {
- for (std::vector<CXDiagnosticImpl *>::iterator it = Diagnostics.begin(),
- et = Diagnostics.end();
- it != et; ++it) {
- delete *it;
- }
+void
+CXDiagnosticSetImpl::appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D) {
+ Diagnostics.push_back(std::move(D));
}
CXDiagnosticImpl::~CXDiagnosticImpl() {}
@@ -105,12 +103,13 @@ public:
if (Level != DiagnosticsEngine::Note)
CurrentSet = MainSet;
-
- CXStoredDiagnostic *CD = new CXStoredDiagnostic(*SD, LangOpts);
- CurrentSet->appendDiagnostic(CD);
-
+
+ auto Owner = llvm::make_unique<CXStoredDiagnostic>(*SD, LangOpts);
+ CXStoredDiagnostic &CD = *Owner;
+ CurrentSet->appendDiagnostic(std::move(Owner));
+
if (Level != DiagnosticsEngine::Note)
- CurrentSet = &CD->getChildDiagnostics();
+ CurrentSet = &CD.getChildDiagnostics();
}
void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
@@ -127,8 +126,8 @@ public:
L = translateSourceLocation(*SM, LangOpts, Loc);
else
L = clang_getNullLocation();
- CXDiagnosticImpl *CD = new CXDiagnosticCustomNoteImpl(Message, L);
- CurrentSet->appendDiagnostic(CD);
+ CurrentSet->appendDiagnostic(
+ llvm::make_unique<CXDiagnosticCustomNoteImpl>(Message, L));
}
void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
@@ -149,8 +148,8 @@ public:
L = translateSourceLocation(*SM, LangOpts, Loc);
else
L = clang_getNullLocation();
- CurrentSet->appendDiagnostic(new CXDiagnosticCustomNoteImpl(Message,
- L));
+ CurrentSet->appendDiagnostic(
+ llvm::make_unique<CXDiagnosticCustomNoteImpl>(Message, L));
}
CXDiagnosticSetImpl *CurrentSet;
diff --git a/tools/libclang/CIndexDiagnostic.h b/tools/libclang/CIndexDiagnostic.h
index 31ae902eac4e..4347fb75f4a5 100644
--- a/tools/libclang/CIndexDiagnostic.h
+++ b/tools/libclang/CIndexDiagnostic.h
@@ -10,10 +10,11 @@
|* Implements the diagnostic functions of the Clang C interface. *|
|* *|
\*===----------------------------------------------------------------------===*/
-#ifndef LLVM_CLANG_CINDEX_DIAGNOSTIC_H
-#define LLVM_CLANG_CINDEX_DIAGNOSTIC_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CINDEXDIAGNOSTIC_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CINDEXDIAGNOSTIC_H
#include "clang-c/Index.h"
+#include <memory>
#include <vector>
#include <assert.h>
@@ -24,27 +25,25 @@ class StoredDiagnostic;
class CXDiagnosticImpl;
class CXDiagnosticSetImpl {
- std::vector<CXDiagnosticImpl *> Diagnostics;
+ std::vector<std::unique_ptr<CXDiagnosticImpl>> Diagnostics;
const bool IsExternallyManaged;
public:
CXDiagnosticSetImpl(bool isManaged = false)
: IsExternallyManaged(isManaged) {}
virtual ~CXDiagnosticSetImpl();
-
+
size_t getNumDiagnostics() const {
return Diagnostics.size();
}
CXDiagnosticImpl *getDiagnostic(unsigned i) const {
assert(i < getNumDiagnostics());
- return Diagnostics[i];
+ return Diagnostics[i].get();
}
-
- void appendDiagnostic(CXDiagnosticImpl *D) {
- Diagnostics.push_back(D);
- }
-
+
+ void appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D);
+
bool empty() const {
return Diagnostics.empty();
}
@@ -99,9 +98,9 @@ public:
protected:
CXDiagnosticImpl(Kind k) : K(k) {}
CXDiagnosticSetImpl ChildDiags;
-
- void append(CXDiagnosticImpl *D) {
- ChildDiags.appendDiagnostic(D);
+
+ void append(std::unique_ptr<CXDiagnosticImpl> D) {
+ ChildDiags.appendDiagnostic(std::move(D));
}
private:
@@ -163,4 +162,4 @@ CXDiagnosticSetImpl *lazyCreateDiags(CXTranslationUnit TU,
} // end namespace clang
-#endif // LLVM_CLANG_CINDEX_DIAGNOSTIC_H
+#endif
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index 25881c3ef062..d7b65852844e 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -15,9 +15,9 @@
#include "CXCursor.h"
#include "CXString.h"
#include "CXTranslationUnit.h"
+#include "clang/Frontend/ASTUnit.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Lex/PreprocessingRecord.h"
-#include "clang/Frontend/ASTUnit.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
index 95d8115a2eee..7a8dbd37d022 100644
--- a/tools/libclang/CIndexer.h
+++ b/tools/libclang/CIndexer.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CINDEXER_H
-#define LLVM_CLANG_CINDEXER_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CINDEXER_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CINDEXER_H
#include "clang-c/Index.h"
#include "llvm/ADT/StringRef.h"
diff --git a/tools/libclang/CLog.h b/tools/libclang/CLog.h
index e7419b71f83f..b9309ed19239 100644
--- a/tools/libclang/CLog.h
+++ b/tools/libclang/CLog.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBCLANG_CLOG_H
-#define LLVM_LIBCLANG_CLOG_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CLOG_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CLOG_H
#include "clang-c/Index.h"
#include "clang/Basic/LLVM.h"
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index e7ab63f7b99d..f1c3f4ca8b23 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -86,7 +86,7 @@ add_clang_library(libclang ${ENABLE_SHARED} ${ENABLE_STATIC}
${LIBS}
LINK_COMPONENTS
- BitReader
+ Core
Support
)
diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp
index 454703149c9d..9cc05ed4e127 100644
--- a/tools/libclang/CXComment.cpp
+++ b/tools/libclang/CXComment.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang-c/Index.h"
-#include "clang-c/Documentation.h"
#include "CXComment.h"
#include "CXCursor.h"
#include "CXString.h"
+#include "clang-c/Documentation.h"
#include "clang/AST/Decl.h"
#include "clang/Index/CommentToXML.h"
#include "llvm/ADT/StringExtras.h"
diff --git a/tools/libclang/CXComment.h b/tools/libclang/CXComment.h
index d9d2bdef4127..a937a8034636 100644
--- a/tools/libclang/CXComment.h
+++ b/tools/libclang/CXComment.h
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CXCOMMENT_H
-#define LLVM_CLANG_CXCOMMENT_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXCOMMENT_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CXCOMMENT_H
#include "CXTranslationUnit.h"
-#include "clang-c/Index.h"
#include "clang-c/Documentation.h"
+#include "clang-c/Index.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Comment.h"
#include "clang/Frontend/ASTUnit.h"
diff --git a/tools/libclang/CXCompilationDatabase.cpp b/tools/libclang/CXCompilationDatabase.cpp
index 51677e721035..1e4a2cd44aab 100644
--- a/tools/libclang/CXCompilationDatabase.cpp
+++ b/tools/libclang/CXCompilationDatabase.cpp
@@ -16,8 +16,8 @@ clang_CompilationDatabase_fromDirectory(const char *BuildDir,
std::string ErrorMsg;
CXCompilationDatabase_Error Err = CXCompilationDatabase_NoError;
- CompilationDatabase *db = CompilationDatabase::loadFromDirectory(BuildDir,
- ErrorMsg);
+ std::unique_ptr<CompilationDatabase> db =
+ CompilationDatabase::loadFromDirectory(BuildDir, ErrorMsg);
if (!db) {
fprintf(stderr, "LIBCLANG TOOLING ERROR: %s\n", ErrorMsg.c_str());
@@ -27,7 +27,7 @@ clang_CompilationDatabase_fromDirectory(const char *BuildDir,
if (ErrorCode)
*ErrorCode = Err;
- return db;
+ return db.release();
}
void
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 432190390b7f..7834181d4781 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -57,6 +57,7 @@ static CXCursorKind GetCursorKind(const Attr *A) {
case attr::CUDADevice: return CXCursor_CUDADeviceAttr;
case attr::CUDAGlobal: return CXCursor_CUDAGlobalAttr;
case attr::CUDAHost: return CXCursor_CUDAHostAttr;
+ case attr::CUDAShared: return CXCursor_CUDASharedAttr;
}
return CXCursor_UnexposedAttr;
@@ -228,6 +229,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXDefaultInitExprClass:
+ case Stmt::CXXFoldExprClass:
case Stmt::CXXStdInitializerListExprClass:
case Stmt::CXXScalarValueInitExprClass:
case Stmt::CXXUuidofExprClass:
@@ -468,6 +470,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::SubstNonTypeTemplateParmPackExprClass:
case Stmt::FunctionParmPackExprClass:
case Stmt::UnresolvedLookupExprClass:
+ case Stmt::TypoExprClass: // A typo could actually be a DeclRef or a MemberRef
K = CXCursor_DeclRefExpr;
break;
@@ -526,6 +529,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::OMPForDirectiveClass:
K = CXCursor_OMPForDirective;
break;
+ case Stmt::OMPForSimdDirectiveClass:
+ K = CXCursor_OMPForSimdDirective;
+ break;
case Stmt::OMPSectionsDirectiveClass:
K = CXCursor_OMPSectionsDirective;
break;
@@ -544,6 +550,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::OMPParallelForDirectiveClass:
K = CXCursor_OMPParallelForDirective;
break;
+ case Stmt::OMPParallelForSimdDirectiveClass:
+ K = CXCursor_OMPParallelForSimdDirective;
+ break;
case Stmt::OMPParallelSectionsDirectiveClass:
K = CXCursor_OMPParallelSectionsDirective;
break;
@@ -562,6 +571,18 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::OMPFlushDirectiveClass:
K = CXCursor_OMPFlushDirective;
break;
+ case Stmt::OMPOrderedDirectiveClass:
+ K = CXCursor_OMPOrderedDirective;
+ break;
+ case Stmt::OMPAtomicDirectiveClass:
+ K = CXCursor_OMPAtomicDirective;
+ break;
+ case Stmt::OMPTargetDirectiveClass:
+ K = CXCursor_OMPTargetDirective;
+ break;
+ case Stmt::OMPTeamsDirectiveClass:
+ K = CXCursor_OMPTeamsDirective;
+ break;
}
CXCursor C = { K, 0, { Parent, S, TU } };
@@ -1055,6 +1076,140 @@ CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i) {
return clang_getNullCursor();
}
+int clang_Cursor_getNumTemplateArguments(CXCursor C) {
+ if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+ return -1;
+ }
+
+ const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+ getCursorDecl(C));
+ if (!FD) {
+ return -1;
+ }
+
+ const FunctionTemplateSpecializationInfo* SpecInfo =
+ FD->getTemplateSpecializationInfo();
+ if (!SpecInfo) {
+ return -1;
+ }
+
+ return SpecInfo->TemplateArguments->size();
+}
+
+enum CXGetTemplateArgumentStatus {
+ /** \brief The operation completed successfully */
+ CXGetTemplateArgumentStatus_Success = 0,
+
+ /** \brief The specified cursor did not represent a FunctionDecl. */
+ CXGetTemplateArgumentStatus_CursorNotFunctionDecl = -1,
+
+ /** \brief The specified cursor was not castable to a FunctionDecl. */
+ CXGetTemplateArgumentStatus_BadFunctionDeclCast = -2,
+
+ /** \brief A NULL FunctionTemplateSpecializationInfo was retrieved. */
+ CXGetTemplateArgumentStatus_NullTemplSpecInfo = -3,
+
+ /** \brief An invalid (OOB) argument index was specified */
+ CXGetTemplateArgumentStatus_InvalidIndex = -4
+};
+
+static int clang_Cursor_getTemplateArgument(
+ CXCursor C, unsigned I, TemplateArgument *TA) {
+ if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+ return CXGetTemplateArgumentStatus_CursorNotFunctionDecl;
+ }
+
+ const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+ getCursorDecl(C));
+ if (!FD) {
+ return CXGetTemplateArgumentStatus_BadFunctionDeclCast;
+ }
+
+ const FunctionTemplateSpecializationInfo* SpecInfo =
+ FD->getTemplateSpecializationInfo();
+ if (!SpecInfo) {
+ return CXGetTemplateArgumentStatus_NullTemplSpecInfo;
+ }
+
+ if (I >= SpecInfo->TemplateArguments->size()) {
+ return CXGetTemplateArgumentStatus_InvalidIndex;
+ }
+
+ *TA = SpecInfo->TemplateArguments->get(I);
+ return 0;
+}
+
+enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(CXCursor C,
+ unsigned I) {
+ TemplateArgument TA;
+ if (clang_Cursor_getTemplateArgument(C, I, &TA)) {
+ return CXTemplateArgumentKind_Invalid;
+ }
+
+ switch (TA.getKind()) {
+ case TemplateArgument::Null: return CXTemplateArgumentKind_Null;
+ case TemplateArgument::Type: return CXTemplateArgumentKind_Type;
+ case TemplateArgument::Declaration:
+ return CXTemplateArgumentKind_Declaration;
+ case TemplateArgument::NullPtr: return CXTemplateArgumentKind_NullPtr;
+ case TemplateArgument::Integral: return CXTemplateArgumentKind_Integral;
+ case TemplateArgument::Template: return CXTemplateArgumentKind_Template;
+ case TemplateArgument::TemplateExpansion:
+ return CXTemplateArgumentKind_TemplateExpansion;
+ case TemplateArgument::Expression: return CXTemplateArgumentKind_Expression;
+ case TemplateArgument::Pack: return CXTemplateArgumentKind_Pack;
+ }
+
+ return CXTemplateArgumentKind_Invalid;
+}
+
+CXType clang_Cursor_getTemplateArgumentType(CXCursor C, unsigned I) {
+ TemplateArgument TA;
+ if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
+ CXGetTemplateArgumentStatus_Success) {
+ return cxtype::MakeCXType(QualType(), getCursorTU(C));
+ }
+
+ if (TA.getKind() != TemplateArgument::Type) {
+ return cxtype::MakeCXType(QualType(), getCursorTU(C));
+ }
+
+ return cxtype::MakeCXType(TA.getAsType(), getCursorTU(C));
+}
+
+long long clang_Cursor_getTemplateArgumentValue(CXCursor C, unsigned I) {
+ TemplateArgument TA;
+ if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
+ CXGetTemplateArgumentStatus_Success) {
+ assert(0 && "Unable to retrieve TemplateArgument");
+ return 0;
+ }
+
+ if (TA.getKind() != TemplateArgument::Integral) {
+ assert(0 && "Passed template argument is not Integral");
+ return 0;
+ }
+
+ return TA.getAsIntegral().getSExtValue();
+}
+
+unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C,
+ unsigned I) {
+ TemplateArgument TA;
+ if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
+ CXGetTemplateArgumentStatus_Success) {
+ assert(0 && "Unable to retrieve TemplateArgument");
+ return 0;
+ }
+
+ if (TA.getKind() != TemplateArgument::Integral) {
+ assert(0 && "Passed template argument is not Integral");
+ return 0;
+ }
+
+ return TA.getAsIntegral().getZExtValue();
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -1262,8 +1417,16 @@ int clang_Cursor_isDynamicCall(CXCursor C) {
if (!E)
return 0;
- if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E))
- return MsgE->getReceiverKind() == ObjCMessageExpr::Instance;
+ if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E)) {
+ if (MsgE->getReceiverKind() != ObjCMessageExpr::Instance)
+ return false;
+ if (auto *RecE = dyn_cast<ObjCMessageExpr>(
+ MsgE->getInstanceReceiver()->IgnoreParenCasts())) {
+ if (RecE->getMethodFamily() == OMF_alloc)
+ return false;
+ }
+ return true;
+ }
const MemberExpr *ME = nullptr;
if (isa<MemberExpr>(E))
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index fee3bac95379..931d112766ed 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CXCURSOR_H
-#define LLVM_CLANG_CXCURSOR_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXCURSOR_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CXCURSOR_H
#include "clang-c/Index.h"
#include "clang/Basic/SourceLocation.h"
diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp
index ddf374903a93..fe5599a3abc9 100644
--- a/tools/libclang/CXLoadedDiagnostic.cpp
+++ b/tools/libclang/CXLoadedDiagnostic.cpp
@@ -16,7 +16,8 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
-#include "clang/Frontend/SerializedDiagnosticPrinter.h"
+#include "clang/Frontend/SerializedDiagnosticReader.h"
+#include "clang/Frontend/SerializedDiagnostics.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -183,475 +184,207 @@ void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
// Deserialize diagnostics.
//===----------------------------------------------------------------------===//
-enum { MaxSupportedVersion = 2 };
-typedef SmallVector<uint64_t, 64> RecordData;
-enum LoadResult { Failure = 1, Success = 0 };
-enum StreamResult { Read_EndOfStream,
- Read_BlockBegin,
- Read_Failure,
- Read_Record,
- Read_BlockEnd };
-
namespace {
-class DiagLoader {
+class DiagLoader : serialized_diags::SerializedDiagnosticReader {
enum CXLoadDiag_Error *error;
CXString *errorString;
-
- void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
+ std::unique_ptr<CXLoadedDiagnosticSetImpl> TopDiags;
+ SmallVector<std::unique_ptr<CXLoadedDiagnostic>, 8> CurrentDiags;
+
+ std::error_code reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
if (error)
*error = code;
if (errorString)
*errorString = cxstring::createDup(err);
+ return serialized_diags::SDError::HandlerFailed;
}
- void reportInvalidFile(llvm::StringRef err) {
+ std::error_code reportInvalidFile(llvm::StringRef err) {
return reportBad(CXLoadDiag_InvalidFile, err);
}
- LoadResult readMetaBlock(llvm::BitstreamCursor &Stream);
-
- LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream,
- CXDiagnosticSetImpl &Diags,
- CXLoadedDiagnosticSetImpl &TopDiags);
-
- StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
- llvm::StringRef errorContext,
- unsigned &BlockOrRecordID,
- bool atTopLevel = false);
-
-
- LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
- Strings &strings, llvm::StringRef errorContext,
- RecordData &Record,
- StringRef Blob,
- bool allowEmptyString = false);
-
- LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
- const char *&RetStr,
- llvm::StringRef errorContext,
- RecordData &Record,
- StringRef Blob,
- bool allowEmptyString = false);
-
- LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags,
- RecordData &Record, unsigned RecStartIdx,
- CXSourceRange &SR);
-
- LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
- RecordData &Record, unsigned &offset,
- CXLoadedDiagnostic::Location &Loc);
-
-public:
- DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
- : error(e), errorString(es) {
- if (error)
- *error = CXLoadDiag_None;
- if (errorString)
- *errorString = cxstring::createEmpty();
- }
+ std::error_code readRange(const serialized_diags::Location &SDStart,
+ const serialized_diags::Location &SDEnd,
+ CXSourceRange &SR);
- CXDiagnosticSet load(const char *file);
-};
-}
+ std::error_code readLocation(const serialized_diags::Location &SDLoc,
+ CXLoadedDiagnostic::Location &LoadedLoc);
-CXDiagnosticSet DiagLoader::load(const char *file) {
- // Open the diagnostics file.
- std::string ErrStr;
- FileSystemOptions FO;
- FileManager FileMgr(FO);
+protected:
+ std::error_code visitStartOfDiagnostic() override;
+ std::error_code visitEndOfDiagnostic() override;
- std::unique_ptr<llvm::MemoryBuffer> Buffer;
- Buffer.reset(FileMgr.getBufferForFile(file));
+ std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override;
- if (!Buffer) {
- reportBad(CXLoadDiag_CannotLoad, ErrStr);
- return nullptr;
- }
+ std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override;
- llvm::BitstreamReader StreamFile;
- StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
- (const unsigned char *)Buffer->getBufferEnd());
-
- llvm::BitstreamCursor Stream;
- Stream.init(StreamFile);
-
- // Sniff for the signature.
- if (Stream.Read(8) != 'D' ||
- Stream.Read(8) != 'I' ||
- Stream.Read(8) != 'A' ||
- Stream.Read(8) != 'G') {
- reportBad(CXLoadDiag_InvalidFile,
- "Bad header in diagnostics file");
- return nullptr;
- }
+ std::error_code visitDiagnosticRecord(
+ unsigned Severity, const serialized_diags::Location &Location,
+ unsigned Category, unsigned Flag, StringRef Message) override;
- std::unique_ptr<CXLoadedDiagnosticSetImpl> Diags(
- new CXLoadedDiagnosticSetImpl());
-
- while (true) {
- unsigned BlockID = 0;
- StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level",
- BlockID, true);
- switch (Res) {
- case Read_EndOfStream:
- return (CXDiagnosticSet)Diags.release();
- case Read_Failure:
- return nullptr;
- case Read_Record:
- llvm_unreachable("Top-level does not have records");
- case Read_BlockEnd:
- continue;
- case Read_BlockBegin:
- break;
- }
-
- switch (BlockID) {
- case serialized_diags::BLOCK_META:
- if (readMetaBlock(Stream))
- return nullptr;
- break;
- case serialized_diags::BLOCK_DIAG:
- if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get()))
- return nullptr;
- break;
- default:
- if (!Stream.SkipBlock()) {
- reportInvalidFile("Malformed block at top-level of diagnostics file");
- return nullptr;
- }
- break;
- }
+ std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
+ unsigned Timestamp,
+ StringRef Name) override;
+
+ std::error_code visitFixitRecord(const serialized_diags::Location &Start,
+ const serialized_diags::Location &End,
+ StringRef CodeToInsert) override;
+
+ std::error_code
+ visitSourceRangeRecord(const serialized_diags::Location &Start,
+ const serialized_diags::Location &End) override;
+
+public:
+ DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
+ : SerializedDiagnosticReader(), error(e), errorString(es) {
+ if (error)
+ *error = CXLoadDiag_None;
+ if (errorString)
+ *errorString = cxstring::createEmpty();
}
+
+ CXDiagnosticSet load(const char *file);
+};
}
-StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
- llvm::StringRef errorContext,
- unsigned &blockOrRecordID,
- bool atTopLevel) {
-
- blockOrRecordID = 0;
-
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
-
- // Handle the top-level specially.
- if (atTopLevel) {
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- unsigned BlockID = Stream.ReadSubBlockID();
- if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
- if (Stream.ReadBlockInfoBlock()) {
- reportInvalidFile("Malformed BlockInfoBlock in diagnostics file");
- return Read_Failure;
- }
- continue;
- }
- blockOrRecordID = BlockID;
- return Read_BlockBegin;
- }
- reportInvalidFile("Only blocks can appear at the top of a "
- "diagnostic file");
- return Read_Failure;
- }
-
- switch ((llvm::bitc::FixedAbbrevIDs)Code) {
- case llvm::bitc::ENTER_SUBBLOCK:
- blockOrRecordID = Stream.ReadSubBlockID();
- return Read_BlockBegin;
-
- case llvm::bitc::END_BLOCK:
- if (Stream.ReadBlockEnd()) {
- reportInvalidFile("Cannot read end of block");
- return Read_Failure;
- }
- return Read_BlockEnd;
-
- case llvm::bitc::DEFINE_ABBREV:
- Stream.ReadAbbrevRecord();
- continue;
-
- case llvm::bitc::UNABBREV_RECORD:
- reportInvalidFile("Diagnostics file should have no unabbreviated "
- "records");
- return Read_Failure;
-
- default:
- // We found a record.
- blockOrRecordID = Code;
- return Read_Record;
+CXDiagnosticSet DiagLoader::load(const char *file) {
+ TopDiags = llvm::make_unique<CXLoadedDiagnosticSetImpl>();
+
+ std::error_code EC = readDiagnostics(file);
+ if (EC) {
+ switch (EC.value()) {
+ case static_cast<int>(serialized_diags::SDError::HandlerFailed):
+ // We've already reported the problem.
+ break;
+ case static_cast<int>(serialized_diags::SDError::CouldNotLoad):
+ reportBad(CXLoadDiag_CannotLoad, EC.message());
+ break;
+ default:
+ reportInvalidFile(EC.message());
+ break;
}
+ return 0;
}
-
- if (atTopLevel)
- return Read_EndOfStream;
-
- reportInvalidFile(Twine("Premature end of diagnostics file within ").str() +
- errorContext.str());
- return Read_Failure;
+
+ return (CXDiagnosticSet)TopDiags.release();
}
-LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
- if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
- reportInvalidFile("Malformed metadata block");
- return Failure;
- }
-
- bool versionChecked = false;
-
- while (true) {
- unsigned blockOrCode = 0;
- StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block",
- blockOrCode);
-
- switch(Res) {
- case Read_EndOfStream:
- llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock");
- case Read_Failure:
- return Failure;
- case Read_Record:
- break;
- case Read_BlockBegin:
- if (Stream.SkipBlock()) {
- reportInvalidFile("Malformed metadata block");
- return Failure;
- }
- case Read_BlockEnd:
- if (!versionChecked) {
- reportInvalidFile("Diagnostics file does not contain version"
- " information");
- return Failure;
- }
- return Success;
- }
-
- RecordData Record;
- unsigned recordID = Stream.readRecord(blockOrCode, Record);
-
- if (recordID == serialized_diags::RECORD_VERSION) {
- if (Record.size() < 1) {
- reportInvalidFile("malformed VERSION identifier in diagnostics file");
- return Failure;
- }
- if (Record[0] > MaxSupportedVersion) {
- reportInvalidFile("diagnostics file is a newer version than the one "
- "supported");
- return Failure;
- }
- versionChecked = true;
- }
+std::error_code
+DiagLoader::readLocation(const serialized_diags::Location &SDLoc,
+ CXLoadedDiagnostic::Location &LoadedLoc) {
+ unsigned FileID = SDLoc.FileID;
+ if (FileID == 0)
+ LoadedLoc.file = nullptr;
+ else {
+ LoadedLoc.file = const_cast<FileEntry *>(TopDiags->Files[FileID]);
+ if (!LoadedLoc.file)
+ return reportInvalidFile("Corrupted file entry in source location");
}
+ LoadedLoc.line = SDLoc.Line;
+ LoadedLoc.column = SDLoc.Col;
+ LoadedLoc.offset = SDLoc.Offset;
+ return std::error_code();
}
-LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
- const char *&RetStr,
- llvm::StringRef errorContext,
- RecordData &Record,
- StringRef Blob,
- bool allowEmptyString) {
+std::error_code
+DiagLoader::readRange(const serialized_diags::Location &SDStart,
+ const serialized_diags::Location &SDEnd,
+ CXSourceRange &SR) {
+ CXLoadedDiagnostic::Location *Start, *End;
+ Start = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>();
+ End = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>();
+
+ std::error_code EC;
+ if ((EC = readLocation(SDStart, *Start)))
+ return EC;
+ if ((EC = readLocation(SDEnd, *End)))
+ return EC;
- // Basic buffer overflow check.
- if (Blob.size() > 65536) {
- reportInvalidFile(std::string("Out-of-bounds string in ") +
- std::string(errorContext));
- return Failure;
- }
+ CXSourceLocation startLoc = makeLocation(Start);
+ CXSourceLocation endLoc = makeLocation(End);
+ SR = clang_getRange(startLoc, endLoc);
+ return std::error_code();
+}
- if (allowEmptyString && Record.size() >= 1 && Blob.size() == 0) {
- RetStr = "";
- return Success;
- }
-
- if (Record.size() < 1 || Blob.size() == 0) {
- reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
- + std::string(" entry"));
- return Failure;
- }
-
- RetStr = TopDiags.copyString(Blob);
- return Success;
+std::error_code DiagLoader::visitStartOfDiagnostic() {
+ CurrentDiags.push_back(llvm::make_unique<CXLoadedDiagnostic>());
+ return std::error_code();
}
-LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
- Strings &strings,
- llvm::StringRef errorContext,
- RecordData &Record,
- StringRef Blob,
- bool allowEmptyString) {
- const char *RetStr;
- if (readString(TopDiags, RetStr, errorContext, Record, Blob,
- allowEmptyString))
- return Failure;
- strings[Record[0]] = RetStr;
- return Success;
+std::error_code DiagLoader::visitEndOfDiagnostic() {
+ auto D = CurrentDiags.pop_back_val();
+ if (CurrentDiags.empty())
+ TopDiags->appendDiagnostic(std::move(D));
+ else
+ CurrentDiags.back()->getChildDiagnostics().appendDiagnostic(std::move(D));
+ return std::error_code();
}
-LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
- RecordData &Record, unsigned &offset,
- CXLoadedDiagnostic::Location &Loc) {
- if (Record.size() < offset + 3) {
- reportInvalidFile("Corrupted source location");
- return Failure;
- }
-
- unsigned fileID = Record[offset++];
- if (fileID == 0) {
- // Sentinel value.
- Loc.file = nullptr;
- Loc.line = 0;
- Loc.column = 0;
- Loc.offset = 0;
- return Success;
- }
+std::error_code DiagLoader::visitCategoryRecord(unsigned ID, StringRef Name) {
+ // FIXME: Why do we care about long strings?
+ if (Name.size() > 65536)
+ return reportInvalidFile("Out-of-bounds string in category");
+ TopDiags->Categories[ID] = TopDiags->copyString(Name);
+ return std::error_code();
+}
- const FileEntry *FE = TopDiags.Files[fileID];
- if (!FE) {
- reportInvalidFile("Corrupted file entry in source location");
- return Failure;
- }
- Loc.file = const_cast<FileEntry *>(FE);
- Loc.line = Record[offset++];
- Loc.column = Record[offset++];
- Loc.offset = Record[offset++];
- return Success;
+std::error_code DiagLoader::visitDiagFlagRecord(unsigned ID, StringRef Name) {
+ // FIXME: Why do we care about long strings?
+ if (Name.size() > 65536)
+ return reportInvalidFile("Out-of-bounds string in warning flag");
+ TopDiags->WarningFlags[ID] = TopDiags->copyString(Name);
+ return std::error_code();
}
-LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
- RecordData &Record,
- unsigned int RecStartIdx,
- CXSourceRange &SR) {
- CXLoadedDiagnostic::Location *Start, *End;
- Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
- End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
-
- if (readLocation(TopDiags, Record, RecStartIdx, *Start))
- return Failure;
- if (readLocation(TopDiags, Record, RecStartIdx, *End))
- return Failure;
-
- CXSourceLocation startLoc = makeLocation(Start);
- CXSourceLocation endLoc = makeLocation(End);
- SR = clang_getRange(startLoc, endLoc);
- return Success;
+std::error_code DiagLoader::visitFilenameRecord(unsigned ID, unsigned Size,
+ unsigned Timestamp,
+ StringRef Name) {
+ // FIXME: Why do we care about long strings?
+ if (Name.size() > 65536)
+ return reportInvalidFile("Out-of-bounds string in filename");
+ TopDiags->FileNames[ID] = TopDiags->copyString(Name);
+ TopDiags->Files[ID] =
+ TopDiags->FakeFiles.getVirtualFile(Name, Size, Timestamp);
+ return std::error_code();
}
-LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
- CXDiagnosticSetImpl &Diags,
- CXLoadedDiagnosticSetImpl &TopDiags){
+std::error_code
+DiagLoader::visitSourceRangeRecord(const serialized_diags::Location &Start,
+ const serialized_diags::Location &End) {
+ CXSourceRange SR;
+ if (std::error_code EC = readRange(Start, End, SR))
+ return EC;
+ CurrentDiags.back()->Ranges.push_back(SR);
+ return std::error_code();
+}
- if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
- reportInvalidFile("malformed diagnostic block");
- return Failure;
- }
+std::error_code
+DiagLoader::visitFixitRecord(const serialized_diags::Location &Start,
+ const serialized_diags::Location &End,
+ StringRef CodeToInsert) {
+ CXSourceRange SR;
+ if (std::error_code EC = readRange(Start, End, SR))
+ return EC;
+ // FIXME: Why do we care about long strings?
+ if (CodeToInsert.size() > 65536)
+ return reportInvalidFile("Out-of-bounds string in FIXIT");
+ CurrentDiags.back()->FixIts.push_back(
+ std::make_pair(SR, TopDiags->copyString(CodeToInsert)));
+ return std::error_code();
+}
- std::unique_ptr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
- RecordData Record;
-
- while (true) {
- unsigned blockOrCode = 0;
- StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
- blockOrCode);
- switch (Res) {
- case Read_EndOfStream:
- llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
- case Read_Failure:
- return Failure;
- case Read_BlockBegin: {
- // The only blocks we care about are subdiagnostics.
- if (blockOrCode != serialized_diags::BLOCK_DIAG) {
- if (!Stream.SkipBlock()) {
- reportInvalidFile("Invalid subblock in Diagnostics block");
- return Failure;
- }
- } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
- TopDiags)) {
- return Failure;
- }
-
- continue;
- }
- case Read_BlockEnd:
- Diags.appendDiagnostic(D.release());
- return Success;
- case Read_Record:
- break;
- }
-
- // Read the record.
- Record.clear();
- StringRef Blob;
- unsigned recID = Stream.readRecord(blockOrCode, Record, &Blob);
-
- if (recID < serialized_diags::RECORD_FIRST ||
- recID > serialized_diags::RECORD_LAST)
- continue;
-
- switch ((serialized_diags::RecordIDs)recID) {
- case serialized_diags::RECORD_VERSION:
- continue;
- case serialized_diags::RECORD_CATEGORY:
- if (readString(TopDiags, TopDiags.Categories, "category", Record,
- Blob, /* allowEmptyString */ true))
- return Failure;
- continue;
-
- case serialized_diags::RECORD_DIAG_FLAG:
- if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
- Blob))
- return Failure;
- continue;
-
- case serialized_diags::RECORD_FILENAME: {
- if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
- Blob))
- return Failure;
-
- if (Record.size() < 3) {
- reportInvalidFile("Invalid file entry");
- return Failure;
- }
-
- const FileEntry *FE =
- TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
- /* size */ Record[1],
- /* time */ Record[2]);
-
- TopDiags.Files[Record[0]] = FE;
- continue;
- }
-
- case serialized_diags::RECORD_SOURCE_RANGE: {
- CXSourceRange SR;
- if (readRange(TopDiags, Record, 0, SR))
- return Failure;
- D->Ranges.push_back(SR);
- continue;
- }
-
- case serialized_diags::RECORD_FIXIT: {
- CXSourceRange SR;
- if (readRange(TopDiags, Record, 0, SR))
- return Failure;
- const char *RetStr;
- if (readString(TopDiags, RetStr, "FIXIT", Record, Blob,
- /* allowEmptyString */ true))
- return Failure;
- D->FixIts.push_back(std::make_pair(SR, RetStr));
- continue;
- }
-
- case serialized_diags::RECORD_DIAG: {
- D->severity = Record[0];
- unsigned offset = 1;
- if (readLocation(TopDiags, Record, offset, D->DiagLoc))
- return Failure;
- D->category = Record[offset++];
- unsigned diagFlag = Record[offset++];
- D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
- D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
- D->Spelling = TopDiags.copyString(Blob);
- continue;
- }
- }
- }
+std::error_code DiagLoader::visitDiagnosticRecord(
+ unsigned Severity, const serialized_diags::Location &Location,
+ unsigned Category, unsigned Flag, StringRef Message) {
+ CXLoadedDiagnostic &D = *CurrentDiags.back();
+ D.severity = Severity;
+ if (std::error_code EC = readLocation(Location, D.DiagLoc))
+ return EC;
+ D.category = Category;
+ D.DiagOption = Flag ? TopDiags->WarningFlags[Flag] : "";
+ D.CategoryText = Category ? TopDiags->Categories[Category] : "";
+ D.Spelling = TopDiags->copyString(Message);
+ return std::error_code();
}
extern "C" {
diff --git a/tools/libclang/CXLoadedDiagnostic.h b/tools/libclang/CXLoadedDiagnostic.h
index c281f9be3e87..54261be6cf46 100644
--- a/tools/libclang/CXLoadedDiagnostic.h
+++ b/tools/libclang/CXLoadedDiagnostic.h
@@ -11,8 +11,8 @@
|* *|
\*===----------------------------------------------------------------------===*/
-#ifndef LLVM_CLANG_CINDEX_LOADED_DIAGNOSTIC_H
-#define LLVM_CLANG_CINDEX_LOADED_DIAGNOSTIC_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXLOADEDDIAGNOSTIC_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CXLOADEDDIAGNOSTIC_H
#include "CIndexDiagnostic.h"
#include "llvm/ADT/StringRef.h"
diff --git a/tools/libclang/CXSourceLocation.h b/tools/libclang/CXSourceLocation.h
index f97ac1f3aff8..f0b3f4954919 100644
--- a/tools/libclang/CXSourceLocation.h
+++ b/tools/libclang/CXSourceLocation.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CXSOURCELOCATION_H
-#define LLVM_CLANG_CXSOURCELOCATION_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXSOURCELOCATION_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CXSOURCELOCATION_H
#include "clang-c/Index.h"
#include "clang/AST/ASTContext.h"
diff --git a/tools/libclang/CXString.h b/tools/libclang/CXString.h
index ed3ed4ad2d52..f6b46f76a443 100644
--- a/tools/libclang/CXString.h
+++ b/tools/libclang/CXString.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CXSTRING_H
-#define LLVM_CLANG_CXSTRING_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXSTRING_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CXSTRING_H
#include "clang-c/Index.h"
#include "clang/Basic/LLVM.h"
diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h
index d86ed2b8d342..6022c9dab1b5 100644
--- a/tools/libclang/CXTranslationUnit.h
+++ b/tools/libclang/CXTranslationUnit.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CXTRANSLATIONUNIT_H
-#define LLVM_CLANG_CXTRANSLATIONUNIT_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXTRANSLATIONUNIT_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CXTRANSLATIONUNIT_H
#include "CLog.h"
#include "CXString.h"
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index fe45899ad548..81cff5abb4f5 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -520,6 +520,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(X86FastCall);
TCALLINGCONV(X86ThisCall);
TCALLINGCONV(X86Pascal);
+ TCALLINGCONV(X86VectorCall);
TCALLINGCONV(X86_64Win64);
TCALLINGCONV(X86_64SysV);
TCALLINGCONV(AAPCS);
diff --git a/tools/libclang/CXType.h b/tools/libclang/CXType.h
index 7660bebf041b..941cc0a9fd7e 100644
--- a/tools/libclang/CXType.h
+++ b/tools/libclang/CXType.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_CXTYPES_H
-#define LLVM_CLANG_CXTYPES_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXTYPE_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CXTYPE_H
#include "clang-c/Index.h"
#include "clang/AST/Type.h"
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
index c4ec7b693766..1b2a922204f8 100644
--- a/tools/libclang/CursorVisitor.h
+++ b/tools/libclang/CursorVisitor.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LIBCLANG_CURSORVISITOR_H
-#define LLVM_CLANG_LIBCLANG_CURSORVISITOR_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CURSORVISITOR_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_CURSORVISITOR_H
#include "CXCursor.h"
#include "CXTranslationUnit.h"
diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp
index 7dc53a627533..5539971f04a7 100644
--- a/tools/libclang/IndexBody.cpp
+++ b/tools/libclang/IndexBody.cpp
@@ -150,7 +150,7 @@ public:
}
bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C) {
- if (C->capturesThis())
+ if (C->capturesThis() || C->capturesVLAType())
return true;
if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols())
diff --git a/tools/libclang/IndexTypeSourceInfo.cpp b/tools/libclang/IndexTypeSourceInfo.cpp
index f13c0aff0da3..706870e514b8 100644
--- a/tools/libclang/IndexTypeSourceInfo.cpp
+++ b/tools/libclang/IndexTypeSourceInfo.cpp
@@ -129,6 +129,7 @@ void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
switch (NNS.getNestedNameSpecifier()->getKind()) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
break;
case NestedNameSpecifier::Namespace:
diff --git a/tools/libclang/Index_Internal.h b/tools/libclang/Index_Internal.h
index 2d42cb83c970..98f069c88738 100644
--- a/tools/libclang/Index_Internal.h
+++ b/tools/libclang/Index_Internal.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBCLANG_INDEX_INTERNAL_H
-#define LLVM_LIBCLANG_INDEX_INTERNAL_H
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_INDEX_INTERNAL_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_INDEX_INTERNAL_H
#include "clang-c/Index.h"
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index 58af61811bf5..20f4474a1ee8 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -414,8 +414,8 @@ public:
: IndexCtx(clientData, indexCallbacks, indexOptions, cxTU),
CXTU(cxTU), SKData(skData) { }
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override {
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override {
PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
if (!PPOpts.ImplicitPCHInclude.empty()) {
@@ -425,17 +425,16 @@ public:
IndexCtx.setASTContext(CI.getASTContext());
Preprocessor &PP = CI.getPreprocessor();
- PP.addPPCallbacks(new IndexPPCallbacks(PP, IndexCtx));
+ PP.addPPCallbacks(llvm::make_unique<IndexPPCallbacks>(PP, IndexCtx));
IndexCtx.setPreprocessor(PP);
if (SKData) {
- PPConditionalDirectiveRecord *
- PPRec = new PPConditionalDirectiveRecord(PP.getSourceManager());
- PP.addPPCallbacks(PPRec);
- SKCtrl.reset(new TUSkipBodyControl(*SKData, *PPRec, PP));
+ auto *PPRec = new PPConditionalDirectiveRecord(PP.getSourceManager());
+ PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
+ SKCtrl = llvm::make_unique<TUSkipBodyControl>(*SKData, *PPRec, PP);
}
- return new IndexingConsumer(IndexCtx, SKCtrl.get());
+ return llvm::make_unique<IndexingConsumer>(IndexCtx, SKCtrl.get());
}
void EndSourceFileAction() override {
@@ -576,10 +575,10 @@ static void clang_indexSourceFile_Impl(void *UserData) {
BufOwner.get());
for (auto &UF : ITUI->unsaved_files) {
- llvm::MemoryBuffer *MB =
+ std::unique_ptr<llvm::MemoryBuffer> MB =
llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename);
- BufOwner->push_back(std::unique_ptr<llvm::MemoryBuffer>(MB));
- CInvok->getPreprocessorOpts().addRemappedFile(UF.Filename, MB);
+ CInvok->getPreprocessorOpts().addRemappedFile(UF.Filename, MB.get());
+ BufOwner->push_back(std::move(MB));
}
// Since libclang is primarily used by batch tools dealing with
diff --git a/tools/libclang/IndexingContext.h b/tools/libclang/IndexingContext.h
index c3851cd7e95e..31fddfb09cd4 100644
--- a/tools/libclang/IndexingContext.h
+++ b/tools/libclang/IndexingContext.h
@@ -7,6 +7,9 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_LIBCLANG_INDEXINGCONTEXT_H
+#define LLVM_CLANG_TOOLS_LIBCLANG_INDEXINGCONTEXT_H
+
#include "CXCursor.h"
#include "Index_Internal.h"
#include "clang/AST/DeclGroup.h"
@@ -517,3 +520,5 @@ inline T *ScratchAlloc::allocate() {
}
}} // end clang::cxindex
+
+#endif
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index db3d4f86244a..97f663cde478 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -16,11 +16,11 @@ LINK_LIBS_IN_SHARED = 1
SHARED_LIBRARY = 1
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
+LINK_COMPONENTS := AsmParser BitReader Core MC MCParser Option Support
USEDLIBS = clangIndex.a clangARCMigrate.a \
clangRewriteFrontend.a \
clangFormat.a \
- clangTooling.a \
+ clangTooling.a clangToolingCore.a \
clangFrontend.a clangDriver.a \
clangSerialization.a \
clangParse.a clangSema.a \
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 48eec2576743..fa2c0e70bf32 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -7,8 +7,14 @@ clang_CXXMethod_isPureVirtual
clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
clang_Cursor_getArgument
+clang_Cursor_getNumTemplateArguments
+clang_Cursor_getTemplateArgumentKind
+clang_Cursor_getTemplateArgumentType
+clang_Cursor_getTemplateArgumentValue
+clang_Cursor_getTemplateArgumentUnsignedValue
clang_Cursor_getBriefCommentText
clang_Cursor_getCommentRange
+clang_Cursor_getMangling
clang_Cursor_getParsedComment
clang_Cursor_getRawCommentText
clang_Cursor_getNumArguments
@@ -24,6 +30,8 @@ clang_Cursor_isNull
clang_Cursor_isObjCOptional
clang_Cursor_isVariadic
clang_Cursor_getModule
+clang_Cursor_getStorageClass
+clang_File_isEqual
clang_Module_getASTFile
clang_Module_getParent
clang_Module_getName
diff --git a/tools/scan-build/c++-analyzer.bat b/tools/scan-build/c++-analyzer.bat
new file mode 100644
index 000000000000..69f048a91671
--- /dev/null
+++ b/tools/scan-build/c++-analyzer.bat
@@ -0,0 +1 @@
+perl -S c++-analyzer %*
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index 4c8f6482a153..9de38d42aafa 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -42,9 +42,17 @@ my $DefaultCCompiler;
my $DefaultCXXCompiler;
my $IsCXX;
+# If on OSX, use xcrun to determine the SDK root.
+my $UseXCRUN = 0;
+
if (`uname -a` =~ m/Darwin/) {
$DefaultCCompiler = 'clang';
$DefaultCXXCompiler = 'clang++';
+ # Older versions of OSX do not have xcrun to
+ # query the SDK location.
+ if (-x "/usr/bin/xcrun") {
+ $UseXCRUN = 1;
+ }
} else {
$DefaultCCompiler = 'gcc';
$DefaultCXXCompiler = 'g++';
@@ -478,6 +486,7 @@ my $HtmlDir = $ENV{'CCC_ANALYZER_HTML'};
my %DisabledArchs = ('ppc' => 1, 'ppc64' => 1);
my %ArchsSeen;
my $HadArch = 0;
+my $HasSDK = 0;
# Process the arguments.
foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
@@ -500,6 +509,12 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
next;
}
+ # On OSX/iOS, record if an SDK path was specified. This
+ # is innocuous for other platforms, so the check just happens.
+ if ($Arg =~ /^-isysroot/) {
+ $HasSDK = 1;
+ }
+
# Options with possible arguments that should pass through to compiler.
if (defined $CompileOptionMap{$ArgKey}) {
my $Cnt = $CompileOptionMap{$ArgKey};
@@ -644,6 +659,15 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
}
}
+# If we are on OSX and have an installation where the
+# default SDK is inferred by xcrun use xcrun to infer
+# the SDK.
+if (not $HasSDK and $UseXCRUN) {
+ my $sdk = `/usr/bin/xcrun --show-sdk-path -sdk macosx`;
+ chomp $sdk;
+ push @CompileOpts, "-isysroot", $sdk;
+}
+
if ($Action eq 'compile' or $Action eq 'link') {
my @Archs = keys %ArchsSeen;
# Skip the file if we don't support the architectures specified.
diff --git a/tools/scan-build/ccc-analyzer.bat b/tools/scan-build/ccc-analyzer.bat
new file mode 100644
index 000000000000..2a85376eb82b
--- /dev/null
+++ b/tools/scan-build/ccc-analyzer.bat
@@ -0,0 +1 @@
+perl -S ccc-analyzer %*
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index 153be2dca1c9..d52d8f5f655c 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -1056,7 +1056,7 @@ sub RunBuildCommand {
shift @$Args;
unshift @$Args, $CXXAnalyzer;
}
- elsif ($Cmd eq "make" or $Cmd eq "gmake") {
+ elsif ($Cmd eq "make" or $Cmd eq "gmake" or $Cmd eq "mingw32-make") {
AddIfNotPresent($Args, "CC=$CCAnalyzer");
AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
if ($IgnoreErrors) {
@@ -1221,104 +1221,104 @@ LOADING CHECKERS:
-load-plugin [plugin library]
ENDTEXT
-# Query clang for list of checkers that are enabled.
-
-# create a list to load the plugins via the 'Xclang' command line
-# argument
-my @PluginLoadCommandline_xclang;
-foreach my $param ( @PluginsToLoad ) {
- push ( @PluginLoadCommandline_xclang, "-Xclang" );
- push ( @PluginLoadCommandline_xclang, $param );
-}
-my %EnabledCheckers;
-foreach my $lang ("c", "objective-c", "objective-c++", "c++") {
- pipe(FROM_CHILD, TO_PARENT);
- my $pid = fork();
- if ($pid == 0) {
- close FROM_CHILD;
- open(STDOUT,">&", \*TO_PARENT);
- open(STDERR,">&", \*TO_PARENT);
- exec $Clang, ( @PluginLoadCommandline_xclang, '--analyze', '-x', $lang, '-', '-###');
- }
- close(TO_PARENT);
- while(<FROM_CHILD>) {
- foreach my $val (split /\s+/) {
- $val =~ s/\"//g;
- if ($val =~ /-analyzer-checker\=([^\s]+)/) {
- $EnabledCheckers{$1} = 1;
+ # Query clang for list of checkers that are enabled.
+
+ # create a list to load the plugins via the 'Xclang' command line
+ # argument
+ my @PluginLoadCommandline_xclang;
+ foreach my $param ( @PluginsToLoad ) {
+ push ( @PluginLoadCommandline_xclang, "-Xclang" );
+ push ( @PluginLoadCommandline_xclang, $param );
+ }
+ my %EnabledCheckers;
+ foreach my $lang ("c", "objective-c", "objective-c++", "c++") {
+ pipe(FROM_CHILD, TO_PARENT);
+ my $pid = fork();
+ if ($pid == 0) {
+ close FROM_CHILD;
+ open(STDOUT,">&", \*TO_PARENT);
+ open(STDERR,">&", \*TO_PARENT);
+ exec $Clang, ( @PluginLoadCommandline_xclang, '--analyze', '-x', $lang, '-', '-###');
+ }
+ close(TO_PARENT);
+ while(<FROM_CHILD>) {
+ foreach my $val (split /\s+/) {
+ $val =~ s/\"//g;
+ if ($val =~ /-analyzer-checker\=([^\s]+)/) {
+ $EnabledCheckers{$1} = 1;
+ }
}
}
- }
- waitpid($pid,0);
- close(FROM_CHILD);
-}
-
-# Query clang for complete list of checkers.
-if (defined $Clang && -x $Clang) {
- pipe(FROM_CHILD, TO_PARENT);
- my $pid = fork();
- if ($pid == 0) {
- close FROM_CHILD;
- open(STDOUT,">&", \*TO_PARENT);
- open(STDERR,">&", \*TO_PARENT);
- exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
- }
- close(TO_PARENT);
- my $foundCheckers = 0;
- while(<FROM_CHILD>) {
- if (/CHECKERS:/) {
- $foundCheckers = 1;
- last;
+ waitpid($pid,0);
+ close(FROM_CHILD);
+ }
+
+ # Query clang for complete list of checkers.
+ if (defined $Clang && -x $Clang) {
+ pipe(FROM_CHILD, TO_PARENT);
+ my $pid = fork();
+ if ($pid == 0) {
+ close FROM_CHILD;
+ open(STDOUT,">&", \*TO_PARENT);
+ open(STDERR,">&", \*TO_PARENT);
+ exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
}
- }
- if (!$foundCheckers) {
- print " *** Could not query Clang for the list of available checkers.";
- }
- else {
- print("\nAVAILABLE CHECKERS:\n\n");
- my $skip = 0;
+ close(TO_PARENT);
+ my $foundCheckers = 0;
while(<FROM_CHILD>) {
- if (/experimental/) {
- $skip = 1;
- next;
- }
- if ($skip) {
- next if (!/^\s\s[^\s]/);
- $skip = 0;
+ if (/CHECKERS:/) {
+ $foundCheckers = 1;
+ last;
}
- s/^\s\s//;
- if (/^([^\s]+)/) {
- # Is the checker enabled?
- my $checker = $1;
- my $enabled = 0;
- my $aggregate = "";
- foreach my $domain (split /\./, $checker) {
- $aggregate .= $domain;
- if ($EnabledCheckers{$aggregate}) {
- $enabled =1;
- last;
- }
- # append a dot, if an additional domain is added in the next iteration
- $aggregate .= ".";
+ }
+ if (!$foundCheckers) {
+ print " *** Could not query Clang for the list of available checkers.";
+ }
+ else {
+ print("\nAVAILABLE CHECKERS:\n\n");
+ my $skip = 0;
+ while(<FROM_CHILD>) {
+ if (/experimental/) {
+ $skip = 1;
+ next;
+ }
+ if ($skip) {
+ next if (!/^\s\s[^\s]/);
+ $skip = 0;
}
+ s/^\s\s//;
+ if (/^([^\s]+)/) {
+ # Is the checker enabled?
+ my $checker = $1;
+ my $enabled = 0;
+ my $aggregate = "";
+ foreach my $domain (split /\./, $checker) {
+ $aggregate .= $domain;
+ if ($EnabledCheckers{$aggregate}) {
+ $enabled =1;
+ last;
+ }
+ # append a dot, if an additional domain is added in the next iteration
+ $aggregate .= ".";
+ }
- if ($enabled) {
- print " + ";
+ if ($enabled) {
+ print " + ";
+ }
+ else {
+ print " ";
+ }
}
else {
print " ";
}
+ print $_;
}
- else {
- print " ";
- }
- print $_;
+ print "\nNOTE: \"+\" indicates that an analysis is enabled by default.\n"
}
- print "\nNOTE: \"+\" indicates that an analysis is enabled by default.\n"
+ waitpid($pid,0);
+ close(FROM_CHILD);
}
- waitpid($pid,0);
- close(FROM_CHILD);
-}
print <<ENDTEXT
@@ -1533,6 +1533,7 @@ while (@ARGV) {
}
if ($arg eq "-no-failure-reports") {
+ shift @ARGV;
$ENV{"CCC_REPORT_FAILURES"} = 0;
next;
}
diff --git a/unittests/AST/ASTTypeTraitsTest.cpp b/unittests/AST/ASTTypeTraitsTest.cpp
index 0e73f7616923..eeb01ccad1df 100644
--- a/unittests/AST/ASTTypeTraitsTest.cpp
+++ b/unittests/AST/ASTTypeTraitsTest.cpp
@@ -26,6 +26,12 @@ template <typename T> static ASTNodeKind DNT() {
return ASTNodeKind::getFromNodeKind<T>();
}
+TEST(ASTNodeKind, IsNone) {
+ EXPECT_TRUE(ASTNodeKind().isNone());
+ EXPECT_FALSE(DNT<Decl>().isNone());
+ EXPECT_FALSE(DNT<VarDecl>().isNone());
+}
+
TEST(ASTNodeKind, Bases) {
EXPECT_TRUE(DNT<Decl>().isBaseOf(DNT<VarDecl>()));
EXPECT_FALSE(DNT<Decl>().isSame(DNT<VarDecl>()));
@@ -60,6 +66,39 @@ TEST(ASTNodeKind, DiffBase) {
EXPECT_FALSE(DNT<Type>().isSame(DNT<QualType>()));
}
+TEST(ASTNodeKind, MostDerivedType) {
+ EXPECT_TRUE(DNT<BinaryOperator>().isSame(
+ ASTNodeKind::getMostDerivedType(DNT<Expr>(), DNT<BinaryOperator>())));
+ EXPECT_TRUE(DNT<BinaryOperator>().isSame(
+ ASTNodeKind::getMostDerivedType(DNT<BinaryOperator>(), DNT<Expr>())));
+ EXPECT_TRUE(DNT<VarDecl>().isSame(
+ ASTNodeKind::getMostDerivedType(DNT<VarDecl>(), DNT<VarDecl>())));
+
+ // Not related. Returns nothing.
+ EXPECT_TRUE(
+ ASTNodeKind::getMostDerivedType(DNT<IfStmt>(), DNT<VarDecl>()).isNone());
+ EXPECT_TRUE(ASTNodeKind::getMostDerivedType(DNT<IfStmt>(),
+ DNT<BinaryOperator>()).isNone());
+}
+
+TEST(ASTNodeKind, MostDerivedCommonAncestor) {
+ EXPECT_TRUE(DNT<Expr>().isSame(ASTNodeKind::getMostDerivedCommonAncestor(
+ DNT<Expr>(), DNT<BinaryOperator>())));
+ EXPECT_TRUE(DNT<Expr>().isSame(ASTNodeKind::getMostDerivedCommonAncestor(
+ DNT<BinaryOperator>(), DNT<Expr>())));
+ EXPECT_TRUE(DNT<VarDecl>().isSame(ASTNodeKind::getMostDerivedCommonAncestor(
+ DNT<VarDecl>(), DNT<VarDecl>())));
+
+ // A little related. Returns the ancestor.
+ EXPECT_TRUE(
+ DNT<NamedDecl>().isSame(ASTNodeKind::getMostDerivedCommonAncestor(
+ DNT<CXXMethodDecl>(), DNT<RecordDecl>())));
+
+ // Not related. Returns nothing.
+ EXPECT_TRUE(ASTNodeKind::getMostDerivedCommonAncestor(
+ DNT<IfStmt>(), DNT<VarDecl>()).isNone());
+}
+
struct Foo {};
TEST(ASTNodeKind, UnknownKind) {
diff --git a/unittests/AST/ASTVectorTest.cpp b/unittests/AST/ASTVectorTest.cpp
index ce6d0a07ce8b..55c06d0071fe 100644
--- a/unittests/AST/ASTVectorTest.cpp
+++ b/unittests/AST/ASTVectorTest.cpp
@@ -14,11 +14,79 @@
#include "llvm/Support/Compiler.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTVector.h"
+#include "clang/Basic/Builtins.h"
+#include "gtest/gtest.h"
using namespace clang;
-LLVM_ATTRIBUTE_UNUSED void CompileTest() {
- ASTContext *C = nullptr;
+namespace clang {
+namespace ast {
+
+namespace {
+class ASTVectorTest : public ::testing::Test {
+protected:
+ ASTVectorTest()
+ : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+ Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr), Idents(LangOpts, nullptr),
+ Ctxt(LangOpts, SourceMgr, Idents, Sels, Builtins) {}
+
+ FileSystemOptions FileMgrOpts;
+ FileManager FileMgr;
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+ DiagnosticsEngine Diags;
+ SourceManager SourceMgr;
+ LangOptions LangOpts;
+ IdentifierTable Idents;
+ SelectorTable Sels;
+ Builtin::Context Builtins;
+ ASTContext Ctxt;
+};
+} // unnamed namespace
+
+TEST_F(ASTVectorTest, Compile) {
ASTVector<int> V;
- V.insert(*C, V.begin(), 0);
+ V.insert(Ctxt, V.begin(), 0);
+}
+
+TEST_F(ASTVectorTest, InsertFill) {
+ ASTVector<double> V;
+
+ // Ensure returned iterator points to first of inserted elements
+ auto I = V.insert(Ctxt, V.begin(), 5, 1.0);
+ ASSERT_EQ(V.begin(), I);
+
+ // Check non-empty case as well
+ I = V.insert(Ctxt, V.begin() + 1, 5, 1.0);
+ ASSERT_EQ(V.begin() + 1, I);
+
+ // And insert-at-end
+ I = V.insert(Ctxt, V.end(), 5, 1.0);
+ ASSERT_EQ(V.end() - 5, I);
}
+
+TEST_F(ASTVectorTest, InsertEmpty) {
+ ASTVector<double> V;
+
+ // Ensure no pointer overflow when inserting empty range
+ int Values[] = { 0, 1, 2, 3 };
+ ArrayRef<int> IntVec(Values);
+ auto I = V.insert(Ctxt, V.begin(), IntVec.begin(), IntVec.begin());
+ ASSERT_EQ(V.begin(), I);
+ ASSERT_TRUE(V.empty());
+
+ // Non-empty range
+ I = V.insert(Ctxt, V.begin(), IntVec.begin(), IntVec.end());
+ ASSERT_EQ(V.begin(), I);
+
+ // Non-Empty Vector, empty range
+ I = V.insert(Ctxt, V.end(), IntVec.begin(), IntVec.begin());
+ ASSERT_EQ(V.begin() + IntVec.size(), I);
+
+ // Non-Empty Vector, non-empty range
+ I = V.insert(Ctxt, V.end(), IntVec.begin(), IntVec.end());
+ ASSERT_EQ(V.begin() + IntVec.size(), I);
+}
+
+} // end namespace ast
+} // end namespace clang
diff --git a/unittests/AST/CommentLexer.cpp b/unittests/AST/CommentLexer.cpp
index cb8de271803a..77ee22ffb43e 100644
--- a/unittests/AST/CommentLexer.cpp
+++ b/unittests/AST/CommentLexer.cpp
@@ -60,8 +60,8 @@ protected:
void CommentLexerTest::lexString(const char *Source,
std::vector<Token> &Toks) {
- MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source);
- FileID File = SourceMgr.createFileID(Buf);
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Source);
+ FileID File = SourceMgr.createFileID(std::move(Buf));
SourceLocation Begin = SourceMgr.getLocForStartOfFile(File);
Lexer L(Allocator, Diags, Traits, Begin, Source, Source + strlen(Source));
diff --git a/unittests/AST/CommentParser.cpp b/unittests/AST/CommentParser.cpp
index ae1410f377fa..f6ef9b9b7cea 100644
--- a/unittests/AST/CommentParser.cpp
+++ b/unittests/AST/CommentParser.cpp
@@ -54,8 +54,8 @@ protected:
};
FullComment *CommentParserTest::parseString(const char *Source) {
- MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source);
- FileID File = SourceMgr.createFileID(Buf);
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Source);
+ FileID File = SourceMgr.createFileID(std::move(Buf));
SourceLocation Begin = SourceMgr.getLocForStartOfFile(File);
Lexer L(Allocator, Diags, Traits, Begin, Source, Source + strlen(Source));
diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp
index 5340756c03db..9f179c4a3f2d 100644
--- a/unittests/AST/DeclPrinterTest.cpp
+++ b/unittests/AST/DeclPrinterTest.cpp
@@ -268,8 +268,8 @@ TEST(DeclPrinter, TestCXXRecordDecl4) {
"class Z { int a; };"
"class A : Z { int b; };",
"A",
- "class A : Z {\n}"));
- // Should be: with semicolon, with { ... }, without two spaces
+ "class A : Z {\n}"));
+ // Should be: with semicolon, with { ... }
}
TEST(DeclPrinter, TestCXXRecordDecl5) {
@@ -277,8 +277,8 @@ TEST(DeclPrinter, TestCXXRecordDecl5) {
"struct Z { int a; };"
"struct A : Z { int b; };",
"A",
- "struct A : Z {\n}"));
- // Should be: with semicolon, with { ... }, without two spaces
+ "struct A : Z {\n}"));
+ // Should be: with semicolon, with { ... }
}
TEST(DeclPrinter, TestCXXRecordDecl6) {
@@ -313,8 +313,8 @@ TEST(DeclPrinter, TestCXXRecordDecl9) {
"class Z { int a; };"
"class A : virtual Z { int b; };",
"A",
- "class A : virtual Z {\n}"));
- // Should be: with semicolon, with { ... }, without two spaces
+ "class A : virtual Z {\n}"));
+ // Should be: with semicolon, with { ... }
}
TEST(DeclPrinter, TestCXXRecordDecl10) {
@@ -544,6 +544,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl10) {
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
"A<T...>(const A<T...> &a)"));
+ // WRONG; Should be: "A(const A<T...> &a);"
}
TEST(DeclPrinter, TestCXXConstructorDecl11) {
@@ -553,8 +554,8 @@ TEST(DeclPrinter, TestCXXConstructorDecl11) {
" A(T&&... ts) : T(ts)... {}"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- "A<T...>(T &&ts...) : T(ts)..."));
- // WRONG; Should be: "A(T&&... ts) : T(ts)..."
+ "A<T...>(T &&...ts) : T(ts)..."));
+ // WRONG; Should be: "A(T &&...ts) : T(ts)... {}"
}
TEST(DeclPrinter, TestCXXDestructorDecl1) {
@@ -1011,8 +1012,8 @@ TEST(DeclPrinter, TestClassTemplateDecl10) {
"template<typename... T>"
"struct A { int a; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <typename ... T> struct A {\n}"));
- // Should be: with semicolon, with { ... }, without spaces before '...'
+ "template <typename ...T> struct A {\n}"));
+ // Should be: with semicolon, with { ... }
}
TEST(DeclPrinter, TestClassTemplateDecl11) {
@@ -1020,8 +1021,8 @@ TEST(DeclPrinter, TestClassTemplateDecl11) {
"template<typename... T>"
"struct A : public T... { int a; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <typename ... T> struct A : public T... {\n}"));
- // Should be: with semicolon, with { ... }, without spaces before '...'
+ "template <typename ...T> struct A : public T... {\n}"));
+ // Should be: with semicolon, with { ... }
}
TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl1) {
@@ -1080,9 +1081,7 @@ TEST(DeclPrinter, TestFunctionTemplateDecl3) {
"template<typename... T>"
"void A(T... a);",
functionTemplateDecl(hasName("A")).bind("id"),
- "template <typename ... T> void A(T a...)"));
- // WRONG; Should be: "template <typename ... T> void A(T... a)"
- // (not "T a...")
+ "template <typename ...T> void A(T ...a)"));
// Should be: with semicolon.
}
@@ -1239,7 +1238,7 @@ TEST(DeclPrinter, TestTemplateArgumentList13) {
"};",
"A",
"Z<T...> A"));
- // Should be: with semicolon, without extra space in "> >"
+ // Should be: with semicolon
}
TEST(DeclPrinter, TestTemplateArgumentList14) {
@@ -1251,7 +1250,7 @@ TEST(DeclPrinter, TestTemplateArgumentList14) {
"};",
"A",
"Z<Y<T>...> A"));
- // Should be: with semicolon, without extra space in "> >"
+ // Should be: with semicolon
}
TEST(DeclPrinter, TestTemplateArgumentList15) {
@@ -1262,7 +1261,7 @@ TEST(DeclPrinter, TestTemplateArgumentList15) {
"};",
"A",
"Z<sizeof...(T)> A"));
- // Should be: with semicolon, without extra space in "> >"
+ // Should be: with semicolon
}
TEST(DeclPrinter, TestObjCMethod1) {
diff --git a/unittests/AST/EvaluateAsRValueTest.cpp b/unittests/AST/EvaluateAsRValueTest.cpp
index 9120c936ed12..820edbc7c3e8 100644
--- a/unittests/AST/EvaluateAsRValueTest.cpp
+++ b/unittests/AST/EvaluateAsRValueTest.cpp
@@ -12,16 +12,14 @@
//
//===----------------------------------------------------------------------===//
-#include <map>
-#include <string>
-
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
-
-#include "clang/AST/ASTConsumer.h"
+#include <map>
+#include <string>
using namespace clang::tooling;
@@ -59,9 +57,10 @@ class EvaluateConstantInitializersVisitor
class EvaluateConstantInitializersAction : public clang::ASTFrontendAction {
public:
- clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler,
- llvm::StringRef FilePath) override {
- return new Consumer;
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &Compiler,
+ llvm::StringRef FilePath) override {
+ return llvm::make_unique<Consumer>();
}
private:
diff --git a/unittests/AST/ExternalASTSourceTest.cpp b/unittests/AST/ExternalASTSourceTest.cpp
index 5cc2defe20fa..0cfde74cccce 100644
--- a/unittests/AST/ExternalASTSourceTest.cpp
+++ b/unittests/AST/ExternalASTSourceTest.cpp
@@ -35,9 +35,9 @@ private:
return ASTFrontendAction::ExecuteAction();
}
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- return new ASTConsumer;
+ virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ return llvm::make_unique<ASTConsumer>();
}
IntrusiveRefCntPtr<ExternalASTSource> Source;
@@ -50,7 +50,7 @@ bool testExternalASTSource(ExternalASTSource *Source,
CompilerInvocation *Invocation = new CompilerInvocation;
Invocation->getPreprocessorOpts().addRemappedFile(
- "test.cc", MemoryBuffer::getMemBuffer(FileContents));
+ "test.cc", MemoryBuffer::getMemBuffer(FileContents).release());
const char *Args[] = { "test.cc" };
CompilerInvocation::CreateFromArgs(*Invocation, Args,
Args + array_lengthof(Args),
diff --git a/unittests/AST/MatchVerifier.h b/unittests/AST/MatchVerifier.h
index 0265f4a24a14..e6593913b700 100644
--- a/unittests/AST/MatchVerifier.h
+++ b/unittests/AST/MatchVerifier.h
@@ -16,6 +16,9 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_UNITTESTS_AST_MATCHVERIFIER_H
+#define LLVM_CLANG_UNITTESTS_AST_MATCHVERIFIER_H
+
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
@@ -25,7 +28,14 @@
namespace clang {
namespace ast_matchers {
-enum Language { Lang_C, Lang_C89, Lang_CXX, Lang_CXX11, Lang_OpenCL };
+enum Language {
+ Lang_C,
+ Lang_C89,
+ Lang_CXX,
+ Lang_CXX11,
+ Lang_OpenCL,
+ Lang_OBJCXX
+};
/// \brief Base class for verifying some property of nodes found by a matcher.
template <typename NodeType>
@@ -102,6 +112,10 @@ testing::AssertionResult MatchVerifier<NodeType>::match(
break;
case Lang_OpenCL:
FileName = "input.cl";
+ break;
+ case Lang_OBJCXX:
+ FileName = "input.mm";
+ break;
}
// Default to failure in case callback is never called
@@ -277,3 +291,5 @@ private:
} // end namespace ast_matchers
} // end namespace clang
+
+#endif
diff --git a/unittests/AST/NamedDeclPrinterTest.cpp b/unittests/AST/NamedDeclPrinterTest.cpp
index 4823b44862e5..f8fb98454bd7 100644
--- a/unittests/AST/NamedDeclPrinterTest.cpp
+++ b/unittests/AST/NamedDeclPrinterTest.cpp
@@ -68,8 +68,8 @@ PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
PrintMatch Printer(SuppressUnwrittenScope);
MatchFinder Finder;
Finder.addMatcher(NodeMatch, &Printer);
- std::unique_ptr<FrontendActionFactory> Factory(
- newFrontendActionFactory(&Finder));
+ std::unique_ptr<FrontendActionFactory> Factory =
+ newFrontendActionFactory(&Finder);
if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
return testing::AssertionFailure()
diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp
index 82bba64334b9..ca5a8892a586 100644
--- a/unittests/AST/SourceLocationTest.cpp
+++ b/unittests/AST/SourceLocationTest.cpp
@@ -486,5 +486,17 @@ TEST(FriendDecl, InstantiationSourceRange) {
friendDecl(hasParent(recordDecl(isTemplateInstantiation())))));
}
+TEST(ObjCMessageExpr, CXXConstructExprRange) {
+ RangeVerifier<CXXConstructExpr> Verifier;
+ Verifier.expectRange(5, 25, 5, 27);
+ EXPECT_TRUE(Verifier.match(
+ "struct A { int a; };\n"
+ "@interface B {}\n"
+ "+ (void) f1: (A)arg;\n"
+ "@end\n"
+ "void f2() { A a; [B f1: (a)]; }\n",
+ constructExpr(), Lang_OBJCXX));
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index bd7a5a6df8f3..d2e9ee19b2cf 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -375,6 +375,13 @@ TEST(DeclarationMatcher, hasDeclContext) {
"}",
recordDecl(hasDeclContext(namespaceDecl(
hasName("M"), hasDeclContext(namespaceDecl()))))));
+
+ EXPECT_TRUE(matches("class D{};", decl(hasDeclContext(decl()))));
+}
+
+TEST(DeclarationMatcher, LinkageSpecification) {
+ EXPECT_TRUE(matches("extern \"C\" { void foo() {}; }", linkageSpecDecl()));
+ EXPECT_TRUE(notMatches("void foo() {};", linkageSpecDecl()));
}
TEST(ClassTemplate, DoesNotMatchClass) {
@@ -455,6 +462,11 @@ TEST(DeclarationMatcher, MatchAnyOf) {
EXPECT_TRUE(matches("class U {};", XOrYOrZOrUOrV));
EXPECT_TRUE(matches("class V {};", XOrYOrZOrUOrV));
EXPECT_TRUE(notMatches("class A {};", XOrYOrZOrUOrV));
+
+ StatementMatcher MixedTypes = stmt(anyOf(ifStmt(), binaryOperator()));
+ EXPECT_TRUE(matches("int F() { return 1 + 2; }", MixedTypes));
+ EXPECT_TRUE(matches("int F() { if (true) return 1; }", MixedTypes));
+ EXPECT_TRUE(notMatches("int F() { return 1; }", MixedTypes));
}
TEST(DeclarationMatcher, MatchHas) {
@@ -581,6 +593,11 @@ TEST(DeclarationMatcher, MatchNot) {
EXPECT_TRUE(matches("class X { class Z {}; };", ClassXHasNotClassY));
EXPECT_TRUE(notMatches("class X { class Y {}; class Z {}; };",
ClassXHasNotClassY));
+
+ DeclarationMatcher NamedNotRecord =
+ namedDecl(hasName("Foo"), unless(recordDecl()));
+ EXPECT_TRUE(matches("void Foo(){}", NamedNotRecord));
+ EXPECT_TRUE(notMatches("struct Foo {};", NamedNotRecord));
}
TEST(DeclarationMatcher, HasDescendant) {
@@ -643,6 +660,45 @@ TEST(DeclarationMatcher, HasDescendant) {
"};", ZDescendantClassXDescendantClassY));
}
+TEST(DeclarationMatcher, HasDescendantMemoization) {
+ DeclarationMatcher CannotMemoize =
+ decl(hasDescendant(typeLoc().bind("x")), has(decl()));
+ EXPECT_TRUE(matches("void f() { int i; }", CannotMemoize));
+}
+
+TEST(DeclarationMatcher, HasDescendantMemoizationUsesRestrictKind) {
+ auto Name = hasName("i");
+ auto VD = internal::Matcher<VarDecl>(Name).dynCastTo<Decl>();
+ auto RD = internal::Matcher<RecordDecl>(Name).dynCastTo<Decl>();
+ // Matching VD first should not make a cache hit for RD.
+ EXPECT_TRUE(notMatches("void f() { int i; }",
+ decl(hasDescendant(VD), hasDescendant(RD))));
+ EXPECT_TRUE(notMatches("void f() { int i; }",
+ decl(hasDescendant(RD), hasDescendant(VD))));
+ // Not matching RD first should not make a cache hit for VD either.
+ EXPECT_TRUE(matches("void f() { int i; }",
+ decl(anyOf(hasDescendant(RD), hasDescendant(VD)))));
+}
+
+TEST(DeclarationMatcher, HasAttr) {
+ EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};",
+ decl(hasAttr(clang::attr::WarnUnused))));
+ EXPECT_FALSE(matches("struct X {};",
+ decl(hasAttr(clang::attr::WarnUnused))));
+}
+
+TEST(DeclarationMatcher, MatchCudaDecl) {
+ EXPECT_TRUE(matchesWithCuda("__global__ void f() { }"
+ "void g() { f<<<1, 2>>>(); }",
+ CUDAKernelCallExpr()));
+ EXPECT_TRUE(matchesWithCuda("__attribute__((device)) void f() {}",
+ hasAttr(clang::attr::CUDADevice)));
+ EXPECT_TRUE(notMatchesWithCuda("void f() {}",
+ CUDAKernelCallExpr()));
+ EXPECT_FALSE(notMatchesWithCuda("__attribute__((global)) void f() {}",
+ hasAttr(clang::attr::CUDAGlobal)));
+}
+
// Implements a run method that returns whether BoundNodes contains a
// Decl bound to Id that can be dynamically cast to T.
// Optionally checks that the check succeeded a specific number of times.
@@ -681,7 +737,7 @@ public:
EXPECT_EQ("", Name);
}
- virtual bool run(const BoundNodes *Nodes) {
+ virtual bool run(const BoundNodes *Nodes) override {
const BoundNodes::IDToNodeMap &M = Nodes->getMap();
if (Nodes->getNodeAs<T>(Id)) {
++Count;
@@ -703,7 +759,7 @@ public:
return false;
}
- virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+ virtual bool run(const BoundNodes *Nodes, ASTContext *Context) override {
return run(Nodes);
}
@@ -771,6 +827,13 @@ TEST(Has, MatchesChildTypes) {
varDecl(hasName("i"), hasType(qualType(has(pointerType()))))));
}
+TEST(ValueDecl, Matches) {
+ EXPECT_TRUE(matches("enum EnumType { EnumValue };",
+ valueDecl(hasType(asString("enum EnumType")))));
+ EXPECT_TRUE(matches("void FunctionDecl();",
+ valueDecl(hasType(asString("void (void)")))));
+}
+
TEST(Enum, DoesNotMatchClasses) {
EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X"))));
}
@@ -1504,6 +1567,13 @@ TEST(IsExternC, MatchesExternCFunctionDeclarations) {
EXPECT_TRUE(notMatches("void f() {}", functionDecl(isExternC())));
}
+TEST(IsDeleted, MatchesDeletedFunctionDeclarations) {
+ EXPECT_TRUE(
+ notMatches("void Func();", functionDecl(hasName("Func"), isDeleted())));
+ EXPECT_TRUE(matches("void Func() = delete;",
+ functionDecl(hasName("Func"), isDeleted())));
+}
+
TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) {
EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };",
methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X")))))));
@@ -1602,6 +1672,64 @@ TEST(Matcher, MatchesSpecificArgument) {
1, refersToType(asString("int"))))));
}
+TEST(TemplateArgument, Matches) {
+ EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(templateArgument()))));
+ EXPECT_TRUE(matches(
+ "template<typename T> struct C {}; C<int> c;",
+ templateSpecializationType(hasAnyTemplateArgument(templateArgument()))));
+}
+
+TEST(TemplateArgumentCountIs, Matches) {
+ EXPECT_TRUE(
+ matches("template<typename T> struct C {}; C<int> c;",
+ classTemplateSpecializationDecl(templateArgumentCountIs(1))));
+ EXPECT_TRUE(
+ notMatches("template<typename T> struct C {}; C<int> c;",
+ classTemplateSpecializationDecl(templateArgumentCountIs(2))));
+
+ EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;",
+ templateSpecializationType(templateArgumentCountIs(1))));
+ EXPECT_TRUE(
+ notMatches("template<typename T> struct C {}; C<int> c;",
+ templateSpecializationType(templateArgumentCountIs(2))));
+}
+
+TEST(IsIntegral, Matches) {
+ EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(isIntegral()))));
+ EXPECT_TRUE(notMatches("template<typename T> struct C {}; C<int> c;",
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ templateArgument(isIntegral())))));
+}
+
+TEST(RefersToIntegralType, Matches) {
+ EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(refersToIntegralType(
+ asString("int"))))));
+ EXPECT_TRUE(notMatches("template<unsigned T> struct C {}; C<42> c;",
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToIntegralType(asString("int"))))));
+}
+
+TEST(EqualsIntegralValue, Matches) {
+ EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(equalsIntegralValue("42")))));
+ EXPECT_TRUE(matches("template<int T> struct C {}; C<-42> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(equalsIntegralValue("-42")))));
+ EXPECT_TRUE(matches("template<int T> struct C {}; C<-0042> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(equalsIntegralValue("-34")))));
+ EXPECT_TRUE(notMatches("template<int T> struct C {}; C<42> c;",
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ equalsIntegralValue("0042")))));
+}
+
TEST(Matcher, MatchesAccessSpecDecls) {
EXPECT_TRUE(matches("class C { public: int i; };", accessSpecDecl()));
EXPECT_TRUE(
@@ -3472,6 +3600,62 @@ TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) {
recordDecl(isTemplateInstantiation())));
}
+TEST(IsInstantiated, MatchesInstantiation) {
+ EXPECT_TRUE(
+ matches("template<typename T> class A { T i; }; class Y { A<int> a; };",
+ recordDecl(isInstantiated())));
+}
+
+TEST(IsInstantiated, NotMatchesDefinition) {
+ EXPECT_TRUE(notMatches("template<typename T> class A { T i; };",
+ recordDecl(isInstantiated())));
+}
+
+TEST(IsInTemplateInstantiation, MatchesInstantiationStmt) {
+ EXPECT_TRUE(matches("template<typename T> struct A { A() { T i; } };"
+ "class Y { A<int> a; }; Y y;",
+ declStmt(isInTemplateInstantiation())));
+}
+
+TEST(IsInTemplateInstantiation, NotMatchesDefinitionStmt) {
+ EXPECT_TRUE(notMatches("template<typename T> struct A { void x() { T i; } };",
+ declStmt(isInTemplateInstantiation())));
+}
+
+TEST(IsInstantiated, MatchesFunctionInstantiation) {
+ EXPECT_TRUE(
+ matches("template<typename T> void A(T t) { T i; } void x() { A(0); }",
+ functionDecl(isInstantiated())));
+}
+
+TEST(IsInstantiated, NotMatchesFunctionDefinition) {
+ EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }",
+ varDecl(isInstantiated())));
+}
+
+TEST(IsInTemplateInstantiation, MatchesFunctionInstantiationStmt) {
+ EXPECT_TRUE(
+ matches("template<typename T> void A(T t) { T i; } void x() { A(0); }",
+ declStmt(isInTemplateInstantiation())));
+}
+
+TEST(IsInTemplateInstantiation, NotMatchesFunctionDefinitionStmt) {
+ EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }",
+ declStmt(isInTemplateInstantiation())));
+}
+
+TEST(IsInTemplateInstantiation, Sharing) {
+ auto Matcher = binaryOperator(unless(isInTemplateInstantiation()));
+ // FIXME: Node sharing is an implementation detail, exposing it is ugly
+ // and makes the matcher behave in non-obvious ways.
+ EXPECT_TRUE(notMatches(
+ "int j; template<typename T> void A(T t) { j += 42; } void x() { A(0); }",
+ Matcher));
+ EXPECT_TRUE(matches(
+ "int j; template<typename T> void A(T t) { j += t; } void x() { A(0); }",
+ Matcher));
+}
+
TEST(IsExplicitTemplateSpecialization,
DoesNotMatchPrimaryTemplate) {
EXPECT_TRUE(notMatches(
@@ -3673,6 +3857,11 @@ TEST(TypeMatching, MatchesTypes) {
EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
}
+TEST(TypeMatching, MatchesVoid) {
+ EXPECT_TRUE(
+ matches("struct S { void func(); };", methodDecl(returns(voidType()))));
+}
+
TEST(TypeMatching, MatchesArrayTypes) {
EXPECT_TRUE(matches("int a[] = {2,3};", arrayType()));
EXPECT_TRUE(matches("int a[42];", arrayType()));
@@ -4163,8 +4352,8 @@ public:
virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
const T *Node = Nodes->getNodeAs<T>(Id);
- return selectFirst<const T>(InnerId,
- match(InnerMatcher, *Node, *Context)) !=nullptr;
+ return selectFirst<T>(InnerId, match(InnerMatcher, *Node, *Context)) !=
+ nullptr;
}
private:
std::string Id;
@@ -4221,7 +4410,7 @@ public:
// Use the original typed pointer to verify we can pass pointers to subtypes
// to equalsNode.
const T *TypedNode = cast<T>(Node);
- return selectFirst<const T>(
+ return selectFirst<T>(
"", match(stmt(hasParent(
stmt(has(stmt(equalsNode(TypedNode)))).bind(""))),
*Node, Context)) != nullptr;
@@ -4230,7 +4419,7 @@ public:
// Use the original typed pointer to verify we can pass pointers to subtypes
// to equalsNode.
const T *TypedNode = cast<T>(Node);
- return selectFirst<const T>(
+ return selectFirst<T>(
"", match(decl(hasParent(
decl(has(decl(equalsNode(TypedNode)))).bind(""))),
*Node, Context)) != nullptr;
@@ -4246,6 +4435,25 @@ TEST(IsEqualTo, MatchesNodesByIdentity) {
new VerifyAncestorHasChildIsEqual<IfStmt>()));
}
+TEST(MatchFinder, CheckProfiling) {
+ MatchFinder::MatchFinderOptions Options;
+ llvm::StringMap<llvm::TimeRecord> Records;
+ Options.CheckProfiling.emplace(Records);
+ MatchFinder Finder(std::move(Options));
+
+ struct NamedCallback : public MatchFinder::MatchCallback {
+ void run(const MatchFinder::MatchResult &Result) override {}
+ StringRef getID() const override { return "MyID"; }
+ } Callback;
+ Finder.addMatcher(decl(), &Callback);
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
+ ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
+
+ EXPECT_EQ(1u, Records.size());
+ EXPECT_EQ("MyID", Records.begin()->getKey());
+}
+
class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
public:
VerifyStartOfTranslationUnit() : Called(false) {}
@@ -4422,5 +4630,58 @@ TEST(EqualsBoundNodeMatcher, UnlessDescendantsOfAncestorsMatch) {
.bind("data")));
}
+TEST(TypeDefDeclMatcher, Match) {
+ EXPECT_TRUE(matches("typedef int typedefDeclTest;",
+ typedefDecl(hasName("typedefDeclTest"))));
+}
+
+// FIXME: Figure out how to specify paths so the following tests pass on Windows.
+#ifndef LLVM_ON_WIN32
+
+TEST(Matcher, IsExpansionInMainFileMatcher) {
+ EXPECT_TRUE(matches("class X {};",
+ recordDecl(hasName("X"), isExpansionInMainFile())));
+ EXPECT_TRUE(notMatches("", recordDecl(isExpansionInMainFile())));
+ FileContentMappings M;
+ M.push_back(std::make_pair("/other", "class X {};"));
+ EXPECT_TRUE(matchesConditionally("#include <other>\n",
+ recordDecl(isExpansionInMainFile()), false,
+ "-isystem/", M));
+}
+
+TEST(Matcher, IsExpansionInSystemHeader) {
+ FileContentMappings M;
+ M.push_back(std::make_pair("/other", "class X {};"));
+ EXPECT_TRUE(matchesConditionally(
+ "#include \"other\"\n", recordDecl(isExpansionInSystemHeader()), true,
+ "-isystem/", M));
+ EXPECT_TRUE(matchesConditionally("#include \"other\"\n",
+ recordDecl(isExpansionInSystemHeader()),
+ false, "-I/", M));
+ EXPECT_TRUE(notMatches("class X {};",
+ recordDecl(isExpansionInSystemHeader())));
+ EXPECT_TRUE(notMatches("", recordDecl(isExpansionInSystemHeader())));
+}
+
+TEST(Matcher, IsExpansionInFileMatching) {
+ FileContentMappings M;
+ M.push_back(std::make_pair("/foo", "class A {};"));
+ M.push_back(std::make_pair("/bar", "class B {};"));
+ EXPECT_TRUE(matchesConditionally(
+ "#include <foo>\n"
+ "#include <bar>\n"
+ "class X {};",
+ recordDecl(isExpansionInFileMatching("b.*"), hasName("B")), true,
+ "-isystem/", M));
+ EXPECT_TRUE(matchesConditionally(
+ "#include <foo>\n"
+ "#include <bar>\n"
+ "class X {};",
+ recordDecl(isExpansionInFileMatching("f.*"), hasName("X")), false,
+ "-isystem/", M));
+}
+
+#endif // LLVM_ON_WIN32
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 2e4ee2c5cbe9..a2ab9feee2a2 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
-#define LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
+#ifndef LLVM_CLANG_UNITTESTS_ASTMATCHERS_ASTMATCHERSTEST_H
+#define LLVM_CLANG_UNITTESTS_ASTMATCHERS_ASTMATCHERSTEST_H
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/ASTUnit.h"
@@ -22,6 +22,7 @@ using clang::tooling::buildASTFromCodeWithArgs;
using clang::tooling::newFrontendActionFactory;
using clang::tooling::runToolOnCodeWithArgs;
using clang::tooling::FrontendActionFactory;
+using clang::tooling::FileContentMappings;
class BoundNodesCallback {
public:
@@ -39,7 +40,7 @@ public:
VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified)
: Verified(Verified), FindResultReviewer(FindResultVerifier) {}
- virtual void run(const MatchFinder::MatchResult &Result) {
+ virtual void run(const MatchFinder::MatchResult &Result) override {
if (FindResultReviewer != nullptr) {
*Verified |= FindResultReviewer->run(&Result.Nodes, Result.Context);
} else {
@@ -58,10 +59,10 @@ private:
};
template <typename T>
-testing::AssertionResult matchesConditionally(const std::string &Code,
- const T &AMatcher,
- bool ExpectMatch,
- llvm::StringRef CompileArg) {
+testing::AssertionResult matchesConditionally(
+ const std::string &Code, const T &AMatcher, bool ExpectMatch,
+ llvm::StringRef CompileArg,
+ const FileContentMappings &VirtualMappedFiles = FileContentMappings()) {
bool Found = false, DynamicFound = false;
MatchFinder Finder;
VerifyMatch VerifyFound(nullptr, &Found);
@@ -73,7 +74,8 @@ testing::AssertionResult matchesConditionally(const std::string &Code,
newFrontendActionFactory(&Finder));
// Some tests use typeof, which is a gnu extension.
std::vector<std::string> Args(1, CompileArg);
- if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, "input.cc",
+ VirtualMappedFiles)) {
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
}
if (Found != DynamicFound) {
@@ -103,6 +105,75 @@ testing::AssertionResult notMatches(const std::string &Code,
return matchesConditionally(Code, AMatcher, false, "-std=c++11");
}
+// Function based on matchesConditionally with "-x cuda" argument added and
+// small CUDA header prepended to the code string.
+template <typename T>
+testing::AssertionResult matchesConditionallyWithCuda(
+ const std::string &Code, const T &AMatcher, bool ExpectMatch,
+ llvm::StringRef CompileArg) {
+ const std::string CudaHeader =
+ "typedef unsigned int size_t;\n"
+ "#define __constant__ __attribute__((constant))\n"
+ "#define __device__ __attribute__((device))\n"
+ "#define __global__ __attribute__((global))\n"
+ "#define __host__ __attribute__((host))\n"
+ "#define __shared__ __attribute__((shared))\n"
+ "struct dim3 {"
+ " unsigned x, y, z;"
+ " __host__ __device__ dim3(unsigned x, unsigned y = 1, unsigned z = 1)"
+ " : x(x), y(y), z(z) {}"
+ "};"
+ "typedef struct cudaStream *cudaStream_t;"
+ "int cudaConfigureCall(dim3 gridSize, dim3 blockSize,"
+ " size_t sharedSize = 0,"
+ " cudaStream_t stream = 0);";
+
+ bool Found = false, DynamicFound = false;
+ MatchFinder Finder;
+ VerifyMatch VerifyFound(nullptr, &Found);
+ Finder.addMatcher(AMatcher, &VerifyFound);
+ VerifyMatch VerifyDynamicFound(nullptr, &DynamicFound);
+ if (!Finder.addDynamicMatcher(AMatcher, &VerifyDynamicFound))
+ return testing::AssertionFailure() << "Could not add dynamic matcher";
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
+ // Some tests use typeof, which is a gnu extension.
+ std::vector<std::string> Args;
+ Args.push_back("-xcuda");
+ Args.push_back("-fno-ms-extensions");
+ Args.push_back(CompileArg);
+ if (!runToolOnCodeWithArgs(Factory->create(),
+ CudaHeader + Code, Args)) {
+ return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+ }
+ if (Found != DynamicFound) {
+ return testing::AssertionFailure() << "Dynamic match result ("
+ << DynamicFound
+ << ") does not match static result ("
+ << Found << ")";
+ }
+ if (!Found && ExpectMatch) {
+ return testing::AssertionFailure()
+ << "Could not find match in \"" << Code << "\"";
+ } else if (Found && !ExpectMatch) {
+ return testing::AssertionFailure()
+ << "Found unexpected match in \"" << Code << "\"";
+ }
+ return testing::AssertionSuccess();
+}
+
+template <typename T>
+testing::AssertionResult matchesWithCuda(const std::string &Code,
+ const T &AMatcher) {
+ return matchesConditionallyWithCuda(Code, AMatcher, true, "-std=c++11");
+}
+
+template <typename T>
+testing::AssertionResult notMatchesWithCuda(const std::string &Code,
+ const T &AMatcher) {
+ return matchesConditionallyWithCuda(Code, AMatcher, false, "-std=c++11");
+}
+
template <typename T>
testing::AssertionResult
matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index 4e3239ff5a50..2a9a61b543d4 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -26,9 +26,12 @@ public:
virtual ~MockSema() {}
uint64_t expectMatcher(StringRef MatcherName) {
- ast_matchers::internal::Matcher<Stmt> M = stmt();
+ // Optimizations on the matcher framework make simple matchers like
+ // 'stmt()' to be all the same matcher.
+ // Use a more complex expression to prevent that.
+ ast_matchers::internal::Matcher<Stmt> M = stmt(stmt(), stmt());
ExpectedMatchers.insert(std::make_pair(MatcherName, M));
- return M.getID();
+ return M.getID().second;
}
void parse(StringRef Code) {
@@ -125,8 +128,12 @@ TEST(ParserTest, ParseMatcher) {
EXPECT_EQ("", Sema.Errors[i]);
}
+ EXPECT_NE(ExpectedFoo, ExpectedBar);
+ EXPECT_NE(ExpectedFoo, ExpectedBaz);
+ EXPECT_NE(ExpectedBar, ExpectedBaz);
+
EXPECT_EQ(1ULL, Sema.Values.size());
- EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID());
+ EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID().second);
EXPECT_EQ(3ULL, Sema.Matchers.size());
const MockSema::MatcherInfo Bar = Sema.Matchers[0];
@@ -145,13 +152,21 @@ TEST(ParserTest, ParseMatcher) {
EXPECT_EQ("Foo", Foo.MatcherName);
EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12));
EXPECT_EQ(2ULL, Foo.Args.size());
- EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID());
- EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID());
+ EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID().second);
+ EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID().second);
EXPECT_EQ("Yo!", Foo.BoundID);
}
using ast_matchers::internal::Matcher;
+Parser::NamedValueMap getTestNamedValues() {
+ Parser::NamedValueMap Values;
+ Values["nameX"] = std::string("x");
+ Values["hasParamA"] =
+ VariantMatcher::SingleMatcher(hasParameter(0, hasName("a")));
+ return Values;
+}
+
TEST(ParserTest, FullParserTest) {
Diagnostics Error;
llvm::Optional<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
@@ -174,21 +189,11 @@ TEST(ParserTest, FullParserTest) {
EXPECT_FALSE(matches("void f(int x, int a);", M));
// Test named values.
- struct NamedSema : public Parser::RegistrySema {
- public:
- virtual VariantValue getNamedValue(StringRef Name) {
- if (Name == "nameX")
- return std::string("x");
- if (Name == "param0")
- return VariantMatcher::SingleMatcher(hasParameter(0, hasName("a")));
- return VariantValue();
- }
- };
- NamedSema Sema;
+ auto NamedValues = getTestNamedValues();
llvm::Optional<DynTypedMatcher> HasParameterWithNamedValues(
Parser::parseMatcherExpression(
- "functionDecl(param0, hasParameter(1, hasName(nameX)))", &Sema,
- &Error));
+ "functionDecl(hasParamA, hasParameter(1, hasName(nameX)))",
+ nullptr, &NamedValues, &Error));
EXPECT_EQ("", Error.toStringFull());
M = HasParameterWithNamedValues->unconditionalConvertTo<Decl>();
@@ -270,7 +275,7 @@ TEST(ParserTest, OverloadErrors) {
ParseWithError("callee(\"A\")"));
}
-TEST(ParserTest, Completion) {
+TEST(ParserTest, CompletionRegistry) {
std::vector<MatcherCompletion> Comps =
Parser::completeExpression("while", 5);
ASSERT_EQ(1u, Comps.size());
@@ -284,6 +289,38 @@ TEST(ParserTest, Completion) {
EXPECT_EQ("bind", Comps[0].MatcherDecl);
}
+TEST(ParserTest, CompletionNamedValues) {
+ // Can complete non-matcher types.
+ auto NamedValues = getTestNamedValues();
+ StringRef Code = "functionDecl(hasName(";
+ std::vector<MatcherCompletion> Comps =
+ Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);
+ ASSERT_EQ(1u, Comps.size());
+ EXPECT_EQ("nameX", Comps[0].TypedText);
+ EXPECT_EQ("String nameX", Comps[0].MatcherDecl);
+
+ // Can complete if there are names in the expression.
+ Code = "methodDecl(hasName(nameX), ";
+ Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);
+ EXPECT_LT(0u, Comps.size());
+
+ // Can complete names and registry together.
+ Code = "methodDecl(hasP";
+ Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);
+ ASSERT_EQ(3u, Comps.size());
+ EXPECT_EQ("aramA", Comps[0].TypedText);
+ EXPECT_EQ("Matcher<FunctionDecl> hasParamA", Comps[0].MatcherDecl);
+
+ EXPECT_EQ("arameter(", Comps[1].TypedText);
+ EXPECT_EQ(
+ "Matcher<FunctionDecl> hasParameter(unsigned, Matcher<ParmVarDecl>)",
+ Comps[1].MatcherDecl);
+
+ EXPECT_EQ("arent(", Comps[2].TypedText);
+ EXPECT_EQ("Matcher<Decl> hasParent(Matcher<Decl|Stmt>)",
+ Comps[2].MatcherDecl);
+}
+
} // end anonymous namespace
} // end namespace dynamic
} // end namespace ast_matchers
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index e659b3a733d6..5483f8f35804 100644
--- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -82,8 +82,9 @@ public:
typedef std::vector<MatcherCompletion> CompVector;
CompVector getCompletions() {
- return Registry::getCompletions(
- ArrayRef<std::pair<MatcherCtor, unsigned> >());
+ std::vector<std::pair<MatcherCtor, unsigned> > Context;
+ return Registry::getMatcherCompletions(
+ Registry::getAcceptedCompletionTypes(Context));
}
CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) {
@@ -92,7 +93,8 @@ public:
if (!Ctor)
return CompVector();
Context.push_back(std::make_pair(*Ctor, ArgNo1));
- return Registry::getCompletions(Context);
+ return Registry::getMatcherCompletions(
+ Registry::getAcceptedCompletionTypes(Context));
}
CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1,
@@ -106,18 +108,16 @@ public:
if (!Ctor)
return CompVector();
Context.push_back(std::make_pair(*Ctor, ArgNo2));
- return Registry::getCompletions(Context);
+ return Registry::getMatcherCompletions(
+ Registry::getAcceptedCompletionTypes(Context));
}
bool hasCompletion(const CompVector &Comps, StringRef TypedText,
- StringRef MatcherDecl = StringRef(),
- unsigned *Index = nullptr) {
+ StringRef MatcherDecl = StringRef()) {
for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E;
++I) {
if (I->TypedText == TypedText &&
(MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) {
- if (Index)
- *Index = I - Comps.begin();
return true;
}
}
@@ -347,7 +347,7 @@ TEST_F(RegistryTest, VariadicOp) {
"anyOf",
constructMatcher("recordDecl",
constructMatcher("hasName", std::string("Foo"))),
- constructMatcher("namedDecl",
+ constructMatcher("functionDecl",
constructMatcher("hasName", std::string("foo"))))
.getTypedMatcher<Decl>();
@@ -380,6 +380,13 @@ TEST_F(RegistryTest, VariadicOp) {
EXPECT_FALSE(matches("class Bar{ int Foo; };", D));
EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D));
+
+ D = constructMatcher(
+ "namedDecl", constructMatcher("hasName", std::string("Foo")),
+ constructMatcher("unless", constructMatcher("recordDecl")))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("void Foo(){}", D));
+ EXPECT_TRUE(notMatches("struct Foo {};", D));
}
TEST_F(RegistryTest, Errors) {
@@ -438,24 +445,27 @@ TEST_F(RegistryTest, Errors) {
TEST_F(RegistryTest, Completion) {
CompVector Comps = getCompletions();
+ // Overloaded
EXPECT_TRUE(hasCompletion(
Comps, "hasParent(", "Matcher<Decl|Stmt> hasParent(Matcher<Decl|Stmt>)"));
+ // Variadic.
EXPECT_TRUE(hasCompletion(Comps, "whileStmt(",
"Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)"));
+ // Polymorphic.
+ EXPECT_TRUE(hasCompletion(
+ Comps, "hasDescendant(",
+ "Matcher<NestedNameSpecifier|NestedNameSpecifierLoc|QualType|...> "
+ "hasDescendant(Matcher<CXXCtorInitializer|NestedNameSpecifier|"
+ "NestedNameSpecifierLoc|...>)"));
CompVector WhileComps = getCompletions("whileStmt", 0);
- unsigned HasBodyIndex, HasParentIndex, AllOfIndex;
EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(",
- "Matcher<WhileStmt> hasBody(Matcher<Stmt>)",
- &HasBodyIndex));
+ "Matcher<WhileStmt> hasBody(Matcher<Stmt>)"));
EXPECT_TRUE(hasCompletion(WhileComps, "hasParent(",
- "Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)",
- &HasParentIndex));
- EXPECT_TRUE(hasCompletion(WhileComps, "allOf(",
- "Matcher<T> allOf(Matcher<T>...)", &AllOfIndex));
- EXPECT_GT(HasParentIndex, HasBodyIndex);
- EXPECT_GT(AllOfIndex, HasParentIndex);
+ "Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)"));
+ EXPECT_TRUE(
+ hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)"));
EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt("));
EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt("));
@@ -475,6 +485,20 @@ TEST_F(RegistryTest, Completion) {
hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()"));
EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"",
"Matcher<NamedDecl> hasName(string)"));
+
+ // Heterogeneous overloads.
+ Comps = getCompletions("classTemplateSpecializationDecl", 0);
+ EXPECT_TRUE(hasCompletion(
+ Comps, "isSameOrDerivedFrom(",
+ "Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)"));
+}
+
+TEST_F(RegistryTest, HasArgs) {
+ Matcher<Decl> Value = constructMatcher(
+ "decl", constructMatcher("hasAttr", std::string("attr::WarnUnused")))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value));
+ EXPECT_FALSE(matches("struct X {};", Value));
}
} // end anonymous namespace
diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt
index b8f69bf357b4..3cb3cb8d3c80 100644
--- a/unittests/Basic/CMakeLists.txt
+++ b/unittests/Basic/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(BasicTests
CharInfoTest.cpp
+ DiagnosticTest.cpp
FileManagerTest.cpp
SourceManagerTest.cpp
VirtualFileSystemTest.cpp
diff --git a/unittests/Basic/DiagnosticTest.cpp b/unittests/Basic/DiagnosticTest.cpp
new file mode 100644
index 000000000000..fa2b56e08341
--- /dev/null
+++ b/unittests/Basic/DiagnosticTest.cpp
@@ -0,0 +1,49 @@
+//===- unittests/Basic/DiagnosticTest.cpp -- Diagnostic engine tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+// Check that DiagnosticErrorTrap works with SuppressAllDiagnostics.
+TEST(DiagnosticTest, suppressAndTrap) {
+ DiagnosticsEngine Diags(new DiagnosticIDs(),
+ new DiagnosticOptions,
+ new IgnoringDiagConsumer());
+ Diags.setSuppressAllDiagnostics(true);
+
+ {
+ DiagnosticErrorTrap trap(Diags);
+
+ // Diag that would set UncompilableErrorOccurred and ErrorOccurred.
+ Diags.Report(diag::err_target_unknown_triple) << "unknown";
+
+ // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred.
+ Diags.Report(diag::err_cannot_open_file) << "file" << "error";
+
+ // Diag that would set FatalErrorOccurred
+ // (via non-note following a fatal error).
+ Diags.Report(diag::warn_mt_message) << "warning";
+
+ EXPECT_TRUE(trap.hasErrorOccurred());
+ EXPECT_TRUE(trap.hasUnrecoverableErrorOccurred());
+ }
+
+ EXPECT_FALSE(Diags.hasErrorOccurred());
+ EXPECT_FALSE(Diags.hasFatalErrorOccurred());
+ EXPECT_FALSE(Diags.hasUncompilableErrorOccurred());
+ EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred());
+}
+
+}
diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp
index b3bc767949e8..dd8cf2410ad1 100644
--- a/unittests/Basic/FileManagerTest.cpp
+++ b/unittests/Basic/FileManagerTest.cpp
@@ -10,8 +10,8 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/FileSystemStatCache.h"
-#include "gtest/gtest.h"
#include "llvm/Config/llvm-config.h"
+#include "gtest/gtest.h"
using namespace llvm;
using namespace clang;
@@ -97,7 +97,7 @@ TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) {
// FileManager to report "file/directory doesn't exist". This
// avoids the possibility of the result of this test being affected
// by what's in the real file system.
- manager.addStatCache(new FakeStatCache);
+ manager.addStatCache(llvm::make_unique<FakeStatCache>());
EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo"));
EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir"));
@@ -107,7 +107,7 @@ TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) {
// When a virtual file is added, all of its ancestors should be created.
TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) {
// Fake an empty real file system.
- manager.addStatCache(new FakeStatCache);
+ manager.addStatCache(llvm::make_unique<FakeStatCache>());
manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo"));
@@ -124,7 +124,7 @@ TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) {
// getFile() returns non-NULL if a real file exists at the given path.
TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
// Inject fake files into the file system.
- FakeStatCache *statCache = new FakeStatCache;
+ auto statCache = llvm::make_unique<FakeStatCache>();
statCache->InjectDirectory("/tmp", 42);
statCache->InjectFile("/tmp/test", 43);
@@ -135,7 +135,7 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
statCache->InjectFile(FileName, 45);
#endif
- manager.addStatCache(statCache);
+ manager.addStatCache(std::move(statCache));
const FileEntry *file = manager.getFile("/tmp/test");
ASSERT_TRUE(file != nullptr);
@@ -158,7 +158,7 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
// getFile() returns non-NULL if a virtual file exists at the given path.
TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
// Fake an empty real file system.
- manager.addStatCache(new FakeStatCache);
+ manager.addStatCache(llvm::make_unique<FakeStatCache>());
manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
const FileEntry *file = manager.getFile("virtual/dir/bar.h");
@@ -175,11 +175,11 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) {
// Inject two fake files into the file system. Different inodes
// mean the files are not symlinked together.
- FakeStatCache *statCache = new FakeStatCache;
+ auto statCache = llvm::make_unique<FakeStatCache>();
statCache->InjectDirectory(".", 41);
statCache->InjectFile("foo.cpp", 42);
statCache->InjectFile("bar.cpp", 43);
- manager.addStatCache(statCache);
+ manager.addStatCache(std::move(statCache));
const FileEntry *fileFoo = manager.getFile("foo.cpp");
const FileEntry *fileBar = manager.getFile("bar.cpp");
@@ -192,10 +192,10 @@ TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) {
// exists at the given path.
TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) {
// Inject a fake foo.cpp into the file system.
- FakeStatCache *statCache = new FakeStatCache;
+ auto statCache = llvm::make_unique<FakeStatCache>();
statCache->InjectDirectory(".", 41);
statCache->InjectFile("foo.cpp", 42);
- manager.addStatCache(statCache);
+ manager.addStatCache(std::move(statCache));
// Create a virtual bar.cpp file.
manager.getVirtualFile("bar.cpp", 200, 0);
@@ -211,11 +211,11 @@ TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) {
// getFile() returns the same FileEntry for real files that are aliases.
TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
// Inject two real files with the same inode.
- FakeStatCache *statCache = new FakeStatCache;
+ auto statCache = llvm::make_unique<FakeStatCache>();
statCache->InjectDirectory("abc", 41);
statCache->InjectFile("abc/foo.cpp", 42);
statCache->InjectFile("abc/bar.cpp", 42);
- manager.addStatCache(statCache);
+ manager.addStatCache(std::move(statCache));
EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
}
@@ -224,11 +224,11 @@ TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
// corresponding real files that are aliases.
TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
// Inject two real files with the same inode.
- FakeStatCache *statCache = new FakeStatCache;
+ auto statCache = llvm::make_unique<FakeStatCache>();
statCache->InjectDirectory("abc", 41);
statCache->InjectFile("abc/foo.cpp", 42);
statCache->InjectFile("abc/bar.cpp", 42);
- manager.addStatCache(statCache);
+ manager.addStatCache(std::move(statCache));
manager.getVirtualFile("abc/foo.cpp", 100, 0);
manager.getVirtualFile("abc/bar.cpp", 200, 0);
@@ -236,6 +236,15 @@ TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
}
+TEST_F(FileManagerTest, addRemoveStatCache) {
+ manager.addStatCache(llvm::make_unique<FakeStatCache>());
+ auto statCacheOwner = llvm::make_unique<FakeStatCache>();
+ auto *statCache = statCacheOwner.get();
+ manager.addStatCache(std::move(statCacheOwner));
+ manager.addStatCache(llvm::make_unique<FakeStatCache>());
+ manager.removeStatCache(statCache);
+}
+
#endif // !LLVM_ON_WIN32
} // anonymous namespace
diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp
index 9ea093c6b2b8..1dda54dff14d 100644
--- a/unittests/Basic/SourceManagerTest.cpp
+++ b/unittests/Basic/SourceManagerTest.cpp
@@ -74,8 +74,8 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
const char *source =
"#define M(x) [x]\n"
"M(foo)";
- MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
- FileID mainFileID = SourceMgr.createFileID(buf);
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(source);
+ FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
SourceMgr.setMainFileID(mainFileID);
VoidModuleLoader ModLoader;
@@ -127,8 +127,8 @@ TEST_F(SourceManagerTest, getColumnNumber) {
"int x;\n"
"int y;";
- MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source);
- FileID MainFileID = SourceMgr.createFileID(Buf);
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Source);
+ FileID MainFileID = SourceMgr.createFileID(std::move(Buf));
SourceMgr.setMainFileID(MainFileID);
bool Invalid;
@@ -186,14 +186,14 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
"#define CONCAT(X, Y) X##Y\n"
"CONCAT(1,1)\n";
- MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header);
- MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main);
- FileID mainFileID = SourceMgr.createFileID(mainBuf);
+ std::unique_ptr<MemoryBuffer> HeaderBuf = MemoryBuffer::getMemBuffer(header);
+ std::unique_ptr<MemoryBuffer> MainBuf = MemoryBuffer::getMemBuffer(main);
+ FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf));
SourceMgr.setMainFileID(mainFileID);
const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
- headerBuf->getBufferSize(), 0);
- SourceMgr.overrideFileContents(headerFile, headerBuf);
+ HeaderBuf->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
VoidModuleLoader ModLoader;
HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
@@ -285,13 +285,13 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
"#define INC2 </test-header.h>\n"
"#include M(INC2)\n";
- MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header);
- MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main);
- SourceMgr.setMainFileID(SourceMgr.createFileID(mainBuf));
+ std::unique_ptr<MemoryBuffer> HeaderBuf = MemoryBuffer::getMemBuffer(header);
+ std::unique_ptr<MemoryBuffer> MainBuf = MemoryBuffer::getMemBuffer(main);
+ SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf)));
const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
- headerBuf->getBufferSize(), 0);
- SourceMgr.overrideFileContents(headerFile, headerBuf);
+ HeaderBuf->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
VoidModuleLoader ModLoader;
HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
@@ -303,7 +303,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
PP.Initialize(*Target);
std::vector<MacroAction> Macros;
- PP.addPPCallbacks(new MacroTracker(Macros));
+ PP.addPPCallbacks(llvm::make_unique<MacroTracker>(Macros));
PP.EnterMainSourceFile();
diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp
index e7d361e252b4..67beb923d976 100644
--- a/unittests/Basic/VirtualFileSystemTest.cpp
+++ b/unittests/Basic/VirtualFileSystemTest.cpp
@@ -32,21 +32,15 @@ class DummyFileSystem : public vfs::FileSystem {
public:
DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
- ErrorOr<vfs::Status> status(const Twine &Path) {
+ ErrorOr<vfs::Status> status(const Twine &Path) override {
std::map<std::string, vfs::Status>::iterator I =
FilesAndDirs.find(Path.str());
if (I == FilesAndDirs.end())
return make_error_code(llvm::errc::no_such_file_or_directory);
return I->second;
}
- std::error_code openFileForRead(const Twine &Path,
- std::unique_ptr<vfs::File> &Result) {
- llvm_unreachable("unimplemented");
- }
- std::error_code getBufferForFile(const Twine &Name,
- std::unique_ptr<MemoryBuffer> &Result,
- int64_t FileSize = -1,
- bool RequiresNullTerminator = true) {
+ ErrorOr<std::unique_ptr<vfs::File>>
+ openFileForRead(const Twine &Path) override {
llvm_unreachable("unimplemented");
}
@@ -539,8 +533,9 @@ public:
IntrusiveRefCntPtr<vfs::FileSystem>
getFromYAMLRawString(StringRef Content,
IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
- MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(Content);
- return getVFSFromYAML(Buffer, CountingDiagHandler, this, ExternalFS);
+ std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
+ return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, this,
+ ExternalFS);
}
IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 936b8b206599..d0e2860e07f0 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -20,6 +20,7 @@ add_subdirectory(AST)
add_subdirectory(Tooling)
add_subdirectory(Format)
add_subdirectory(Sema)
+add_subdirectory(CodeGen)
# FIXME: Why are the libclang unit tests disabled on Windows?
if(NOT WIN32)
add_subdirectory(libclang)
diff --git a/unittests/CodeGen/BufferSourceTest.cpp b/unittests/CodeGen/BufferSourceTest.cpp
new file mode 100644
index 000000000000..8169a6d0c9e5
--- /dev/null
+++ b/unittests/CodeGen/BufferSourceTest.cpp
@@ -0,0 +1,78 @@
+//===- unittests/CodeGen/BufferSourceTest.cpp - MemoryBuffer source tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+// Emitting constructors for global objects involves looking
+// at the source file name. This makes sure that we don't crash
+// if the source file is a memory buffer.
+const char TestProgram[] =
+ "class EmitCXXGlobalInitFunc "
+ "{ "
+ "public: "
+ " EmitCXXGlobalInitFunc() {} "
+ "}; "
+ "EmitCXXGlobalInitFunc test; ";
+
+TEST(BufferSourceTest, EmitCXXGlobalInitFunc) {
+ CompilerInstance compiler;
+
+ compiler.createDiagnostics();
+ compiler.getLangOpts().CPlusPlus = 1;
+ compiler.getLangOpts().CPlusPlus11 = 1;
+
+ compiler.getTargetOpts().Triple = llvm::Triple::normalize(
+ llvm::sys::getProcessTriple());
+ compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
+ compiler.getDiagnostics(),
+ std::make_shared<clang::TargetOptions>(
+ compiler.getTargetOpts())));
+
+ compiler.createFileManager();
+ compiler.createSourceManager(compiler.getFileManager());
+ compiler.createPreprocessor(clang::TU_Prefix);
+
+ compiler.createASTContext();
+
+ compiler.setASTConsumer(std::unique_ptr<ASTConsumer>(
+ CreateLLVMCodeGen(
+ compiler.getDiagnostics(),
+ "EmitCXXGlobalInitFuncTest",
+ compiler.getCodeGenOpts(),
+ compiler.getTargetOpts(),
+ llvm::getGlobalContext())));
+
+ compiler.createSema(clang::TU_Prefix,NULL);
+
+ clang::SourceManager &sm = compiler.getSourceManager();
+ sm.setMainFileID(sm.createFileID(
+ llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User));
+
+ clang::ParseAST(compiler.getSema(), false, false);
+}
+
+}
diff --git a/unittests/CodeGen/CMakeLists.txt b/unittests/CodeGen/CMakeLists.txt
new file mode 100644
index 000000000000..27a513a2f982
--- /dev/null
+++ b/unittests/CodeGen/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(LLVM_LINK_COMPONENTS
+ Core
+ Support
+ )
+
+add_clang_unittest(ClangCodeGenTests
+ BufferSourceTest.cpp
+ )
+
+target_link_libraries(ClangCodeGenTests
+ clangBasic
+ clangCodeGen
+ clangFrontend
+ clangParse
+ )
diff --git a/unittests/CodeGen/Makefile b/unittests/CodeGen/Makefile
new file mode 100644
index 000000000000..de347e1afddc
--- /dev/null
+++ b/unittests/CodeGen/Makefile
@@ -0,0 +1,20 @@
+##===- unittests/CodeGen/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 = ../..
+TESTNAME = CodeGen
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader mc option \
+ profiledata support
+USEDLIBS = clangCodeGen.a clangFrontend.a clangSerialization.a \
+ clangDriver.a \
+ clangParse.a clangSema.a clangAnalysis.a \
+ clangEdit.a clangAST.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Format/CMakeLists.txt b/unittests/Format/CMakeLists.txt
index 14fc22d05c08..4a7ab794187b 100644
--- a/unittests/Format/CMakeLists.txt
+++ b/unittests/Format/CMakeLists.txt
@@ -4,11 +4,12 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(FormatTests
FormatTest.cpp
+ FormatTestJava.cpp
FormatTestJS.cpp
FormatTestProto.cpp
)
target_link_libraries(FormatTests
clangFormat
- clangTooling
+ clangToolingCore
)
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 21bc86275461..8e770c2e9cd5 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -111,6 +111,7 @@ TEST_F(FormatTest, NestedNameSpecifiers) {
verifyFormat("vector<::Type> v;");
verifyFormat("::ns::SomeFunction(::ns::SomeOtherFunction())");
verifyFormat("static constexpr bool Bar = decltype(bar())::value;");
+ verifyFormat("bool a = 2 < ::SomeFunction();");
}
TEST_F(FormatTest, OnlyGeneratesNecessaryReplacements) {
@@ -158,9 +159,21 @@ TEST_F(FormatTest, FormatsCorrectRegionForLeadingWhitespace) {
25, 0, getLLVMStyleWithColumns(12)));
}
+TEST_F(FormatTest, FormatLineWhenInvokedOnTrailingNewline) {
+ EXPECT_EQ("int b;\n\nint a;",
+ format("int b;\n\nint a;", 8, 0, getLLVMStyle()));
+ EXPECT_EQ("int b;\n\nint a;",
+ format("int b;\n\nint a;", 7, 0, getLLVMStyle()));
+
+ // This might not strictly be correct, but is likely good in all practical
+ // cases.
+ EXPECT_EQ("int b;\nint a;",
+ format("int b;int a;", 7, 0, getLLVMStyle()));
+}
+
TEST_F(FormatTest, RemovesWhitespaceWhenTriggeredOnEmptyLine) {
EXPECT_EQ("int a;\n\n int b;",
- format("int a;\n \n\n int b;", 7, 0, getLLVMStyle()));
+ format("int a;\n \n\n int b;", 8, 0, getLLVMStyle()));
EXPECT_EQ("int a;\n\n int b;",
format("int a;\n \n\n int b;", 9, 0, getLLVMStyle()));
}
@@ -174,7 +187,7 @@ TEST_F(FormatTest, RemovesEmptyLines) {
"\n"
"};"));
- // Don't remove empty lines at the start of namespaces.
+ // Don't remove empty lines at the start of namespaces or extern "C" blocks.
EXPECT_EQ("namespace N {\n"
"\n"
"int i;\n"
@@ -184,6 +197,29 @@ TEST_F(FormatTest, RemovesEmptyLines) {
"int i;\n"
"}",
getGoogleStyle()));
+ EXPECT_EQ("extern /**/ \"C\" /**/ {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ format("extern /**/ \"C\" /**/ {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ getGoogleStyle()));
+
+ // ...but do keep inlining and removing empty lines for non-block extern "C"
+ // functions.
+ verifyFormat("extern \"C\" int f() { return 42; }", getGoogleStyle());
+ EXPECT_EQ("extern \"C\" int f() {\n"
+ " int i = 42;\n"
+ " return i;\n"
+ "}",
+ format("extern \"C\" int f() {\n"
+ "\n"
+ " int i = 42;\n"
+ " return i;\n"
+ "}",
+ getGoogleStyle()));
// Remove empty lines at the beginning and end of blocks.
EXPECT_EQ("void f() {\n"
@@ -700,6 +736,58 @@ TEST_F(FormatTest, CaseRanges) {
"}");
}
+TEST_F(FormatTest, ShortCaseLabels) {
+ FormatStyle Style = getLLVMStyle();
+ Style.AllowShortCaseLabelsOnASingleLine = true;
+ verifyFormat("switch (a) {\n"
+ "case 1: x = 1; break;\n"
+ "case 2: return;\n"
+ "case 3:\n"
+ "case 4:\n"
+ "case 5: return;\n"
+ "case 6: // comment\n"
+ " return;\n"
+ "case 7:\n"
+ " // comment\n"
+ " return;\n"
+ "default: y = 1; break;\n"
+ "}",
+ Style);
+ verifyFormat("switch (a) {\n"
+ "#if FOO\n"
+ "case 0: return 0;\n"
+ "#endif\n"
+ "}",
+ Style);
+ verifyFormat("switch (a) {\n"
+ "case 1: {\n"
+ "}\n"
+ "case 2: {\n"
+ " return;\n"
+ "}\n"
+ "case 3: {\n"
+ " x = 1;\n"
+ " return;\n"
+ "}\n"
+ "case 4:\n"
+ " if (x)\n"
+ " return;\n"
+ "}",
+ Style);
+ Style.ColumnLimit = 21;
+ verifyFormat("switch (a) {\n"
+ "case 1: x = 1; break;\n"
+ "case 2: return;\n"
+ "case 3:\n"
+ "case 4:\n"
+ "case 5: return;\n"
+ "default:\n"
+ " y = 1;\n"
+ " break;\n"
+ "}",
+ Style);
+}
+
TEST_F(FormatTest, FormatsLabels) {
verifyFormat("void f() {\n"
" some_code();\n"
@@ -791,6 +879,12 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) {
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
" // Comment inside a statement.\n"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
+ verifyFormat("SomeFunction(a,\n"
+ " // comment\n"
+ " b + x);");
+ verifyFormat("SomeFunction(a, a,\n"
+ " // comment\n"
+ " b + x);");
verifyFormat(
"bool aaaaaaaaaaaaa = // comment\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
@@ -904,6 +998,14 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) {
" // first\n"
"// at start\n"
"otherLine();"));
+ EXPECT_EQ("void f() {\n"
+ " lineWith(); // comment\n"
+ " // at start\n"
+ "}",
+ format("void f() {\n"
+ " lineWith(); // comment\n"
+ " // at start\n"
+ "}"));
verifyFormat(
"#define A \\\n"
@@ -1159,8 +1261,8 @@ TEST_F(FormatTest, CorrectlyHandlesLengthOfBlockComments) {
}
TEST_F(FormatTest, DontBreakNonTrailingBlockComments) {
- EXPECT_EQ("void\n"
- "ffffffffff(int aaaaa /* test */);",
+ EXPECT_EQ("void ffffffffff(\n"
+ " int aaaaa /* test */);",
format("void ffffffffff(int aaaaa /* test */);",
getLLVMStyleWithColumns(35)));
}
@@ -1210,11 +1312,11 @@ TEST_F(FormatTest, SplitsLongCxxComments) {
format("// A comment before a macro definition\n"
"#define a b",
getLLVMStyleWithColumns(20)));
- EXPECT_EQ("void\n"
- "ffffff(int aaaaaaaaa, // wwww\n"
- " int bbbbbbbbbb, // xxxxxxx\n"
- " // yyyyyyyyyy\n"
- " int c, int d, int e) {}",
+ EXPECT_EQ("void ffffff(\n"
+ " int aaaaaaaaa, // wwww\n"
+ " int bbbbbbbbbb, // xxxxxxx\n"
+ " // yyyyyyyyyy\n"
+ " int c, int d, int e) {}",
format("void ffffff(\n"
" int aaaaaaaaa, // wwww\n"
" int bbbbbbbbbb, // xxxxxxx yyyyyyyyyy\n"
@@ -1846,6 +1948,7 @@ TEST_F(FormatTest, FormatsClasses) {
verifyFormat("template <class R, class C>\n"
"struct Aaaaaaaaaaaaaaaaa<R (C::*)(int) const>\n"
" : Aaaaaaaaaaaaaaaaa<R (C::*)(int)> {};");
+ verifyFormat("class ::A::B {};");
}
TEST_F(FormatTest, FormatsVariableDeclarationsAfterStructOrClass) {
@@ -1903,7 +2006,8 @@ TEST_F(FormatTest, FormatsEnum) {
verifyFormat("enum E { // comment\n"
" ONE,\n"
" TWO\n"
- "};");
+ "};\n"
+ "int i;");
}
TEST_F(FormatTest, FormatsEnumsWithErrors) {
@@ -1973,6 +2077,21 @@ TEST_F(FormatTest, FormatsNSEnums) {
" // Information about aThirdDecentlyLongValue.\n"
" aThirdDecentlyLongValue\n"
"};");
+ verifyGoogleFormat("typedef NS_OPTIONS(NSInteger, MyType) {\n"
+ " a = 1,\n"
+ " b = 2,\n"
+ " c = 3,\n"
+ "};");
+ verifyGoogleFormat("typedef CF_ENUM(NSInteger, MyType) {\n"
+ " a = 1,\n"
+ " b = 2,\n"
+ " c = 3,\n"
+ "};");
+ verifyGoogleFormat("typedef CF_OPTIONS(NSInteger, MyType) {\n"
+ " a = 1,\n"
+ " b = 2,\n"
+ " c = 3,\n"
+ "};");
}
TEST_F(FormatTest, FormatsBitfields) {
@@ -2063,12 +2182,32 @@ TEST_F(FormatTest, FormatsExternC) { verifyFormat("extern \"C\" {\nint a;"); }
TEST_F(FormatTest, FormatsInlineASM) {
verifyFormat("asm(\"xyz\" : \"=a\"(a), \"=d\"(b) : \"a\"(data));");
+ verifyFormat("asm(\"nop\" ::: \"memory\");");
verifyFormat(
"asm(\"movq\\t%%rbx, %%rsi\\n\\t\"\n"
" \"cpuid\\n\\t\"\n"
" \"xchgq\\t%%rbx, %%rsi\\n\\t\"\n"
" : \"=a\"(*rEAX), \"=S\"(*rEBX), \"=c\"(*rECX), \"=d\"(*rEDX)\n"
" : \"a\"(value));");
+ EXPECT_EQ(
+ "void NS_InvokeByIndex(void *that, unsigned int methodIndex) {\n"
+ " __asm {\n"
+ " mov edx,[that] // vtable in edx\n"
+ " mov eax,methodIndex\n"
+ " call [edx][eax*4] // stdcall\n"
+ " }\n"
+ "}",
+ format("void NS_InvokeByIndex(void *that, unsigned int methodIndex) {\n"
+ " __asm {\n"
+ " mov edx,[that] // vtable in edx\n"
+ " mov eax,methodIndex\n"
+ " call [edx][eax*4] // stdcall\n"
+ " }\n"
+ "}"));
+ verifyFormat("void function() {\n"
+ " // comment\n"
+ " asm(\"\");\n"
+ "}");
}
TEST_F(FormatTest, FormatTryCatch) {
@@ -2247,6 +2386,16 @@ TEST_F(FormatTest, NestedStaticInitializers) {
" {kOsWin, \"Windows\"},\n"
" {kOsLinux, \"Linux\"},\n"
" {kOsCrOS, \"Chrome OS\"}};");
+ verifyFormat(
+ "struct {\n"
+ " unsigned bit;\n"
+ " const char *const name;\n"
+ "} kBitsToOs[] = {\n"
+ " {kOsMac, \"Mac\"},\n"
+ " {kOsWin, \"Windows\"},\n"
+ " {kOsLinux, \"Linux\"},\n"
+ " {kOsCrOS, \"Chrome OS\"},\n"
+ "};");
}
TEST_F(FormatTest, FormatsSmallMacroDefinitionsInSingleLine) {
@@ -2482,6 +2631,14 @@ TEST_F(FormatTest, MacrosWithoutTrailingSemicolon) {
" Q_Object\n"
" A() {\n}\n"
"} ;"));
+
+ // Only if the next line can actually start an unwrapped line.
+ EXPECT_EQ("SOME_WEIRD_LOG_MACRO << SomeThing;",
+ format("SOME_WEIRD_LOG_MACRO\n"
+ "<< SomeThing;"));
+
+ verifyFormat("VISIT_GL_CALL(GenBuffers, void, (GLsizei n, GLuint* buffers), "
+ "(n, buffers))\n", getChromiumStyle(FormatStyle::LK_Cpp));
}
TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) {
@@ -2659,6 +2816,17 @@ TEST_F(FormatTest, NoEscapedNewlineHandlingInBlockComments) {
EXPECT_EQ("/* \\ \\ \\\n*/", format("\\\n/* \\ \\ \\\n*/"));
}
+TEST_F(FormatTest, DontCrashOnBlockComments) {
+ EXPECT_EQ(
+ "int xxxxxxxxx; /* "
+ "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\n"
+ "zzzzzz\n"
+ "0*/",
+ format("int xxxxxxxxx; /* "
+ "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy zzzzzz\n"
+ "0*/"));
+}
+
TEST_F(FormatTest, CalculateSpaceOnConsecutiveLinesInMacro) {
verifyFormat("#define A \\\n"
" int v( \\\n"
@@ -2779,11 +2947,19 @@ TEST_F(FormatTest, LayoutBlockInsideParens) {
"});",
format(" functionCall ( {int i;int j;} );"));
EXPECT_EQ("functionCall({\n"
- " int i;\n"
- " int j;\n"
- " },\n"
- " aaaa, bbbb, cccc);",
+ " int i;\n"
+ " int j;\n"
+ "}, aaaa, bbbb, cccc);",
format(" functionCall ( {int i;int j;}, aaaa, bbbb, cccc);"));
+ EXPECT_EQ("functionCall(\n"
+ " {\n"
+ " int i;\n"
+ " int j;\n"
+ " },\n"
+ " aaaa, bbbb, // comment\n"
+ " cccc);",
+ format(" functionCall ( {int i;int j;}, aaaa, bbbb, // comment\n"
+ "cccc);"));
EXPECT_EQ("functionCall(aaaa, bbbb, { int i; });",
format(" functionCall (aaaa, bbbb, {int i;});"));
EXPECT_EQ("functionCall(aaaa, bbbb, {\n"
@@ -2794,7 +2970,8 @@ TEST_F(FormatTest, LayoutBlockInsideParens) {
EXPECT_EQ("functionCall(aaaa, bbbb, { int i; });",
format(" functionCall (aaaa, bbbb, {int i;});"));
verifyFormat(
- "Aaa({\n"
+ "Aaa(\n" // FIXME: There shouldn't be a linebreak here.
+ " {\n"
" int i; // break\n"
" },\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
@@ -2876,10 +3053,9 @@ TEST_F(FormatTest, LayoutNestedBlocks) {
FormatStyle Style = getGoogleStyle();
Style.ColumnLimit = 45;
verifyFormat("Debug(aaaaa, {\n"
- " if (aaaaaaaaaaaaaaaaaaaaaaaa)\n"
- " return;\n"
- " },\n"
- " a);", Style);
+ " if (aaaaaaaaaaaaaaaaaaaaaaaa) return;\n"
+ "}, a);",
+ Style);
}
TEST_F(FormatTest, IndividualStatementsOfNestedBlocks) {
@@ -3025,6 +3201,9 @@ TEST_F(FormatTest, LineBreakingInBinaryExpressions) {
verifyFormat("if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
" bbbbbbbbbbbbbbbbbb) && // aaaaaaaaaaaaaaaa\n"
" cccccc) {\n}");
+ verifyFormat("b = a &&\n"
+ " // Comment\n"
+ " b.c && d;");
// If the LHS of a comparison is not a binary expression itself, the
// additional linebreak confuses many people.
@@ -3114,39 +3293,47 @@ TEST_F(FormatTest, ExpressionIndentationBreakingBeforeOperators) {
// everything until something with the same indent as the operator is found.
// FIXME: Is this a good system?
FormatStyle Style = getLLVMStyle();
- Style.BreakBeforeBinaryOperators = true;
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
verifyFormat(
"bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
- " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
" && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " > ccccccccccccccccccccccccccccccccccccccccc;",
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " > ccccccccccccccccccccccccccccccccccccccccc;",
Style);
verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" == bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
Style);
verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" == bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
Style);
verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
Style);
verifyFormat("if () {\n"
"} else if (aaaaa\n"
" && bbbbb // break\n"
- " > ccccc) {\n"
+ " > ccccc) {\n"
"}",
Style);
+ verifyFormat("return (a)\n"
+ " // comment\n"
+ " + b;",
+ Style);
+ verifyFormat("int aaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " + cc;",
+ Style);
// Forced by comments.
verifyFormat(
@@ -3167,6 +3354,48 @@ TEST_F(FormatTest, ExpressionIndentationBreakingBeforeOperators) {
Style);
}
+TEST_F(FormatTest, NoOperandAlignment) {
+ FormatStyle Style = getLLVMStyle();
+ Style.AlignOperands = false;
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
+ verifyFormat(
+ "bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " > ccccccccccccccccccccccccccccccccccccccccc;",
+ Style);
+
+ verifyFormat("int aaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " + cc;",
+ Style);
+ verifyFormat("int a = aa\n"
+ " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " * cccccccccccccccccccccccccccccccccccc;",
+ Style);
+
+ Style.AlignAfterOpenBracket = false;
+ verifyFormat("return (a > b\n"
+ " // comment1\n"
+ " // comment2\n"
+ " || c);",
+ Style);
+}
+
+TEST_F(FormatTest, BreakingBeforeNonAssigmentOperators) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
+ verifyFormat("int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;",
+ Style);
+}
+
TEST_F(FormatTest, ConstructorInitializers) {
verifyFormat("Constructor() : Initializer(FitsOnTheLine) {}");
verifyFormat("Constructor() : Inttializer(FitsOnTheLine) {}",
@@ -3409,6 +3638,10 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) {
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" bbbb bbbb);");
+ verifyFormat("void SomeLoooooooooooongFunction(\n"
+ " std::unique_ptr<aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " int bbbbbbbbbbbbb);");
// Treat overloaded operators like other functions.
verifyFormat("SomeLoooooooooooooooooooooooooogType\n"
@@ -3427,6 +3660,10 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) {
" int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 1);");
verifyFormat("aaaaaaaaaaaaaaaaaaaaaa\n"
"aaaaaaaaaaaaaaaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaa = 1);");
+ verifyGoogleFormat(
+ "typename aaaaaaaaaa<aaaaaa>::aaaaaaaaaaa\n"
+ "aaaaaaaaaa<aaaaaa>::aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " bool *aaaaaaaaaaaaaaaaaa, bool *aa) {}");
}
TEST_F(FormatTest, TrailingReturnType) {
@@ -3437,6 +3674,9 @@ TEST_F(FormatTest, TrailingReturnType) {
verifyFormat("template <size_t Order, typename T>\n"
"auto load_img(const std::string &filename)\n"
" -> alias::tensor<Order, T, mem::tag::cpu> {}");
+ verifyFormat("auto SomeFunction(A aaaaaaaaaaaaaaaaaaaaa) const\n"
+ " -> decltype(f(aaaaaaaaaaaaaaaaaaaaa)) {}");
+ verifyFormat("auto doSomething(Aaaaaa *aaaaaa) -> decltype(aaaaaa->f()) {}");
// Not trailing return types.
verifyFormat("void f() { auto a = b->c(); }");
@@ -3447,8 +3687,8 @@ TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) {
// they are not function-like.
FormatStyle Style = getGoogleStyle();
Style.ColumnLimit = 47;
- verifyFormat("void\n"
- "someLongFunction(int someLongParameter) const {\n}",
+ verifyFormat("void someLongFunction(\n"
+ " int someLoooooooooooooongParameter) const {\n}",
getLLVMStyleWithColumns(47));
verifyFormat("LoooooongReturnType\n"
"someLoooooooongFunction() const {}",
@@ -3513,6 +3753,7 @@ TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) {
" LOCKS_EXCLUDED(aaaaaaaaaaaaa) {}");
verifyGoogleFormat("void aaaaaaaaaaaaaa(aaaaaaaa aaa) override\n"
" AAAAAAAAAAAAAAAAAAAAAAAA(aaaaaaaaaaaaaaa);");
+ verifyFormat("SomeFunction([](int i) LOCKS_EXCLUDED(a) {});");
verifyFormat(
"void aaaaaaaaaaaaaaaaaa()\n"
@@ -3607,9 +3848,25 @@ TEST_F(FormatTest, BreaksDesireably) {
" NSTrackingActiveAlways;");
}
+TEST_F(FormatTest, FormatsDeclarationsOnePerLine) {
+ FormatStyle NoBinPacking = getGoogleStyle();
+ NoBinPacking.BinPackParameters = false;
+ NoBinPacking.BinPackArguments = true;
+ verifyFormat("void f() {\n"
+ " f(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n"
+ "}",
+ NoBinPacking);
+ verifyFormat("void f(int aaaaaaaaaaaaaaaaaaaa,\n"
+ " int aaaaaaaaaaaaaaaaaaaa,\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}",
+ NoBinPacking);
+}
+
TEST_F(FormatTest, FormatsOneParameterPerLineIfNecessary) {
FormatStyle NoBinPacking = getGoogleStyle();
NoBinPacking.BinPackParameters = false;
+ NoBinPacking.BinPackArguments = false;
verifyFormat("f(aaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaa);",
@@ -3866,6 +4123,66 @@ TEST_F(FormatTest, AlignsAfterReturn) {
" code == a || code == b;");
}
+TEST_F(FormatTest, AlignsAfterOpenBracket) {
+ verifyFormat(
+ "void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaa aaaaaaaa,\n"
+ " aaaaaaaaa aaaaaaa) {}");
+ verifyFormat(
+ "SomeLongVariableName->someVeryLongFunctionName(aaaaaaaaaaa aaaaaaaaa,\n"
+ " aaaaaaaaaaa aaaaaaaaa);");
+ verifyFormat(
+ "SomeLongVariableName->someFunction(foooooooo(aaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaa));");
+ FormatStyle Style = getLLVMStyle();
+ Style.AlignAfterOpenBracket = false;
+ verifyFormat(
+ "void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaa aaaaaaaa, aaaaaaaaa aaaaaaa) {}",
+ Style);
+ verifyFormat(
+ "SomeLongVariableName->someVeryLongFunctionName(\n"
+ " aaaaaaaaaaa aaaaaaaaa, aaaaaaaaaaa aaaaaaaaa);",
+ Style);
+ verifyFormat(
+ "SomeLongVariableName->someFunction(\n"
+ " foooooooo(aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaa));",
+ Style);
+ verifyFormat(
+ "void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaa aaaaaaaa,\n"
+ " aaaaaaaaa aaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}",
+ Style);
+ verifyFormat(
+ "SomeLongVariableName->someVeryLongFunctionName(aaaaaaaaaaa aaaaaaaaa,\n"
+ " aaaaaaaaaaa aaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
+ verifyFormat(
+ "SomeLongVariableName->someFunction(foooooooo(aaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa));",
+ Style);
+}
+
+TEST_F(FormatTest, ParenthesesAndOperandAlignment) {
+ FormatStyle Style = getLLVMStyleWithColumns(40);
+ verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n"
+ " bbbbbbbbbbbbbbbbbbbbbb);",
+ Style);
+ Style.AlignAfterOpenBracket = true;
+ Style.AlignOperands = false;
+ verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n"
+ " bbbbbbbbbbbbbbbbbbbbbb);",
+ Style);
+ Style.AlignAfterOpenBracket = false;
+ Style.AlignOperands = true;
+ verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n"
+ " bbbbbbbbbbbbbbbbbbbbbb);",
+ Style);
+ Style.AlignAfterOpenBracket = false;
+ Style.AlignOperands = false;
+ verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n"
+ " bbbbbbbbbbbbbbbbbbbbbb);",
+ Style);
+}
+
TEST_F(FormatTest, BreaksConditionalExpressions) {
verifyFormat(
"aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
@@ -3918,6 +4235,10 @@ TEST_F(FormatTest, BreaksConditionalExpressions) {
" aaaaaaaaa\n"
" ? b\n"
" : c);");
+ verifyFormat("return aaaa == bbbb\n"
+ " // comment\n"
+ " ? aaaa\n"
+ " : bbbb;");
verifyFormat(
"unsigned Indent =\n"
" format(TheLine.First, IndentForLevel[TheLine.Level] >= 0\n"
@@ -3948,7 +4269,7 @@ TEST_F(FormatTest, BreaksConditionalExpressions) {
" : aaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
FormatStyle NoBinPacking = getLLVMStyle();
- NoBinPacking.BinPackParameters = false;
+ NoBinPacking.BinPackArguments = false;
verifyFormat(
"void f() {\n"
" g(aaa,\n"
@@ -3966,6 +4287,32 @@ TEST_F(FormatTest, BreaksConditionalExpressions) {
" ?: aaaaaaaaaaaaaaa);\n"
"}",
NoBinPacking);
+
+ verifyFormat("SomeFunction(aaaaaaaaaaaaaaaaa,\n"
+ " // comment.\n"
+ " ccccccccccccccccccccccccccccccccccccccc\n"
+ " ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb);");
+
+ // Assignments in conditional expressions. Apparently not uncommon :-(.
+ verifyFormat("return a != b\n"
+ " // comment\n"
+ " ? a = b\n"
+ " : a = b;");
+ verifyFormat("return a != b\n"
+ " // comment\n"
+ " ? a = a != b\n"
+ " // comment\n"
+ " ? a = b\n"
+ " : a\n"
+ " : a;\n");
+ verifyFormat("return a != b\n"
+ " // comment\n"
+ " ? a\n"
+ " : a = a != b\n"
+ " // comment\n"
+ " ? a = b\n"
+ " : a;");
}
TEST_F(FormatTest, BreaksConditionalExpressionsAfterOperator) {
@@ -4079,13 +4426,13 @@ TEST_F(FormatTest, DeclarationsOfMultipleVariables) {
// line. Also fix indent for breaking after the type, this looks bad.
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaa,\n"
- " *b = bbbbbbbbbbbbbbbbbbb;",
+ " * b = bbbbbbbbbbbbbbbbbbb;",
getGoogleStyle());
// Not ideal, but pointer-with-type does not allow much here.
verifyGoogleFormat(
- "aaaaaaaaa* a = aaaaaaaaaaaaaaaaaaa, *b = bbbbbbbbbbbbbbbbbbb,\n"
- " *b = bbbbbbbbbbbbbbbbbbb, *d = ddddddddddddddddddd;");
+ "aaaaaaaaa* a = aaaaaaaaaaaaaaaaaaa, * b = bbbbbbbbbbbbbbbbbbb,\n"
+ " * b = bbbbbbbbbbbbbbbbbbb, * d = ddddddddddddddddddd;");
}
TEST_F(FormatTest, ConditionalExpressionsInBrackets) {
@@ -4145,6 +4492,40 @@ TEST_F(FormatTest, AlignsStringLiterals) {
getLLVMStyleWithColumns(25));
}
+TEST_F(FormatTest, AlwaysBreakAfterDefinitionReturnType) {
+ FormatStyle AfterType = getLLVMStyle();
+ AfterType.AlwaysBreakAfterDefinitionReturnType = true;
+ verifyFormat("const char *\n"
+ "f(void) {\n" // Break here.
+ " return \"\";\n"
+ "}\n"
+ "const char *bar(void);\n", // No break here.
+ AfterType);
+ verifyFormat("template <class T>\n"
+ "T *\n"
+ "f(T &c) {\n" // Break here.
+ " return NULL;\n"
+ "}\n"
+ "template <class T> T *f(T &c);\n", // No break here.
+ AfterType);
+ AfterType.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
+ verifyFormat("const char *\n"
+ "f(void)\n" // Break here.
+ "{\n"
+ " return \"\";\n"
+ "}\n"
+ "const char *bar(void);\n", // No break here.
+ AfterType);
+ verifyFormat("template <class T>\n"
+ "T *\n" // Problem here: no line break
+ "f(T &c)\n" // Break here.
+ "{\n"
+ " return NULL;\n"
+ "}\n"
+ "template <class T> T *f(T &c);\n", // No break here.
+ AfterType);
+}
+
TEST_F(FormatTest, AlwaysBreakBeforeMultilineStrings) {
FormatStyle NoBreak = getLLVMStyle();
NoBreak.AlwaysBreakBeforeMultilineStrings = false;
@@ -4308,6 +4689,10 @@ TEST_F(FormatTest, AlignsPipes) {
" CHECK_EQ(aaaa, (*bbbbbbbbb)->cccccc)\n"
" << \"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\";\n"
"}");
+
+ // Handle 'endl'.
+ verifyFormat("llvm::errs() << aaaa << endl\n"
+ " << bbbb << endl;");
}
TEST_F(FormatTest, UnderstandsEquals) {
@@ -4353,6 +4738,11 @@ TEST_F(FormatTest, WrapsAtFunctionCallsIfNecessary) {
verifyFormat("EXPECT_CALL(SomeObject, SomeFunction(Parameter))\n"
" .WillRepeatedly(Return(SomeValue));");
+ verifyFormat("void f() {\n"
+ " EXPECT_CALL(SomeObject, SomeFunction(Parameter))\n"
+ " .Times(2)\n"
+ " .WillRepeatedly(Return(SomeValue));\n"
+ "}");
verifyFormat("SomeMap[std::pair(aaaaaaaaaaaa, bbbbbbbbbbbbbbb)].insert(\n"
" ccccccccccccccccccccccc);");
verifyFormat("aaaaa(aaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
@@ -4480,6 +4870,8 @@ TEST_F(FormatTest, WrapsTemplateDeclarations) {
" B>*>(\n"
"\n"
" );"));
+ verifyFormat("int aaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " const typename aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaa);");
FormatStyle AlwaysBreak = getLLVMStyle();
AlwaysBreak.AlwaysBreakTemplateDeclarations = true;
@@ -4559,11 +4951,14 @@ TEST_F(FormatTest, UnderstandsTemplateParameters) {
EXPECT_EQ("A<::A<int>> a;", format("A< ::A<int>> a;", getGoogleStyle()));
EXPECT_EQ("A<::A<int>> a;", format("A<::A<int> > a;", getGoogleStyle()));
+ verifyFormat("A<A>> a;", getChromiumStyle(FormatStyle::LK_Cpp));
+
verifyFormat("test >> a >> b;");
verifyFormat("test << a >> b;");
verifyFormat("f<int>();");
verifyFormat("template <typename T> void f() {}");
+ verifyFormat("struct A<std::enable_if<sizeof(T2) < sizeof(int32)>::type>;");
// Not template parameters.
verifyFormat("return a < b && c > d;");
@@ -4577,6 +4972,8 @@ TEST_F(FormatTest, UnderstandsTemplateParameters) {
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> aaaaa);",
getLLVMStyleWithColumns(60));
+ verifyFormat("static_assert(is_convertible<A &&, B>::value, \"AAA\");");
+ verifyFormat("Constructor(A... a) : a_(X<A>{std::forward<A>(a)}...) {}");
}
TEST_F(FormatTest, UnderstandsBinaryOperators) {
@@ -4687,6 +5084,7 @@ TEST_F(FormatTest, UnderstandsOverloadedOperators) {
" return left.group < right.group;\n"
"}");
verifyFormat("SomeType &operator=(const SomeType &S);");
+ verifyFormat("f.template operator()<int>();");
verifyGoogleFormat("operator void*();");
verifyGoogleFormat("operator SomeType<SomeType<int>>();");
@@ -4712,6 +5110,12 @@ TEST_F(FormatTest, UnderstandsNewAndDelete) {
" delete a;\n"
" delete (A *)a;\n"
"}");
+ verifyFormat("new (aaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaa))\n"
+ " typename aaaaaaaaaaaaaaaaaaaaaaaa();");
+ verifyFormat("auto aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " new (aaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaa))\n"
+ " typename aaaaaaaaaaaaaaaaaaaaaaaa();");
+ verifyFormat("delete[] h->p;");
}
TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
@@ -4765,6 +5169,10 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("typedef void (*f)(int *a);");
verifyIndependentOfContext("int i{a * b};");
verifyIndependentOfContext("aaa && aaa->f();");
+ verifyIndependentOfContext("int x = ~*p;");
+ verifyFormat("Constructor() : a(a), area(width * height) {}");
+ verifyFormat("Constructor() : a(a), area(a, width * height) {}");
+ verifyFormat("void f() { f(a, c * d); }");
verifyIndependentOfContext("InvalidRegions[*R] = 0;");
@@ -4784,6 +5192,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaa, *aaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyGoogleFormat("**outparam = 1;");
verifyGoogleFormat("int main(int argc, char** argv) {}");
verifyGoogleFormat("A<int*> a;");
verifyGoogleFormat("A<int**> a;");
@@ -4798,6 +5207,14 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyGoogleFormat("Type* t = x++ * y;");
verifyGoogleFormat(
"const char* const p = reinterpret_cast<const char* const>(q);");
+ verifyGoogleFormat("void f(int i = 0, SomeType** temps = NULL);");
+ verifyGoogleFormat("void f(Bar* a = nullptr, Bar* b);");
+ verifyGoogleFormat("template <typename T>\n"
+ "void f(int i = 0, SomeType** temps = NULL);");
+
+ FormatStyle Left = getLLVMStyle();
+ Left.PointerAlignment = FormatStyle::PAS_Left;
+ verifyFormat("x = *a(x) = *a(y);", Left);
verifyIndependentOfContext("a = *(x + y);");
verifyIndependentOfContext("a = &(x + y);");
@@ -4858,6 +5275,19 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyFormat("vector<a * b> v;");
verifyFormat("foo<b && false>();");
verifyFormat("foo<b & 1>();");
+ verifyFormat("decltype(*::std::declval<const T &>()) void F();");
+ verifyFormat(
+ "template <class T, class = typename std::enable_if<\n"
+ " std::is_integral<T>::value &&\n"
+ " (sizeof(T) > 1 || sizeof(T) < 8)>::type>\n"
+ "void F();",
+ getLLVMStyleWithColumns(76));
+ verifyFormat(
+ "template <class T,\n"
+ " class = typename ::std::enable_if<\n"
+ " ::std::is_array<T>{} && ::std::is_array<T>{}>::type>\n"
+ "void F();",
+ getGoogleStyleWithColumns(68));
verifyIndependentOfContext("MACRO(int *i);");
verifyIndependentOfContext("MACRO(auto *a);");
@@ -4880,7 +5310,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
// FIXME: We cannot handle this case yet; we might be able to figure out that
// foo<x> d > v; doesn't make sense.
- verifyFormat("foo<a < b && c> d > v;");
+ verifyFormat("foo<a<b && c> d> v;");
FormatStyle PointerMiddle = getLLVMStyle();
PointerMiddle.PointerAlignment = FormatStyle::PAS_Middle;
@@ -4987,6 +5417,7 @@ TEST_F(FormatTest, FormatsCasts) {
verifyFormat("my_int a = (my_int)sizeof(int);");
verifyFormat("return (my_int)aaa;");
verifyFormat("#define x ((int)-1)");
+ verifyFormat("#define LENGTH(x, y) (x) - (y) + 1");
verifyFormat("#define p(q) ((int *)&q)");
verifyFormat("fn(a)(b) + 1;");
@@ -4994,11 +5425,12 @@ TEST_F(FormatTest, FormatsCasts) {
verifyFormat("void f() { return P ? (my_int)*P : (my_int)0; }");
verifyFormat("my_int a = (my_int)~0;");
verifyFormat("my_int a = (my_int)++a;");
- verifyFormat("my_int a = (my_int)+2;");
+ verifyFormat("my_int a = (my_int)-2;");
verifyFormat("my_int a = (my_int)1;");
verifyFormat("my_int a = (my_int *)1;");
verifyFormat("my_int a = (const my_int)-1;");
verifyFormat("my_int a = (const my_int *)-1;");
+ verifyFormat("my_int a = (my_int)(my_int)-1;");
// FIXME: single value wrapped with paren will be treated as cast.
verifyFormat("void f(int i = (kValue)*kMask) {}");
@@ -5095,6 +5527,8 @@ TEST_F(FormatTest, BreaksLongDeclarations) {
"LoooooooooooooooooooooooooooooooongFunctionDeclaration();");
verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType\n"
"LooooooooooooooooooooooooooooooooooongFunctionDefinition() {}");
+ verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType MACRO\n"
+ "LooooooooooooooooooooooooooooooooooongFunctionDefinition() {}");
verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType const\n"
"LooooooooooooooooooooooooooooooooooongFunctionDefinition() {}");
verifyFormat("decltype(LoooooooooooooooooooooooooooooooooooooooongName)\n"
@@ -5156,6 +5590,10 @@ TEST_F(FormatTest, BreaksLongDeclarations) {
"aaaaaaaaaaaaaaaaaaaaaaaa<T>::aaaaaaa() {}");
verifyGoogleFormat("A<A<A>> aaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" int aaaaaaaaaaaaaaaaaaaaaaa);");
+
+ verifyFormat("typedef size_t (*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)(\n"
+ " const aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
}
TEST_F(FormatTest, FormatsArrays) {
@@ -5210,6 +5648,8 @@ TEST_F(FormatTest, HandlesIncludeDirectives) {
"#include <strstream>\n"
"#endif");
+ verifyFormat("#define MY_IMPORT <a/b>");
+
// Protocol buffer definition or missing "#".
verifyFormat("import \"aaaaaaaaaaaaaaaaa/aaaaaaaaaaaaaaa\";",
getLLVMStyleWithColumns(30));
@@ -5218,6 +5658,10 @@ TEST_F(FormatTest, HandlesIncludeDirectives) {
Style.AlwaysBreakBeforeMultilineStrings = true;
Style.ColumnLimit = 0;
verifyFormat("#import \"abc.h\"", Style);
+
+ // But 'import' might also be a regular C++ namespace.
+ verifyFormat("import::SomeFunction(aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
}
//===----------------------------------------------------------------------===//
@@ -5385,6 +5829,9 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
verifyFormat("int foo(int i) { return fo1{}(i); }");
verifyFormat("int foo(int i) { return fo1{}(i); }");
verifyFormat("auto i = decltype(x){};");
+ verifyFormat("std::vector<int> v = {1, 0 /* comment */};");
+ verifyFormat("Node n{1, Node{1000}, //\n"
+ " 2};");
// In combination with BinPackParameters = false.
FormatStyle NoBinPacking = getLLVMStyle();
@@ -5415,13 +5862,20 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
" kkkkkk,\n"
"};",
NoBinPacking);
+ verifyFormat(
+ "const Aaaaaa aaaaa = {\n"
+ " aaaaa, bbbbb, ccccc, ddddd, eeeee, ffffff, ggggg, hhhhhh,\n"
+ " iiiiii, jjjjjj, kkkkkk, aaaaa, bbbbb, ccccc, ddddd, eeeee,\n"
+ " ffffff, ggggg, hhhhhh, iiiiii, jjjjjj, kkkkkk,\n"
+ "};",
+ NoBinPacking);
// FIXME: The alignment of these trailing comments might be bad. Then again,
// this might be utterly useless in real code.
verifyFormat("Constructor::Constructor()\n"
- " : some_value{ //\n"
- " aaaaaaa //\n"
- " } {}");
+ " : some_value{ //\n"
+ " aaaaaaa, //\n"
+ " bbbbbbb} {}");
// In braced lists, the first comment is always assumed to belong to the
// first element. Thus, it can be moved to the next or previous line as
@@ -5445,6 +5899,13 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
" // Second element:\n"
" 2};",
getLLVMStyleWithColumns(30)));
+ // A trailing comma should still lead to an enforced line break.
+ EXPECT_EQ("vector<int> SomeVector = {\n"
+ " // aaa\n"
+ " 1, 2,\n"
+ "};",
+ format("vector<int> SomeVector = { // aaa\n"
+ " 1, 2, };"));
FormatStyle ExtraSpaces = getLLVMStyle();
ExtraSpaces.Cpp11BracedListStyle = false;
@@ -5473,32 +5934,24 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
" bbbbbbbbbbbbbbbbbbbb, bbbbb };",
ExtraSpaces);
verifyFormat("DoSomethingWithVector({} /* No data */);", ExtraSpaces);
- verifyFormat("DoSomethingWithVector({\n"
- " {} /* No data */\n"
- " },\n"
- " { { 1, 2 } });",
+ verifyFormat("DoSomethingWithVector({ {} /* No data */ }, { { 1, 2 } });",
ExtraSpaces);
verifyFormat(
"someFunction(OtherParam,\n"
" BracedList{ // comment 1 (Forcing interesting break)\n"
" param1, param2,\n"
" // comment 2\n"
- " param3, param4\n"
- " });",
+ " param3, param4 });",
ExtraSpaces);
verifyFormat(
"std::this_thread::sleep_for(\n"
" std::chrono::nanoseconds{ std::chrono::seconds{ 1 } } / 5);",
ExtraSpaces);
- verifyFormat("std::vector<MyValues> aaaaaaaaaaaaaaaaaaa{\n"
- " aaaaaaa, aaaaaaaaaa,\n"
- " aaaaa, aaaaaaaaaaaaaaa,\n"
- " aaa, aaaaaaaaaa,\n"
- " a, aaaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaa, a\n"
- "};",
- ExtraSpaces);
+ verifyFormat(
+ "std::vector<MyValues> aaaaaaaaaaaaaaaaaaa{\n"
+ " aaaaaaa, aaaaaaaaaa, aaaaa, aaaaaaaaaaaaaaa, aaa, aaaaaaaaaa, a,\n"
+ " aaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaa, aaaaaaa, a};");
verifyFormat("vector<int> foo = { ::SomeGlobalFunction() };", ExtraSpaces);
}
@@ -5546,10 +5999,9 @@ TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
" 1, 1, 1, 1, 1, 1, 1, 1, //\n"
"};",
getLLVMStyleWithColumns(39));
- verifyFormat("vector<int> x = {\n"
- " 1, 1, 1, 1, 1, 1, 1, 1,\n"
- " /**/ /**/\n"
- "};",
+ verifyFormat("vector<int> x = {1, 1, 1, 1,\n"
+ " 1, 1, 1, 1,\n"
+ " /**/ /**/};",
getLLVMStyleWithColumns(39));
verifyFormat("return {{aaaaaaaaaaaaaaaaaaaaa},\n"
" {aaaaaaaaaaaaaaaaaaa},\n"
@@ -6112,7 +6564,7 @@ TEST_F(FormatTest, FormatObjCInterface) {
"+ (id)init;\n"
"@end");
- verifyGoogleFormat("@interface Foo (HackStuff)<MyProtocol>\n"
+ verifyGoogleFormat("@interface Foo (HackStuff) <MyProtocol>\n"
"+ (id)init;\n"
"@end");
@@ -6154,7 +6606,7 @@ TEST_F(FormatTest, FormatObjCInterface) {
FormatStyle OnePerLine = getGoogleStyle();
OnePerLine.BinPackParameters = false;
- verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ()<\n"
+ verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa () <\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
@@ -6291,11 +6743,16 @@ TEST_F(FormatTest, FormatObjCMethodDeclarations) {
" evenLongerKeyword:(float)theInterval\n"
" error:(NSError **)theError {\n"
"}");
+ verifyFormat("- (instancetype)initXxxxxx:(id<x>)x\n"
+ " y:(id<yyyyyyyyyyyyyyyyyyyy>)y\n"
+ " NS_DESIGNATED_INITIALIZER;",
+ getLLVMStyleWithColumns(60));
}
TEST_F(FormatTest, FormatObjCMethodExpr) {
verifyFormat("[foo bar:baz];");
verifyFormat("return [foo bar:baz];");
+ verifyFormat("return (a)[foo bar:baz];");
verifyFormat("f([foo bar:baz]);");
verifyFormat("f(2, [foo bar:baz]);");
verifyFormat("f(2, a ? b : c);");
@@ -6353,8 +6810,10 @@ TEST_F(FormatTest, FormatObjCMethodExpr) {
// Whew!
verifyFormat("return in[42];");
+ verifyFormat("for (auto v : in[1]) {\n}");
verifyFormat("for (id foo in [self getStuffFor:bla]) {\n"
"}");
+ verifyFormat("[self aaaaa:MACRO(a, b:, c:)];");
verifyFormat("[self stuffWithInt:(4 + 2) float:4.5];");
verifyFormat("[self stuffWithInt:a ? b : c float:4.5];");
@@ -6408,17 +6867,16 @@ TEST_F(FormatTest, FormatObjCMethodExpr) {
" der:NO]);\n"
"}",
getLLVMStyleWithColumns(70));
- verifyFormat("{\n"
- " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n"
- " initWithContentRect:NSMakeRect(origin_global.x,\n"
- " origin_global.y,\n"
- " pos.width(),\n"
- " pos.height())\n"
- " styleMask:NSBorderlessWindowMask\n"
- " backing:NSBackingStoreBuffered\n"
- " defer:NO]);\n"
- "}",
- getChromiumStyle(FormatStyle::LK_Cpp));
+ verifyFormat(
+ "void f() {\n"
+ " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n"
+ " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n"
+ " pos.width(), pos.height())\n"
+ " styleMask:NSBorderlessWindowMask\n"
+ " backing:NSBackingStoreBuffered\n"
+ " defer:NO]);\n"
+ "}",
+ getChromiumStyle(FormatStyle::LK_Cpp));
verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n"
" with:contentsNativeView];");
@@ -6957,22 +7415,14 @@ TEST_F(FormatTest, BreaksWideAndNSStringLiterals) {
format("@\"NSString literal\";", getGoogleStyleWithColumns(19)));
}
-TEST_F(FormatTest, BreaksRawStringLiterals) {
- EXPECT_EQ("R\"x(raw )x\"\n"
- "R\"x(literal)x\";",
- format("R\"x(raw literal)x\";", getGoogleStyleWithColumns(15)));
- EXPECT_EQ("uR\"x(raw )x\"\n"
- "uR\"x(literal)x\";",
- format("uR\"x(raw literal)x\";", getGoogleStyleWithColumns(16)));
- EXPECT_EQ("u8R\"x(raw )x\"\n"
- "u8R\"x(literal)x\";",
- format("u8R\"x(raw literal)x\";", getGoogleStyleWithColumns(17)));
- EXPECT_EQ("LR\"x(raw )x\"\n"
- "LR\"x(literal)x\";",
- format("LR\"x(raw literal)x\";", getGoogleStyleWithColumns(16)));
- EXPECT_EQ("UR\"x(raw )x\"\n"
- "UR\"x(literal)x\";",
- format("UR\"x(raw literal)x\";", getGoogleStyleWithColumns(16)));
+TEST_F(FormatTest, DoesNotBreakRawStringLiterals) {
+ FormatStyle Style = getGoogleStyleWithColumns(15);
+ EXPECT_EQ("R\"x(raw literal)x\";", format("R\"x(raw literal)x\";", Style));
+ EXPECT_EQ("uR\"x(raw literal)x\";", format("uR\"x(raw literal)x\";", Style));
+ EXPECT_EQ("LR\"x(raw literal)x\";", format("LR\"x(raw literal)x\";", Style));
+ EXPECT_EQ("UR\"x(raw literal)x\";", format("UR\"x(raw literal)x\";", Style));
+ EXPECT_EQ("u8R\"x(raw literal)x\";",
+ format("u8R\"x(raw literal)x\";", Style));
}
TEST_F(FormatTest, BreaksStringLiteralsWithin_TMacro) {
@@ -7161,11 +7611,6 @@ TEST_F(FormatTest, DoNotBreakStringLiteralsInEscapeSequence) {
"\"00000000\"\n"
"\"1\"",
format("\"test\\000000000001\"", getLLVMStyleWithColumns(10)));
- // FIXME: We probably don't need to care about escape sequences in raw
- // literals.
- EXPECT_EQ("R\"(\\x)\"\n"
- "R\"(\\x00)\"\n",
- format("R\"(\\x\\x00)\"\n", getGoogleStyleWithColumns(7)));
}
TEST_F(FormatTest, DoNotCreateUnreasonableUnwrappedLines) {
@@ -7213,7 +7658,7 @@ TEST_F(FormatTest, ConfigurableIndentWidth) {
}
TEST_F(FormatTest, ConfigurableFunctionDeclarationIndentAfterType) {
- verifyFormat("void\n"
+ verifyFormat("double\n"
"f();",
getLLVMStyleWithColumns(8));
}
@@ -7353,11 +7798,10 @@ TEST_F(FormatTest, ConfigurableUseOfTab) {
Tab);
verifyFormat("{\n"
"\tQ({\n"
- "\t\t int a;\n"
- "\t\t someFunction(aaaaaaaaaa,\n"
- "\t\t bbbbbbbbb);\n"
- "\t },\n"
- "\t p);\n"
+ "\t\tint a;\n"
+ "\t\tsomeFunction(aaaaaaaa,\n"
+ "\t\t bbbbbbb);\n"
+ "\t}, p);\n"
"}",
Tab);
EXPECT_EQ("{\n"
@@ -7521,6 +7965,14 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) {
"default:\n"
" break;\n"
"}", NoSpace);
+ verifyFormat("auto i = std::make_unique<int>(5);", NoSpace);
+ verifyFormat("size_t x = sizeof(x);", NoSpace);
+ verifyFormat("auto f(int x) -> decltype(x);", NoSpace);
+ verifyFormat("int f(T x) noexcept(x.create());", NoSpace);
+ verifyFormat("alignas(128) char a[128];", NoSpace);
+ verifyFormat("size_t x = alignof(MyType);", NoSpace);
+ verifyFormat("static_assert(sizeof(char) == 1, \"Impossible!\");", NoSpace);
+ verifyFormat("int f() throw(Deprecated);", NoSpace);
FormatStyle Space = getLLVMStyle();
Space.SpaceBeforeParens = FormatStyle::SBPO_Always;
@@ -7557,6 +8009,14 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) {
verifyFormat("#if defined(x)\n"
"#endif",
Space);
+ verifyFormat("auto i = std::make_unique<int> (5);", Space);
+ verifyFormat("size_t x = sizeof (x);", Space);
+ verifyFormat("auto f (int x) -> decltype (x);", Space);
+ verifyFormat("int f (T x) noexcept (x.create ());", Space);
+ verifyFormat("alignas (128) char a[128];", Space);
+ verifyFormat("size_t x = alignof (MyType);", Space);
+ verifyFormat("static_assert (sizeof (char) == 1, \"Impossible!\");", Space);
+ verifyFormat("int f () throw (Deprecated);", Space);
}
TEST_F(FormatTest, ConfigurableSpacesInParentheses) {
@@ -7618,6 +8078,60 @@ TEST_F(FormatTest, ConfigurableSpacesInParentheses) {
"default:\n"
" break;\n"
"}", Spaces);
+
+ Spaces.SpaceAfterCStyleCast = true;
+ verifyFormat("call(x, y, z);", Spaces);
+ verifyFormat("while (( bool ) 1)\n"
+ " continue;",
+ Spaces);
+ verifyFormat("for (;;)\n"
+ " continue;",
+ Spaces);
+ verifyFormat("if (true)\n"
+ " f( );\n"
+ "else if (true)\n"
+ " f( );",
+ Spaces);
+ verifyFormat("do {\n"
+ " do_something(( int ) i);\n"
+ "} while (something( ));",
+ Spaces);
+ verifyFormat("switch (x) {\n"
+ "default:\n"
+ " break;\n"
+ "}",
+ Spaces);
+ Spaces.SpacesInCStyleCastParentheses = false;
+ Spaces.SpaceAfterCStyleCast = true;
+ verifyFormat("while ((bool) 1)\n"
+ " continue;",
+ Spaces);
+ verifyFormat("do {\n"
+ " do_something((int) i);\n"
+ "} while (something( ));",
+ Spaces);
+}
+
+TEST_F(FormatTest, ConfigurableSpacesInSquareBrackets) {
+ verifyFormat("int a[5];");
+ verifyFormat("a[3] += 42;");
+
+ FormatStyle Spaces = getLLVMStyle();
+ Spaces.SpacesInSquareBrackets = true;
+ // Lambdas unchanged.
+ verifyFormat("int c = []() -> int { return 2; }();\n", Spaces);
+ verifyFormat("return [i, args...] {};", Spaces);
+
+ // Not lambdas.
+ verifyFormat("int a[ 5 ];", Spaces);
+ verifyFormat("a[ 3 ] += 42;", Spaces);
+ verifyFormat("constexpr char hello[]{\"hello\"};", Spaces);
+ verifyFormat("double &operator[](int i) { return 0; }\n"
+ "int i;",
+ Spaces);
+ verifyFormat("std::unique_ptr<int[]> foo() {}", Spaces);
+ verifyFormat("int i = a[ a ][ a ]->f();", Spaces);
+ verifyFormat("int i = (*b)[ a ]->f();", Spaces);
}
TEST_F(FormatTest, ConfigurableSpaceBeforeAssignmentOperators) {
@@ -7633,8 +8147,8 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeAssignmentOperators) {
}
TEST_F(FormatTest, LinuxBraceBreaking) {
- FormatStyle BreakBeforeBrace = getLLVMStyle();
- BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Linux;
+ FormatStyle LinuxBraceStyle = getLLVMStyle();
+ LinuxBraceStyle.BreakBeforeBraces = FormatStyle::BS_Linux;
verifyFormat("namespace a\n"
"{\n"
"class A\n"
@@ -7647,14 +8161,33 @@ TEST_F(FormatTest, LinuxBraceBreaking) {
" }\n"
" }\n"
" void g() { return; }\n"
- "}\n"
- "}",
- BreakBeforeBrace);
+ "};\n"
+ "struct B {\n"
+ " int x;\n"
+ "};\n"
+ "}\n",
+ LinuxBraceStyle);
+ verifyFormat("enum X {\n"
+ " Y = 0,\n"
+ "}\n",
+ LinuxBraceStyle);
+ verifyFormat("struct S {\n"
+ " int Type;\n"
+ " union {\n"
+ " int x;\n"
+ " double y;\n"
+ " } Value;\n"
+ " class C\n"
+ " {\n"
+ " MyFavoriteType Value;\n"
+ " } Class;\n"
+ "}\n",
+ LinuxBraceStyle);
}
TEST_F(FormatTest, StroustrupBraceBreaking) {
- FormatStyle BreakBeforeBrace = getLLVMStyle();
- BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
+ FormatStyle StroustrupBraceStyle = getLLVMStyle();
+ StroustrupBraceStyle.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
verifyFormat("namespace a {\n"
"class A {\n"
" void f()\n"
@@ -7665,9 +8198,23 @@ TEST_F(FormatTest, StroustrupBraceBreaking) {
" }\n"
" }\n"
" void g() { return; }\n"
- "}\n"
- "}",
- BreakBeforeBrace);
+ "};\n"
+ "struct B {\n"
+ " int x;\n"
+ "};\n"
+ "}\n",
+ StroustrupBraceStyle);
+
+ verifyFormat("void foo()\n"
+ "{\n"
+ " if (a) {\n"
+ " a();\n"
+ " }\n"
+ " else {\n"
+ " b();\n"
+ " }\n"
+ "}\n",
+ StroustrupBraceStyle);
verifyFormat("#ifdef _DEBUG\n"
"int foo(int i = 0)\n"
@@ -7677,7 +8224,7 @@ TEST_F(FormatTest, StroustrupBraceBreaking) {
"{\n"
" return i;\n"
"}",
- BreakBeforeBrace);
+ StroustrupBraceStyle);
verifyFormat("void foo() {}\n"
"void bar()\n"
@@ -7689,7 +8236,7 @@ TEST_F(FormatTest, StroustrupBraceBreaking) {
"{\n"
"}\n"
"#endif",
- BreakBeforeBrace);
+ StroustrupBraceStyle);
verifyFormat("void foobar() { int i = 5; }\n"
"#ifdef _DEBUG\n"
@@ -7697,12 +8244,12 @@ TEST_F(FormatTest, StroustrupBraceBreaking) {
"#else\n"
"void bar() { foobar(); }\n"
"#endif",
- BreakBeforeBrace);
+ StroustrupBraceStyle);
}
TEST_F(FormatTest, AllmanBraceBreaking) {
- FormatStyle BreakBeforeBrace = getLLVMStyle();
- BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Allman;
+ FormatStyle AllmanBraceStyle = getLLVMStyle();
+ AllmanBraceStyle.BreakBeforeBraces = FormatStyle::BS_Allman;
verifyFormat("namespace a\n"
"{\n"
"class A\n"
@@ -7716,9 +8263,13 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
" }\n"
" }\n"
" void g() { return; }\n"
- "}\n"
+ "};\n"
+ "struct B\n"
+ "{\n"
+ " int x;\n"
+ "};\n"
"}",
- BreakBeforeBrace);
+ AllmanBraceStyle);
verifyFormat("void f()\n"
"{\n"
@@ -7735,7 +8286,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
" c();\n"
" }\n"
"}\n",
- BreakBeforeBrace);
+ AllmanBraceStyle);
verifyFormat("void f()\n"
"{\n"
@@ -7752,7 +8303,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
" c();\n"
" } while (false)\n"
"}\n",
- BreakBeforeBrace);
+ AllmanBraceStyle);
verifyFormat("void f(int a)\n"
"{\n"
@@ -7772,18 +8323,18 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
" break;\n"
" }\n"
"}\n",
- BreakBeforeBrace);
+ AllmanBraceStyle);
verifyFormat("enum X\n"
"{\n"
" Y = 0,\n"
"}\n",
- BreakBeforeBrace);
+ AllmanBraceStyle);
verifyFormat("enum X\n"
"{\n"
" Y = 0\n"
"}\n",
- BreakBeforeBrace);
+ AllmanBraceStyle);
verifyFormat("@interface BSApplicationController ()\n"
"{\n"
@@ -7791,7 +8342,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
" id _extraIvar;\n"
"}\n"
"@end\n",
- BreakBeforeBrace);
+ AllmanBraceStyle);
verifyFormat("#ifdef _DEBUG\n"
"int foo(int i = 0)\n"
@@ -7801,7 +8352,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
"{\n"
" return i;\n"
"}",
- BreakBeforeBrace);
+ AllmanBraceStyle);
verifyFormat("void foo() {}\n"
"void bar()\n"
@@ -7813,7 +8364,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
"{\n"
"}\n"
"#endif",
- BreakBeforeBrace);
+ AllmanBraceStyle);
verifyFormat("void foobar() { int i = 5; }\n"
"#ifdef _DEBUG\n"
@@ -7821,37 +8372,42 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
"#else\n"
"void bar() { foobar(); }\n"
"#endif",
- BreakBeforeBrace);
+ AllmanBraceStyle);
// This shouldn't affect ObjC blocks..
verifyFormat("[self doSomeThingWithACompletionHandler:^{\n"
- " // ...\n"
- " int i;\n"
+ " // ...\n"
+ " int i;\n"
"}];",
- BreakBeforeBrace);
+ AllmanBraceStyle);
verifyFormat("void (^block)(void) = ^{\n"
- " // ...\n"
- " int i;\n"
+ " // ...\n"
+ " int i;\n"
"};",
- BreakBeforeBrace);
+ AllmanBraceStyle);
// .. or dict literals.
verifyFormat("void f()\n"
"{\n"
" [object someMethod:@{ @\"a\" : @\"b\" }];\n"
"}",
- BreakBeforeBrace);
+ AllmanBraceStyle);
+ verifyFormat("int f()\n"
+ "{ // comment\n"
+ " return 42;\n"
+ "}",
+ AllmanBraceStyle);
- BreakBeforeBrace.ColumnLimit = 19;
- verifyFormat("void f() { int i; }", BreakBeforeBrace);
- BreakBeforeBrace.ColumnLimit = 18;
+ AllmanBraceStyle.ColumnLimit = 19;
+ verifyFormat("void f() { int i; }", AllmanBraceStyle);
+ AllmanBraceStyle.ColumnLimit = 18;
verifyFormat("void f()\n"
"{\n"
" int i;\n"
"}",
- BreakBeforeBrace);
- BreakBeforeBrace.ColumnLimit = 80;
+ AllmanBraceStyle);
+ AllmanBraceStyle.ColumnLimit = 80;
- FormatStyle BreakBeforeBraceShortIfs = BreakBeforeBrace;
+ FormatStyle BreakBeforeBraceShortIfs = AllmanBraceStyle;
BreakBeforeBraceShortIfs.AllowShortIfStatementsOnASingleLine = true;
BreakBeforeBraceShortIfs.AllowShortLoopsOnASingleLine = true;
verifyFormat("void f(bool b)\n"
@@ -8108,34 +8664,41 @@ TEST_F(FormatTest, GetsCorrectBasedOnStyle) {
EXPECT_ALL_STYLES_EQUAL(Styles);
}
+#define CHECK_PARSE_BOOL_FIELD(FIELD, CONFIG_NAME) \
+ Style.FIELD = false; \
+ EXPECT_EQ(0, parseConfiguration(CONFIG_NAME ": true", &Style).value()); \
+ EXPECT_TRUE(Style.FIELD); \
+ EXPECT_EQ(0, parseConfiguration(CONFIG_NAME ": false", &Style).value()); \
+ EXPECT_FALSE(Style.FIELD);
+
+#define CHECK_PARSE_BOOL(FIELD) CHECK_PARSE_BOOL_FIELD(FIELD, #FIELD)
+
#define CHECK_PARSE(TEXT, FIELD, VALUE) \
EXPECT_NE(VALUE, Style.FIELD); \
EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value()); \
EXPECT_EQ(VALUE, Style.FIELD)
-#define CHECK_PARSE_BOOL(FIELD) \
- Style.FIELD = false; \
- EXPECT_EQ(0, parseConfiguration(#FIELD ": true", &Style).value()); \
- EXPECT_TRUE(Style.FIELD); \
- EXPECT_EQ(0, parseConfiguration(#FIELD ": false", &Style).value()); \
- EXPECT_FALSE(Style.FIELD);
-
-TEST_F(FormatTest, ParsesConfiguration) {
+TEST_F(FormatTest, ParsesConfigurationBools) {
FormatStyle Style = {};
Style.Language = FormatStyle::LK_Cpp;
+ CHECK_PARSE_BOOL(AlignAfterOpenBracket);
CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft);
+ CHECK_PARSE_BOOL(AlignOperands);
CHECK_PARSE_BOOL(AlignTrailingComments);
CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
CHECK_PARSE_BOOL(AllowShortBlocksOnASingleLine);
+ CHECK_PARSE_BOOL(AllowShortCaseLabelsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine);
+ CHECK_PARSE_BOOL(AlwaysBreakAfterDefinitionReturnType);
CHECK_PARSE_BOOL(AlwaysBreakTemplateDeclarations);
CHECK_PARSE_BOOL(BinPackParameters);
- CHECK_PARSE_BOOL(BreakBeforeBinaryOperators);
+ CHECK_PARSE_BOOL(BinPackArguments);
CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
CHECK_PARSE_BOOL(BreakConstructorInitializersBeforeComma);
CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine);
CHECK_PARSE_BOOL(DerivePointerAlignment);
+ CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding");
CHECK_PARSE_BOOL(IndentCaseLabels);
CHECK_PARSE_BOOL(IndentWrappedFunctionNames);
CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks);
@@ -8143,15 +8706,24 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
CHECK_PARSE_BOOL(Cpp11BracedListStyle);
CHECK_PARSE_BOOL(SpacesInParentheses);
+ CHECK_PARSE_BOOL(SpacesInSquareBrackets);
CHECK_PARSE_BOOL(SpacesInAngles);
CHECK_PARSE_BOOL(SpaceInEmptyParentheses);
CHECK_PARSE_BOOL(SpacesInContainerLiterals);
CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses);
+ CHECK_PARSE_BOOL(SpaceAfterCStyleCast);
CHECK_PARSE_BOOL(SpaceBeforeAssignmentOperators);
+}
+
+#undef CHECK_PARSE_BOOL
+TEST_F(FormatTest, ParsesConfiguration) {
+ FormatStyle Style = {};
+ Style.Language = FormatStyle::LK_Cpp;
CHECK_PARSE("AccessModifierOffset: -1234", AccessModifierOffset, -1234);
CHECK_PARSE("ConstructorInitializerIndentWidth: 1234",
ConstructorInitializerIndentWidth, 1234u);
+ CHECK_PARSE("ObjCBlockIndentWidth: 1234", ObjCBlockIndentWidth, 1234u);
CHECK_PARSE("ColumnLimit: 1234", ColumnLimit, 1234u);
CHECK_PARSE("MaxEmptyLinesToKeep: 1234", MaxEmptyLinesToKeep, 1234u);
CHECK_PARSE("PenaltyBreakBeforeFirstCallParameter: 1234",
@@ -8165,9 +8737,19 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE("ContinuationIndentWidth: 11", ContinuationIndentWidth, 11u);
Style.PointerAlignment = FormatStyle::PAS_Middle;
- CHECK_PARSE("PointerAlignment: Left", PointerAlignment, FormatStyle::PAS_Left);
- CHECK_PARSE("PointerAlignment: Right", PointerAlignment, FormatStyle::PAS_Right);
- CHECK_PARSE("PointerAlignment: Middle", PointerAlignment, FormatStyle::PAS_Middle);
+ CHECK_PARSE("PointerAlignment: Left", PointerAlignment,
+ FormatStyle::PAS_Left);
+ CHECK_PARSE("PointerAlignment: Right", PointerAlignment,
+ FormatStyle::PAS_Right);
+ CHECK_PARSE("PointerAlignment: Middle", PointerAlignment,
+ FormatStyle::PAS_Middle);
+ // For backward compatibility:
+ CHECK_PARSE("PointerBindsToType: Left", PointerAlignment,
+ FormatStyle::PAS_Left);
+ CHECK_PARSE("PointerBindsToType: Right", PointerAlignment,
+ FormatStyle::PAS_Right);
+ CHECK_PARSE("PointerBindsToType: Middle", PointerAlignment,
+ FormatStyle::PAS_Middle);
Style.Standard = FormatStyle::LS_Auto;
CHECK_PARSE("Standard: Cpp03", Standard, FormatStyle::LS_Cpp03);
@@ -8176,24 +8758,41 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE("Standard: C++11", Standard, FormatStyle::LS_Cpp11);
CHECK_PARSE("Standard: Auto", Standard, FormatStyle::LS_Auto);
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
+ CHECK_PARSE("BreakBeforeBinaryOperators: NonAssignment",
+ BreakBeforeBinaryOperators, FormatStyle::BOS_NonAssignment);
+ CHECK_PARSE("BreakBeforeBinaryOperators: None", BreakBeforeBinaryOperators,
+ FormatStyle::BOS_None);
+ CHECK_PARSE("BreakBeforeBinaryOperators: All", BreakBeforeBinaryOperators,
+ FormatStyle::BOS_All);
+ // For backward compatibility:
+ CHECK_PARSE("BreakBeforeBinaryOperators: false", BreakBeforeBinaryOperators,
+ FormatStyle::BOS_None);
+ CHECK_PARSE("BreakBeforeBinaryOperators: true", BreakBeforeBinaryOperators,
+ FormatStyle::BOS_All);
+
Style.UseTab = FormatStyle::UT_ForIndentation;
- CHECK_PARSE("UseTab: false", UseTab, FormatStyle::UT_Never);
- CHECK_PARSE("UseTab: true", UseTab, FormatStyle::UT_Always);
CHECK_PARSE("UseTab: Never", UseTab, FormatStyle::UT_Never);
CHECK_PARSE("UseTab: ForIndentation", UseTab, FormatStyle::UT_ForIndentation);
CHECK_PARSE("UseTab: Always", UseTab, FormatStyle::UT_Always);
+ // For backward compatibility:
+ CHECK_PARSE("UseTab: false", UseTab, FormatStyle::UT_Never);
+ CHECK_PARSE("UseTab: true", UseTab, FormatStyle::UT_Always);
Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
- CHECK_PARSE("AllowShortFunctionsOnASingleLine: false",
- AllowShortFunctionsOnASingleLine, FormatStyle::SFS_None);
- CHECK_PARSE("AllowShortFunctionsOnASingleLine: true",
- AllowShortFunctionsOnASingleLine, FormatStyle::SFS_All);
CHECK_PARSE("AllowShortFunctionsOnASingleLine: None",
AllowShortFunctionsOnASingleLine, FormatStyle::SFS_None);
CHECK_PARSE("AllowShortFunctionsOnASingleLine: Inline",
AllowShortFunctionsOnASingleLine, FormatStyle::SFS_Inline);
+ CHECK_PARSE("AllowShortFunctionsOnASingleLine: Empty",
+ AllowShortFunctionsOnASingleLine, FormatStyle::SFS_Empty);
CHECK_PARSE("AllowShortFunctionsOnASingleLine: All",
AllowShortFunctionsOnASingleLine, FormatStyle::SFS_All);
+ // For backward compatibility:
+ CHECK_PARSE("AllowShortFunctionsOnASingleLine: false",
+ AllowShortFunctionsOnASingleLine, FormatStyle::SFS_None);
+ CHECK_PARSE("AllowShortFunctionsOnASingleLine: true",
+ AllowShortFunctionsOnASingleLine, FormatStyle::SFS_All);
Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
CHECK_PARSE("SpaceBeforeParens: Never", SpaceBeforeParens,
@@ -8344,7 +8943,6 @@ TEST_F(FormatTest, ParsesConfigurationWithLanguages) {
}
#undef CHECK_PARSE
-#undef CHECK_PARSE_BOOL
TEST_F(FormatTest, UsesLanguageForBasedOnStyle) {
FormatStyle Style = {};
@@ -8519,7 +9117,10 @@ TEST_F(FormatTest, ConstructorInitializerIndentWidth) {
": aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
" aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
Style);
+}
+TEST_F(FormatTest, BreakConstructorInitializersBeforeComma) {
+ FormatStyle Style = getLLVMStyle();
Style.BreakConstructorInitializersBeforeComma = true;
Style.ConstructorInitializerIndentWidth = 4;
verifyFormat("SomeClass::Constructor()\n"
@@ -8592,6 +9193,11 @@ TEST_F(FormatTest, ConstructorInitializerIndentWidth) {
Style);
}
+TEST_F(FormatTest, Destructors) {
+ verifyFormat("void F(int &i) { i.~int(); }");
+ verifyFormat("void F(int &i) { i->~int(); }");
+}
+
TEST_F(FormatTest, FormatsWithWebKitStyle) {
FormatStyle Style = getWebKitStyle();
@@ -8644,7 +9250,7 @@ TEST_F(FormatTest, FormatsWithWebKitStyle) {
verifyFormat("Constructor()\n"
" : aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
" , aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaa, // break\n"
- " aaaaaaaaaaaaaa)\n"
+ " aaaaaaaaaaaaaa)\n"
" , aaaaaaaaaaaaaaaaaaaaaaa()\n"
"{\n"
"}",
@@ -8685,6 +9291,11 @@ TEST_F(FormatTest, FormatsWithWebKitStyle) {
"double b; // align comments.",
Style);
+ // Do not align operands.
+ EXPECT_EQ("ASSERT(aaaa\n"
+ " || bbbb);",
+ format("ASSERT ( aaaa\n||bbbb);", Style));
+
// Accept input's line breaks.
EXPECT_EQ("if (aaaaaaaaaaaaaaa\n"
" || bbbbbbbbbbbbbbb) {\n"
@@ -8764,30 +9375,50 @@ TEST_F(FormatTest, FormatsLambdas) {
verifyFormat("SomeFunction([]() { // A cool function...\n"
" return 43;\n"
"});");
+ EXPECT_EQ("SomeFunction([]() {\n"
+ "#define A a\n"
+ " return 43;\n"
+ "});",
+ format("SomeFunction([](){\n"
+ "#define A a\n"
+ "return 43;\n"
+ "});"));
verifyFormat("void f() {\n"
" SomeFunction([](decltype(x), A *a) {});\n"
"}");
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" [](const aaaaaaaaaa &a) { return a; });");
+ verifyFormat("string abc = SomeFunction(aaaaaaaaaaaaa, aaaaa, []() {\n"
+ " SomeOtherFunctioooooooooooooooooooooooooon();\n"
+ "});");
+ verifyFormat("Constructor()\n"
+ " : Field([] { // comment\n"
+ " int i;\n"
+ " }) {}");
// Lambdas with return types.
verifyFormat("int c = []() -> int { return 2; }();\n");
verifyFormat("int c = []() -> vector<int> { return {2}; }();\n");
verifyFormat("Foo([]() -> std::vector<int> { return {2}; }());");
+ verifyGoogleFormat("auto a = [&b, c](D* d) -> D* {};");
+ verifyGoogleFormat("auto a = [&b, c](D* d) -> pair<D*, D*> {};");
+ verifyGoogleFormat("auto a = [&b, c](D* d) -> D& {};");
+ verifyGoogleFormat("auto a = [&b, c](D* d) -> const D* {};");
verifyFormat("auto aaaaaaaa = [](int i, // break for some reason\n"
" int j) -> int {\n"
" return ffffffffffffffffffffffffffffffffffffffffffff(i * j);\n"
"};");
// Multiple lambdas in the same parentheses change indentation rules.
- verifyFormat("SomeFunction([]() {\n"
- " int i = 42;\n"
- " return i;\n"
- " },\n"
- " []() {\n"
- " int j = 43;\n"
- " return j;\n"
- " });");
+ verifyFormat("SomeFunction(\n"
+ " []() {\n"
+ " int i = 42;\n"
+ " return i;\n"
+ " },\n"
+ " []() {\n"
+ " int j = 43;\n"
+ " return j;\n"
+ " });");
// More complex introducers.
verifyFormat("return [i, args...] {};");
@@ -8810,89 +9441,113 @@ TEST_F(FormatTest, FormatsLambdas) {
verifyFormat("void f() {\n"
" MACRO((const AA &a) { return 1; });\n"
"}");
+
+ verifyFormat("if (blah_blah(whatever, whatever, [] {\n"
+ " doo_dah();\n"
+ " doo_dah();\n"
+ " })) {\n"
+ "}");
}
TEST_F(FormatTest, FormatsBlocks) {
- verifyFormat("int (^Block)(int, int);");
- verifyFormat("int (^Block1)(int, int) = ^(int i, int j)");
- verifyFormat("void (^block)(int) = ^(id test) { int i; };");
- verifyFormat("void (^block)(int) = ^(int test) { int i; };");
- verifyFormat("void (^block)(int) = ^id(int test) { int i; };");
- verifyFormat("void (^block)(int) = ^int(int test) { int i; };");
-
- verifyFormat("foo(^{ bar(); });");
- verifyFormat("foo(a, ^{ bar(); });");
-
- // FIXME: Make whitespace formatting consistent. Ask a ObjC dev how
- // it would ideally look.
- verifyFormat("[operation setCompletionBlock:^{ [self onOperationDone]; }];");
- verifyFormat("int i = {[operation setCompletionBlock : ^{ [self "
- "onOperationDone]; }]};");
- verifyFormat("[operation setCompletionBlock:^(int *i) { f(); }];");
- verifyFormat("int a = [operation block:^int(int *i) { return 1; }];");
+ FormatStyle ShortBlocks = getLLVMStyle();
+ ShortBlocks.AllowShortBlocksOnASingleLine = true;
+ verifyFormat("int (^Block)(int, int);", ShortBlocks);
+ verifyFormat("int (^Block1)(int, int) = ^(int i, int j)", ShortBlocks);
+ verifyFormat("void (^block)(int) = ^(id test) { int i; };", ShortBlocks);
+ verifyFormat("void (^block)(int) = ^(int test) { int i; };", ShortBlocks);
+ verifyFormat("void (^block)(int) = ^id(int test) { int i; };", ShortBlocks);
+ verifyFormat("void (^block)(int) = ^int(int test) { int i; };", ShortBlocks);
+
+ verifyFormat("foo(^{ bar(); });", ShortBlocks);
+ verifyFormat("foo(a, ^{ bar(); });", ShortBlocks);
+ verifyFormat("{ void (^block)(Object *x); }", ShortBlocks);
+
+ verifyFormat("[operation setCompletionBlock:^{\n"
+ " [self onOperationDone];\n"
+ "}];");
+ verifyFormat("int i = {[operation setCompletionBlock:^{\n"
+ " [self onOperationDone];\n"
+ "}]};");
+ verifyFormat("[operation setCompletionBlock:^(int *i) {\n"
+ " f();\n"
+ "}];");
+ verifyFormat("int a = [operation block:^int(int *i) {\n"
+ " return 1;\n"
+ "}];");
verifyFormat("[myObject doSomethingWith:arg1\n"
- " aaa:^int(int *a) { return 1; }\n"
+ " aaa:^int(int *a) {\n"
+ " return 1;\n"
+ " }\n"
" bbb:f(a * bbbbbbbb)];");
verifyFormat("[operation setCompletionBlock:^{\n"
- " [self.delegate newDataAvailable];\n"
+ " [self.delegate newDataAvailable];\n"
"}];",
getLLVMStyleWithColumns(60));
verifyFormat("dispatch_async(_fileIOQueue, ^{\n"
- " NSString *path = [self sessionFilePath];\n"
- " if (path) {\n"
- " // ...\n"
- " }\n"
+ " NSString *path = [self sessionFilePath];\n"
+ " if (path) {\n"
+ " // ...\n"
+ " }\n"
"});");
verifyFormat("[[SessionService sharedService]\n"
" loadWindowWithCompletionBlock:^(SessionWindow *window) {\n"
- " if (window) {\n"
- " [self windowDidLoad:window];\n"
- " } else {\n"
- " [self errorLoadingWindow];\n"
- " }\n"
+ " if (window) {\n"
+ " [self windowDidLoad:window];\n"
+ " } else {\n"
+ " [self errorLoadingWindow];\n"
+ " }\n"
" }];");
verifyFormat("void (^largeBlock)(void) = ^{\n"
- " // ...\n"
+ " // ...\n"
"};\n",
getLLVMStyleWithColumns(40));
verifyFormat("[[SessionService sharedService]\n"
" loadWindowWithCompletionBlock: //\n"
" ^(SessionWindow *window) {\n"
- " if (window) {\n"
- " [self windowDidLoad:window];\n"
- " } else {\n"
- " [self errorLoadingWindow];\n"
- " }\n"
+ " if (window) {\n"
+ " [self windowDidLoad:window];\n"
+ " } else {\n"
+ " [self errorLoadingWindow];\n"
+ " }\n"
" }];",
getLLVMStyleWithColumns(60));
verifyFormat("[myObject doSomethingWith:arg1\n"
" firstBlock:^(Foo *a) {\n"
- " // ...\n"
- " int i;\n"
+ " // ...\n"
+ " int i;\n"
" }\n"
" secondBlock:^(Bar *b) {\n"
- " // ...\n"
- " int i;\n"
+ " // ...\n"
+ " int i;\n"
" }\n"
" thirdBlock:^Foo(Bar *b) {\n"
- " // ...\n"
- " int i;\n"
+ " // ...\n"
+ " int i;\n"
" }];");
verifyFormat("[myObject doSomethingWith:arg1\n"
" firstBlock:-1\n"
" secondBlock:^(Bar *b) {\n"
- " // ...\n"
- " int i;\n"
+ " // ...\n"
+ " int i;\n"
" }];");
verifyFormat("f(^{\n"
- " @autoreleasepool {\n"
- " if (a) {\n"
- " g();\n"
- " }\n"
+ " @autoreleasepool {\n"
+ " if (a) {\n"
+ " g();\n"
" }\n"
+ " }\n"
"});");
+ verifyFormat("Block b = ^int *(A *a, B *b) {}");
+
+ FormatStyle FourIndent = getLLVMStyle();
+ FourIndent.ObjCBlockIndentWidth = 4;
+ verifyFormat("[operation setCompletionBlock:^{\n"
+ " [self onOperationDone];\n"
+ "}];",
+ FourIndent);
}
TEST_F(FormatTest, SupportsCRLF) {
@@ -9097,5 +9752,32 @@ TEST_F(FormatTest, HandleConflictMarkers) {
"int i;\n"));
}
+TEST_F(FormatTest, DisableRegions) {
+ EXPECT_EQ("int i;\n"
+ "// clang-format off\n"
+ " int j;\n"
+ "// clang-format on\n"
+ "int k;",
+ format(" int i;\n"
+ " // clang-format off\n"
+ " int j;\n"
+ " // clang-format on\n"
+ " int k;"));
+ EXPECT_EQ("int i;\n"
+ "/* clang-format off */\n"
+ " int j;\n"
+ "/* clang-format on */\n"
+ "int k;",
+ format(" int i;\n"
+ " /* clang-format off */\n"
+ " int j;\n"
+ " /* clang-format on */\n"
+ " int k;"));
+}
+
+TEST_F(FormatTest, DoNotCrashOnInvalidInput) {
+ format("? ) =");
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
index f8802b85d606..780b02f746e9 100644
--- a/unittests/Format/FormatTestJS.cpp
+++ b/unittests/Format/FormatTestJS.cpp
@@ -81,11 +81,23 @@ TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) {
getGoogleJSStyleWithColumns(20));
verifyFormat("var b = a.map((x) => x + 1);");
+ verifyFormat("return ('aaa') in bbbb;");
+}
+
+TEST_F(FormatTestJS, UnderstandsAmpAmp) {
+ verifyFormat("e && e.SomeFunction();");
+}
+
+TEST_F(FormatTestJS, LiteralOperatorsCanBeKeywords) {
+ verifyFormat("not.and.or.not_eq = 1;");
}
TEST_F(FormatTestJS, ES6DestructuringAssignment) {
verifyFormat("var [a, b, c] = [1, 2, 3];");
- verifyFormat("var {a, b} = {a: 1, b: 2};");
+ verifyFormat("var {a, b} = {\n"
+ " a: 1,\n"
+ " b: 2\n"
+ "};");
}
TEST_F(FormatTestJS, ContainerLiterals) {
@@ -102,29 +114,45 @@ TEST_F(FormatTestJS, ContainerLiterals) {
"};");
verifyFormat("return {\n"
" a: a,\n"
- " link:\n"
- " function() {\n"
- " f(); //\n"
- " },\n"
- " link:\n"
- " function() {\n"
- " f(); //\n"
- " }\n"
+ " link: function() {\n"
+ " f(); //\n"
+ " },\n"
+ " link: function() {\n"
+ " f(); //\n"
+ " }\n"
+ "};");
+ verifyFormat("var stuff = {\n"
+ " // comment for update\n"
+ " update: false,\n"
+ " // comment for modules\n"
+ " modules: false,\n"
+ " // comment for tasks\n"
+ " tasks: false\n"
+ "};");
+ verifyFormat("return {\n"
+ " 'finish':\n"
+ " //\n"
+ " a\n"
+ "};");
+ verifyFormat("var obj = {\n"
+ " fooooooooo: function(x) {\n"
+ " return x.zIsTooLongForOneLineWithTheDeclarationLine();\n"
+ " }\n"
"};");
}
TEST_F(FormatTestJS, SpacesInContainerLiterals) {
verifyFormat("var arr = [1, 2, 3];");
- verifyFormat("var obj = {a: 1, b: 2, c: 3};");
+ verifyFormat("f({a: 1, b: 2, c: 3});");
verifyFormat("var object_literal_with_long_name = {\n"
" a: 'aaaaaaaaaaaaaaaaaa',\n"
" b: 'bbbbbbbbbbbbbbbbbb'\n"
"};");
- verifyFormat("var obj = {a: 1, b: 2, c: 3};",
+ verifyFormat("f({a: 1, b: 2, c: 3});",
getChromiumStyle(FormatStyle::LK_JavaScript));
- verifyFormat("someVariable = {'a': [{}]};");
+ verifyFormat("f({'a': [{}]});");
}
TEST_F(FormatTestJS, SingleQuoteStrings) {
@@ -138,6 +166,22 @@ TEST_F(FormatTestJS, GoogScopes) {
"}); // goog.scope");
}
+TEST_F(FormatTestJS, GoogModules) {
+ verifyFormat("goog.module('this.is.really.absurdly.long');",
+ getGoogleJSStyleWithColumns(40));
+ verifyFormat("goog.require('this.is.really.absurdly.long');",
+ getGoogleJSStyleWithColumns(40));
+ verifyFormat("goog.provide('this.is.really.absurdly.long');",
+ getGoogleJSStyleWithColumns(40));
+ verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
+ getGoogleJSStyleWithColumns(40));
+
+ // These should be wrapped normally.
+ verifyFormat(
+ "var MyLongClassName =\n"
+ " goog.module.get('my.long.module.name.followedBy.MyLongClassName');");
+}
+
TEST_F(FormatTestJS, FormatsFreestandingFunctions) {
verifyFormat("function outer1(a, b) {\n"
" function inner1(a, b) { return a; }\n"
@@ -150,8 +194,11 @@ TEST_F(FormatTestJS, FormatsFreestandingFunctions) {
}
TEST_F(FormatTestJS, FunctionLiterals) {
+ verifyFormat("doFoo(function() {});");
verifyFormat("doFoo(function() { return 1; });");
- verifyFormat("var func = function() { return 1; };");
+ verifyFormat("var func = function() {\n"
+ " return 1;\n"
+ "};");
verifyFormat("return {\n"
" body: {\n"
" setAttribute: function(key, val) { this[key] = val; },\n"
@@ -159,7 +206,13 @@ TEST_F(FormatTestJS, FunctionLiterals) {
" style: {direction: ''}\n"
" }\n"
"};");
- EXPECT_EQ("abc = xyz ? function() { return 1; } : function() { return -1; };",
+ EXPECT_EQ("abc = xyz ?\n"
+ " function() {\n"
+ " return 1;\n"
+ " } :\n"
+ " function() {\n"
+ " return -1;\n"
+ " };",
format("abc=xyz?function(){return 1;}:function(){return -1;};"));
verifyFormat("var closure = goog.bind(\n"
@@ -181,13 +234,18 @@ TEST_F(FormatTestJS, FunctionLiterals) {
" };\n"
" }\n"
"};");
+ verifyFormat("{\n"
+ " var someVariable = function(x) {\n"
+ " return x.zIsTooLongForOneLineWithTheDeclarationLine();\n"
+ " };\n"
+ "}");
- verifyFormat("var x = {a: function() { return 1; }};",
- getGoogleJSStyleWithColumns(38));
- verifyFormat("var x = {\n"
+ verifyFormat("f({a: function() { return 1; }});",
+ getGoogleJSStyleWithColumns(33));
+ verifyFormat("f({\n"
" a: function() { return 1; }\n"
- "};",
- getGoogleJSStyleWithColumns(37));
+ "});",
+ getGoogleJSStyleWithColumns(32));
verifyFormat("return {\n"
" a: function SomeFunction() {\n"
@@ -195,6 +253,74 @@ TEST_F(FormatTestJS, FunctionLiterals) {
" return 1;\n"
" }\n"
"};");
+ verifyFormat("this.someObject.doSomething(aaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " .then(goog.bind(function(aaaaaaaaaaa) {\n"
+ " someFunction();\n"
+ " someFunction();\n"
+ " }, this), aaaaaaaaaaaaaaaaa);");
+
+ // FIXME: This is not ideal yet.
+ verifyFormat("someFunction(goog.bind(\n"
+ " function() {\n"
+ " doSomething();\n"
+ " doSomething();\n"
+ " },\n"
+ " this),\n"
+ " goog.bind(function() {\n"
+ " doSomething();\n"
+ " doSomething();\n"
+ " }, this));");
+}
+
+TEST_F(FormatTestJS, InliningFunctionLiterals) {
+ FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
+ verifyFormat("var func = function() {\n"
+ " return 1;\n"
+ "};",
+ Style);
+ verifyFormat("var func = doSomething(function() { return 1; });", Style);
+ verifyFormat("var outer = function() {\n"
+ " var inner = function() { return 1; }\n"
+ "};",
+ Style);
+ verifyFormat("function outer1(a, b) {\n"
+ " function inner1(a, b) { return a; }\n"
+ "}",
+ Style);
+
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
+ verifyFormat("var func = function() { return 1; };", Style);
+ verifyFormat("var func = doSomething(function() { return 1; });", Style);
+ verifyFormat(
+ "var outer = function() { var inner = function() { return 1; } };",
+ Style);
+ verifyFormat("function outer1(a, b) {\n"
+ " function inner1(a, b) { return a; }\n"
+ "}",
+ Style);
+
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
+ verifyFormat("var func = function() {\n"
+ " return 1;\n"
+ "};",
+ Style);
+ verifyFormat("var func = doSomething(function() {\n"
+ " return 1;\n"
+ "});",
+ Style);
+ verifyFormat("var outer = function() {\n"
+ " var inner = function() {\n"
+ " return 1;\n"
+ " }\n"
+ "};",
+ Style);
+ verifyFormat("function outer1(a, b) {\n"
+ " function inner1(a, b) {\n"
+ " return a;\n"
+ " }\n"
+ "}",
+ Style);
}
TEST_F(FormatTestJS, MultipleFunctionLiterals) {
@@ -228,10 +354,33 @@ TEST_F(FormatTestJS, MultipleFunctionLiterals) {
" doFoo();\n"
" doBaz();\n"
" });\n");
+
+ verifyFormat("getSomeLongPromise()\n"
+ " .then(function(value) { body(); })\n"
+ " .thenCatch(function(error) {\n"
+ " body();\n"
+ " body();\n"
+ " });");
+ verifyFormat("getSomeLongPromise()\n"
+ " .then(function(value) {\n"
+ " body();\n"
+ " body();\n"
+ " })\n"
+ " .thenCatch(function(error) {\n"
+ " body();\n"
+ " body();\n"
+ " });");
+
+ // FIXME: This is bad, but it used to be formatted correctly by accident.
+ verifyFormat("getSomeLongPromise().then(function(value) {\n"
+ " body();\n"
+ "}).thenCatch(function(error) { body(); });");
}
TEST_F(FormatTestJS, ReturnStatements) {
- verifyFormat("function() { return [hello, world]; }");
+ verifyFormat("function() {\n"
+ " return [hello, world];\n"
+ "}");
}
TEST_F(FormatTestJS, ClosureStyleComments) {
@@ -246,6 +395,11 @@ TEST_F(FormatTestJS, TryCatch) {
"} finally {\n"
" h();\n"
"}");
+
+ // But, of course, "catch" is a perfectly fine function name in JavaScript.
+ verifyFormat("someObject.catch();");
+ verifyFormat("someObject.new();");
+ verifyFormat("someObject.delete();");
}
TEST_F(FormatTestJS, StringLiteralConcatenation) {
@@ -307,6 +461,12 @@ TEST_F(FormatTestJS, RegexLiteralSpecialCharacters) {
verifyFormat("var regex = /\\\\/g;");
verifyFormat("var regex = /\\a\\\\/g;");
verifyFormat("var regex = /\a\\//g;");
+ verifyFormat("var regex = /a\\//;\n"
+ "var x = 0;");
+ EXPECT_EQ("var regex = /\\/*/;\n"
+ "var x = 0;",
+ format("var regex = /\\/*/;\n"
+ "var x=0;"));
}
TEST_F(FormatTestJS, RegexLiteralModifiers) {
@@ -322,6 +482,8 @@ TEST_F(FormatTestJS, RegexLiteralLength) {
verifyFormat("var regex =\n"
" /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
getGoogleJSStyleWithColumns(60));
+ verifyFormat("var regex = /\\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
+ getGoogleJSStyleWithColumns(50));
}
TEST_F(FormatTestJS, RegexLiteralExamples) {
diff --git a/unittests/Format/FormatTestJava.cpp b/unittests/Format/FormatTestJava.cpp
new file mode 100644
index 000000000000..8d6daa62a599
--- /dev/null
+++ b/unittests/Format/FormatTestJava.cpp
@@ -0,0 +1,492 @@
+//===- unittest/Format/FormatTestJava.cpp - Formatting tests for Java -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatTestUtils.h"
+#include "clang/Format/Format.h"
+#include "llvm/Support/Debug.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "format-test"
+
+namespace clang {
+namespace format {
+
+class FormatTestJava : public ::testing::Test {
+protected:
+ static std::string format(llvm::StringRef Code, unsigned Offset,
+ unsigned Length, const FormatStyle &Style) {
+ DEBUG(llvm::errs() << "---\n");
+ DEBUG(llvm::errs() << Code << "\n\n");
+ std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
+ tooling::Replacements Replaces = reformat(Style, Code, Ranges);
+ std::string Result = applyAllReplacements(Code, Replaces);
+ EXPECT_NE("", Result);
+ DEBUG(llvm::errs() << "\n" << Result << "\n\n");
+ return Result;
+ }
+
+ static std::string format(
+ llvm::StringRef Code,
+ const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_Java)) {
+ return format(Code, 0, Code.size(), Style);
+ }
+
+ static FormatStyle getStyleWithColumns(unsigned ColumnLimit) {
+ FormatStyle Style = getGoogleStyle(FormatStyle::LK_Java);
+ Style.ColumnLimit = ColumnLimit;
+ return Style;
+ }
+
+ static void verifyFormat(
+ llvm::StringRef Code,
+ const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_Java)) {
+ EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
+ }
+};
+
+TEST_F(FormatTestJava, NoAlternativeOperatorNames) {
+ verifyFormat("someObject.and();");
+}
+
+TEST_F(FormatTestJava, UnderstandsCasts) {
+ verifyFormat("a[b >> 1] = (byte) (c() << 4);");
+}
+
+TEST_F(FormatTestJava, FormatsInstanceOfLikeOperators) {
+ FormatStyle Style = getStyleWithColumns(50);
+ verifyFormat("return aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " instanceof bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;",
+ Style);
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
+ verifyFormat("return aaaaaaaaaaaaaaaaaaaaaaaaaaaaa instanceof\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;",
+ Style);
+}
+
+TEST_F(FormatTestJava, Chromium) {
+ verifyFormat("class SomeClass {\n"
+ " void f() {}\n"
+ " int g() {\n"
+ " return 0;\n"
+ " }\n"
+ " void h() {\n"
+ " while (true) f();\n"
+ " for (;;) f();\n"
+ " if (true) f();\n"
+ " }\n"
+ "}",
+ getChromiumStyle(FormatStyle::LK_Java));
+}
+
+TEST_F(FormatTestJava, QualifiedNames) {
+ verifyFormat("public some.package.Type someFunction( // comment\n"
+ " int parameter) {}");
+}
+
+TEST_F(FormatTestJava, ClassKeyword) {
+ verifyFormat("SomeClass.class.getName();");
+ verifyFormat("Class c = SomeClass.class;");
+}
+
+TEST_F(FormatTestJava, ClassDeclarations) {
+ verifyFormat("public class SomeClass {\n"
+ " private int a;\n"
+ " private int b;\n"
+ "}");
+ verifyFormat("public class A {\n"
+ " class B {\n"
+ " int i;\n"
+ " }\n"
+ " class C {\n"
+ " int j;\n"
+ " }\n"
+ "}");
+ verifyFormat("public class A extends B.C {}");
+
+ verifyFormat("abstract class SomeClass\n"
+ " extends SomeOtherClass implements SomeInterface {}",
+ getStyleWithColumns(60));
+ verifyFormat("abstract class SomeClass extends SomeOtherClass\n"
+ " implements SomeInterfaceeeeeeeeeeeee {}",
+ getStyleWithColumns(60));
+ verifyFormat("abstract class SomeClass\n"
+ " extends SomeOtherClass\n"
+ " implements SomeInterface {}",
+ getStyleWithColumns(40));
+ verifyFormat("abstract class SomeClass\n"
+ " extends SomeOtherClass\n"
+ " implements SomeInterface,\n"
+ " AnotherInterface {}",
+ getStyleWithColumns(40));
+ verifyFormat("abstract class SomeClass\n"
+ " implements SomeInterface, AnotherInterface {}",
+ getStyleWithColumns(60));
+ verifyFormat("@SomeAnnotation()\n"
+ "abstract class aaaaaaaaaaaa\n"
+ " extends bbbbbbbbbbbbbbb implements cccccccccccc {}",
+ getStyleWithColumns(76));
+ verifyFormat("@SomeAnnotation()\n"
+ "abstract class aaaaaaaaa<a>\n"
+ " extends bbbbbbbbbbbb<b> implements cccccccccccc {}",
+ getStyleWithColumns(76));
+ verifyFormat("interface SomeInterface<A> extends Foo, Bar {\n"
+ " void doStuff(int theStuff);\n"
+ " void doMoreStuff(int moreStuff);\n"
+ "}");
+ verifyFormat("public interface SomeInterface {\n"
+ " void doStuff(int theStuff);\n"
+ " void doMoreStuff(int moreStuff);\n"
+ "}");
+ verifyFormat("@interface SomeInterface {\n"
+ " void doStuff(int theStuff);\n"
+ " void doMoreStuff(int moreStuff);\n"
+ "}");
+ verifyFormat("public @interface SomeInterface {\n"
+ " void doStuff(int theStuff);\n"
+ " void doMoreStuff(int moreStuff);\n"
+ "}");
+}
+
+TEST_F(FormatTestJava, EnumDeclarations) {
+ verifyFormat("enum SomeThing { ABC, CDE }");
+ verifyFormat("enum SomeThing {\n"
+ " ABC,\n"
+ " CDE,\n"
+ "}");
+ verifyFormat("public class SomeClass {\n"
+ " enum SomeThing { ABC, CDE }\n"
+ " void f() {}\n"
+ "}");
+ verifyFormat("public class SomeClass implements SomeInterface {\n"
+ " enum SomeThing { ABC, CDE }\n"
+ " void f() {}\n"
+ "}");
+ verifyFormat("enum SomeThing {\n"
+ " ABC,\n"
+ " CDE;\n"
+ " void f() {}\n"
+ "}");
+ verifyFormat("enum SomeThing {\n"
+ " ABC(1, \"ABC\"),\n"
+ " CDE(2, \"CDE\");\n"
+ " Something(int i, String s) {}\n"
+ "}");
+ verifyFormat("enum SomeThing {\n"
+ " ABC(new int[] {1, 2}),\n"
+ " CDE(new int[] {2, 3});\n"
+ " Something(int[] i) {}\n"
+ "}");
+ verifyFormat("public enum SomeThing {\n"
+ " ABC {\n"
+ " public String toString() {\n"
+ " return \"ABC\";\n"
+ " }\n"
+ " },\n"
+ " CDE {\n"
+ " @Override\n"
+ " public String toString() {\n"
+ " return \"CDE\";\n"
+ " }\n"
+ " };\n"
+ " public void f() {}\n"
+ "}");
+ verifyFormat("private enum SomeEnum implements Foo<?, B> {\n"
+ " ABC {\n"
+ " @Override\n"
+ " public String toString() {\n"
+ " return \"ABC\";\n"
+ " }\n"
+ " },\n"
+ " CDE {\n"
+ " @Override\n"
+ " public String toString() {\n"
+ " return \"CDE\";\n"
+ " }\n"
+ " };\n"
+ "}");
+}
+
+TEST_F(FormatTestJava, ArrayInitializers) {
+ verifyFormat("new int[] {1, 2, 3, 4};");
+ verifyFormat("new int[] {\n"
+ " 1, 2, 3, 4,\n"
+ "};");
+
+ FormatStyle Style = getStyleWithColumns(65);
+ Style.Cpp11BracedListStyle = false;
+ verifyFormat(
+ "expected = new int[] { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n"
+ " 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 };",
+ Style);
+}
+
+TEST_F(FormatTestJava, ThrowsDeclarations) {
+ verifyFormat("public void doSooooooooooooooooooooooooooomething()\n"
+ " throws LooooooooooooooooooooooooooooongException {}");
+ verifyFormat("public void doSooooooooooooooooooooooooooomething()\n"
+ " throws LoooooooooongException, LooooooooooongException {}");
+}
+
+TEST_F(FormatTestJava, Annotations) {
+ verifyFormat("@Override\n"
+ "public String toString() {}");
+ verifyFormat("@Override\n"
+ "@Nullable\n"
+ "public String getNameIfPresent() {}");
+ verifyFormat("@Override // comment\n"
+ "@Nullable\n"
+ "public String getNameIfPresent() {}");
+ verifyFormat("@java.lang.Override // comment\n"
+ "@Nullable\n"
+ "public String getNameIfPresent() {}");
+
+ verifyFormat("@SuppressWarnings(value = \"unchecked\")\n"
+ "public void doSomething() {}");
+ verifyFormat("@SuppressWarnings(value = \"unchecked\")\n"
+ "@Author(name = \"abc\")\n"
+ "public void doSomething() {}");
+
+ verifyFormat("DoSomething(new A() {\n"
+ " @Override\n"
+ " public String toString() {}\n"
+ "});");
+
+ verifyFormat("void SomeFunction(@Nullable String something) {}");
+ verifyFormat("void SomeFunction(@org.llvm.Nullable String something) {}");
+
+ verifyFormat("@Partial @Mock DataLoader loader;");
+ verifyFormat("@SuppressWarnings(value = \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\")\n"
+ "public static int iiiiiiiiiiiiiiiiiiiiiiii;");
+
+ verifyFormat("@SomeAnnotation(\"With some really looooooooooooooong text\")\n"
+ "private static final long something = 0L;");
+ verifyFormat("@org.llvm.Qualified(\"With some really looooooooooong text\")\n"
+ "private static final long something = 0L;");
+ verifyFormat("@Mock\n"
+ "DataLoader loooooooooooooooooooooooader =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ getStyleWithColumns(60));
+ verifyFormat("@org.llvm.QualifiedMock\n"
+ "DataLoader loooooooooooooooooooooooader =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ getStyleWithColumns(60));
+ verifyFormat("@Test(a)\n"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat("@SomeAnnotation(\n"
+ " aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa)\n"
+ "int i;",
+ getStyleWithColumns(50));
+ verifyFormat("@Test\n"
+ "ReturnType doSomething(\n"
+ " String aaaaaaaaaaaaa, String bbbbbbbbbbbbbbb) {}",
+ getStyleWithColumns(60));
+ verifyFormat("{\n"
+ " boolean someFunction(\n"
+ " @Param(aaaaaaaaaaaaaaaa) String aaaaa,\n"
+ " String bbbbbbbbbbbbbbb) {}\n"
+ "}",
+ getStyleWithColumns(60));
+}
+
+TEST_F(FormatTestJava, Generics) {
+ verifyFormat("Iterable<?> a;");
+ verifyFormat("Iterable<?> a;");
+ verifyFormat("Iterable<? extends SomeObject> a;");
+
+ verifyFormat("A.<B>doSomething();");
+
+ verifyFormat("@Override\n"
+ "public Map<String, ?> getAll() {}");
+
+ verifyFormat("public <R> ArrayList<R> get() {}");
+ verifyFormat("protected <R> ArrayList<R> get() {}");
+ verifyFormat("private <R> ArrayList<R> get() {}");
+ verifyFormat("public static <R> ArrayList<R> get() {}");
+ verifyFormat("public static native <R> ArrayList<R> get();");
+ verifyFormat("public final <X> Foo foo() {}");
+ verifyFormat("public abstract <X> Foo foo();");
+ verifyFormat("<T extends B> T getInstance(Class<T> type);");
+ verifyFormat("Function<F, ? extends T> function;");
+
+ verifyFormat("private Foo<X, Y>[] foos;");
+ verifyFormat("Foo<X, Y>[] foos = this.foos;");
+ verifyFormat("return (a instanceof List<?>)\n"
+ " ? aaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa)\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaa;",
+ getStyleWithColumns(60));
+
+ verifyFormat(
+ "SomeLoooooooooooooooooooooongType name =\n"
+ " SomeType.foo(someArgument)\n"
+ " .<X>method()\n"
+ " .aaaaaaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();");
+}
+
+TEST_F(FormatTestJava, StringConcatenation) {
+ verifyFormat("String someString = \"abc\"\n"
+ " + \"cde\";");
+}
+
+TEST_F(FormatTestJava, TryCatchFinally) {
+ verifyFormat("try {\n"
+ " Something();\n"
+ "} catch (SomeException e) {\n"
+ " HandleException(e);\n"
+ "}");
+ verifyFormat("try {\n"
+ " Something();\n"
+ "} finally {\n"
+ " AlwaysDoThis();\n"
+ "}");
+ verifyFormat("try {\n"
+ " Something();\n"
+ "} catch (SomeException e) {\n"
+ " HandleException(e);\n"
+ "} finally {\n"
+ " AlwaysDoThis();\n"
+ "}");
+
+ verifyFormat("try {\n"
+ " Something();\n"
+ "} catch (SomeException | OtherException e) {\n"
+ " HandleException(e);\n"
+ "}");
+}
+
+TEST_F(FormatTestJava, TryWithResources) {
+ verifyFormat("try (SomeResource rs = someFunction()) {\n"
+ " Something();\n"
+ "}");
+ verifyFormat("try (SomeResource rs = someFunction()) {\n"
+ " Something();\n"
+ "} catch (SomeException e) {\n"
+ " HandleException(e);\n"
+ "}");
+}
+
+TEST_F(FormatTestJava, SynchronizedKeyword) {
+ verifyFormat("synchronized (mData) {\n"
+ " // ...\n"
+ "}");
+}
+
+TEST_F(FormatTestJava, PackageDeclarations) {
+ verifyFormat("package some.really.loooooooooooooooooooooong.package;",
+ getStyleWithColumns(50));
+}
+
+TEST_F(FormatTestJava, ImportDeclarations) {
+ verifyFormat("import some.really.loooooooooooooooooooooong.imported.Class;",
+ getStyleWithColumns(50));
+ verifyFormat("import static some.really.looooooooooooooooong.imported.Class;",
+ getStyleWithColumns(50));
+}
+
+TEST_F(FormatTestJava, MethodDeclarations) {
+ verifyFormat("void methodName(Object arg1,\n"
+ " Object arg2, Object arg3) {}",
+ getStyleWithColumns(40));
+ verifyFormat("void methodName(\n"
+ " Object arg1, Object arg2) {}",
+ getStyleWithColumns(40));
+}
+
+TEST_F(FormatTestJava, CppKeywords) {
+ verifyFormat("public void union(Type a, Type b);");
+ verifyFormat("public void struct(Object o);");
+ verifyFormat("public void delete(Object o);");
+}
+
+TEST_F(FormatTestJava, NeverAlignAfterReturn) {
+ verifyFormat("return aaaaaaaaaaaaaaaaaaa\n"
+ " && bbbbbbbbbbbbbbbbbbb\n"
+ " && ccccccccccccccccccc;",
+ getStyleWithColumns(40));
+ verifyFormat("return (result == null)\n"
+ " ? aaaaaaaaaaaaaaaaa\n"
+ " : bbbbbbbbbbbbbbbbb;",
+ getStyleWithColumns(40));
+ verifyFormat("return aaaaaaaaaaaaaaaaaaa()\n"
+ " .bbbbbbbbbbbbbbbbbbb()\n"
+ " .ccccccccccccccccccc();",
+ getStyleWithColumns(40));
+ verifyFormat("return aaaaaaaaaaaaaaaaaaa()\n"
+ " .bbbbbbbbbbbbbbbbbbb(\n"
+ " ccccccccccccccc)\n"
+ " .ccccccccccccccccccc();",
+ getStyleWithColumns(40));
+}
+
+TEST_F(FormatTestJava, FormatsInnerBlocks) {
+ verifyFormat("someObject.someFunction(new Runnable() {\n"
+ " @Override\n"
+ " public void run() {\n"
+ " System.out.println(42);\n"
+ " }\n"
+ "}, someOtherParameter);");
+ verifyFormat("someFunction(new Runnable() {\n"
+ " public void run() {\n"
+ " System.out.println(42);\n"
+ " }\n"
+ "});");
+ verifyFormat("someObject.someFunction(\n"
+ " new Runnable() {\n"
+ " @Override\n"
+ " public void run() {\n"
+ " System.out.println(42);\n"
+ " }\n"
+ " },\n"
+ " new Runnable() {\n"
+ " @Override\n"
+ " public void run() {\n"
+ " System.out.println(43);\n"
+ " }\n"
+ " },\n"
+ " someOtherParameter);");
+}
+
+TEST_F(FormatTestJava, FormatsLambdas) {
+ verifyFormat("(aaaaaaaaaa, bbbbbbbbbb) -> aaaaaaaaaa + bbbbbbbbbb;");
+ verifyFormat("(aaaaaaaaaa, bbbbbbbbbb)\n"
+ " -> aaaaaaaaaa + bbbbbbbbbb;",
+ getStyleWithColumns(40));
+ verifyFormat("Runnable someLambda = () -> DoSomething();");
+ verifyFormat("Runnable someLambda = () -> {\n"
+ " DoSomething();\n"
+ "}");
+
+ verifyFormat("Runnable someLambda =\n"
+ " (int aaaaa) -> DoSomething(aaaaa);",
+ getStyleWithColumns(40));
+}
+
+TEST_F(FormatTestJava, BreaksStringLiterals) {
+ // FIXME: String literal breaking is currently disabled for Java and JS, as it
+ // requires strings to be merged using "+" which we don't support.
+ EXPECT_EQ("\"some text other\";",
+ format("\"some text other\";", getStyleWithColumns(14)));
+}
+
+TEST_F(FormatTestJava, AlignsBlockComments) {
+ EXPECT_EQ("/*\n"
+ " * Really multi-line\n"
+ " * comment.\n"
+ " */\n"
+ "void f() {}",
+ format(" /*\n"
+ " * Really multi-line\n"
+ " * comment.\n"
+ " */\n"
+ " void f() {}"));
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/unittests/Format/FormatTestProto.cpp b/unittests/Format/FormatTestProto.cpp
index bfd502566757..3a2f97e875d1 100644
--- a/unittests/Format/FormatTestProto.cpp
+++ b/unittests/Format/FormatTestProto.cpp
@@ -85,21 +85,50 @@ TEST_F(FormatTestProto, MessageFieldAttributes) {
" [default = REALLY_REALLY_LONG_CONSTANT_VALUE];");
verifyFormat("repeated double value = 1\n"
" [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaaa: AAAAAAAA}];");
- verifyFormat("repeated double value = 1\n"
- " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n"
- " bbbbbbbbbbbbbbbb: BBBBBBBBBB}];");
- verifyFormat("repeated double value = 1\n"
- " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaa: AAAAAAAAAA\n"
- " bbbbbbbbbbbbbbbb: BBBBBBBBBB}];");
- verifyFormat("repeated double value = 1\n"
- " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n"
- " bbbbbbb: BBBB,\n"
- " bbbb: BBB}];");
+ verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n"
+ " aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n"
+ " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n"
+ "}];");
+ verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n"
+ " aaaaaaaaaaaaaaaa: AAAAAAAAAA\n"
+ " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n"
+ "}];");
+ verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n"
+ " aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n"
+ " bbbbbbb: BBBB,\n"
+ " bbbb: BBB\n"
+ "}];");
}
TEST_F(FormatTestProto, FormatsOptions) {
- verifyFormat("option java_package = \"my.test.package\";");
- verifyFormat("option (my_custom_option) = \"abc\";");
+ verifyFormat("option (MyProto.options) = {\n"
+ " field_a: OK\n"
+ " field_b: \"OK\"\n"
+ " field_c: \"OK\"\n"
+ " msg_field: {field_d: 123}\n"
+ "};");
+
+ verifyFormat("option (MyProto.options) = {\n"
+ " field_a: OK\n"
+ " field_b: \"OK\"\n"
+ " field_c: \"OK\"\n"
+ " msg_field: {\n"
+ " field_d: 123\n"
+ " field_e: OK\n"
+ " }\n"
+ "};");
+
+ verifyFormat("option (MyProto.options) = {\n"
+ " field_a: OK // Comment\n"
+ " field_b: \"OK\"\n"
+ " field_c: \"OK\"\n"
+ " msg_field: {field_d: 123}\n"
+ "};");
+
+ verifyFormat("option (MyProto.options) = {\n"
+ " field_c: \"OK\"\n"
+ " msg_field{field_d: 123}\n"
+ "};");
}
TEST_F(FormatTestProto, FormatsService) {
diff --git a/unittests/Format/FormatTestUtils.h b/unittests/Format/FormatTestUtils.h
index 649f5b3822c5..bd340e5b0e60 100644
--- a/unittests/Format/FormatTestUtils.h
+++ b/unittests/Format/FormatTestUtils.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FORMAT_TEST_UTILS_H
-#define LLVM_CLANG_FORMAT_TEST_UTILS_H
+#ifndef LLVM_CLANG_UNITTESTS_FORMAT_FORMATTESTUTILS_H
+#define LLVM_CLANG_UNITTESTS_FORMAT_FORMATTESTUTILS_H
#include "llvm/ADT/StringRef.h"
@@ -64,4 +64,4 @@ inline std::string messUp(llvm::StringRef Code) {
} // end namespace format
} // end namespace clang
-#endif // LLVM_CLANG_FORMAT_TEST_UTILS_H
+#endif
diff --git a/unittests/Format/Makefile b/unittests/Format/Makefile
index e6dce4d8e814..f95d6d34127b 100644
--- a/unittests/Format/Makefile
+++ b/unittests/Format/Makefile
@@ -11,8 +11,8 @@ CLANG_LEVEL = ../..
TESTNAME = Format
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
-USEDLIBS = clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
- clangDriver.a clangParse.a clangRewrite.a \
+USEDLIBS = clangFormat.a clangTooling.a clangToolingCore.a clangFrontend.a \
+ clangSerialization.a clangDriver.a clangParse.a clangRewrite.a \
clangRewriteFrontend.a clangSema.a clangAnalysis.a clangEdit.a \
clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
diff --git a/unittests/Frontend/CMakeLists.txt b/unittests/Frontend/CMakeLists.txt
index cdc955944bcf..a1310e885a55 100644
--- a/unittests/Frontend/CMakeLists.txt
+++ b/unittests/Frontend/CMakeLists.txt
@@ -8,4 +8,6 @@ add_clang_unittest(FrontendTests
target_link_libraries(FrontendTests
clangAST
clangFrontend
+ clangLex
+ clangSema
)
diff --git a/unittests/Frontend/FrontendActionTest.cpp b/unittests/Frontend/FrontendActionTest.cpp
index e39d00f6af3d..5581c4487ecc 100644
--- a/unittests/Frontend/FrontendActionTest.cpp
+++ b/unittests/Frontend/FrontendActionTest.cpp
@@ -14,6 +14,7 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Sema.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/MemoryBuffer.h"
#include "gtest/gtest.h"
@@ -25,10 +26,13 @@ namespace {
class TestASTFrontendAction : public ASTFrontendAction {
public:
- TestASTFrontendAction(bool enableIncrementalProcessing = false)
- : EnableIncrementalProcessing(enableIncrementalProcessing) { }
+ TestASTFrontendAction(bool enableIncrementalProcessing = false,
+ bool actOnEndOfTranslationUnit = false)
+ : EnableIncrementalProcessing(enableIncrementalProcessing),
+ ActOnEndOfTranslationUnit(actOnEndOfTranslationUnit) { }
bool EnableIncrementalProcessing;
+ bool ActOnEndOfTranslationUnit;
std::vector<std::string> decl_names;
virtual bool BeginSourceFileAction(CompilerInstance &ci, StringRef filename) {
@@ -38,17 +42,24 @@ public:
return ASTFrontendAction::BeginSourceFileAction(ci, filename);
}
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- return new Visitor(decl_names);
+ virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ return llvm::make_unique<Visitor>(CI, ActOnEndOfTranslationUnit,
+ decl_names);
}
private:
class Visitor : public ASTConsumer, public RecursiveASTVisitor<Visitor> {
public:
- Visitor(std::vector<std::string> &decl_names) : decl_names_(decl_names) {}
+ Visitor(CompilerInstance &CI, bool ActOnEndOfTranslationUnit,
+ std::vector<std::string> &decl_names) :
+ CI(CI), ActOnEndOfTranslationUnit(ActOnEndOfTranslationUnit),
+ decl_names_(decl_names) {}
virtual void HandleTranslationUnit(ASTContext &context) {
+ if (ActOnEndOfTranslationUnit) {
+ CI.getSema().ActOnEndOfTranslationUnit();
+ }
TraverseDecl(context.getTranslationUnitDecl());
}
@@ -58,6 +69,8 @@ private:
}
private:
+ CompilerInstance &CI;
+ bool ActOnEndOfTranslationUnit;
std::vector<std::string> &decl_names_;
};
};
@@ -65,7 +78,8 @@ private:
TEST(ASTFrontendAction, Sanity) {
CompilerInvocation *invocation = new CompilerInvocation;
invocation->getPreprocessorOpts().addRemappedFile(
- "test.cc", MemoryBuffer::getMemBuffer("int main() { float x; }"));
+ "test.cc",
+ MemoryBuffer::getMemBuffer("int main() { float x; }").release());
invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
IK_CXX));
invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
@@ -84,7 +98,8 @@ TEST(ASTFrontendAction, Sanity) {
TEST(ASTFrontendAction, IncrementalParsing) {
CompilerInvocation *invocation = new CompilerInvocation;
invocation->getPreprocessorOpts().addRemappedFile(
- "test.cc", MemoryBuffer::getMemBuffer("int main() { float x; }"));
+ "test.cc",
+ MemoryBuffer::getMemBuffer("int main() { float x; }").release());
invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
IK_CXX));
invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
@@ -100,4 +115,79 @@ TEST(ASTFrontendAction, IncrementalParsing) {
EXPECT_EQ("x", test_action.decl_names[1]);
}
+TEST(ASTFrontendAction, LateTemplateIncrementalParsing) {
+ CompilerInvocation *invocation = new CompilerInvocation;
+ invocation->getLangOpts()->CPlusPlus = true;
+ invocation->getLangOpts()->DelayedTemplateParsing = true;
+ invocation->getPreprocessorOpts().addRemappedFile(
+ "test.cc", MemoryBuffer::getMemBuffer(
+ "template<typename T> struct A { A(T); T data; };\n"
+ "template<typename T> struct B: public A<T> {\n"
+ " B();\n"
+ " B(B const& b): A<T>(b.data) {}\n"
+ "};\n"
+ "B<char> c() { return B<char>(); }\n").release());
+ invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
+ IK_CXX));
+ invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
+ invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
+ CompilerInstance compiler;
+ compiler.setInvocation(invocation);
+ compiler.createDiagnostics();
+
+ TestASTFrontendAction test_action(/*enableIncrementalProcessing=*/true,
+ /*actOnEndOfTranslationUnit=*/true);
+ ASSERT_TRUE(compiler.ExecuteAction(test_action));
+ ASSERT_EQ(13U, test_action.decl_names.size());
+ EXPECT_EQ("A", test_action.decl_names[0]);
+ EXPECT_EQ("c", test_action.decl_names[12]);
+}
+
+struct TestPPCallbacks : public PPCallbacks {
+ TestPPCallbacks() : SeenEnd(false) {}
+
+ void EndOfMainFile() override { SeenEnd = true; }
+
+ bool SeenEnd;
+};
+
+class TestPPCallbacksFrontendAction : public PreprocessorFrontendAction {
+ TestPPCallbacks *Callbacks;
+
+public:
+ TestPPCallbacksFrontendAction(TestPPCallbacks *C)
+ : Callbacks(C), SeenEnd(false) {}
+
+ void ExecuteAction() override {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ PP.addPPCallbacks(std::unique_ptr<TestPPCallbacks>(Callbacks));
+ PP.EnterMainSourceFile();
+ }
+ void EndSourceFileAction() override { SeenEnd = Callbacks->SeenEnd; }
+
+ bool SeenEnd;
+};
+
+TEST(PreprocessorFrontendAction, EndSourceFile) {
+ CompilerInvocation *Invocation = new CompilerInvocation;
+ Invocation->getPreprocessorOpts().addRemappedFile(
+ "test.cc",
+ MemoryBuffer::getMemBuffer("int main() { float x; }").release());
+ Invocation->getFrontendOpts().Inputs.push_back(
+ FrontendInputFile("test.cc", IK_CXX));
+ Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
+ Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
+ CompilerInstance Compiler;
+ Compiler.setInvocation(Invocation);
+ Compiler.createDiagnostics();
+
+ TestPPCallbacks *Callbacks = new TestPPCallbacks;
+ TestPPCallbacksFrontendAction TestAction(Callbacks);
+ ASSERT_FALSE(Callbacks->SeenEnd);
+ ASSERT_FALSE(TestAction.SeenEnd);
+ ASSERT_TRUE(Compiler.ExecuteAction(TestAction));
+ // Check that EndOfMainFile was called before EndSourceFileAction.
+ ASSERT_TRUE(TestAction.SeenEnd);
+}
+
} // anonymous namespace
diff --git a/unittests/Lex/CMakeLists.txt b/unittests/Lex/CMakeLists.txt
index 1fb57cfdfba0..461e0d95fc87 100644
--- a/unittests/Lex/CMakeLists.txt
+++ b/unittests/Lex/CMakeLists.txt
@@ -14,5 +14,4 @@ target_link_libraries(LexTests
clangLex
clangParse
clangSema
- clangSerialization
)
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index 2d75b52276cc..85987bf00161 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -62,8 +62,8 @@ protected:
std::vector<Token> CheckLex(StringRef Source,
ArrayRef<tok::TokenKind> ExpectedTokens) {
- MemoryBuffer *buf = MemoryBuffer::getMemBuffer(Source);
- SourceMgr.setMainFileID(SourceMgr.createFileID(buf));
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Source);
+ SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
VoidModuleLoader ModLoader;
HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
index a1af75403638..bb27bac6ed66 100644
--- a/unittests/Lex/PPCallbacksTest.cpp
+++ b/unittests/Lex/PPCallbacksTest.cpp
@@ -27,8 +27,6 @@
#include "llvm/Support/Path.h"
#include "gtest/gtest.h"
-using namespace llvm;
-using namespace llvm::sys;
using namespace clang;
namespace {
@@ -142,7 +140,7 @@ protected:
FileMgr.getVirtualFile(HeaderPath, 0, 0);
// Add header's parent path to search path.
- StringRef SearchPath = path::parent_path(HeaderPath);
+ StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
DirectoryLookup DL(DE, SrcMgr::C_User, false);
HeaderInfo.AddSearchPath(DL, IsSystemHeader);
@@ -160,8 +158,9 @@ protected:
// the InclusionDirective callback.
CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
const char* HeaderPath, bool SystemHeader) {
- MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(SourceText);
- SourceMgr.setMainFileID(SourceMgr.createFileID(Buf));
+ std::unique_ptr<llvm::MemoryBuffer> Buf =
+ llvm::MemoryBuffer::getMemBuffer(SourceText);
+ SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
VoidModuleLoader ModLoader;
@@ -176,7 +175,7 @@ protected:
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
- PP.addPPCallbacks(Callbacks); // Takes ownership.
+ PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
// Lex source text.
PP.EnterMainSourceFile();
@@ -197,8 +196,9 @@ protected:
LangOptions OpenCLLangOpts;
OpenCLLangOpts.OpenCL = 1;
- MemoryBuffer* sourceBuf = MemoryBuffer::getMemBuffer(SourceText, "test.cl");
- SourceMgr.setMainFileID(SourceMgr.createFileID(sourceBuf));
+ std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
+ llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
+ SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
VoidModuleLoader ModLoader;
HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags,
@@ -221,7 +221,7 @@ protected:
Sema S(PP, Context, Consumer);
Parser P(PP, S, false);
PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
- PP.addPPCallbacks(Callbacks); // Takes ownership.
+ PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
// Lex source text.
PP.EnterMainSourceFile();
diff --git a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
index e63106c295a3..946cb88b9810 100644
--- a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
+++ b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -90,8 +90,8 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
"#endif\n"
"9\n";
- MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
- SourceMgr.setMainFileID(SourceMgr.createFileID(buf));
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(source);
+ SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
VoidModuleLoader ModLoader;
HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
@@ -103,7 +103,7 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
PP.Initialize(*Target);
PPConditionalDirectiveRecord *
PPRec = new PPConditionalDirectiveRecord(SourceMgr);
- PP.addPPCallbacks(PPRec);
+ PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
PP.EnterMainSourceFile();
std::vector<Token> toks;
diff --git a/unittests/Makefile b/unittests/Makefile
index 95b1639415b2..1e6a50835b05 100644
--- a/unittests/Makefile
+++ b/unittests/Makefile
@@ -14,12 +14,13 @@ ifndef CLANG_LEVEL
IS_UNITTEST_LEVEL := 1
CLANG_LEVEL := ..
-PARALLEL_DIRS = Basic Lex Driver libclang Format ASTMatchers AST Tooling Sema
+PARALLEL_DIRS = CodeGen Basic Lex Driver Format ASTMatchers AST Tooling \
+ Sema
include $(CLANG_LEVEL)/../..//Makefile.config
ifeq ($(ENABLE_CLANG_ARCMT),1)
-PARALLEL_DIRS += Frontend
+PARALLEL_DIRS += Frontend libclang
endif
endif # CLANG_LEVEL
diff --git a/unittests/Sema/ExternalSemaSourceTest.cpp b/unittests/Sema/ExternalSemaSourceTest.cpp
index bc0d632cfdb5..3a93fc77fb19 100644
--- a/unittests/Sema/ExternalSemaSourceTest.cpp
+++ b/unittests/Sema/ExternalSemaSourceTest.cpp
@@ -140,10 +140,10 @@ class ExternalSemaSourceInstaller : public clang::ASTFrontendAction {
std::unique_ptr<DiagnosticConsumer> OwnedClient;
protected:
- virtual clang::ASTConsumer *
+ virtual std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &Compiler,
llvm::StringRef /* dummy */) {
- return new clang::ASTConsumer();
+ return llvm::make_unique<clang::ASTConsumer>();
}
virtual void ExecuteAction() {
@@ -154,7 +154,7 @@ protected:
DiagnosticsEngine &Diagnostics = CI.getDiagnostics();
DiagnosticConsumer *Client = Diagnostics.getClient();
if (Diagnostics.ownsClient())
- OwnedClient.reset(Diagnostics.takeClient());
+ OwnedClient = Diagnostics.takeClient();
for (size_t I = 0, E = Watchers.size(); I < E; ++I)
Client = Watchers[I]->Chain(Client);
Diagnostics.setClient(Client, false);
diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt
index a41d87c6ea82..469e6a956b2d 100644
--- a/unittests/Tooling/CMakeLists.txt
+++ b/unittests/Tooling/CMakeLists.txt
@@ -7,6 +7,10 @@ add_clang_unittest(ToolingTests
CompilationDatabaseTest.cpp
ToolingTest.cpp
RecursiveASTVisitorTest.cpp
+ RecursiveASTVisitorTestCallVisitor.cpp
+ RecursiveASTVisitorTestDeclVisitor.cpp
+ RecursiveASTVisitorTestExprVisitor.cpp
+ RecursiveASTVisitorTestTypeLocVisitor.cpp
RefactoringTest.cpp
RewriterTest.cpp
RefactoringCallbacksTest.cpp
@@ -21,4 +25,5 @@ target_link_libraries(ToolingTests
clangLex
clangRewrite
clangTooling
+ clangToolingCore
)
diff --git a/unittests/Tooling/Makefile b/unittests/Tooling/Makefile
index 46af8a11bba1..514e80bd0309 100644
--- a/unittests/Tooling/Makefile
+++ b/unittests/Tooling/Makefile
@@ -11,7 +11,8 @@ CLANG_LEVEL = ../..
TESTNAME = Tooling
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
-USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+USEDLIBS = clangTooling.a clangToolingCore.a clangFrontend.a \
+ clangSerialization.a clangDriver.a \
clangParse.a clangRewrite.a clangRewriteFrontend.a \
clangSema.a clangAnalysis.a clangEdit.a \
clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index a1a93a59c79b..c28704532a6e 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -14,85 +14,6 @@ using namespace clang;
namespace {
-class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> {
-public:
- bool VisitTypeLoc(TypeLoc TypeLocation) {
- Match(TypeLocation.getType().getAsString(), TypeLocation.getBeginLoc());
- return true;
- }
-};
-
-class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
-public:
- bool VisitDeclRefExpr(DeclRefExpr *Reference) {
- Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
- return true;
- }
-};
-
-class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
-public:
- bool VisitVarDecl(VarDecl *Variable) {
- Match(Variable->getNameAsString(), Variable->getLocStart());
- return true;
- }
-};
-
-class ParmVarDeclVisitorForImplicitCode :
- public ExpectedLocationVisitor<ParmVarDeclVisitorForImplicitCode> {
-public:
- bool shouldVisitImplicitCode() const { return true; }
-
- bool VisitParmVarDecl(ParmVarDecl *ParamVar) {
- Match(ParamVar->getNameAsString(), ParamVar->getLocStart());
- return true;
- }
-};
-
-class CXXMemberCallVisitor
- : public ExpectedLocationVisitor<CXXMemberCallVisitor> {
-public:
- bool VisitCXXMemberCallExpr(CXXMemberCallExpr *Call) {
- Match(Call->getMethodDecl()->getQualifiedNameAsString(),
- Call->getLocStart());
- return true;
- }
-};
-
-class NamedDeclVisitor
- : public ExpectedLocationVisitor<NamedDeclVisitor> {
-public:
- bool VisitNamedDecl(NamedDecl *Decl) {
- std::string NameWithTemplateArgs;
- llvm::raw_string_ostream OS(NameWithTemplateArgs);
- Decl->getNameForDiagnostic(OS,
- Decl->getASTContext().getPrintingPolicy(),
- true);
- Match(OS.str(), Decl->getLocation());
- return true;
- }
-};
-
-class CXXOperatorCallExprTraverser
- : public ExpectedLocationVisitor<CXXOperatorCallExprTraverser> {
-public:
- // Use Traverse, not Visit, to check that data recursion optimization isn't
- // bypassing the call of this function.
- bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE) {
- Match(getOperatorSpelling(CE->getOperator()), CE->getExprLoc());
- return ExpectedLocationVisitor<CXXOperatorCallExprTraverser>::
- TraverseCXXOperatorCallExpr(CE);
- }
-};
-
-class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> {
-public:
- bool VisitParenExpr(ParenExpr *Parens) {
- Match("", Parens->getExprLoc());
- return true;
- }
-};
-
class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
public:
bool VisitLambdaExpr(LambdaExpr *Lambda) {
@@ -117,429 +38,6 @@ private:
std::stack<LambdaExpr *> PendingBodies;
};
-// Matches the (optional) capture-default of a lambda-introducer.
-class LambdaDefaultCaptureVisitor
- : public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> {
-public:
- bool VisitLambdaExpr(LambdaExpr *Lambda) {
- if (Lambda->getCaptureDefault() != LCD_None) {
- Match("", Lambda->getCaptureDefaultLoc());
- }
- return true;
- }
-};
-
-class TemplateArgumentLocTraverser
- : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> {
-public:
- bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
- std::string ArgStr;
- llvm::raw_string_ostream Stream(ArgStr);
- const TemplateArgument &Arg = ArgLoc.getArgument();
-
- Arg.print(Context->getPrintingPolicy(), Stream);
- Match(Stream.str(), ArgLoc.getLocation());
- return ExpectedLocationVisitor<TemplateArgumentLocTraverser>::
- TraverseTemplateArgumentLoc(ArgLoc);
- }
-};
-
-class CXXBoolLiteralExprVisitor
- : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> {
-public:
- bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) {
- if (BE->getValue())
- Match("true", BE->getLocation());
- else
- Match("false", BE->getLocation());
- return true;
- }
-};
-
-// Test RAV visits parameter variable declaration of the implicit
-// copy assignment operator and implicit copy constructor.
-TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) {
- ParmVarDeclVisitorForImplicitCode Visitor;
- // Match parameter variable name of implicit copy assignment operator and
- // implicit copy constructor.
- // This parameter name does not have a valid IdentifierInfo, and shares
- // same SourceLocation with its class declaration, so we match an empty name
- // with the class' source location.
- Visitor.ExpectMatch("", 1, 7);
- Visitor.ExpectMatch("", 3, 7);
- EXPECT_TRUE(Visitor.runOver(
- "class X {};\n"
- "void foo(X a, X b) {a = b;}\n"
- "class Y {};\n"
- "void bar(Y a) {Y b = a;}"));
-}
-
-TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) {
- TypeLocVisitor Visitor;
- Visitor.ExpectMatch("class X", 1, 30);
- EXPECT_TRUE(Visitor.runOver("class X {}; class Y : public X {};"));
-}
-
-TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfForwardDeclaredClass) {
- TypeLocVisitor Visitor;
- Visitor.ExpectMatch("class X", 3, 18);
- EXPECT_TRUE(Visitor.runOver(
- "class Y;\n"
- "class X {};\n"
- "class Y : public X {};"));
-}
-
-TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersWithIncompleteInnerClass) {
- TypeLocVisitor Visitor;
- Visitor.ExpectMatch("class X", 2, 18);
- EXPECT_TRUE(Visitor.runOver(
- "class X {};\n"
- "class Y : public X { class Z; };"));
-}
-
-TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfSelfReferentialType) {
- TypeLocVisitor Visitor;
- Visitor.ExpectMatch("X<class Y>", 2, 18);
- EXPECT_TRUE(Visitor.runOver(
- "template<typename T> class X {};\n"
- "class Y : public X<Y> {};"));
-}
-
-TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
- DeclRefExprVisitor Visitor;
- Visitor.ExpectMatch("x", 2, 3);
- EXPECT_TRUE(Visitor.runOver(
- "void x(); template <void (*T)()> class X {};\nX<x> y;"));
-}
-
-TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) {
- DeclRefExprVisitor Visitor;
- Visitor.ExpectMatch("x", 2, 25);
- Visitor.ExpectMatch("x", 2, 30);
- EXPECT_TRUE(Visitor.runOver(
- "int x[5];\n"
- "void f() { for (int i : x) { x[0] = 1; } }",
- DeclRefExprVisitor::Lang_CXX11));
-}
-
-TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) {
- VarDeclVisitor Visitor;
- Visitor.ExpectMatch("i", 2, 17);
- EXPECT_TRUE(Visitor.runOver(
- "int x[5];\n"
- "void f() { for (int i : x) {} }",
- VarDeclVisitor::Lang_CXX11));
-}
-
-TEST(RecursiveASTVisitor, VisitsCallExpr) {
- DeclRefExprVisitor Visitor;
- Visitor.ExpectMatch("x", 1, 22);
- EXPECT_TRUE(Visitor.runOver(
- "void x(); void y() { x(); }"));
-}
-
-TEST(RecursiveASTVisitor, VisitsCallInTemplateInstantiation) {
- CXXMemberCallVisitor Visitor;
- Visitor.ExpectMatch("Y::x", 3, 3);
- EXPECT_TRUE(Visitor.runOver(
- "struct Y { void x(); };\n"
- "template<typename T> void y(T t) {\n"
- " t.x();\n"
- "}\n"
- "void foo() { y<Y>(Y()); }"));
-}
-
-TEST(RecursiveASTVisitor, VisitsCallInNestedFunctionTemplateInstantiation) {
- CXXMemberCallVisitor Visitor;
- Visitor.ExpectMatch("Y::x", 4, 5);
- EXPECT_TRUE(Visitor.runOver(
- "struct Y { void x(); };\n"
- "template<typename T> struct Z {\n"
- " template<typename U> static void f() {\n"
- " T().x();\n"
- " }\n"
- "};\n"
- "void foo() { Z<Y>::f<int>(); }"));
-}
-
-TEST(RecursiveASTVisitor, VisitsCallInNestedClassTemplateInstantiation) {
- CXXMemberCallVisitor Visitor;
- Visitor.ExpectMatch("A::x", 5, 7);
- EXPECT_TRUE(Visitor.runOver(
- "template <typename T1> struct X {\n"
- " template <typename T2> struct Y {\n"
- " void f() {\n"
- " T2 y;\n"
- " y.x();\n"
- " }\n"
- " };\n"
- "};\n"
- "struct A { void x(); };\n"
- "int main() {\n"
- " (new X<A>::Y<A>())->f();\n"
- "}"));
-}
-
-/* FIXME: According to Richard Smith this is a bug in the AST.
-TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
- DeclRefExprVisitor Visitor;
- Visitor.ExpectMatch("x", 3, 43);
- EXPECT_TRUE(Visitor.runOver(
- "template <typename T> void x();\n"
- "template <void (*T)()> class X {};\n"
- "template <typename T> class Y : public X< x<T> > {};\n"
- "Y<int> y;"));
-}
-*/
-
-TEST(RecursiveASTVisitor, VisitsCallInPartialTemplateSpecialization) {
- CXXMemberCallVisitor Visitor;
- Visitor.ExpectMatch("A::x", 6, 20);
- EXPECT_TRUE(Visitor.runOver(
- "template <typename T1> struct X {\n"
- " template <typename T2, bool B> struct Y { void g(); };\n"
- "};\n"
- "template <typename T1> template <typename T2>\n"
- "struct X<T1>::Y<T2, true> {\n"
- " void f() { T2 y; y.x(); }\n"
- "};\n"
- "struct A { void x(); };\n"
- "int main() {\n"
- " (new X<A>::Y<A, true>())->f();\n"
- "}\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsExplicitTemplateSpecialization) {
- CXXMemberCallVisitor Visitor;
- Visitor.ExpectMatch("A::f", 4, 5);
- EXPECT_TRUE(Visitor.runOver(
- "struct A {\n"
- " void f() const {}\n"
- " template<class T> void g(const T& t) const {\n"
- " t.f();\n"
- " }\n"
- "};\n"
- "template void A::g(const A& a) const;\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsPartialTemplateSpecialization) {
- // From cfe-commits/Week-of-Mon-20100830/033998.html
- // Contrary to the approach suggested in that email, we visit all
- // specializations when we visit the primary template. Visiting them when we
- // visit the associated specialization is problematic for specializations of
- // template members of class templates.
- NamedDeclVisitor Visitor;
- Visitor.ExpectMatch("A<bool>", 1, 26);
- Visitor.ExpectMatch("A<char *>", 2, 26);
- EXPECT_TRUE(Visitor.runOver(
- "template <class T> class A {};\n"
- "template <class T> class A<T*> {};\n"
- "A<bool> ab;\n"
- "A<char*> acp;\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) {
- NamedDeclVisitor Visitor;
- Visitor.ExpectMatch("A<int>", 1, 29);
- EXPECT_TRUE(Visitor.runOver(
- "template<typename T> struct A;\n"
- "A<int> *p;\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) {
- NamedDeclVisitor Visitor;
- Visitor.ExpectMatch("A<int>::B<char>", 2, 31);
- EXPECT_TRUE(Visitor.runOver(
- "template<typename T> struct A {\n"
- " template<typename U> struct B;\n"
- "};\n"
- "A<int>::B<char> *p;\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) {
- NamedDeclVisitor Visitor;
- Visitor.ExpectMatch("A<int>", 1, 26);
- EXPECT_TRUE(Visitor.runOver(
- "template<typename T> int A();\n"
- "int k = A<int>();\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) {
- NamedDeclVisitor Visitor;
- Visitor.ExpectMatch("A<int>::B<char>", 2, 35);
- EXPECT_TRUE(Visitor.runOver(
- "template<typename T> struct A {\n"
- " template<typename U> static int B();\n"
- "};\n"
- "int k = A<int>::B<char>();\n"));
-}
-
-TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) {
- // From cfe-commits/Week-of-Mon-20100830/033977.html
- NamedDeclVisitor Visitor;
- Visitor.ExpectMatch("vector_iterator<int>", 2, 7);
- EXPECT_TRUE(Visitor.runOver(
- "template<typename Container>\n"
- "class vector_iterator {\n"
- " template <typename C> friend class vector_iterator;\n"
- "};\n"
- "vector_iterator<int> it_int;\n"));
-}
-
-TEST(RecursiveASTVisitor, TraversesOverloadedOperator) {
- CXXOperatorCallExprTraverser Visitor;
- Visitor.ExpectMatch("()", 4, 9);
- EXPECT_TRUE(Visitor.runOver(
- "struct A {\n"
- " int operator()();\n"
- "} a;\n"
- "int k = a();\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) {
- ParenExprVisitor Visitor;
- Visitor.ExpectMatch("", 1, 9);
- EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsClassTemplateNonTypeParmDefaultArgument) {
- CXXBoolLiteralExprVisitor Visitor;
- Visitor.ExpectMatch("true", 2, 19);
- EXPECT_TRUE(Visitor.runOver(
- "template<bool B> class X;\n"
- "template<bool B = true> class Y;\n"
- "template<bool B> class Y {};\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsClassTemplateTypeParmDefaultArgument) {
- TypeLocVisitor Visitor;
- Visitor.ExpectMatch("class X", 2, 23);
- EXPECT_TRUE(Visitor.runOver(
- "class X;\n"
- "template<typename T = X> class Y;\n"
- "template<typename T> class Y {};\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) {
- TemplateArgumentLocTraverser Visitor;
- Visitor.ExpectMatch("X", 2, 40);
- EXPECT_TRUE(Visitor.runOver(
- "template<typename T> class X;\n"
- "template<template <typename> class T = X> class Y;\n"
- "template<template <typename> class T> class Y {};\n"));
-}
-
-// A visitor that visits implicit declarations and matches constructors.
-class ImplicitCtorVisitor
- : public ExpectedLocationVisitor<ImplicitCtorVisitor> {
-public:
- bool shouldVisitImplicitCode() const { return true; }
-
- bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) {
- if (Ctor->isImplicit()) { // Was not written in source code
- if (const CXXRecordDecl* Class = Ctor->getParent()) {
- Match(Class->getName(), Ctor->getLocation());
- }
- }
- return true;
- }
-};
-
-TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) {
- ImplicitCtorVisitor Visitor;
- Visitor.ExpectMatch("Simple", 2, 8);
- // Note: Clang lazily instantiates implicit declarations, so we need
- // to use them in order to force them to appear in the AST.
- EXPECT_TRUE(Visitor.runOver(
- "struct WithCtor { WithCtor(); }; \n"
- "struct Simple { Simple(); WithCtor w; }; \n"
- "int main() { Simple s; Simple t(s); }\n"));
-}
-
-/// \brief A visitor that optionally includes implicit code and matches
-/// CXXConstructExpr.
-///
-/// The name recorded for the match is the name of the class whose constructor
-/// is invoked by the CXXConstructExpr, not the name of the class whose
-/// constructor the CXXConstructExpr is contained in.
-class ConstructExprVisitor
- : public ExpectedLocationVisitor<ConstructExprVisitor> {
-public:
- ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
-
- bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
-
- void setShouldVisitImplicitCode(bool NewValue) {
- ShouldVisitImplicitCode = NewValue;
- }
-
- bool VisitCXXConstructExpr(CXXConstructExpr* Expr) {
- if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) {
- if (const CXXRecordDecl* Class = Ctor->getParent()) {
- Match(Class->getName(), Expr->getLocation());
- }
- }
- return true;
- }
-
- private:
- bool ShouldVisitImplicitCode;
-};
-
-TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
- ConstructExprVisitor Visitor;
- Visitor.setShouldVisitImplicitCode(true);
- Visitor.ExpectMatch("WithCtor", 2, 8);
- // Simple has a constructor that implicitly initializes 'w'. Test
- // that a visitor that visits implicit code visits that initialization.
- // Note: Clang lazily instantiates implicit declarations, so we need
- // to use them in order to force them to appear in the AST.
- EXPECT_TRUE(Visitor.runOver(
- "struct WithCtor { WithCtor(); }; \n"
- "struct Simple { WithCtor w; }; \n"
- "int main() { Simple s; }\n"));
-}
-
-// The same as CanVisitImplicitMemberInitializations, but checking that the
-// visits are omitted when the visitor does not include implicit code.
-TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
- ConstructExprVisitor Visitor;
- Visitor.setShouldVisitImplicitCode(false);
- Visitor.DisallowMatch("WithCtor", 2, 8);
- // Simple has a constructor that implicitly initializes 'w'. Test
- // that a visitor that skips implicit code skips that initialization.
- // Note: Clang lazily instantiates implicit declarations, so we need
- // to use them in order to force them to appear in the AST.
- EXPECT_TRUE(Visitor.runOver(
- "struct WithCtor { WithCtor(); }; \n"
- "struct Simple { WithCtor w; }; \n"
- "int main() { Simple s; }\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsExtension) {
- DeclRefExprVisitor Visitor;
- Visitor.ExpectMatch("s", 1, 24);
- EXPECT_TRUE(Visitor.runOver(
- "int s = __extension__ (s);\n"));
-}
-
-TEST(RecursiveASTVisitor, VisitsCompoundLiteralType) {
- TypeLocVisitor Visitor;
- Visitor.ExpectMatch("struct S", 1, 26);
- EXPECT_TRUE(Visitor.runOver(
- "int f() { return (struct S { int a; }){.a = 0}.a; }",
- TypeLocVisitor::Lang_C));
-}
-
-TEST(RecursiveASTVisitor, VisitsObjCPropertyType) {
- TypeLocVisitor Visitor;
- Visitor.ExpectMatch("NSNumber", 2, 33);
- EXPECT_TRUE(Visitor.runOver(
- "@class NSNumber; \n"
- "@interface A @property (retain) NSNumber *x; @end\n",
- TypeLocVisitor::Lang_OBJC));
-}
-
TEST(RecursiveASTVisitor, VisitsLambdaExpr) {
LambdaExprVisitor Visitor;
Visitor.ExpectMatch("", 1, 12);
@@ -554,6 +52,18 @@ TEST(RecursiveASTVisitor, TraverseLambdaBodyCanBeOverridden) {
EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
}
+// Matches the (optional) capture-default of a lambda-introducer.
+class LambdaDefaultCaptureVisitor
+ : public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> {
+public:
+ bool VisitLambdaExpr(LambdaExpr *Lambda) {
+ if (Lambda->getCaptureDefault() != LCD_None) {
+ Match("", Lambda->getCaptureDefaultLoc());
+ }
+ return true;
+ }
+};
+
TEST(RecursiveASTVisitor, HasCaptureDefaultLoc) {
LambdaDefaultCaptureVisitor Visitor;
Visitor.ExpectMatch("", 1, 20);
@@ -561,16 +71,6 @@ TEST(RecursiveASTVisitor, HasCaptureDefaultLoc) {
LambdaDefaultCaptureVisitor::Lang_CXX11));
}
-TEST(RecursiveASTVisitor, VisitsCopyExprOfBlockDeclCapture) {
- DeclRefExprVisitor Visitor;
- Visitor.ExpectMatch("x", 3, 24);
- EXPECT_TRUE(Visitor.runOver("void f(int(^)(int)); \n"
- "void g() { \n"
- " f([&](int x){ return x; }); \n"
- "}",
- DeclRefExprVisitor::Lang_OBJCXX11));
-}
-
// Checks for lambda classes that are not marked as implicitly-generated.
// (There should be none.)
class ClassVisitor : public ExpectedLocationVisitor<ClassVisitor> {
@@ -598,7 +98,6 @@ TEST(RecursiveASTVisitor, LambdaClosureTypesAreImplicit) {
}
-
// Check to ensure that attributes and expressions within them are being
// visited.
class AttrVisitor : public ExpectedLocationVisitor<AttrVisitor> {
diff --git a/unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp
new file mode 100644
index 000000000000..f8ff5bdc7879
--- /dev/null
+++ b/unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp
@@ -0,0 +1,121 @@
+//===- unittest/Tooling/RecursiveASTVisitorTestCallVisitor.cpp ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+#include <stack>
+
+using namespace clang;
+
+namespace {
+
+class CXXMemberCallVisitor
+ : public ExpectedLocationVisitor<CXXMemberCallVisitor> {
+public:
+ bool VisitCXXMemberCallExpr(CXXMemberCallExpr *Call) {
+ Match(Call->getMethodDecl()->getQualifiedNameAsString(),
+ Call->getLocStart());
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsCallInTemplateInstantiation) {
+ CXXMemberCallVisitor Visitor;
+ Visitor.ExpectMatch("Y::x", 3, 3);
+ EXPECT_TRUE(Visitor.runOver(
+ "struct Y { void x(); };\n"
+ "template<typename T> void y(T t) {\n"
+ " t.x();\n"
+ "}\n"
+ "void foo() { y<Y>(Y()); }"));
+}
+
+TEST(RecursiveASTVisitor, VisitsCallInNestedFunctionTemplateInstantiation) {
+ CXXMemberCallVisitor Visitor;
+ Visitor.ExpectMatch("Y::x", 4, 5);
+ EXPECT_TRUE(Visitor.runOver(
+ "struct Y { void x(); };\n"
+ "template<typename T> struct Z {\n"
+ " template<typename U> static void f() {\n"
+ " T().x();\n"
+ " }\n"
+ "};\n"
+ "void foo() { Z<Y>::f<int>(); }"));
+}
+
+TEST(RecursiveASTVisitor, VisitsCallInNestedClassTemplateInstantiation) {
+ CXXMemberCallVisitor Visitor;
+ Visitor.ExpectMatch("A::x", 5, 7);
+ EXPECT_TRUE(Visitor.runOver(
+ "template <typename T1> struct X {\n"
+ " template <typename T2> struct Y {\n"
+ " void f() {\n"
+ " T2 y;\n"
+ " y.x();\n"
+ " }\n"
+ " };\n"
+ "};\n"
+ "struct A { void x(); };\n"
+ "int main() {\n"
+ " (new X<A>::Y<A>())->f();\n"
+ "}"));
+}
+
+TEST(RecursiveASTVisitor, VisitsCallInPartialTemplateSpecialization) {
+ CXXMemberCallVisitor Visitor;
+ Visitor.ExpectMatch("A::x", 6, 20);
+ EXPECT_TRUE(Visitor.runOver(
+ "template <typename T1> struct X {\n"
+ " template <typename T2, bool B> struct Y { void g(); };\n"
+ "};\n"
+ "template <typename T1> template <typename T2>\n"
+ "struct X<T1>::Y<T2, true> {\n"
+ " void f() { T2 y; y.x(); }\n"
+ "};\n"
+ "struct A { void x(); };\n"
+ "int main() {\n"
+ " (new X<A>::Y<A, true>())->f();\n"
+ "}\n"));
+}
+
+TEST(RecursiveASTVisitor, VisitsExplicitTemplateSpecialization) {
+ CXXMemberCallVisitor Visitor;
+ Visitor.ExpectMatch("A::f", 4, 5);
+ EXPECT_TRUE(Visitor.runOver(
+ "struct A {\n"
+ " void f() const {}\n"
+ " template<class T> void g(const T& t) const {\n"
+ " t.f();\n"
+ " }\n"
+ "};\n"
+ "template void A::g(const A& a) const;\n"));
+}
+
+class CXXOperatorCallExprTraverser
+ : public ExpectedLocationVisitor<CXXOperatorCallExprTraverser> {
+public:
+ // Use Traverse, not Visit, to check that data recursion optimization isn't
+ // bypassing the call of this function.
+ bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE) {
+ Match(getOperatorSpelling(CE->getOperator()), CE->getExprLoc());
+ return ExpectedLocationVisitor<CXXOperatorCallExprTraverser>::
+ TraverseCXXOperatorCallExpr(CE);
+ }
+};
+
+TEST(RecursiveASTVisitor, TraversesOverloadedOperator) {
+ CXXOperatorCallExprTraverser Visitor;
+ Visitor.ExpectMatch("()", 4, 9);
+ EXPECT_TRUE(Visitor.runOver(
+ "struct A {\n"
+ " int operator()();\n"
+ "} a;\n"
+ "int k = a();\n"));
+}
+
+} // end anonymous namespace
diff --git a/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp
new file mode 100644
index 000000000000..02676a737ab1
--- /dev/null
+++ b/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp
@@ -0,0 +1,141 @@
+//===- unittest/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+#include <stack>
+
+using namespace clang;
+
+namespace {
+
+class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
+public:
+ bool VisitVarDecl(VarDecl *Variable) {
+ Match(Variable->getNameAsString(), Variable->getLocStart());
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) {
+ VarDeclVisitor Visitor;
+ Visitor.ExpectMatch("i", 2, 17);
+ EXPECT_TRUE(Visitor.runOver(
+ "int x[5];\n"
+ "void f() { for (int i : x) {} }",
+ VarDeclVisitor::Lang_CXX11));
+}
+
+class ParmVarDeclVisitorForImplicitCode :
+ public ExpectedLocationVisitor<ParmVarDeclVisitorForImplicitCode> {
+public:
+ bool shouldVisitImplicitCode() const { return true; }
+
+ bool VisitParmVarDecl(ParmVarDecl *ParamVar) {
+ Match(ParamVar->getNameAsString(), ParamVar->getLocStart());
+ return true;
+ }
+};
+
+// Test RAV visits parameter variable declaration of the implicit
+// copy assignment operator and implicit copy constructor.
+TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) {
+ ParmVarDeclVisitorForImplicitCode Visitor;
+ // Match parameter variable name of implicit copy assignment operator and
+ // implicit copy constructor.
+ // This parameter name does not have a valid IdentifierInfo, and shares
+ // same SourceLocation with its class declaration, so we match an empty name
+ // with the class' source location.
+ Visitor.ExpectMatch("", 1, 7);
+ Visitor.ExpectMatch("", 3, 7);
+ EXPECT_TRUE(Visitor.runOver(
+ "class X {};\n"
+ "void foo(X a, X b) {a = b;}\n"
+ "class Y {};\n"
+ "void bar(Y a) {Y b = a;}"));
+}
+
+class NamedDeclVisitor
+ : public ExpectedLocationVisitor<NamedDeclVisitor> {
+public:
+ bool VisitNamedDecl(NamedDecl *Decl) {
+ std::string NameWithTemplateArgs;
+ llvm::raw_string_ostream OS(NameWithTemplateArgs);
+ Decl->getNameForDiagnostic(OS,
+ Decl->getASTContext().getPrintingPolicy(),
+ true);
+ Match(OS.str(), Decl->getLocation());
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsPartialTemplateSpecialization) {
+ // From cfe-commits/Week-of-Mon-20100830/033998.html
+ // Contrary to the approach suggested in that email, we visit all
+ // specializations when we visit the primary template. Visiting them when we
+ // visit the associated specialization is problematic for specializations of
+ // template members of class templates.
+ NamedDeclVisitor Visitor;
+ Visitor.ExpectMatch("A<bool>", 1, 26);
+ Visitor.ExpectMatch("A<char *>", 2, 26);
+ EXPECT_TRUE(Visitor.runOver(
+ "template <class T> class A {};\n"
+ "template <class T> class A<T*> {};\n"
+ "A<bool> ab;\n"
+ "A<char*> acp;\n"));
+}
+
+TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) {
+ NamedDeclVisitor Visitor;
+ Visitor.ExpectMatch("A<int>", 1, 29);
+ EXPECT_TRUE(Visitor.runOver(
+ "template<typename T> struct A;\n"
+ "A<int> *p;\n"));
+}
+
+TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) {
+ NamedDeclVisitor Visitor;
+ Visitor.ExpectMatch("A<int>::B<char>", 2, 31);
+ EXPECT_TRUE(Visitor.runOver(
+ "template<typename T> struct A {\n"
+ " template<typename U> struct B;\n"
+ "};\n"
+ "A<int>::B<char> *p;\n"));
+}
+
+TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) {
+ NamedDeclVisitor Visitor;
+ Visitor.ExpectMatch("A<int>", 1, 26);
+ EXPECT_TRUE(Visitor.runOver(
+ "template<typename T> int A();\n"
+ "int k = A<int>();\n"));
+}
+
+TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) {
+ NamedDeclVisitor Visitor;
+ Visitor.ExpectMatch("A<int>::B<char>", 2, 35);
+ EXPECT_TRUE(Visitor.runOver(
+ "template<typename T> struct A {\n"
+ " template<typename U> static int B();\n"
+ "};\n"
+ "int k = A<int>::B<char>();\n"));
+}
+
+TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) {
+ // From cfe-commits/Week-of-Mon-20100830/033977.html
+ NamedDeclVisitor Visitor;
+ Visitor.ExpectMatch("vector_iterator<int>", 2, 7);
+ EXPECT_TRUE(Visitor.runOver(
+ "template<typename Container>\n"
+ "class vector_iterator {\n"
+ " template <typename C> friend class vector_iterator;\n"
+ "};\n"
+ "vector_iterator<int> it_int;\n"));
+}
+
+} // end anonymous namespace
diff --git a/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
new file mode 100644
index 000000000000..6af5906c3fd4
--- /dev/null
+++ b/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
@@ -0,0 +1,224 @@
+//===- unittest/Tooling/RecursiveASTVisitorTestExprVisitor.cpp ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+#include <stack>
+
+using namespace clang;
+
+namespace {
+
+class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> {
+public:
+ bool VisitParenExpr(ParenExpr *Parens) {
+ Match("", Parens->getExprLoc());
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) {
+ ParenExprVisitor Visitor;
+ Visitor.ExpectMatch("", 1, 9);
+ EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n"));
+}
+
+class TemplateArgumentLocTraverser
+ : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> {
+public:
+ bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
+ std::string ArgStr;
+ llvm::raw_string_ostream Stream(ArgStr);
+ const TemplateArgument &Arg = ArgLoc.getArgument();
+
+ Arg.print(Context->getPrintingPolicy(), Stream);
+ Match(Stream.str(), ArgLoc.getLocation());
+ return ExpectedLocationVisitor<TemplateArgumentLocTraverser>::
+ TraverseTemplateArgumentLoc(ArgLoc);
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) {
+ TemplateArgumentLocTraverser Visitor;
+ Visitor.ExpectMatch("X", 2, 40);
+ EXPECT_TRUE(Visitor.runOver(
+ "template<typename T> class X;\n"
+ "template<template <typename> class T = X> class Y;\n"
+ "template<template <typename> class T> class Y {};\n"));
+}
+
+class CXXBoolLiteralExprVisitor
+ : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> {
+public:
+ bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) {
+ if (BE->getValue())
+ Match("true", BE->getLocation());
+ else
+ Match("false", BE->getLocation());
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsClassTemplateNonTypeParmDefaultArgument) {
+ CXXBoolLiteralExprVisitor Visitor;
+ Visitor.ExpectMatch("true", 2, 19);
+ EXPECT_TRUE(Visitor.runOver(
+ "template<bool B> class X;\n"
+ "template<bool B = true> class Y;\n"
+ "template<bool B> class Y {};\n"));
+}
+
+// A visitor that visits implicit declarations and matches constructors.
+class ImplicitCtorVisitor
+ : public ExpectedLocationVisitor<ImplicitCtorVisitor> {
+public:
+ bool shouldVisitImplicitCode() const { return true; }
+
+ bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) {
+ if (Ctor->isImplicit()) { // Was not written in source code
+ if (const CXXRecordDecl* Class = Ctor->getParent()) {
+ Match(Class->getName(), Ctor->getLocation());
+ }
+ }
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) {
+ ImplicitCtorVisitor Visitor;
+ Visitor.ExpectMatch("Simple", 2, 8);
+ // Note: Clang lazily instantiates implicit declarations, so we need
+ // to use them in order to force them to appear in the AST.
+ EXPECT_TRUE(Visitor.runOver(
+ "struct WithCtor { WithCtor(); }; \n"
+ "struct Simple { Simple(); WithCtor w; }; \n"
+ "int main() { Simple s; Simple t(s); }\n"));
+}
+
+/// \brief A visitor that optionally includes implicit code and matches
+/// CXXConstructExpr.
+///
+/// The name recorded for the match is the name of the class whose constructor
+/// is invoked by the CXXConstructExpr, not the name of the class whose
+/// constructor the CXXConstructExpr is contained in.
+class ConstructExprVisitor
+ : public ExpectedLocationVisitor<ConstructExprVisitor> {
+public:
+ ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
+
+ bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
+
+ void setShouldVisitImplicitCode(bool NewValue) {
+ ShouldVisitImplicitCode = NewValue;
+ }
+
+ bool VisitCXXConstructExpr(CXXConstructExpr* Expr) {
+ if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) {
+ if (const CXXRecordDecl* Class = Ctor->getParent()) {
+ Match(Class->getName(), Expr->getLocation());
+ }
+ }
+ return true;
+ }
+
+ private:
+ bool ShouldVisitImplicitCode;
+};
+
+TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
+ ConstructExprVisitor Visitor;
+ Visitor.setShouldVisitImplicitCode(true);
+ Visitor.ExpectMatch("WithCtor", 2, 8);
+ // Simple has a constructor that implicitly initializes 'w'. Test
+ // that a visitor that visits implicit code visits that initialization.
+ // Note: Clang lazily instantiates implicit declarations, so we need
+ // to use them in order to force them to appear in the AST.
+ EXPECT_TRUE(Visitor.runOver(
+ "struct WithCtor { WithCtor(); }; \n"
+ "struct Simple { WithCtor w; }; \n"
+ "int main() { Simple s; }\n"));
+}
+
+// The same as CanVisitImplicitMemberInitializations, but checking that the
+// visits are omitted when the visitor does not include implicit code.
+TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
+ ConstructExprVisitor Visitor;
+ Visitor.setShouldVisitImplicitCode(false);
+ Visitor.DisallowMatch("WithCtor", 2, 8);
+ // Simple has a constructor that implicitly initializes 'w'. Test
+ // that a visitor that skips implicit code skips that initialization.
+ // Note: Clang lazily instantiates implicit declarations, so we need
+ // to use them in order to force them to appear in the AST.
+ EXPECT_TRUE(Visitor.runOver(
+ "struct WithCtor { WithCtor(); }; \n"
+ "struct Simple { WithCtor w; }; \n"
+ "int main() { Simple s; }\n"));
+}
+
+class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
+public:
+ bool VisitDeclRefExpr(DeclRefExpr *Reference) {
+ Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
+ DeclRefExprVisitor Visitor;
+ Visitor.ExpectMatch("x", 2, 3);
+ EXPECT_TRUE(Visitor.runOver(
+ "void x(); template <void (*T)()> class X {};\nX<x> y;"));
+}
+
+TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) {
+ DeclRefExprVisitor Visitor;
+ Visitor.ExpectMatch("x", 2, 25);
+ Visitor.ExpectMatch("x", 2, 30);
+ EXPECT_TRUE(Visitor.runOver(
+ "int x[5];\n"
+ "void f() { for (int i : x) { x[0] = 1; } }",
+ DeclRefExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, VisitsCallExpr) {
+ DeclRefExprVisitor Visitor;
+ Visitor.ExpectMatch("x", 1, 22);
+ EXPECT_TRUE(Visitor.runOver(
+ "void x(); void y() { x(); }"));
+}
+
+/* FIXME: According to Richard Smith this is a bug in the AST.
+TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
+ DeclRefExprVisitor Visitor;
+ Visitor.ExpectMatch("x", 3, 43);
+ EXPECT_TRUE(Visitor.runOver(
+ "template <typename T> void x();\n"
+ "template <void (*T)()> class X {};\n"
+ "template <typename T> class Y : public X< x<T> > {};\n"
+ "Y<int> y;"));
+}
+*/
+
+TEST(RecursiveASTVisitor, VisitsExtension) {
+ DeclRefExprVisitor Visitor;
+ Visitor.ExpectMatch("s", 1, 24);
+ EXPECT_TRUE(Visitor.runOver(
+ "int s = __extension__ (s);\n"));
+}
+
+TEST(RecursiveASTVisitor, VisitsCopyExprOfBlockDeclCapture) {
+ DeclRefExprVisitor Visitor;
+ Visitor.ExpectMatch("x", 3, 24);
+ EXPECT_TRUE(Visitor.runOver("void f(int(^)(int)); \n"
+ "void g() { \n"
+ " f([&](int x){ return x; }); \n"
+ "}",
+ DeclRefExprVisitor::Lang_OBJCXX11));
+}
+
+} // end anonymous namespace
diff --git a/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
new file mode 100644
index 000000000000..63e2e8b6024c
--- /dev/null
+++ b/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
@@ -0,0 +1,93 @@
+//===- unittest/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+#include <stack>
+
+using namespace clang;
+
+namespace {
+
+class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> {
+public:
+ bool VisitTypeLoc(TypeLoc TypeLocation) {
+ Match(TypeLocation.getType().getAsString(), TypeLocation.getBeginLoc());
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("class X", 1, 30);
+ EXPECT_TRUE(Visitor.runOver("class X {}; class Y : public X {};"));
+}
+
+TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfForwardDeclaredClass) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("class X", 3, 18);
+ EXPECT_TRUE(Visitor.runOver(
+ "class Y;\n"
+ "class X {};\n"
+ "class Y : public X {};"));
+}
+
+TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersWithIncompleteInnerClass) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("class X", 2, 18);
+ EXPECT_TRUE(Visitor.runOver(
+ "class X {};\n"
+ "class Y : public X { class Z; };"));
+}
+
+TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfSelfReferentialType) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("X<class Y>", 2, 18);
+ EXPECT_TRUE(Visitor.runOver(
+ "template<typename T> class X {};\n"
+ "class Y : public X<Y> {};"));
+}
+
+TEST(RecursiveASTVisitor, VisitsClassTemplateTypeParmDefaultArgument) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("class X", 2, 23);
+ EXPECT_TRUE(Visitor.runOver(
+ "class X;\n"
+ "template<typename T = X> class Y;\n"
+ "template<typename T> class Y {};\n"));
+}
+
+TEST(RecursiveASTVisitor, VisitsCompoundLiteralType) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("struct S", 1, 26);
+ EXPECT_TRUE(Visitor.runOver(
+ "int f() { return (struct S { int a; }){.a = 0}.a; }",
+ TypeLocVisitor::Lang_C));
+}
+
+TEST(RecursiveASTVisitor, VisitsObjCPropertyType) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("NSNumber", 2, 33);
+ EXPECT_TRUE(Visitor.runOver(
+ "@class NSNumber; \n"
+ "@interface A @property (retain) NSNumber *x; @end\n",
+ TypeLocVisitor::Lang_OBJC));
+}
+
+TEST(RecursiveASTVisitor, VisitInvalidType) {
+ TypeLocVisitor Visitor;
+ // FIXME: It would be nice to have information about subtypes of invalid type
+ //Visitor.ExpectMatch("typeof(struct F *) []", 1, 1);
+ // Even if the full type is invalid, it should still find sub types
+ //Visitor.ExpectMatch("struct F", 1, 19);
+ EXPECT_FALSE(Visitor.runOver(
+ "__typeof__(struct F*) var[invalid];\n",
+ TypeLocVisitor::Lang_C));
+}
+
+} // end anonymous namespace
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index ddb974ac9f4a..a026a942610b 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -237,7 +237,8 @@ public:
const FileEntry *File = Context.Files.getFile(Path);
assert(File != nullptr);
- StringRef Found = TemporaryFiles.GetOrCreateValue(Name, Path.str()).second;
+ StringRef Found =
+ TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second;
assert(Found == Path);
(void)Found;
return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
@@ -251,9 +252,8 @@ public:
// descriptor, which might not see the changes made.
// FIXME: Figure out whether there is a way to get the SourceManger to
// reopen the file.
- std::unique_ptr<const llvm::MemoryBuffer> FileBuffer(
- Context.Files.getBufferForFile(Path, nullptr));
- return FileBuffer->getBuffer();
+ auto FileBuffer = Context.Files.getBufferForFile(Path);
+ return (*FileBuffer)->getBuffer();
}
llvm::StringMap<std::string> TemporaryFiles;
@@ -299,11 +299,12 @@ private:
public:
TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
- virtual clang::ASTConsumer* CreateASTConsumer(
- clang::CompilerInstance& compiler, llvm::StringRef dummy) {
+ virtual std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &compiler,
+ llvm::StringRef dummy) {
Visitor->SM = &compiler.getSourceManager();
/// TestConsumer will be deleted by the framework calling us.
- return new FindConsumer(Visitor);
+ return llvm::make_unique<FindConsumer>(Visitor);
}
private:
@@ -392,6 +393,8 @@ TEST(DeduplicateTest, removesDuplicates) {
Input.push_back(Replacement("fileA", 50, 0, " foo ")); // Duplicate
Input.push_back(Replacement("fileA", 51, 3, " bar "));
Input.push_back(Replacement("fileB", 51, 3, " bar ")); // Filename differs!
+ Input.push_back(Replacement("fileB", 60, 1, " bar "));
+ Input.push_back(Replacement("fileA", 60, 2, " bar "));
Input.push_back(Replacement("fileA", 51, 3, " moo ")); // Replacement text
// differs!
@@ -402,12 +405,14 @@ TEST(DeduplicateTest, removesDuplicates) {
Expected.push_back(Replacement("fileA", 50, 0, " foo "));
Expected.push_back(Replacement("fileA", 51, 3, " bar "));
Expected.push_back(Replacement("fileA", 51, 3, " moo "));
- Expected.push_back(Replacement("fileB", 51, 3, " bar "));
+ Expected.push_back(Replacement("fileB", 60, 1, " bar "));
+ Expected.push_back(Replacement("fileA", 60, 2, " bar "));
std::vector<Range> Conflicts; // Ignored for this test
deduplicate(Input, Conflicts);
- ASSERT_TRUE(Expected == Input);
+ EXPECT_EQ(3U, Conflicts.size());
+ EXPECT_EQ(Expected, Input);
}
TEST(DeduplicateTest, detectsConflicts) {
diff --git a/unittests/Tooling/RewriterTestContext.h b/unittests/Tooling/RewriterTestContext.h
index fe108ad308e5..112efac52ebc 100644
--- a/unittests/Tooling/RewriterTestContext.h
+++ b/unittests/Tooling/RewriterTestContext.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_REWRITER_TEST_CONTEXT_H
-#define LLVM_CLANG_REWRITER_TEST_CONTEXT_H
+#ifndef LLVM_CLANG_UNITTESTS_TOOLING_REWRITERTESTCONTEXT_H
+#define LLVM_CLANG_UNITTESTS_TOOLING_REWRITERTESTCONTEXT_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
@@ -48,10 +48,11 @@ class RewriterTestContext {
~RewriterTestContext() {}
FileID createInMemoryFile(StringRef Name, StringRef Content) {
- llvm::MemoryBuffer *Source = llvm::MemoryBuffer::getMemBuffer(Content);
+ std::unique_ptr<llvm::MemoryBuffer> Source =
+ llvm::MemoryBuffer::getMemBuffer(Content);
const FileEntry *Entry =
Files.getVirtualFile(Name, Source->getBufferSize(), 0);
- Sources.overrideFileContents(Entry, Source);
+ Sources.overrideFileContents(Entry, std::move(Source));
assert(Entry != nullptr);
return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
}
@@ -71,7 +72,8 @@ class RewriterTestContext {
const FileEntry *File = Files.getFile(Path);
assert(File != nullptr);
- StringRef Found = TemporaryFiles.GetOrCreateValue(Name, Path.str()).second;
+ StringRef Found =
+ TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second;
assert(Found == Path);
(void)Found;
return Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
@@ -100,9 +102,8 @@ class RewriterTestContext {
// descriptor, which might not see the changes made.
// FIXME: Figure out whether there is a way to get the SourceManger to
// reopen the file.
- std::unique_ptr<const llvm::MemoryBuffer> FileBuffer(
- Files.getBufferForFile(Path, nullptr));
- return FileBuffer->getBuffer();
+ auto FileBuffer = Files.getBufferForFile(Path);
+ return (*FileBuffer)->getBuffer();
}
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
diff --git a/unittests/Tooling/TestVisitor.h b/unittests/Tooling/TestVisitor.h
index 205a0aa16eb6..d4416950f226 100644
--- a/unittests/Tooling/TestVisitor.h
+++ b/unittests/Tooling/TestVisitor.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TEST_VISITOR_H
-#define LLVM_CLANG_TEST_VISITOR_H
+#ifndef LLVM_CLANG_UNITTESTS_TOOLING_TESTVISITOR_H
+#define LLVM_CLANG_UNITTESTS_TOOLING_TESTVISITOR_H
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -95,10 +95,10 @@ protected:
public:
TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
- virtual clang::ASTConsumer* CreateASTConsumer(
- CompilerInstance&, llvm::StringRef dummy) {
+ virtual std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(CompilerInstance &, llvm::StringRef dummy) {
/// TestConsumer will be deleted by the framework calling us.
- return new FindConsumer(Visitor);
+ return llvm::make_unique<FindConsumer>(Visitor);
}
protected:
@@ -231,4 +231,4 @@ protected:
};
}
-#endif /* LLVM_CLANG_TEST_VISITOR_H */
+#endif
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index 9aede044f695..5a93e38c80c2 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/llvm-config.h"
#include "gtest/gtest.h"
+#include <algorithm>
#include <string>
namespace clang {
@@ -28,20 +29,20 @@ namespace {
/// Takes an ast consumer and returns it from CreateASTConsumer. This only
/// works with single translation unit compilations.
class TestAction : public clang::ASTFrontendAction {
- public:
+public:
/// Takes ownership of TestConsumer.
- explicit TestAction(clang::ASTConsumer *TestConsumer)
- : TestConsumer(TestConsumer) {}
+ explicit TestAction(std::unique_ptr<clang::ASTConsumer> TestConsumer)
+ : TestConsumer(std::move(TestConsumer)) {}
- protected:
- virtual clang::ASTConsumer* CreateASTConsumer(
- clang::CompilerInstance& compiler, StringRef dummy) {
+protected:
+ virtual std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &compiler, StringRef dummy) {
/// TestConsumer will be deleted by the framework calling us.
- return TestConsumer;
+ return std::move(TestConsumer);
}
- private:
- clang::ASTConsumer * const TestConsumer;
+private:
+ std::unique_ptr<clang::ASTConsumer> TestConsumer;
};
class FindTopLevelDeclConsumer : public clang::ASTConsumer {
@@ -59,8 +60,10 @@ class FindTopLevelDeclConsumer : public clang::ASTConsumer {
TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) {
bool FoundTopLevelDecl = false;
- EXPECT_TRUE(runToolOnCode(
- new TestAction(new FindTopLevelDeclConsumer(&FoundTopLevelDecl)), ""));
+ EXPECT_TRUE(
+ runToolOnCode(new TestAction(llvm::make_unique<FindTopLevelDeclConsumer>(
+ &FoundTopLevelDecl)),
+ ""));
EXPECT_FALSE(FoundTopLevelDecl);
}
@@ -97,13 +100,17 @@ bool FindClassDeclX(ASTUnit *AST) {
TEST(runToolOnCode, FindsClassDecl) {
bool FoundClassDeclX = false;
- EXPECT_TRUE(runToolOnCode(new TestAction(
- new FindClassDeclXConsumer(&FoundClassDeclX)), "class X;"));
+ EXPECT_TRUE(
+ runToolOnCode(new TestAction(llvm::make_unique<FindClassDeclXConsumer>(
+ &FoundClassDeclX)),
+ "class X;"));
EXPECT_TRUE(FoundClassDeclX);
FoundClassDeclX = false;
- EXPECT_TRUE(runToolOnCode(new TestAction(
- new FindClassDeclXConsumer(&FoundClassDeclX)), "class Y;"));
+ EXPECT_TRUE(
+ runToolOnCode(new TestAction(llvm::make_unique<FindClassDeclXConsumer>(
+ &FoundClassDeclX)),
+ "class Y;"));
EXPECT_FALSE(FoundClassDeclX);
}
@@ -125,8 +132,8 @@ TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
}
struct IndependentFrontendActionCreator {
- ASTConsumer *newASTConsumer() {
- return new FindTopLevelDeclConsumer(nullptr);
+ std::unique_ptr<ASTConsumer> newASTConsumer() {
+ return llvm::make_unique<FindTopLevelDeclConsumer>(nullptr);
}
};
@@ -182,11 +189,11 @@ struct VerifyEndCallback : public SourceFileCallbacks {
++BeginCalled;
return true;
}
- virtual void handleEndSource() {
+ virtual void handleEndSource() override {
++EndCalled;
}
- ASTConsumer *newASTConsumer() {
- return new FindTopLevelDeclConsumer(&Matched);
+ std::unique_ptr<ASTConsumer> newASTConsumer() {
+ return llvm::make_unique<FindTopLevelDeclConsumer>(&Matched);
}
unsigned BeginCalled;
unsigned EndCalled;
@@ -225,10 +232,10 @@ struct SkipBodyConsumer : public clang::ASTConsumer {
};
struct SkipBodyAction : public clang::ASTFrontendAction {
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &Compiler,
- StringRef) {
+ virtual std::unique_ptr<ASTConsumer>
+ CreateASTConsumer(CompilerInstance &Compiler, StringRef) {
Compiler.getFrontendOpts().SkipFunctionBodies = true;
- return new SkipBodyConsumer;
+ return llvm::make_unique<SkipBodyConsumer>();
}
};
@@ -254,25 +261,6 @@ TEST(runToolOnCodeWithArgs, TestNoDepFile) {
EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str()));
}
-struct CheckSyntaxOnlyAdjuster: public ArgumentsAdjuster {
- bool &Found;
- bool &Ran;
-
- CheckSyntaxOnlyAdjuster(bool &Found, bool &Ran) : Found(Found), Ran(Ran) { }
-
- virtual CommandLineArguments
- Adjust(const CommandLineArguments &Args) override {
- Ran = true;
- for (unsigned I = 0, E = Args.size(); I != E; ++I) {
- if (Args[I] == "-fsyntax-only") {
- Found = true;
- break;
- }
- }
- return Args;
- }
-};
-
TEST(ClangToolTest, ArgumentAdjusters) {
FixedCompilationDatabase Compilations("/", std::vector<std::string>());
@@ -284,15 +272,22 @@ TEST(ClangToolTest, ArgumentAdjusters) {
bool Found = false;
bool Ran = false;
- Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
+ ArgumentsAdjuster CheckSyntaxOnlyAdjuster =
+ [&Found, &Ran](const CommandLineArguments &Args) {
+ Ran = true;
+ if (std::find(Args.begin(), Args.end(), "-fsyntax-only") != Args.end())
+ Found = true;
+ return Args;
+ };
+ Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
Tool.run(Action.get());
EXPECT_TRUE(Ran);
EXPECT_TRUE(Found);
Ran = Found = false;
Tool.clearArgumentsAdjusters();
- Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
- Tool.appendArgumentsAdjuster(new ClangSyntaxOnlyAdjuster());
+ Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
+ Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
Tool.run(Action.get());
EXPECT_TRUE(Ran);
EXPECT_FALSE(Found);
diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp
index ee56e229367b..a21881429e62 100644
--- a/unittests/libclang/LibclangTest.cpp
+++ b/unittests/libclang/LibclangTest.cpp
@@ -8,11 +8,11 @@
//===----------------------------------------------------------------------===//
#include "clang-c/Index.h"
-#include "gtest/gtest.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
#include <fstream>
#include <set>
#define DEBUG_TYPE "libclang-test"
diff --git a/unittests/libclang/Makefile b/unittests/libclang/Makefile
index a6590eb97aeb..f8e83aa83a1b 100644
--- a/unittests/libclang/Makefile
+++ b/unittests/libclang/Makefile
@@ -20,6 +20,7 @@ USEDLIBS = clang.a \
clangIndex.a clangFormat.a clangRewrite.a \
clangFrontend.a clangDriver.a \
clangTooling.a \
+ clangToolingCore.a \
clangSerialization.a clangParse.a clangSema.a \
clangAnalysis.a clangEdit.a clangAST.a clangLex.a \
clangBasic.a
diff --git a/utils/ABITest/ABITestGen.py b/utils/ABITest/ABITestGen.py
index 4855f4893c9d..27cc5ec25823 100755
--- a/utils/ABITest/ABITestGen.py
+++ b/utils/ABITest/ABITestGen.py
@@ -214,7 +214,7 @@ class TypePrinter:
yield '(%s) 1'%(t.name,)
elif isinstance(t, EnumType):
for i in range(0, len(t.enumerators)):
- yield 'enum%dval%d' % (t.index, i)
+ yield 'enum%dval%d_%d' % (t.index, i, t.unique_id)
elif isinstance(t, RecordType):
nonPadding = [f for f in t.fields
if not f.isPaddingBitField()]
diff --git a/utils/ABITest/TypeGen.py b/utils/ABITest/TypeGen.py
index 7a99d628cd2e..1e4471c71e57 100644
--- a/utils/ABITest/TypeGen.py
+++ b/utils/ABITest/TypeGen.py
@@ -56,16 +56,20 @@ class BuiltinType(Type):
return self.name
class EnumType(Type):
+ unique_id = 0
+
def __init__(self, index, enumerators):
self.index = index
self.enumerators = enumerators
+ self.unique_id = self.__class__.unique_id
+ self.__class__.unique_id += 1
def getEnumerators(self):
result = ''
for i, init in enumerate(self.enumerators):
if i > 0:
result = result + ', '
- result = result + 'enum%dval%d' % (self.index, i)
+ result = result + 'enum%dval%d_%d' % (self.index, i, self.unique_id)
if init:
result = result + ' = %s' % (init)
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index 1790dcbd8d33..a73be2e0815b 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
@@ -206,6 +207,7 @@ namespace {
virtual bool isEnumArg() const { return false; }
virtual bool isVariadicEnumArg() const { return false; }
+ virtual bool isVariadic() const { return false; }
virtual void writeImplicitCtorArgs(raw_ostream &OS) const {
OS << getUpperName();
@@ -485,18 +487,18 @@ namespace {
}
void writeValue(raw_ostream &OS) const override {
OS << "\";\n";
- OS << " assert(is" << getLowerName() << "Expr && " << getLowerName()
- << "Expr != nullptr);\n";
- OS << " " << getLowerName() << "Expr->printPretty(OS, 0, Policy);\n";
+ // The aligned attribute argument expression is optional.
+ OS << " if (is" << getLowerName() << "Expr && "
+ << getLowerName() << "Expr)\n";
+ OS << " " << getLowerName() << "Expr->printPretty(OS, 0, Policy);\n";
OS << " OS << \"";
}
void writeDump(raw_ostream &OS) const override {
}
void writeDumpChildren(raw_ostream &OS) const override {
- OS << " if (SA->is" << getUpperName() << "Expr()) {\n";
- OS << " lastChild();\n";
+ OS << " if (SA->is" << getUpperName() << "Expr())\n";
OS << " dumpStmt(SA->get" << getUpperName() << "Expr());\n";
- OS << " } else\n";
+ OS << " else\n";
OS << " dumpType(SA->get" << getUpperName()
<< "Type()->getType());\n";
}
@@ -508,12 +510,19 @@ namespace {
class VariadicArgument : public Argument {
std::string Type, ArgName, ArgSizeName, RangeName;
+ protected:
+ // Assumed to receive a parameter: raw_ostream OS.
+ virtual void writeValueImpl(raw_ostream &OS) const {
+ OS << " OS << Val;\n";
+ }
+
public:
VariadicArgument(const Record &Arg, StringRef Attr, std::string T)
: Argument(Arg, Attr), Type(T), ArgName(getLowerName().str() + "_"),
ArgSizeName(ArgName + "Size"), RangeName(getLowerName()) {}
std::string getType() const { return Type; }
+ bool isVariadic() const override { return true; }
void writeAccessors(raw_ostream &OS) const override {
std::string IteratorType = getLowerName().str() + "_iterator";
@@ -586,9 +595,9 @@ namespace {
OS << " bool isFirst = true;\n"
<< " for (const auto &Val : " << RangeName << "()) {\n"
<< " if (isFirst) isFirst = false;\n"
- << " else OS << \", \";\n"
- << " OS << Val;\n"
- << " }\n";
+ << " else OS << \", \";\n";
+ writeValueImpl(OS);
+ OS << " }\n";
OS << " OS << \"";
}
void writeDump(raw_ostream &OS) const override {
@@ -675,7 +684,11 @@ namespace {
OS << "Record.push_back(SA->get" << getUpperName() << "());\n";
}
void writeValue(raw_ostream &OS) const override {
- OS << "\" << get" << getUpperName() << "() << \"";
+ // FIXME: this isn't 100% correct -- some enum arguments require printing
+ // as a string literal, while others require printing as an identifier.
+ // Tablegen currently does not distinguish between the two forms.
+ OS << "\\\"\" << " << getAttrName() << "Attr::Convert" << type << "ToStr(get"
+ << getUpperName() << "()) << \"\\\"";
}
void writeDump(raw_ostream &OS) const override {
OS << " switch(SA->get" << getUpperName() << "()) {\n";
@@ -700,13 +713,40 @@ namespace {
OS << " if (R) {\n";
OS << " Out = *R;\n return true;\n }\n";
OS << " return false;\n";
- OS << " }\n";
+ OS << " }\n\n";
+
+ // Mapping from enumeration values back to enumeration strings isn't
+ // trivial because some enumeration values have multiple named
+ // enumerators, such as type_visibility(internal) and
+ // type_visibility(hidden) both mapping to TypeVisibilityAttr::Hidden.
+ OS << " static const char *Convert" << type << "ToStr("
+ << type << " Val) {\n"
+ << " switch(Val) {\n";
+ std::set<std::string> Uniques;
+ for (size_t I = 0; I < enums.size(); ++I) {
+ if (Uniques.insert(enums[I]).second)
+ OS << " case " << getAttrName() << "Attr::" << enums[I]
+ << ": return \"" << values[I] << "\";\n";
+ }
+ OS << " }\n"
+ << " llvm_unreachable(\"No enumerator with that value\");\n"
+ << " }\n";
}
};
class VariadicEnumArgument: public VariadicArgument {
std::string type, QualifiedTypeName;
std::vector<std::string> values, enums, uniques;
+
+ protected:
+ void writeValueImpl(raw_ostream &OS) const override {
+ // FIXME: this isn't 100% correct -- some enum arguments require printing
+ // as a string literal, while others require printing as an identifier.
+ // Tablegen currently does not distinguish between the two forms.
+ OS << " OS << \"\\\"\" << " << getAttrName() << "Attr::Convert" << type
+ << "ToStr(Val)" << "<< \"\\\"\";\n";
+ }
+
public:
VariadicEnumArgument(const Record &Arg, StringRef Attr)
: VariadicArgument(Arg, Attr, Arg.getValueAsString("Type")),
@@ -782,7 +822,20 @@ namespace {
OS << " if (R) {\n";
OS << " Out = *R;\n return true;\n }\n";
OS << " return false;\n";
- OS << " }\n";
+ OS << " }\n\n";
+
+ OS << " static const char *Convert" << type << "ToStr("
+ << type << " Val) {\n"
+ << " switch(Val) {\n";
+ std::set<std::string> Uniques;
+ for (size_t I = 0; I < enums.size(); ++I) {
+ if (Uniques.insert(enums[I]).second)
+ OS << " case " << getAttrName() << "Attr::" << enums[I]
+ << ": return \"" << values[I] << "\";\n";
+ }
+ OS << " }\n"
+ << " llvm_unreachable(\"No enumerator with that value\");\n"
+ << " }\n";
}
};
@@ -868,7 +921,6 @@ namespace {
void writeDump(raw_ostream &OS) const override {}
void writeDumpChildren(raw_ostream &OS) const override {
- OS << " lastChild();\n";
OS << " dumpStmt(SA->get" << getUpperName() << "());\n";
}
void writeHasChildren(raw_ostream &OS) const override { OS << "true"; }
@@ -923,11 +975,8 @@ namespace {
void writeDumpChildren(raw_ostream &OS) const override {
OS << " for (" << getAttrName() << "Attr::" << getLowerName()
<< "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->"
- << getLowerName() << "_end(); I != E; ++I) {\n";
- OS << " if (I + 1 == E)\n";
- OS << " lastChild();\n";
+ << getLowerName() << "_end(); I != E; ++I)\n";
OS << " dumpStmt(*I);\n";
- OS << " }\n";
}
void writeHasChildren(raw_ostream &OS) const override {
@@ -966,44 +1015,49 @@ createArgument(const Record &Arg, StringRef Attr,
if (!Search)
Search = &Arg;
- Argument *Ptr = nullptr;
+ std::unique_ptr<Argument> Ptr;
llvm::StringRef ArgName = Search->getName();
- if (ArgName == "AlignedArgument") Ptr = new AlignedArgument(Arg, Attr);
- else if (ArgName == "EnumArgument") Ptr = new EnumArgument(Arg, Attr);
- else if (ArgName == "ExprArgument") Ptr = new ExprArgument(Arg, Attr);
+ if (ArgName == "AlignedArgument")
+ Ptr = llvm::make_unique<AlignedArgument>(Arg, Attr);
+ else if (ArgName == "EnumArgument")
+ Ptr = llvm::make_unique<EnumArgument>(Arg, Attr);
+ else if (ArgName == "ExprArgument")
+ Ptr = llvm::make_unique<ExprArgument>(Arg, Attr);
else if (ArgName == "FunctionArgument")
- Ptr = new SimpleArgument(Arg, Attr, "FunctionDecl *");
+ Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "FunctionDecl *");
else if (ArgName == "IdentifierArgument")
- Ptr = new SimpleArgument(Arg, Attr, "IdentifierInfo *");
+ Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *");
else if (ArgName == "DefaultBoolArgument")
- Ptr = new DefaultSimpleArgument(Arg, Attr, "bool",
- Arg.getValueAsBit("Default"));
- else if (ArgName == "BoolArgument") Ptr = new SimpleArgument(Arg, Attr,
- "bool");
+ Ptr = llvm::make_unique<DefaultSimpleArgument>(
+ Arg, Attr, "bool", Arg.getValueAsBit("Default"));
+ else if (ArgName == "BoolArgument")
+ Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "bool");
else if (ArgName == "DefaultIntArgument")
- Ptr = new DefaultSimpleArgument(Arg, Attr, "int",
- Arg.getValueAsInt("Default"));
- else if (ArgName == "IntArgument") Ptr = new SimpleArgument(Arg, Attr, "int");
- else if (ArgName == "StringArgument") Ptr = new StringArgument(Arg, Attr);
- else if (ArgName == "TypeArgument") Ptr = new TypeArgument(Arg, Attr);
+ Ptr = llvm::make_unique<DefaultSimpleArgument>(
+ Arg, Attr, "int", Arg.getValueAsInt("Default"));
+ else if (ArgName == "IntArgument")
+ Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "int");
+ else if (ArgName == "StringArgument")
+ Ptr = llvm::make_unique<StringArgument>(Arg, Attr);
+ else if (ArgName == "TypeArgument")
+ Ptr = llvm::make_unique<TypeArgument>(Arg, Attr);
else if (ArgName == "UnsignedArgument")
- Ptr = new SimpleArgument(Arg, Attr, "unsigned");
+ Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "unsigned");
else if (ArgName == "VariadicUnsignedArgument")
- Ptr = new VariadicArgument(Arg, Attr, "unsigned");
+ Ptr = llvm::make_unique<VariadicArgument>(Arg, Attr, "unsigned");
else if (ArgName == "VariadicEnumArgument")
- Ptr = new VariadicEnumArgument(Arg, Attr);
+ Ptr = llvm::make_unique<VariadicEnumArgument>(Arg, Attr);
else if (ArgName == "VariadicExprArgument")
- Ptr = new VariadicExprArgument(Arg, Attr);
+ Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr);
else if (ArgName == "VersionArgument")
- Ptr = new VersionArgument(Arg, Attr);
+ Ptr = llvm::make_unique<VersionArgument>(Arg, Attr);
if (!Ptr) {
// Search in reverse order so that the most-derived type is handled first.
std::vector<Record*> Bases = Search->getSuperClasses();
for (const auto *Base : llvm::make_range(Bases.rbegin(), Bases.rend())) {
- Ptr = createArgument(Arg, Attr, Base).release();
- if (Ptr)
+ if ((Ptr = createArgument(Arg, Attr, Base)))
break;
}
}
@@ -1011,7 +1065,7 @@ createArgument(const Record &Arg, StringRef Attr,
if (Ptr && Arg.getValueAsBit("Optional"))
Ptr->setOptional(true);
- return std::unique_ptr<Argument>(Ptr);
+ return Ptr;
}
static void writeAvailabilityValue(raw_ostream &OS) {
@@ -1118,6 +1172,11 @@ writePrettyPrintFunction(Record &R,
continue;
}
+ // FIXME: always printing the parenthesis isn't the correct behavior for
+ // attributes which have optional arguments that were not provided. For
+ // instance: __attribute__((aligned)) will be pretty printed as
+ // __attribute__((aligned())). The logic should check whether there is only
+ // a single argument, and if it is optional, whether it has been provided.
if (!Args.empty())
OS << "(";
if (Spelling == "availability") {
@@ -1328,6 +1387,7 @@ static bool isIdentifierArgument(Record *Arg) {
llvm::StringSwitch<bool>(Arg->getSuperClasses().back()->getName())
.Case("IdentifierArgument", true)
.Case("EnumArgument", true)
+ .Case("VariadicEnumArgument", true)
.Default(false);
}
@@ -1606,8 +1666,16 @@ static void EmitAttrList(raw_ostream &OS, StringRef Class,
}
}
-namespace clang {
+// Determines if an attribute has a Pragma spelling.
+static bool AttrHasPragmaSpelling(const Record *R) {
+ std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R);
+ return std::find_if(Spellings.begin(), Spellings.end(),
+ [](const FlattenedSpelling &S) {
+ return S.variety() == "Pragma";
+ }) != Spellings.end();
+}
+namespace clang {
// Emits the enumeration list for attributes.
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
@@ -1633,14 +1701,25 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
" INHERITABLE_PARAM_ATTR(NAME)\n";
OS << "#endif\n\n";
+ OS << "#ifndef PRAGMA_SPELLING_ATTR\n";
+ OS << "#define PRAGMA_SPELLING_ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifndef LAST_PRAGMA_SPELLING_ATTR\n";
+ OS << "#define LAST_PRAGMA_SPELLING_ATTR(NAME) PRAGMA_SPELLING_ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
Record *InhClass = Records.getClass("InheritableAttr");
Record *InhParamClass = Records.getClass("InheritableParamAttr");
- std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
- NonInhAttrs, InhAttrs, InhParamAttrs;
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"),
+ NonInhAttrs, InhAttrs, InhParamAttrs, PragmaAttrs;
for (auto *Attr : Attrs) {
if (!Attr->getValueAsBit("ASTNode"))
continue;
-
+
+ if (AttrHasPragmaSpelling(Attr))
+ PragmaAttrs.push_back(Attr);
+
if (Attr->isSubClassOf(InhParamClass))
InhParamAttrs.push_back(Attr);
else if (Attr->isSubClassOf(InhClass))
@@ -1649,6 +1728,7 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
NonInhAttrs.push_back(Attr);
}
+ EmitAttrList(OS, "PRAGMA_SPELLING_ATTR", PragmaAttrs);
EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs);
EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs);
EmitAttrList(OS, "ATTR", NonInhAttrs);
@@ -1657,6 +1737,8 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
OS << "#undef INHERITABLE_ATTR\n";
OS << "#undef LAST_INHERITABLE_ATTR\n";
OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n";
+ OS << "#undef LAST_PRAGMA_ATTR\n";
+ OS << "#undef PRAGMA_SPELLING_ATTR\n";
OS << "#undef ATTR\n";
}
@@ -1740,6 +1822,27 @@ static void GenerateHasAttrSpellingStringSwitch(
const std::vector<Record *> &Attrs, raw_ostream &OS,
const std::string &Variety = "", const std::string &Scope = "") {
for (const auto *Attr : Attrs) {
+ // C++11-style attributes have specific version information associated with
+ // them. If the attribute has no scope, the version information must not
+ // have the default value (1), as that's incorrect. Instead, the unscoped
+ // attribute version information should be taken from the SD-6 standing
+ // document, which can be found at:
+ // https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
+ int Version = 1;
+
+ if (Variety == "CXX11") {
+ std::vector<Record *> Spellings = Attr->getValueAsListOfDefs("Spellings");
+ for (const auto &Spelling : Spellings) {
+ if (Spelling->getValueAsString("Variety") == "CXX11") {
+ Version = static_cast<int>(Spelling->getValueAsInt("Version"));
+ if (Scope.empty() && Version == 1)
+ PrintError(Spelling->getLoc(), "C++ standard attributes must "
+ "have valid version information.");
+ break;
+ }
+ }
+ }
+
// It is assumed that there will be an llvm::Triple object named T within
// scope that can be used to determine whether the attribute exists in
// a given target.
@@ -1778,16 +1881,16 @@ static void GenerateHasAttrSpellingStringSwitch(
// C++11 mode should be checked against LangOpts, which is presumed to be
// present in the caller.
Test = "LangOpts.CPlusPlus11";
- else
- Test = "true";
+ std::string TestStr =
+ !Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : "1";
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr);
for (const auto &S : Spellings)
if (Variety.empty() || (Variety == S.variety() &&
(Scope.empty() || Scope == S.nameSpace())))
- OS << " .Case(\"" << S.name() << "\", " << Test << ")\n";
+ OS << " .Case(\"" << S.name() << "\", " << TestStr << ")\n";
}
- OS << " .Default(false);\n";
+ OS << " .Default(0);\n";
}
// Emits the list of spellings for attributes.
@@ -1818,17 +1921,14 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
}
OS << "switch (Syntax) {\n";
- OS << "case AttrSyntax::Generic:\n";
- OS << " return llvm::StringSwitch<bool>(Name)\n";
- GenerateHasAttrSpellingStringSwitch(Attrs, OS);
OS << "case AttrSyntax::GNU:\n";
- OS << " return llvm::StringSwitch<bool>(Name)\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(GNU, OS, "GNU");
OS << "case AttrSyntax::Declspec:\n";
- OS << " return llvm::StringSwitch<bool>(Name)\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec");
OS << "case AttrSyntax::Pragma:\n";
- OS << " return llvm::StringSwitch<bool>(Name)\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
OS << "case AttrSyntax::CXX: {\n";
// C++11-style attributes are further split out based on the Scope.
@@ -1841,7 +1941,7 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << "if (!Scope || Scope->getName() == \"\") {\n";
else
OS << "if (Scope->getName() == \"" << I->first << "\") {\n";
- OS << " return llvm::StringSwitch<bool>(Name)\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(I->second, OS, "CXX11", I->first);
OS << "}";
}
@@ -2033,16 +2133,26 @@ void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
}
}
+static bool isArgVariadic(const Record &R, StringRef AttrName) {
+ return createArgument(R, AttrName)->isVariadic();
+}
+
static void emitArgInfo(const Record &R, std::stringstream &OS) {
// This function will count the number of arguments specified for the
// attribute and emit the number of required arguments followed by the
// number of optional arguments.
std::vector<Record *> Args = R.getValueAsListOfDefs("Args");
unsigned ArgCount = 0, OptCount = 0;
+ bool HasVariadic = false;
for (const auto *Arg : Args) {
Arg->getValueAsBit("Optional") ? ++OptCount : ++ArgCount;
+ if (!HasVariadic && isArgVariadic(*Arg, R.getName()))
+ HasVariadic = true;
}
- OS << ArgCount << ", " << OptCount;
+
+ // If there is a variadic argument, we will set the optional argument count
+ // to its largest value. Since it's currently a 4-bit number, we set it to 15.
+ OS << ArgCount << ", " << (HasVariadic ? 15 : OptCount);
}
static void GenerateDefaultAppertainsTo(raw_ostream &OS) {
@@ -2075,7 +2185,8 @@ static std::string CalculateDiagnostic(const Record &S) {
Namespace = 1U << 11,
Field = 1U << 12,
CXXMethod = 1U << 13,
- ObjCProtocol = 1U << 14
+ ObjCProtocol = 1U << 14,
+ Enum = 1U << 15
};
uint32_t SubMask = 0;
@@ -2109,6 +2220,7 @@ static std::string CalculateDiagnostic(const Record &S) {
.Case("Namespace", Namespace)
.Case("Field", Field)
.Case("CXXMethod", CXXMethod)
+ .Case("Enum", Enum)
.Default(0);
if (!V) {
// Something wasn't in our mapping, so be helpful and let the developer
@@ -2127,6 +2239,7 @@ static std::string CalculateDiagnostic(const Record &S) {
case Var: return "ExpectedVariable";
case Param: return "ExpectedParameter";
case Class: return "ExpectedClass";
+ case Enum: return "ExpectedEnum";
case CXXMethod:
// FIXME: Currently, this maps to ExpectedMethod based on existing code,
// but should map to something a bit more accurate at some point.
@@ -2280,6 +2393,8 @@ static std::string GenerateLangOptRequirements(const Record &R,
std::string FnName = "check", Test;
for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) {
std::string Part = (*I)->getValueAsString("Name");
+ if ((*I)->getValueAsBit("Negated"))
+ Test += "!";
Test += "S.LangOpts." + Part;
if (I + 1 != E)
Test += " || ";
@@ -2603,25 +2718,8 @@ void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS) {
for (const auto *Arg : Args)
createArgument(*Arg, R.getName())->writeDump(OS);
- // Code for detecting the last child.
- OS << " bool OldMoreChildren = hasMoreChildren();\n";
- OS << " bool MoreChildren;\n";
-
- for (auto AI = Args.begin(), AE = Args.end(); AI != AE; ++AI) {
- // More code for detecting the last child.
- OS << " MoreChildren = OldMoreChildren";
- for (auto Next = AI + 1; Next != AE; ++Next) {
- OS << " || ";
- createArgument(**Next, R.getName())->writeHasChildren(OS);
- }
- OS << ";\n";
- OS << " setMoreChildren(MoreChildren);\n";
-
+ for (auto AI = Args.begin(), AE = Args.end(); AI != AE; ++AI)
createArgument(**AI, R.getName())->writeDumpChildren(OS);
- }
-
- // Reset the last child.
- OS << " setMoreChildren(OldMoreChildren);\n";
}
OS <<
" break;\n"
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
index cd27fbcdf697..a8e8e394194e 100644
--- a/utils/TableGen/NeonEmitter.cpp
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -34,11 +34,11 @@
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/SetTheory.h"
#include "llvm/TableGen/TableGenBackend.h"
-#include <string>
+#include <algorithm>
+#include <map>
#include <sstream>
+#include <string>
#include <vector>
-#include <map>
-#include <algorithm>
using namespace llvm;
namespace {
@@ -1646,7 +1646,7 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagShuffle(DagInit *DI){
ST.addOperator("highhalf", &HH);
ST.addOperator("rev", &R);
ST.addExpander("MaskExpand", &ME);
- ST.evaluate(DI->getArg(2), Elts, ArrayRef<SMLoc>());
+ ST.evaluate(DI->getArg(2), Elts, None);
std::string S = "__builtin_shufflevector(" + Arg1.second + ", " + Arg2.second;
for (auto &E : Elts) {
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 78745f1aac60..4adf368cbd56 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -13,6 +13,9 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_UTILS_TABLEGEN_TABLEGENBACKENDS_H
+#define LLVM_CLANG_UTILS_TABLEGEN_TABLEGENBACKENDS_H
+
#include <string>
namespace llvm {
@@ -68,3 +71,5 @@ void EmitNeonTest2(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS);
} // end namespace clang
+
+#endif
diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index 441032eb7c05..0a2c836b26f0 100644
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -170,7 +170,7 @@ SBOutputDirReferencePrefix = "Ref"
# The list of checkers used during analyzes.
# Currently, consists of all the non-experimental checkers, plus a few alpha
# checkers we don't want to regress on.
-Checkers="alpha.unix.SimpleStream,alpha.security.taint,alpha.cplusplus.NewDeleteLeaks,core,cplusplus,deadcode,security,unix,osx"
+Checkers="alpha.unix.SimpleStream,alpha.security.taint,cplusplus.NewDeleteLeaks,core,cplusplus,deadcode,security,unix,osx"
Verbose = 1
diff --git a/www/analyzer/open_projects.html b/www/analyzer/open_projects.html
index 75c069260c7c..4c3429da1f96 100644
--- a/www/analyzer/open_projects.html
+++ b/www/analyzer/open_projects.html
@@ -181,7 +181,7 @@ mailing list</a> to notify other members of the community.</p>
<p>Take a look at the
<a href="http://pages.cs.wisc.edu/~shanlu/paper/TSE-CPMiner.pdf">CP-Miner</a>
paper for inspiration.
- <i>(Difficulty: Medium-Hard; current contacts: Per Viberg and Daniel Fahlgren)</i></p>
+ <i>(Difficulty: Medium-Hard; current contacts: Daniel Marjam&auml;ki and Daniel Fahlgren)</i></p>
</li>
</ul>
</li>
diff --git a/www/analyzer/potential_checkers.html b/www/analyzer/potential_checkers.html
index a06e9426fb5f..101e3c6fc402 100644
--- a/www/analyzer/potential_checkers.html
+++ b/www/analyzer/potential_checkers.html
@@ -104,6 +104,32 @@ void test() {
</pre></div></div></td>
<td class="aligned"></td></tr>
+<tr><td><div class="namedescr expandable"><span class="name">
+memory.ZeroAlloc</span><span class="lang">
+(C, C++)</span><div class="descr">
+Allocation of zero bytes.
+<br>Note: an enhancement to <span class="name">unix.Malloc</span>.
+<br>Note: <span class="name">unix.API</span> perform C-checks for zero
+allocation. This should be moved to <span class="name">unix.Malloc</span>.
+<p>Source: C++03 3.7.3.1p2; C++11 3.7.4.1p2.</p></div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+#include &lt;stdlib.h&gt;
+
+void test() {
+ int *p = malloc(0); // warn
+ free(p);
+}
+</pre></div>
+<div class="example"><pre>
+void test() {
+ int *p = new int[0]; // warn
+ delete[] p;
+}
+</pre></div></div></td>
+<td class="aligned"><a href="http://reviews.llvm.org/D6178">
+D6178</a></td></tr>
+
</table>
<!-- ======================= constructors/destructors ====================== -->
@@ -461,12 +487,22 @@ unix.Malloc</span>.
<p>Source: C++03 3.7.3.1p2; C++11 3.7.4.1p2.</p></div></div></td>
<td><div class="exampleContainer expandable">
<div class="example"><pre>
-int *p = malloc(0);
-*p = 1; // warn
+#include &lt;stdlib.h&gt;
+
+void test() {
+ int *p = (int *)malloc(0);
+ *p = 1; // warn
+ free(p);
+}
</pre></div>
<div class="example"><pre>
-int *p = new int{};
-int i = *p; // warn
+void f(int);
+
+void test() {
+ int *p = new int[0];
+ f(*p); // warn
+ delete[] p;
+}
</pre></div></div></td>
<td class="aligned"></td></tr>
diff --git a/www/analyzer/scan-build.html b/www/analyzer/scan-build.html
index abd2bc0dda89..1a06f00913dd 100644
--- a/www/analyzer/scan-build.html
+++ b/www/analyzer/scan-build.html
@@ -124,11 +124,34 @@ files:</p>
<h3 id="scanbuild_forwindowsusers">For Windows Users</h3>
-<p>Windows users must have Perl installed to use scan-build. Currently scan-build
-is known to work with the msys perl port.</p>
+<p>Windows users must have Perl installed to use scan-build.</p>
-<p>scan-build.bat script allows you to launch scan-build in the same way as it described in the Basic Usage section above.
-All you need to be able to invoke scan-build from an arbitrary location is to add the path to scan-build to your PATH environment variable.</p>
+<p><tt>scan-build.bat</tt> script allows you to launch scan-build in the same
+way as it described in the Basic Usage section above. To invoke scan-build from
+an arbitrary location, add the path to the folder containing scan-build.bat to
+your PATH environment variable.</p>
+
+<p>If you have unexpected compilation/make problems when running scan-build
+with MinGW/MSYS the following information may be helpful:</p>
+
+<ul>
+ <li> If getting unexpected <tt>"fatal error: no input files"</tt> while
+building with MSYS make from the Windows cmd, try one of the these
+solutions:</li>
+ <ul>
+ <li> Use MinGW <tt>mingw32-make</tt> instead of MSYS <tt>make</tt> and
+exclude the path to MSYS from PATH to prevent <tt>mingw32-make</tt> from using
+MSYS utils. MSYS utils are dependent on the MSYS runtime and they are not
+intended for being run from the Windows cmd. Specifically, makefile commands
+with backslashed quotes may be heavily corrupted when passed for execution.</li>
+ <li> Run <tt>make</tt> from the sh shell:
+<pre class="code_example">
+$ <span class="code_highlight">scan-build</span> <i>[scan-build options]</i> sh -c "make <i>[make options]</i>"
+</pre></li>
+ </ul>
+ <li> If getting <tt>"Error : *** target pattern contains no `%'"</tt> while
+using GNU Make 3.81, try to use another version of make.</li>
+</ul>
<h3 id="scanbuild_otheroptions">Other Options</h3>
diff --git a/www/compatibility.html b/www/compatibility.html
index 8bfaff191cb5..293be6f22032 100644
--- a/www/compatibility.html
+++ b/www/compatibility.html
@@ -83,10 +83,10 @@
<!-- ======================================================================= -->
<h3 id="inline">C99 inline functions</h3>
<!-- ======================================================================= -->
-<p>By default, Clang builds C code according to the C99 standard,
-which provides different semantics for the <code>inline</code> keyword
-than GCC's default behavior. For example, consider the following
-code:</p>
+<p>By default, Clang builds C code in GNU C11 mode, so it uses standard C99
+semantics for the <code>inline</code> keyword. These semantics are different
+from those in GNU C89 mode, which is the default mode in versions of GCC
+prior to 5.0. For example, consider the following code:</p>
<pre>
inline int add(int i, int j) { return i + j; }
@@ -110,10 +110,10 @@ Undefined symbols:
_main in cc-y1jXIr.o
</pre>
-<p>By contrast, GCC's default behavior follows the GNU89 dialect,
-which is the C89 standard plus a lot of extensions. C89 doesn't have
-an <code>inline</code> keyword, but GCC recognizes it as an extension
-and just treats it as a hint to the optimizer.</p>
+<p>By contrast, GNU C89 mode (used by default in older versions of GCC) is the
+C89 standard plus a lot of extensions. C89 doesn't have an <code>inline</code>
+keyword, but GCC recognizes it as an extension and just treats it as a hint to
+the optimizer.</p>
<p>There are several ways to fix this problem:</p>
@@ -130,12 +130,12 @@ and just treats it as a hint to the optimizer.</p>
for a function to be inlined, nor does it guarantee that it will be.
Some compilers ignore it completely. Clang treats it as a mild
suggestion from the programmer.</li>
-
+
<li>Provide an external (non-<code>inline</code>) definition
of <code>add</code> somewhere else in your program. The two
definitions must be equivalent!</li>
- <li>Compile with the GNU89 dialect by adding
+ <li>Compile in the GNU C89 dialect by adding
<code>-std=gnu89</code> to the set of Clang options. This option is
only recommended if the program source cannot be changed or if the
program also relies on additional C89-specific behavior that cannot
diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html
index 2d58415a111e..ce90ca7aa688 100644
--- a/www/cxx_dr_status.html
+++ b/www/cxx_dr_status.html
@@ -28,7 +28,7 @@
<!--*************************************************************************-->
<h1>C++ Defect Report Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2014-06-03 23:58:55 +0200 (Tue, 03 Jun 2014) $</p>
+<p>Last updated: $Date: 2015-01-14 23:31:21 +0100 (Wed, 14 Jan 2015) $</p>
<h2 id="cxxdr">C++ defect report implementation status</h2>
@@ -147,7 +147,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#18">18</a></td>
<td>NAD</td>
<td>f(TYPE) where TYPE is void should be allowed</td>
- <td class="none" align="center">Superseded by <a href="#577">577</a></td>
+ <td class="full" align="center">Superseded by <a href="#577">577</a></td>
</tr>
<tr id="19">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#19">19</a></td>
@@ -321,7 +321,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#47">47</a></td>
<td>NAD</td>
<td>Template friend issues</td>
- <td class="svn" align="center">Superseded by <a href="#329">329</a></td>
+ <td class="full" align="center">Superseded by <a href="#329">329</a></td>
</tr>
<tr id="48">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48">48</a></td>
@@ -645,7 +645,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#101">101</a></td>
<td>TC1</td>
<td>Redeclaration of extern "C" names via using-declarations</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="102">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#102">102</a></td>
@@ -675,7 +675,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#106">106</a></td>
<td>CD1</td>
<td>Creating references to references during template deduction/instantiation</td>
- <td class="none" align="center">Superseded by <a href="#540">540</a></td>
+ <td class="full" align="center">Superseded by <a href="#540">540</a></td>
</tr>
<tr id="107">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#107">107</a></td>
@@ -705,7 +705,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#111">111</a></td>
<td>NAD</td>
<td>Copy constructors and cv-qualifiers</td>
- <td class="none" align="center">Duplicate of <a href="#535">535</a></td>
+ <td class="full" align="center">Duplicate of <a href="#535">535</a></td>
</tr>
<tr id="112">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#112">112</a></td>
@@ -969,7 +969,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#155">155</a></td>
<td>dup</td>
<td>Brace initializer for scalar</td>
- <td class="none" align="center">Duplicate of <a href="#632">632</a></td>
+ <td class="full" align="center">Duplicate of <a href="#632">632</a></td>
</tr>
<tr class="open" id="156">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#156">156</a></td>
@@ -993,7 +993,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#159">159</a></td>
<td>TC1</td>
<td>Namespace qualification in declarators</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="160">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#160">160</a></td>
@@ -1372,7 +1372,7 @@ accessible?</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#222">222</a></td>
<td>CD1</td>
<td>Sequence points and lvalue-returning operators</td>
- <td class="none" align="center">Duplicate of <a href="#637">637</a></td>
+ <td class="full" align="center">Duplicate of <a href="#637">637</a></td>
</tr>
<tr id="223">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#223">223</a></td>
@@ -1490,7 +1490,7 @@ accessible?</td>
</tr>
<tr class="open" id="242">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#242">242</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Interpretation of old-style casts</td>
<td align="center">Not resolved</td>
</tr>
@@ -1504,7 +1504,7 @@ accessible?</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#244">244</a></td>
<td>CD1</td>
<td>Destructor lookup</td>
- <td class="svn" align="center">SVN</td>
+ <td class="partial" align="center">Partial</td>
</tr>
<tr id="245">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#245">245</a></td>
@@ -1921,11 +1921,11 @@ of class templates</td>
<td>Class with single conversion function to integral as array size in <TT>new</TT></td>
<td class="full" align="center">Duplicate of <a href="#299">299</a> (C++11 onwards)</td>
</tr>
- <tr id="314">
+ <tr class="open" id="314">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#314">314</a></td>
- <td>ready</td>
+ <td>review</td>
<td><TT>template</TT> in base class specifier</td>
- <td class="none" align="center">Duplicate of <a href="#1710">1710</a></td>
+ <td align="center">Not resolved</td>
</tr>
<tr id="315">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#315">315</a></td>
@@ -1943,7 +1943,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#317">317</a></td>
<td>CD1</td>
<td>Can a function be declared inline after it has been called?</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="318">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#318">318</a></td>
@@ -1967,7 +1967,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#321">321</a></td>
<td>dup</td>
<td>Associated classes and namespaces for argument-dependent lookup</td>
- <td class="none" align="center">Duplicate of <a href="#557">557</a></td>
+ <td class="full" align="center">Duplicate of <a href="#557">557</a></td>
</tr>
<tr id="322">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#322">322</a></td>
@@ -2003,7 +2003,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#327">327</a></td>
<td>CD1</td>
<td>Use of "structure" without definition</td>
- <td class="none" align="center">Duplicate of <a href="#538">538</a></td>
+ <td class="na" align="center">Duplicate of <a href="#538">538</a></td>
</tr>
<tr id="328">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#328">328</a></td>
@@ -2015,13 +2015,13 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#329">329</a></td>
<td>CD1</td>
<td>Evaluation of friends of templates</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
- <tr class="open" id="330">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#330">330</a></td>
- <td>open</td>
+ <tr id="330">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#330">330</a></td>
+ <td>DR</td>
<td>Qualification conversions and pointers to arrays of pointers</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="331">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#331">331</a></td>
@@ -2033,7 +2033,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#332">332</a></td>
<td>CD3</td>
<td>cv-qualified <TT>void</TT> parameter types</td>
- <td class="none" align="center">Duplicate of <a href="#557">557</a></td>
+ <td class="full" align="center">Duplicate of <a href="#577">577</a></td>
</tr>
<tr id="333">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#333">333</a></td>
@@ -2095,11 +2095,11 @@ of class templates</td>
<td>Terminology: "indirection" versus "dereference"</td>
<td class="na" align="center">N/A</td>
</tr>
- <tr id="343">
+ <tr class="open" id="343">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#343">343</a></td>
- <td>ready</td>
+ <td>review</td>
<td>Make <TT>template</TT> optional in contexts that require a type</td>
- <td class="none" align="center">No</td>
+ <td align="center">Not resolved</td>
</tr>
<tr id="344">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#344">344</a></td>
@@ -2396,8 +2396,8 @@ of class templates</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="393">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#393">393</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#393">393</a></td>
+ <td>DR</td>
<td>Pointer to array of unknown bound in template argument list in parameter</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -2663,7 +2663,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#437">437</a></td>
<td>CD1</td>
<td>Is type of class allowed in member function exception specification?</td>
- <td class="none" align="center">No</td>
+ <td class="none" align="center">Superseded by <a href="#1308">1308</a></td>
</tr>
<tr id="438">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#438">438</a></td>
@@ -2903,7 +2903,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#477">477</a></td>
<td>CD1</td>
<td>Can <TT>virtual</TT> appear in a <TT>friend</TT> declaration?</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="478">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#478">478</a></td>
@@ -2933,7 +2933,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#482">482</a></td>
<td>CD3</td>
<td>Qualified declarators in redeclarations</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="483">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#483">483</a></td>
@@ -3011,7 +3011,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#495">495</a></td>
<td>CD2</td>
<td>Overload resolution with template and non-template conversion functions</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="496">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#496">496</a></td>
@@ -3197,13 +3197,13 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#526">526</a></td>
<td>CD1</td>
<td>Confusing aspects in the specification of non-deduced contexts</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="527">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#527">527</a></td>
<td>CD2</td>
<td>Problems with linkage of types</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr class="open" id="528">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#528">528</a></td>
@@ -3221,37 +3221,37 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#530">530</a></td>
<td>CD1</td>
<td>Nontype template arguments in constant expressions</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="531">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#531">531</a></td>
<td>C++11</td>
<td>Defining members of explicit specializations</td>
- <td class="none" align="center">Unknown</td>
+ <td class="partial" align="center">Partial</td>
</tr>
<tr id="532">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#532">532</a></td>
<td>C++11</td>
<td>Member/nonmember operator template partial ordering</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="533">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#533">533</a></td>
<td>NAD</td>
<td>Special treatment for C-style header names</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="534">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#534">534</a></td>
<td>CD1</td>
<td><I>template-name</I>s and <I>operator-function-id</I>s</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="535">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#535">535</a></td>
<td>CD3</td>
<td>Copy construction without a copy constructor</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="536">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#536">536</a></td>
@@ -3263,7 +3263,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#537">537</a></td>
<td>CD1</td>
<td>Definition of &#8220;signature&#8221;</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="538">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#538">538</a></td>
@@ -3271,43 +3271,43 @@ of class templates</td>
<td>Definition and usage
of <I>structure</I>, <I>POD-struct</I>, <I>POD-union</I>,
and <I>POD class</I></td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="539">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#539">539</a></td>
<td>CD3</td>
<td>Constraints on <I>type-specifier-seq</I></td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="540">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#540">540</a></td>
<td>CD1</td>
<td>Propagation of cv-qualifiers in reference-to-reference collapse</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="541">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#541">541</a></td>
<td>CD2</td>
<td>Dependent function types</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="542">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#542">542</a></td>
<td>CD2</td>
<td>Value initialization of arrays of POD-structs</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="543">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#543">543</a></td>
<td>CD1</td>
<td>Value initialization and default constructors</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="544">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#544">544</a></td>
<td>NAD</td>
<td>Base class lookup in explicit specialization</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="545">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#545">545</a></td>
@@ -3319,19 +3319,19 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#546">546</a></td>
<td>C++11</td>
<td>Explicit instantiation of class template members</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="547">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#547">547</a></td>
<td>C++11</td>
<td>Partial specialization on member function types</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="548">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#548">548</a></td>
<td>dup</td>
<td><I>qualified-id</I>s in declarations</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Duplicate of <a href="#482">482</a></td>
</tr>
<tr class="open" id="549">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#549">549</a></td>
@@ -3339,23 +3339,23 @@ and <I>POD class</I></td>
<td>Non-deducible parameters in partial specializations</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="550">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#550">550</a></td>
- <td>open</td>
+ <tr id="550">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#550">550</a></td>
+ <td>dup</td>
<td>Pointer to array of unknown bound in parameter declarations</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="551">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#551">551</a></td>
<td>CD1</td>
<td>When is <TT>inline</TT> permitted in an explicit instantiation?</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes (C++11 onwards)</td>
</tr>
<tr id="552">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#552">552</a></td>
<td>NAD</td>
<td>Use of <TT>typename</TT> in the type in a non-type <I>parameter-declaration</I></td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="553">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#553">553</a></td>
@@ -3365,7 +3365,7 @@ and <I>POD class</I></td>
</tr>
<tr class="open" id="554">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#554">554</a></td>
- <td>drafting</td>
+ <td>open</td>
<td>Definition of &#8220;declarative region&#8221; and &#8220;scope&#8221;</td>
<td align="center">Not resolved</td>
</tr>
@@ -3379,25 +3379,25 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#556">556</a></td>
<td>CD2</td>
<td>Conflicting requirements for acceptable aliasing</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="557">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#557">557</a></td>
<td>CD1</td>
<td>Does argument-dependent lookup cause template instantiation?</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="558">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#558">558</a></td>
<td>CD1</td>
<td>Excluded characters in universal character names</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="559">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#559">559</a></td>
<td>CD1</td>
<td>Editing error in issue 382 resolution</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="560">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#560">560</a></td>
@@ -3409,7 +3409,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561">561</a></td>
<td>CD2</td>
<td>Internal linkage functions in dependent name lookup</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="562">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#562">562</a></td>
@@ -3427,43 +3427,43 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#564">564</a></td>
<td>CD2</td>
<td>Agreement of language linkage or <I>linkage-specification</I>s?</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="565">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#565">565</a></td>
<td>CD3</td>
<td>Conflict rules for <I>using-declaration</I>s naming function templates</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="566">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#566">566</a></td>
<td>NAD</td>
<td>Conversion of negative floating point values to integer type</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="567">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#567">567</a></td>
<td>NAD</td>
<td>Can <TT>size_t</TT> and <TT>ptrdiff_t</TT> be larger than <TT>long</TT>?</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="568">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#568">568</a></td>
<td>CD1</td>
<td>Definition of POD is too strict</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes (C++11 onwards)</td>
</tr>
<tr id="569">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#569">569</a></td>
<td>CD2</td>
<td>Spurious semicolons at namespace scope should be allowed</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes (C++11 onwards)</td>
</tr>
<tr id="570">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#570">570</a></td>
<td>CD2</td>
<td>Are references subject to the ODR?</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">Duplicate of <a href="#633">633</a></td>
</tr>
<tr id="571">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#571">571</a></td>
@@ -3475,37 +3475,37 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#572">572</a></td>
<td>C++11</td>
<td>Standard conversions for non-built-in types</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="573">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#573">573</a></td>
<td>C++11</td>
<td>Conversions between function pointers and <TT>void*</TT></td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">No</td>
</tr>
<tr id="574">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#574">574</a></td>
<td>NAD</td>
<td>Definition of &#8220;copy assignment operator&#8221;</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="575">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#575">575</a></td>
<td>C++11</td>
<td>Criteria for deduction failure</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="576">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#576">576</a></td>
<td>CD2</td>
<td>Typedefs in function definitions</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="577">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#577">577</a></td>
<td>CD3</td>
<td><TT>void</TT> in an empty parameter list</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="578">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#578">578</a></td>
@@ -3523,7 +3523,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#580">580</a></td>
<td>C++11</td>
<td>Access in <I>template-parameter</I>s of member and friend definitions</td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">No</td>
</tr>
<tr class="open" id="581">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#581">581</a></td>
@@ -3535,67 +3535,67 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#582">582</a></td>
<td>CD1</td>
<td>Template conversion functions</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="583">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#583">583</a></td>
<td>CD3</td>
<td>Relational pointer comparisons against the null pointer constant</td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">No</td>
</tr>
<tr id="584">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#584">584</a></td>
<td>NAD</td>
<td>Unions and aliasing</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="585">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#585">585</a></td>
<td>NAD</td>
<td>Friend template template parameters</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="586">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#586">586</a></td>
<td>NAD</td>
<td>Default <I>template-argument</I>s and template argument deduction</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="587">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#587">587</a></td>
<td>CD2</td>
<td>Lvalue operands of a conditional expression differing only in cv-qualification</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="588">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#588">588</a></td>
<td>CD2</td>
<td>Searching dependent bases of classes local to function templates</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="589">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#589">589</a></td>
<td>CD2</td>
<td>Direct binding of class and array rvalues in reference initialization</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="590">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#590">590</a></td>
<td>C++11</td>
<td>Nested classes and the &#8220;current instantiation&#8221;</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="591">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#591">591</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#591">591</a></td>
+ <td>DR</td>
<td>When a dependent base class is the current instantiation</td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">No</td>
</tr>
<tr id="592">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#592">592</a></td>
<td>CD1</td>
<td>Exceptions during construction of local static objects</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="593">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#593">593</a></td>
@@ -3607,13 +3607,13 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#594">594</a></td>
<td>CD1</td>
<td>Coordinating issues 119 and 404 with delegating constructors</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="595">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#595">595</a></td>
<td>dup</td>
<td>Exception specifications in templates instantiated from class bodies</td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">Duplicate of <a href="#1330">1330</a></td>
</tr>
<tr class="open" id="596">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#596">596</a></td>
@@ -3625,19 +3625,19 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#597">597</a></td>
<td>CD3</td>
<td>Conversions applied to out-of-lifetime non-POD lvalues</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="598">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#598">598</a></td>
<td>CD2</td>
<td>Associated namespaces of overloaded functions and function templates</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="599">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#599">599</a></td>
<td>CD2</td>
<td>Deleting a null function pointer</td>
- <td class="none" align="center">Unknown</td>
+ <td class="partial" align="center">Partial</td>
</tr>
<tr class="open" id="600">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#600">600</a></td>
@@ -3649,25 +3649,25 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#601">601</a></td>
<td>CD2</td>
<td>Type of literals in preprocessing expressions</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="602">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#602">602</a></td>
<td>C++11</td>
<td>When is the injected-class-name of a class template a template?</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="603">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#603">603</a></td>
<td>CD1</td>
<td>Type equivalence and unsigned overflow</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="604">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#604">604</a></td>
<td>CD2</td>
<td>Argument list for overload resolution in copy-initialization</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="605">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#605">605</a></td>
@@ -3679,7 +3679,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#606">606</a></td>
<td>CD1</td>
<td>Template argument deduction for rvalue references</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="607">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#607">607</a></td>
@@ -3691,11 +3691,11 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#608">608</a></td>
<td>CD2</td>
<td>Determining the final overrider of a virtual function</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="609">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#609">609</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#609">609</a></td>
+ <td>DR</td>
<td>What is a &#8220;top-level&#8221; cv-qualifier?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -3703,43 +3703,43 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#610">610</a></td>
<td>NAD</td>
<td>Computing the negative of <TT>0U</TT></td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="611">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#611">611</a></td>
<td>CD2</td>
<td>Zero-initializing references</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="612">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#612">612</a></td>
<td>CD2</td>
<td>Requirements on a conforming implementation</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="613">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#613">613</a></td>
<td>CD1</td>
<td>Unevaluated uses of non-static class members</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes (C++11 onwards)</td>
</tr>
<tr id="614">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#614">614</a></td>
<td>CD1</td>
<td>Results of integer <TT>/</TT> and <TT>%</TT></td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="615">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#615">615</a></td>
<td>C++11</td>
<td>Incorrect description of variables that can be initialized</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="616">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#616">616</a></td>
<td>CD3</td>
<td>Definition of &#8220;indeterminate value&#8221;</td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">No</td>
</tr>
<tr class="open" id="617">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#617">617</a></td>
@@ -3751,19 +3751,19 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#618">618</a></td>
<td>CD2</td>
<td>Casts in preprocessor conditional expressions</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="619">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#619">619</a></td>
<td>C++11</td>
<td>Completeness of array types</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="620">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#620">620</a></td>
<td>CD1</td>
<td>Declaration order in layout-compatible POD structs</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Duplicate of <a href="#568">568</a></td>
</tr>
<tr id="621">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#621">621</a></td>
@@ -3781,7 +3781,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#623">623</a></td>
<td>CD3</td>
<td>Use of pointers to deallocated storage</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="624">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#624">624</a></td>
@@ -3793,67 +3793,67 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#625">625</a></td>
<td>CD2</td>
<td>Use of <TT>auto</TT> as a <I>template-argument</I></td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="626">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#626">626</a></td>
<td>CD2</td>
<td>Preprocessor string literals</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="627">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#627">627</a></td>
<td>NAD</td>
<td>Values behaving as types</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="628">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#628">628</a></td>
<td>CD2</td>
<td>The values of an enumeration with no enumerator</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="629">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#629">629</a></td>
<td>CD1</td>
<td><TT>auto</TT> parsing ambiguity</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="630">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#630">630</a></td>
<td>CD2</td>
<td>Equality of narrow and wide character values in the basic character set</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="631">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#631">631</a></td>
<td>CD3</td>
<td>Jumping into a &#8220;then&#8221; clause</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="632">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#632">632</a></td>
<td>CD1</td>
<td>Brace-enclosed initializer for scalar member of aggregate</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="633">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#633">633</a></td>
<td>CD2</td>
<td>Specifications for variables that should also apply to references</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="634">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#634">634</a></td>
<td>CD1</td>
<td>Conditionally-supported behavior for non-POD objects passed to ellipsis redux</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="635">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#635">635</a></td>
<td>NAD</td>
<td>Names of constructors and destructors of templates</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="636">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#636">636</a></td>
@@ -3865,19 +3865,19 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#637">637</a></td>
<td>CD1</td>
<td>Sequencing rules and example disagree</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="638">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#638">638</a></td>
<td>CD2</td>
<td>Explicit specialization and friendship</td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">No</td>
</tr>
<tr id="639">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#639">639</a></td>
<td>CD1</td>
<td>What makes side effects &#8220;different&#8221; from one another?</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="640">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#640">640</a></td>
@@ -5613,11 +5613,11 @@ and <I>POD class</I></td>
<td>Nested types without linkage</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="967">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#967">967</a></td>
- <td>open</td>
+ <tr id="967">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#967">967</a></td>
+ <td>NAD</td>
<td>Exception specification of replacement allocation function</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="968">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#968">968</a></td>
@@ -5733,11 +5733,11 @@ and <I>POD class</I></td>
<td>Transitivity of <I>using-directive</I>s versus qualified lookup</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="987">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#987">987</a></td>
- <td>open</td>
+ <tr id="987">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#987">987</a></td>
+ <td>DR</td>
<td>Which declarations introduce namespace members?</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="988">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#988">988</a></td>
@@ -5755,7 +5755,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#990">990</a></td>
<td>CD2</td>
<td>Value initialization with multiple initializer-list constructors</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="991">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#991">991</a></td>
@@ -5937,11 +5937,11 @@ and <I>POD class</I></td>
<td>Implicitly-defined copy constructors and explicit base class constructors</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1021">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1021">1021</a></td>
- <td>drafting</td>
+ <tr id="1021">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1021">1021</a></td>
+ <td>DR</td>
<td>Definitions of namespace members</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1022">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1022">1022</a></td>
@@ -6099,11 +6099,11 @@ and <I>POD class</I></td>
<td>When is <TT>typeid</TT> value-dependent?</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1048">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1048">1048</a></td>
- <td>open</td>
+ <tr id="1048">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1048">1048</a></td>
+ <td>CD3</td>
<td><TT>auto</TT> deduction and lambda return type deduction.</td>
- <td align="center">Not resolved</td>
+ <td class="full" align="center">Clang 3.6</td>
</tr>
<tr class="open" id="1049">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1049">1049</a></td>
@@ -6235,7 +6235,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1070">1070</a></td>
<td>C++11</td>
<td>Missing initializer clauses in aggregate initialization</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="1071">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1071">1071</a></td>
@@ -7535,7 +7535,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1287">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1287">1287</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Direct initialization vs &#8220;implicit&#8221; conversion in reference binding</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7564,8 +7564,8 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1292">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1292">1292</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1292">1292</a></td>
+ <td>DR</td>
<td>Dependent calls with <I>braced-init-list</I>s containing a pack expansion</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7605,11 +7605,11 @@ and <I>POD class</I></td>
<td>Incorrect example in overload resolution</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr id="1299">
+ <tr class="open" id="1299">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1299">1299</a></td>
- <td>ready</td>
+ <td>drafting</td>
<td>&#8220;Temporary objects&#8221; vs &#8220;temporary expressions&#8221;</td>
- <td class="none" align="center">Unknown</td>
+ <td align="center">Not resolved</td>
</tr>
<tr id="1300">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1300">1300</a></td>
@@ -7655,7 +7655,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1307">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1307">1307</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Overload resolution based on size of array <I>initializer-list</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7665,11 +7665,11 @@ and <I>POD class</I></td>
<td>Completeness of class type within an <I>exception-specification</I></td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1309">
+ <tr id="1309">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1309">1309</a></td>
- <td>drafting</td>
+ <td>ready</td>
<td>Incorrect note regarding lookup of a member of the current instantiation</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1310">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1310">1310</a></td>
@@ -7840,8 +7840,8 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1338">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1338">1338</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1338">1338</a></td>
+ <td>DR</td>
<td>Aliasing and allocation functions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7877,7 +7877,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1344">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1344">1344</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Adding new special member functions to a class via default arguments</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7891,7 +7891,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1346">1346</a></td>
<td>CD3</td>
<td><I>expression-list</I> initializers and the <TT>auto</TT> specifier</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="1347">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1347">1347</a></td>
@@ -7905,11 +7905,11 @@ and <I>POD class</I></td>
<td>Use of <TT>auto</TT> in a <I>trailing-return-type</I></td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1349">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1349">1349</a></td>
- <td>drafting</td>
+ <tr id="1349">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1349">1349</a></td>
+ <td>dup</td>
<td>Consistency of alias template redeclarations</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1350">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1350">1350</a></td>
@@ -7917,11 +7917,11 @@ and <I>POD class</I></td>
<td>Incorrect exception specification for inherited constructors</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1351">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1351">1351</a></td>
- <td>review</td>
+ <tr id="1351">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1351">1351</a></td>
+ <td>DR</td>
<td>Problems with implicitly-declared <I>exception-specification</I>s</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1352">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1352">1352</a></td>
@@ -7947,11 +7947,11 @@ and <I>POD class</I></td>
<td>Aggregates and &#8220;user-provided&#8221; constructors</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1356">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1356">1356</a></td>
- <td>review</td>
+ <tr id="1356">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1356">1356</a></td>
+ <td>DR</td>
<td>Exception specifications of copy assignment operators with virtual bases</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1357">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1357">1357</a></td>
@@ -8069,7 +8069,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1376">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1376">1376</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td><TT>static_cast</TT> of temporary to rvalue reference</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8194,8 +8194,8 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1397">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1397">1397</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1397">1397</a></td>
+ <td>DR</td>
<td>Class completeness in non-static data member initializers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8315,7 +8315,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1417">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1417">1417</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Pointers/references to functions with cv-qualifiers or <I>ref-qualifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8357,7 +8357,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1424">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1424">1424</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>When must sub-object destructors be accessible?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8459,7 +8459,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1441">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1441">1441</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Unclear wording for signal handler restrictions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8488,8 +8488,8 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1446">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1446">1446</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1446">1446</a></td>
+ <td>DR</td>
<td>Member function with no <I>ref-qualifier</I> and non-member function with rvalue reference</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8573,9 +8573,9 @@ and <I>POD class</I></td>
</tr>
<tr id="1460">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1460">1460</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>What is an empty union?</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr id="1461">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1461">1461</a></td>
@@ -8601,23 +8601,23 @@ and <I>POD class</I></td>
<td>Negative array bound in a <I>new-expression</I></td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1465">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1465">1465</a></td>
- <td>review</td>
+ <tr id="1465">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1465">1465</a></td>
+ <td>DR</td>
<td><TT>noexcept</TT> and <TT>std::bad_array_new_length</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1466">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1466">1466</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Visible sequences of side effects are redundant</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1467">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1467">1467</a></td>
- <td>drafting</td>
+ <tr id="1467">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467">1467</a></td>
+ <td>DR</td>
<td>List-initialization of aggregate from same-type object</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1468">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1468">1468</a></td>
@@ -8716,8 +8716,8 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1484">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1484">1484</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1484">1484</a></td>
+ <td>DR</td>
<td>Unused local classes of function templates</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8751,11 +8751,11 @@ and <I>POD class</I></td>
<td>Is value-initialization of an array constant initialization?</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1490">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1490">1490</a></td>
- <td>drafting</td>
+ <tr id="1490">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1490">1490</a></td>
+ <td>DR</td>
<td>List-initialization from a string literal</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1491">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1491">1491</a></td>
@@ -8764,14 +8764,14 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1492">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1492">1492</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1492">1492</a></td>
+ <td>DR</td>
<td>Exception specifications on template destructors</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1493">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1493">1493</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Criteria for move-construction</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8861,13 +8861,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1508">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1508">1508</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Template initializer-list constructors</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1509">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1509">1509</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Definition of &#8220;non-template function&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8897,7 +8897,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1514">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1514">1514</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Ambiguity between enumeration definition and zero-length bit-field</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9119,13 +9119,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1551">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1551">1551</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Wording problems in <I>using-declaration</I> specification</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1552">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1552">1552</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1552">1552</a></td>
+ <td>DR</td>
<td><I>exception-specification</I>s and defaulted special member functions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9160,8 +9160,8 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1558">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1558">1558</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1558">1558</a></td>
+ <td>DR</td>
<td>Unused arguments in alias template specializations</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9175,7 +9175,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1560">1560</a></td>
<td>CD3</td>
<td>Gratuitous lvalue-to-rvalue conversion in <I>conditional-expression</I> with <I>throw-expression</I> operand</td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
<tr class="open" id="1561">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1561">1561</a></td>
@@ -9185,7 +9185,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1562">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1562">1562</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Non-static data member initializers and union <I>ctor-initializer</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9215,7 +9215,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1567">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1567">1567</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Inheriting constructors and copy/move constructors</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9227,31 +9227,31 @@ and <I>POD class</I></td>
</tr>
<tr id="1569">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1569">1569</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Deducing a function parameter pack before ellipsis</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1570">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1570">1570</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Address of subobject as non-type template argument</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1571">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1571">1571</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1571">1571</a></td>
+ <td>DR</td>
<td>cv-qualification for indirect reference binding via conversion function</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1572">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1572">1572</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1572">1572</a></td>
+ <td>DR</td>
<td>Incorrect example for rvalue reference binding via conversion function</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1573">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1573">1573</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1573">1573</a></td>
+ <td>DR</td>
<td>Inherited constructor characteristics</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9263,13 +9263,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1575">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1575">1575</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Incorrect definition of &#8220;strict pointer safety&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1576">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1576">1576</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Discarded-value volatile xvalues</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9287,7 +9287,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1579">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1579">1579</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Return by converting move constructor</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9311,15 +9311,15 @@ and <I>POD class</I></td>
</tr>
<tr id="1583">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1583">1583</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Incorrect example of unspecified behavior</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr id="1584">
+ <tr class="open" id="1584">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1584">1584</a></td>
- <td>ready</td>
+ <td>open</td>
<td>Deducing function types from cv-qualified types</td>
- <td class="none" align="center">Unknown</td>
+ <td align="center">Not resolved</td>
</tr>
<tr id="1585">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1585">1585</a></td>
@@ -9335,7 +9335,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1587">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1587">1587</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td><TT>constexpr</TT> initialization and nested anonymous unions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9345,33 +9345,33 @@ and <I>POD class</I></td>
<td>Deducing cv-qualified <TT>auto</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1589">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1589">1589</a></td>
- <td>drafting</td>
+ <tr id="1589">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1589">1589</a></td>
+ <td>DR</td>
<td>Ambiguous ranking of list-initialization sequences</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1590">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1590">1590</a></td>
- <td>review</td>
+ <td>drafting</td>
<td>Bypassing non-copy/move constructor copying</td>
<td align="center">Not resolved</td>
</tr>
<tr id="1591">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1591">1591</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1591">1591</a></td>
+ <td>DR</td>
<td>Deducing array bound and element type from initializer list</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1592">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1592">1592</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>When do template parameters match?</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1593">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1593">1593</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>&#8220;Parameter type&#8221; of special member functions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9383,13 +9383,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1595">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1595">1595</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Constructors &#8220;involved in&#8221; subobject initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1596">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1596">1596</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1596">1596</a></td>
+ <td>DR</td>
<td>Non-array objects as <TT>array[1]</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9401,7 +9401,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1598">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1598">1598</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Criterion for equality of pointers to members</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9412,14 +9412,14 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1600">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1600">1600</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1600">1600</a></td>
+ <td>DR</td>
<td>Erroneous reference initialization in example</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1601">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1601">1601</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Promotion of enumeration with fixed underlying type</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9429,15 +9429,15 @@ and <I>POD class</I></td>
<td>Linkage of specialization vs linkage of template arguments</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1603">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1603">1603</a></td>
- <td>review</td>
+ <tr id="1603">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1603">1603</a></td>
+ <td>DR</td>
<td>Errors resulting from giving unnamed namespaces internal linkage</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1604">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1604">1604</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Double temporaries in reference initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9455,13 +9455,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1607">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1607">1607</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Lambdas in template parameters</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1608">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1608">1608</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Operator lookup in trailing return type</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9479,31 +9479,31 @@ and <I>POD class</I></td>
</tr>
<tr id="1611">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1611">1611</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Deleted default constructor for abstract class</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1612">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1612">1612</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Implicit lambda capture and anonymous unions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1613">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1613">1613</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Constant expressions and lambda capture</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1614">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1614">1614</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1614">1614</a></td>
+ <td>DR</td>
<td>Address of pure virtual function vs odr-use</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1615">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1615">1615</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1615">1615</a></td>
+ <td>DR</td>
<td>Alignment of types, variables, and members</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9521,7 +9521,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1618">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1618">1618</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Gratuitously-unsigned underlying enum type</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9587,21 +9587,21 @@ and <I>POD class</I></td>
</tr>
<tr id="1629">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1629">1629</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Can a closure class be a literal type?</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1630">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1630">1630</a></td>
- <td>drafting</td>
+ <tr id="1630">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1630">1630</a></td>
+ <td>DR</td>
<td>Multiple default constructor templates</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1631">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1631">1631</a></td>
- <td>drafting</td>
+ <tr id="1631">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1631">1631</a></td>
+ <td>DR</td>
<td>Incorrect overload resolution for single-element <I>initializer-list</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1632">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1632">1632</a></td>
@@ -9609,11 +9609,11 @@ and <I>POD class</I></td>
<td>Lambda capture in member initializers</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1633">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1633">1633</a></td>
- <td>review</td>
+ <tr id="1633">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1633">1633</a></td>
+ <td>DR</td>
<td>Copy-initialization in member initialization</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1634">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1634">1634</a></td>
@@ -9645,11 +9645,11 @@ and <I>POD class</I></td>
<td>Declaring an explicit specialization of a scoped enumeration</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1639">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1639">1639</a></td>
- <td>review</td>
+ <tr id="1639">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1639">1639</a></td>
+ <td>DR</td>
<td><I>exception-specification</I>s and pointer/pointer-to-member expressions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1640">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1640">1640</a></td>
@@ -9701,13 +9701,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1648">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1648">1648</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td><TT>thread_local</TT> vs block extern declarations</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1649">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1649">1649</a></td>
- <td>DRWP</td>
+ <td>C++14</td>
<td>Error in the syntax of <I>mem-initializer-list</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9717,17 +9717,17 @@ and <I>POD class</I></td>
<td>Class prvalues in reference initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr id="1651">
+ <tr class="open" id="1651">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1651">1651</a></td>
- <td>ready</td>
+ <td>drafting</td>
<td>Lifetime extension of temporary via reference to subobject</td>
- <td class="none" align="center">Unknown</td>
+ <td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1652">
+ <tr id="1652">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1652">1652</a></td>
- <td>drafting</td>
+ <td>ready</td>
<td>Object addresses in <TT>constexpr</TT> expressions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1653">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1653">1653</a></td>
@@ -9761,7 +9761,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1658">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1658">1658</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Deleted default constructor for abstract class via destructor</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9773,7 +9773,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1660">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1660">1660</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td><I>member-declaration</I> requirements and unnamed bit-fields</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9785,7 +9785,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1662">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1662">1662</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Capturing function parameter packs</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9797,7 +9797,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1664">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1664">1664</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Argument-dependent lookup of lambdas used in default arguments</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9809,7 +9809,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1666">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1666">1666</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Address constant expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9827,7 +9827,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1669">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1669">1669</a></td>
- <td>accepted</td>
+ <td>C++14</td>
<td><TT>auto</TT> return type for <TT>main</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9843,21 +9843,21 @@ and <I>POD class</I></td>
<td>Unclear rules for deduction with cv-qualification</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1672">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1672">1672</a></td>
- <td>drafting</td>
+ <tr id="1672">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1672">1672</a></td>
+ <td>DR</td>
<td>Layout compatibility with multiple empty bases</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1673">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1673">1673</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Clarifying overload resolution for the second step of copy-initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1674">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1674">1674</a></td>
- <td>accepted</td>
+ <td>C++14</td>
<td>Return type deduction for address of function</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9899,7 +9899,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1681">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1681">1681</a></td>
- <td>accepted</td>
+ <td>C++14</td>
<td><I>init-capture</I>s and nested lambdas</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9917,9 +9917,9 @@ and <I>POD class</I></td>
</tr>
<tr id="1684">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1684">1684</a></td>
- <td>accepted</td>
+ <td>C++14</td>
<td>Static <TT>constexpr</TT> member functions for non-literal classes</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Clang 3.6</td>
</tr>
<tr id="1685">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1685">1685</a></td>
@@ -9928,14 +9928,14 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1686">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1686">1686</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1686">1686</a></td>
+ <td>DR</td>
<td>Which variables are &#8220;explicitly declared <TT>const</TT>?&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1687">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1687">1687</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Conversions of operands of built-in operators</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9947,51 +9947,51 @@ and <I>POD class</I></td>
</tr>
<tr id="1689">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1689">1689</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Syntactic nonterminal for operand of <TT>alignas</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1690">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1690">1690</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Associated namespace for local type</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1691">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1691">1691</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Argument-dependent lookup and opaque enumerations</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1692">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1692">1692</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Associated namespaces of doubly-nested classes</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1693">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1693">1693</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Superfluous semicolons in class definitions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1694">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1694">1694</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1694">1694</a></td>
+ <td>DR</td>
<td>Restriction on reference to temporary as a constant expression</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1695">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1695">1695</a></td>
- <td>drafting</td>
+ <tr id="1695">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1695">1695</a></td>
+ <td>NAD</td>
<td>Lifetime extension via <I>init-capture</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1696">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1696">1696</a></td>
- <td>drafting</td>
+ <tr id="1696">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1696">1696</a></td>
+ <td>DR</td>
<td>Temporary lifetime and non-static data member initializers</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1697">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1697">1697</a></td>
@@ -10042,8 +10042,8 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1705">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1705">1705</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1705">1705</a></td>
+ <td>DR</td>
<td>Unclear specification of &#8220;more specialized&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10055,15 +10055,15 @@ and <I>POD class</I></td>
</tr>
<tr id="1707">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1707">1707</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td><TT>template</TT> in <I>elaborated-type-specifier</I> without <I>nested-name-specifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1708">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1708">1708</a></td>
- <td>review</td>
+ <tr id="1708">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1708">1708</a></td>
+ <td>DR</td>
<td>overly-strict requirements for names with C language linkage</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1709">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1709">1709</a></td>
@@ -10071,11 +10071,11 @@ and <I>POD class</I></td>
<td>Stringizing raw string literals containing newline</td>
<td align="center">Not resolved</td>
</tr>
- <tr id="1710">
+ <tr class="open" id="1710">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1710">1710</a></td>
- <td>ready</td>
+ <td>review</td>
<td>Missing <TT>template</TT> keyword in <I>class-or-decltype</I></td>
- <td class="none" align="center">Unknown</td>
+ <td align="center">Not resolved</td>
</tr>
<tr class="open" id="1711">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1711">1711</a></td>
@@ -10084,8 +10084,8 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1712">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1712">1712</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1712">1712</a></td>
+ <td>DR</td>
<td><TT>constexpr</TT> variable template declarations</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10101,21 +10101,21 @@ and <I>POD class</I></td>
<td>odr-use of <TT>this</TT> from a local class</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr id="1715">
+ <tr class="open" id="1715">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1715">1715</a></td>
- <td>ready</td>
+ <td>drafting</td>
<td>Access and inherited constructor templates</td>
- <td class="none" align="center">Unknown</td>
+ <td align="center">Not resolved</td>
</tr>
<tr id="1716">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1716">1716</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>When are default arguments evaluated?</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1717">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1717">1717</a></td>
- <td>accepted</td>
+ <td>C++14</td>
<td>Missing specification of type of binary literal</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10125,11 +10125,11 @@ and <I>POD class</I></td>
<td>Macro invocation spanning end-of-file</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1719">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1719">1719</a></td>
- <td>drafting</td>
+ <tr id="1719">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1719">1719</a></td>
+ <td>DR</td>
<td>Layout compatibility and cv-qualification revisited</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1720">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1720">1720</a></td>
@@ -10205,7 +10205,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1732">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1732">1732</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Defining types in <I>condition</I>s and range-based <TT>for</TT> statements</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10235,31 +10235,31 @@ and <I>POD class</I></td>
</tr>
<tr id="1737">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1737">1737</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Type dependence of call to a member of the current instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1738">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1738">1738</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Explicit instantiation/specialization of inheriting constructor templates</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1739">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1739">1739</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Conversion of floating point to enumeration</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1740">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1740">1740</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Disambiguation of <TT>noexcept</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1741">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1741">1741</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>odr-use of class object in lvalue-to-rvalue conversion</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10275,11 +10275,11 @@ and <I>POD class</I></td>
<td><I>init-capture</I>s in nested lambdas</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1744">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1744">1744</a></td>
- <td>review</td>
+ <tr id="1744">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1744">1744</a></td>
+ <td>DR</td>
<td>Unordered initialization for variable template specializations</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1745">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1745">1745</a></td>
@@ -10289,19 +10289,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1746">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1746">1746</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Are volatile scalar types trivially copyable?</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1747">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1747">1747</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Constant initialization of reference to function</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1748">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1748">1748</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1748">1748</a></td>
+ <td>DR</td>
<td>Placement new with a null pointer</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10312,26 +10312,26 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1750">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1750">1750</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1750">1750</a></td>
+ <td>DR</td>
<td>&#8220;Argument&#8221; vs &#8220;parameter&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1751">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1751">1751</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1751">1751</a></td>
+ <td>DR</td>
<td>Non-trivial operations vs non-trivial initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1752">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1752">1752</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1752">1752</a></td>
+ <td>DR</td>
<td>Right-recursion in <I>mem-initializer-list</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1753">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1753">1753</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1753">1753</a></td>
+ <td>DR</td>
<td><I>decltype-specifier</I> in <I>nested-name-specifier</I> of destructor</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10347,33 +10347,33 @@ and <I>POD class</I></td>
<td>Out-of-class partial specializations of member templates</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1756">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1756">1756</a></td>
- <td>review</td>
+ <tr id="1756">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1756">1756</a></td>
+ <td>DR</td>
<td>Direct-list-initialization of a non-class object</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1757">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1757">1757</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1757">1757</a></td>
+ <td>DR</td>
<td>Const integral subobjects</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1758">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1758">1758</a></td>
- <td>open</td>
+ <tr id="1758">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1758">1758</a></td>
+ <td>DR</td>
<td>Explicit conversion in copy/move list initialization</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1759">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1759">1759</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>UTF-8 code units in plain <TT>char</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1760">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1760">1760</a></td>
- <td>accepted</td>
+ <td>C++14</td>
<td>Access of member corresponding to <I>init-capture</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10385,7 +10385,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1762">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1762">1762</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Reserved identifier used in <I>literal-operator-id</I> example</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10397,25 +10397,25 @@ and <I>POD class</I></td>
</tr>
<tr id="1764">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1764">1764</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Hiding of function from using-declaration by signature</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1765">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1765">1765</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Overflow of enumeration used as enumerator value</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1766">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1766">1766</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1766">1766</a></td>
+ <td>DR</td>
<td>Values outside the range of the values of an enumeration</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1767">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1767">1767</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Scoped enumeration in a <TT>switch</TT> statement</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10427,13 +10427,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1769">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1769">1769</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Catching a base class of the exception object</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1770">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1770">1770</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Type matching of non-type template parameters and arguments</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10445,25 +10445,25 @@ and <I>POD class</I></td>
</tr>
<tr id="1772">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1772">1772</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td><TT>__func__</TT> in a lambda body</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1773">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1773">1773</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Out-of-lifetime lvalue-to-rvalue conversion</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1774">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1774">1774</a></td>
- <td>drafting</td>
+ <tr id="1774">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1774">1774</a></td>
+ <td>DR</td>
<td>Discrepancy between subobject destruction and stack unwinding</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1775">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1775">1775</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Undefined behavior of line splice in raw string literal</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10474,26 +10474,26 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1777">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1777">1777</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1777">1777</a></td>
+ <td>DR</td>
<td>Empty pack expansion in <I>dynamic-exception-specification</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1778">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1778">1778</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td><I>exception-specification</I> in explicitly-defaulted functions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1779">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1779">1779</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1779">1779</a></td>
+ <td>DR</td>
<td>Type dependency of <TT>__func__</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1780">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1780">1780</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1780">1780</a></td>
+ <td>DR</td>
<td>Explicit instantiation/specialization of generic lambda <TT>operator()</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10504,8 +10504,8 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1782">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1782">1782</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1782">1782</a></td>
+ <td>DR</td>
<td>Form of initialization for <TT>nullptr_t</TT> to <TT>bool</TT> conversion</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10529,21 +10529,21 @@ and <I>POD class</I></td>
</tr>
<tr id="1786">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1786">1786</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Effect of merging allocations on memory leakage</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1787">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1787">1787</a></td>
- <td>DR</td>
+ <td>C++14</td>
<td>Uninitialized <TT>unsigned char</TT> values</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1788">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1788">1788</a></td>
- <td>review</td>
+ <tr id="1788">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1788">1788</a></td>
+ <td>DR</td>
<td>Sized deallocation of array of non-class type</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1789">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1789">1789</a></td>
@@ -10552,14 +10552,14 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1790">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1790">1790</a></td>
- <td>open</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1790">1790</a></td>
+ <td>extension</td>
<td>Ellipsis following function parameter pack</td>
<td align="center">Not resolved</td>
</tr>
<tr id="1791">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1791">1791</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1791">1791</a></td>
+ <td>DR</td>
<td>Incorrect restrictions on <I>cv-qualifier-seq</I> and <I>ref-qualifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10570,32 +10570,32 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1793">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1793">1793</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1793">1793</a></td>
+ <td>DR</td>
<td><TT>thread_local</TT> in explicit specializations</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr id="1794">
+ <tr class="open" id="1794">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1794">1794</a></td>
- <td>ready</td>
+ <td>review</td>
<td><TT>template</TT> keyword and alias templates</td>
- <td class="none" align="center">Unknown</td>
+ <td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1795">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1795">1795</a></td>
- <td>drafting</td>
+ <tr id="1795">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1795">1795</a></td>
+ <td>DR</td>
<td>Disambiguating <I>original-namespace-definition</I> and <I>extension-namespace-definition</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1796">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1796">1796</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1796">1796</a></td>
+ <td>DR</td>
<td>Is all-bits-zero for null characters a meaningful requirement?</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1797">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1797">1797</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1797">1797</a></td>
+ <td>DR</td>
<td>Are all bit patterns of <TT>unsigned char</TT> distinct numbers?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10606,14 +10606,14 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1799">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1799">1799</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1799">1799</a></td>
+ <td>DR</td>
<td><TT>mutable</TT> and non-explicit const qualification</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1800">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1800">1800</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1800">1800</a></td>
+ <td>DR</td>
<td>Pointer to member of nested anonymous union</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10624,8 +10624,8 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1802">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1802">1802</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1802">1802</a></td>
+ <td>DR</td>
<td><TT>char16_t</TT> string literals and surrogate pairs</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10636,26 +10636,26 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1804">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1804">1804</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1804">1804</a></td>
+ <td>DR</td>
<td>Partial specialization and friendship</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1805">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1805">1805</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1805">1805</a></td>
+ <td>DR</td>
<td>Conversions of array operands in <I>conditional-expression</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1806">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1806">1806</a></td>
- <td>review</td>
+ <tr id="1806">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1806">1806</a></td>
+ <td>DR</td>
<td>Virtual bases and move-assignment</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1807">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1807">1807</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1807">1807</a></td>
+ <td>DR</td>
<td>Order of destruction of array elements after an exception</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10666,58 +10666,58 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1809">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1809">1809</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1809">1809</a></td>
+ <td>DR</td>
<td>Narrowing and template argument deduction</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1810">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1810">1810</a></td>
- <td>review</td>
+ <tr id="1810">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1810">1810</a></td>
+ <td>DR</td>
<td>Invalid <I>ud-suffix</I>es</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1811">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1811">1811</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1811">1811</a></td>
+ <td>DR</td>
<td>Lookup of deallocation function in a virtual destructor definition</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr id="1812">
+ <tr class="open" id="1812">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1812">1812</a></td>
- <td>ready</td>
+ <td>review</td>
<td>Omission of <TT>template</TT> in a <I>typename-specifier</I></td>
- <td class="none" align="center">Unknown</td>
+ <td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1813">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1813">1813</a></td>
- <td>drafting</td>
+ <tr id="1813">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1813">1813</a></td>
+ <td>DR</td>
<td>Direct vs indirect bases in standard-layout classes</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1814">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1814">1814</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1814">1814</a></td>
+ <td>DR</td>
<td>Default arguments in <I>lambda-expression</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1815">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1815">1815</a></td>
- <td>drafting</td>
+ <tr id="1815">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1815">1815</a></td>
+ <td>DR</td>
<td>Lifetime extension in aggregate initialization</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1816">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1816">1816</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1816">1816</a></td>
+ <td>DR</td>
<td>Unclear specification of bit-field values</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr id="1817">
+ <tr class="open" id="1817">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1817">1817</a></td>
- <td>ready</td>
+ <td>drafting</td>
<td>Linkage specifications and nested scopes</td>
- <td class="none" align="center">Unknown</td>
+ <td align="center">Not resolved</td>
</tr>
<tr class="open" id="1818">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1818">1818</a></td>
@@ -10725,11 +10725,11 @@ and <I>POD class</I></td>
<td>Visibility and inherited language linkage</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1819">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1819">1819</a></td>
- <td>review</td>
+ <tr id="1819">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1819">1819</a></td>
+ <td>DR</td>
<td>Acceptable scopes for definition of partial specialization</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1820">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1820">1820</a></td>
@@ -10749,15 +10749,15 @@ and <I>POD class</I></td>
<td>Lookup of parameter names in <I>lambda-expression</I>s</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1823">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1823">1823</a></td>
- <td>review</td>
+ <tr id="1823">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1823">1823</a></td>
+ <td>DR</td>
<td>String literal uniqueness in inline functions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1824">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1824">1824</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1824">1824</a></td>
+ <td>DR</td>
<td>Completeness of return type vs point of instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10792,8 +10792,8 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1830">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1830">1830</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1830">1830</a></td>
+ <td>DR</td>
<td>Repeated specifiers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10804,8 +10804,8 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1832">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1832">1832</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1832">1832</a></td>
+ <td>DR</td>
<td>Casting to incomplete enumeration</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10816,8 +10816,8 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1834">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1834">1834</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1834">1834</a></td>
+ <td>DR</td>
<td>Constant initialization binding a reference to an xvalue</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10839,11 +10839,11 @@ and <I>POD class</I></td>
<td>Use of <TT>this</TT> in <TT>friend</TT> and local class declarations</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1838">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1838">1838</a></td>
- <td>drafting</td>
+ <tr id="1838">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1838">1838</a></td>
+ <td>DR</td>
<td>Definition via <I>unqualified-id</I> and <I>using-declaration</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1839">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1839">1839</a></td>
@@ -10870,8 +10870,8 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1843">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1843">1843</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1843">1843</a></td>
+ <td>DR</td>
<td>Bit-field in conditional operator with <TT>throw</TT> operand</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10887,11 +10887,11 @@ and <I>POD class</I></td>
<td>Point of instantiation of a variable template specialization</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1846">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1846">1846</a></td>
- <td>review</td>
+ <tr id="1846">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1846">1846</a></td>
+ <td>DR</td>
<td>Declaring explicitly-defaulted implicitly-deleted functions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1847">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1847">1847</a></td>
@@ -10899,11 +10899,11 @@ and <I>POD class</I></td>
<td>Clarifying compatibility during partial ordering</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1848">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1848">1848</a></td>
- <td>open</td>
+ <tr id="1848">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1848">1848</a></td>
+ <td>DR</td>
<td>Parenthesized constructor and destructor declarators</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1849">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1849">1849</a></td>
@@ -10912,20 +10912,20 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1850">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1850">1850</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1850">1850</a></td>
+ <td>DR</td>
<td>Differences between definition context and point of instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1851">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1851">1851</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1851">1851</a></td>
+ <td>DR</td>
<td><TT>decltype(auto)</TT> in <I>new-expression</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1852">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1852">1852</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1852">1852</a></td>
+ <td>DR</td>
<td>Wording issues regarding <TT>decltype(auto)</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10937,15 +10937,15 @@ and <I>POD class</I></td>
</tr>
<tr class="open" id="1854">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1854">1854</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Disallowing use of implicitly-deleted functions</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1855">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1855">1855</a></td>
- <td>open</td>
+ <tr id="1855">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1855">1855</a></td>
+ <td>dup</td>
<td>Out-of-lifetime access to nonstatic data members</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1856">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1856">1856</a></td>
@@ -10955,195 +10955,195 @@ and <I>POD class</I></td>
</tr>
<tr class="open" id="1857">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1857">1857</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Additional questions about bits</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1858">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1858">1858</a></td>
- <td>open</td>
+ <tr id="1858">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1858">1858</a></td>
+ <td>DR</td>
<td>Comparing pointers to union members</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1859">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1859">1859</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>UTF-16 in <TT>char16_t</TT> string literals</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1860">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1860">1860</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>What is a &#8220;direct member?&#8221;</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1861">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1861">1861</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Values of a bit-field</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1862">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1862">1862</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Determining &#8220;corresponding members&#8221; for friendship</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1863">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1863">1863</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Requirements on thrown object type to support <TT>std::current_exception()</TT></td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1864">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1864">1864</a></td>
- <td>open</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1864">1864</a></td>
+ <td>extension</td>
<td>List-initialization of array objects</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1865">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1865">1865</a></td>
- <td>open</td>
+ <tr id="1865">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1865">1865</a></td>
+ <td>DR</td>
<td>Pointer arithmetic and multi-level qualification conversions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1866">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1866">1866</a></td>
- <td>open</td>
+ <tr id="1866">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1866">1866</a></td>
+ <td>DR</td>
<td>Initializing variant members with non-trivial destructors</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1867">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1867">1867</a></td>
- <td>open</td>
+ <tr id="1867">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1867">1867</a></td>
+ <td>NAD</td>
<td>Function/expression ambiguity with qualified parameter name</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1868">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1868">1868</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Meaning of &#8220;placeholder type&#8221;</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1869">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1869">1869</a></td>
- <td>open</td>
+ <tr id="1869">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1869">1869</a></td>
+ <td>NAD</td>
<td><TT>thread_local</TT> vs <I>linkage-specification</I>s</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1870">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1870">1870</a></td>
- <td>open</td>
+ <tr id="1870">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1870">1870</a></td>
+ <td>DR</td>
<td>Contradictory wording about definitions vs explicit specialization/instantiation</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1871">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1871">1871</a></td>
- <td>open</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1871">1871</a></td>
+ <td>extension</td>
<td>Non-identifier characters in <I>ud-suffix</I></td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1872">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1872">1872</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Instantiations of <TT>constexpr</TT> templates that cannot appear in constant expressions</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1873">
+ <tr id="1873">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1873">1873</a></td>
- <td>open</td>
+ <td>ready</td>
<td>Protected member access from derived class friends</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1874">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1874">1874</a></td>
- <td>open</td>
+ <tr id="1874">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1874">1874</a></td>
+ <td>DR</td>
<td>Type vs non-type template parameters with <TT>class</TT> keyword</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1875">
+ <tr id="1875">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1875">1875</a></td>
- <td>open</td>
+ <td>ready</td>
<td>Reordering declarations in class scope</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1876">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1876">1876</a></td>
- <td>open</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1876">1876</a></td>
+ <td>extension</td>
<td>Preventing explicit specialization</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1877">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1877">1877</a></td>
- <td>open</td>
+ <tr id="1877">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1877">1877</a></td>
+ <td>DR</td>
<td>Return type deduction from <TT>return</TT> with no operand</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1878">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1878">1878</a></td>
- <td>open</td>
+ <tr id="1878">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1878">1878</a></td>
+ <td>DR</td>
<td><TT>operator auto</TT> template</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1879">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1879">1879</a></td>
- <td>open</td>
+ <tr id="1879">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1879">1879</a></td>
+ <td>NAD</td>
<td>Inadequate definition of alignment requirement</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1880">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1880">1880</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>When are parameter objects destroyed?</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1881">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1881">1881</a></td>
- <td>open</td>
+ <tr id="1881">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1881">1881</a></td>
+ <td>DR</td>
<td>Standard-layout classes and unnamed bit-fields</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1882">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1882">1882</a></td>
- <td>open</td>
+ <tr id="1882">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1882">1882</a></td>
+ <td>DR</td>
<td>Reserved names without library use</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1883">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1883">1883</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Protected access to constructors in <I>mem-initializer</I>s</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1884">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1884">1884</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Unclear requirements for same-named external-linkage entities</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1885">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1885">1885</a></td>
- <td>open</td>
+ <tr id="1885">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1885">1885</a></td>
+ <td>DR</td>
<td>Return value of a function is underspecified</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1886">
+ <tr id="1886">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1886">1886</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Language linkage for <TT>main()</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1887">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1887">1887</a></td>
- <td>open</td>
+ <tr id="1887">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1887">1887</a></td>
+ <td>DR</td>
<td>Problems with <TT>::</TT> as <I>nested-name-specifier</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1888">
+ <tr id="1888">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1888">1888</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Implicitly-declared default constructors and <TT>explicit</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1889">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1889">1889</a></td>
@@ -11153,26 +11153,26 @@ and <I>POD class</I></td>
</tr>
<tr class="open" id="1890">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1890">1890</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Member type depending on definition of member function</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1891">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1891">1891</a></td>
- <td>open</td>
+ <tr id="1891">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1891">1891</a></td>
+ <td>DR</td>
<td>Move constructor/assignment for closure class</td>
- <td align="center">Not resolved</td>
+ <td class="full" align="center">Clang 3.6</td>
</tr>
- <tr class="open" id="1892">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1892">1892</a></td>
- <td>open</td>
+ <tr id="1892">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1892">1892</a></td>
+ <td>DR</td>
<td>Use of <TT>auto</TT> in function type</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1893">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1893">1893</a></td>
- <td>open</td>
- <td>Function-syle cast with <I>braced-init-list</I>s and empty pack expansions</td>
+ <td>drafting</td>
+ <td>Function-style cast with <I>braced-init-list</I>s and empty pack expansions</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1894">
@@ -11183,51 +11183,51 @@ and <I>POD class</I></td>
</tr>
<tr class="open" id="1895">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1895">1895</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Deleted conversions in conditional operator operands</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1896">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1896">1896</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Repeated alias templates</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1897">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1897">1897</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>ODR vs alternative tokens</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1898">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1898">1898</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Use of &#8220;equivalent&#8221; in overload resolution</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1899">
+ <tr id="1899">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1899">1899</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Value-dependent constant expressions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1900">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1900">1900</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Do <TT>friend</TT> declarations count as &#8220;previous declarations&#8221;?</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1901">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1901">1901</a></td>
- <td>open</td>
+ <td>drafting</td>
<td><I>punctuator</I> referenced but not defined</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1902">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1902">1902</a></td>
- <td>open</td>
+ <tr id="1902">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1902">1902</a></td>
+ <td>DR</td>
<td>What makes a conversion &#8220;otherwise ill-formed&#8221;?</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1903">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1903">1903</a></td>
@@ -11235,21 +11235,21 @@ and <I>POD class</I></td>
<td>What declarations are introduced by a non-member <I>using-declaration</I>?</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1904">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1904">1904</a></td>
- <td>open</td>
+ <tr id="1904">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1904">1904</a></td>
+ <td>NAD</td>
<td>Default template arguments for members of class templates</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1905">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1905">1905</a></td>
- <td>open</td>
+ <tr id="1905">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/">1905</a></td>
+ <td>MAD</td>
<td>Dependent types and injected-class-names</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1906">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1906">1906</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Name lookup in member <TT>friend</TT> declaration</td>
<td align="center">Not resolved</td>
</tr>
@@ -11261,61 +11261,61 @@ and <I>POD class</I></td>
</tr>
<tr class="open" id="1908">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1908">1908</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Dual destructor lookup and <I>template-id</I>s</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1909">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1909">1909</a></td>
- <td>open</td>
+ <tr id="1909">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1909">1909</a></td>
+ <td>DR</td>
<td>Member class template with the same name as the class</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1910">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1910">1910</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>&#8220;Shall&#8221; requirement applied to runtime behavior</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1911">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1911">1911</a></td>
- <td>open</td>
+ <tr id="1911">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1911">1911</a></td>
+ <td>DR</td>
<td><TT>constexpr</TT> constructor with non-literal base class</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1912">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1912">1912</a></td>
- <td>open</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1912">1912</a></td>
+ <td>extension</td>
<td><I>exception-specification</I> of defaulted function</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1913">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1913">1913</a></td>
- <td>open</td>
+ <td>drafting</td>
<td><TT>decltype((x))</TT> in <I>lambda-expression</I>s</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1914">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1914">1914</a></td>
- <td>open</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1914">1914</a></td>
+ <td>extension</td>
<td>Duplicate standard attributes</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1915">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1915">1915</a></td>
- <td>open</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1915">1915</a></td>
+ <td>extension</td>
<td>Potentially-invoked destructors in non-throwing constructors</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1916">
+ <tr id="1916">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1916">1916</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>&#8220;Same cv-unqualified type&#8221;</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1917">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1917">1917</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>decltype-qualified enumeration names</td>
<td align="center">Not resolved</td>
</tr>
@@ -11331,53 +11331,53 @@ and <I>POD class</I></td>
<td>Overload resolution for <TT>!</TT> with explicit conversion operator</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1920">
+ <tr id="1920">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1920">1920</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Qualification mismatch in <I>pseudo-destructor-name</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1921">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1921">1921</a></td>
- <td>open</td>
+ <tr id="1921">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1921">1921</a></td>
+ <td>NAD</td>
<td><TT>constexpr</TT> constructors and point of initialization of <TT>const</TT> variables</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1922">
+ <tr id="1922">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1922">1922</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Injected class template names and default arguments</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1923">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1923">1923</a></td>
- <td>open</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1923">1923</a></td>
+ <td>extension</td>
<td>Lvalues of type <TT>void</TT></td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1924">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1924">1924</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Definition of &#8220;literal&#8221; and kinds of literals</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1925">
+ <tr id="1925">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1925">1925</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Bit-field prvalues</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1926">
+ <tr id="1926">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1926">1926</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Potential results of subscript operator</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1927">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1927">1927</a></td>
- <td>open</td>
+ <tr id="1927">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1927">1927</a></td>
+ <td>dup</td>
<td>Lifetime of temporaries in <I>init-capture</I>s</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1928">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1928">1928</a></td>
@@ -11385,24 +11385,648 @@ and <I>POD class</I></td>
<td>Triviality of deleted special member functions</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1929">
+ <tr id="1929">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1929">1929</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td><TT>template</TT> keyword following namespace <I>nested-name-specifier</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1930">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1930">1930</a></td>
- <td>open</td>
+ <td>review</td>
<td><I>init-declarator-list</I> vs <I>member-declarator-list</I></td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1931">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1931">1931</a></td>
- <td>open</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1931">1931</a></td>
+ <td>extension</td>
<td>Default-constructible and copy-assignable closure types</td>
<td align="center">Not resolved</td>
</tr>
+ <tr class="open" id="1932">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1932">1932</a></td>
+ <td>drafting</td>
+ <td>Bit-field results of conditional operators</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1933">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1933">1933</a></td>
+ <td>NAD</td>
+ <td>Implementation limit for <I>initializer-list</I> elements</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1934">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1934">1934</a></td>
+ <td>extension</td>
+ <td>Relaxing <I>exception-specification</I> compatibility requirements</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1935">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1935">1935</a></td>
+ <td>drafting</td>
+ <td>Reuse of placement arguments in deallocation</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1936">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1936">1936</a></td>
+ <td>drafting</td>
+ <td>Dependent <I>qualified-id</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1937">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1937">1937</a></td>
+ <td>drafting</td>
+ <td>Incomplete specification of function pointer from lambda</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1938">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1938">1938</a></td>
+ <td>drafting</td>
+ <td>Should hosted/freestanding be implementation-defined?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1939">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1939">1939</a></td>
+ <td>drafting</td>
+ <td>Argument conversions to nondeduced parameter types revisited</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1940">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1940">1940</a></td>
+ <td>DR</td>
+ <td><TT>static_assert</TT> in anonymous unions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1941">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1941">1941</a></td>
+ <td>drafting</td>
+ <td>SFINAE and inherited constructor default arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1942">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1942">1942</a></td>
+ <td>tentatively ready</td>
+ <td>Incorrect reference to <I>trailing-return-type</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1943">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1943">1943</a></td>
+ <td>open</td>
+ <td>Unspecified meaning of &#8220;bit&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1944">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1944">1944</a></td>
+ <td>open</td>
+ <td>New C incompatibilities</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1945">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1945">1945</a></td>
+ <td>open</td>
+ <td>Friend declarations naming members of class templates in non-templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1946">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1946">1946</a></td>
+ <td>open</td>
+ <td><I>exception-specification</I>s vs pointer dereference</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1947">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1947">1947</a></td>
+ <td>NAD</td>
+ <td>Digit separators following non-octal prefix</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="1948">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1948">1948</a></td>
+ <td>NAD</td>
+ <td><I>exception-specification</I> of replacement global <TT>new</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1949">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1949">1949</a></td>
+ <td>drafting</td>
+ <td>&#8220;sequenced after&#8221; instead of &#8220;sequenced before&#8221;</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1950">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1950">1950</a></td>
+ <td>NAD</td>
+ <td>Restructuring description of ranks of conversion sequences</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1951">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1951">1951</a></td>
+ <td>drafting</td>
+ <td>Cv-qualification and literal types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1952">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1952">1952</a></td>
+ <td>drafting</td>
+ <td>Constant expressions and library undefined behavior</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1953">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1953">1953</a></td>
+ <td>open</td>
+ <td>Data races and common initial sequence</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1954">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1954">1954</a></td>
+ <td>open</td>
+ <td><TT>typeid</TT> null dereference check in subexpressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1955">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1955">1955</a></td>
+ <td>review</td>
+ <td><TT>#elif</TT> with invalid controlling expression</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1956">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1956">1956</a></td>
+ <td>tentatively ready</td>
+ <td>Reuse of storage of automatic variables</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1957">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1957">1957</a></td>
+ <td>extension</td>
+ <td><TT>decltype(auto)</TT> with direct-list-initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1958">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1958">1958</a></td>
+ <td>drafting</td>
+ <td><TT>decltype(auto)</TT> with parenthesized initializer</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1959">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1959">1959</a></td>
+ <td>drafting</td>
+ <td>Inadvertently inherited copy constructor</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1960">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1960">1960</a></td>
+ <td>NAD</td>
+ <td>Visibility of entity named in class-scope <I>using-declaration</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1961">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1961">1961</a></td>
+ <td>concurrency</td>
+ <td>Potentially-concurrent actions within a signal handler</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1962">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1962">1962</a></td>
+ <td>open</td>
+ <td>Type of <TT>__func__</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1963">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1963">1963</a></td>
+ <td>drafting</td>
+ <td>Implementation-defined identifier characters</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1964">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1964">1964</a></td>
+ <td>NAD</td>
+ <td><I>opaque-enum-declaration</I> in <I>alias-declaration</I>?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1965">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1965">1965</a></td>
+ <td>open</td>
+ <td>Explicit casts to reference types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1966">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1966">1966</a></td>
+ <td>drafting</td>
+ <td>Colon following enumeration <I>elaborated-type-specifier</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1967">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1967">1967</a></td>
+ <td>drafting</td>
+ <td>Temporary lifetime and move-elision</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1968">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1968">1968</a></td>
+ <td>NAD</td>
+ <td>Address of <TT>typeid</TT> in constant expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1969">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1969">1969</a></td>
+ <td>open</td>
+ <td>Missing exclusion of <TT>~S</TT> as an ordinary function name</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1970">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1970">1970</a></td>
+ <td>NAD</td>
+ <td>Ambiguity resolution for <TT>(T())*x</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="1971">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1971">1971</a></td>
+ <td>tentatively ready</td>
+ <td>Unclear disambiguation of destructor and <TT>operator~</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1972">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1972">1972</a></td>
+ <td>open</td>
+ <td>Identifier character restrictions in non-<I>identifier</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1973">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1973">1973</a></td>
+ <td>drafting</td>
+ <td>Which <I>parameter-declaration-clause</I> in a <I>lambda-expression</I>?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1974">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1974">1974</a></td>
+ <td>open</td>
+ <td>Redundant specification of non-type <I>typename-specifier</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1975">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1975">1975</a></td>
+ <td>drafting</td>
+ <td>Permissible declarations for <I>exception-specification</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1976">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1976">1976</a></td>
+ <td>NAD</td>
+ <td>Ambiguity of <I>namespace-alias</I>es</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1977">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1977">1977</a></td>
+ <td>drafting</td>
+ <td>Contradictory results of failed destructor lookup</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1978">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1978">1978</a></td>
+ <td>drafting</td>
+ <td>Redundant description of explicit constructor use</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1979">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1979">1979</a></td>
+ <td>open</td>
+ <td>Alias template specialization in template member definition</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1980">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1980">1980</a></td>
+ <td>drafting</td>
+ <td>Equivalent but not functionally-equivalent redeclarations</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1981">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1981">1981</a></td>
+ <td>drafting</td>
+ <td>Implicit contextual conversions and <TT>explicit</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1982">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1982">1982</a></td>
+ <td>NAD</td>
+ <td>Deduction extending parameter pack</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1983">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1983">1983</a></td>
+ <td>drafting</td>
+ <td>Inappropriate use of <I>virt-specifier</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1984">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1984">1984</a></td>
+ <td>NAD</td>
+ <td>Lossless narrowing conversions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="1985">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1985">1985</a></td>
+ <td>NAD</td>
+ <td>Unknown bound array member with <I>brace-or-equal-initializer</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="1986">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1986">1986</a></td>
+ <td>ready</td>
+ <td>odr-use and delayed initialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="1987">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1987">1987</a></td>
+ <td>NAD</td>
+ <td><TT>constexpr</TT> static data members across translation units</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1988">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1988">1988</a></td>
+ <td>drafting</td>
+ <td>Ambiguity between dependent and non-dependent bases in implicit member access</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1989">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1989">1989</a></td>
+ <td>drafting</td>
+ <td>Insufficient restrictions on parameters of postfix operators</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1990">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1990">1990</a></td>
+ <td>drafting</td>
+ <td>Ambiguity due to optional <I>decl-specifier-seq</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1991">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1991">1991</a></td>
+ <td>open</td>
+ <td>Inheriting constructors vs default arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1992">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1992">1992</a></td>
+ <td>drafting</td>
+ <td><TT>new (std::nothrow) int[N]</TT> can throw</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1993">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1993">1993</a></td>
+ <td>open</td>
+ <td>Use of <TT>template&lt;&gt;</TT> defining member of explicit specialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1994">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1994">1994</a></td>
+ <td>dup</td>
+ <td>Confusing wording regarding multiple <TT>template&lt;&gt;</TT> prefixes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1995">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1995">1995</a></td>
+ <td>open</td>
+ <td><I>exception-specification</I>s and non-type template parameters</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1996">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1996">1996</a></td>
+ <td>open</td>
+ <td>Reference list-initialization ignores conversion functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="1997">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1997">1997</a></td>
+ <td>drafting</td>
+ <td>Placement new and previous initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="1998">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1998">1998</a></td>
+ <td>NAD</td>
+ <td>Additional sources of xvalue expressions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="1999">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1999">1999</a></td>
+ <td>drafting</td>
+ <td>Representation of source characters as universal-character-names</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2000">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2000">2000</a></td>
+ <td>drafting</td>
+ <td><I>header-name</I> outside <TT>#include</TT> directive</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2001">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2001">2001</a></td>
+ <td>drafting</td>
+ <td><I>non-directive</I> is underspecified</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2002">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2002">2002</a></td>
+ <td>open</td>
+ <td>White space within preprocessing directives</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2003">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2003">2003</a></td>
+ <td>drafting</td>
+ <td>Zero-argument macros incorrectly specified</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2004">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2004">2004</a></td>
+ <td>drafting</td>
+ <td>Unions with mutable members in constant expressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2005">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2005">2005</a></td>
+ <td>NAD</td>
+ <td>Incorrect <TT>constexpr</TT> reference initialization requirements</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2006">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2006">2006</a></td>
+ <td>drafting</td>
+ <td>Cv-qualified <TT>void</TT> types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2007">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2007">2007</a></td>
+ <td>drafting</td>
+ <td>Argument-dependent lookup for <TT>operator=</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2008">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2008">2008</a></td>
+ <td>review</td>
+ <td>Default <I>template-argument</I>s underspecified</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2009">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2009">2009</a></td>
+ <td>open</td>
+ <td>Unclear specification of class scope</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2010">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2010">2010</a></td>
+ <td>open</td>
+ <td><I>exception-specification</I>s and conversion operators</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2011">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2011">2011</a></td>
+ <td>review</td>
+ <td>Unclear effect of reference capture of reference</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2012">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2012">2012</a></td>
+ <td>open</td>
+ <td>Lifetime of references</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2013">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2013">2013</a></td>
+ <td>drafting</td>
+ <td>Pointer subtraction in large array</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2014">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2014">2014</a></td>
+ <td>NAD</td>
+ <td>Unneeded deallocation signatures</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2015">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2015">2015</a></td>
+ <td>drafting</td>
+ <td>odr-use of deleted virtual functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2016">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2016">2016</a></td>
+ <td>drafting</td>
+ <td>Confusing wording in description of conversion function</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2017">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2017">2017</a></td>
+ <td>drafting</td>
+ <td>Flowing off end is not equivalent to no-expression return</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2018">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2018">2018</a></td>
+ <td>open</td>
+ <td>Qualification conversion vs reference binding</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2019">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2019">2019</a></td>
+ <td>drafting</td>
+ <td>Member references omitted from description of storage duration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2020">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2020">2020</a></td>
+ <td>drafting</td>
+ <td>Inadequate description of odr-use of implicitly-invoked functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2021">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2021">2021</a></td>
+ <td>dup</td>
+ <td>Function template redeclaration via alias template</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2022">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2022">2022</a></td>
+ <td>drafting</td>
+ <td>Copy elision in constant expressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2023">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2023">2023</a></td>
+ <td>open</td>
+ <td>Composite reference result type of conditional operator</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2024">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2024">2024</a></td>
+ <td>open</td>
+ <td>Dependent types and unexpanded parameter packs</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2025">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2025">2025</a></td>
+ <td>open</td>
+ <td>Declaration matching via alias templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2026">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2026">2026</a></td>
+ <td>drafting</td>
+ <td>Zero-initialization and <TT>constexpr</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2027">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2027">2027</a></td>
+ <td>drafting</td>
+ <td>Unclear requirements for multiple <TT>alignas</TT> specifiers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2028">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2028">2028</a></td>
+ <td>drafting</td>
+ <td>Converting constructors in rvalue reference initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2029">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2029">2029</a></td>
+ <td>dup</td>
+ <td>Abstract class return type in <TT>decltype</TT> operand</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2030">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2030">2030</a></td>
+ <td>NAD</td>
+ <td>Access of injected-class-name with template arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2031">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2031">2031</a></td>
+ <td>drafting</td>
+ <td>Missing incompatibility for <TT>&amp;&amp;</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2032">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2032">2032</a></td>
+ <td>open</td>
+ <td>Default <I>template-argument</I>s of variable templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2033">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2033">2033</a></td>
+ <td>open</td>
+ <td>Redundant restriction on partial specialization argument</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2034">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2034">2034</a></td>
+ <td>open</td>
+ <td>Deprecating <TT>uncaught_exception()</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2035">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2035">2035</a></td>
+ <td>open</td>
+ <td>Multi-section example is confusing</td>
+ <td align="center">Not resolved</td>
+ </tr>
</table>
</div>
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 9d1d29c7e6b7..a494469bb6e8 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -25,11 +25,11 @@
<!--*************************************************************************-->
<h1>C++ Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2014-06-22 18:00:05 +0200 (Sun, 22 Jun 2014) $</p>
+<p>Last updated: $Date: 2014-11-27 02:54:27 +0100 (Thu, 27 Nov 2014) $</p>
<p>Clang fully implements all published ISO C++ standards including <a
-href="#cxx11">C++11</a>, as well as the upcoming standard provisionally named <a
-href="#cxx14">C++14</a>, and some parts of the fledgling <a
+href="#cxx11">C++11</a>, as well as the upcoming <a
+href="#cxx14">C++14</a> standard, and some parts of the fledgling <a
href="#cxx17">C++1z</a> standard,
and is considered a production-quality C++ compiler.
@@ -422,20 +422,21 @@ because changing <code>intmax_t</code> would be an ABI-incompatible
change.</span>
</p>
-<h2 id="cxx14">C++1y implementation status</h2>
+<h2 id="cxx14">C++14 implementation status</h2>
<p>Clang 3.4 and later implement all of the Draft International Standard (see <a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf">most
recent publicly available draft</a>)
-of the upcoming C++ language standard, provisionally named C++1y. The following
-table describes the Clang version in which each feature became available.</p>
+of the upcoming C++14 language standard. The following table describes the
+Clang version in which each feature became available.</p>
-<p>You can use Clang in C++1y mode with the <code>-std=c++1y</code> option.</p>
+<p>You can use Clang in C++14 mode with the <code>-std=c++14</code> option
+(use <code>-std=c++1y</code> in Clang 3.4 and earlier).</p>
<table width="689" border="1" cellspacing="0">
<tr>
<th>Language Feature</th>
- <th>C++1y Proposal</th>
+ <th>C++14 Proposal</th>
<th>Available in Clang?</th>
</tr>
<tr>
@@ -507,7 +508,7 @@ table describes the Clang version in which each feature became available.</p>
<h2 id="cxx17">C++1z implementation status</h2>
<p>Clang has <b>highly experimental</b> support for some proposed features of
-the C++ standard following C++1y,
+the C++ standard following C++14,
provisionally named C++1z. The following table describes which C++1z features
have been implemented in Clang and in which Clang version they became
available.</p>
@@ -523,24 +524,62 @@ as the draft C++1z standard evolves.</p>
<th>C++1z Proposal</th>
<th>Available in Clang?</th>
</tr>
+ <!-- Issaquah papers -->
<tr>
<td><tt>static_assert</tt> with no message</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3928.pdf">N3928</a></td>
- <td class="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
+ <!-- Rapperswil papers -->
<tr>
<td>Disabling trigraph expansion by default</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3981.html">N3981</a></td>
- <td class="svn" align="center">SVN</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4086.html">N4086</a></td>
+ <td class="full" align="center">Clang 3.5</td>
</tr>
+ <!--
<tr>
- <td>Terse range-based for loops</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3994.htm">N3994</a></td>
- <td class="svn" align="center">SVN</td>
+ <td rowspan="2">Terse range-based for loops (removed from C++1z)</td>
+ <td rowspan="2"><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3994.htm">N3994</a></td>
+ <td class="none" align="center">Clang 3.5: Yes</td>
</tr>
<tr>
+ <td class="svn" align="center">SVN: No</td>
+ </tr>
+ -->
+ <tr>
<td><tt>typename</tt> in a template template parameter</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4051.html">N4051</a></td>
+ <td class="full" align="center">Clang 3.5</td>
+ </tr>
+ <tr>
+ <td>New <tt>auto</tt> rules for direct-list-initialization
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3922.html">N3922</a></td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <!-- Urbana papers -->
+ <tr>
+ <td>Fold expressions</td>
+ <td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4295.html">-->N4295<!--</a>--></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td><tt>u8</tt> character literals</td>
+ <td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4267.html">-->N4267<!--</a>--></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td>Nested namespace definition</td>
+ <td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4230.html">-->N4230<!--</a>--></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td>Attributes for namespaces and enumerators</td>
+ <td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4266.html">-->N4266<!--</a>--></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td>Allow constant evaluation for all non-type template arguments</td>
+ <td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4268.html">-->N4268<!--</a>--></td>
<td class="svn" align="center">SVN</td>
</tr>
</table>
@@ -559,9 +598,16 @@ Clang version they became available:</p>
<th>Available in Clang?</th>
</tr>
<tr>
- <td>SD-6: SG10 feature test recommendations</td>
- <td><a href="http://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations">SD-6</a></td>
- <td class="full" align="center">Clang 3.4 (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3745">N3745</a>)</td>
+ <td rowspan="2">SD-6: SG10 feature test recommendations</td>
+ <td rowspan="2"><a href="http://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations">SD-6</a></td>
+ <td class="full" align="center">
+ Clang 3.4 (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3745">N3745</a>)</br>
+ </td>
+ </tr>
+ <tr>
+ <td class="svn" align="center">
+ SVN (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4200">N4200</a>)</a>
+ </td>
</tr>
<tr>
<td>[DRAFT TS] Array extensions (arrays of runtime bound)</td>
diff --git a/www/make_cxx_dr_status b/www/make_cxx_dr_status
index 82e8abd31733..db316353e0d7 100755
--- a/www/make_cxx_dr_status
+++ b/www/make_cxx_dr_status
@@ -102,10 +102,10 @@ def availability(issue):
if status == 'unknown':
avail = 'Unknown'
avail_style = ' class="none"'
- elif status == '3.5':
+ elif status == '3.7':
avail = 'SVN'
avail_style = ' class="svn"'
- elif status in ('3.1', '3.2', '3.3', '3.4'):
+ elif status in ('3.1', '3.2', '3.3', '3.4', '3.5', '3.6'):
avail = 'Clang %s' % status
avail_style = ' class="full"'
elif status == 'yes':